From 9ade9b0921ca62d61abc1656ec8be316978cad51 Mon Sep 17 00:00:00 2001 From: Tony Kovanen Date: Sun, 17 Apr 2016 00:15:21 +0300 Subject: [PATCH] Add sketch of `now-rm` --- bin/now | 4 +-- bin/now-deploy | 2 ++ bin/now-remove | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/index.js | 24 ++++++++++++++++++ 4 files changed, 97 insertions(+), 2 deletions(-) create mode 100755 bin/now-remove diff --git a/bin/now b/bin/now index ed777ff..7adc132 100755 --- a/bin/now +++ b/bin/now @@ -18,8 +18,8 @@ const exit = (code) => { setTimeout(() => process.exit(code), 1000); }; -const commands = new Set(['deploy', 'list', 'ls']); -const aliases = new Map([['ls', 'list']]); +const commands = new Set(['deploy', 'list', 'ls', 'rm', 'remove']); +const aliases = new Map([['ls', 'list'], ['rm', 'remove']]); let cmd = argv._[0]; let args; diff --git a/bin/now-deploy b/bin/now-deploy index e96743b..73302fc 100755 --- a/bin/now-deploy +++ b/bin/now-deploy @@ -22,6 +22,8 @@ const help = () => { list output list of instances ls alias of list + rm remove a deployment by deployment id + remove alias of rm Options: diff --git a/bin/now-remove b/bin/now-remove new file mode 100755 index 0000000..8590d1b --- /dev/null +++ b/bin/now-remove @@ -0,0 +1,69 @@ +#!/usr/bin/env node + +import minimist from 'minimist'; +import chalk from 'chalk'; +import ms from 'ms'; +import Now from '../lib'; +import login from '../lib/login'; +import * as cfg from '../lib/cfg'; +import { handleError, error } from '../lib/error'; + +const argv = minimist(process.argv.slice(2)); +const deploymentId = argv._[0]; + +if (!deploymentId) { + console.log(`${chalk.cyan('> No deployment id specified. You can see active deployments with `now ls`.')}`); + process.exit(1); +} + +// options +const debug = argv.debug || argv.d; +const apiUrl = argv.url || 'https://api.now.sh'; + +const config = cfg.read(); + +function readConfirmation () { + return new Promise((resolve, reject) => { + process.stdout.write(`${chalk.cyan('> Are you sure? ')} ${chalk.bold(deploymentId)} ${chalk.cyan('will be removed permanently')} [${chalk.bold('yN')}]`); + process.stdin.on('data', (d) => { + process.stdin.pause(); + resolve(d.toString().trim()); + }).resume(); + }); +} + +Promise.resolve(config.token || login(apiUrl)) +.then(async (token) => { + try { + await remove(token); + } catch (err) { + error(`Unknown error: ${err.stack}`); + process.exit(1); + } +}) +.catch((e) => { + error(`Authentication error – ${e.message}`); + process.exit(1); +}); + +async function remove (token) { + const now = new Now(apiUrl, token, { debug }); + + try { + const confirmation = (await readConfirmation()).toLowerCase(); + if ('y' !== confirmation) { + console.log(`${chalk.cyan('> Aborted ')}`); + return; + } + + const start = new Date(); + await now.remove(deploymentId); + const elapsed = ms(new Date() - start); + console.log(`${chalk.cyan('> Deployment ')} ${chalk.bold(deploymentId)} ${chalk.cyan('removed')} [${elapsed}]`); + } catch (err) { + handleError(err); + process.exit(1); + } + + now.close(); +} diff --git a/lib/index.js b/lib/index.js index 773dd97..3893d41 100644 --- a/lib/index.js +++ b/lib/index.js @@ -185,6 +185,30 @@ export default class Now extends EventEmitter { return deployments; } + async remove (deploymentId) { + await retry(async (bail) => { + if (this._debug) console.time('> [debug] /remove'); + const res = await this._fetch('/remove', { + method: 'DELETE' + }); + if (this._debug) console.timeEnd('> [debug] /remove'); + + // no retry on 4xx + if (400 <= res.status && 500 > res.status) { + if (this._debug) { + console.log('> [debug] bailing on listing due to %s', res.status); + } + return bail(responseError(res)); + } + + if (200 !== res.status) { + throw new Error('Removing deployment failed'); + } + }, { retries: 3, minTimeout: 2500, onRetry: this._onRetry }); + + return true; + } + _onRetry (err) { if (this._debug) { console.log(`> [debug] Retrying: ${err.stack}`);