oclif
Version:
oclif: create your own CLI
152 lines (151 loc) • 10.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const _ = require("lodash");
const core_1 = require("@oclif/core");
const aws_1 = require("../aws");
const Tarballs = require("../tarballs");
const upload_util_1 = require("../upload-util");
const version_indexes_1 = require("../version-indexes");
class Promote extends core_1.Command {
async run() {
var _a, _b;
const { flags } = await this.parse(Promote);
const buildConfig = await Tarballs.buildConfig(flags.root, { targets: (_a = flags === null || flags === void 0 ? void 0 : flags.targets) === null || _a === void 0 ? void 0 : _a.split(',') });
const { s3Config, config } = buildConfig;
const indexDefaults = {
version: flags.version,
s3Config,
maxAge: `max-age=${flags['max-age']}`,
};
if (!s3Config.bucket)
this.error('Cannot determine S3 bucket for promotion');
const awsDefaults = {
Bucket: s3Config.bucket,
ACL: (_b = s3Config.acl) !== null && _b !== void 0 ? _b : 'public-read',
MetadataDirective: 'REPLACE',
CacheControl: indexDefaults.maxAge,
};
const cloudBucketCommitKey = (shortKey) => path.join(s3Config.bucket, (0, upload_util_1.commitAWSDir)(flags.version, flags.sha, s3Config), shortKey);
const cloudChannelKey = (shortKey) => path.join((0, 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}`);
const promoteManifest = async (target) => {
const manifest = (0, upload_util_1.templateShortKey)('manifest', {
arch: target.arch,
bin: config.bin,
platform: target.platform,
sha: flags.sha,
version: flags.version,
});
// strip version & sha so update/scripts can point to a static channel manifest
const unversionedManifest = manifest.replace(`-v${flags.version}-${flags.sha}`, '');
await aws_1.default.s3.copyObject(Object.assign(Object.assign({}, awsDefaults), { CopySource: cloudBucketCommitKey(manifest), Key: cloudChannelKey(unversionedManifest) }));
};
const promoteGzTarballs = async (target) => {
const versionedTarGzName = (0, 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);
await Promise.all([aws_1.default.s3.copyObject(Object.assign(Object.assign({}, awsDefaults), { CopySource: versionedTarGzKey, Key: unversionedTarGzKey }))].concat(flags.indexes ? [(0, version_indexes_1.appendToIndex)(Object.assign(Object.assign({}, indexDefaults), { originalUrl: versionedTarGzKey, filename: unversionedTarGzName }))] : []));
};
const promoteXzTarballs = async (target) => {
const versionedTarXzName = (0, 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);
await Promise.all([aws_1.default.s3.copyObject(Object.assign(Object.assign({}, awsDefaults), { CopySource: versionedTarXzKey, Key: unversionedTarXzKey }))].concat(flags.indexes ? [(0, version_indexes_1.appendToIndex)(Object.assign(Object.assign({}, indexDefaults), { originalUrl: versionedTarXzKey, filename: unversionedTarXzName }))] : []));
};
const promoteMacInstallers = async () => {
this.log(`Promoting macos pkgs to ${flags.channel}`);
const arches = _.uniq(buildConfig.targets.filter(t => t.platform === 'darwin').map(t => t.arch));
await Promise.all(arches.map(async (arch) => {
const darwinPkg = (0, upload_util_1.templateShortKey)('macos', { bin: config.bin, version: flags.version, sha: flags.sha, arch });
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}`, '');
await Promise.all([aws_1.default.s3.copyObject(Object.assign(Object.assign({}, awsDefaults), { CopySource: darwinCopySource, Key: cloudChannelKey(unversionedPkg) }))].concat(flags.indexes ? [(0, version_indexes_1.appendToIndex)(Object.assign(Object.assign({}, indexDefaults), { originalUrl: darwinCopySource, filename: unversionedPkg }))] : []));
}));
};
const promoteWindowsInstallers = async () => {
// copy win exe
this.log(`Promoting windows exe to ${flags.channel}`);
const arches = buildConfig.targets.filter(t => t.platform === 'win32').map(t => t.arch);
await Promise.all(arches.map(async (arch) => {
const winPkg = (0, 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}`, '');
await Promise.all([aws_1.default.s3.copyObject(Object.assign(Object.assign({}, awsDefaults), { CopySource: winCopySource, Key: cloudChannelKey(unversionedExe) }))].concat(flags.indexes ? [(0, version_indexes_1.appendToIndex)(Object.assign(Object.assign({}, indexDefaults), { originalUrl: winCopySource, filename: unversionedExe }))] : []));
core_1.CliUx.ux.action.stop('successfully');
}));
};
const promoteDebianAptPackages = async () => {
// copy debian artifacts
const debArtifacts = [
(0, upload_util_1.templateShortKey)('deb', { bin: config.bin, versionShaRevision: (0, upload_util_1.debVersion)(buildConfig), arch: 'amd64' }),
(0, upload_util_1.templateShortKey)('deb', { bin: config.bin, versionShaRevision: (0, upload_util_1.debVersion)(buildConfig), arch: 'i386' }),
'Packages.gz',
'Packages.xz',
'Packages.bz2',
'Release',
'InRelease',
'Release.gpg',
];
this.log(`Promoting debian artifacts to ${flags.channel}`);
await Promise.all(debArtifacts.flatMap(artifact => {
const debCopySource = cloudBucketCommitKey(`apt/${artifact}`);
const debKey = cloudChannelKey(`apt/${artifact}`);
// apt expects ../apt/dists/versionName/[artifacts] but oclif wants varsions/sha/apt/[artifacts]
// see https://github.com/oclif/oclif/issues/347 for the AWS-redirect that solves this
// this workaround puts the code in both places that the redirect was doing
// with this, the docs are correct. The copies are all done in parallel so it shouldn't be too costly.
const workaroundKey = cloudChannelKey(`apt/./${artifact}`);
return [
aws_1.default.s3.copyObject(Object.assign(Object.assign({}, awsDefaults), { CopySource: debCopySource, Key: debKey })),
aws_1.default.s3.copyObject(Object.assign(Object.assign({}, awsDefaults), { CopySource: debCopySource, Key: workaroundKey })),
];
}));
};
await Promise.all(buildConfig.targets.flatMap(target => [
// always promote the manifest and gz
promoteManifest(target),
promoteGzTarballs(target),
])
// optionally promote other artifacts depending on the specified flags
.concat(flags.xz ? buildConfig.targets.map(target => promoteXzTarballs(target)) : [])
.concat(flags.macos ? [promoteMacInstallers()] : [])
.concat(flags.win ? [promoteWindowsInstallers()] : [])
.concat(flags.deb ? [promoteDebianAptPackages()] : []));
}
}
exports.default = Promote;
Promote.description = 'promote CLI builds to a S3 release channel';
Promote.flags = {
root: core_1.Flags.string({ char: 'r', description: 'path to the oclif CLI project root', default: '.', required: true }),
version: core_1.Flags.string({ description: 'semantic version of the CLI to promote', required: true }),
sha: core_1.Flags.string({ description: '7-digit short git commit SHA of the CLI to promote', required: true }),
channel: core_1.Flags.string({ description: 'which channel to promote to', required: true, default: 'stable' }),
targets: core_1.Flags.string({ char: 't', description: 'comma-separated targets to promote (e.g.: linux-arm,win32-x64)' }),
deb: core_1.Flags.boolean({ char: 'd', description: 'promote debian artifacts' }),
macos: core_1.Flags.boolean({ char: 'm', description: 'promote macOS pkg' }),
win: core_1.Flags.boolean({ char: 'w', description: 'promote Windows exe' }),
'max-age': core_1.Flags.string({ char: 'a', description: 'cache control max-age in seconds', default: '86400' }),
xz: core_1.Flags.boolean({ description: 'also upload xz', allowNo: true }),
indexes: core_1.Flags.boolean({ description: 'append the promoted urls into the index files' }),
};