Skip to content

Commit

Permalink
ci(release): add sync-peer-deps step
Browse files Browse the repository at this point in the history
  • Loading branch information
Badisi committed Jun 21, 2024
1 parent 5edcb74 commit 9a93e5e
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 6 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/ci_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ on:

env:
HUSKY: 0
FORCE_COLOR: 3

jobs:
ci_release:
Expand All @@ -39,3 +40,23 @@ jobs:
working-directory: 'projects/${{ inputs.package }}'
dry-run: ${{ inputs.dry-run }}
release: true

ci_sync_peer_deps:
needs: ci_release
runs-on: 'ubuntu-latest'
steps:
- name: Checkout sources
uses: actions/checkout@v4
with:
persist-credentials: false

- name: Synchronize peer dependencies
working-directory: 'scripts'
env:
GITHUB_TOKEN: ${{ secrets.DSI_HUG_BOT_GITHUB_TOKEN }}
run: |
git config user.name 'dsi-hug-bot'
git config user.email '[email protected]'
git remote set-url origin https://x-access-token:${{ secrets.DSI_HUG_BOT_GITHUB_TOKEN }}@github.com/${{ github.repository }}
npm --prefix . i chalk
node ./sync-peer-deps.mjs
46 changes: 41 additions & 5 deletions nx.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,55 @@
},
"conventionalCommits": {
"types": {
"refactor": {
"feat": {
"semverBump": "minor",
"changelog": {
"title": "🚀 Features"
}
},
"fix": {
"semverBump": "patch",
"changelog": false
"changelog": {
"title": "🐛 Fixes"
}
},
"styles": {
"perf": {
"semverBump": "patch",
"changelog": false
"changelog": {
"title": "🔥 Performance"
}
},
"docs": {
"semverBump": "patch",
"changelog": {
"title": "Documentation Changes"
"title": "📖 Documentation"
}
},
"chore": {
"semverBump": "patch",
"changelog": {
"title": "🛠️ Chore"
}
},
"refactor": {
"semverBump": "patch",
"changelog": false
},
"types": {
"semverBump": "patch",
"changelog": false
},
"style": {
"semverBump": "patch",
"changelog": false
},
"test": {
"semverBump": "patch",
"changelog": false
},
"revert": {
"semverBump": "patch",
"changelog": false
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion projects/numeric-stepper/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@
"dependencies": {
"tslib": "^2.6.3"
}
}
}
97 changes: 97 additions & 0 deletions scripts/sync-peer-deps.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* Automated script that ensures consistent versioning across interdependent packages in a monorepo.
*
* This script reads the current version of each package and updates any other packages that reference
* it in their `peerDependencies` to maintain version synchronization.
*
* @example: $ node ./sync-peer-deps.mjs [--dry-run]
*
* TODO: remove this script if one day this feature is supported by `nx release` directly
* @see https://github.com/nrwl/nx/issues/22776
* @see https://github.com/nrwl/nx/discussions/23388
*/

import chalk from 'chalk';
import { spawnSync } from 'node:child_process';
import { readFileSync, writeFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

const { yellow, blue, red, green, gray, white, bgBlue, bgWhite } = chalk;

const __dirname = dirname(fileURLToPath(import.meta.url));
const rootPath = resolve(__dirname, '..');

const dryRun = (process.argv[2] === '--dry-run');

const execCommand = (command, args) => {
console.log(`\n${command} ${args.join(' ')}`);
if (!dryRun) {
const result = spawnSync(command, args, { stdio: 'inherit' });
if (result.error) {
throw result.error;
}
if (result.status !== 0) {
throw new Error(`Command failed with exit code ${result.status}`);
}
}
};

const getWorkspaces = () => {
const rootPackageJson = JSON.parse(readFileSync(resolve(rootPath, 'package.json'), 'utf8'));
if (!rootPackageJson.workspaces) {
console.error(red('No workspaces found in package.json'));
}
return (rootPackageJson.workspaces || []).map(workspace => ({
packageJsonPath: resolve(rootPath, workspace, 'package.json'),
packageJson: JSON.parse(readFileSync(resolve(rootPath, workspace, 'package.json'), 'utf8'))
}));
};

(() => {
console.log(`\n${bgBlue(' > ')} Synchronizing peer dependencies`);
let changesDetected = false;
const workspaces = getWorkspaces();
workspaces.forEach(workspace => {
workspaces.forEach(workspace2 => {
const peerDependencies = workspace2.packageJson.peerDependencies || {};
if (Object.hasOwn(peerDependencies, workspace.packageJson.name)) {
const version = peerDependencies[workspace.packageJson.name];
if (!version.includes(workspace.packageJson.version)) {
changesDetected = true;

const versionRange = version.match(/(^[^\d]*)\d.*/)[1];
const newVersion = `${versionRange}${workspace.packageJson.version}`;

console.log(blue.bold(`\n[${workspace2.packageJson.name}]`));
console.log(`\n${bgWhite(' > ')} ${white('UPDATE')} ${workspace2.packageJsonPath}${dryRun ? yellow(' [dry-run]') : ''}\n`);
console.log(gray(' "peerDependencies": {'));
console.log(red(`- "${workspace.packageJson.name}": "${version}"`));
console.log(green(`+ "${workspace.packageJson.name}": "${newVersion}"`));
console.log(gray(' }'));
if (!dryRun) {
workspace2.packageJson.peerDependencies[workspace.packageJson.name] = newVersion;
writeFileSync(workspace2.packageJsonPath, JSON.stringify(workspace2.packageJson, null, 4), { encoding: 'utf8' });
}

console.log(`\n${bgWhite(' > ')} Staging changed files with git${dryRun ? yellow(' [dry-run]') : ''}`);
execCommand('git', ['add', workspace2.packageJsonPath]);

console.log(`\n${bgWhite(' > ')} Committing changes with git${dryRun ? yellow(' [dry-run]') : ''}`);
execCommand('git', ['commit', '--message', `chore(deps): upgrade ${workspace.packageJson.name} to v${workspace.packageJson.version}`]);
}
}
});
});

if (changesDetected) {
console.log(`\n${bgWhite(' > ')} Pushing to git remote${dryRun ? yellow(' [dry-run]') : ''}`);
execCommand('git', ['push', '--follow-tags', '--no-verify', '--atomic']);
} else {
console.log('\nNo changes were needed, versions already in sync.');
}

if (dryRun) {
console.log(yellow('\nNOTE: The "--dry-run" flag means no changes were made.\n'));
}
})();

0 comments on commit 9a93e5e

Please sign in to comment.