Browse Source

Support `now alias` reading `config.alias` (#93)

* feat: support `now alias` reading config.alias

Reads the last deployment and will automatically alias to the package.json's config.alias property

* chore: corrected typo on `console.time`

* fix: use `root/now.alias` over `root/config.alias`
master
Remy Sharp 8 years ago
committed by Leo Lamprecht
parent
commit
ce32dce2aa
  1. 30
      bin/now-alias.js
  2. 141
      lib/index.js
  3. 112
      lib/read-metadata.js

30
bin/now-alias.js

@ -13,6 +13,7 @@ import login from '../lib/login'
import * as cfg from '../lib/cfg'
import {error} from '../lib/error'
import toHost from '../lib/to-host'
import readMetaData from '../lib/read-metadata'
const argv = minimist(process.argv.slice(2), {
string: ['config', 'token'],
@ -89,7 +90,7 @@ const exit = code => {
setTimeout(() => process.exit(code || 0), 100)
}
if (argv.help || !subcommand) {
if (argv.help) {
help()
exit(0)
} else {
@ -211,6 +212,11 @@ async function run(token) {
break
default:
if (argv._.length === 0) {
await realias(alias)
break
}
if (argv._.length === 2) {
await alias.set(String(argv._[0]), String(argv._[1]))
} else if (argv._.length >= 3) {
@ -285,3 +291,25 @@ function findAlias(alias, list) {
return _alias
}
async function realias(alias) {
const path = process.cwd()
const {pkg, name} = await readMetaData(path, {
deploymentType: 'npm', // FIXME: hard coding settings…
quiet: true // `quiet`
})
const pkgConfig = pkg ? pkg.now || {} : {}
const target = pkgConfig.alias
// the user never intended to support aliases from the package
if (!target) {
help()
return exit(0)
}
// now try to find the last deployment
const source = await alias.last(name)
await alias.set(source.url, target)
}

141
lib/index.js

@ -1,6 +1,6 @@
// Native
import {homedir} from 'os'
import {basename, resolve as resolvePath} from 'path'
import {resolve as resolvePath} from 'path'
import EventEmitter from 'events'
// Packages
@ -11,13 +11,13 @@ import {parse as parseIni} from 'ini'
import {readFile} from 'fs-promise'
import resumer from 'resumer'
import splitArray from 'split-array'
import {parse as parseDockerfile} from 'docker-file-parser'
// Ours
import {npm as getNpmFiles, docker as getDockerFiles} from './get-files'
import ua from './ua'
import hash from './hash'
import Agent from './agent'
import readMetaData from './read-metadata'
// how many concurrent HTTP/2 stream uploads
const MAX_CONCURRENT = 10
@ -47,122 +47,25 @@ export default class Now extends EventEmitter {
}) {
this._path = path
let pkg = {}
let name
let description
let files
if (deploymentType === 'npm') {
try {
pkg = await readFile(resolvePath(path, 'package.json'))
pkg = JSON.parse(pkg)
} catch (err) {
const e = Error(`Failed to read JSON in "${path}/package.json"`)
e.userError = true
throw e
}
if (!pkg.scripts || (!pkg.scripts.start && !pkg.scripts['now-start'])) {
const e = Error('Missing `start` (or `now-start`) script in `package.json`. ' +
'See: https://docs.npmjs.com/cli/start.')
e.userError = true
throw e
}
if (pkg.name === null || typeof pkg.name !== 'string') {
name = basename(path)
if (!quiet) {
console.log(`> No \`name\` in \`package.json\`, using ${chalk.bold(name)}`)
}
} else {
name = pkg.name
}
description = pkg.description
const {pkg, name, description} = await readMetaData(path, {
deploymentType,
quiet
})
if (this._debug) {
console.time('> [debug] Getting files')
}
if (this._debug) {
console.time('> [debug] Getting files')
}
if (deploymentType === 'npm') {
files = await getNpmFiles(path, pkg, {debug: this._debug})
if (this._debug) {
console.timeEnd('> [debug] Getting files')
}
} else if (deploymentType === 'docker') {
let docker
try {
const dockerfile = await readFile(resolvePath(path, 'Dockerfile'), 'utf8')
docker = parseDockerfile(dockerfile, {includeComments: true})
} catch (err) {
const e = Error(`Failed to parse "${path}/Dockerfile"`)
e.userError = true
throw e
}
if (docker.length <= 0) {
const e = Error('No commands found in `Dockerfile`')
e.userError = true
throw e
}
if (!docker.some(cmd => cmd.name === 'CMD')) {
const e = Error('No `CMD` found in `Dockerfile`. ' +
'See: https://docs.docker.com/engine/reference/builder/#/cmd')
e.userError = true
throw e
}
if (!docker.some(cmd => cmd.name === 'EXPOSE')) {
const e = Error('No `EXPOSE` found in `Dockerfile`. A port must be supplied. ' +
'See: https://docs.docker.com/engine/reference/builder/#/expose')
e.userError = true
throw e
}
const labels = {}
docker
.filter(cmd => cmd.name === 'LABEL')
.forEach(({args}) => {
for (const key in args) {
if (!{}.hasOwnProperty.call(args, key)) {
continue
}
// unescape and convert into string
try {
labels[key] = JSON.parse(args[key])
} catch (err) {
const e = Error(`Error parsing value for LABEL ${key} in \`Dockerfile\``)
e.userError = true
throw e
}
}
})
if (labels.name === null) {
name = basename(path)
if (!quiet) {
console.log(`> No \`name\` LABEL in \`Dockerfile\`, using ${chalk.bold(name)}`)
}
} else {
name = labels.name
}
description = labels.description
if (this._debug) {
console.time('> [debug] Getting files')
}
} else {
files = await getDockerFiles(path, {debug: this._debug})
}
if (this._debug) {
console.timeEnd('> [debug] Getting files')
}
if (this._debug) {
console.timeEnd('> [debug] Getting files')
}
const nowProperties = pkg ? pkg.now || {} : {}
@ -423,6 +326,22 @@ export default class Now extends EventEmitter {
})
}
async last(app) {
const deployments = await this.list(app)
const last = deployments.sort((a, b) => {
return b.created - a.created
}).shift()
if (!last) {
const e = Error(`No deployments found for "${app}"`)
e.userError = true
throw e
}
return last
}
getNameservers(domain) {
return new Promise(resolve => {
let fallback = false

112
lib/read-metadata.js

@ -0,0 +1,112 @@
import {basename, resolve as resolvePath} from 'path'
import chalk from 'chalk'
import {readFile} from 'fs-promise'
import {parse as parseDockerfile} from 'docker-file-parser'
export default async function (path, {
deploymentType = 'npm',
quiet = false
}) {
let pkg = {}
let name
let description
if (deploymentType === 'npm') {
try {
pkg = await readFile(resolvePath(path, 'package.json'))
pkg = JSON.parse(pkg)
} catch (err) {
const e = Error(`Failed to read JSON in "${path}/package.json"`)
e.userError = true
throw e
}
if (!pkg.scripts || (!pkg.scripts.start && !pkg.scripts['now-start'])) {
const e = Error('Missing `start` (or `now-start`) script in `package.json`. ' +
'See: https://docs.npmjs.com/cli/start.')
e.userError = true
throw e
}
if (pkg.name === null || typeof pkg.name !== 'string') {
name = basename(path)
if (!quiet) {
console.log(`> No \`name\` in \`package.json\`, using ${chalk.bold(name)}`)
}
} else {
name = pkg.name
}
description = pkg.description
} else if (deploymentType === 'docker') {
let docker
try {
const dockerfile = await readFile(resolvePath(path, 'Dockerfile'), 'utf8')
docker = parseDockerfile(dockerfile, {includeComments: true})
} catch (err) {
const e = Error(`Failed to parse "${path}/Dockerfile"`)
e.userError = true
throw e
}
if (docker.length <= 0) {
const e = Error('No commands found in `Dockerfile`')
e.userError = true
throw e
}
if (!docker.some(cmd => cmd.name === 'CMD')) {
const e = Error('No `CMD` found in `Dockerfile`. ' +
'See: https://docs.docker.com/engine/reference/builder/#/cmd')
e.userError = true
throw e
}
if (!docker.some(cmd => cmd.name === 'EXPOSE')) {
const e = Error('No `EXPOSE` found in `Dockerfile`. A port must be supplied. ' +
'See: https://docs.docker.com/engine/reference/builder/#/expose')
e.userError = true
throw e
}
const labels = {}
docker
.filter(cmd => cmd.name === 'LABEL')
.forEach(({args}) => {
for (const key in args) {
if (!{}.hasOwnProperty.call(args, key)) {
continue
}
// unescape and convert into string
try {
labels[key] = JSON.parse(args[key])
} catch (err) {
const e = Error(`Error parsing value for LABEL ${key} in \`Dockerfile\``)
e.userError = true
throw e
}
}
})
if (labels.name === null) {
name = basename(path)
if (!quiet) {
console.log(`> No \`name\` LABEL in \`Dockerfile\`, using ${chalk.bold(name)}`)
}
} else {
name = labels.name
}
description = labels.description
}
return {
name,
description,
pkg
}
}
Loading…
Cancel
Save