build: convert all release scripts to typescript (#44060)
* build: run gha on tag not branch (#42490) * build: convert all release scripts to typescript (#44035) * build: convert all release scripts to typescript * fix test imports * build: fix version bumper export * refactor: use as const * spec: fix bad type spec * build: use ts-node to spawn the version-bumper (#44057) Missed this in the tsification, we should probably call this via API instead of spawning a sub-proc? * build: still colors
This commit is contained in:
parent
956677b66a
commit
2e84985439
22 changed files with 1173 additions and 779 deletions
608
script/release/release.ts
Executable file
608
script/release/release.ts
Executable file
|
@ -0,0 +1,608 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import { BlobServiceClient } from '@azure/storage-blob';
|
||||
import { Octokit } from '@octokit/rest';
|
||||
import got from 'got';
|
||||
import { execSync, ExecSyncOptions } from 'node:child_process';
|
||||
import { statSync, createReadStream, writeFileSync, close } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { gte } from 'semver';
|
||||
import { track as trackTemp } from 'temp';
|
||||
|
||||
import { ELECTRON_DIR } from '../lib/utils';
|
||||
import { getElectronVersion } from '../lib/get-version';
|
||||
import { getUrlHash } from './get-url-hash';
|
||||
import { createGitHubTokenStrategy } from './github-token';
|
||||
import { ELECTRON_REPO, ElectronReleaseRepo, NIGHTLY_REPO } from './types';
|
||||
import { parseArgs } from 'node:util';
|
||||
|
||||
const temp = trackTemp();
|
||||
|
||||
require('colors');
|
||||
const pass = '✓'.green;
|
||||
const fail = '✗'.red;
|
||||
|
||||
const pkgVersion = `v${getElectronVersion()}`;
|
||||
|
||||
function getRepo (): ElectronReleaseRepo {
|
||||
return pkgVersion.indexOf('nightly') > 0 ? NIGHTLY_REPO : ELECTRON_REPO;
|
||||
}
|
||||
|
||||
const targetRepo = getRepo();
|
||||
let failureCount = 0;
|
||||
|
||||
const octokit = new Octokit({
|
||||
authStrategy: createGitHubTokenStrategy(targetRepo)
|
||||
});
|
||||
|
||||
async function getDraftRelease (
|
||||
version?: string,
|
||||
skipValidation: boolean = false
|
||||
) {
|
||||
const releaseInfo = await octokit.repos.listReleases({
|
||||
owner: 'electron',
|
||||
repo: targetRepo
|
||||
});
|
||||
|
||||
const versionToCheck = version || pkgVersion;
|
||||
const drafts = releaseInfo.data.filter((release) => {
|
||||
return release.tag_name === versionToCheck && release.draft === true;
|
||||
});
|
||||
|
||||
const draft = drafts[0];
|
||||
if (!skipValidation) {
|
||||
failureCount = 0;
|
||||
check(drafts.length === 1, 'one draft exists', true);
|
||||
if (versionToCheck.includes('beta')) {
|
||||
check(draft.prerelease, 'draft is a prerelease');
|
||||
}
|
||||
check(
|
||||
!!draft.body &&
|
||||
draft.body.length > 50 &&
|
||||
!draft.body.includes('(placeholder)'),
|
||||
'draft has release notes'
|
||||
);
|
||||
check(failureCount === 0, 'Draft release looks good to go.', true);
|
||||
}
|
||||
return draft;
|
||||
}
|
||||
|
||||
type MinimalRelease = {
|
||||
id: number;
|
||||
tag_name: string;
|
||||
draft: boolean;
|
||||
prerelease: boolean;
|
||||
assets: {
|
||||
name: string;
|
||||
browser_download_url: string;
|
||||
id: number;
|
||||
}[];
|
||||
};
|
||||
|
||||
async function validateReleaseAssets (
|
||||
release: MinimalRelease,
|
||||
validatingRelease: boolean = false
|
||||
) {
|
||||
const requiredAssets = assetsForVersion(
|
||||
release.tag_name,
|
||||
validatingRelease
|
||||
).sort();
|
||||
const extantAssets = release.assets.map((asset) => asset.name).sort();
|
||||
const downloadUrls = release.assets
|
||||
.map((asset) => ({ url: asset.browser_download_url, file: asset.name }))
|
||||
.sort((a, b) => a.file.localeCompare(b.file));
|
||||
|
||||
failureCount = 0;
|
||||
for (const asset of requiredAssets) {
|
||||
check(extantAssets.includes(asset), asset);
|
||||
}
|
||||
check(
|
||||
failureCount === 0,
|
||||
'All required GitHub assets exist for release',
|
||||
true
|
||||
);
|
||||
|
||||
if (!validatingRelease || !release.draft) {
|
||||
if (release.draft) {
|
||||
await verifyDraftGitHubReleaseAssets(release);
|
||||
} else {
|
||||
await verifyShasumsForRemoteFiles(downloadUrls).catch((err) => {
|
||||
console.error(`${fail} error verifyingShasums`, err);
|
||||
});
|
||||
}
|
||||
const azRemoteFiles = azRemoteFilesForVersion(release.tag_name);
|
||||
await verifyShasumsForRemoteFiles(azRemoteFiles, true);
|
||||
}
|
||||
}
|
||||
|
||||
function check (condition: boolean, statement: string, exitIfFail = false) {
|
||||
if (condition) {
|
||||
console.log(`${pass} ${statement}`);
|
||||
} else {
|
||||
failureCount++;
|
||||
console.error(`${fail} ${statement}`);
|
||||
if (exitIfFail) process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function assetsForVersion (version: string, validatingRelease: boolean) {
|
||||
const patterns = [
|
||||
`chromedriver-${version}-darwin-x64.zip`,
|
||||
`chromedriver-${version}-darwin-arm64.zip`,
|
||||
`chromedriver-${version}-linux-arm64.zip`,
|
||||
`chromedriver-${version}-linux-armv7l.zip`,
|
||||
`chromedriver-${version}-linux-x64.zip`,
|
||||
`chromedriver-${version}-mas-x64.zip`,
|
||||
`chromedriver-${version}-mas-arm64.zip`,
|
||||
`chromedriver-${version}-win32-ia32.zip`,
|
||||
`chromedriver-${version}-win32-x64.zip`,
|
||||
`chromedriver-${version}-win32-arm64.zip`,
|
||||
`electron-${version}-darwin-x64-dsym.zip`,
|
||||
`electron-${version}-darwin-x64-dsym-snapshot.zip`,
|
||||
`electron-${version}-darwin-x64-symbols.zip`,
|
||||
`electron-${version}-darwin-x64.zip`,
|
||||
`electron-${version}-darwin-arm64-dsym.zip`,
|
||||
`electron-${version}-darwin-arm64-dsym-snapshot.zip`,
|
||||
`electron-${version}-darwin-arm64-symbols.zip`,
|
||||
`electron-${version}-darwin-arm64.zip`,
|
||||
`electron-${version}-linux-arm64-symbols.zip`,
|
||||
`electron-${version}-linux-arm64.zip`,
|
||||
`electron-${version}-linux-armv7l-symbols.zip`,
|
||||
`electron-${version}-linux-armv7l.zip`,
|
||||
`electron-${version}-linux-x64-debug.zip`,
|
||||
`electron-${version}-linux-x64-symbols.zip`,
|
||||
`electron-${version}-linux-x64.zip`,
|
||||
`electron-${version}-mas-x64-dsym.zip`,
|
||||
`electron-${version}-mas-x64-dsym-snapshot.zip`,
|
||||
`electron-${version}-mas-x64-symbols.zip`,
|
||||
`electron-${version}-mas-x64.zip`,
|
||||
`electron-${version}-mas-arm64-dsym.zip`,
|
||||
`electron-${version}-mas-arm64-dsym-snapshot.zip`,
|
||||
`electron-${version}-mas-arm64-symbols.zip`,
|
||||
`electron-${version}-mas-arm64.zip`,
|
||||
`electron-${version}-win32-ia32-pdb.zip`,
|
||||
`electron-${version}-win32-ia32-symbols.zip`,
|
||||
`electron-${version}-win32-ia32.zip`,
|
||||
`electron-${version}-win32-x64-pdb.zip`,
|
||||
`electron-${version}-win32-x64-symbols.zip`,
|
||||
`electron-${version}-win32-x64.zip`,
|
||||
`electron-${version}-win32-arm64-pdb.zip`,
|
||||
`electron-${version}-win32-arm64-symbols.zip`,
|
||||
`electron-${version}-win32-arm64.zip`,
|
||||
'electron-api.json',
|
||||
'electron.d.ts',
|
||||
'hunspell_dictionaries.zip',
|
||||
'libcxx_headers.zip',
|
||||
'libcxxabi_headers.zip',
|
||||
`libcxx-objects-${version}-linux-arm64.zip`,
|
||||
`libcxx-objects-${version}-linux-armv7l.zip`,
|
||||
`libcxx-objects-${version}-linux-x64.zip`,
|
||||
`ffmpeg-${version}-darwin-x64.zip`,
|
||||
`ffmpeg-${version}-darwin-arm64.zip`,
|
||||
`ffmpeg-${version}-linux-arm64.zip`,
|
||||
`ffmpeg-${version}-linux-armv7l.zip`,
|
||||
`ffmpeg-${version}-linux-x64.zip`,
|
||||
`ffmpeg-${version}-mas-x64.zip`,
|
||||
`ffmpeg-${version}-mas-arm64.zip`,
|
||||
`ffmpeg-${version}-win32-ia32.zip`,
|
||||
`ffmpeg-${version}-win32-x64.zip`,
|
||||
`ffmpeg-${version}-win32-arm64.zip`,
|
||||
`mksnapshot-${version}-darwin-x64.zip`,
|
||||
`mksnapshot-${version}-darwin-arm64.zip`,
|
||||
`mksnapshot-${version}-linux-arm64-x64.zip`,
|
||||
`mksnapshot-${version}-linux-armv7l-x64.zip`,
|
||||
`mksnapshot-${version}-linux-x64.zip`,
|
||||
`mksnapshot-${version}-mas-x64.zip`,
|
||||
`mksnapshot-${version}-mas-arm64.zip`,
|
||||
`mksnapshot-${version}-win32-ia32.zip`,
|
||||
`mksnapshot-${version}-win32-x64.zip`,
|
||||
`mksnapshot-${version}-win32-arm64-x64.zip`,
|
||||
`electron-${version}-win32-ia32-toolchain-profile.zip`,
|
||||
`electron-${version}-win32-x64-toolchain-profile.zip`,
|
||||
`electron-${version}-win32-arm64-toolchain-profile.zip`
|
||||
];
|
||||
if (!validatingRelease) {
|
||||
patterns.push('SHASUMS256.txt');
|
||||
}
|
||||
return patterns;
|
||||
}
|
||||
|
||||
const cloudStoreFilePaths = (version: string) => [
|
||||
`iojs-${version}-headers.tar.gz`,
|
||||
`iojs-${version}.tar.gz`,
|
||||
`node-${version}.tar.gz`,
|
||||
'node.lib',
|
||||
'x64/node.lib',
|
||||
'win-x64/iojs.lib',
|
||||
'win-x86/iojs.lib',
|
||||
'win-arm64/iojs.lib',
|
||||
'win-x64/node.lib',
|
||||
'win-x86/node.lib',
|
||||
'win-arm64/node.lib',
|
||||
'arm64/node.lib',
|
||||
'SHASUMS.txt',
|
||||
'SHASUMS256.txt'
|
||||
];
|
||||
|
||||
function azRemoteFilesForVersion (version: string) {
|
||||
const azCDN = 'https://artifacts.electronjs.org/headers/';
|
||||
const versionPrefix = `${azCDN}dist/${version}/`;
|
||||
return cloudStoreFilePaths(version).map((filePath) => ({
|
||||
file: filePath,
|
||||
url: `${versionPrefix}${filePath}`
|
||||
}));
|
||||
}
|
||||
|
||||
function runScript (scriptName: string, scriptArgs: string[], cwd?: string) {
|
||||
const scriptCommand = `${scriptName} ${scriptArgs.join(' ')}`;
|
||||
const scriptOptions: ExecSyncOptions = {
|
||||
encoding: 'utf-8'
|
||||
};
|
||||
if (cwd) scriptOptions.cwd = cwd;
|
||||
try {
|
||||
return execSync(scriptCommand, scriptOptions);
|
||||
} catch (err) {
|
||||
console.error(`${fail} Error running ${scriptName}`, err);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function uploadNodeShasums () {
|
||||
console.log('Uploading Node SHASUMS file to artifacts.electronjs.org.');
|
||||
const scriptPath = join(
|
||||
ELECTRON_DIR,
|
||||
'script',
|
||||
'release',
|
||||
'uploaders',
|
||||
'upload-node-checksums.py'
|
||||
);
|
||||
runScript(scriptPath, ['-v', pkgVersion]);
|
||||
console.log(
|
||||
`${pass} Done uploading Node SHASUMS file to artifacts.electronjs.org.`
|
||||
);
|
||||
}
|
||||
|
||||
function uploadIndexJson () {
|
||||
console.log('Uploading index.json to artifacts.electronjs.org.');
|
||||
const scriptPath = join(
|
||||
ELECTRON_DIR,
|
||||
'script',
|
||||
'release',
|
||||
'uploaders',
|
||||
'upload-index-json.py'
|
||||
);
|
||||
runScript(scriptPath, [pkgVersion]);
|
||||
console.log(`${pass} Done uploading index.json to artifacts.electronjs.org.`);
|
||||
}
|
||||
|
||||
async function mergeShasums (pkgVersion: string) {
|
||||
// Download individual checksum files for Electron zip files from artifact storage,
|
||||
// concatenate them, and upload to GitHub.
|
||||
|
||||
const connectionString = process.env.ELECTRON_ARTIFACTS_BLOB_STORAGE;
|
||||
if (!connectionString) {
|
||||
throw new Error(
|
||||
'Please set the $ELECTRON_ARTIFACTS_BLOB_STORAGE environment variable'
|
||||
);
|
||||
}
|
||||
|
||||
const blobServiceClient =
|
||||
BlobServiceClient.fromConnectionString(connectionString);
|
||||
const containerClient = blobServiceClient.getContainerClient(
|
||||
'checksums-scratchpad'
|
||||
);
|
||||
const blobsIter = containerClient.listBlobsFlat({
|
||||
prefix: `${pkgVersion}/`
|
||||
});
|
||||
const shasums = [];
|
||||
for await (const blob of blobsIter) {
|
||||
if (blob.name.endsWith('.sha256sum')) {
|
||||
const blobClient = containerClient.getBlockBlobClient(blob.name);
|
||||
const response = await blobClient.downloadToBuffer();
|
||||
shasums.push(response.toString('ascii').trim());
|
||||
}
|
||||
}
|
||||
return shasums.join('\n');
|
||||
}
|
||||
|
||||
async function createReleaseShasums (release: MinimalRelease) {
|
||||
const fileName = 'SHASUMS256.txt';
|
||||
const existingAssets = release.assets.filter(
|
||||
(asset) => asset.name === fileName
|
||||
);
|
||||
if (existingAssets.length > 0) {
|
||||
console.log(
|
||||
`${fileName} already exists on GitHub; deleting before creating new file.`
|
||||
);
|
||||
await octokit.repos
|
||||
.deleteReleaseAsset({
|
||||
owner: 'electron',
|
||||
repo: targetRepo,
|
||||
asset_id: existingAssets[0].id
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(`${fail} Error deleting ${fileName} on GitHub:`, err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
console.log(`Creating and uploading the release ${fileName}.`);
|
||||
const checksums = await mergeShasums(pkgVersion);
|
||||
|
||||
console.log(`${pass} Generated release SHASUMS.`);
|
||||
const filePath = await saveShaSumFile(checksums, fileName);
|
||||
|
||||
console.log(`${pass} Created ${fileName} file.`);
|
||||
await uploadShasumFile(filePath, fileName, release.id);
|
||||
|
||||
console.log(`${pass} Successfully uploaded ${fileName} to GitHub.`);
|
||||
}
|
||||
|
||||
async function uploadShasumFile (
|
||||
filePath: string,
|
||||
fileName: string,
|
||||
releaseId: number
|
||||
) {
|
||||
const uploadUrl = `https://uploads.github.com/repos/electron/${targetRepo}/releases/${releaseId}/assets{?name,label}`;
|
||||
return octokit.repos
|
||||
.uploadReleaseAsset({
|
||||
url: uploadUrl,
|
||||
headers: {
|
||||
'content-type': 'text/plain',
|
||||
'content-length': statSync(filePath).size
|
||||
},
|
||||
data: createReadStream(filePath),
|
||||
name: fileName
|
||||
} as any)
|
||||
.catch((err) => {
|
||||
console.error(`${fail} Error uploading ${filePath} to GitHub:`, err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
function saveShaSumFile (checksums: string, fileName: string) {
|
||||
return new Promise<string>((resolve) => {
|
||||
temp.open(fileName, (err, info) => {
|
||||
if (err) {
|
||||
console.error(`${fail} Could not create ${fileName} file`);
|
||||
process.exit(1);
|
||||
} else {
|
||||
writeFileSync(info.fd, checksums);
|
||||
close(info.fd, (err) => {
|
||||
if (err) {
|
||||
console.error(`${fail} Could close ${fileName} file`);
|
||||
process.exit(1);
|
||||
}
|
||||
resolve(info.path);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function publishRelease (release: MinimalRelease) {
|
||||
let makeLatest = false;
|
||||
if (!release.prerelease) {
|
||||
const currentLatest = await octokit.repos.getLatestRelease({
|
||||
owner: 'electron',
|
||||
repo: targetRepo
|
||||
});
|
||||
|
||||
makeLatest = gte(release.tag_name, currentLatest.data.tag_name);
|
||||
}
|
||||
|
||||
return octokit.repos
|
||||
.updateRelease({
|
||||
owner: 'electron',
|
||||
repo: targetRepo,
|
||||
release_id: release.id,
|
||||
tag_name: release.tag_name,
|
||||
draft: false,
|
||||
make_latest: makeLatest ? 'true' : 'false'
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(`${fail} Error publishing release:`, err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
async function makeRelease (releaseToValidate: string | boolean) {
|
||||
if (releaseToValidate) {
|
||||
if (releaseToValidate === true) {
|
||||
releaseToValidate = pkgVersion;
|
||||
} else {
|
||||
console.log('Release to validate !=== true');
|
||||
}
|
||||
console.log(`Validating release ${releaseToValidate}`);
|
||||
const release = await getDraftRelease(releaseToValidate);
|
||||
await validateReleaseAssets(release, true);
|
||||
} else {
|
||||
let draftRelease = await getDraftRelease();
|
||||
uploadNodeShasums();
|
||||
await createReleaseShasums(draftRelease);
|
||||
|
||||
// Fetch latest version of release before verifying
|
||||
draftRelease = await getDraftRelease(pkgVersion, true);
|
||||
await validateReleaseAssets(draftRelease);
|
||||
// index.json goes live once uploaded so do these uploads as
|
||||
// late as possible to reduce the chances it contains a release
|
||||
// which fails to publish. It has to be done before the final
|
||||
// publish to ensure there aren't published releases not contained
|
||||
// in index.json, which causes other problems in downstream projects
|
||||
uploadIndexJson();
|
||||
await publishRelease(draftRelease);
|
||||
console.log(
|
||||
`${pass} SUCCESS!!! Release has been published. Please run ` +
|
||||
'"npm run publish-to-npm" to publish release to npm.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const SHASUM_256_FILENAME = 'SHASUMS256.txt';
|
||||
const SHASUM_1_FILENAME = 'SHASUMS.txt';
|
||||
|
||||
async function verifyDraftGitHubReleaseAssets (release: MinimalRelease) {
|
||||
console.log('Fetching authenticated GitHub artifact URLs to verify shasums');
|
||||
|
||||
const remoteFilesToHash = await Promise.all(
|
||||
release.assets.map(async (asset) => {
|
||||
const requestOptions = octokit.repos.getReleaseAsset.endpoint({
|
||||
owner: 'electron',
|
||||
repo: targetRepo,
|
||||
asset_id: asset.id,
|
||||
headers: {
|
||||
Accept: 'application/octet-stream'
|
||||
}
|
||||
});
|
||||
|
||||
const { url, headers } = requestOptions;
|
||||
headers.authorization = `token ${
|
||||
((await octokit.auth()) as { token: string }).token
|
||||
}`;
|
||||
|
||||
const response = await got(url, {
|
||||
followRedirect: false,
|
||||
method: 'HEAD',
|
||||
headers: headers as any,
|
||||
throwHttpErrors: false
|
||||
});
|
||||
|
||||
if (response.statusCode !== 302 && response.statusCode !== 301) {
|
||||
console.error('Failed to HEAD github asset: ' + url);
|
||||
throw new Error(
|
||||
"Unexpected status HEAD'ing github asset: " + response.statusCode
|
||||
);
|
||||
}
|
||||
|
||||
return { url: response.headers.location!, file: asset.name };
|
||||
})
|
||||
).catch((err) => {
|
||||
console.error(`${fail} Error downloading files from GitHub`, err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
await verifyShasumsForRemoteFiles(remoteFilesToHash);
|
||||
}
|
||||
|
||||
async function getShaSumMappingFromUrl (
|
||||
shaSumFileUrl: string,
|
||||
fileNamePrefix: string
|
||||
) {
|
||||
const response = await got(shaSumFileUrl, {
|
||||
throwHttpErrors: false
|
||||
});
|
||||
|
||||
if (response.statusCode !== 200) {
|
||||
console.error('Failed to fetch SHASUM mapping: ' + shaSumFileUrl);
|
||||
console.error('Bad SHASUM mapping response: ' + response.body.trim());
|
||||
throw new Error(
|
||||
'Unexpected status fetching SHASUM mapping: ' + response.statusCode
|
||||
);
|
||||
}
|
||||
|
||||
const raw = response.body;
|
||||
return raw
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.filter(Boolean)
|
||||
.reduce((map, line) => {
|
||||
const [sha, file] = line.replace(' ', ' ').split(' ');
|
||||
map[file.slice(fileNamePrefix.length)] = sha;
|
||||
return map;
|
||||
}, Object.create(null) as Record<string, string>);
|
||||
}
|
||||
|
||||
type HashedFile = HashableFile & {
|
||||
hash: string;
|
||||
};
|
||||
|
||||
type HashableFile = {
|
||||
file: string;
|
||||
url: string;
|
||||
};
|
||||
|
||||
async function validateFileHashesAgainstShaSumMapping (
|
||||
remoteFilesWithHashes: HashedFile[],
|
||||
mapping: Record<string, string>
|
||||
) {
|
||||
for (const remoteFileWithHash of remoteFilesWithHashes) {
|
||||
check(
|
||||
remoteFileWithHash.hash === mapping[remoteFileWithHash.file],
|
||||
`Release asset ${remoteFileWithHash.file} should have hash of ${
|
||||
mapping[remoteFileWithHash.file]
|
||||
} but found ${remoteFileWithHash.hash}`,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function verifyShasumsForRemoteFiles (
|
||||
remoteFilesToHash: HashableFile[],
|
||||
filesAreNodeJSArtifacts = false
|
||||
) {
|
||||
console.log(
|
||||
`Generating SHAs for ${remoteFilesToHash.length} files to verify shasums`
|
||||
);
|
||||
|
||||
// Only used for node.js artifact uploads
|
||||
const shaSum1File = remoteFilesToHash.find(
|
||||
({ file }) => file === SHASUM_1_FILENAME
|
||||
)!;
|
||||
// Used for both node.js artifact uploads and normal electron artifacts
|
||||
const shaSum256File = remoteFilesToHash.find(
|
||||
({ file }) => file === SHASUM_256_FILENAME
|
||||
)!;
|
||||
remoteFilesToHash = remoteFilesToHash.filter(
|
||||
({ file }) => file !== SHASUM_1_FILENAME && file !== SHASUM_256_FILENAME
|
||||
);
|
||||
|
||||
const remoteFilesWithHashes = await Promise.all(
|
||||
remoteFilesToHash.map(async (file) => {
|
||||
return {
|
||||
hash: await getUrlHash(file.url, 'sha256'),
|
||||
...file
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
await validateFileHashesAgainstShaSumMapping(
|
||||
remoteFilesWithHashes,
|
||||
await getShaSumMappingFromUrl(
|
||||
shaSum256File.url,
|
||||
filesAreNodeJSArtifacts ? '' : '*'
|
||||
)
|
||||
);
|
||||
|
||||
if (filesAreNodeJSArtifacts) {
|
||||
const remoteFilesWithSha1Hashes = await Promise.all(
|
||||
remoteFilesToHash.map(async (file) => {
|
||||
return {
|
||||
hash: await getUrlHash(file.url, 'sha1'),
|
||||
...file
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
await validateFileHashesAgainstShaSumMapping(
|
||||
remoteFilesWithSha1Hashes,
|
||||
await getShaSumMappingFromUrl(
|
||||
shaSum1File.url,
|
||||
filesAreNodeJSArtifacts ? '' : '*'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
values: { validateRelease }
|
||||
} = parseArgs({
|
||||
options: {
|
||||
validateRelease: {
|
||||
type: 'boolean'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
makeRelease(!!validateRelease).catch((err) => {
|
||||
console.error('Error occurred while making release:', err);
|
||||
process.exit(1);
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue