Skip to content

Commit ea8615f

Browse files
authored
Merge pull request #183 from drivecore/fix/issue-180-monorepo-versioning
fix(monorepo): implement semantic-release-monorepo for proper version…
2 parents e18d886 + 96c6284 commit ea8615f

File tree

9 files changed

+130
-3
lines changed

9 files changed

+130
-3
lines changed

.releaserc.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"branches": ["release"],
3+
"extends": "semantic-release-monorepo",
34
"plugins": [
45
"@semantic-release/commit-analyzer",
56
"@semantic-release/release-notes-generator",

docs/release-process.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Release Process with semantic-release-monorepo\n\n## Overview\n\nThis project uses `semantic-release-monorepo` to automate the versioning and release process across all packages in the monorepo. This ensures that each package is versioned independently based on its own changes, while maintaining a consistent release process.\n\n## How It Works\n\n1. When code is pushed to the `release` branch, the GitHub Actions workflow is triggered.\n2. The workflow builds and tests all packages.\n3. `semantic-release-monorepo` analyzes the commit history for each package to determine the next version.\n4. New versions are published to npm, and release notes are generated based on conventional commits.\n5. Git tags are created for each package release.\n\n## Commit Message Format\n\nThis project follows the [Conventional Commits](https://www.conventionalcommits.org/) specification. Your commit messages should be structured as follows:\n\n```\n<type>[optional scope]: <description>\n\n[optional body]\n\n[optional footer(s)]\n```\n\nExamples:\n\n```\nfeat(cli): add new command for project initialization\nfix(agent): resolve issue with async tool execution\ndocs: update installation instructions\n```\n\n### Types\n\n- `feat`: A new feature (triggers a minor version bump)\n- `fix`: A bug fix (triggers a patch version bump)\n- `docs`: Documentation changes\n- `style`: Changes that don't affect the code's meaning (formatting, etc.)\n- `refactor`: Code changes that neither fix a bug nor add a feature\n- `perf`: Performance improvements\n- `test`: Adding or correcting tests\n- `chore`: Changes to the build process, tooling, etc.\n\n### Breaking Changes\n\nIf your commit introduces a breaking change, add `BREAKING CHANGE:` in the footer followed by a description of the change. This will trigger a major version bump.\n\nExample:\n\n```\nfeat(agent): change API for tool execution\n\nBREAKING CHANGE: The tool execution API now requires an options object instead of individual parameters.\n```\n\n## Troubleshooting\n\nIf you encounter issues with the release process:\n\n1. Run `pnpm verify-release-config` to check if your semantic-release configuration is correct.\n2. Ensure your commit messages follow the conventional commits format.\n3. Check if the package has a `.releaserc.json` file that extends `semantic-release-monorepo`.\n4. Verify that each package has a `semantic-release` script in its `package.json`.\n\n## Manual Release\n\nIn rare cases, you might need to trigger a release manually. You can do this by:\n\n```bash\n# Release all packages\npnpm release\n\n# Release a specific package\ncd packages/cli\npnpm semantic-release\n```\n

lerna.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{\n \"version\": \"independent\",\n \"npmClient\": \"pnpm\",\n \"command\": {\n \"publish\": {\n \"conventionalCommits\": true,\n \"message\": \"chore(release): publish\"\n }\n },\n \"packages\": [\"packages/*\"]\n}

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
"cli": "cd packages/cli && node --no-deprecation bin/cli.js",
2323
"prepare": "husky",
2424
"semantic-release": "semantic-release",
25-
"release": "semantic-release"
25+
"verify-release-config": "node scripts/verify-release-config.js",
26+
"release": "pnpm verify-release-config && npx lerna exec --concurrency 1 -- npx --no-install semantic-release -e semantic-release-monorepo"
2627
},
2728
"lint-staged": {
2829
"*.{js,jsx,ts,tsx}": [
@@ -51,9 +52,11 @@
5152
"eslint-plugin-promise": "^7.2.1",
5253
"eslint-plugin-unused-imports": "^4.1.4",
5354
"husky": "^9.1.7",
55+
"lerna": "^8.2.1",
5456
"lint-staged": "^15.4.3",
5557
"prettier": "^3.5.1",
5658
"semantic-release": "^24.2.3",
59+
"semantic-release-monorepo": "^8.0.2",
5760
"typescript-eslint": "^8.23.0"
5861
},
5962
"pnpm": {

packages/agent/.releaserc.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"extends": "semantic-release-monorepo",
3+
"branches": ["release"],
4+
"plugins": [
5+
"@semantic-release/commit-analyzer",
6+
"@semantic-release/release-notes-generator",
7+
"@semantic-release/changelog",
8+
"@semantic-release/npm",
9+
[
10+
"@semantic-release/git",
11+
{
12+
"assets": ["package.json", "CHANGELOG.md"],
13+
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
14+
}
15+
],
16+
"@semantic-release/github"
17+
]
18+
}

packages/agent/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"typecheck": "tsc --noEmit",
3030
"clean": "rimraf dist",
3131
"clean:all": "rimraf node_modules dist",
32-
"prepublishOnly": "pnpm run clean && pnpm run build && pnpm run test"
32+
"prepublishOnly": "pnpm run clean && pnpm run build && pnpm run test",
33+
"semantic-release": "semantic-release -e semantic-release-monorepo"
3334
},
3435
"keywords": [
3536
"ai",

packages/cli/.releaserc.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"extends": "semantic-release-monorepo",
3+
"branches": ["release"],
4+
"plugins": [
5+
"@semantic-release/commit-analyzer",
6+
"@semantic-release/release-notes-generator",
7+
"@semantic-release/changelog",
8+
"@semantic-release/npm",
9+
[
10+
"@semantic-release/git",
11+
{
12+
"assets": ["package.json", "CHANGELOG.md"],
13+
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
14+
}
15+
],
16+
"@semantic-release/github"
17+
]
18+
}

packages/cli/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"test:ci": "vitest --run --coverage",
3030
"changeset": "changeset",
3131
"version": "changeset version",
32-
"prepublishOnly": "pnpm run clean && pnpm run build && pnpm run test"
32+
"prepublishOnly": "pnpm run clean && pnpm run build && pnpm run test",
33+
"semantic-release": "semantic-release -e semantic-release-monorepo"
3334
},
3435
"keywords": [
3536
"ai",

scripts/verify-release-config.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#!/usr/bin/env node
2+
3+
/* eslint-disable no-console */
4+
/* eslint-env node */
5+
6+
import fs from 'fs';
7+
import path from 'path';
8+
9+
const ROOT_DIR = path.resolve('.');
10+
const PACKAGES_DIR = path.join(ROOT_DIR, 'packages');
11+
12+
console.log('Starting verification script...');
13+
console.log('Checking root package.json...');
14+
// Check if required packages are installed
15+
const rootPackageJson = JSON.parse(fs.readFileSync(path.join(ROOT_DIR, 'package.json'), 'utf8'));
16+
const hasSemanticReleaseMonorepo = rootPackageJson.devDependencies && 'semantic-release-monorepo' in rootPackageJson.devDependencies;
17+
const hasLerna = rootPackageJson.devDependencies && 'lerna' in rootPackageJson.devDependencies;
18+
19+
if (!hasSemanticReleaseMonorepo) {
20+
console.error('❌ semantic-release-monorepo is not installed in root package.json');
21+
process.exit(1);
22+
}
23+
24+
if (!hasLerna) {
25+
console.error('❌ lerna is not installed in root package.json');
26+
process.exit(1);
27+
}
28+
29+
console.log('Checking root .releaserc.json...');
30+
// Check root .releaserc.json
31+
const rootReleaseRc = JSON.parse(fs.readFileSync(path.join(ROOT_DIR, '.releaserc.json'), 'utf8'));
32+
if (!rootReleaseRc.extends || rootReleaseRc.extends !== 'semantic-release-monorepo') {
33+
console.error('❌ Root .releaserc.json does not extend semantic-release-monorepo');
34+
process.exit(1);
35+
}
36+
37+
console.log('Checking lerna.json...');
38+
// Check lerna.json
39+
if (!fs.existsSync(path.join(ROOT_DIR, 'lerna.json'))) {
40+
console.error('❌ lerna.json is missing');
41+
process.exit(1);
42+
}
43+
44+
console.log('Checking packages...');
45+
// Check packages
46+
const packages = fs.readdirSync(PACKAGES_DIR)
47+
.filter(dir => fs.statSync(path.join(PACKAGES_DIR, dir)).isDirectory());
48+
49+
console.log(`Found packages: ${packages.join(', ')}`);
50+
51+
for (const pkg of packages) {
52+
const packageDir = path.join(PACKAGES_DIR, pkg);
53+
const packageJsonPath = path.join(packageDir, 'package.json');
54+
const releaseRcPath = path.join(packageDir, '.releaserc.json');
55+
56+
console.log(`Checking package ${pkg}...`);
57+
58+
// Check package.json
59+
if (fs.existsSync(packageJsonPath)) {
60+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
61+
if (!packageJson.scripts || !packageJson.scripts['semantic-release']) {
62+
console.error(`❌ Package ${pkg} does not have a semantic-release script`);
63+
process.exit(1);
64+
}
65+
} else {
66+
console.error(`❌ Package ${pkg} does not have a package.json file`);
67+
process.exit(1);
68+
}
69+
70+
// Check .releaserc.json
71+
if (fs.existsSync(releaseRcPath)) {
72+
const releaseRc = JSON.parse(fs.readFileSync(releaseRcPath, 'utf8'));
73+
if (!releaseRc.extends || releaseRc.extends !== 'semantic-release-monorepo') {
74+
console.error(`❌ Package ${pkg} .releaserc.json does not extend semantic-release-monorepo`);
75+
process.exit(1);
76+
}
77+
} else {
78+
console.error(`❌ Package ${pkg} does not have a .releaserc.json file`);
79+
process.exit(1);
80+
}
81+
}
82+
83+
console.log('✅ All semantic-release-monorepo configurations are correct!');

0 commit comments

Comments
 (0)