-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Expand file tree
/
Copy pathversion.js
More file actions
163 lines (128 loc) · 5.4 KB
/
Copy pathversion.js
File metadata and controls
163 lines (128 loc) · 5.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#!/usr/bin/env node
import { execFileSync, execSync } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import semver from 'semver';
import { assertValidNpmPackageName, getPublishablePackages } from './utils.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Get command line arguments
const args = process.argv.slice(2);
const versionType = args[0];
const isDryRun = args.includes('--dry-run');
// Get prerelease tag if provided
let prereleaseTag = 'beta'; // default
const prereleaseArg = args.find((arg) => arg.startsWith('--prerelease-tag='));
if (prereleaseArg) {
prereleaseTag = prereleaseArg.split('=')[1];
}
const validVersionTypes = ['major', 'minor', 'patch', 'prerelease', 'prepatch', 'preminor', 'premajor'];
const validPrereleaseTags = ['alpha', 'beta', 'rc'];
if (!validVersionTypes.includes(versionType)) {
console.error(
`Usage: node scripts/version.js [${validVersionTypes.join('|')}] [--prerelease-tag=alpha|beta|rc] [--dry-run]`,
);
process.exit(1);
}
if (versionType.includes('pre') && !validPrereleaseTags.includes(prereleaseTag)) {
console.error(`Invalid prerelease tag: ${prereleaseTag}. Must be one of: ${validPrereleaseTags.join(', ')}`);
process.exit(1);
}
// Check if git working directory is clean
try {
const status = execSync('git status --porcelain', { encoding: 'utf8' });
if (status.trim() && !isDryRun) {
console.error('Git working directory is not clean. Please commit or stash your changes first.');
process.exit(1);
}
} catch (error) {
console.error('Failed to check git status:', error.message);
process.exit(1);
}
const baseDir = path.join(__dirname, '..');
const packageFolders = getPublishablePackages(baseDir);
console.log(`🚀 ${isDryRun ? '[DRY RUN] ' : ''}Bumping ${versionType} version for all packages...`);
const updatedVersions = [];
// Backup original package.json files if not dry run
const backups = [];
// Update each package version
packageFolders.forEach(({ folder, directory }) => {
const packageJsonPath = path.join(baseDir, directory, folder, 'package.json');
if (fs.existsSync(packageJsonPath)) {
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
assertValidNpmPackageName(packageJson.name);
const originalContent = JSON.stringify(packageJson, null, 2) + '\n';
if (!isDryRun) {
backups.push({ path: packageJsonPath, content: originalContent });
}
const currentVersion = packageJson.version;
let newVersion;
if (versionType.includes('pre')) {
// For prerelease versions, pass the prerelease tag
newVersion = semver.inc(currentVersion, versionType, prereleaseTag);
} else {
newVersion = semver.inc(currentVersion, versionType);
}
packageJson.version = newVersion;
if (!isDryRun) {
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
}
updatedVersions.push({
name: packageJson.name,
oldVersion: currentVersion,
newVersion: newVersion,
});
console.log(` 📦 ${packageJson.name}: ${currentVersion} → ${newVersion}`);
}
});
// Update root package.json version (use egg's version as reference)
const eggVersion = updatedVersions.find((pkg) => pkg.name === 'egg')?.newVersion;
if (eggVersion) {
const rootPackageJsonPath = path.join(__dirname, '..', 'package.json');
const rootPackageJson = JSON.parse(fs.readFileSync(rootPackageJsonPath, 'utf8'));
const oldRootVersion = rootPackageJson.version;
if (!isDryRun) {
backups.push({
path: rootPackageJsonPath,
content: JSON.stringify(rootPackageJson, null, 2) + '\n',
});
rootPackageJson.version = eggVersion;
fs.writeFileSync(rootPackageJsonPath, JSON.stringify(rootPackageJson, null, 2) + '\n');
}
console.log(` 📦 @eggjs/monorepo: ${oldRootVersion} → ${eggVersion}`);
}
if (isDryRun) {
console.log('\n✅ Dry run complete! No changes were made.');
console.log('\nTo apply these changes, run:');
console.log(` ut run version:${versionType}`);
process.exit(0);
}
try {
// Stage all changes
console.log('\n📝 Staging changes...');
execSync('git add .', { stdio: 'inherit' });
// Create commit message with [skip ci] to avoid triggering CI for release commits
const commitMessage = `chore(release): ${versionType} version bump
${updatedVersions.map((pkg) => `- ${pkg.name}@${pkg.newVersion}`).join('\n')}`;
// Commit changes. Pass the message as an argv entry (execFileSync), never as
// an interpolated shell string — the message embeds package names.
console.log('\n💾 Creating version commit...');
execFileSync('git', ['commit', '-m', commitMessage], { stdio: 'inherit' });
// Create tag using the main egg version
const tagName = `v${eggVersion}`;
console.log(`\n🏷️ Creating tag ${tagName}...`);
execFileSync('git', ['tag', tagName], { stdio: 'inherit' });
console.log('\n✅ Version bump complete!');
console.log(`\nTo publish, push the changes and tag:`);
console.log(` git push origin HEAD --tags`);
console.log(`\nOr trigger the manual release workflow in GitHub Actions.`);
} catch (error) {
console.error('\n❌ Error during git operations:', error.message);
// Restore backup files
console.log('🔄 Restoring original files...');
backups.forEach((backup) => {
fs.writeFileSync(backup.path, backup.content);
});
process.exit(1);
}