forked from oclif/plugin-update
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Diana Sentoso
committed
Jun 7, 2021
1 parent
d6863fb
commit 6cecef6
Showing
2 changed files
with
192 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import cli from 'cli-ux' | ||
import * as semver from 'semver' | ||
import * as fs from 'fs-extra' | ||
|
||
import UpdateCommand from './update' | ||
|
||
export default class InstallCommand extends UpdateCommand { | ||
static args = [{name: 'version', optional: false}] | ||
|
||
static flags = {} | ||
|
||
async run() { | ||
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) | ||
this.channel = channelUpdateRequested ? args.version : await this.determineChannel() | ||
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() | ||
this.updatedVersion = targetVersion | ||
if (channelUpdateRequested) { | ||
await this.setChannel() | ||
} | ||
} else { | ||
cli.action.start(`${this.config.name}: Updating CLI`) | ||
await this.config.runHook('preupdate', {channel: this.channel}) | ||
const manifest = await this.fetchManifest() | ||
this.currentVersion = await this.determineCurrentVersion() | ||
|
||
this.updatedVersion = (manifest as any).sha ? `${targetVersion}-${(manifest as any).sha}` : targetVersion | ||
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) | ||
this.debug('tidy') | ||
await this.tidy() | ||
await this.config.runHook('update', {channel: this.channel}) | ||
|
||
this.debug('done') | ||
cli.action.stop() | ||
} | ||
|
||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,162 @@ | ||
import InstallCommand from '../../src/commands/use'; | ||
import * as fs from 'fs'; | ||
import { mocked } from 'ts-jest/utils'; | ||
import { IConfig } from '@oclif/config'; | ||
import InstallCommand from '../../src/commands/install' | ||
import * as fs from 'fs-extra' | ||
import {mocked} from 'ts-jest/utils' | ||
import {IConfig} from '@oclif/config' | ||
|
||
const mockFs = mocked(fs, true); | ||
jest.mock('fs-extra') | ||
jest.mock('http-call', () => ({ | ||
HTTP: { | ||
get: jest.fn(), | ||
}, | ||
})) | ||
const mockFs = mocked(fs, true) | ||
|
||
class MockedInstallCommand extends InstallCommand { | ||
public fetchManifest = jest.fn(); | ||
public channel!: string; | ||
|
||
public clientBin!: string; | ||
|
||
public clientRoot!: string; | ||
|
||
public currentVersion!: string; | ||
|
||
public updatedVersion!: string; | ||
|
||
public determineCurrentVersion = jest.fn(); | ||
|
||
public downloadAndExtract = jest.fn(); | ||
|
||
public reexec = jest.fn(); | ||
|
||
public updateToExistingVersion = jest.fn(); | ||
} | ||
|
||
describe.skip('Install Command', () => { | ||
let commandInstance: MockedInstallCommand; | ||
let config: IConfig; | ||
describe('Install Command', () => { | ||
let commandInstance: MockedInstallCommand | ||
let config: IConfig | ||
const {HTTP: http} = require('http-call') | ||
beforeEach(() => { | ||
mockFs.existsSync.mockReturnValue(true); | ||
|
||
config = { | ||
name: 'test', | ||
version: '', | ||
channel: '', | ||
version: '1.0.0', | ||
channel: 'stable', | ||
cacheDir: '', | ||
commandIDs: [''], | ||
runHook: jest.fn(), | ||
topics: [], | ||
valid: true, | ||
arch: 'arm64', | ||
platform: 'darwin', | ||
plugins: [], | ||
commands: [], | ||
configDir: '', | ||
pjson: {} as any, | ||
dataDir: '', | ||
root: '', | ||
bin: '', | ||
} as any; | ||
}); | ||
|
||
it.skip('will run an update', async () => { | ||
commandInstance = new MockedInstallCommand([], config); | ||
|
||
await commandInstance.run(); | ||
}); | ||
|
||
it.todo( | ||
'when requesting a channel, will fetch manifest to install the latest version', | ||
); | ||
it.todo( | ||
'when requesting a version, will return the explicit version with appropriate URL', | ||
); | ||
it.todo('will handle an invalid version request'); | ||
it.todo('will handle an invalid channel request'); | ||
}); | ||
bin: 'cli', | ||
binPath: 'cli', | ||
pjson: {oclif: {update: {s3: './folder'}}}, | ||
scopedEnvVar: jest.fn(), | ||
scopedEnvVarKey: jest.fn(), | ||
scopedEnvVarTrue: jest.fn(), | ||
s3Url: () => null, | ||
s3Key: jest.fn(), | ||
} as any | ||
}) | ||
|
||
it('when requesting a channel, will fetch manifest to install the latest version', async () => { | ||
mockFs.readdirSync.mockReturnValue([] as any) | ||
commandInstance = new MockedInstallCommand(['next'], config) | ||
|
||
http.get.mockResolvedValue({body: { | ||
version: '1.0.0', | ||
baseDir: 'test-cli', | ||
channel: 'next', | ||
gz: 'https://test-cli-oclif.s3.amazonaws.com/test-cli-v1.0.0/test-cli-v1.0.0.tar.gz', | ||
xz: 'https://test-cli-oclif.s3.amazonaws.com/test-cli-v1.0.0/test-cli-v1.0.0.tar.xz', | ||
sha256gz: 'cae9de53d3cb9bfdb43b5fd75b1d9f4655e07cf479a8d86658155ff66d618dbb', | ||
node: { | ||
compatible: '>=10', | ||
recommended: '10.24.0', | ||
}, | ||
}}) | ||
|
||
await commandInstance.run() | ||
|
||
expect(commandInstance.downloadAndExtract).toBeCalled() | ||
expect(commandInstance.updatedVersion).toBe('next') | ||
}) | ||
|
||
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) | ||
|
||
http.get.mockResolvedValue({body: { | ||
version: '2.2.1', | ||
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', | ||
sha256gz: 'cae9de53d3cb9bfdb43b5fd75b1d9f4655e07cf479a8d86658155ff66d618dbb', | ||
node: { | ||
compatible: '>=10', | ||
recommended: '10.24.0', | ||
}, | ||
}}) | ||
|
||
await commandInstance.run() | ||
|
||
expect(commandInstance.downloadAndExtract).toBeCalled() | ||
expect(commandInstance.updatedVersion).toBe('2.2.1') | ||
}) | ||
|
||
it('when requesting a version already available locally, will call updateToExistingVersion', async () => { | ||
mockFs.readdirSync.mockReturnValue([ | ||
'1.0.0-next.2', | ||
'1.0.0-next.3', | ||
'1.0.1', | ||
'1.0.0-alpha.0', | ||
] as any) | ||
commandInstance = new MockedInstallCommand(['1.0.0-next.3'], config) | ||
await commandInstance.run() | ||
|
||
expect(commandInstance.updateToExistingVersion).toBeCalled() | ||
expect(commandInstance.downloadAndExtract).not.toBeCalled() | ||
expect(commandInstance.updatedVersion).toBe('1.0.0-next.3') | ||
}) | ||
|
||
it('will handle an invalid version request', async () => { | ||
mockFs.readdirSync.mockReturnValue([] as any) | ||
commandInstance = new MockedInstallCommand(['2.2.1'], {...config, scopedEnvVarTrue: () => false}) | ||
http.get.mockRejectedValue(new Error('unable to find version')) | ||
|
||
let err | ||
|
||
try { | ||
await commandInstance.run() | ||
} catch (error) { | ||
err = error | ||
} | ||
|
||
expect(err.message).toBe('unable to find version') | ||
}) | ||
|
||
it('will handle an invalid channel request', async () => { | ||
mockFs.readdirSync.mockReturnValue([] as any) | ||
commandInstance = new MockedInstallCommand(['2.2.1'], {...config, scopedEnvVarTrue: () => true}) | ||
|
||
http.get.mockRejectedValue({statusCode: 403}) | ||
|
||
let err | ||
|
||
try { | ||
await commandInstance.run() | ||
} catch (error) { | ||
err = error | ||
} | ||
|
||
expect(commandInstance.downloadAndExtract).not.toBeCalled() | ||
expect(err.message).toBe('HTTP 403: Invalid channel undefined') | ||
}) | ||
}) |