This commit is contained in:
Jerome 2025-06-14 19:56:58 +01:00
commit a30a3fbe8d
No known key found for this signature in database
3 changed files with 107 additions and 85 deletions

View file

@ -9,6 +9,7 @@ This directory contains scripts for managing version consistency across the mono
Updates the version across all package.json files in the monorepo and updates package-lock.json. Updates the version across all package.json files in the monorepo and updates package-lock.json.
**Usage:** **Usage:**
```bash ```bash
npm run update-version <new-version> npm run update-version <new-version>
# Example: # Example:
@ -16,6 +17,7 @@ npm run update-version 0.14.3
``` ```
This script will: This script will:
1. Update the version in all package.json files (root, client, server, cli) 1. Update the version in all package.json files (root, client, server, cli)
2. Update workspace dependencies in the root package.json 2. Update workspace dependencies in the root package.json
3. Run `npm install` to update package-lock.json 3. Run `npm install` to update package-lock.json
@ -26,11 +28,13 @@ This script will:
Checks that all packages have consistent versions and that package-lock.json is up to date. Checks that all packages have consistent versions and that package-lock.json is up to date.
**Usage:** **Usage:**
```bash ```bash
npm run check-version npm run check-version
``` ```
This script checks: This script checks:
1. All package.json files have the same version 1. All package.json files have the same version
2. Workspace dependencies in root package.json match the current version 2. Workspace dependencies in root package.json match the current version
3. package-lock.json version matches package.json 3. package-lock.json version matches package.json
@ -41,12 +45,14 @@ This check runs automatically in CI on every PR and push to main.
## CI Integration ## CI Integration
The version consistency check is integrated into the GitHub Actions workflow (`.github/workflows/main.yml`) and will fail the build if: The version consistency check is integrated into the GitHub Actions workflow (`.github/workflows/main.yml`) and will fail the build if:
- Package versions are inconsistent - Package versions are inconsistent
- package-lock.json is out of sync - package-lock.json is out of sync
## Common Workflows ## Common Workflows
### Bumping version for a release: ### Bumping version for a release:
```bash ```bash
# Update to new version # Update to new version
npm run update-version 0.15.0 npm run update-version 0.15.0

View file

