mirror of
https://github.com/WeBankFinTech/fes.js.git
synced 2025-04-05 19:41:57 +08:00
feat: 优化 release 流程
This commit is contained in:
parent
366c4900e3
commit
40bbb7d1d2
@ -4,6 +4,10 @@ module.exports = {
|
||||
'create-fes-app',
|
||||
'fes',
|
||||
'fes-compiler',
|
||||
'fes-build-vite',
|
||||
'fes-build-webpack',
|
||||
'fes-runtime',
|
||||
'fes-utils',
|
||||
'fes-plugin-access',
|
||||
'fes-plugin-enums',
|
||||
'fes-plugin-icon',
|
||||
@ -19,10 +23,6 @@ module.exports = {
|
||||
'fes-plugin-pinia',
|
||||
'fes-preset-built-in',
|
||||
'fes-plugin-windicss',
|
||||
'fes-runtime',
|
||||
'fes-utils',
|
||||
'fes-build-webpack',
|
||||
'fes-build-vite',
|
||||
],
|
||||
copy: [],
|
||||
};
|
||||
|
18
package.json
18
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "fes.js",
|
||||
"version": "2.0.0",
|
||||
"version": "2.1.0",
|
||||
"description": "一个好用的前端管理台快速开发框架",
|
||||
"preferGlobal": true,
|
||||
"private": true,
|
||||
@ -8,16 +8,14 @@
|
||||
"packages/*"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "lerna clean",
|
||||
"bootstrap": "lerna bootstrap",
|
||||
"dev": "node scripts/build.js --watch",
|
||||
"build": "node scripts/build.js",
|
||||
"ver": "lerna version --conventional-prerelease --no-changelog --no-commit-hooks --no-private",
|
||||
"release": "node scripts/build.js && lerna publish from-git",
|
||||
"release": "node scripts/release.mjs",
|
||||
"docs:dev": "vuepress dev docs --clean-cache",
|
||||
"docs:build": "vuepress build docs --clean-cache",
|
||||
"test": "fes test",
|
||||
"lint": "eslint -c ./.eslintrc.js --ext .js,.jsx,.vue,.ts"
|
||||
"lint": "eslint -c ./.eslintrc.js --ext .js,.jsx,.vue,.ts",
|
||||
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
|
||||
},
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
@ -28,7 +26,12 @@
|
||||
"strong"
|
||||
],
|
||||
"dependencies": {
|
||||
"lerna": "^4.0.0",
|
||||
"chalk": "^5.0.1",
|
||||
"conventional-changelog-cli": "^2.2.2",
|
||||
"enquirer": "^2.3.6",
|
||||
"execa": "^6.1.0",
|
||||
"minimist": "^1.2.6",
|
||||
"semver": "^7.3.6",
|
||||
"vuepress": "^2.0.0-beta.37"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -42,7 +45,6 @@
|
||||
"@vuepress/plugin-pwa": "^2.0.0-beta.37",
|
||||
"@vuepress/plugin-pwa-popup": "^2.0.0-beta.37",
|
||||
"@webank/eslint-config-webank": "^1.2.0",
|
||||
"chalk": "^4.1.2",
|
||||
"chokidar": "^3.5.2",
|
||||
"commitizen": "^4.2.1",
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
|
229
scripts/release.mjs
Normal file
229
scripts/release.mjs
Normal file
@ -0,0 +1,229 @@
|
||||
import minimist from 'minimist';
|
||||
import fs from 'fs';
|
||||
import * as url from 'url';
|
||||
import path from 'path';
|
||||
import chalk from 'chalk';
|
||||
import semver from 'semver';
|
||||
import enquirer from 'enquirer';
|
||||
import { execa } from 'execa';
|
||||
|
||||
// eslint-disable-next-line import/extensions
|
||||
import buildConfig from '../build.config.js';
|
||||
|
||||
const { prompt } = enquirer;
|
||||
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
||||
|
||||
const { preid: preId, dry: isDryRun, tag: releaseTag } = minimist(process.argv.slice(2));
|
||||
const packages = buildConfig.pkgs;
|
||||
|
||||
const versionIncrements = ['patch', 'minor', 'major', ...(preId ? ['prepatch', 'preminor', 'premajor', 'prerelease'] : [])];
|
||||
|
||||
const incVersion = (version, i) => semver.inc(version, i, preId);
|
||||
const run = (bin, args, opts = {}) => execa(bin, args, { stdio: 'inherit', ...opts });
|
||||
const dryRun = (bin, args, opts = {}) => console.log(chalk.blue(`[dryrun] ${bin} ${args.join(' ')}`), opts);
|
||||
const runIfNotDry = isDryRun ? dryRun : run;
|
||||
const getPkgRoot = (pkg) => path.resolve(__dirname, `../packages/${pkg}`);
|
||||
const step = (msg) => console.log(chalk.cyan(msg));
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
async function publishPackage(pkg, runIfNotDry) {
|
||||
let _releaseTag;
|
||||
if (releaseTag) {
|
||||
_releaseTag = releaseTag;
|
||||
} else if (pkg.newVersion.includes('alpha')) {
|
||||
_releaseTag = 'alpha';
|
||||
} else if (pkg.newVersion.includes('beta')) {
|
||||
_releaseTag = 'beta';
|
||||
} else if (pkg.newVersion.includes('rc')) {
|
||||
_releaseTag = 'rc';
|
||||
}
|
||||
|
||||
step(`Publishing ${pkg.name}...`);
|
||||
try {
|
||||
await runIfNotDry(
|
||||
// note: use of yarn is intentional here as we rely on its publishing
|
||||
// behavior.
|
||||
'yarn',
|
||||
[
|
||||
'publish',
|
||||
'--new-version',
|
||||
pkg.version,
|
||||
...(_releaseTag ? ['--tag', _releaseTag] : []),
|
||||
'--access',
|
||||
'public',
|
||||
'--registry',
|
||||
'https://registry.npmjs.org',
|
||||
],
|
||||
{
|
||||
cwd: getPkgRoot(pkg.dirName),
|
||||
stdio: 'pipe',
|
||||
},
|
||||
);
|
||||
console.log(chalk.green(`Successfully published ${pkg.name}@${pkg.newVersion}`));
|
||||
} catch (e) {
|
||||
if (e.stderr.match(/previously published/)) {
|
||||
console.log(chalk.red(`Skipping already published: ${pkg.name}`));
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function readPackageJson(pkg) {
|
||||
const pkgPath = path.resolve(getPkgRoot(pkg), 'package.json');
|
||||
return JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
||||
}
|
||||
|
||||
function genRootPackageVersion() {
|
||||
const pkgPath = path.resolve(path.resolve(__dirname, '..'), 'package.json');
|
||||
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
||||
return semver.inc(pkg.version, 'patch');
|
||||
}
|
||||
|
||||
function readPackageVersionAndName(pkg) {
|
||||
const { version, name } = readPackageJson(pkg);
|
||||
return {
|
||||
version,
|
||||
name,
|
||||
};
|
||||
}
|
||||
|
||||
function updatePackage(pkgRoot, version) {
|
||||
const pkgPath = path.resolve(pkgRoot, 'package.json');
|
||||
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
||||
pkg.version = version;
|
||||
fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
||||
}
|
||||
|
||||
function updateVersions(packagesVersion, newRootVersion) {
|
||||
// 1. update root package.json
|
||||
updatePackage(path.resolve(__dirname, '..'), newRootVersion);
|
||||
// 2. update all packages
|
||||
packagesVersion.forEach((p) => updatePackage(getPkgRoot(p.dirName), p.newVersion));
|
||||
}
|
||||
|
||||
const isChangeInCurrentTag = async (pkg, newestTag) => {
|
||||
const { stdout: pkgDiffContent } = await run('git', ['diff', newestTag, `packages/${pkg}`], { stdio: 'pipe' });
|
||||
return !!pkgDiffContent;
|
||||
};
|
||||
|
||||
const filterChangedPackages = async () => {
|
||||
const { stdout: newestTag } = await run('git', ['describe', '--abbrev=0', '--tags'], { stdio: 'pipe' });
|
||||
|
||||
return packages.filter(async (pkg) => {
|
||||
const result = await isChangeInCurrentTag(pkg, newestTag);
|
||||
return result;
|
||||
});
|
||||
};
|
||||
|
||||
async function createPackageNewVersion(pkg) {
|
||||
const { name, version } = readPackageVersionAndName(pkg);
|
||||
|
||||
// no explicit version, offer suggestions
|
||||
const { release } = await prompt({
|
||||
type: 'select',
|
||||
name: 'release',
|
||||
message: `Select release type: ${name}`,
|
||||
choices: versionIncrements.map((i) => `${i} (${incVersion(version, i)})`).concat(['custom']),
|
||||
});
|
||||
|
||||
let newVersion;
|
||||
if (release === 'custom') {
|
||||
newVersion = (
|
||||
await prompt({
|
||||
type: 'input',
|
||||
name: 'version',
|
||||
message: `Input custom version: ${name}`,
|
||||
initial: version,
|
||||
})
|
||||
).version;
|
||||
} else {
|
||||
newVersion = release.match(/\((.*)\)/)[1];
|
||||
}
|
||||
|
||||
if (!semver.valid(newVersion)) {
|
||||
console.log(`invalid target version: ${newVersion}, please again.`);
|
||||
return createPackageNewVersion(pkg);
|
||||
}
|
||||
|
||||
return newVersion;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const changedPackages = await filterChangedPackages();
|
||||
|
||||
if (!changedPackages.length) {
|
||||
console.log(chalk.yellow(`No changes to commit.`));
|
||||
return;
|
||||
}
|
||||
|
||||
const packagesVersion = [];
|
||||
for (const pkg of changedPackages) {
|
||||
const newVersion = await createPackageNewVersion(pkg);
|
||||
packagesVersion.push({
|
||||
dirName: pkg,
|
||||
newVersion,
|
||||
...readPackageVersionAndName(pkg),
|
||||
});
|
||||
}
|
||||
|
||||
const { yes } = await prompt({
|
||||
type: 'confirm',
|
||||
name: 'yes',
|
||||
message: `These packages will be released: \n${packagesVersion
|
||||
.map((pkg) => `${chalk.magenta(pkg.name)}: v${pkg.version} > ${chalk.green(`v${pkg.newVersion}`)}`)
|
||||
.join('\n')}\nConfirm?`,
|
||||
});
|
||||
|
||||
if (!yes) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newRootVersion = genRootPackageVersion();
|
||||
|
||||
// update all package versions and inter-dependencies
|
||||
step('\nUpdating cross dependencies...');
|
||||
updateVersions(packagesVersion, newRootVersion);
|
||||
|
||||
// // build all packages with types
|
||||
step('\nBuilding all packages...');
|
||||
if (!isDryRun) {
|
||||
await run('yarn', ['build']);
|
||||
} else {
|
||||
console.log(`(skipped build)`);
|
||||
}
|
||||
|
||||
// generate changelog
|
||||
step('\nGenerating changelog...');
|
||||
await run(`yarn`, ['changelog']);
|
||||
|
||||
const { stdout } = await run('git', ['diff'], { stdio: 'pipe' });
|
||||
if (stdout) {
|
||||
step('\nCommitting changes...');
|
||||
await runIfNotDry('git', ['add', '-A']);
|
||||
await runIfNotDry('git', ['commit', '-m', `release: v${newRootVersion}`]);
|
||||
} else {
|
||||
console.log('No changes to commit.');
|
||||
}
|
||||
|
||||
// publish packages
|
||||
step('\nPublishing packages...');
|
||||
for (const pkg of packagesVersion) {
|
||||
await publishPackage(pkg, runIfNotDry);
|
||||
}
|
||||
|
||||
// push to GitHub
|
||||
step('\nPushing to GitHub...');
|
||||
await runIfNotDry('git', ['tag', `v${newRootVersion}`]);
|
||||
await runIfNotDry('git', ['push', 'origin', `refs/tags/v${newRootVersion}`]);
|
||||
await runIfNotDry('git', ['push']);
|
||||
|
||||
if (isDryRun) {
|
||||
console.log(`\nDry run finished - run git diff to see package changes.`);
|
||||
}
|
||||
console.log();
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err);
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user