159 lines
5.3 KiB
JavaScript
Executable File
159 lines
5.3 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
||
|
||
const { execSync } = require('child_process');
|
||
const { readFileSync, writeFileSync } = require('fs');
|
||
const path = require('path');
|
||
const readline = require('readline');
|
||
|
||
/**
|
||
* 发布正式版本到 npm
|
||
* 使用 latest tag,支持语义化版本升级
|
||
*/
|
||
async function publishRelease() {
|
||
const rl = readline.createInterface({
|
||
input: process.stdin,
|
||
output: process.stdout
|
||
});
|
||
|
||
const question = (query) => new Promise(resolve => rl.question(query, resolve));
|
||
|
||
try {
|
||
console.log('🚀 Starting production release process...\n');
|
||
|
||
// 1. 确保在主分支
|
||
const currentBranch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim();
|
||
if (currentBranch !== 'main' && currentBranch !== 'master') {
|
||
console.log('⚠️ Not on main/master branch. Current branch:', currentBranch);
|
||
const proceed = await question('Continue anyway? (y/N): ');
|
||
if (proceed.toLowerCase() !== 'y') {
|
||
console.log('❌ Cancelled');
|
||
process.exit(0);
|
||
}
|
||
}
|
||
|
||
// 2. 检查工作区是否干净
|
||
try {
|
||
execSync('git diff --exit-code', { stdio: 'ignore' });
|
||
execSync('git diff --cached --exit-code', { stdio: 'ignore' });
|
||
console.log('✅ Working directory is clean');
|
||
} catch {
|
||
console.log('❌ Working directory has uncommitted changes');
|
||
console.log('Please commit or stash your changes before releasing');
|
||
process.exit(1);
|
||
}
|
||
|
||
// 3. 拉取最新代码
|
||
console.log('📡 Pulling latest changes...');
|
||
execSync('git pull origin ' + currentBranch, { stdio: 'inherit' });
|
||
|
||
// 4. 读取当前版本
|
||
const packagePath = path.join(process.cwd(), 'package.json');
|
||
const packageJson = JSON.parse(readFileSync(packagePath, 'utf8'));
|
||
const currentVersion = packageJson.version;
|
||
|
||
console.log(`📦 Current version: ${currentVersion}`);
|
||
|
||
// 5. 选择版本升级类型
|
||
console.log('\n🔢 Version bump options:');
|
||
const versionParts = currentVersion.split('.');
|
||
const major = parseInt(versionParts[0]);
|
||
const minor = parseInt(versionParts[1]);
|
||
const patch = parseInt(versionParts[2]);
|
||
|
||
console.log(` 1. patch → ${major}.${minor}.${patch + 1} (bug fixes)`);
|
||
console.log(` 2. minor → ${major}.${minor + 1}.0 (new features)`);
|
||
console.log(` 3. major → ${major + 1}.0.0 (breaking changes)`);
|
||
console.log(` 4. custom → enter custom version`);
|
||
|
||
const choice = await question('\nSelect version bump (1-4): ');
|
||
|
||
let newVersion;
|
||
switch (choice) {
|
||
case '1':
|
||
newVersion = `${major}.${minor}.${patch + 1}`;
|
||
break;
|
||
case '2':
|
||
newVersion = `${major}.${minor + 1}.0`;
|
||
break;
|
||
case '3':
|
||
newVersion = `${major + 1}.0.0`;
|
||
break;
|
||
case '4':
|
||
newVersion = await question('Enter custom version: ');
|
||
break;
|
||
default:
|
||
console.log('❌ Invalid choice');
|
||
process.exit(1);
|
||
}
|
||
|
||
// 6. 确认发布
|
||
console.log(`\n📋 Release Summary:`);
|
||
console.log(` Current: ${currentVersion}`);
|
||
console.log(` New: ${newVersion}`);
|
||
console.log(` Branch: ${currentBranch}`);
|
||
console.log(` Tag: latest`);
|
||
|
||
const confirm = await question('\n🤔 Proceed with release? (y/N): ');
|
||
if (confirm.toLowerCase() !== 'y') {
|
||
console.log('❌ Cancelled');
|
||
process.exit(0);
|
||
}
|
||
|
||
// 7. 更新版本号
|
||
console.log('📝 Updating version...');
|
||
packageJson.version = newVersion;
|
||
writeFileSync(packagePath, JSON.stringify(packageJson, null, 2));
|
||
|
||
// 8. 运行测试
|
||
console.log('🧪 Running tests...');
|
||
try {
|
||
execSync('npm run typecheck', { stdio: 'inherit' });
|
||
execSync('npm test', { stdio: 'inherit' });
|
||
} catch (error) {
|
||
console.log('❌ Tests failed, rolling back version...');
|
||
packageJson.version = currentVersion;
|
||
writeFileSync(packagePath, JSON.stringify(packageJson, null, 2));
|
||
process.exit(1);
|
||
}
|
||
|
||
// 9. 构建项目
|
||
console.log('🔨 Building project...');
|
||
execSync('npm run build', { stdio: 'inherit' });
|
||
|
||
// 10. 运行预发布检查
|
||
console.log('🔍 Running pre-publish checks...');
|
||
execSync('node scripts/prepublish-check.js', { stdio: 'inherit' });
|
||
|
||
// 11. 提交版本更新
|
||
console.log('📝 Committing version update...');
|
||
execSync('git add package.json');
|
||
execSync(`git commit -m "chore: bump version to ${newVersion}"`);
|
||
|
||
// 12. 创建 git tag
|
||
console.log('🏷️ Creating git tag...');
|
||
execSync(`git tag -a v${newVersion} -m "Release ${newVersion}"`);
|
||
|
||
// 13. 发布到 npm
|
||
console.log('📤 Publishing to npm...');
|
||
execSync('npm publish --access public', { stdio: 'inherit' });
|
||
|
||
// 14. 推送到 git
|
||
console.log('📡 Pushing to git...');
|
||
execSync(`git push origin ${currentBranch}`);
|
||
execSync(`git push origin v${newVersion}`);
|
||
|
||
console.log('\n🎉 Production release published successfully!');
|
||
console.log(`📦 Version: ${newVersion}`);
|
||
console.log(`🔗 Install with: npm install -g @shareai-lab/kode`);
|
||
console.log(`🔗 Or: npm install -g @shareai-lab/kode@${newVersion}`);
|
||
console.log(`📊 View on npm: https://www.npmjs.com/package/@shareai-lab/kode`);
|
||
|
||
} catch (error) {
|
||
console.error('❌ Production release failed:', error.message);
|
||
process.exit(1);
|
||
} finally {
|
||
rl.close();
|
||
}
|
||
}
|
||
|
||
publishRelease(); |