#!/usr/bin/env node // Packages const minimist = require('minimist') const chalk = require('chalk') const ms = require('ms') const printf = require('printf') require('epipebomb')() const supportsColor = require('supports-color') // Ours const Now = require('../lib') const login = require('../lib/login') const cfg = require('../lib/cfg') const { handleError, error } = require('../lib/error') const logo = require('../lib/utils/output/logo') const sort = require('../lib/sort-deployments') const argv = minimist(process.argv.slice(2), { string: ['config', 'token'], boolean: ['help', 'debug', 'all'], alias: { help: 'h', config: 'c', debug: 'd', token: 't' } }) const help = () => { console.log(` ${chalk.bold(`${logo} now list`)} [app] ${chalk.dim('Options:')} -h, --help Output usage information -c ${chalk.bold.underline('FILE')}, --config=${chalk.bold.underline('FILE')} Config file -d, --debug Debug mode [off] -t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline('TOKEN')} Login token ${chalk.dim('Examples:')} ${chalk.gray('–')} List all deployments ${chalk.cyan('$ now ls')} ${chalk.gray('–')} List all deployments for the app ${chalk.dim('`my-app`')} ${chalk.cyan('$ now ls my-app')} ${chalk.dim('Alias:')} ls `) } if (argv.help) { help() process.exit(0) } const app = argv._[0] // Options const debug = argv.debug const apiUrl = argv.url || 'https://api.zeit.co' if (argv.config) { cfg.setConfigFile(argv.config) } Promise.resolve().then(async () => { const config = await cfg.read({ token: argv.token }) let token try { token = config.token || (await login(apiUrl)) } catch (err) { error(`Authentication error – ${err.message}`) process.exit(1) } try { await list({ token, config }) } catch (err) { error(`Unknown error: ${err}\n${err.stack}`) process.exit(1) } }) async function list({ token, config: { currentTeam, user } }) { const now = new Now({ apiUrl, token, debug, currentTeam }) const start = new Date() if (argv.all && !app) { console.log('> You must define an app when using `--all`') process.exit(1) } let deployments try { deployments = await now.list(app) } catch (err) { handleError(err) process.exit(1) } if (!deployments || (Array.isArray(deployments) && deployments.length <= 0)) { const match = await now.findDeployment(app) if (match !== null && typeof match !== 'undefined') { deployments = Array.of(match) } } if (!deployments || (Array.isArray(deployments) && deployments.length <= 0)) { const aliases = await now.listAliases() const item = aliases.find(e => e.uid === app || e.alias === app) if (item) { const match = await now.findDeployment(item.deploymentId) if (match !== null && typeof match !== 'undefined') { deployments = Array.of(match) } } } now.close() const apps = new Map() if (argv.all) { await Promise.all( deployments.map(async ({ uid }, i) => { deployments[i].instances = await now.listInstances(uid) }) ) } for (const dep of deployments) { const deps = apps.get(dep.name) || [] apps.set(dep.name, deps.concat(dep)) } const sorted = await sort([...apps]) const urlLength = deployments.reduce((acc, i) => { return Math.max(acc, (i.url && i.url.length) || 0) }, 0) + 5 const timeNow = new Date() console.log( `> ${deployments.length} deployment${deployments.length === 1 ? '' : 's'} found under ${chalk.bold((currentTeam && currentTeam.slug) || user.username || user.email)} ${chalk.grey('[' + ms(timeNow - start) + ']')}` ) let shouldShowAllInfo = false for (const app of apps) { shouldShowAllInfo = app[1].length > 5 || app.find(depl => { return depl.scale && depl.scale.current > 1 }) if (shouldShowAllInfo) { break } } if (!argv.all && shouldShowAllInfo) { console.log( `> To expand the list and see instances run ${chalk.cyan('`now ls --all [app]`')}` ) } console.log() sorted.forEach(([name, deps]) => { const listedDeployments = argv.all ? deps : deps.slice(0, 5) console.log( `${chalk.bold(name)} ${chalk.gray('(' + listedDeployments.length + ' of ' + deps.length + ' total)')}` ) const urlSpec = `%-${urlLength}s` console.log( printf( ` ${chalk.grey(urlSpec + ' %8s %-16s %8s')}`, 'url', 'inst #', 'state', 'age' ) ) listedDeployments.forEach(dep => { let state = dep.state let extraSpaceForState = 0 if (state === null || typeof state === 'undefined') { state = 'DEPLOYMENT_ERROR' } if (/ERROR/.test(state)) { state = chalk.red(state) extraSpaceForState = 10 } else if (state === 'FROZEN') { state = chalk.grey(state) extraSpaceForState = 10 } let spec if (supportsColor) { spec = ` %-${urlLength + 10}s %8s %-${extraSpaceForState + 16}s %8s` } else { spec = ` %-${urlLength + 1}s %8s %-${16}s %8s` } console.log( printf( spec, chalk.underline(dep.url), dep.scale ? dep.scale.current : '✖', state, ms(timeNow - dep.created) ) ) if (Array.isArray(dep.instances) && dep.instances.length > 0) { dep.instances.forEach(i => { console.log( printf(` %-${urlLength + 10}s`, ` - ${chalk.underline(i.url)}`) ) }) console.log() } }) console.log() }) }