You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

223 lines
5.6 KiB

#!/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()
})
}