123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- import { Octokit } from '@octokit/rest';
- import * as chalk from 'chalk';
- import { GitProcess } from 'dugite';
- import { execSync } from 'node:child_process';
- import { join } from 'node:path';
- import { createGitHubTokenStrategy } from './github-token';
- import releaseNotesGenerator from './notes';
- import { runReleaseCIJobs } from './run-release-ci-jobs';
- import { ELECTRON_ORG, ElectronReleaseRepo, VersionBumpType } from './types';
- import { getCurrentBranch, ELECTRON_DIR } from '../lib/utils.js';
- const pass = chalk.green('✓');
- const fail = chalk.red('✗');
- enum DryRunMode {
- DRY_RUN,
- REAL_RUN,
- }
- type PrepareReleaseOptions = {
- targetRepo: ElectronReleaseRepo;
- targetBranch?: string;
- bumpType: VersionBumpType;
- isPreRelease: boolean;
- };
- async function getNewVersion (
- options: PrepareReleaseOptions,
- dryRunMode: DryRunMode
- ) {
- if (dryRunMode === DryRunMode.REAL_RUN) {
- console.log(`Bumping for new "${options.bumpType}" version.`);
- }
- const bumpScript = join(__dirname, 'version-bumper.ts');
- const scriptArgs = [
- 'node',
- 'node_modules/.bin/ts-node',
- bumpScript,
- `--bump=${options.bumpType}`
- ];
- if (dryRunMode === DryRunMode.DRY_RUN) scriptArgs.push('--dryRun');
- try {
- let bumpVersion = execSync(scriptArgs.join(' '), { encoding: 'utf-8' });
- bumpVersion = bumpVersion.substr(bumpVersion.indexOf(':') + 1).trim();
- const newVersion = `v${bumpVersion}`;
- if (dryRunMode === DryRunMode.REAL_RUN) {
- console.log(`${pass} Successfully bumped version to ${newVersion}`);
- }
- return newVersion;
- } catch (err) {
- console.log(`${fail} Could not bump version, error was:`, err);
- throw err;
- }
- }
- async function getReleaseNotes (
- options: PrepareReleaseOptions,
- currentBranch: string,
- newVersion: string
- ) {
- if (options.bumpType === 'nightly') {
- return {
- text: 'Nightlies do not get release notes, please compare tags for info.'
- };
- }
- console.log(`Generating release notes for ${currentBranch}.`);
- const releaseNotes = await releaseNotesGenerator(currentBranch, newVersion);
- if (releaseNotes.warning) {
- console.warn(releaseNotes.warning);
- }
- return releaseNotes;
- }
- async function createRelease (
- options: PrepareReleaseOptions,
- branchToTarget: string
- ) {
- const newVersion = await getNewVersion(options, DryRunMode.REAL_RUN);
- const releaseNotes = await getReleaseNotes(
- options,
- branchToTarget,
- newVersion
- );
- await tagRelease(newVersion);
- const octokit = new Octokit({
- authStrategy: createGitHubTokenStrategy(options.targetRepo)
- });
- console.log('Checking for existing draft release.');
- const releases = await octokit.repos
- .listReleases({
- owner: ELECTRON_ORG,
- repo: options.targetRepo
- })
- .catch((err) => {
- console.log(`${fail} Could not get releases. Error was: `, err);
- throw err;
- });
- const drafts = releases.data.filter(
- (release) => release.draft && release.tag_name === newVersion
- );
- if (drafts.length > 0) {
- console.log(`${fail} Aborting because draft release for
- ${drafts[0].tag_name} already exists.`);
- process.exit(1);
- }
- console.log(`${pass} A draft release does not exist; creating one.`);
- let releaseBody;
- let releaseIsPrelease = false;
- if (options.isPreRelease) {
- if (newVersion.indexOf('nightly') > 0) {
- releaseBody =
- 'Note: This is a nightly release. Please file new issues ' +
- 'for any bugs you find in it.\n \n This release is published to npm ' +
- 'under the electron-nightly package and can be installed via `npm install electron-nightly`, ' +
- `or \`npm install electron-nightly@${newVersion.substr(1)}\`.\n \n ${
- releaseNotes.text
- }`;
- } else if (newVersion.indexOf('alpha') > 0) {
- releaseBody =
- 'Note: This is an alpha release. Please file new issues ' +
- 'for any bugs you find in it.\n \n This release is published to npm ' +
- 'under the alpha tag and can be installed via `npm install electron@alpha`, ' +
- `or \`npm install electron@${newVersion.substr(1)}\`.\n \n ${
- releaseNotes.text
- }`;
- } else {
- releaseBody =
- 'Note: This is a beta release. Please file new issues ' +
- 'for any bugs you find in it.\n \n This release is published to npm ' +
- 'under the beta tag and can be installed via `npm install electron@beta`, ' +
- `or \`npm install electron@${newVersion.substr(1)}\`.\n \n ${
- releaseNotes.text
- }`;
- }
- releaseIsPrelease = true;
- } else {
- releaseBody = releaseNotes.text;
- }
- const release = await octokit.repos
- .createRelease({
- owner: ELECTRON_ORG,
- repo: options.targetRepo,
- tag_name: newVersion,
- draft: true,
- name: `electron ${newVersion}`,
- body: releaseBody,
- prerelease: releaseIsPrelease,
- target_commitish: newVersion.includes('nightly')
- ? 'main'
- : branchToTarget
- })
- .catch((err) => {
- console.log(`${fail} Error creating new release: `, err);
- process.exit(1);
- });
- console.log(`Release has been created with id: ${release.data.id}.`);
- console.log(`${pass} Draft release for ${newVersion} successful.`);
- }
- async function pushRelease (branch: string) {
- const pushDetails = await GitProcess.exec(
- ['push', 'origin', `HEAD:${branch}`, '--follow-tags'],
- ELECTRON_DIR
- );
- if (pushDetails.exitCode === 0) {
- console.log(
- `${pass} Successfully pushed the release. Wait for ` +
- 'release builds to finish before running "npm run release".'
- );
- } else {
- console.log(`${fail} Error pushing the release: ${pushDetails.stderr}`);
- process.exit(1);
- }
- }
- async function runReleaseBuilds (branch: string, newVersion: string) {
- await runReleaseCIJobs(branch, {
- ci: undefined,
- ghRelease: true,
- newVersion
- });
- }
- async function tagRelease (version: string) {
- console.log(`Tagging release ${version}.`);
- const checkoutDetails = await GitProcess.exec(
- ['tag', '-a', '-m', version, version],
- ELECTRON_DIR
- );
- if (checkoutDetails.exitCode === 0) {
- console.log(`${pass} Successfully tagged ${version}.`);
- } else {
- console.log(
- `${fail} Error tagging ${version}: ` + `${checkoutDetails.stderr}`
- );
- process.exit(1);
- }
- }
- export async function printNextVersion (options: PrepareReleaseOptions) {
- const newVersion = await getNewVersion(options, DryRunMode.DRY_RUN);
- console.log(newVersion);
- }
- export async function prepareRelease (options: PrepareReleaseOptions) {
- const currentBranch =
- options.targetBranch || (await getCurrentBranch(ELECTRON_DIR));
- const newVersion = await getNewVersion(options, DryRunMode.DRY_RUN);
- console.log(`${pass} Starting release of ${newVersion}`);
- await createRelease(options, currentBranch);
- await pushRelease(currentBranch);
- await runReleaseBuilds(currentBranch, newVersion);
- }
|