@fesjs/fes-design
Version:
fes-design for PC
174 lines (149 loc) • 4.78 kB
JavaScript
import fs from 'node:fs';
import path from 'node:path';
import process from 'node:process';
import minimist from 'minimist';
import chalk from 'chalk';
import semver from 'semver';
import enquirer from 'enquirer';
import execa from 'execa';
import {
getProjectRootDir,
getPackageJsonVersion,
loadJsonFile,
} from './utils.js';
const prompt = enquirer.prompt;
const args = minimist(process.argv.slice(2));
const rootDir = getProjectRootDir();
const packageJsonPath = path.join(rootDir, './package.json');
const currentVersion = getPackageJsonVersion();
const preId =
args.preid ||
(semver.prerelease(currentVersion) && semver.prerelease(currentVersion)[0]);
const skipBuild = args.skipBuild;
const versionIncrements = [
'patch',
'minor',
'major',
...(preId ? ['prepatch', 'preminor', 'premajor', 'prerelease'] : []),
];
const inc = (i) => semver.inc(currentVersion, i, preId);
const run = (rBin, rArgs, opts = {}) =>
execa(rBin, rArgs, { stdio: 'inherit', ...opts });
const step = (msg) => console.log(chalk.cyan(msg));
function updatePackage(version) {
const pkg = loadJsonFile(packageJsonPath);
pkg.version = version;
fs.writeFileSync(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`);
}
function updateVersions(version) {
// 1. update root package.json
updatePackage(version);
}
async function publish(version) {
let releaseTag = null;
if (args.tag) {
releaseTag = args.tag;
} else if (version.includes('alpha')) {
releaseTag = 'alpha';
} else if (version.includes('beta')) {
releaseTag = 'beta';
} else if (version.includes('rc')) {
releaseTag = 'rc';
}
step(`Publishing...`);
try {
await run(
// note: use of yarn is intentional here as we rely on its publishing
// behavior.
'npm',
[
'publish',
...(releaseTag ? ['--tag', releaseTag] : []),
'--access',
'public',
'--registry',
'https://registry.npmjs.org',
],
);
console.log(chalk.green(`Successfully published ${version}`));
} catch (e) {
if (e.stderr.match(/previously published/)) {
console.log(chalk.red(`Skipping already published`));
} else {
throw e;
}
}
}
async function main() {
let targetVersion = args._[0];
if (!targetVersion) {
// no explicit version, offer suggestions
const { release } = await prompt({
type: 'select',
name: 'release',
message: 'Select release type',
choices: versionIncrements
.map((i) => `${i} (${inc(i)})`)
.concat(['custom']),
});
if (release === 'custom') {
targetVersion = (
await prompt({
type: 'input',
name: 'version',
message: 'Input custom version',
initial: currentVersion,
})
).version;
} else {
targetVersion = release.match(/\((.*)\)/)?.[1];
}
}
if (!semver.valid(targetVersion)) {
throw new Error(`invalid target version: ${targetVersion}`);
}
const { yes } = await prompt({
type: 'confirm',
name: 'yes',
message: `Releasing v${targetVersion}. Confirm?`,
});
if (!yes) {
return;
}
// update all package versions and inter-dependencies
step('\nUpdating cross dependencies...');
updateVersions(targetVersion);
// build all packages with types
step('\nBuilding all packages...');
if (!skipBuild) {
await run('pnpm', ['run', 'build']);
} else {
console.log(`(skipped)`);
}
// generate changelog
step('\nGenerating changelog...');
await run(`pnpm`, ['run', 'changelog']);
// update pnpm-lock.yaml
step('\nUpdating lockfile...');
await run(`pnpm`, ['install', '--prefer-offline']);
const { stdout } = await run('git', ['diff'], { stdio: 'pipe' });
if (stdout) {
step('\nCommitting changes...');
await run('git', ['add', '-A']);
await run('git', ['commit', '-m', `release: v${targetVersion}`]);
} else {
console.log('No changes to commit.');
}
// publish packages
step('\nPublishing...');
await publish(targetVersion);
// push to GitHub
step('\nPushing to GitHub...');
await run('git', ['tag', `v${targetVersion}`]);
await run('git', ['push', 'origin', `refs/tags/v${targetVersion}`]);
await run('git', ['push']);
console.log();
}
main().catch((err) => {
console.error(err);
});