diff --git a/src/commands/install.ts b/src/commands/install.ts index d5c4076e..1dbfc435 100644 --- a/src/commands/install.ts +++ b/src/commands/install.ts @@ -13,14 +13,24 @@ export default class InstallCommand extends UpdateCommand { const {args} = this.parse(InstallCommand) // Check if this command is trying to update the channel. TODO: make this dynamic - const channelUpdateRequested = ['alpha', 'beta', 'next', 'stable'].some(c => args.version === c) + const prereleaseChannels = ['alpha', 'beta', 'next'] + const channelUpdateRequested = ['stable', ...prereleaseChannels].some( + c => args.version === c, + ) this.channel = channelUpdateRequested ? args.version : await this.determineChannel() + + const targetVersion = semver.clean(args.version) || args.version + // Determine if the version is from a different channel and update to account for it (ex. cli-example update 3.0.0-next.22 should update the channel to next as well.) + const versionParts = targetVersion?.split('-') || ['', ''] + if (versionParts && versionParts[1]) { + this.channel = versionParts[1].substr(0, versionParts[1].indexOf('.')) + this.debug(`Flag overriden target channel: ${this.channel}`) + } + const versions = fs .readdirSync(this.clientRoot) .filter(dirOrFile => dirOrFile !== 'bin' && dirOrFile !== 'current') - const targetVersion = semver.clean(args.version) || args.version - if (versions.includes(targetVersion)) { await this.updateToExistingVersion(targetVersion) this.currentVersion = await this.determineCurrentVersion() @@ -29,6 +39,10 @@ export default class InstallCommand extends UpdateCommand { await this.setChannel() } } else { + let specifiVersion + if (targetVersion !== this.channel) { + specifiVersion = targetVersion + } cli.action.start(`${this.config.name}: Updating CLI`) await this.config.runHook('preupdate', {channel: this.channel}) const manifest = await this.fetchManifest() @@ -38,7 +52,7 @@ export default class InstallCommand extends UpdateCommand { this.debug(`Updating to ${this.updatedVersion}`) const reason = await this.skipUpdate() if (reason) cli.action.stop(reason || 'done') - else await this.update(manifest, this.channel) + else await this.update(manifest, this.channel, specifiVersion) this.debug('tidy') await this.tidy() await this.config.runHook('update', {channel: this.channel}) diff --git a/src/commands/update.ts b/src/commands/update.ts index b77eee3b..a9f0c9d6 100644 --- a/src/commands/update.ts +++ b/src/commands/update.ts @@ -154,44 +154,34 @@ export default class UpdateCommand extends Command { } } - protected async downloadAndExtract( - output: string, - manifest: IManifest, - channel: string, - ) { - const { version } = manifest; + protected async downloadAndExtract(output: string, manifest: IManifest, channel: string, targetVersion?: string) { + const {version} = manifest const filesize = (n: number): string => { - const [num, suffix] = require('filesize')(n, { output: 'array' }); - return num.toFixed(1) + ` ${suffix}`; - }; + const [num, suffix] = require('filesize')(n, {output: 'array'}) + return num.toFixed(1) + ` ${suffix}` + } - const http: typeof HTTP = require('http-call').HTTP; - const gzUrl = - manifest.gz || - this.config.s3Url( - this.config.s3Key('versioned', { - version, - channel, - bin: this.config.bin, - platform: this.config.platform, - arch: this.config.arch, - ext: 'gz', - }), - ); - const { response: stream } = await http.stream(gzUrl); - stream.pause(); - - const baseDir = - manifest.baseDir || - this.config.s3Key('baseDir', { - version, - channel, - bin: this.config.bin, - platform: this.config.platform, - arch: this.config.arch, - }); - const extraction = extract(stream, baseDir, output, manifest.sha256gz); + const http: typeof HTTP = require('http-call').HTTP + const gzUrl = !targetVersion && manifest.gz ? manifest.gz : this.config.s3Url(this.config.s3Key('versioned', { + version: targetVersion, + channel, + bin: this.config.bin, + platform: this.config.platform, + arch: this.config.arch, + ext: targetVersion ? 'tar.gz' : 'gz', + })) + const {response: stream} = await http.stream(gzUrl) + stream.pause() + + const baseDir = manifest.baseDir || this.config.s3Key('baseDir', { + version, + channel, + bin: this.config.bin, + platform: this.config.platform, + arch: this.config.arch, + }) + const extraction = extract(stream, baseDir, output, manifest.sha256gz) // to-do: use cli.action.type if ((cli.action as any).frames) { @@ -215,22 +205,16 @@ export default class UpdateCommand extends Command { await extraction; } - protected async update(manifest: IManifest, channel = this.channel) { - const { channel: manifestChannel } = manifest; - if (manifestChannel) channel = manifestChannel; - cli.action.start( - `${this.config.name}: Updating CLI from ${color.green( - this.currentVersion, - )} to ${color.green(this.updatedVersion)}${ - channel === 'stable' ? '' : ' (' + color.yellow(channel) + ')' - }`, - ); + protected async update(manifest: IManifest, channel = this.channel, targetVersion?: string) { + const {channel: manifestChannel} = manifest + if (manifestChannel) channel = manifestChannel + cli.action.start(`${this.config.name}: Updating CLI from ${color.green(this.currentVersion)} to ${color.green(this.updatedVersion)}${channel === 'stable' ? '' : ' (' + color.yellow(channel) + ')'}`) - await this.ensureClientDir(); - const output = path.join(this.clientRoot, this.updatedVersion); + await this.ensureClientDir() + const output = path.join(this.clientRoot, this.updatedVersion) - if (!(await fs.pathExists(output))) { - await this.downloadAndExtract(output, manifest, channel); + if (!await fs.pathExists(output)) { + await this.downloadAndExtract(output, manifest, channel, targetVersion) } await this.setChannel(); diff --git a/test/commands/install.test.ts b/test/commands/install.test.ts index 7247b986..748f7e18 100644 --- a/test/commands/install.test.ts +++ b/test/commands/install.test.ts @@ -90,14 +90,14 @@ describe('Install Command', () => { it('when requesting a version, will return the explicit version with appropriate URL', async () => { mockFs.readdirSync.mockReturnValue([] as any) - commandInstance = new MockedInstallCommand(['2.2.1'], config) + commandInstance = new MockedInstallCommand(['2.2.1-next.22'], config) http.get.mockResolvedValue({body: { - version: '2.2.1', + version: '2.2.1-next.22', baseDir: 'test-cli', channel: 'next', - gz: 'https://test-cli-oclif.s3.amazonaws.com/test-cli-v2.2.1/test-cli-v2.2.1.tar.gz', - xz: 'https://test-cli-oclif.s3.amazonaws.com/test-cli-v2.2.1/test-cli-v2.2.1.tar.xz', + gz: 'https://test-cli-oclif.s3.amazonaws.com/test-cli-v2.2.1-next.22/test-cli-v2.2.1-next.22.tar.gz', + xz: 'https://test-cli-oclif.s3.amazonaws.com/test-cli-v2.2.1-next.22/test-cli-v2.2.1-next.22.tar.xz', sha256gz: 'cae9de53d3cb9bfdb43b5fd75b1d9f4655e07cf479a8d86658155ff66d618dbb', node: { compatible: '>=10', @@ -108,7 +108,7 @@ describe('Install Command', () => { await commandInstance.run() expect(commandInstance.downloadAndExtract).toBeCalled() - expect(commandInstance.updatedVersion).toBe('2.2.1') + expect(commandInstance.updatedVersion).toBe('2.2.1-next.22') }) it('when requesting a version already available locally, will call updateToExistingVersion', async () => {