-
Notifications
You must be signed in to change notification settings - Fork 224
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(spaces): Move command spaces:wait to oclif (#2841)
* Covert spaces:wait to oclif * Remove semicolons
- Loading branch information
Showing
6 changed files
with
238 additions
and
196 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,98 @@ | ||
import color from '@heroku-cli/color' | ||
import {Command, flags} from '@heroku-cli/command' | ||
import {Args, ux} from '@oclif/core' | ||
import * as Heroku from '@heroku-cli/schema' | ||
import heredoc from 'tsheredoc' | ||
import Spinner from '@oclif/core/lib/cli-ux/action/spinner' | ||
import debug from 'debug' | ||
import {renderInfo} from '../../lib/spaces/spaces' | ||
import {Notification, notify} from '@heroku-cli/notifications' | ||
|
||
const pgDebug = debug('pg') | ||
|
||
export default class Wait extends Command { | ||
static topic = 'spaces' | ||
static description = 'wait for a space to be created' | ||
static flags = { | ||
space: flags.string({char: 's', description: 'space to get info of'}), | ||
json: flags.boolean({description: 'output in json format'}), | ||
interval: flags.integer({ | ||
char: 'i', | ||
description: 'seconds to wait between poll intervals', | ||
default: 30, | ||
}), | ||
timeout: flags.integer({ | ||
char: 't', | ||
description: 'maximum number of seconds to wait', | ||
default: 25 * 60, | ||
}), | ||
} | ||
|
||
static args = { | ||
space: Args.string({hidden: true}), | ||
} | ||
|
||
public async run(): Promise<void> { | ||
const {flags, args} = await this.parse(Wait) | ||
const spaceName = flags.space || args.space | ||
if (!spaceName) { | ||
ux.error(heredoc(` | ||
Error: Missing 1 required arg: | ||
space | ||
See more help with --help | ||
`)) | ||
} | ||
|
||
const interval = flags.interval * 1000 | ||
const timeout = flags.timeout * 1000 | ||
const deadline = new Date(Date.now() + timeout) | ||
const action = new Spinner() | ||
action.start(`Waiting for space ${color.green(spaceName as string)} to allocate`) | ||
let headers = {} | ||
if (!flags.json) { | ||
headers = {'Accept-Expansion': 'region'} | ||
} | ||
|
||
let {body: space} = await this.heroku.get<Heroku.Space>(`/spaces/${spaceName}`, {headers}) | ||
while (space.state === 'allocating') { | ||
if (new Date() > deadline) { | ||
throw new Error('Timeout waiting for space to become allocated.') | ||
} | ||
|
||
await this.wait(interval) | ||
const {body: updatedSpace} = await this.heroku.get<Heroku.Space>(`/spaces/${spaceName}`, {headers}) | ||
space = updatedSpace | ||
} | ||
|
||
try { | ||
const {body: nat} = await this.heroku.get<Heroku.SpaceNetworkAddressTranslation>(`/spaces/${spaceName}/nat`) | ||
space.outbound_ips = nat | ||
} catch (error) { | ||
pgDebug(`Retrieving NAT details for the space failed with ${error}`) | ||
} | ||
|
||
action.stop() | ||
renderInfo(space, flags.json) | ||
this.notify(spaceName as string) | ||
} | ||
|
||
protected wait(ms: number) { | ||
return new Promise(resolve => setTimeout(resolve, ms)) | ||
} | ||
|
||
protected notify(spaceName: string) { | ||
try { | ||
const notification: Notification & { | ||
sound?: boolean, message?: string, title?: string, subtitle?: string | ||
} = { | ||
title: spaceName, | ||
subtitle: `heroku spaces:wait ${spaceName}`, | ||
message: 'space was successfully created', | ||
sound: true, | ||
} | ||
notify(notification) | ||
} catch (error: any) { | ||
ux.warn(error) | ||
} | ||
} | ||
} |
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
119 changes: 119 additions & 0 deletions
119
packages/cli/test/unit/commands/spaces/wait.unit.test.ts
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,119 @@ | ||
import {stderr, stdout} from 'stdout-stderr' | ||
import Cmd from '../../../../src/commands/spaces/wait' | ||
import runCommand from '../../../helpers/runCommand' | ||
import * as nock from 'nock' | ||
import heredoc from 'tsheredoc' | ||
import {expect} from 'chai' | ||
import expectOutput from '../../../helpers/utils/expectOutput' | ||
import * as fixtures from '../../../fixtures/spaces/fixtures' | ||
import * as sinon from 'sinon' | ||
|
||
describe('spaces:wait', function () { | ||
const allocatingSpace = fixtures.spaces['allocating-space'] | ||
const allocatedSpace = fixtures.spaces['non-shield-space'] | ||
let sandbox: sinon.SinonSandbox | ||
let notifySpy: sinon.SinonSpy | ||
|
||
beforeEach(() => { | ||
sandbox = sinon.createSandbox() | ||
notifySpy = sandbox.spy(require('@heroku-cli/notifications'), 'notify') | ||
}) | ||
|
||
afterEach(() => { | ||
sandbox.restore() | ||
}) | ||
|
||
it('waits for space to allocate and then shows space info', async function () { | ||
nock('https://api.heroku.com', {reqheaders: {'Accept-Expansion': 'region'}}) | ||
.get(`/spaces/${allocatingSpace.name}`) | ||
.reply(200, allocatingSpace) | ||
.get(`/spaces/${allocatingSpace.name}`) | ||
.reply(200, allocatedSpace) | ||
nock('https://api.heroku.com') | ||
.get(`/spaces/${allocatedSpace.name}/nat`) | ||
.reply(200, {state: 'enabled', sources: ['123.456.789.123']}) | ||
|
||
await runCommand(Cmd, [ | ||
'--space', | ||
allocatedSpace.name, | ||
'--interval', | ||
'0', | ||
]) | ||
expectOutput(stderr.output, heredoc(` | ||
Waiting for space ${allocatedSpace.name} to allocate... | ||
Waiting for space ${allocatedSpace.name} to allocate... done | ||
`)) | ||
expectOutput(stdout.output, heredoc(` | ||
=== ${allocatedSpace.name} | ||
ID: ${allocatedSpace.id} | ||
Team: ${allocatedSpace.team.name} | ||
Region: ${allocatedSpace.region.description} | ||
CIDR: ${allocatedSpace.cidr} | ||
Data CIDR: ${allocatedSpace.data_cidr} | ||
State: ${allocatedSpace.state} | ||
Shield: off | ||
Outbound IPs: 123.456.789.123 | ||
Created at: ${allocatedSpace.created_at} | ||
`)) | ||
expect(notifySpy.called).to.be.true | ||
expect(notifySpy.calledOnce).to.be.true | ||
}) | ||
|
||
it('waits for space with --json', async function () { | ||
nock('https://api.heroku.com') | ||
.get(`/spaces/${allocatingSpace.name}`) | ||
.reply(200, allocatingSpace) | ||
.get(`/spaces/${allocatedSpace.name}`) | ||
.reply(200, allocatedSpace) | ||
nock('https://api.heroku.com') | ||
.get(`/spaces/${allocatedSpace.name}/nat`) | ||
.reply(200, {state: 'enabled', sources: ['123.456.789.123']}) | ||
|
||
await runCommand(Cmd, [ | ||
'--space', | ||
allocatedSpace.name, | ||
'--json', | ||
'--interval', | ||
'0', | ||
]) | ||
const allocatedSpaceWithOutboundIPs = Object.assign( | ||
{}, | ||
allocatedSpace, | ||
{outbound_ips: {state: 'enabled', sources: ['123.456.789.123']}}, | ||
) | ||
expectOutput(stderr.output, heredoc(` | ||
Waiting for space ${allocatedSpace.name} to allocate... | ||
Waiting for space ${allocatedSpace.name} to allocate... done | ||
`)) | ||
expectOutput(stdout.output, JSON.stringify(allocatedSpaceWithOutboundIPs, null, 2)) | ||
}) | ||
|
||
it('not failing when nat is unavailable for space which is allocated', async function () { | ||
nock('https://api.heroku.com', {reqheaders: {'Accept-Expansion': 'region'}}) | ||
.get(`/spaces/${allocatedSpace.name}`) | ||
.reply(200, allocatedSpace) | ||
nock('https://api.heroku.com') | ||
.get(`/spaces/${allocatedSpace.name}/nat`) | ||
.reply(503, {}) | ||
|
||
await runCommand(Cmd, [ | ||
'--space', | ||
allocatedSpace.name, | ||
'--interval', | ||
'0', | ||
]) | ||
expectOutput(stdout.output, heredoc(` | ||
=== ${allocatedSpace.name} | ||
ID: ${allocatedSpace.id} | ||
Team: ${allocatedSpace.team.name} | ||
Region: ${allocatedSpace.region.description} | ||
CIDR: ${allocatedSpace.cidr} | ||
Data CIDR: ${allocatedSpace.data_cidr} | ||
State: ${allocatedSpace.state} | ||
Shield: off | ||
Created at: ${allocatedSpace.created_at} | ||
`)) | ||
expect(notifySpy.called).to.be.true | ||
expect(notifySpy.calledOnce).to.be.true | ||
}) | ||
}) |
This file was deleted.
Oops, something went wrong.
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
Oops, something went wrong.