123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- const temp = require('temp');
- const fs = require('node:fs');
- const path = require('node:path');
- const childProcess = require('node:child_process');
- const semver = require('semver');
- const { getCurrentBranch, ELECTRON_DIR } = require('../lib/utils');
- const { getElectronVersion } = require('../lib/get-version');
- const rootPackageJson = require('../../package.json');
- const { Octokit } = require('@octokit/rest');
- const { getAssetContents } = require('./get-asset');
- const octokit = new Octokit({
- userAgent: 'electron-npm-publisher',
- auth: process.env.ELECTRON_GITHUB_TOKEN
- });
- if (!process.env.ELECTRON_NPM_OTP) {
- console.error('Please set ELECTRON_NPM_OTP');
- process.exit(1);
- }
- let tempDir;
- temp.track(); // track and cleanup files at exit
- const files = [
- 'cli.js',
- 'index.js',
- 'install.js',
- 'package.json',
- 'README.md',
- 'LICENSE'
- ];
- const jsonFields = [
- 'name',
- 'repository',
- 'description',
- 'license',
- 'author',
- 'keywords'
- ];
- let npmTag = '';
- const currentElectronVersion = getElectronVersion();
- const isNightlyElectronVersion = currentElectronVersion.includes('nightly');
- new Promise((resolve, reject) => {
- temp.mkdir('electron-npm', (err, dirPath) => {
- if (err) {
- reject(err);
- } else {
- resolve(dirPath);
- }
- });
- })
- .then((dirPath) => {
- tempDir = dirPath;
- // copy files from `/npm` to temp directory
- files.forEach((name) => {
- const noThirdSegment = name === 'README.md' || name === 'LICENSE';
- fs.writeFileSync(
- path.join(tempDir, name),
- fs.readFileSync(path.join(ELECTRON_DIR, noThirdSegment ? '' : 'npm', name))
- );
- });
- // copy from root package.json to temp/package.json
- const packageJson = require(path.join(tempDir, 'package.json'));
- jsonFields.forEach((fieldName) => {
- packageJson[fieldName] = rootPackageJson[fieldName];
- });
- packageJson.version = currentElectronVersion;
- fs.writeFileSync(
- path.join(tempDir, 'package.json'),
- JSON.stringify(packageJson, null, 2)
- );
- return octokit.repos.listReleases({
- owner: 'electron',
- repo: isNightlyElectronVersion ? 'nightlies' : 'electron'
- });
- })
- .then((releases) => {
- // download electron.d.ts from release
- const release = releases.data.find(
- (release) => release.tag_name === `v${currentElectronVersion}`
- );
- if (!release) {
- throw new Error(`cannot find release with tag v${currentElectronVersion}`);
- }
- return release;
- })
- .then(async (release) => {
- const tsdAsset = release.assets.find((asset) => asset.name === 'electron.d.ts');
- if (!tsdAsset) {
- throw new Error(`cannot find electron.d.ts from v${currentElectronVersion} release assets`);
- }
- const typingsContent = await getAssetContents(
- isNightlyElectronVersion ? 'nightlies' : 'electron',
- tsdAsset.id
- );
- fs.writeFileSync(path.join(tempDir, 'electron.d.ts'), typingsContent);
- return release;
- })
- .then(async (release) => {
- const checksumsAsset = release.assets.find((asset) => asset.name === 'SHASUMS256.txt');
- if (!checksumsAsset) {
- throw new Error(`cannot find SHASUMS256.txt from v${currentElectronVersion} release assets`);
- }
- const checksumsContent = await getAssetContents(
- isNightlyElectronVersion ? 'nightlies' : 'electron',
- checksumsAsset.id
- );
- const checksumsObject = {};
- for (const line of checksumsContent.trim().split('\n')) {
- const [checksum, file] = line.split(' *');
- checksumsObject[file] = checksum;
- }
- fs.writeFileSync(path.join(tempDir, 'checksums.json'), JSON.stringify(checksumsObject, null, 2));
- return release;
- })
- .then(async (release) => {
- const currentBranch = await getCurrentBranch();
- if (isNightlyElectronVersion) {
- // Nightlies get published to their own module, so they should be tagged as latest
- npmTag = currentBranch === 'main' ? 'latest' : `nightly-${currentBranch}`;
- const currentJson = JSON.parse(fs.readFileSync(path.join(tempDir, 'package.json'), 'utf8'));
- currentJson.name = 'electron-nightly';
- rootPackageJson.name = 'electron-nightly';
- fs.writeFileSync(
- path.join(tempDir, 'package.json'),
- JSON.stringify(currentJson, null, 2)
- );
- } else {
- if (currentBranch === 'main') {
- // This should never happen, main releases should be nightly releases
- // this is here just-in-case
- throw new Error('Unreachable release phase, can\'t tag a non-nightly release on the main branch');
- } else if (!release.prerelease) {
- // Tag the release with a `2-0-x` style tag
- npmTag = currentBranch;
- } else if (release.tag_name.indexOf('alpha') > 0) {
- // Tag the release with an `alpha-3-0-x` style tag
- npmTag = `alpha-${currentBranch}`;
- } else {
- // Tag the release with a `beta-3-0-x` style tag
- npmTag = `beta-${currentBranch}`;
- }
- }
- })
- .then(() => childProcess.execSync('npm pack', { cwd: tempDir }))
- .then(() => {
- // test that the package can install electron prebuilt from github release
- const tarballPath = path.join(tempDir, `${rootPackageJson.name}-${currentElectronVersion}.tgz`);
- return new Promise((resolve, reject) => {
- const result = childProcess.spawnSync('npm', ['install', tarballPath, '--force', '--silent'], {
- env: { ...process.env, electron_config_cache: tempDir },
- cwd: tempDir,
- stdio: 'inherit'
- });
- if (result.status !== 0) {
- return reject(new Error(`npm install failed with status ${result.status}`));
- }
- try {
- const electronPath = require(path.resolve(tempDir, 'node_modules', rootPackageJson.name));
- if (typeof electronPath !== 'string') {
- return reject(new Error(`path to electron binary (${electronPath}) returned by the ${rootPackageJson.name} module is not a string`));
- }
- if (!fs.existsSync(electronPath)) {
- return reject(new Error(`path to electron binary (${electronPath}) returned by the ${rootPackageJson.name} module does not exist on disk`));
- }
- } catch (e) {
- console.error(e);
- return reject(new Error(`loading the generated ${rootPackageJson.name} module failed with an error`));
- }
- resolve(tarballPath);
- });
- })
- .then((tarballPath) => {
- const existingVersionJSON = childProcess.execSync(`npx npm@7 view ${rootPackageJson.name}@${currentElectronVersion} --json`).toString('utf-8');
- // It's possible this is a re-run and we already have published the package, if not we just publish like normal
- if (!existingVersionJSON) {
- childProcess.execSync(`npm publish ${tarballPath} --tag ${npmTag} --otp=${process.env.ELECTRON_NPM_OTP}`);
- }
- })
- .then(() => {
- const currentTags = JSON.parse(childProcess.execSync('npm show electron dist-tags --json').toString());
- const parsedLocalVersion = semver.parse(currentElectronVersion);
- if (rootPackageJson.name === 'electron') {
- // We should only customly add dist tags for non-nightly releases where the package name is still
- // "electron"
- if (parsedLocalVersion.prerelease.length === 0 &&
- semver.gt(currentElectronVersion, currentTags.latest)) {
- childProcess.execSync(`npm dist-tag add electron@${currentElectronVersion} latest --otp=${process.env.ELECTRON_NPM_OTP}`);
- }
- if (parsedLocalVersion.prerelease[0] === 'beta' &&
- semver.gt(currentElectronVersion, currentTags.beta)) {
- childProcess.execSync(`npm dist-tag add electron@${currentElectronVersion} beta --otp=${process.env.ELECTRON_NPM_OTP}`);
- }
- if (parsedLocalVersion.prerelease[0] === 'alpha' &&
- semver.gt(currentElectronVersion, currentTags.alpha)) {
- childProcess.execSync(`npm dist-tag add electron@${currentElectronVersion} alpha --otp=${process.env.ELECTRON_NPM_OTP}`);
- }
- }
- })
- .catch((err) => {
- console.error('Error:', err);
- process.exit(1);
- });
|