@ -1,8 +1,8 @@
#!/usr/bin/env node #!/usr/bin/env node
import fs from 'fs'; import fs from "fs";
import path from 'path'; import path from "path";
import { fileURLToPath } from 'url'; import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
@ -13,22 +13,22 @@ const __dirname = path.dirname(__filename);
* Usage: node scripts/check-version-consistency.js * Usage: node scripts/check-version-consistency.js
*/ */
console.log('🔍 Checking version consistency across packages...\n'); console.log("🔍 Checking version consistency across packages...\n");
// List of package.json files to check // List of package.json files to check
const packagePaths = [ const packagePaths = [
'package.json', "package.json",
'client/package.json', "client/package.json",
'server/package.json', "server/package.json",
'cli/package.json' "cli/package.json",
]; ];
const versions = new Map(); const versions = new Map();
const errors = []; const errors = [];
// Read version from each package.json // Read version from each package.json
packagePaths.forEach(packagePath => { packagePaths.forEach((packagePath) => {
const fullPath = path.join(__dirname, '..', packagePath); const fullPath = path.join(__dirname, "..", packagePath);
if (!fs.existsSync(fullPath)) { if (!fs.existsSync(fullPath)) {
console.warn(`⚠️ Skipping ${packagePath} - file not found`); console.warn(`⚠️ Skipping ${packagePath} - file not found`);
@ -36,14 +36,14 @@ packagePaths.forEach(packagePath => {
} }
try { try {
const packageJson = JSON.parse(fs.readFileSync(fullPath, 'utf8')); const packageJson = JSON.parse(fs.readFileSync(fullPath, "utf8"));
const version = packageJson.version; const version = packageJson.version;
const packageName = packageJson.name || packagePath; const packageName = packageJson.name || packagePath;
versions.set(packagePath, { versions.set(packagePath, {
name: packageName, name: packageName,
version: version, version: version,
dependencies: packageJson.dependencies || {} dependencies: packageJson.dependencies || {},
}); });
console.log(`📦 ${packagePath}:`); console.log(`📦 ${packagePath}:`);
@ -55,24 +55,24 @@ packagePaths.forEach(packagePath => {
}); });
if (errors.length > 0) { if (errors.length > 0) {
console.error('\n❌ Errors occurred while reading package files:'); console.error("\n❌ Errors occurred while reading package files:");
errors.forEach(error => console.error(` - ${error}`)); errors.forEach((error) => console.error(` - ${error}`));
process.exit(1); process.exit(1);
} }
// Check if all versions match // Check if all versions match
const allVersions = Array.from(versions.values()).map(v => v.version); const allVersions = Array.from(versions.values()).map((v) => v.version);
const uniqueVersions = [...new Set(allVersions)]; const uniqueVersions = [...new Set(allVersions)];
console.log('\n📊 Version Summary:'); console.log("\n📊 Version Summary:");
console.log(` Total packages: ${versions.size}`); console.log(` Total packages: ${versions.size}`);
console.log(` Unique versions: ${uniqueVersions.length}`); console.log(` Unique versions: ${uniqueVersions.length}`);
if (uniqueVersions.length > 1) { if (uniqueVersions.length > 1) {
console.error('\n❌ Version mismatch detected!'); console.error("\n❌ Version mismatch detected!");
console.error(' Found versions: ' + uniqueVersions.join(', ')); console.error(" Found versions: " + uniqueVersions.join(", "));
console.error('\n Package versions:'); console.error("\n Package versions:");
versions.forEach((info, path) => { versions.forEach((info, path) => {
console.error(` - ${path}: ${info.version}`); console.error(` - ${path}: ${info.version}`);
}); });
@ -81,17 +81,19 @@ if (uniqueVersions.length > 1) {
} }
// Check workspace dependencies in root package.json // Check workspace dependencies in root package.json
const rootPackage = versions.get('package.json'); const rootPackage = versions.get("package.json");
if (rootPackage) { if (rootPackage) {
console.log('\n🔗 Checking workspace dependencies...'); console.log("\n🔗 Checking workspace dependencies...");
const expectedVersion = rootPackage.version; const expectedVersion = rootPackage.version;
let dependencyErrors = false; let dependencyErrors = false;
Object.entries(rootPackage.dependencies).forEach(([dep, version]) => { Object.entries(rootPackage.dependencies).forEach(([dep, version]) => {
if (dep.startsWith('@modelcontextprotocol/inspector-')) { if (dep.startsWith("@modelcontextprotocol/inspector-")) {
const expectedDepVersion = `^${expectedVersion}`; const expectedDepVersion = `^${expectedVersion}`;
if (version !== expectedDepVersion) { if (version !== expectedDepVersion) {
console.error(` ❌ ${dep}: ${version} (expected ${expectedDepVersion})`); console.error(
` ❌ ${dep}: ${version} (expected ${expectedDepVersion})`,
);
dependencyErrors = true; dependencyErrors = true;
} else { } else {
console.log(` ✅ ${dep}: ${version}`); console.log(` ✅ ${dep}: ${version}`);
@ -100,26 +102,28 @@ if (rootPackage) {
}); });
if (dependencyErrors) { if (dependencyErrors) {
errors.push('Workspace dependency versions do not match package versions'); errors.push("Workspace dependency versions do not match package versions");
} }
} }
// Check if package-lock.json is up to date // Check if package-lock.json is up to date
console.log('\n🔒 Checking package-lock.json...'); console.log("\n🔒 Checking package-lock.json...");
const lockPath = path.join(__dirname, '..', 'package-lock.json'); const lockPath = path.join(__dirname, "..", "package-lock.json");
let lockFileError = false; let lockFileError = false;
if (!fs.existsSync(lockPath)) { if (!fs.existsSync(lockPath)) {
console.error(' ❌ package-lock.json not found'); console.error(" ❌ package-lock.json not found");
lockFileError = true; lockFileError = true;
} else { } else {
try { try {
const lockFile = JSON.parse(fs.readFileSync(lockPath, 'utf8')); const lockFile = JSON.parse(fs.readFileSync(lockPath, "utf8"));
const lockVersion = lockFile.version; const lockVersion = lockFile.version;
const expectedVersion = rootPackage?.version || uniqueVersions[0]; const expectedVersion = rootPackage?.version || uniqueVersions[0];
if (lockVersion !== expectedVersion) { if (lockVersion !== expectedVersion) {
console.error(` ❌ package-lock.json version (${lockVersion}) does not match package.json version (${expectedVersion})`); console.error(
` ❌ package-lock.json version (${lockVersion}) does not match package.json version (${expectedVersion})`,
);
lockFileError = true; lockFileError = true;
} else { } else {
console.log(` ✅ package-lock.json version matches: ${lockVersion}`); console.log(` ✅ package-lock.json version matches: ${lockVersion}`);
@ -128,15 +132,17 @@ if (!fs.existsSync(lockPath)) {
// Check workspace package versions in lock file // Check workspace package versions in lock file
if (lockFile.packages) { if (lockFile.packages) {
const workspacePackages = [ const workspacePackages = [
{ path: 'client', name: '@modelcontextprotocol/inspector-client' }, { path: "client", name: "@modelcontextprotocol/inspector-client" },
{ path: 'server', name: '@modelcontextprotocol/inspector-server' }, { path: "server", name: "@modelcontextprotocol/inspector-server" },
{ path: 'cli', name: '@modelcontextprotocol/inspector-cli' } { path: "cli", name: "@modelcontextprotocol/inspector-cli" },
]; ];
workspacePackages.forEach(({ path, name }) => { workspacePackages.forEach(({ path, name }) => {
const lockPkgPath = lockFile.packages[path]; const lockPkgPath = lockFile.packages[path];
if (lockPkgPath && lockPkgPath.version !== expectedVersion) { if (lockPkgPath && lockPkgPath.version !== expectedVersion) {
console.error(` ❌ ${name} in lock file: ${lockPkgPath.version} (expected ${expectedVersion})`); console.error(
` ❌ ${name} in lock file: ${lockPkgPath.version} (expected ${expectedVersion})`,
);
lockFileError = true; lockFileError = true;
} }
}); });
@ -148,22 +154,24 @@ if (!fs.existsSync(lockPath)) {
} }
// Final result // Final result
console.log('\n🎯 Result:'); console.log("\n🎯 Result:");
if (uniqueVersions.length === 1 && errors.length === 0 && !lockFileError) { if (uniqueVersions.length === 1 && errors.length === 0 && !lockFileError) {
console.log(' ✅ Version consistency check passed!'); console.log(" ✅ Version consistency check passed!");
process.exit(0); process.exit(0);
} else { } else {
console.error(' ❌ Version consistency check failed!'); console.error(" ❌ Version consistency check failed!");
if (uniqueVersions.length > 1) { if (uniqueVersions.length > 1) {
console.error(' - Package versions are not consistent'); console.error(" - Package versions are not consistent");
} }
if (errors.length > 0) { if (errors.length > 0) {
console.error(' - ' + errors.join('\n - ')); console.error(" - " + errors.join("\n - "));
} }
if (lockFileError) { if (lockFileError) {
console.error(' - package-lock.json is out of sync'); console.error(" - package-lock.json is out of sync");
} }
console.error('\n💡 Run "npm run update-version <new-version>" to fix version inconsistencies'); console.error(
'\n💡 Run "npm run update-version <new-version>" to fix version inconsistencies',
);
console.error(' or run "npm install" to update package-lock.json'); console.error(' or run "npm install" to update package-lock.json');
process.exit(1); process.exit(1);
} }

View file

@ -1,9 +1,9 @@
#!/usr/bin/env node #!/usr/bin/env node
import fs from 'fs'; import fs from "fs";
import path from 'path'; import path from "path";
import { execSync } from 'child_process'; import { execSync } from "child_process";
import { fileURLToPath } from 'url'; import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
@ -17,16 +17,18 @@ const __dirname = path.dirname(__filename);
const newVersion = process.argv[2]; const newVersion = process.argv[2];
if (!newVersion) { if (!newVersion) {
console.error('❌ Please provide a version number'); console.error("❌ Please provide a version number");
console.error('Usage: node scripts/update-version.js <new-version>'); console.error("Usage: node scripts/update-version.js <new-version>");
console.error('Example: node scripts/update-version.js 0.14.2'); console.error("Example: node scripts/update-version.js 0.14.2");
process.exit(1); process.exit(1);
} }
// Validate version format // Validate version format
const versionRegex = /^\d+\.\d+\.\d+(-[\w.]+)?$/; const versionRegex = /^\d+\.\d+\.\d+(-[\w.]+)?$/;
if (!versionRegex.test(newVersion)) { if (!versionRegex.test(newVersion)) {
console.error('❌ Invalid version format. Please use semantic versioning (e.g., 1.2.3 or 1.2.3-beta.1)'); console.error(
"❌ Invalid version format. Please use semantic versioning (e.g., 1.2.3 or 1.2.3-beta.1)",
);
process.exit(1); process.exit(1);
} }
@ -34,17 +36,17 @@ console.log(`🔄 Updating all packages to version ${newVersion}...`);
// List of package.json files to update // List of package.json files to update
const packagePaths = [ const packagePaths = [
'package.json', "package.json",
'client/package.json', "client/package.json",
'server/package.json', "server/package.json",
'cli/package.json' "cli/package.json",
]; ];
const updatedFiles = []; const updatedFiles = [];
// Update version in each package.json // Update version in each package.json
packagePaths.forEach(packagePath => { packagePaths.forEach((packagePath) => {
const fullPath = path.join(__dirname, '..', packagePath); const fullPath = path.join(__dirname, "..", packagePath);
if (!fs.existsSync(fullPath)) { if (!fs.existsSync(fullPath)) {
console.warn(`⚠️ Skipping ${packagePath} - file not found`); console.warn(`⚠️ Skipping ${packagePath} - file not found`);
@ -52,45 +54,51 @@ packagePaths.forEach(packagePath => {
} }
try { try {
const packageJson = JSON.parse(fs.readFileSync(fullPath, 'utf8')); const packageJson = JSON.parse(fs.readFileSync(fullPath, "utf8"));
const oldVersion = packageJson.version; const oldVersion = packageJson.version;
packageJson.version = newVersion; packageJson.version = newVersion;
// Update workspace dependencies in root package.json // Update workspace dependencies in root package.json
if (packagePath === 'package.json' && packageJson.dependencies) { if (packagePath === "package.json" && packageJson.dependencies) {
Object.keys(packageJson.dependencies).forEach(dep => { Object.keys(packageJson.dependencies).forEach((dep) => {
if (dep.startsWith('@modelcontextprotocol/inspector-')) { if (dep.startsWith("@modelcontextprotocol/inspector-")) {
packageJson.dependencies[dep] = `^${newVersion}`; packageJson.dependencies[dep] = `^${newVersion}`;
} }
}); });
} }
fs.writeFileSync(fullPath, JSON.stringify(packageJson, null, 2) + '\n'); fs.writeFileSync(fullPath, JSON.stringify(packageJson, null, 2) + "\n");
updatedFiles.push(packagePath); updatedFiles.push(packagePath);
console.log(`✅ Updated ${packagePath} from ${oldVersion} to ${newVersion}`); console.log(
`✅ Updated ${packagePath} from ${oldVersion} to ${newVersion}`,
);
} catch (error) { } catch (error) {
console.error(`❌ Failed to update ${packagePath}:`, error.message); console.error(`❌ Failed to update ${packagePath}:`, error.message);
process.exit(1); process.exit(1);
} }
}); });
console.log('\n📝 Summary:'); console.log("\n📝 Summary:");
console.log(`Updated ${updatedFiles.length} files to version ${newVersion}`); console.log(`Updated ${updatedFiles.length} files to version ${newVersion}`);
// Update package-lock.json // Update package-lock.json
console.log('\n🔒 Updating package-lock.json...'); console.log("\n🔒 Updating package-lock.json...");
try { try {
execSync('npm install', { stdio: 'inherit' }); execSync("npm install", { stdio: "inherit" });
console.log('✅ package-lock.json updated successfully'); console.log("✅ package-lock.json updated successfully");
} catch (error) { } catch (error) {
console.error('❌ Failed to update package-lock.json:', error.message); console.error("❌ Failed to update package-lock.json:", error.message);
console.error('Please run "npm install" manually'); console.error('Please run "npm install" manually');
process.exit(1); process.exit(1);
} }
console.log('\n✨ Version update complete!'); console.log("\n✨ Version update complete!");
console.log('\nNext steps:'); console.log("\nNext steps:");
console.log('1. Review the changes: git diff'); console.log("1. Review the changes: git diff");
console.log('2. Commit the changes: git add -A && git commit -m "chore: bump version to ' + newVersion + '"'); console.log(
console.log('3. Create a git tag: git tag v' + newVersion); '2. Commit the changes: git add -A && git commit -m "chore: bump version to ' +
console.log('4. Push changes and tag: git push && git push --tags'); newVersion +
'"',
);
console.log("3. Create a git tag: git tag v" + newVersion);
console.log("4. Push changes and tag: git push && git push --tags");