mirror of
				https://github.com/Tencent/tmagic-editor.git
				synced 2025-11-04 10:49:51 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			215 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			215 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
const args = require('minimist')(process.argv.slice(2));
 | 
						|
const fs = require('fs');
 | 
						|
const path = require('path');
 | 
						|
const chalk = require('chalk');
 | 
						|
const semver = require('semver');
 | 
						|
const currentVersion = require('../package.json').version;
 | 
						|
const { prompt } = require('enquirer');
 | 
						|
const execa = require('execa');
 | 
						|
 | 
						|
const preId = args.preid || (semver.prerelease(currentVersion) && semver.prerelease(currentVersion)[0]);
 | 
						|
const isDryRun = args.dry;
 | 
						|
const { skipTests } = args;
 | 
						|
const { skipBuild } = args;
 | 
						|
const packages = fs
 | 
						|
  .readdirSync(path.resolve(__dirname, '../packages'))
 | 
						|
  .filter((p) => !p.endsWith('.ts') && !p.startsWith('.'));
 | 
						|
 | 
						|
const skippedPackages = [];
 | 
						|
 | 
						|
const versionIncrements = [
 | 
						|
  'patch',
 | 
						|
  'minor',
 | 
						|
  'major',
 | 
						|
  ...(preId ? ['prepatch', 'preminor', 'premajor', 'prerelease'] : []),
 | 
						|
];
 | 
						|
 | 
						|
const inc = (i) => semver.inc(currentVersion, 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 getRunTimeRoot = (pkg) => path.resolve(__dirname, `../runtime/${pkg}`);
 | 
						|
const getPlayground = () => path.resolve(__dirname, `../playground`);
 | 
						|
const getDocs = () => path.resolve(__dirname, `../docs`);
 | 
						|
const step = (msg) => console.log(chalk.cyan(msg));
 | 
						|
 | 
						|
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(/\((.*)\)/);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  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;
 | 
						|
  }
 | 
						|
 | 
						|
  // run tests before release
 | 
						|
  step('\nRunning tests...');
 | 
						|
  if (!skipTests && !isDryRun) {
 | 
						|
    await run('pnpm', ['test']);
 | 
						|
  } else {
 | 
						|
    console.log(`(skipped)`);
 | 
						|
  }
 | 
						|
 | 
						|
  // update all package versions and inter-dependencies
 | 
						|
  step('\nUpdating cross dependencies...');
 | 
						|
  updateVersions(targetVersion);
 | 
						|
 | 
						|
  // build all packages with types
 | 
						|
  step('\nBuilding all packages...');
 | 
						|
  if (!skipBuild && !isDryRun) {
 | 
						|
    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 runIfNotDry('git', ['add', '-A']);
 | 
						|
    await runIfNotDry('git', ['commit', '-m', `chore: release v${targetVersion}`]);
 | 
						|
  } else {
 | 
						|
    console.log('No changes to commit.');
 | 
						|
  }
 | 
						|
 | 
						|
  // publish packages
 | 
						|
  step('\nPublishing packages...');
 | 
						|
  for (const pkg of packages) {
 | 
						|
    await publishPackage(pkg, targetVersion, runIfNotDry);
 | 
						|
  }
 | 
						|
 | 
						|
  // push to GitHub
 | 
						|
  step('\nPushing to GitHub...');
 | 
						|
  await runIfNotDry('git', ['tag', `v${targetVersion}`]);
 | 
						|
  await runIfNotDry('git', ['push']);
 | 
						|
 | 
						|
  if (isDryRun) {
 | 
						|
    console.log(`\nDry run finished - run git diff to see package changes.`);
 | 
						|
  }
 | 
						|
 | 
						|
  if (skippedPackages.length) {
 | 
						|
    console.log(
 | 
						|
      chalk.yellow(`The following packages are skipped and NOT published:\n- ${skippedPackages.join('\n- ')}`),
 | 
						|
    );
 | 
						|
  }
 | 
						|
  console.log();
 | 
						|
}
 | 
						|
 | 
						|
function updateVersions(version) {
 | 
						|
  // 1. update root package.json
 | 
						|
  updatePackage(path.resolve(__dirname, '..'), version);
 | 
						|
  // 2. update all packages
 | 
						|
  packages.forEach((p) => updatePackage(getPkgRoot(p), version));
 | 
						|
  ['vue3', 'react', 'vue2'].forEach((p) => updatePackage(getRunTimeRoot(p), version));
 | 
						|
  updatePackage(getPlayground(), version);
 | 
						|
  updatePackage(getDocs(), version);
 | 
						|
}
 | 
						|
 | 
						|
function updatePackage(pkgRoot, version) {
 | 
						|
  const pkgPath = path.resolve(pkgRoot, 'package.json');
 | 
						|
  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
 | 
						|
  pkg.version = version;
 | 
						|
  updateDeps(pkg, 'dependencies', version);
 | 
						|
  updateDeps(pkg, 'peerDependencies', version);
 | 
						|
  fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
 | 
						|
}
 | 
						|
 | 
						|
function updateDeps(pkg, depType, version) {
 | 
						|
  const deps = pkg[depType];
 | 
						|
  if (!deps) return;
 | 
						|
  Object.keys(deps).forEach((dep) => {
 | 
						|
    if (dep.startsWith('@tmagic') && packages.includes(dep.replace(/^@tmagic\//, ''))) {
 | 
						|
      console.log(chalk.yellow(`${pkg.name} -> ${depType} -> ${dep}@${version}`));
 | 
						|
      deps[dep] = version;
 | 
						|
    }
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
async function publishPackage(pkgName, version, runIfNotDry) {
 | 
						|
  if (skippedPackages.includes(pkgName)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  const pkgRoot = getPkgRoot(pkgName);
 | 
						|
  const pkgPath = path.resolve(pkgRoot, 'package.json');
 | 
						|
  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
 | 
						|
  if (pkg.private) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  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 ${pkgName}...`);
 | 
						|
  try {
 | 
						|
    await runIfNotDry(
 | 
						|
      // note: use of yarn is intentional here as we rely on its publishing
 | 
						|
      // behavior.
 | 
						|
      'yarn',
 | 
						|
      ['publish', '--new-version', version, ...(releaseTag ? ['--tag', releaseTag] : []), '--access', 'public'],
 | 
						|
      {
 | 
						|
        cwd: pkgRoot,
 | 
						|
        stdio: 'pipe',
 | 
						|
      },
 | 
						|
    );
 | 
						|
    console.log(chalk.green(`Successfully published ${pkgName}@${version}`));
 | 
						|
  } catch (e) {
 | 
						|
    if (e.stderr.match(/previously published/)) {
 | 
						|
      console.log(chalk.red(`Skipping already published: ${pkgName}`));
 | 
						|
    } else {
 | 
						|
      throw e;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
main().catch((err) => {
 | 
						|
  updateVersions(currentVersion);
 | 
						|
  console.error(err);
 | 
						|
});
 |