UNPKG

oclif

Version:

oclif: create your own CLI

214 lines (213 loc) 11.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const command_1 = require("@oclif/command"); const cli_ux_1 = require("cli-ux"); const fs = require("fs-extra"); const path = require("path"); const aws_1 = require("../aws"); const Tarballs = require("../tarballs"); const upload_util_1 = require("../upload-util"); const util_1 = require("../util"); class Promote extends command_1.Command { async run() { const { flags } = this.parse(Promote); const maxAge = `max-age=${flags['max-age']}`; const targets = flags.targets.split(','); const buildConfig = await Tarballs.buildConfig(flags.root, { targets }); const { s3Config, config } = buildConfig; const appendToIndex = async (input) => { var _a; // these checks are both nice for users AND helpful for TS if (!s3Config.bucket) throw new Error('[package.json].oclif.s3.bucket is required for indexes'); if (!s3Config.host) throw new Error('[package.json].oclif.s3.host is required for indexes'); // json-friendly filenames like sfdx-linux-x64-tar-gz const jsonFileName = `${input.filename.replace(/\./g, '-')}.json`; const key = path.join(s3Config.folder, 'versions', jsonFileName); // retrieve existing index file let existing = {}; try { existing = JSON.parse((_a = (await aws_1.default.s3.getObject({ Bucket: s3Config.bucket, Key: key, })).Body) === null || _a === void 0 ? void 0 : _a.toString()); this.log('appending to existing index file'); } catch (error) { this.error(`error on ${key}`, error); } // appends new version from this promotion if not already present (idempotent) await fs.writeJSON(jsonFileName, util_1.sortVersionsObjectByKeysDesc(Object.assign(Object.assign({}, existing), { [flags.version]: input.originalUrl.replace(s3Config.bucket, s3Config.host) })), { spaces: 2 }); // put the file back in the same place await aws_1.default.s3.uploadFile(jsonFileName, { Bucket: s3Config.bucket, Key: key, CacheControl: maxAge, }); // cleans up local fs await fs.remove(jsonFileName); }; if (!s3Config.bucket) this.error('Cannot determine S3 bucket for promotion'); const cloudBucketCommitKey = (shortKey) => path.join(s3Config.bucket, upload_util_1.commitAWSDir(flags.version, flags.sha, s3Config), shortKey); const cloudChannelKey = (shortKey) => path.join(upload_util_1.channelAWSDir(flags.channel, s3Config), shortKey); // copy tarballs manifests if (buildConfig.targets.length > 0) this.log(`Promoting buildmanifests & unversioned tarballs to ${flags.channel}`); for (const target of buildConfig.targets) { const manifest = upload_util_1.templateShortKey('manifest', { arch: target.arch, bin: config.bin, platform: target.platform, sha: flags.sha, version: flags.version, }); const copySource = cloudBucketCommitKey(manifest); // strip version & sha so update/scripts can point to a static channel manifest const unversionedManifest = manifest.replace(`-v${flags.version}-${flags.sha}`, ''); const key = cloudChannelKey(unversionedManifest); // eslint-disable-next-line no-await-in-loop await aws_1.default.s3.copyObject({ Bucket: s3Config.bucket, CopySource: copySource, Key: key, CacheControl: maxAge, MetadataDirective: 'REPLACE', }); const versionedTarGzName = upload_util_1.templateShortKey('versioned', '.tar.gz', { arch: target.arch, bin: config.bin, platform: target.platform, sha: flags.sha, version: flags.version, }); const versionedTarGzKey = cloudBucketCommitKey(versionedTarGzName); // strip version & sha so update/scripts can point to a static channel tarball const unversionedTarGzName = versionedTarGzName.replace(`-v${flags.version}-${flags.sha}`, ''); const unversionedTarGzKey = cloudChannelKey(unversionedTarGzName); // eslint-disable-next-line no-await-in-loop await aws_1.default.s3.copyObject({ Bucket: s3Config.bucket, CopySource: versionedTarGzKey, Key: unversionedTarGzKey, CacheControl: maxAge, MetadataDirective: 'REPLACE', }); // eslint-disable-next-line no-await-in-loop if (flags.indexes) await appendToIndex({ originalUrl: versionedTarGzKey, filename: unversionedTarGzName }); if (flags.xz) { const versionedTarXzName = upload_util_1.templateShortKey('versioned', '.tar.xz', { arch: target.arch, bin: config.bin, platform: target.platform, sha: flags.sha, version: flags.version, }); const versionedTarXzKey = cloudBucketCommitKey(versionedTarXzName); // strip version & sha so update/scripts can point to a static channel tarball const unversionedTarXzName = versionedTarXzName.replace(`-v${flags.version}-${flags.sha}`, ''); const unversionedTarXzKey = cloudChannelKey(unversionedTarXzName); // eslint-disable-next-line no-await-in-loop await aws_1.default.s3.copyObject({ Bucket: s3Config.bucket, CopySource: versionedTarXzKey, Key: unversionedTarXzKey, CacheControl: maxAge, MetadataDirective: 'REPLACE', }); // eslint-disable-next-line no-await-in-loop if (flags.indexes) await appendToIndex({ originalUrl: versionedTarXzKey, filename: unversionedTarXzName }); } } // copy darwin pkg if (flags.macos) { this.log(`Promoting macos pkg to ${flags.channel}`); const darwinPkg = upload_util_1.templateShortKey('macos', { bin: config.bin, version: flags.version, sha: flags.sha }); const darwinCopySource = cloudBucketCommitKey(darwinPkg); // strip version & sha so scripts can point to a static channel pkg const unversionedPkg = darwinPkg.replace(`-v${flags.version}-${flags.sha}`, ''); const darwinKey = cloudChannelKey(unversionedPkg); await aws_1.default.s3.copyObject({ Bucket: s3Config.bucket, CopySource: darwinCopySource, Key: darwinKey, CacheControl: maxAge, MetadataDirective: 'REPLACE', }); if (flags.indexes) await appendToIndex({ originalUrl: darwinCopySource, filename: unversionedPkg }); } // copy win exe if (flags.win) { this.log(`Promoting windows exe to ${flags.channel}`); const archs = buildConfig.targets.filter(t => t.platform === 'win32').map(t => t.arch); for (const arch of archs) { const winPkg = upload_util_1.templateShortKey('win32', { bin: config.bin, version: flags.version, sha: flags.sha, arch }); const winCopySource = cloudBucketCommitKey(winPkg); // strip version & sha so scripts can point to a static channel exe const unversionedExe = winPkg.replace(`-v${flags.version}-${flags.sha}`, ''); const winKey = cloudChannelKey(unversionedExe); // eslint-disable-next-line no-await-in-loop await aws_1.default.s3.copyObject({ Bucket: s3Config.bucket, CopySource: winCopySource, Key: winKey, CacheControl: maxAge, }); // eslint-disable-next-line no-await-in-loop if (flags.indexes) await appendToIndex({ originalUrl: winCopySource, filename: unversionedExe }); cli_ux_1.cli.action.stop('successfully'); } } // copy debian artifacts const debArtifacts = [ upload_util_1.templateShortKey('deb', { bin: config.bin, versionShaRevision: upload_util_1.debVersion(buildConfig), arch: 'amd64' }), upload_util_1.templateShortKey('deb', { bin: config.bin, versionShaRevision: upload_util_1.debVersion(buildConfig), arch: 'i386' }), 'Packages.gz', 'Packages.xz', 'Packages.bz2', 'Release', 'InRelease', 'Release.gpg', ]; if (flags.deb) { this.log(`Promoting debian artifacts to ${flags.channel}`); for (const artifact of debArtifacts) { const debCopySource = cloudBucketCommitKey(`apt/${artifact}`); const debKey = cloudChannelKey(`apt/${artifact}`); // eslint-disable-next-line no-await-in-loop await aws_1.default.s3.copyObject({ Bucket: s3Config.bucket, CopySource: debCopySource, Key: debKey, CacheControl: maxAge, MetadataDirective: 'REPLACE', }); } } } } exports.default = Promote; Promote.hidden = true; Promote.description = 'promote CLI builds to a S3 release channel'; Promote.flags = { root: command_1.flags.string({ char: 'r', description: 'path to the oclif CLI project root', default: '.', required: true }), version: command_1.flags.string({ description: 'semantic version of the CLI to promote', required: true }), sha: command_1.flags.string({ description: '7-digit short git commit SHA of the CLI to promote', required: true }), channel: command_1.flags.string({ description: 'which channel to promote to', required: true, default: 'stable' }), targets: command_1.flags.string({ char: 't', description: 'comma-separated targets to promote (e.g.: linux-arm,win32-x64)', default: Tarballs.TARGETS.join(','), }), deb: command_1.flags.boolean({ char: 'd', description: 'promote debian artifacts' }), macos: command_1.flags.boolean({ char: 'm', description: 'promote macOS pkg' }), win: command_1.flags.boolean({ char: 'w', description: 'promote Windows exe' }), 'max-age': command_1.flags.string({ char: 'a', description: 'cache control max-age in seconds', default: '86400' }), xz: command_1.flags.boolean({ description: 'also upload xz', allowNo: true, default: true }), indexes: command_1.flags.boolean({ description: 'append the promoted urls into the index files' }), };