just-release 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,195 @@
1
+ # just-release
2
+
3
+ Automated monorepo release tool with conventional commits support.
4
+
5
+ ## Features
6
+
7
+ - 🔍 **Automatic workspace detection** - Works with pnpm, npm, and yarn workspaces
8
+ - 📝 **Conventional commits** - Analyzes commits to determine version bumps
9
+ - 📦 **Unified versioning** - All packages in the workspace share the same version
10
+ - 📄 **Smart changelogs** - Generates per-package changelogs only for packages with changes
11
+ - 🌿 **Git automation** - Creates release branches, commits, and pushes automatically
12
+ - 🔗 **GitHub integration** - Creates or updates PRs automatically
13
+ - 🔒 **Dry-run by default** - Safe to run locally without making changes
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ pnpm add -D just-release
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ### Local Development (Dry-run)
24
+
25
+ By default, `just-release` runs in dry-run mode when not in a CI environment:
26
+
27
+ ```bash
28
+ pnpm just-release
29
+ ```
30
+
31
+ This will show you what would happen without making any actual changes.
32
+
33
+ ### CI Environment (Live mode)
34
+
35
+ Set `CI=1` to execute the release process:
36
+
37
+ ```bash
38
+ CI=1 GITHUB_TOKEN=$GITHUB_TOKEN pnpm just-release
39
+ ```
40
+
41
+ ## How It Works
42
+
43
+ 1. **Detects workspace** - Reads `pnpm-workspace.yaml` or `package.json` workspaces field
44
+ 2. **Analyzes commits** - Gets all commits since the last release (marked by `release: X.Y.Z` commits)
45
+ 3. **Calculates version bump** - Based on conventional commit types:
46
+ - `feat:` → minor version bump
47
+ - `fix:` → patch version bump
48
+ - `BREAKING CHANGE:` or `feat!:` → major version bump
49
+ - `chore:`, `docs:` → no release
50
+ 4. **Generates changelogs** - Creates/updates `CHANGELOG.md` in each affected package
51
+ 5. **Creates release branch** - Named `release/YYYY-MM-DD`
52
+ 6. **Updates versions** - Updates `version` field in all package.json files
53
+ 7. **Commits and pushes** - Creates commit with message `release: X.Y.Z`
54
+ 8. **Creates/updates PR** - Opens or updates a pull request on GitHub
55
+
56
+ ## Environment Variables
57
+
58
+ - `CI` - Set to `1` to run in live mode (default: dry-run)
59
+ - `GITHUB_TOKEN` - Required for creating/updating PRs (only in live mode)
60
+
61
+ ## Conventional Commit Format
62
+
63
+ ```
64
+ <type>: <subject>
65
+
66
+ <body>
67
+
68
+ <footer>
69
+ ```
70
+
71
+ ### Types
72
+
73
+ - `feat:` - New feature (minor version bump)
74
+ - `fix:` - Bug fix (patch version bump)
75
+ - `perf:` - Performance improvement (patch version bump)
76
+ - `docs:` - Documentation changes (no version bump)
77
+ - `chore:` - Maintenance tasks (no version bump)
78
+ - `test:` - Test changes (no version bump)
79
+
80
+ ### Breaking Changes
81
+
82
+ Add `!` after the type or include `BREAKING CHANGE:` in the footer:
83
+
84
+ ```
85
+ feat!: remove deprecated API
86
+
87
+ BREAKING CHANGE: The old API has been removed. Use the new API instead.
88
+ ```
89
+
90
+ ## Workflow Setup
91
+
92
+ ### GitHub Actions
93
+
94
+ Create `.github/workflows/release.yml`:
95
+
96
+ ```yaml
97
+ name: Release
98
+
99
+ on:
100
+ push:
101
+ branches:
102
+ - main
103
+
104
+ permissions:
105
+ contents: write
106
+ pull-requests: write
107
+
108
+ jobs:
109
+ release:
110
+ runs-on: ubuntu-latest
111
+ steps:
112
+ - uses: actions/checkout@v4
113
+ with:
114
+ fetch-depth: 0 # Required to get all commits
115
+
116
+ - uses: pnpm/action-setup@v2
117
+ with:
118
+ version: 8
119
+
120
+ - uses: actions/setup-node@v4
121
+ with:
122
+ node-version: '20'
123
+ cache: 'pnpm'
124
+
125
+ - run: pnpm install
126
+
127
+ - name: Create release PR
128
+ env:
129
+ CI: 1
130
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
131
+ run: pnpm just-release
132
+ ```
133
+
134
+ ### Publishing
135
+
136
+ Create `.github/workflows/publish.yml` to publish when release PR is merged:
137
+
138
+ ```yaml
139
+ name: Publish
140
+
141
+ on:
142
+ push:
143
+ branches:
144
+ - main
145
+
146
+ permissions:
147
+ contents: write
148
+ id-token: write
149
+
150
+ jobs:
151
+ publish:
152
+ runs-on: ubuntu-latest
153
+ # Only run if commit message starts with "release:"
154
+ if: startsWith(github.event.head_commit.message, 'release:')
155
+ steps:
156
+ - uses: actions/checkout@v4
157
+
158
+ - uses: pnpm/action-setup@v2
159
+ with:
160
+ version: 8
161
+
162
+ - uses: actions/setup-node@v4
163
+ with:
164
+ node-version: '20'
165
+ cache: 'pnpm'
166
+ registry-url: 'https://registry.npmjs.org'
167
+
168
+ - run: pnpm install
169
+
170
+ - run: pnpm build
171
+
172
+ - run: pnpm publish -r --access public
173
+ env:
174
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
175
+ ```
176
+
177
+ ## Single-Package vs Monorepo
178
+
179
+ `just-release` automatically adapts to your repository structure:
180
+
181
+ - **Monorepo** - If `pnpm-workspace.yaml` or `package.json` workspaces are found, all workspace packages are bumped to the same version
182
+ - **Single-package** - If no workspace configuration is found, the root package is treated as the only package
183
+
184
+ This means you can use `just-release` for both monorepos and single-package repos without any configuration changes.
185
+
186
+ ## Requirements
187
+
188
+ - Node.js >= 18
189
+ - Git repository with `origin` remote pointing to GitHub
190
+ - Root `package.json` with `version` field
191
+ - Optional: Workspace configuration in `pnpm-workspace.yaml` or `package.json`
192
+
193
+ ## License
194
+
195
+ ISC
@@ -0,0 +1,6 @@
1
+ import { CommitInfo } from './commits.js';
2
+ import { WorkspacePackage } from './workspace.js';
3
+ export declare function generateChangelogSection(newVersion: string, commits: CommitInfo[]): string;
4
+ export declare function groupCommitsByPackage(commits: CommitInfo[]): Map<string, CommitInfo[]>;
5
+ export declare function generateChangelogs(newVersion: string, commits: CommitInfo[], packages: WorkspacePackage[]): Promise<void>;
6
+ //# sourceMappingURL=changelog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changelog.d.ts","sourceRoot":"","sources":["../src/changelog.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAQlD,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,UAAU,EAAE,GACpB,MAAM,CAuHR;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,UAAU,EAAE,GACpB,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAa3B;AAED,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,UAAU,EAAE,EACrB,QAAQ,EAAE,gBAAgB,EAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CAoCf"}
@@ -0,0 +1,152 @@
1
+ // ABOUTME: Generates changelog entries for workspace packages with changes
2
+ // ABOUTME: Creates markdown-formatted changelogs grouped by commit type
3
+ import { readFile, writeFile } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ export function generateChangelogSection(newVersion, commits) {
6
+ const today = new Date().toISOString().split('T')[0];
7
+ let versionSection = `## ${newVersion} (${today})\n\n`;
8
+ // Group commits by type
9
+ const breaking = commits.filter((c) => c.breaking);
10
+ const features = commits.filter((c) => c.type === 'feat' && !c.breaking);
11
+ const fixes = commits.filter((c) => c.type === 'fix');
12
+ const perf = commits.filter((c) => c.type === 'perf');
13
+ const tests = commits.filter((c) => c.type === 'test');
14
+ const docs = commits.filter((c) => c.type === 'docs');
15
+ const chores = commits.filter((c) => c.type === 'chore');
16
+ const refactors = commits.filter((c) => c.type === 'refactor');
17
+ const styles = commits.filter((c) => c.type === 'style');
18
+ const builds = commits.filter((c) => c.type === 'build');
19
+ const ci = commits.filter((c) => c.type === 'ci');
20
+ // Add breaking changes section
21
+ if (breaking.length > 0) {
22
+ versionSection += '### BREAKING CHANGES\n\n';
23
+ for (const commit of breaking) {
24
+ versionSection += `- ${commit.subject}\n`;
25
+ }
26
+ versionSection += '\n';
27
+ }
28
+ // Add features section
29
+ if (features.length > 0) {
30
+ versionSection += '### Features\n\n';
31
+ for (const commit of features) {
32
+ versionSection += `- ${commit.subject}\n`;
33
+ }
34
+ versionSection += '\n';
35
+ }
36
+ // Add bug fixes section
37
+ if (fixes.length > 0) {
38
+ versionSection += '### Bug Fixes\n\n';
39
+ for (const commit of fixes) {
40
+ versionSection += `- ${commit.subject}\n`;
41
+ }
42
+ versionSection += '\n';
43
+ }
44
+ // Add performance section
45
+ if (perf.length > 0) {
46
+ versionSection += '### Performance Improvements\n\n';
47
+ for (const commit of perf) {
48
+ versionSection += `- ${commit.subject}\n`;
49
+ }
50
+ versionSection += '\n';
51
+ }
52
+ // Add tests section
53
+ if (tests.length > 0) {
54
+ versionSection += '### Tests\n\n';
55
+ for (const commit of tests) {
56
+ versionSection += `- ${commit.subject}\n`;
57
+ }
58
+ versionSection += '\n';
59
+ }
60
+ // Add documentation section
61
+ if (docs.length > 0) {
62
+ versionSection += '### Documentation\n\n';
63
+ for (const commit of docs) {
64
+ versionSection += `- ${commit.subject}\n`;
65
+ }
66
+ versionSection += '\n';
67
+ }
68
+ // Add refactoring section
69
+ if (refactors.length > 0) {
70
+ versionSection += '### Refactoring\n\n';
71
+ for (const commit of refactors) {
72
+ versionSection += `- ${commit.subject}\n`;
73
+ }
74
+ versionSection += '\n';
75
+ }
76
+ // Add chores section
77
+ if (chores.length > 0) {
78
+ versionSection += '### Chores\n\n';
79
+ for (const commit of chores) {
80
+ versionSection += `- ${commit.subject}\n`;
81
+ }
82
+ versionSection += '\n';
83
+ }
84
+ // Add style section
85
+ if (styles.length > 0) {
86
+ versionSection += '### Styles\n\n';
87
+ for (const commit of styles) {
88
+ versionSection += `- ${commit.subject}\n`;
89
+ }
90
+ versionSection += '\n';
91
+ }
92
+ // Add build section
93
+ if (builds.length > 0) {
94
+ versionSection += '### Build\n\n';
95
+ for (const commit of builds) {
96
+ versionSection += `- ${commit.subject}\n`;
97
+ }
98
+ versionSection += '\n';
99
+ }
100
+ // Add CI section
101
+ if (ci.length > 0) {
102
+ versionSection += '### CI\n\n';
103
+ for (const commit of ci) {
104
+ versionSection += `- ${commit.subject}\n`;
105
+ }
106
+ versionSection += '\n';
107
+ }
108
+ return versionSection;
109
+ }
110
+ export function groupCommitsByPackage(commits) {
111
+ const commitsByPackage = new Map();
112
+ for (const commit of commits) {
113
+ for (const packageName of commit.packages) {
114
+ if (!commitsByPackage.has(packageName)) {
115
+ commitsByPackage.set(packageName, []);
116
+ }
117
+ commitsByPackage.get(packageName).push(commit);
118
+ }
119
+ }
120
+ return commitsByPackage;
121
+ }
122
+ export async function generateChangelogs(newVersion, commits, packages) {
123
+ // Group commits by package
124
+ const commitsByPackage = groupCommitsByPackage(commits);
125
+ // Generate changelog for each package with changes
126
+ for (const pkg of packages) {
127
+ const packageCommits = commitsByPackage.get(pkg.name);
128
+ // Skip packages with no changes
129
+ if (!packageCommits || packageCommits.length === 0) {
130
+ continue;
131
+ }
132
+ const changelogPath = join(pkg.path, 'CHANGELOG.md');
133
+ // Read existing changelog if it exists
134
+ let existingContent = '';
135
+ try {
136
+ existingContent = await readFile(changelogPath, 'utf-8');
137
+ // Remove the header if it exists
138
+ if (existingContent.startsWith('# Changelog\n\n')) {
139
+ existingContent = existingContent.substring('# Changelog\n\n'.length);
140
+ }
141
+ }
142
+ catch (error) {
143
+ // File doesn't exist, that's okay
144
+ }
145
+ // Generate new version section
146
+ const versionSection = generateChangelogSection(newVersion, packageCommits);
147
+ // Combine new and existing content
148
+ const fullChangelog = '# Changelog\n\n' + versionSection + existingContent;
149
+ await writeFile(changelogPath, fullChangelog, 'utf-8');
150
+ }
151
+ }
152
+ //# sourceMappingURL=changelog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changelog.js","sourceRoot":"","sources":["../src/changelog.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env node
2
+ // ABOUTME: CLI entry point for just-release tool
3
+ // ABOUTME: Orchestrates release workflow with dry-run and live modes
4
+ import { detectWorkspace } from './workspace.js';
5
+ import { analyzeCommits } from './commits.js';
6
+ import { calculateVersionBump } from './version.js';
7
+ import { generateChangelogs } from './changelog.js';
8
+ import { createReleaseBranch, updatePackageVersions, commitAndPush, } from './git.js';
9
+ import { createOrUpdatePR } from './github.js';
10
+ import { getColors } from './colors.js';
11
+ import { generateChangelogSection, groupCommitsByPackage } from './changelog.js';
12
+ const colors = getColors(process.env, process.stdout.isTTY);
13
+ function getCommitPrefix(commit) {
14
+ if (commit.breaking)
15
+ return '⚠️ BREAKING: ';
16
+ switch (commit.type) {
17
+ case 'feat': return '✨ ';
18
+ case 'fix': return '🐛 ';
19
+ case 'perf': return '⚡ ';
20
+ case 'test': return '✅ ';
21
+ case 'docs': return '📝 ';
22
+ case 'refactor': return '♻️ ';
23
+ case 'chore': return '🔧 ';
24
+ case 'style': return '💄 ';
25
+ case 'build': return '📦 ';
26
+ case 'ci': return '👷 ';
27
+ default: return '';
28
+ }
29
+ }
30
+ function generatePRSummary(commits) {
31
+ return commits
32
+ .map((c) => {
33
+ let summary = `- ${c.hash}: ${getCommitPrefix(c)}${c.subject}`;
34
+ // Include body if present
35
+ if (c.body && c.body.trim()) {
36
+ // Indent the body for better readability (blank line before body)
37
+ const indentedBody = c.body
38
+ .split('\n')
39
+ .map((line) => ` ${line}`)
40
+ .join('\n');
41
+ summary += `\n\n${indentedBody}`;
42
+ }
43
+ return summary;
44
+ })
45
+ .join('\n\n');
46
+ }
47
+ async function main() {
48
+ const isDryRun = process.env.CI !== '1';
49
+ const showPrPreview = process.argv.includes('--pr');
50
+ const cwd = process.cwd();
51
+ console.log('🚀 just-release\n');
52
+ if (isDryRun) {
53
+ console.log('🔍 Running in DRY-RUN mode (set CI=1 to execute)\n');
54
+ }
55
+ else {
56
+ console.log('✅ Running in LIVE mode\n');
57
+ }
58
+ try {
59
+ // Step 1: Detect workspace
60
+ console.log('📦 Detecting workspace...');
61
+ const workspace = await detectWorkspace(cwd);
62
+ // Check if this is a single-package repo (root package only)
63
+ const isSinglePackage = workspace.packages.length === 1 &&
64
+ workspace.packages[0].path === workspace.rootPath;
65
+ if (isSinglePackage) {
66
+ console.log(` No workspace configuration found`);
67
+ console.log(` Using root package at ${colors.blue}./package.json${colors.reset}`);
68
+ }
69
+ else {
70
+ console.log(` Found ${workspace.packages.length} package(s) in workspace`);
71
+ }
72
+ console.log(` Current version: ${workspace.rootVersion}\n`);
73
+ // Step 2: Analyze commits
74
+ console.log('📝 Analyzing commits since last release...');
75
+ const commits = await analyzeCommits(cwd, workspace.packages);
76
+ if (commits.length === 0) {
77
+ console.log(` Found ${commits.length} commit(s) since last release`);
78
+ console.log('\n✨ No new commits since last release. Nothing to do!');
79
+ process.exit(0);
80
+ }
81
+ console.log(` Found ${commits.length} commit(s) since last release:`);
82
+ // Summarize commit types
83
+ const commitCounts = new Map();
84
+ for (const commit of commits) {
85
+ const type = commit.type || 'other';
86
+ commitCounts.set(type, (commitCounts.get(type) || 0) + 1);
87
+ }
88
+ const sortedCounts = Array.from(commitCounts.entries())
89
+ .sort((a, b) => b[1] - a[1]); // Sort by count descending
90
+ for (const [type, count] of sortedCounts) {
91
+ console.log(` - ${count} ${type}`);
92
+ }
93
+ console.log();
94
+ // Step 3: Calculate version bump
95
+ console.log('🔢 Calculating version bump...');
96
+ const versionBump = calculateVersionBump(workspace.rootVersion, commits);
97
+ if (versionBump.bumpType === null) {
98
+ console.log(' No releasable changes (only chore/docs commits). Skipping release.');
99
+ process.exit(0);
100
+ }
101
+ console.log(` Bump type: ${versionBump.bumpType} (${workspace.rootVersion} → ${versionBump.newVersion})\n`);
102
+ if (isDryRun) {
103
+ const packageJsonCount = workspace.packages.filter((p) => p.path !== workspace.rootPath).length + 1;
104
+ const today = new Date().toISOString().split('T')[0];
105
+ const branchName = `release/${today}`;
106
+ console.log('🎯 Dry-run summary:');
107
+ console.log(` • Would create release branch ${colors.blue}${branchName}${colors.reset}`);
108
+ console.log(` • Would update ${packageJsonCount} package.json file(s)`);
109
+ console.log(` • Would generate changelogs for affected packages`);
110
+ console.log(` • Would commit changes with message: "release: ${versionBump.newVersion}"`);
111
+ console.log(` • Would push to remote and create/update PR`);
112
+ console.log('\n💡 Set CI=1 to execute these changes for real.\n');
113
+ if (showPrPreview) {
114
+ console.log('📄 PR Preview:\n');
115
+ // Generate PR title and body
116
+ const prTitle = `Release ${versionBump.newVersion}`;
117
+ console.log(`${colors.blue}Title:${colors.reset}`);
118
+ console.log(` ${prTitle}\n`);
119
+ // Generate changelog summary for PR body
120
+ const changelogSummary = generatePRSummary(commits);
121
+ console.log(`${colors.blue}Description:${colors.reset}`);
122
+ console.log(` ## Release ${versionBump.newVersion}\n`);
123
+ if (changelogSummary) {
124
+ changelogSummary.split('\n').forEach(line => console.log(` ${line}`));
125
+ }
126
+ console.log();
127
+ // Show files that would be changed
128
+ console.log(`${colors.blue}Files changed:${colors.reset}\n`);
129
+ // Root package.json
130
+ console.log(` ${colors.blue}package.json${colors.reset}`);
131
+ console.log(` - version: ${workspace.rootVersion} → ${versionBump.newVersion}\n`);
132
+ // Workspace package.json files
133
+ for (const pkg of workspace.packages) {
134
+ if (pkg.path !== workspace.rootPath) {
135
+ const relativePath = pkg.path.replace(workspace.rootPath + '/', '');
136
+ console.log(` ${colors.blue}${relativePath}/package.json${colors.reset}`);
137
+ console.log(` - version: ${pkg.version} → ${versionBump.newVersion}\n`);
138
+ }
139
+ }
140
+ // Changelogs
141
+ const commitsByPackage = groupCommitsByPackage(commits);
142
+ for (const pkg of workspace.packages) {
143
+ const packageCommits = commitsByPackage.get(pkg.name);
144
+ if (packageCommits && packageCommits.length > 0) {
145
+ const relativePath = pkg.path === workspace.rootPath
146
+ ? ''
147
+ : pkg.path.replace(workspace.rootPath + '/', '') + '/';
148
+ console.log(` ${colors.blue}${relativePath}CHANGELOG.md${colors.reset}`);
149
+ // Generate and display the changelog section
150
+ const changelogContent = generateChangelogSection(versionBump.newVersion, packageCommits);
151
+ // Indent each line for display
152
+ const lines = changelogContent.split('\n');
153
+ for (const line of lines) {
154
+ if (line.trim()) {
155
+ console.log(` ${line}`);
156
+ }
157
+ else {
158
+ console.log();
159
+ }
160
+ }
161
+ }
162
+ }
163
+ }
164
+ process.exit(0);
165
+ }
166
+ // Step 4: Generate changelogs
167
+ console.log('📄 Generating changelogs...');
168
+ await generateChangelogs(versionBump.newVersion, commits, workspace.packages);
169
+ console.log(' Changelogs generated\n');
170
+ // Step 5: Create release branch
171
+ console.log('🌿 Creating release branch...');
172
+ const branchName = await createReleaseBranch(cwd);
173
+ console.log(` Created branch: ${branchName}\n`);
174
+ // Step 6: Update package versions
175
+ console.log('📝 Updating package versions...');
176
+ await updatePackageVersions(cwd, versionBump.newVersion, workspace.packages);
177
+ console.log(' Package versions updated\n');
178
+ // Step 7: Commit and push
179
+ console.log('💾 Committing and pushing changes...');
180
+ await commitAndPush(cwd, versionBump.newVersion, true);
181
+ console.log(' Changes pushed to remote\n');
182
+ // Step 8: Create or update PR
183
+ console.log('🔗 Creating/updating pull request...');
184
+ const githubToken = process.env.GITHUB_TOKEN;
185
+ if (!githubToken) {
186
+ console.error('❌ GITHUB_TOKEN environment variable is required to create PR');
187
+ process.exit(1);
188
+ }
189
+ // Build changelog summary for PR body
190
+ const changelogSummary = generatePRSummary(commits);
191
+ const prUrl = await createOrUpdatePR(cwd, branchName, versionBump.newVersion, changelogSummary, githubToken);
192
+ console.log(` PR URL: ${prUrl}\n`);
193
+ console.log('✅ Release process complete!\n');
194
+ }
195
+ catch (error) {
196
+ console.error('\n❌ Error:', error instanceof Error ? error.message : error);
197
+ process.exit(1);
198
+ }
199
+ }
200
+ main();
201
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare function supportsColor(env: NodeJS.ProcessEnv, isTTY: boolean): boolean;
2
+ export declare function getColors(env: NodeJS.ProcessEnv, isTTY: boolean): {
3
+ blue: string;
4
+ reset: string;
5
+ };
6
+ //# sourceMappingURL=colors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colors.d.ts","sourceRoot":"","sources":["../src/colors.ts"],"names":[],"mappings":"AAGA,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAiB7E;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO;;;EAO/D"}
package/dist/colors.js ADDED
@@ -0,0 +1,25 @@
1
+ // ABOUTME: Detects terminal color support capabilities
2
+ // ABOUTME: Respects NO_COLOR standard and terminal type detection
3
+ export function supportsColor(env, isTTY) {
4
+ // Respect NO_COLOR standard: https://no-color.org/
5
+ if (env.NO_COLOR) {
6
+ return false;
7
+ }
8
+ // Dumb terminals don't support colors
9
+ if (env.TERM === 'dumb') {
10
+ return false;
11
+ }
12
+ // Only use colors in TTY (not when piped)
13
+ if (!isTTY) {
14
+ return false;
15
+ }
16
+ return true;
17
+ }
18
+ export function getColors(env, isTTY) {
19
+ const hasColor = supportsColor(env, isTTY);
20
+ return {
21
+ blue: hasColor ? '\x1b[34m' : '',
22
+ reset: hasColor ? '\x1b[0m' : '',
23
+ };
24
+ }
25
+ //# sourceMappingURL=colors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colors.js","sourceRoot":"","sources":["../src/colors.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,kEAAkE;AAElE,MAAM,UAAU,aAAa,CAAC,GAAsB,EAAE,KAAc;IAClE,mDAAmD;IACnD,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QACjB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,sCAAsC;IACtC,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACxB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,0CAA0C;IAC1C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAsB,EAAE,KAAc;IAC9D,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAE3C,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;QAChC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;KACjC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { WorkspacePackage } from './workspace.js';
2
+ export interface CommitInfo {
3
+ hash: string;
4
+ type: string | null;
5
+ scope: string | null;
6
+ subject: string | null;
7
+ body: string | null;
8
+ breaking: boolean;
9
+ packages: string[];
10
+ files: string[];
11
+ }
12
+ export declare function analyzeCommits(repoPath: string, workspacePackages: WorkspacePackage[]): Promise<CommitInfo[]>;
13
+ //# sourceMappingURL=commits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commits.d.ts","sourceRoot":"","sources":["../src/commits.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAKlD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,iBAAiB,EAAE,gBAAgB,EAAE,GACpC,OAAO,CAAC,UAAU,EAAE,CAAC,CAyEvB"}
@@ -0,0 +1,70 @@
1
+ // ABOUTME: Analyzes git commits and parses conventional commit messages
2
+ // ABOUTME: Maps file changes to workspace packages for changelog generation
3
+ import { simpleGit } from 'simple-git';
4
+ import * as conventionalCommitsParser from 'conventional-commits-parser';
5
+ const { CommitParser } = conventionalCommitsParser;
6
+ const parser = new CommitParser();
7
+ export async function analyzeCommits(repoPath, workspacePackages) {
8
+ const git = simpleGit(repoPath);
9
+ // Get all commits
10
+ const log = await git.log();
11
+ // Find the most recent release commit (message starts with "release: ")
12
+ let endIndex = log.all.length; // Take all commits by default
13
+ for (let i = 0; i < log.all.length; i++) {
14
+ if (log.all[i].message.startsWith('release: ')) {
15
+ endIndex = i; // Stop before the release commit
16
+ break;
17
+ }
18
+ }
19
+ // Only analyze commits since last release (or all if no release found)
20
+ const commitsToAnalyze = log.all.slice(0, endIndex);
21
+ const commits = [];
22
+ for (const commit of commitsToAnalyze) {
23
+ // Parse conventional commit (combine message and body for full parsing)
24
+ const fullMessage = commit.body
25
+ ? `${commit.message}\n\n${commit.body}`
26
+ : commit.message;
27
+ const parsed = parser.parse(fullMessage);
28
+ // Get files changed in this commit
29
+ const diffSummary = await git.show([
30
+ '--name-only',
31
+ '--format=',
32
+ commit.hash,
33
+ ]);
34
+ const files = diffSummary
35
+ .split('\n')
36
+ .filter((line) => line.trim().length > 0);
37
+ // Map files to packages
38
+ const affectedPackages = new Set();
39
+ for (const file of files) {
40
+ for (const pkg of workspacePackages) {
41
+ const relativePkgPath = pkg.path.replace(repoPath + '/', '');
42
+ // For single-package repos, pkg.path === repoPath, so relativePkgPath will be unchanged
43
+ // In that case, all files belong to the root package
44
+ if (relativePkgPath === pkg.path) {
45
+ // Root package - all files belong to it
46
+ affectedPackages.add(pkg.name);
47
+ }
48
+ else if (file.startsWith(relativePkgPath)) {
49
+ affectedPackages.add(pkg.name);
50
+ }
51
+ }
52
+ }
53
+ // Check for breaking changes
54
+ const breaking = parsed.notes.some((note) => note.title === 'BREAKING CHANGE') ||
55
+ commit.message.includes('!:');
56
+ commits.push({
57
+ hash: commit.hash,
58
+ type: parsed.type,
59
+ scope: parsed.scope,
60
+ subject: parsed.subject,
61
+ body: parsed.body,
62
+ breaking,
63
+ packages: Array.from(affectedPackages),
64
+ files,
65
+ });
66
+ }
67
+ // Return commits in chronological order (oldest first)
68
+ return commits.reverse();
69
+ }
70
+ //# sourceMappingURL=commits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commits.js","sourceRoot":"","sources":["../src/commits.ts"],"names":[],"mappings":"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"}
package/dist/git.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { WorkspacePackage } from './workspace.js';
2
+ export declare function createReleaseBranch(repoPath: string): Promise<string>;
3
+ export declare function updatePackageVersions(repoPath: string, newVersion: string, packages: WorkspacePackage[]): Promise<void>;
4
+ export declare function commitAndPush(repoPath: string, newVersion: string, push: boolean): Promise<void>;
5
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AA0BlD,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoB3E;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,gBAAgB,EAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC,IAAI,CAAC,CAiBf"}
package/dist/git.js ADDED
@@ -0,0 +1,79 @@
1
+ // ABOUTME: Handles git operations for creating release branches and commits
2
+ // ABOUTME: Updates package.json versions across workspace packages
3
+ import { simpleGit } from 'simple-git';
4
+ import { readFile, writeFile } from 'node:fs/promises';
5
+ import { join } from 'node:path';
6
+ async function ensureGitConfig(git) {
7
+ // Only configure if we're in GitHub Actions
8
+ if (!process.env.GITHUB_ACTIONS) {
9
+ return;
10
+ }
11
+ // Check if user.name is already configured locally (not global)
12
+ try {
13
+ const userName = await git.getConfig('user.name', 'local');
14
+ const userEmail = await git.getConfig('user.email', 'local');
15
+ // If both are configured locally, we're good
16
+ if (userName.value && userEmail.value) {
17
+ return;
18
+ }
19
+ }
20
+ catch (error) {
21
+ // Config not set, continue to set defaults
22
+ }
23
+ // Set github-actions[bot] as default (local config)
24
+ await git.addConfig('user.name', 'github-actions[bot]', false, 'local');
25
+ await git.addConfig('user.email', 'github-actions[bot]@users.noreply.github.com', false, 'local');
26
+ }
27
+ export async function createReleaseBranch(repoPath) {
28
+ const git = simpleGit(repoPath);
29
+ // Generate branch name with current date
30
+ const today = new Date().toISOString().split('T')[0];
31
+ const branchName = `release/${today}`;
32
+ // Check if branch already exists
33
+ const branches = await git.branchLocal();
34
+ if (branches.all.includes(branchName)) {
35
+ // Branch exists, switch to it and reset to main
36
+ await git.checkout(branchName);
37
+ await git.reset(['--hard', 'HEAD']);
38
+ }
39
+ else {
40
+ // Create new branch
41
+ await git.checkoutLocalBranch(branchName);
42
+ }
43
+ return branchName;
44
+ }
45
+ export async function updatePackageVersions(repoPath, newVersion, packages) {
46
+ // Update root package.json
47
+ const rootPath = join(repoPath, 'package.json');
48
+ const rootContent = await readFile(rootPath, 'utf-8');
49
+ const rootPackage = JSON.parse(rootContent);
50
+ rootPackage.version = newVersion;
51
+ await writeFile(rootPath, JSON.stringify(rootPackage, null, 2) + '\n');
52
+ // Update workspace packages (skip root if it's in the packages list)
53
+ for (const pkg of packages) {
54
+ // Skip if this package is the root (single-package repo)
55
+ if (pkg.path === repoPath) {
56
+ continue;
57
+ }
58
+ const pkgPath = join(pkg.path, 'package.json');
59
+ const pkgContent = await readFile(pkgPath, 'utf-8');
60
+ const pkgJson = JSON.parse(pkgContent);
61
+ pkgJson.version = newVersion;
62
+ await writeFile(pkgPath, JSON.stringify(pkgJson, null, 2) + '\n');
63
+ }
64
+ }
65
+ export async function commitAndPush(repoPath, newVersion, push) {
66
+ const git = simpleGit(repoPath);
67
+ // Ensure git is configured (auto-configure in GitHub Actions if needed)
68
+ await ensureGitConfig(git);
69
+ // Stage all changes
70
+ await git.add('.');
71
+ // Commit with release message
72
+ await git.commit(`release: ${newVersion}`);
73
+ if (push) {
74
+ // Push to remote (force push to update existing branch)
75
+ const currentBranch = await git.revparse(['--abbrev-ref', 'HEAD']);
76
+ await git.push('origin', currentBranch.trim(), ['--force', '--set-upstream']);
77
+ }
78
+ }
79
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export interface RepoInfo {
2
+ owner: string;
3
+ repo: string;
4
+ }
5
+ export declare function getRepoInfo(repoPath: string): Promise<RepoInfo>;
6
+ export declare function findExistingReleaseBranch(branches: Array<{
7
+ name: string;
8
+ }>): string | null;
9
+ export declare function createOrUpdatePR(repoPath: string, branchName: string, version: string, changelogSummary: string, token: string): Promise<string>;
10
+ //# sourceMappingURL=github.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAsBrE;AAED,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAChC,MAAM,GAAG,IAAI,CAGf;AAED,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,EACxB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CA0DjB"}
package/dist/github.js ADDED
@@ -0,0 +1,77 @@
1
+ // ABOUTME: Manages GitHub API interactions for PR creation and updates
2
+ // ABOUTME: Handles release branch detection and repository information extraction
3
+ import { Octokit } from '@octokit/rest';
4
+ import { simpleGit } from 'simple-git';
5
+ export async function getRepoInfo(repoPath) {
6
+ const git = simpleGit(repoPath);
7
+ const remotes = await git.getRemotes(true);
8
+ const origin = remotes.find((r) => r.name === 'origin');
9
+ if (!origin) {
10
+ throw new Error('No origin remote found');
11
+ }
12
+ const url = origin.refs.fetch || origin.refs.push || '';
13
+ // Parse GitHub URL (supports both HTTPS and SSH)
14
+ let match = url.match(/github\.com[:/]([^/]+)\/([^/.]+)(\.git)?$/);
15
+ if (!match) {
16
+ throw new Error(`Could not parse GitHub repo from remote URL: ${url}`);
17
+ }
18
+ return {
19
+ owner: match[1],
20
+ repo: match[2],
21
+ };
22
+ }
23
+ export function findExistingReleaseBranch(branches) {
24
+ const releaseBranch = branches.find((b) => b.name.startsWith('release/'));
25
+ return releaseBranch ? releaseBranch.name : null;
26
+ }
27
+ export async function createOrUpdatePR(repoPath, branchName, version, changelogSummary, token) {
28
+ const octokit = new Octokit({ auth: token });
29
+ const repoInfo = await getRepoInfo(repoPath);
30
+ // List all branches to find existing release PR
31
+ const { data: branches } = await octokit.repos.listBranches({
32
+ owner: repoInfo.owner,
33
+ repo: repoInfo.repo,
34
+ });
35
+ const existingReleaseBranch = findExistingReleaseBranch(branches);
36
+ // Get default branch (usually main or master)
37
+ const { data: repo } = await octokit.repos.get({
38
+ owner: repoInfo.owner,
39
+ repo: repoInfo.repo,
40
+ });
41
+ const baseBranch = repo.default_branch;
42
+ const title = `Release ${version}`;
43
+ const body = `## Release ${version}\n\n${changelogSummary}`;
44
+ if (existingReleaseBranch) {
45
+ // Find existing PR for this branch
46
+ const { data: prs } = await octokit.pulls.list({
47
+ owner: repoInfo.owner,
48
+ repo: repoInfo.repo,
49
+ head: `${repoInfo.owner}:${existingReleaseBranch}`,
50
+ base: baseBranch,
51
+ state: 'open',
52
+ });
53
+ if (prs.length > 0) {
54
+ // Update existing PR
55
+ const pr = prs[0];
56
+ await octokit.pulls.update({
57
+ owner: repoInfo.owner,
58
+ repo: repoInfo.repo,
59
+ pull_number: pr.number,
60
+ title,
61
+ body,
62
+ });
63
+ return pr.html_url;
64
+ }
65
+ }
66
+ // Create new PR
67
+ const { data: pr } = await octokit.pulls.create({
68
+ owner: repoInfo.owner,
69
+ repo: repoInfo.repo,
70
+ head: branchName,
71
+ base: baseBranch,
72
+ title,
73
+ body,
74
+ });
75
+ return pr.html_url;
76
+ }
77
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { CommitInfo } from './commits.js';
2
+ export type BumpType = 'major' | 'minor' | 'patch' | null;
3
+ export interface VersionBumpResult {
4
+ bumpType: BumpType;
5
+ newVersion: string | null;
6
+ }
7
+ export declare function calculateVersionBump(currentVersion: string, commits: CommitInfo[]): VersionBumpResult;
8
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC;AAE1D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAKD,wBAAgB,oBAAoB,CAClC,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,UAAU,EAAE,GACpB,iBAAiB,CAsCnB"}
@@ -0,0 +1,40 @@
1
+ // ABOUTME: Calculates version bumps based on conventional commit types
2
+ // ABOUTME: Determines major, minor, or patch semver increments
3
+ import semver from 'semver';
4
+ const RELEASE_TYPES = ['feat', 'fix', 'perf'];
5
+ const SKIP_TYPES = ['chore', 'docs', 'style', 'refactor', 'test', 'build', 'ci'];
6
+ export function calculateVersionBump(currentVersion, commits) {
7
+ if (commits.length === 0) {
8
+ return { bumpType: null, newVersion: null };
9
+ }
10
+ let bumpType = null;
11
+ // Check for breaking changes first (major bump)
12
+ const hasBreaking = commits.some((c) => c.breaking);
13
+ if (hasBreaking) {
14
+ bumpType = 'major';
15
+ }
16
+ else {
17
+ // Check for features (minor bump)
18
+ const hasFeat = commits.some((c) => c.type === 'feat');
19
+ if (hasFeat) {
20
+ bumpType = 'minor';
21
+ }
22
+ else {
23
+ // Check for fixes or performance improvements (patch bump)
24
+ const hasFix = commits.some((c) => c.type === 'fix' || c.type === 'perf');
25
+ if (hasFix) {
26
+ bumpType = 'patch';
27
+ }
28
+ }
29
+ }
30
+ // If only chore/docs/etc commits, don't bump
31
+ if (bumpType === null) {
32
+ return { bumpType: null, newVersion: null };
33
+ }
34
+ const newVersion = semver.inc(currentVersion, bumpType);
35
+ return {
36
+ bumpType,
37
+ newVersion,
38
+ };
39
+ }
40
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,+DAA+D;AAE/D,OAAO,MAAM,MAAM,QAAQ,CAAC;AAU5B,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAC9C,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;AAEjF,MAAM,UAAU,oBAAoB,CAClC,cAAsB,EACtB,OAAqB;IAErB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IAC9C,CAAC;IAED,IAAI,QAAQ,GAAa,IAAI,CAAC;IAE9B,gDAAgD;IAChD,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACpD,IAAI,WAAW,EAAE,CAAC;QAChB,QAAQ,GAAG,OAAO,CAAC;IACrB,CAAC;SAAM,CAAC;QACN,kCAAkC;QAClC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;QACvD,IAAI,OAAO,EAAE,CAAC;YACZ,QAAQ,GAAG,OAAO,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,2DAA2D;YAC3D,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CACzB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,CAC7C,CAAC;YACF,IAAI,MAAM,EAAE,CAAC;gBACX,QAAQ,GAAG,OAAO,CAAC;YACrB,CAAC;QACH,CAAC;IACH,CAAC;IAED,6CAA6C;IAC7C,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IAC9C,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;IAExD,OAAO;QACL,QAAQ;QACR,UAAU;KACX,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ export interface WorkspacePackage {
2
+ name: string;
3
+ version: string;
4
+ path: string;
5
+ }
6
+ export interface WorkspaceInfo {
7
+ rootVersion: string;
8
+ rootPath: string;
9
+ packages: WorkspacePackage[];
10
+ }
11
+ export declare function detectWorkspace(rootPath: string): Promise<WorkspaceInfo>;
12
+ //# sourceMappingURL=workspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAED,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAqE9E"}
@@ -0,0 +1,69 @@
1
+ // ABOUTME: Detects monorepo workspace configuration from pnpm-workspace.yaml or package.json
2
+ // ABOUTME: Resolves workspace packages and validates root package.json version
3
+ import { readFile } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ import { parse as parseYaml } from 'yaml';
6
+ import { glob } from 'glob';
7
+ export async function detectWorkspace(rootPath) {
8
+ // Read and validate root package.json
9
+ const rootPackageJsonPath = join(rootPath, 'package.json');
10
+ let rootPackageJson;
11
+ try {
12
+ const rootContent = await readFile(rootPackageJsonPath, 'utf-8');
13
+ rootPackageJson = JSON.parse(rootContent);
14
+ }
15
+ catch (error) {
16
+ throw new Error('root package.json not found');
17
+ }
18
+ if (!rootPackageJson.version) {
19
+ throw new Error('root package.json must have a version field');
20
+ }
21
+ // Try to read pnpm-workspace.yaml first
22
+ let workspacePatterns = [];
23
+ try {
24
+ const pnpmWorkspacePath = join(rootPath, 'pnpm-workspace.yaml');
25
+ const pnpmContent = await readFile(pnpmWorkspacePath, 'utf-8');
26
+ const pnpmConfig = parseYaml(pnpmContent);
27
+ workspacePatterns = pnpmConfig.packages || [];
28
+ }
29
+ catch (error) {
30
+ // If pnpm-workspace.yaml doesn't exist, try package.json workspaces
31
+ if (rootPackageJson.workspaces) {
32
+ workspacePatterns = Array.isArray(rootPackageJson.workspaces)
33
+ ? rootPackageJson.workspaces
34
+ : rootPackageJson.workspaces.packages || [];
35
+ }
36
+ }
37
+ // Resolve workspace packages
38
+ const packages = [];
39
+ for (const pattern of workspacePatterns) {
40
+ const packagePaths = await glob(join(pattern, 'package.json'), {
41
+ cwd: rootPath,
42
+ absolute: true,
43
+ });
44
+ for (const packageJsonPath of packagePaths) {
45
+ const packageContent = await readFile(packageJsonPath, 'utf-8');
46
+ const packageJson = JSON.parse(packageContent);
47
+ const packagePath = packageJsonPath.replace(/\/package\.json$/, '');
48
+ packages.push({
49
+ name: packageJson.name,
50
+ version: packageJson.version,
51
+ path: packagePath,
52
+ });
53
+ }
54
+ }
55
+ // If no workspace packages found, treat root as the package
56
+ if (packages.length === 0) {
57
+ packages.push({
58
+ name: rootPackageJson.name,
59
+ version: rootPackageJson.version,
60
+ path: rootPath,
61
+ });
62
+ }
63
+ return {
64
+ rootVersion: rootPackageJson.version,
65
+ rootPath,
66
+ packages,
67
+ };
68
+ }
69
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "just-release",
3
+ "version": "0.3.0",
4
+ "description": "Automated monorepo release tool with conventional commits",
5
+ "type": "module",
6
+ "bin": {
7
+ "just-release": "./dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md"
12
+ ],
13
+ "keywords": [
14
+ "monorepo",
15
+ "release",
16
+ "conventional-commits",
17
+ "changelog"
18
+ ],
19
+ "author": "",
20
+ "license": "ISC",
21
+ "dependencies": {
22
+ "@octokit/rest": "^22.0.1",
23
+ "conventional-commits-parser": "^6.2.1",
24
+ "glob": "^11.0.3",
25
+ "semver": "^7.7.3",
26
+ "simple-git": "^3.30.0",
27
+ "yaml": "^2.8.1"
28
+ },
29
+ "devDependencies": {
30
+ "@types/conventional-commits-parser": "^5.0.2",
31
+ "@types/node": "^24.10.0",
32
+ "@types/semver": "^7.7.1",
33
+ "tsx": "^4.20.6",
34
+ "typescript": "^5.9.3"
35
+ },
36
+ "scripts": {
37
+ "build": "tsc",
38
+ "dev": "tsc --watch",
39
+ "test": "node --import tsx --test 'src/**/*.test.ts'"
40
+ }
41
+ }