Skip to content

Commit

Permalink
add now.json support
Browse files Browse the repository at this point in the history
  • Loading branch information
rauchg committed Jan 26, 2017
2 parents 168f553 + f6e67cb commit 83326fd
Show file tree
Hide file tree
Showing 16 changed files with 166 additions and 34 deletions.
5 changes: 2 additions & 3 deletions bin/now-alias.js
Expand Up @@ -296,13 +296,12 @@ function findAlias(alias, list) {

async function realias(alias) {
const path = process.cwd()
const {pkg, name} = await readMetaData(path, {
const {nowConfig, name} = await readMetaData(path, {
deploymentType: 'npm', // hard coding settings…
quiet: true // `quiet`
})

const pkgConfig = pkg ? pkg.now || {} : {}
const target = pkgConfig.alias
const target = nowConfig && nowConfig.alias

// the user never intended to support aliases from the package
if (!target) {
Expand Down
4 changes: 2 additions & 2 deletions bin/now-deploy.js
Expand Up @@ -363,7 +363,7 @@ async function sync(token) {
}
}

const {pkg: {now: pkgConfig = {}} = {}} = await readMetaData(path, {
const {nowConfig} = await readMetaData(path, {
deploymentType,
deploymentName,
isStatic,
Expand All @@ -373,7 +373,7 @@ async function sync(token) {
const now = new Now(apiUrl, token, {debug})

// Merge `now.env` from package.json with `-e` arguments.
const pkgEnv = pkgConfig.env
const pkgEnv = nowConfig && nowConfig.env
const envs = [
...Object.keys(pkgEnv || {}).map(k => `${k}=${pkgEnv[k]}`),
...[].concat(argv.env || [])
Expand Down
29 changes: 23 additions & 6 deletions lib/get-files.js
Expand Up @@ -24,11 +24,15 @@ const IGNORED = require('./ignored')
* @return {Array} comprehensive list of paths to sync
*/

async function npm(path, pkg, {
async function npm(path, pkg, nowConfig = null, {
limit = null,
hasNowJson = false,
debug = false
} = {}) {
const whitelist = pkg.now && pkg.now.files ? pkg.now.files : pkg.files
const whitelist = (nowConfig && nowConfig.files) || pkg.files

// the package.json `files` whitelist still
// honors ignores: https://docs.npmjs.com/files/package.json#files
const search_ = whitelist || ['.']
// convert all filenames into absolute paths
const search = Array.prototype.concat.apply([], (await Promise.all(search_.map(file => glob(file, {cwd: path, absolute: true, dot: true})))))
Expand Down Expand Up @@ -92,6 +96,10 @@ async function npm(path, pkg, {
// source: https://docs.npmjs.com/files/package.json#files
files.push(asAbsolute('package.json', path))

if (hasNowJson) {
files.push(asAbsolute('now.json', path))
}

// get files
return unique(files)
}
Expand Down Expand Up @@ -125,12 +133,17 @@ const asAbsolute = function (path, parent) {
* @return {Array} comprehensive list of paths to sync
*/

async function docker(path, {
async function docker(path, nowConfig = null, {
limit = null,
hasNowJson = false,
debug = false
} = {}) {
const whitelist = nowConfig && nowConfig.files

// base search path
const search_ = ['.']
// the now.json `files` whitelist still
// honors ignores: https://docs.npmjs.com/files/package.json#files
const search_ = whitelist || ['.']

// convert all filenames into absolute paths
const search = search_.map(file => asAbsolute(file, path))
Expand Down Expand Up @@ -176,6 +189,10 @@ async function docker(path, {
// source: https://docs.npmjs.com/files/package.json#files
files.push(asAbsolute('Dockerfile', path))

if (hasNowJson) {
files.push(asAbsolute('now.json', path))
}

// get files
return unique(files)
}
Expand Down Expand Up @@ -206,7 +223,7 @@ const glob = async function (pattern, options) {
* @return {Array} of {String}s of full paths
*/

const explode = async function (paths, {accepts, debug}) {
async function explode(paths, {accepts, debug}) {
const list = async file => {
let path = file
let s
Expand Down Expand Up @@ -262,7 +279,7 @@ const explode = async function (paths, {accepts, debug}) {

const maybeRead = async function (path, default_ = '') {
try {
return (await readFile(path, 'utf8'))
return await readFile(path, 'utf8')
} catch (err) {
return default_
}
Expand Down
15 changes: 8 additions & 7 deletions lib/index.js
Expand Up @@ -53,30 +53,31 @@ module.exports = class Now extends EventEmitter {

let files

const {pkg, name, description} = await readMetaData(path, {
const meta = await readMetaData(path, {
deploymentType,
deploymentName,
quiet,
isStatic
})
const {pkg, name, description, nowConfig, hasNowJson} = meta
deploymentType = meta.deploymentType

if (this._debug) {
console.time('> [debug] Getting files')
}

const opts = {debug: this._debug, hasNowJson}
if (deploymentType === 'npm') {
files = await getNpmFiles(path, pkg, {debug: this._debug})
files = await getNpmFiles(path, pkg, nowConfig, opts)
} else {
files = await getDockerFiles(path, {debug: this._debug})
files = await getDockerFiles(path, nowConfig, opts)
}

if (this._debug) {
console.timeEnd('> [debug] Getting files')
}

const nowProperties = pkg ? pkg.now || {} : {}

forwardNpm = forwardNpm || nowProperties.forwardNpm
forwardNpm = forwardNpm || (nowConfig && nowConfig.forwardNpm)

// Read .npmrc
let npmrc = {}
Expand Down Expand Up @@ -118,7 +119,7 @@ module.exports = class Now extends EventEmitter {

this._files = hashes

const engines = nowProperties.engines || pkg.engines
const engines = (nowConfig && nowConfig.engines) || pkg.engines

const deployment = await this.retry(async bail => {
if (this._debug) {
Expand Down
63 changes: 56 additions & 7 deletions lib/read-metadata.js
Expand Up @@ -12,32 +12,59 @@ const listPackage = {
}
}

module.exports = async function (path, {
module.exports = readMetaData

async function readMetaData(path, {
deploymentType = 'npm',
deploymentName,
quiet = false,
strict = true,
isStatic = false
}) {
let pkg = {}
let nowConfig = null
let hasNowJson = false

let name
let description

try {
nowConfig = JSON.parse(await readFile(resolvePath(path, 'now.json')))
hasNowJson = true
} catch (err) {
// if the file doesn't exist then that's fine; any other error bubbles up
if (err.code !== 'ENOENT') {
const e = Error(`Failed to read JSON in "${path}/now.json"`)
e.userError = true
throw e
}
}

if (hasNowJson) {
// user can specify the type of deployment explicitly in the `now.json` file
// when both a package.json and Dockerfile exist
if (nowConfig.type) {
deploymentType = nowConfig.type
}
if (nowConfig.name) {
deploymentName = nowConfig.name
}
}

if (deploymentType === 'npm') {
if (isStatic) {
pkg = listPackage
} else {
try {
pkg = await readFile(resolvePath(path, 'package.json'))
pkg = JSON.parse(pkg)
pkg = JSON.parse(await readFile(resolvePath(path, 'package.json')))
} 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'])) {
if (strict && (!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
Expand Down Expand Up @@ -68,7 +95,7 @@ module.exports = async function (path, {
throw e
}

if (docker.length <= 0) {
if (strict && docker.length <= 0) {
const e = Error('No commands found in `Dockerfile`')
e.userError = true
throw e
Expand Down Expand Up @@ -101,21 +128,43 @@ module.exports = async function (path, {
name = basename(path)

if (!quiet) {
console.log(`> No \`name\` LABEL in \`Dockerfile\`, using ${chalk.bold(name)}`)
if (hasNowJson) {
console.log(`> No \`name\` LABEL in \`Dockerfile\` or \`name\` field in \`now.json\`, using ${chalk.bold(name)}`)
} else {
console.log(`> No \`name\` LABEL in \`Dockerfile\`, using ${chalk.bold(name)}`)
}
}
}
}

description = labels.description
} else {
throw new TypeError(`Unsupported "deploymentType": ${deploymentType}`)
}

if (deploymentName) {
name = deploymentName
}

if (pkg.now) {
// if the project has both a `now.json` and `now` Object in the `package.json`
// file, then fail hard and let the user know that they need to pick one or the
// other
if (hasNowJson) {
const e = new Error('You have a `now` configuration field inside `package.json`, but configuration is also present in `now.json`! Please ensure there\'s a single source of configuration by removing one')
e.userError = true
throw e
} else {
nowConfig = pkg.now
}
}

return {
name,
description,
pkg
deploymentType,
pkg,
nowConfig,
hasNowJson
}
}
1 change: 1 addition & 0 deletions test/_fixtures/now-json-docker/Dockerfile
@@ -0,0 +1 @@
CMD echo 'world'
1 change: 1 addition & 0 deletions test/_fixtures/now-json-docker/a.js
@@ -0,0 +1 @@
// should not be included
1 change: 1 addition & 0 deletions test/_fixtures/now-json-docker/b.js
@@ -0,0 +1 @@
// should be included
6 changes: 6 additions & 0 deletions test/_fixtures/now-json-docker/now.json
@@ -0,0 +1,6 @@
{
"type": "docker",
"files": [
"b.js"
]
}
3 changes: 3 additions & 0 deletions test/_fixtures/now-json-throws/now.json
@@ -0,0 +1,3 @@
{
"alias": "bar.com"
}
9 changes: 9 additions & 0 deletions test/_fixtures/now-json-throws/package.json
@@ -0,0 +1,9 @@
{
"name": "woot",
"version": "0.0.1",
"description": "",
"dependencies": {},
"now": {
"alias": "foo.com"
}
}
1 change: 1 addition & 0 deletions test/_fixtures/now-json/a.js
@@ -0,0 +1 @@
// should not be included
1 change: 1 addition & 0 deletions test/_fixtures/now-json/b.js
@@ -0,0 +1 @@
// should be included
5 changes: 5 additions & 0 deletions test/_fixtures/now-json/now.json
@@ -0,0 +1,5 @@
{
"files": [
"b.js"
]
}
9 changes: 9 additions & 0 deletions test/_fixtures/now-json/package.json
@@ -0,0 +1,9 @@
{
"name": "woot",
"version": "0.0.1",
"description": "",
"dependencies": {},
"files": [
"a.js"
]
}
47 changes: 38 additions & 9 deletions test/index.js
Expand Up @@ -4,25 +4,20 @@ const {join, resolve} = require('path')
// Packages
const test = require('ava')
const {asc: alpha} = require('alpha-sort')
const {readFile} = require('fs-promise')

// Ours
const {npm: getNpmFiles_, docker: getDockerFiles} = require('../lib/get-files')
const hash = require('../lib/hash')
const readMetadata = require('../lib/read-metadata')
const {npm: getNpmFiles_, docker: getDockerFiles} = require('../lib/get-files')

const prefix = join(__dirname, '_fixtures') + '/'
const base = path => path.replace(prefix, '')
const fixture = name => resolve(`./test/_fixtures/${name}`)

const readJSON = async file => {
const data = await readFile(file)
return JSON.parse(data)
}

// overload to force debugging
const getNpmFiles = async dir => {
const pkg = await readJSON(resolve(dir, 'package.json'))
return getNpmFiles_(dir, pkg)
const {pkg, nowConfig, hasNowJson} = await readMetadata(dir, {quiet: true, strict: false})
return getNpmFiles_(dir, pkg, nowConfig, {hasNowJson})
}

test('`files`', async t => {
Expand Down Expand Up @@ -170,3 +165,37 @@ test('prefix regression', async t => {
t.is(base(files[0]), 'prefix-regression/package.json')
t.is(base(files[1]), 'prefix-regression/woot.js')
})

test('support `now.json` files with package.json', async t => {
let files = await getNpmFiles(fixture('now-json'))
files = files.sort(alpha)
t.is(files.length, 3)
t.is(base(files[0]), 'now-json/b.js')
t.is(base(files[1]), 'now-json/now.json')
t.is(base(files[2]), 'now-json/package.json')
})

test('support `now.json` files with Dockerfile', async t => {
const f = fixture('now-json-docker')
const {deploymentType, nowConfig, hasNowJson} = await readMetadata(f, {quiet: true, strict: false})
t.is(deploymentType, 'docker')

let files = await getDockerFiles(f, nowConfig, {hasNowJson})
files = files.sort(alpha)
t.is(files.length, 3)
t.is(base(files[0]), 'now-json-docker/Dockerfile')
t.is(base(files[1]), 'now-json-docker/b.js')
t.is(base(files[2]), 'now-json-docker/now.json')
})

test('throws when both `now.json` and `package.json:now` exist', async t => {
let e
try {
await readMetadata(fixture('now-json-throws'), {quiet: true, strict: false})
} catch (err) {
e = err
}
t.is(e.name, 'Error')
t.is(e.userError, true)
t.pass(/please ensure there's a single source of configuration/i.test(e.message))
})

0 comments on commit 83326fd

Please sign in to comment.