From 04e50b24e49a9d573ad7ff431268ac735a31d9b4 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Fri, 25 Nov 2016 15:13:17 +0100 Subject: [PATCH 001/160] Basic implementation for GitHub deployments --- bin/now-deploy.js | 26 ++++++++++++--- lib/github.js | 82 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 4 ++- 3 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 lib/github.js diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 84f0922..332bf54 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -22,6 +22,7 @@ import toHumanPath from '../lib/utils/to-human-path' import promptOptions from '../lib/utils/prompt-options' import {handleError, error} from '../lib/error' import readMetaData from '../lib/read-metadata' +import {onGitHub, isRepoPath} from '../lib/github' const argv = minimist(process.argv.slice(2), { string: [ @@ -192,18 +193,35 @@ if (argv.h || argv.help) { async function sync(token) { const start = Date.now() + const rawPath = argv._[0] - if (!quiet) { - console.log(`> Deploying ${chalk.bold(toHumanPath(path))}`) + const stopDeployment = msg => { + error(msg) + process.exit(1) } try { await stat(path) } catch (err) { - error(`Could not read directory ${chalk.bold(path)}`) - process.exit(1) + const repo = await onGitHub(rawPath, debug) + + if (repo) { + path = repo + } else if (isRepoPath(rawPath)) { + stopDeployment(`This path neither exists, nor is there a repository named "${rawPath}" on GitHub`) + } else { + stopDeployment(`Could not read directory ${chalk.bold(path)}`) + } + + console.log(repo) + } + + if (!quiet) { + console.log(`> Deploying ${chalk.bold(toHumanPath(path))}`) } + process.exit() + let deploymentType let hasPackage diff --git a/lib/github.js b/lib/github.js new file mode 100644 index 0000000..12525e4 --- /dev/null +++ b/lib/github.js @@ -0,0 +1,82 @@ +// Packages +import fetch from 'node-fetch' +import download from 'download' +import tmp from 'tmp-promise' + +// Ours +import {error} from './error' + +const exists = async repoPath => { + const apiURL = `https://api.github.com/repos/${repoPath}` + let request + + try { + request = await fetch(apiURL) + } catch(err) { + error(`Not able to check if repo exists - ${err.message}`) + return false + } + + const res = await request.json() + + if (!res.name) { + return false + } + + return res +} + +const downloadRepo = async repoPath => { + const url = `https://api.github.com/repos/${repoPath}/tarball` + + const tmpDir = await tmp.dir({ + keep: true + }) + + try { + await download(url, tmpDir.path, { + extract: true + }) + } catch (err) { + error(`Not able to download repo: ${err.stack}`) + } + + return tmpDir +} + +export const isRepoPath = path => { + if (!path) { + return false + } + + const slashCount = path.split('/').length - 1 + + if (!slashCount || slashCount > 1) { + return false + } + + return true +} + +export const onGitHub = async (path, debug) => { + let repo = await exists(path) + + try { + repo = await exists(path) + } catch(err) { + if (debug) { + console.log(`Repository "${path}" does not exist on GitHub`) + } + + return false + } + + if (!repo) { + return false + } + + const tmpDir = await downloadRepo(path) + console.log(tmpDir) + + return 'test' +} diff --git a/package.json b/package.json index ccda899..3b6c4e8 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "copy-paste": "1.3.0", "cross-spawn": "5.0.1", "docker-file-parser": "0.1.0", + "download": "5.0.2", "email-prompt": "0.1.8", "email-validator": "1.0.7", "fs-promise": "1.0.0", @@ -89,7 +90,8 @@ "socket.io-client": "1.6.0", "spdy": "3.4.4", "split-array": "1.0.1", - "text-table": "0.2.0" + "text-table": "0.2.0", + "tmp-promise": "1.0.2" }, "devDependencies": { "alpha-sort": "1.0.2", From 6a1837c4af7b9d266043e4d0f513ec52004f73fe Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Fri, 25 Nov 2016 15:28:08 +0100 Subject: [PATCH 002/160] Make users able to deploy GitHub repos --- bin/now-deploy.js | 13 +++++++++---- lib/github.js | 31 ++++++++++++++++++++----------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 332bf54..69a8ea4 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -195,6 +195,8 @@ async function sync(token) { const start = Date.now() const rawPath = argv._[0] + let gitHubRepo + const stopDeployment = msg => { error(msg) process.exit(1) @@ -206,18 +208,21 @@ async function sync(token) { const repo = await onGitHub(rawPath, debug) if (repo) { - path = repo + path = repo.path + gitHubRepo = repo } else if (isRepoPath(rawPath)) { stopDeployment(`This path neither exists, nor is there a repository named "${rawPath}" on GitHub`) } else { stopDeployment(`Could not read directory ${chalk.bold(path)}`) } - - console.log(repo) } if (!quiet) { - console.log(`> Deploying ${chalk.bold(toHumanPath(path))}`) + if (gitHubRepo) { + console.log(`> Deploying GitHub repository "${chalk.bold(toHumanPath(rawPath))}"`) + } else { + console.log(`> Deploying ${chalk.bold(toHumanPath(path))}`) + } } process.exit() diff --git a/lib/github.js b/lib/github.js index 12525e4..530026e 100644 --- a/lib/github.js +++ b/lib/github.js @@ -1,4 +1,8 @@ +// Native +import path from 'path' + // Packages +import fs from 'fs-promise' import fetch from 'node-fetch' import download from 'download' import tmp from 'tmp-promise' @@ -29,17 +33,16 @@ const exists = async repoPath => { const downloadRepo = async repoPath => { const url = `https://api.github.com/repos/${repoPath}/tarball` - const tmpDir = await tmp.dir({ + let tmpDir = await tmp.dir({ keep: true }) - try { - await download(url, tmpDir.path, { - extract: true - }) - } catch (err) { - error(`Not able to download repo: ${err.stack}`) - } + await download(url, tmpDir.path, { + extract: true + }) + + const tmpContents = await fs.readdir(tmpDir.path) + tmpDir.path = path.join(tmpDir.path, tmpContents[0]) return tmpDir } @@ -75,8 +78,14 @@ export const onGitHub = async (path, debug) => { return false } - const tmpDir = await downloadRepo(path) - console.log(tmpDir) + let tmpDir - return 'test' + try { + tmpDir = await downloadRepo(path) + } catch (err) { + error(`Not able to download repo: ${err.stack}`) + process.exit(1) + } + + return tmpDir } From e16a6eaa30e5cb72327e6343586b0629e5f15396 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Fri, 25 Nov 2016 15:31:18 +0100 Subject: [PATCH 003/160] Tell user that we're looking on GitHub --- bin/now-deploy.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 69a8ea4..c94bcc1 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -205,7 +205,12 @@ async function sync(token) { try { await stat(path) } catch (err) { - const repo = await onGitHub(rawPath, debug) + let repo + + if (isRepoPath(rawPath)) { + console.log('> Didn\'t find directory. Searching on GitHub...') + repo = await onGitHub(rawPath, debug) + } if (repo) { path = repo.path @@ -225,8 +230,6 @@ async function sync(token) { } } - process.exit() - let deploymentType let hasPackage From 43d0b5693af778731bf2b00a82b5bf01e9e645dd Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Fri, 25 Nov 2016 15:50:15 +0100 Subject: [PATCH 004/160] Remove tmp dir for repo after deployment went ok --- bin/now-deploy.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index c94bcc1..8ad9ef9 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -134,6 +134,9 @@ if (path) { path = process.cwd() } +// If the current deployment is a repo +let gitHubRepo + const exit = code => { // we give stdout some time to flush out // because there's a node bug where @@ -195,8 +198,6 @@ async function sync(token) { const start = Date.now() const rawPath = argv._[0] - let gitHubRepo - const stopDeployment = msg => { error(msg) process.exit(1) @@ -214,7 +215,7 @@ async function sync(token) { if (repo) { path = repo.path - gitHubRepo = repo + gitHubRepo = true } else if (isRepoPath(rawPath)) { stopDeployment(`This path neither exists, nor is there a repository named "${rawPath}" on GitHub`) } else { @@ -511,6 +512,15 @@ function printLogs(host) { if (!quiet) { console.log(`${chalk.cyan('> Deployment complete!')}`) } + + if (gitHubRepo) { + fs.removeSync(path) + + if (debug) { + console.log(`> [debug] Removed temporary repo directory`) + } + } + process.exit(0) }) } From fe6bd9b1f267cf80c44a01fad42b4b0abcf2cb3b Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Fri, 25 Nov 2016 16:10:10 +0100 Subject: [PATCH 005/160] Forgot to load fs-promise --- bin/now-deploy.js | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 8ad9ef9..fd57175 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -10,6 +10,7 @@ import bytes from 'bytes' import chalk from 'chalk' import minimist from 'minimist' import ms from 'ms' +import fs from 'fs-promise' // Ours import copy from '../lib/copy' From b9f9e71b9fc76120d2a95e3d4f4783e850a67fc8 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Fri, 25 Nov 2016 16:15:40 +0100 Subject: [PATCH 006/160] Neat loading animation for looking on GitHub --- bin/now-deploy.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index fd57175..848aa9a 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -210,8 +210,23 @@ async function sync(token) { let repo if (isRepoPath(rawPath)) { - console.log('> Didn\'t find directory. Searching on GitHub...') + process.stdout.write('> Didn\'t find directory. Searching on GitHub') + + let dotCount = 0 + + const dots = setInterval(() => { + dotCount++ + process.stdout.write('.') + + if (dotCount === 20) { + clearInterval(dots) + } + }, 500) + repo = await onGitHub(rawPath, debug) + + clearInterval(dots) + process.stdout.write('\n') } if (repo) { From 81a1b8946b9e22ce77a865cd4adca9b20f8ef140 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Fri, 25 Nov 2016 16:25:38 +0100 Subject: [PATCH 007/160] Install it globally --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8170c93..99d18ef 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Realtime global deployments served over HTTP/2. You can find the FAQ [here](http ## Usage -Firstly, make sure to install the package: +Firstly, make sure to install the package globally: ```bash $ npm install -g now From fd24ea0c6a426b5b65eaf2c23f2ef3b1e6f97b4f Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Fri, 25 Nov 2016 17:50:32 +0100 Subject: [PATCH 008/160] Fixed tests --- bin/now-deploy.js | 11 +++++------ lib/github.js | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 848aa9a..feb4a57 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -5,12 +5,11 @@ import {resolve} from 'path' // Packages import Progress from 'progress' -import {stat} from 'fs-promise' +import fs from 'fs-promise' import bytes from 'bytes' import chalk from 'chalk' import minimist from 'minimist' import ms from 'ms' -import fs from 'fs-promise' // Ours import copy from '../lib/copy' @@ -205,7 +204,7 @@ async function sync(token) { } try { - await stat(path) + await fs.stat(path) } catch (err) { let repo @@ -270,7 +269,7 @@ async function sync(token) { isStatic = true } else { try { - await stat(resolve(path, 'package.json')) + await fs.stat(resolve(path, 'package.json')) } catch (err) { hasPackage = true } @@ -278,7 +277,7 @@ async function sync(token) { [hasPackage, hasDockerfile] = await Promise.all([ await (async () => { try { - await stat(resolve(path, 'package.json')) + await fs.stat(resolve(path, 'package.json')) } catch (err) { return false } @@ -286,7 +285,7 @@ async function sync(token) { })(), await (async () => { try { - await stat(resolve(path, 'Dockerfile')) + await fs.stat(resolve(path, 'Dockerfile')) } catch (err) { return false } diff --git a/lib/github.js b/lib/github.js index 530026e..f47d864 100644 --- a/lib/github.js +++ b/lib/github.js @@ -16,7 +16,7 @@ const exists = async repoPath => { try { request = await fetch(apiURL) - } catch(err) { + } catch (err) { error(`Not able to check if repo exists - ${err.message}`) return false } @@ -33,7 +33,7 @@ const exists = async repoPath => { const downloadRepo = async repoPath => { const url = `https://api.github.com/repos/${repoPath}/tarball` - let tmpDir = await tmp.dir({ + const tmpDir = await tmp.dir({ keep: true }) @@ -66,7 +66,7 @@ export const onGitHub = async (path, debug) => { try { repo = await exists(path) - } catch(err) { + } catch (err) { if (debug) { console.log(`Repository "${path}" does not exist on GitHub`) } From 50db54fd83129726f47c0e6362936f00b9ee5bb1 Mon Sep 17 00:00:00 2001 From: Cody Zuschlag Date: Sat, 26 Nov 2016 12:12:26 +0100 Subject: [PATCH 009/160] pass flags to subcommands (#98) * rework args parsing * test args parsing --- bin/now.js | 30 ++++++++------- package.json | 1 + test/args-parsing.js | 88 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 test/args-parsing.js diff --git a/bin/now.js b/bin/now.js index ba5050f..551a954 100755 --- a/bin/now.js +++ b/bin/now.js @@ -29,6 +29,7 @@ const defaultCommand = 'deploy' const commands = new Set([ defaultCommand, + 'help', 'list', 'ls', 'rm', @@ -55,25 +56,26 @@ const aliases = new Map([ ['secret', 'secrets'] ]) -let cmd = argv._[0] -let args = [] +let cmd = defaultCommand +const args = process.argv.slice(2) +const index = args.findIndex(a => commands.has(a)) -if (cmd === 'help') { - cmd = argv._[1] +if (index > -1) { + cmd = args[index] + args.splice(index, 1) - if (!commands.has(cmd)) { - cmd = defaultCommand - } + if (cmd === 'help') { + if (index < args.length && commands.has(args[index])) { + cmd = args[index] + args.splice(index, 1) + } else { + cmd = defaultCommand + } - args.push('--help') -} + args.unshift('--help') + } -if (commands.has(cmd)) { cmd = aliases.get(cmd) || cmd - args = args.concat(process.argv.slice(3)) -} else { - cmd = defaultCommand - args = args.concat(process.argv.slice(2)) } let bin = resolve(__dirname, 'now-' + cmd) diff --git a/package.json b/package.json index ccda899..a3bd910 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "scripts": { "start": "gulp", "test": "xo && ava", + "pretest": "gulp compile", "prepublish": "gulp compile", "pkg": "pkg . --out-dir out" }, diff --git a/test/args-parsing.js b/test/args-parsing.js new file mode 100644 index 0000000..f56fccd --- /dev/null +++ b/test/args-parsing.js @@ -0,0 +1,88 @@ +import path from 'path' +import test from 'ava' +import {spawn} from 'cross-spawn' + +const deployHelpMessage = '𝚫 now [options] ' +const aliasHelpMessage = '𝚫 now alias ' + +test('"now help" prints deploy help message', async t => { + const result = await now('help') + + t.is(result.code, 0) + const stdout = result.stdout.split('\n') + t.true(stdout.length > 1) + t.true(stdout[1].includes(deployHelpMessage)) +}) + +test('"now --help" prints deploy help message', async t => { + const result = await now('--help') + + t.is(result.code, 0) + const stdout = result.stdout.split('\n') + t.true(stdout.length > 1) + t.true(stdout[1].includes(deployHelpMessage)) +}) + +test('"now deploy --help" prints deploy help message', async t => { + const result = await now('deploy', '--help') + + t.is(result.code, 0) + const stdout = result.stdout.split('\n') + t.true(stdout.length > 1) + t.true(stdout[1].includes(deployHelpMessage)) +}) + +test('"now --help deploy" prints deploy help message', async t => { + const result = await now('--help', 'deploy') + + t.is(result.code, 0) + const stdout = result.stdout.split('\n') + t.true(stdout.length > 1) + t.true(stdout[1].includes(deployHelpMessage)) +}) + +test('"now help alias" prints alias help message', async t => { + const result = await now('help', 'alias') + + t.is(result.code, 0) + const stdout = result.stdout.split('\n') + t.true(stdout.length > 1) + t.true(stdout[1].includes(aliasHelpMessage)) +}) + +test('"now alias --help" is the same as "now --help alias"', async t => { + const [result1, result2] = await Promise.all([now('alias', '--help'), now('--help', 'alias')]) + + t.is(result1.code, 0) + t.is(result1.code, result2.code) + t.is(result1.stdout, result2.stdout) +}) + +/** + * Run the built now binary with given arguments + * + * @param {String} args string arguements + * @return {Promise} promise that resolves to an object {code, stdout} + */ +function now(...args) { + return new Promise((resolve, reject) => { + const command = path.resolve(__dirname, '../build/bin/now') + const now = spawn(command, args) + + let stdout = '' + now.stdout.on('data', data => { + stdout += data + }) + + now.on('error', err => { + reject(err) + }) + + now.on('close', code => { + resolve({ + code, + stdout + }) + }) + }) +} From 5e5545789fbfd2520fa682318d081f387f67fdda Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 26 Nov 2016 12:19:49 +0100 Subject: [PATCH 010/160] Handle potential error when converting res to JSON --- lib/github.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/github.js b/lib/github.js index f47d864..780c0a6 100644 --- a/lib/github.js +++ b/lib/github.js @@ -12,22 +12,23 @@ import {error} from './error' const exists = async repoPath => { const apiURL = `https://api.github.com/repos/${repoPath}` + let request + let response try { request = await fetch(apiURL) + response = await request.json() } catch (err) { error(`Not able to check if repo exists - ${err.message}`) return false } - const res = await request.json() - - if (!res.name) { + if (!response.name) { return false } - return res + return response } const downloadRepo = async repoPath => { From c92d4dfb37ba49791b17cd64645abec68d1b58f5 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 26 Nov 2016 12:28:32 +0100 Subject: [PATCH 011/160] Clean up tmp dir for repo in a better way --- bin/now-deploy.js | 9 +++++++-- lib/github.js | 5 ++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index feb4a57..86f3d3b 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -229,8 +229,12 @@ async function sync(token) { } if (repo) { + // Tell now which directory to deploy path = repo.path - gitHubRepo = true + + // Set global variable for deleting tmp dir later + // once the deployment has finished + gitHubRepo = repo } else if (isRepoPath(rawPath)) { stopDeployment(`This path neither exists, nor is there a repository named "${rawPath}" on GitHub`) } else { @@ -529,7 +533,8 @@ function printLogs(host) { } if (gitHubRepo) { - fs.removeSync(path) + // Delete temporary directory that contains repository + gitHubRepo.cleanup() if (debug) { console.log(`> [debug] Removed temporary repo directory`) diff --git a/lib/github.js b/lib/github.js index 780c0a6..c8db1fb 100644 --- a/lib/github.js +++ b/lib/github.js @@ -35,7 +35,10 @@ const downloadRepo = async repoPath => { const url = `https://api.github.com/repos/${repoPath}/tarball` const tmpDir = await tmp.dir({ - keep: true + // We'll remove it manually once deployment is done + keep: true, + // Recursively remove directory when calling respective method + unsafeCleanup: true }) await download(url, tmpDir.path, { From bb74c71896f20ab3d2cb0900a105a7d2b11d28f7 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 26 Nov 2016 12:38:17 +0100 Subject: [PATCH 012/160] Check if path is a repo path via regex --- lib/github.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/github.js b/lib/github.js index c8db1fb..3135db4 100644 --- a/lib/github.js +++ b/lib/github.js @@ -56,13 +56,7 @@ export const isRepoPath = path => { return false } - const slashCount = path.split('/').length - 1 - - if (!slashCount || slashCount > 1) { - return false - } - - return true + return /[^\s\\]\/[^\s\\]/g.test(path) } export const onGitHub = async (path, debug) => { From d51a6024c74ead46f093d7450dbe647c995fd529 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 26 Nov 2016 17:05:50 +0100 Subject: [PATCH 013/160] Swallow errors, just check if falsy --- bin/now-deploy.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 86f3d3b..86ca03b 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -222,7 +222,9 @@ async function sync(token) { } }, 500) - repo = await onGitHub(rawPath, debug) + try { + repo = await onGitHub(rawPath, debug) + } catch (err) {} clearInterval(dots) process.stdout.write('\n') From fd0e39da0ecb3598658aea27fdb09a295373b93d Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 26 Nov 2016 17:18:48 +0100 Subject: [PATCH 014/160] Only do one network roundtrip to GitHub --- lib/github.js | 57 ++++++++++----------------------------------------- 1 file changed, 11 insertions(+), 46 deletions(-) diff --git a/lib/github.js b/lib/github.js index 3135db4..7f97f69 100644 --- a/lib/github.js +++ b/lib/github.js @@ -3,34 +3,9 @@ import path from 'path' // Packages import fs from 'fs-promise' -import fetch from 'node-fetch' import download from 'download' import tmp from 'tmp-promise' -// Ours -import {error} from './error' - -const exists = async repoPath => { - const apiURL = `https://api.github.com/repos/${repoPath}` - - let request - let response - - try { - request = await fetch(apiURL) - response = await request.json() - } catch (err) { - error(`Not able to check if repo exists - ${err.message}`) - return false - } - - if (!response.name) { - return false - } - - return response -} - const downloadRepo = async repoPath => { const url = `https://api.github.com/repos/${repoPath}/tarball` @@ -41,9 +16,14 @@ const downloadRepo = async repoPath => { unsafeCleanup: true }) - await download(url, tmpDir.path, { - extract: true - }) + try { + await download(url, tmpDir.path, { + extract: true + }) + } catch (err) { + tmpDir.cleanup() + return false + } const tmpContents = await fs.readdir(tmpDir.path) tmpDir.path = path.join(tmpDir.path, tmpContents[0]) @@ -60,29 +40,14 @@ export const isRepoPath = path => { } export const onGitHub = async (path, debug) => { - let repo = await exists(path) + let tmpDir = false try { - repo = await exists(path) + tmpDir = await downloadRepo(path) } catch (err) { if (debug) { - console.log(`Repository "${path}" does not exist on GitHub`) + console.log(`Could not download "${path}" repo from GitHub`) } - - return false - } - - if (!repo) { - return false - } - - let tmpDir - - try { - tmpDir = await downloadRepo(path) - } catch (err) { - error(`Not able to download repo: ${err.stack}`) - process.exit(1) } return tmpDir From 3e7634159ed444f2813f926b785fff24f66dc948 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 26 Nov 2016 17:24:59 +0100 Subject: [PATCH 015/160] Only show message if GH search takes long --- bin/now-deploy.js | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 86ca03b..6c6cd65 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -209,25 +209,15 @@ async function sync(token) { let repo if (isRepoPath(rawPath)) { - process.stdout.write('> Didn\'t find directory. Searching on GitHub') - - let dotCount = 0 - - const dots = setInterval(() => { - dotCount++ - process.stdout.write('.') - - if (dotCount === 20) { - clearInterval(dots) - } + const searchMessage = setTimeout(() => { + console.log('> Didn\'t find directory. Searching on GitHub...') }, 500) try { repo = await onGitHub(rawPath, debug) } catch (err) {} - clearInterval(dots) - process.stdout.write('\n') + clearTimeout(searchMessage) } if (repo) { From 09670c986ec05ca54c4b14f212f0736367231846 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 26 Nov 2016 17:44:59 +0100 Subject: [PATCH 016/160] Support for git references --- lib/github.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/github.js b/lib/github.js index 7f97f69..a257a3c 100644 --- a/lib/github.js +++ b/lib/github.js @@ -7,7 +7,8 @@ import download from 'download' import tmp from 'tmp-promise' const downloadRepo = async repoPath => { - const url = `https://api.github.com/repos/${repoPath}/tarball` + const pathParts = gitPathParts(repoPath) + const url = `https://api.github.com/repos/${pathParts.main}/tarball/${pathParts.ref}` const tmpDir = await tmp.dir({ // We'll remove it manually once deployment is done @@ -31,6 +32,19 @@ const downloadRepo = async repoPath => { return tmpDir } +export const gitPathParts = main => { + let ref = '' + + if (main.split('/')[1].includes('#')) { + const parts = main.split('#') + + ref = parts[1] + main = parts[0] + } + + return {main, ref} +} + export const isRepoPath = path => { if (!path) { return false From 5d1cce8c1c070909d0ad30e3c08c4a4807f1a71a Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 26 Nov 2016 17:53:43 +0100 Subject: [PATCH 017/160] Respect git ref in error message --- bin/now-deploy.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 6c6cd65..169b11c 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -21,8 +21,8 @@ import Now from '../lib' import toHumanPath from '../lib/utils/to-human-path' import promptOptions from '../lib/utils/prompt-options' import {handleError, error} from '../lib/error' +import {onGitHub, isRepoPath, gitPathParts} from '../lib/github' import readMetaData from '../lib/read-metadata' -import {onGitHub, isRepoPath} from '../lib/github' const argv = minimist(process.argv.slice(2), { string: [ @@ -228,7 +228,10 @@ async function sync(token) { // once the deployment has finished gitHubRepo = repo } else if (isRepoPath(rawPath)) { - stopDeployment(`This path neither exists, nor is there a repository named "${rawPath}" on GitHub`) + const gitParts = gitPathParts(rawPath) + const gitRef = gitParts.ref ? `with the ref "${gitParts.ref}" ` : '' + + stopDeployment(`There's no repository named "${gitParts.main}" ${gitRef}on GitHub`) } else { stopDeployment(`Could not read directory ${chalk.bold(path)}`) } From 3e43225204f369ecd51ac5c825194fe5a5ed0efa Mon Sep 17 00:00:00 2001 From: Greenkeeper Date: Sun, 27 Nov 2016 09:36:02 +0100 Subject: [PATCH 018/160] chore(package): update socket.io-client to version 1.7.0 (#144) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a3bd910..0d04a88 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "progress": "1.1.8", "resumer": "0.0.0", "semver-compare": "1.0.0", - "socket.io-client": "1.6.0", + "socket.io-client": "1.7.0", "spdy": "3.4.4", "split-array": "1.0.1", "text-table": "0.2.0" From 9d7746f9ed51d5a1407c3fc133bd876553b1849d Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sun, 27 Nov 2016 22:14:56 +0100 Subject: [PATCH 019/160] Support for deploying GitHub URLs --- lib/github.js | 33 +++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 34 insertions(+) diff --git a/lib/github.js b/lib/github.js index a257a3c..8c3436d 100644 --- a/lib/github.js +++ b/lib/github.js @@ -1,13 +1,16 @@ // Native import path from 'path' +import url from 'url' // Packages import fs from 'fs-promise' import download from 'download' import tmp from 'tmp-promise' +import isURL from 'is-url' const downloadRepo = async repoPath => { const pathParts = gitPathParts(repoPath) + console.log(pathParts) const url = `https://api.github.com/repos/${pathParts.main}/tarball/${pathParts.ref}` const tmpDir = await tmp.dir({ @@ -32,9 +35,29 @@ const downloadRepo = async repoPath => { return tmpDir } +const splittedURL = fullURL => { + const pathParts = url.parse(fullURL).path.split('/') + pathParts.shift() + + // Set path to repo... + const main = pathParts[0] + '/' + pathParts[1] + + // ...and then remove it from the parts + pathParts.splice(0, 2) + + return { + main, + ref: pathParts.length >= 2 ? pathParts[1] : '' + } +} + export const gitPathParts = main => { let ref = '' + if (isURL(main)) { + return splittedURL(main) + } + if (main.split('/')[1].includes('#')) { const parts = main.split('#') @@ -50,6 +73,16 @@ export const isRepoPath = path => { return false } + if (isURL(path)) { + const urlParts = url.parse(path) + const slashCount = (urlParts.path.match(new RegExp('/', 'g')) || []).length + const notBare = slashCount >= 2 + + if (urlParts.host === 'github.com' && notBare) { + return true + } + } + return /[^\s\\]\/[^\s\\]/g.test(path) } diff --git a/package.json b/package.json index 3b6c4e8..fb74cd2 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,7 @@ "graceful-fs": "4.1.11", "ignore": "3.2.0", "ini": "1.3.4", + "is-url": "1.2.2", "minimist": "1.2.0", "ms": "0.7.2", "node-fetch": "1.6.3", From be9e61dfebede015b50d5652b2fabdb3dfec47a5 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sun, 27 Nov 2016 22:17:22 +0100 Subject: [PATCH 020/160] Support GitLab as well --- lib/github.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/github.js b/lib/github.js index 8c3436d..fadc3af 100644 --- a/lib/github.js +++ b/lib/github.js @@ -10,7 +10,6 @@ import isURL from 'is-url' const downloadRepo = async repoPath => { const pathParts = gitPathParts(repoPath) - console.log(pathParts) const url = `https://api.github.com/repos/${pathParts.main}/tarball/${pathParts.ref}` const tmpDir = await tmp.dir({ @@ -73,12 +72,17 @@ export const isRepoPath = path => { return false } + const allowedHosts = [ + 'github.com', + 'gitlab.com' + ] + if (isURL(path)) { const urlParts = url.parse(path) const slashCount = (urlParts.path.match(new RegExp('/', 'g')) || []).length const notBare = slashCount >= 2 - if (urlParts.host === 'github.com' && notBare) { + if (allowedHosts.includes(urlParts.host) && notBare) { return true } } From 8075ffae4e2cc40a584ec8afe7dcc113f4188160 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sun, 27 Nov 2016 22:26:26 +0100 Subject: [PATCH 021/160] Show good looking messages when deploying Git URL --- bin/now-deploy.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 169b11c..a19d1de 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -135,7 +135,7 @@ if (path) { } // If the current deployment is a repo -let gitHubRepo +const gitHubRepo = {} const exit = code => { // we give stdout some time to flush out @@ -218,6 +218,9 @@ async function sync(token) { } catch (err) {} clearTimeout(searchMessage) + + const gitParts = gitPathParts(rawPath) + Object.assign(gitHubRepo, gitParts) } if (repo) { @@ -226,12 +229,10 @@ async function sync(token) { // Set global variable for deleting tmp dir later // once the deployment has finished - gitHubRepo = repo + Object.assign(gitHubRepo, repo) } else if (isRepoPath(rawPath)) { - const gitParts = gitPathParts(rawPath) - const gitRef = gitParts.ref ? `with the ref "${gitParts.ref}" ` : '' - - stopDeployment(`There's no repository named "${gitParts.main}" ${gitRef}on GitHub`) + const gitRef = gitHubRepo.ref ? `with the ref "${gitHubRepo.ref}" ` : '' + stopDeployment(`There's no repository named "${gitHubRepo.main}" ${gitRef}on GitHub`) } else { stopDeployment(`Could not read directory ${chalk.bold(path)}`) } @@ -239,7 +240,7 @@ async function sync(token) { if (!quiet) { if (gitHubRepo) { - console.log(`> Deploying GitHub repository "${chalk.bold(toHumanPath(rawPath))}"`) + console.log(`> Deploying GitHub repository "${chalk.bold(gitHubRepo.main)}"`) } else { console.log(`> Deploying ${chalk.bold(toHumanPath(path))}`) } @@ -527,7 +528,7 @@ function printLogs(host) { console.log(`${chalk.cyan('> Deployment complete!')}`) } - if (gitHubRepo) { + if (gitHubRepo && gitHubRepo.cleanup) { // Delete temporary directory that contains repository gitHubRepo.cleanup() From 04d58f25587e074cd9e3a148902edd459d9e2d71 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 28 Nov 2016 10:43:54 +0100 Subject: [PATCH 022/160] Throw error if URL is not valid --- bin/now-deploy.js | 8 ++++++-- lib/github.js | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index a19d1de..c9c6d41 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -203,12 +203,14 @@ async function sync(token) { process.exit(1) } + const isValidRepo = isRepoPath(rawPath) + try { await fs.stat(path) } catch (err) { let repo - if (isRepoPath(rawPath)) { + if (isValidRepo && isValidRepo !== 'no-valid-url') { const searchMessage = setTimeout(() => { console.log('> Didn\'t find directory. Searching on GitHub...') }, 500) @@ -230,7 +232,9 @@ async function sync(token) { // Set global variable for deleting tmp dir later // once the deployment has finished Object.assign(gitHubRepo, repo) - } else if (isRepoPath(rawPath)) { + } else if (isValidRepo === 'no-valid-url') { + stopDeployment(`URL is no valid repository from GitHub or GitLab.`) + } else if (isValidRepo) { const gitRef = gitHubRepo.ref ? `with the ref "${gitHubRepo.ref}" ` : '' stopDeployment(`There's no repository named "${gitHubRepo.main}" ${gitRef}on GitHub`) } else { diff --git a/lib/github.js b/lib/github.js index fadc3af..9fcfacb 100644 --- a/lib/github.js +++ b/lib/github.js @@ -85,6 +85,8 @@ export const isRepoPath = path => { if (allowedHosts.includes(urlParts.host) && notBare) { return true } + + return 'no-valid-url' } return /[^\s\\]\/[^\s\\]/g.test(path) From 5fb53762eb15b3936467b12055efb70ead606bdc Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 28 Nov 2016 10:52:31 +0100 Subject: [PATCH 023/160] Show the git reference when deploying --- bin/now-deploy.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index c9c6d41..7c49a7b 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -244,7 +244,8 @@ async function sync(token) { if (!quiet) { if (gitHubRepo) { - console.log(`> Deploying GitHub repository "${chalk.bold(gitHubRepo.main)}"`) + const gitRef = gitHubRepo.ref ? ` at "${chalk.bold(gitHubRepo.ref)}" ` : '' + console.log(`> Deploying GitHub repository "${chalk.bold(gitHubRepo.main)}"` + gitRef) } else { console.log(`> Deploying ${chalk.bold(toHumanPath(path))}`) } From 0ea689c27aecf322664e0a0a852c382c64b3bd8d Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 28 Nov 2016 10:56:54 +0100 Subject: [PATCH 024/160] Shorten git reference if commit --- lib/github.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/github.js b/lib/github.js index 9fcfacb..3492a56 100644 --- a/lib/github.js +++ b/lib/github.js @@ -44,10 +44,15 @@ const splittedURL = fullURL => { // ...and then remove it from the parts pathParts.splice(0, 2) - return { - main, - ref: pathParts.length >= 2 ? pathParts[1] : '' + // Assign Git reference + let ref = pathParts.length >= 2 ? pathParts[1] : '' + + // Shorten SHA for commits + if (pathParts[0] && pathParts[0] === 'commit') { + ref = ref.substring(0, 7) } + + return {main, ref} } export const gitPathParts = main => { From c9c32664bb8fc351ca637c23b47694f367829f84 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 28 Nov 2016 10:59:30 +0100 Subject: [PATCH 025/160] Don't indicate git ref if master branch --- lib/github.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/github.js b/lib/github.js index 3492a56..234bcf6 100644 --- a/lib/github.js +++ b/lib/github.js @@ -52,6 +52,12 @@ const splittedURL = fullURL => { ref = ref.substring(0, 7) } + // We're deploying master by default, + // so there's no need to indicate it explicitly + if (ref === 'master') { + ref = '' + } + return {main, ref} } From 5d5a59d1b1700a7b736fa6527a7ba2d60055ff9f Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 28 Nov 2016 11:04:41 +0100 Subject: [PATCH 026/160] Make important info bold when error occurs --- bin/now-deploy.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 7c49a7b..1752b59 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -235,8 +235,8 @@ async function sync(token) { } else if (isValidRepo === 'no-valid-url') { stopDeployment(`URL is no valid repository from GitHub or GitLab.`) } else if (isValidRepo) { - const gitRef = gitHubRepo.ref ? `with the ref "${gitHubRepo.ref}" ` : '' - stopDeployment(`There's no repository named "${gitHubRepo.main}" ${gitRef}on GitHub`) + const gitRef = gitHubRepo.ref ? `with "${chalk.bold(gitHubRepo.ref)}" ` : '' + stopDeployment(`There's no repository named "${chalk.bold(gitHubRepo.main)}" ${gitRef}on GitHub or GitLab`) } else { stopDeployment(`Could not read directory ${chalk.bold(path)}`) } From 27b860d6fe729aa1eae3a2e61c0fb488a6bbd4c9 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 28 Nov 2016 11:12:25 +0100 Subject: [PATCH 027/160] Only show examples related to `now deploy` --- bin/now-deploy.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 1752b59..73db937 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -102,19 +102,15 @@ const help = () => { ${chalk.cyan('$ now /usr/src/project')} - ${chalk.gray('–')} Lists all deployments with their IDs + ${chalk.gray('–')} Deploys a GitHub repository - ${chalk.cyan('$ now ls')} + ${chalk.cyan('$ now user/repo#ref')} - ${chalk.gray('–')} Associates deployment ${chalk.dim('`deploymentId`')} with ${chalk.dim('`custom-domain.com`')} + ${chalk.gray('–')} Deploys a GitHub or GitLab repo using its URL - ${chalk.cyan('$ now alias deploymentId custom-domain.com')} + ${chalk.cyan('$ now https://gitlab.com/user/repo')} - ${chalk.gray('–')} Stores a secret - - ${chalk.cyan('$ now secret add mysql-password 123456')} - - ${chalk.gray('–')} Deploys with ENV vars (using the ${chalk.dim('`mysql-password`')} secret stored above) + ${chalk.gray('–')} Deploys with ENV vars ${chalk.cyan('$ now -e NODE_ENV=production -e MYSQL_PASSWORD=@mysql-password')} From 4a5de7321a04902b39de443faefcbf6295c492c4 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 28 Nov 2016 11:36:03 +0100 Subject: [PATCH 028/160] Much stricter repo URL checking --- bin/now-deploy.js | 2 +- lib/github.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 73db937..0df1a5f 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -229,7 +229,7 @@ async function sync(token) { // once the deployment has finished Object.assign(gitHubRepo, repo) } else if (isValidRepo === 'no-valid-url') { - stopDeployment(`URL is no valid repository from GitHub or GitLab.`) + stopDeployment(`This URL is not a valid repository from GitHub or GitLab.`) } else if (isValidRepo) { const gitRef = gitHubRepo.ref ? `with "${chalk.bold(gitHubRepo.ref)}" ` : '' stopDeployment(`There's no repository named "${chalk.bold(gitHubRepo.main)}" ${gitRef}on GitHub or GitLab`) diff --git a/lib/github.js b/lib/github.js index 234bcf6..3df8000 100644 --- a/lib/github.js +++ b/lib/github.js @@ -90,8 +90,8 @@ export const isRepoPath = path => { if (isURL(path)) { const urlParts = url.parse(path) - const slashCount = (urlParts.path.match(new RegExp('/', 'g')) || []).length - const notBare = slashCount >= 2 + const slashSplitted = urlParts.path.split('/').filter(n => n) + const notBare = slashSplitted.length >= 2 if (allowedHosts.includes(urlParts.host) && notBare) { return true From b73ff097030e6c7b66b599e50c3a8c287a1bc20d Mon Sep 17 00:00:00 2001 From: Greenkeeper Date: Mon, 28 Nov 2016 11:44:48 +0100 Subject: [PATCH 029/160] chore(package): update socket.io-client to version 1.7.1 (#145) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0d04a88..3590acb 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "progress": "1.1.8", "resumer": "0.0.0", "semver-compare": "1.0.0", - "socket.io-client": "1.7.0", + "socket.io-client": "1.7.1", "spdy": "3.4.4", "split-array": "1.0.1", "text-table": "0.2.0" From a63924ff850ca18b2e58a333ae2d2892e8b62379 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 28 Nov 2016 17:27:07 +0100 Subject: [PATCH 030/160] 0.31.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 498b088..be0cf8e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "0.30.0", + "version": "0.31.0", "description": "Realtime global deployments", "repository": "zeit/now", "main": "./build/lib/index", From 77412000ca6c5ab8ef69a72b065f5278a254150e Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 28 Nov 2016 22:39:27 +0100 Subject: [PATCH 031/160] Accept GitLab URLs --- lib/github.js | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/github.js b/lib/github.js index 3df8000..aed7bdc 100644 --- a/lib/github.js +++ b/lib/github.js @@ -10,7 +10,16 @@ import isURL from 'is-url' const downloadRepo = async repoPath => { const pathParts = gitPathParts(repoPath) - const url = `https://api.github.com/repos/${pathParts.main}/tarball/${pathParts.ref}` + let url + + switch (pathParts.type) { + case 'gitlab': + const ref = pathParts.ref ? `?ref=${pathParts.ref}` : '' + url = `https://gitlab.com/${pathParts.main}/repository/archive.tar` + ref + break + default: + url = `https://api.github.com/repos/${pathParts.main}/tarball/${pathParts.ref}` + } const tmpDir = await tmp.dir({ // We'll remove it manually once deployment is done @@ -35,7 +44,9 @@ const downloadRepo = async repoPath => { } const splittedURL = fullURL => { - const pathParts = url.parse(fullURL).path.split('/') + const parsedURL = url.parse(fullURL) + const pathParts = parsedURL.path.split('/') + pathParts.shift() // Set path to repo... @@ -58,7 +69,11 @@ const splittedURL = fullURL => { ref = '' } - return {main, ref} + return { + main, + ref, + type: parsedURL.host.split('.')[0] + } } export const gitPathParts = main => { @@ -75,7 +90,11 @@ export const gitPathParts = main => { main = parts[0] } - return {main, ref} + return { + main, + ref, + type: 'github' + } } export const isRepoPath = path => { From b04ab0470b9ac4b21cb6e9fbbdef58c5652d6d1a Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 28 Nov 2016 22:47:08 +0100 Subject: [PATCH 032/160] Show cooler messages when deploying from other platforms --- bin/now-deploy.js | 14 +++++++------- lib/github.js | 10 +++++++--- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 0df1a5f..29fc7bb 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -207,8 +207,11 @@ async function sync(token) { let repo if (isValidRepo && isValidRepo !== 'no-valid-url') { + const gitParts = gitPathParts(rawPath) + Object.assign(gitHubRepo, gitParts) + const searchMessage = setTimeout(() => { - console.log('> Didn\'t find directory. Searching on GitHub...') + console.log(`> Didn\'t find directory. Searching on ${gitHubRepo.type}...`) }, 500) try { @@ -216,9 +219,6 @@ async function sync(token) { } catch (err) {} clearTimeout(searchMessage) - - const gitParts = gitPathParts(rawPath) - Object.assign(gitHubRepo, gitParts) } if (repo) { @@ -229,10 +229,10 @@ async function sync(token) { // once the deployment has finished Object.assign(gitHubRepo, repo) } else if (isValidRepo === 'no-valid-url') { - stopDeployment(`This URL is not a valid repository from GitHub or GitLab.`) + stopDeployment(`This URL is neither a valid repository from GitHub, nor from GitLab.`) } else if (isValidRepo) { const gitRef = gitHubRepo.ref ? `with "${chalk.bold(gitHubRepo.ref)}" ` : '' - stopDeployment(`There's no repository named "${chalk.bold(gitHubRepo.main)}" ${gitRef}on GitHub or GitLab`) + stopDeployment(`There's no repository named "${chalk.bold(gitHubRepo.main)}" ${gitRef}on ${gitHubRepo.type}`) } else { stopDeployment(`Could not read directory ${chalk.bold(path)}`) } @@ -241,7 +241,7 @@ async function sync(token) { if (!quiet) { if (gitHubRepo) { const gitRef = gitHubRepo.ref ? ` at "${chalk.bold(gitHubRepo.ref)}" ` : '' - console.log(`> Deploying GitHub repository "${chalk.bold(gitHubRepo.main)}"` + gitRef) + console.log(`> Deploying ${gitHubRepo.type} repository "${chalk.bold(gitHubRepo.main)}"` + gitRef) } else { console.log(`> Deploying ${chalk.bold(toHumanPath(path))}`) } diff --git a/lib/github.js b/lib/github.js index aed7bdc..cbe5810 100644 --- a/lib/github.js +++ b/lib/github.js @@ -13,7 +13,7 @@ const downloadRepo = async repoPath => { let url switch (pathParts.type) { - case 'gitlab': + case 'GitLab': const ref = pathParts.ref ? `?ref=${pathParts.ref}` : '' url = `https://gitlab.com/${pathParts.main}/repository/archive.tar` + ref break @@ -43,6 +43,10 @@ const downloadRepo = async repoPath => { return tmpDir } +const capitalizePlatform = name => { + return name.replace('github', 'GitHub').replace('gitlab', 'GitLab') +} + const splittedURL = fullURL => { const parsedURL = url.parse(fullURL) const pathParts = parsedURL.path.split('/') @@ -72,7 +76,7 @@ const splittedURL = fullURL => { return { main, ref, - type: parsedURL.host.split('.')[0] + type: capitalizePlatform(parsedURL.host.split('.')[0]) } } @@ -93,7 +97,7 @@ export const gitPathParts = main => { return { main, ref, - type: 'github' + type: capitalizePlatform('github') } } From fd0ff2fbf65a29d9198c32c38e9b0edc625f5518 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 28 Nov 2016 22:51:22 +0100 Subject: [PATCH 033/160] Make code naming for multiple platforms --- bin/now-deploy.js | 26 +++++++++++++------------- lib/{github.js => git.js} | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) rename lib/{github.js => git.js} (98%) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 29fc7bb..ce7e1fc 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -21,7 +21,7 @@ import Now from '../lib' import toHumanPath from '../lib/utils/to-human-path' import promptOptions from '../lib/utils/prompt-options' import {handleError, error} from '../lib/error' -import {onGitHub, isRepoPath, gitPathParts} from '../lib/github' +import {fromGit, isRepoPath, gitPathParts} from '../lib/git' import readMetaData from '../lib/read-metadata' const argv = minimist(process.argv.slice(2), { @@ -131,7 +131,7 @@ if (path) { } // If the current deployment is a repo -const gitHubRepo = {} +const gitRepo = {} const exit = code => { // we give stdout some time to flush out @@ -208,14 +208,14 @@ async function sync(token) { if (isValidRepo && isValidRepo !== 'no-valid-url') { const gitParts = gitPathParts(rawPath) - Object.assign(gitHubRepo, gitParts) + Object.assign(gitRepo, gitParts) const searchMessage = setTimeout(() => { - console.log(`> Didn\'t find directory. Searching on ${gitHubRepo.type}...`) + console.log(`> Didn\'t find directory. Searching on ${gitRepo.type}...`) }, 500) try { - repo = await onGitHub(rawPath, debug) + repo = await fromGit(rawPath, debug) } catch (err) {} clearTimeout(searchMessage) @@ -227,21 +227,21 @@ async function sync(token) { // Set global variable for deleting tmp dir later // once the deployment has finished - Object.assign(gitHubRepo, repo) + Object.assign(gitRepo, repo) } else if (isValidRepo === 'no-valid-url') { stopDeployment(`This URL is neither a valid repository from GitHub, nor from GitLab.`) } else if (isValidRepo) { - const gitRef = gitHubRepo.ref ? `with "${chalk.bold(gitHubRepo.ref)}" ` : '' - stopDeployment(`There's no repository named "${chalk.bold(gitHubRepo.main)}" ${gitRef}on ${gitHubRepo.type}`) + const gitRef = gitRepo.ref ? `with "${chalk.bold(gitRepo.ref)}" ` : '' + stopDeployment(`There's no repository named "${chalk.bold(gitRepo.main)}" ${gitRef}on ${gitRepo.type}`) } else { stopDeployment(`Could not read directory ${chalk.bold(path)}`) } } if (!quiet) { - if (gitHubRepo) { - const gitRef = gitHubRepo.ref ? ` at "${chalk.bold(gitHubRepo.ref)}" ` : '' - console.log(`> Deploying ${gitHubRepo.type} repository "${chalk.bold(gitHubRepo.main)}"` + gitRef) + if (gitRepo) { + const gitRef = gitRepo.ref ? ` at "${chalk.bold(gitRepo.ref)}" ` : '' + console.log(`> Deploying ${gitRepo.type} repository "${chalk.bold(gitRepo.main)}"` + gitRef) } else { console.log(`> Deploying ${chalk.bold(toHumanPath(path))}`) } @@ -529,9 +529,9 @@ function printLogs(host) { console.log(`${chalk.cyan('> Deployment complete!')}`) } - if (gitHubRepo && gitHubRepo.cleanup) { + if (gitRepo && gitRepo.cleanup) { // Delete temporary directory that contains repository - gitHubRepo.cleanup() + gitRepo.cleanup() if (debug) { console.log(`> [debug] Removed temporary repo directory`) diff --git a/lib/github.js b/lib/git.js similarity index 98% rename from lib/github.js rename to lib/git.js index cbe5810..ade629a 100644 --- a/lib/github.js +++ b/lib/git.js @@ -126,7 +126,7 @@ export const isRepoPath = path => { return /[^\s\\]\/[^\s\\]/g.test(path) } -export const onGitHub = async (path, debug) => { +export const fromGit = async (path, debug) => { let tmpDir = false try { From 9bfa06f1632f02cdbbb675cb0eb1b53a9ea82947 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 28 Nov 2016 23:01:04 +0100 Subject: [PATCH 034/160] Support for Bitbucket --- lib/git.js | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/lib/git.js b/lib/git.js index ade629a..8123514 100644 --- a/lib/git.js +++ b/lib/git.js @@ -17,6 +17,9 @@ const downloadRepo = async repoPath => { const ref = pathParts.ref ? `?ref=${pathParts.ref}` : '' url = `https://gitlab.com/${pathParts.main}/repository/archive.tar` + ref break + case 'Bitbucket': + url = `https://bitbucket.org/${pathParts.main}/get/${pathParts.ref || 'master'}.zip` + break default: url = `https://api.github.com/repos/${pathParts.main}/tarball/${pathParts.ref}` } @@ -44,7 +47,13 @@ const downloadRepo = async repoPath => { } const capitalizePlatform = name => { - return name.replace('github', 'GitHub').replace('gitlab', 'GitLab') + const names = { + github: 'GitHub', + gitlab: 'GitLab', + bitbucket: 'Bitbucket' + } + + return names[name] } const splittedURL = fullURL => { @@ -62,9 +71,12 @@ const splittedURL = fullURL => { // Assign Git reference let ref = pathParts.length >= 2 ? pathParts[1] : '' - // Shorten SHA for commits - if (pathParts[0] && pathParts[0] === 'commit') { - ref = ref.substring(0, 7) + // Firstly be sure that we haven know the ref type + if (pathParts[0]) { + // Then shorten the SHA of the commit + if (pathParts[0] === 'commit' || pathParts[0] === 'commits') { + ref = ref.substring(0, 7) + } } // We're deploying master by default, @@ -108,7 +120,8 @@ export const isRepoPath = path => { const allowedHosts = [ 'github.com', - 'gitlab.com' + 'gitlab.com', + 'bitbucket.org' ] if (isURL(path)) { From de0635e8b1eb4619461c1db478b64d51cb0e1844 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 28 Nov 2016 23:09:56 +0100 Subject: [PATCH 035/160] Use a clean prefix when deploying --- lib/git.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/git.js b/lib/git.js index 8123514..0b1e91e 100644 --- a/lib/git.js +++ b/lib/git.js @@ -41,7 +41,12 @@ const downloadRepo = async repoPath => { } const tmpContents = await fs.readdir(tmpDir.path) - tmpDir.path = path.join(tmpDir.path, tmpContents[0]) + + const oldTemp = path.join(tmpDir.path, tmpContents[0]) + const newTemp = path.join(tmpDir.path, pathParts.main.replace('/', '-')) + + await fs.rename(oldTemp, newTemp) + tmpDir.path = newTemp return tmpDir } From 7ae4532ea7561eda48d7534ae473f23a8ad8bf46 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 28 Nov 2016 23:11:31 +0100 Subject: [PATCH 036/160] Bitbucket's master branches are default --- lib/git.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/git.js b/lib/git.js index 0b1e91e..0cda2c9 100644 --- a/lib/git.js +++ b/lib/git.js @@ -18,7 +18,7 @@ const downloadRepo = async repoPath => { url = `https://gitlab.com/${pathParts.main}/repository/archive.tar` + ref break case 'Bitbucket': - url = `https://bitbucket.org/${pathParts.main}/get/${pathParts.ref || 'master'}.zip` + url = `https://bitbucket.org/${pathParts.main}/get/${pathParts.ref || 'default'}.zip` break default: url = `https://api.github.com/repos/${pathParts.main}/tarball/${pathParts.ref}` From 8028b87531cdbef85dc588cf32ea90adc5e907b5 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 28 Nov 2016 23:13:11 +0100 Subject: [PATCH 037/160] Tell users that Bitbucket is available --- bin/now-deploy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index ce7e1fc..111f8e7 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -106,7 +106,7 @@ const help = () => { ${chalk.cyan('$ now user/repo#ref')} - ${chalk.gray('–')} Deploys a GitHub or GitLab repo using its URL + ${chalk.gray('–')} Deploys a GitHub, GitLab or Bitbucket repo using its URL ${chalk.cyan('$ now https://gitlab.com/user/repo')} From 2b8fafa66f1bdb43c32d3e1fc49db213cef08225 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 28 Nov 2016 23:13:15 +0100 Subject: [PATCH 038/160] 0.32.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index be0cf8e..cdb1ab9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "0.31.0", + "version": "0.32.0", "description": "Realtime global deployments", "repository": "zeit/now", "main": "./build/lib/index", From 6e943590523eb36f090c7c90f89ceb8c616a7ccd Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 29 Nov 2016 19:03:51 +0100 Subject: [PATCH 039/160] Support for private Git repos --- lib/git.js | 77 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/lib/git.js b/lib/git.js index 0cda2c9..c80306e 100644 --- a/lib/git.js +++ b/lib/git.js @@ -1,6 +1,7 @@ // Native import path from 'path' import url from 'url' +import childProcess from 'child_process' // Packages import fs from 'fs-promise' @@ -8,8 +9,67 @@ import download from 'download' import tmp from 'tmp-promise' import isURL from 'is-url' +const cloneRepo = (parts, tmpDir) => new Promise((resolve, reject) => { + let host + + switch (parts.type) { + case 'GitLab': + host = `gitlab.com` + break + case 'Bitbucket': + host = `bitbucket.org` + break + default: + host = `github.com` + } + + const url = `https://${host}/${parts.main}` + const ref = parts.ref || (parts.type === 'Bitbucket' ? 'default' : 'master') + const cmd = `git clone ${url} --single-branch ${ref}` + + childProcess.exec(cmd, {cwd: tmpDir.path}, (err, stdout) => { + if (err) { + reject(err) + } + + resolve(stdout) + }) +}) + +const renameRepoDir = async (pathParts, tmpDir) => { + const tmpContents = await fs.readdir(tmpDir.path) + + const oldTemp = path.join(tmpDir.path, tmpContents[0]) + const newTemp = path.join(tmpDir.path, pathParts.main.replace('/', '-')) + + await fs.rename(oldTemp, newTemp) + tmpDir.path = newTemp + + return tmpDir +} + const downloadRepo = async repoPath => { const pathParts = gitPathParts(repoPath) + + const tmpDir = await tmp.dir({ + // We'll remove it manually once deployment is done + keep: true, + // Recursively remove directory when calling respective method + unsafeCleanup: true + }) + + let gitInstalled = true + + try { + await cloneRepo(pathParts, tmpDir) + } catch (err) { + gitInstalled = false + } + + if (gitInstalled) { + return await renameRepoDir(pathParts, tmpDir) + } + let url switch (pathParts.type) { @@ -24,13 +84,6 @@ const downloadRepo = async repoPath => { url = `https://api.github.com/repos/${pathParts.main}/tarball/${pathParts.ref}` } - const tmpDir = await tmp.dir({ - // We'll remove it manually once deployment is done - keep: true, - // Recursively remove directory when calling respective method - unsafeCleanup: true - }) - try { await download(url, tmpDir.path, { extract: true @@ -40,15 +93,7 @@ const downloadRepo = async repoPath => { return false } - const tmpContents = await fs.readdir(tmpDir.path) - - const oldTemp = path.join(tmpDir.path, tmpContents[0]) - const newTemp = path.join(tmpDir.path, pathParts.main.replace('/', '-')) - - await fs.rename(oldTemp, newTemp) - tmpDir.path = newTemp - - return tmpDir + return await renameRepoDir(pathParts, tmpDir) } const capitalizePlatform = name => { From ccefece100204998ac3c3b806396d72fdb654f11 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 29 Nov 2016 19:09:27 +0100 Subject: [PATCH 040/160] Removed duplicated fixture --- test/_fixtures/hashes/duplicate/dei.png | Bin 170690 -> 0 bytes test/index.js | 1 - 2 files changed, 1 deletion(-) delete mode 100644 test/_fixtures/hashes/duplicate/dei.png diff --git a/test/_fixtures/hashes/duplicate/dei.png b/test/_fixtures/hashes/duplicate/dei.png deleted file mode 100644 index 54279df190715e0b83ab6d5004fb9d4ecea57e13..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 170690 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
p1QCn{xu zCI(n%2xGUHWki8jQwUy~Z-CxvO1Hi9SGePM5IFOv0R&iw$lPny~B8IHZou45CEC% z9n;_hh{bL2%q!8bs-zS#$cDhp6*^O9uQitP7!rvGUqiJKoB`2T1+dI3_F#rQ^AP3x zA>XAog!(*(7QoAcTH4TZ-q81+0bJUKmW%9nd=iDuw{EgMq(&Z&G&ryrF_ZjjWC>Tp z?Ec8mD<4{Ro^Xu)e3yqD!H{S1Z@#5Z9zmWlh#CGJMhbn>Ka1hDwZ+uH&zY};AFs=c z@>Qk|;YS9ItGp>g42TBG%}RKkp&+_+0&ocX4EJ_wco`X`{zD(*zf%ZsZ&^dq`#RKw zT?hnE^YZVv3}{$dI!q?(c)nKa@qCq$(W}Vpt8f31BjVbLCf_w~^mB z>1gigU^92=%bh!vG}L!*OIo+M<(cR1^;Fx?9D%1{s;_tNG6Klxgg*WG-~WG3&NGdf$tME2+6Ib`;C<&}I5N8P!voCAy8KOP{uPE%CgtwUu7+}7C` z4rSzNeNLf1+s?)cjSU=wbDq~&WzE|;J=YXKI4M!(h8ejY4-<9zyKG%kHQE)z3dep} z9;Z+aLhHvMEssWG@ToI&kB1GGI8X){ECrl4)DyK9-+CVvcnksCNKiFah&YUc^ljw8 z3L1YKZ_;eu-t-DNap1_qs7iAW-x@CY#A%=!<{D;=Q~0n_XFly|-ilBjywaF^#%;?M zPJ{@yIKT2OEWbRwFJdeS+9q})Vu*g~#^qbxn+HBv-E8dL@uc$}1t-aXiFY{UbGQfC z;&cSk@gWW@bXcUhACJSvbOxUX>jZCaN09?Ql$TfIeDvh;#e=|*Mh$pR0(^pL6KPEk z9qLGcuaO9ii}wO??GeWtW>}F}GuSI!}8Ry&1^4`({O)3n!0g z71o%zuU-WYx?K?7obIA$Qkoi_ujhrl#z+{$GM-z^SgN3KlRg@lJhH(NXQ%kb5+$8Y z7@8ve=Ii+pf$8~Fy$9dRTMscQJIND1hmUJR2~f+1n9=Qnhw^wz3ueqVmyP&C?ZD-np|M^-QhrlL)^-NVKtqg(eXx= zw?L#ky6_$(Cr=d~`TAY&OcQi|_v zqvZEn26T_^!5jTxdJ}gd{s!`crBmz}(3Fi1F!{dY#i3Ha3}|&OF!K$b!y1!Lt}0;^ z!W<^$6Gss=P?sL7n?r-jGomP8jR~R;cKlb!AWH;;LAY57_s!nyg`~8})B{OpT&C2|ZTF@opl) z{>wHW4L;8{3F{QVzp0Qz$p7ar2x`BOtA`=CvIGUqhG7wAOEUM^u1^o7a9Ldqs`dzHvkx$)The(bLl1?TOQ+`81 zc#_LZd}5fN78xF={0U0%9+X^zEs)KTUm5a4{9$7r@)s}kz;BW7eT&E#`dV%Ot#p^?tTGBStj!q>kplU7f3|aKEsS}?j(Hu=;kpc&pixyh0#?KI_Jh^r zmnm-uvfGLnBf(sf$#evP2f6t-hf$bYnnpdtSov!#vJ%U1G%VwJFkgv5UenvGViL^5 z44=S&fSXQe<1k~;^gzygjAvz`hZhDv9vH=)w-dKpZC+-NT^>`}gg*;6R?1Fq5(Q>^ znea!kb|DN5|7N%{G?EW~))140sfeB9#b5U&GB&vwsmnCfH!)2A_NRZnc=q)BdU)dr z>!iFH;vCM`C(pG8E^x@#Vwj`EuCDTpo!oyO51*GWs6UHP?SR5RgYQ&zT2${eaROXb zqR>JI1Va+#%+>m}+1mjijLN-S=q>>vA|eaOJSSq*u($d1YXi>CgN6ae)U{vrQ`CU#_jX`Ch06pe#A{^@dH<50&3b{N>5^;W5{#QG)P8C?m1K*=HCJI0Ms~X i@}~US8^%){JpTjTCxi~oB?2J;0000 { const hashes = await hash(files) t.is(hashes.size, 3) t.is(hashes.get('277c55a2042910b9fe706ad00859e008c1b7d172').names[0], prefix + 'hashes/dei.png') - t.is(hashes.get('277c55a2042910b9fe706ad00859e008c1b7d172').names[1], prefix + 'hashes/duplicate/dei.png') t.is(hashes.get('56c00d0466fc6bdd41b13dac5fc920cc30a63b45').names[0], prefix + 'hashes/index.js') t.is(hashes.get('706214f42ae940a01d2aa60c5e32408f4d2127dd').names[0], prefix + 'hashes/package.json') }) From cf414438b0c2a0c1a29b320ce7800158ef5f5186 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 29 Nov 2016 19:10:39 +0100 Subject: [PATCH 041/160] Better title for contribution section --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 99d18ef..31efc7f 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ For more examples, usage instructions and other commands run: $ now help ``` -## Contribute +## Caught a Bug? 1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device 2. Link the package to the global module directory: `npm link` From 578a02d9ad22c66729da7d16ac25ff16f4a763c6 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 29 Nov 2016 19:11:57 +0100 Subject: [PATCH 042/160] 0.33.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cdb1ab9..b51a402 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "0.32.0", + "version": "0.33.0", "description": "Realtime global deployments", "repository": "zeit/now", "main": "./build/lib/index", From 115487382278a487907427fadeef5b474d248781 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Thu, 1 Dec 2016 01:21:57 +0100 Subject: [PATCH 043/160] Show proper deploying message --- bin/now-deploy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 111f8e7..896c10e 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -239,7 +239,7 @@ async function sync(token) { } if (!quiet) { - if (gitRepo) { + if (gitRepo.main) { const gitRef = gitRepo.ref ? ` at "${chalk.bold(gitRepo.ref)}" ` : '' console.log(`> Deploying ${gitRepo.type} repository "${chalk.bold(gitRepo.main)}"` + gitRef) } else { From 6b35479a2431dbcf9699e819e4f24885e907462c Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Thu, 1 Dec 2016 01:22:01 +0100 Subject: [PATCH 044/160] 0.33.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b51a402..2b59f21 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "0.33.0", + "version": "0.33.1", "description": "Realtime global deployments", "repository": "zeit/now", "main": "./build/lib/index", From 4de1c69b6a8e428b493306f129b4c9d1d5e9550b Mon Sep 17 00:00:00 2001 From: Jarmo Isotalo Date: Fri, 2 Dec 2016 15:27:13 +0200 Subject: [PATCH 045/160] Improve error handling when issuing cert fails (#154) Fix `now certs ls` error when showing expiration date Improve logging for when alias creation fails --- bin/now-certs.js | 6 +++++- lib/alias.js | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/bin/now-certs.js b/bin/now-certs.js index 4a7e69c..8571ab7 100755 --- a/bin/now-certs.js +++ b/bin/now-certs.js @@ -108,7 +108,7 @@ if (argv.help || !subcommand) { function formatExpirationDate(date) { const diff = date - Date.now() - return diff < 0 ? chalk.gray(ms(new Date(-diff)) + ' ago') : chalk.gray('in ' + ms(new Date(diff))) + return diff < 0 ? chalk.gray(ms(-diff) + ' ago') : chalk.gray('in ' + ms(diff)) } async function run(token) { @@ -172,6 +172,10 @@ async function run(token) { } else { // Issue a standard certificate cert = await certs.create(cn) } + if (!cert) { + // Cert is undefined and "Cert is alread issued" has been printed to stdout + return exit(1) + } const elapsed = ms(new Date() - start) console.log(`${chalk.cyan('> Success!')} Certificate entry ${chalk.bold(cn)} ${chalk.gray(`(${cert.uid})`)} created ${chalk.gray(`[${elapsed}]`)}`) } else if (subcommand === 'renew') { diff --git a/lib/alias.js b/lib/alias.js index fd3236f..66f72fb 100644 --- a/lib/alias.js +++ b/lib/alias.js @@ -196,7 +196,11 @@ export default class Alias extends Now { this._agent.close() this._agent._initAgent() - const {created, uid} = await this.createAlias(depl, alias) + const newAlias = await this.createAlias(depl, alias) + if (!newAlias || !newAlias.created) { + throw new Error(`Unexpected error occurred while setting up alias: ${JSON.stringify(newAlias)}`) + } + const {created, uid} = newAlias if (created) { console.log(`${chalk.cyan('> Success!')} Alias created ${chalk.dim(`(${uid})`)}: ${chalk.bold(chalk.underline(`https://${alias}`))} now points to ${chalk.bold(`https://${depl.url}`)} ${chalk.dim(`(${depl.uid})`)}`) } else { From 96fc0c94970d039fd301ef43860bf88bb304320f Mon Sep 17 00:00:00 2001 From: Jarmo Isotalo Date: Fri, 2 Dec 2016 16:07:11 +0200 Subject: [PATCH 046/160] 0.33.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2b59f21..9241238 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "0.33.1", + "version": "0.33.2", "description": "Realtime global deployments", "repository": "zeit/now", "main": "./build/lib/index", From 9ca1a486bd3a1b2d1dc5c3914bfc19ac6b24690e Mon Sep 17 00:00:00 2001 From: Jarmo Isotalo Date: Sat, 3 Dec 2016 01:32:38 +0200 Subject: [PATCH 047/160] Fix typo --- bin/now-certs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/now-certs.js b/bin/now-certs.js index 8571ab7..16905c7 100755 --- a/bin/now-certs.js +++ b/bin/now-certs.js @@ -173,7 +173,7 @@ async function run(token) { cert = await certs.create(cn) } if (!cert) { - // Cert is undefined and "Cert is alread issued" has been printed to stdout + // Cert is undefined and "Cert is already issued" has been printed to stdout return exit(1) } const elapsed = ms(new Date() - start) From 25fef39f1a2051c66b2c444cea23cd57f53eb3e5 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 3 Dec 2016 12:41:08 +0100 Subject: [PATCH 048/160] Ability to set name This closes #150 --- bin/now-deploy.js | 11 +++++++++-- lib/index.js | 2 ++ lib/read-metadata.js | 33 +++++++++++++++++++++------------ 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 896c10e..7935a84 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -27,7 +27,8 @@ import readMetaData from '../lib/read-metadata' const argv = minimist(process.argv.slice(2), { string: [ 'config', - 'token' + 'token', + 'name' ], boolean: [ 'help', @@ -53,7 +54,8 @@ const argv = minimist(process.argv.slice(2), { login: 'L', public: 'p', 'no-clipboard': 'C', - 'forward-npm': 'N' + 'forward-npm': 'N', + name: 'n' } }) @@ -76,6 +78,7 @@ const help = () => { -h, --help Output usage information -v, --version Output the version number + -n, --name Set the name of the deployment -c ${chalk.underline('FILE')}, --config=${chalk.underline('FILE')} Config file -d, --debug Debug mode [off] -f, --force Force a new deployment even if nothing has changed @@ -149,6 +152,7 @@ const forceNew = argv.force const forceSync = argv.forceSync const shouldLogin = argv.login const wantsPublic = argv.public +const deploymentName = argv.name || false const apiUrl = argv.url || 'https://api.zeit.co' const isTTY = process.stdout.isTTY const quiet = !isTTY @@ -337,6 +341,7 @@ async function sync(token) { const {pkg: {now: pkgConfig = {}} = {}} = await readMetaData(path, { deploymentType, + deploymentName, isStatic, quiet: true }) @@ -366,6 +371,7 @@ async function sync(token) { error('Env key and value missing') return process.exit(1) } + const [key, ...rest] = kv.split('=') let val @@ -433,6 +439,7 @@ async function sync(token) { await now.create(path, { env, deploymentType, + deploymentName, forceNew, forceSync, forwardNpm: alwaysForwardNpm || forwardNpm, diff --git a/lib/index.js b/lib/index.js index d97609b..e29eced 100644 --- a/lib/index.js +++ b/lib/index.js @@ -44,6 +44,7 @@ export default class Now extends EventEmitter { forceSync = false, forwardNpm = false, deploymentType = 'npm', + deploymentName, isStatic = false }) { this._path = path @@ -53,6 +54,7 @@ export default class Now extends EventEmitter { const {pkg, name, description} = await readMetaData(path, { deploymentType, + deploymentName, quiet, isStatic }) diff --git a/lib/read-metadata.js b/lib/read-metadata.js index c76d5d4..579aab0 100644 --- a/lib/read-metadata.js +++ b/lib/read-metadata.js @@ -15,6 +15,7 @@ const listPackage = { export default async function (path, { deploymentType = 'npm', + deploymentName, quiet = false, isStatic = false }) { @@ -44,13 +45,15 @@ export default async function (path, { throw e } - if (typeof pkg.name === 'string') { - name = pkg.name - } else { - name = basename(path) + if (!deploymentName) { + if (typeof pkg.name === 'string') { + name = pkg.name + } else { + name = basename(path) - if (!quiet && !isStatic) { - console.log(`> No \`name\` in \`package.json\`, using ${chalk.bold(name)}`) + if (!quiet && !isStatic) { + console.log(`> No \`name\` in \`package.json\`, using ${chalk.bold(name)}`) + } } } @@ -106,19 +109,25 @@ export default async function (path, { } }) - if (labels.name) { - name = labels.name - } else { - name = basename(path) + if (!deploymentName) { + if (labels.name) { + name = labels.name + } else { + name = basename(path) - if (!quiet) { - console.log(`> No \`name\` LABEL in \`Dockerfile\`, using ${chalk.bold(name)}`) + if (!quiet) { + console.log(`> No \`name\` LABEL in \`Dockerfile\`, using ${chalk.bold(name)}`) + } } } description = labels.description } + if (deploymentName) { + name = deploymentName + } + return { name, description, From 0db509d0b5413d80658a088f87da82da8c46389c Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 3 Dec 2016 12:48:44 +0100 Subject: [PATCH 049/160] Missing greather-than-sign added --- bin/now-deploy.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 7935a84..fe99f5e 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -320,19 +320,19 @@ async function sync(token) { } } else if (hasPackage) { if (debug) { - console.log('[debug] `package.json` found, assuming `deploymentType` = `npm`') + console.log('> [debug] `package.json` found, assuming `deploymentType` = `npm`') } deploymentType = 'npm' } else if (hasDockerfile) { if (debug) { - console.log('[debug] `Dockerfile` found, assuming `deploymentType` = `docker`') + console.log('> [debug] `Dockerfile` found, assuming `deploymentType` = `docker`') } deploymentType = 'docker' } else { if (debug) { - console.log('[debug] No manifest files found, assuming static deployment') + console.log('> [debug] No manifest files found, assuming static deployment') } isStatic = true From 3f4d419f7858e5426aaa81cecea41557cf0f3471 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 3 Dec 2016 12:54:06 +0100 Subject: [PATCH 050/160] Force new deployment if -n or -p defined This closes #136 --- bin/now-deploy.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index fe99f5e..56918dd 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -145,10 +145,10 @@ const exit = code => { } // options +let forceNew = argv.force const debug = argv.debug const clipboard = !argv['no-clipboard'] const forwardNpm = argv['forward-npm'] -const forceNew = argv.force const forceSync = argv.forceSync const shouldLogin = argv.login const wantsPublic = argv.public @@ -161,6 +161,14 @@ if (argv.config) { cfg.setConfigFile(argv.config) } +// Create a new deployment if user changed +// the name or made _src public. +// This should just work fine because it doesn't +// force a new sync, it just forces a new deployment. +if (deploymentName || wantsPublic) { + forceNew = true +} + const config = cfg.read() const alwaysForwardNpm = config.forwardNpm From 1ee41f3c2a1448d6b3a9b237e35c844ca6aa385b Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 3 Dec 2016 13:11:18 +0100 Subject: [PATCH 051/160] Don't just break for older nodes --- bin/now.js | 7 +++++++ package.json | 1 + 2 files changed, 8 insertions(+) diff --git a/bin/now.js b/bin/now.js index 551a954..edbdcd2 100755 --- a/bin/now.js +++ b/bin/now.js @@ -6,9 +6,16 @@ import {resolve} from 'path' // Packages import minimist from 'minimist' import {spawn} from 'cross-spawn' +import nodeVersion from 'node-version' // Ours import checkUpdate from '../lib/check-update' +import {error} from '../lib/error' + +if (nodeVersion.major < 6) { + error('Now requires at least version 6 of Node. Please upgrade!') + process.exit(1) +} const argv = minimist(process.argv.slice(2)) diff --git a/package.json b/package.json index 9241238..616390e 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "minimist": "1.2.0", "ms": "0.7.2", "node-fetch": "1.6.3", + "node-version": "1.0.0", "progress": "1.1.8", "resumer": "0.0.0", "semver-compare": "1.0.0", From d8da820fe7cde7348445e95dd0b4416394b8db61 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 3 Dec 2016 13:36:07 +0100 Subject: [PATCH 052/160] y OR N --- bin/now-alias.js | 2 +- bin/now-certs.js | 2 +- bin/now-dns.js | 2 +- bin/now-domains.js | 2 +- bin/now-remove.js | 2 +- bin/now-secrets.js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/now-alias.js b/bin/now-alias.js index 1ac35f7..d7a0207 100755 --- a/bin/now-alias.js +++ b/bin/now-alias.js @@ -247,7 +247,7 @@ async function readConfirmation(alias, _alias) { process.stdout.write('> The following alias will be removed permanently\n') process.stdout.write(' ' + tbl + '\n') - process.stdout.write(` ${chalk.bold.red('> Are you sure?')} ${chalk.gray('[yN] ')}`) + process.stdout.write(` ${chalk.bold.red('> Are you sure?')} ${chalk.gray('[y/N] ')}`) process.stdin.on('data', d => { process.stdin.pause() diff --git a/bin/now-certs.js b/bin/now-certs.js index 16905c7..543cb85 100755 --- a/bin/now-certs.js +++ b/bin/now-certs.js @@ -264,7 +264,7 @@ function readConfirmation(cert, msg) { process.stdout.write(`> ${msg}`) process.stdout.write(' ' + tbl + '\n') - process.stdout.write(`${chalk.bold.red('> Are you sure?')} ${chalk.gray('[yN] ')}`) + process.stdout.write(`${chalk.bold.red('> Are you sure?')} ${chalk.gray('[y/N] ')}`) process.stdin.on('data', d => { process.stdin.pause() diff --git a/bin/now-dns.js b/bin/now-dns.js index 08aede7..4f1658b 100755 --- a/bin/now-dns.js +++ b/bin/now-dns.js @@ -192,7 +192,7 @@ function readConfirmation(record, msg) { process.stdout.write(`> ${msg}`) process.stdout.write(' ' + tbl + '\n') - process.stdout.write(`${chalk.bold.red('> Are you sure?')} ${chalk.gray('[yN] ')}`) + process.stdout.write(`${chalk.bold.red('> Are you sure?')} ${chalk.gray('[y/N] ')}`) process.stdin.on('data', d => { process.stdin.pause() diff --git a/bin/now-domains.js b/bin/now-domains.js index 2cfc992..2cddcc5 100755 --- a/bin/now-domains.js +++ b/bin/now-domains.js @@ -244,7 +244,7 @@ async function readConfirmation(domain, _domain) { `will be removed. Run ${chalk.dim('`now alias ls`')} to list.\n`) } - process.stdout.write(` ${chalk.bold.red('> Are you sure?')} ${chalk.gray('[yN] ')}`) + process.stdout.write(` ${chalk.bold.red('> Are you sure?')} ${chalk.gray('[y/N] ')}`) process.stdin.on('data', d => { process.stdin.pause() diff --git a/bin/now-remove.js b/bin/now-remove.js index e9537eb..7873683 100755 --- a/bin/now-remove.js +++ b/bin/now-remove.js @@ -94,7 +94,7 @@ function readConfirmation(matches) { } } - process.stdout.write(`${chalk.bold.red('> Are you sure?')} ${chalk.gray('[yN] ')}`) + process.stdout.write(`${chalk.bold.red('> Are you sure?')} ${chalk.gray('[y/N] ')}`) process.stdin.on('data', d => { process.stdin.pause() diff --git a/bin/now-secrets.js b/bin/now-secrets.js index 1388164..7060c98 100755 --- a/bin/now-secrets.js +++ b/bin/now-secrets.js @@ -229,7 +229,7 @@ function readConfirmation(secret) { process.stdout.write('> The following secret will be removed permanently\n') process.stdout.write(' ' + tbl + '\n') - process.stdout.write(`${chalk.bold.red('> Are you sure?')} ${chalk.gray('[yN] ')}`) + process.stdout.write(`${chalk.bold.red('> Are you sure?')} ${chalk.gray('[y/N] ')}`) process.stdin.on('data', d => { process.stdin.pause() From 673b0dcd96c7f964267c100ca3eb65ecffa019c4 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 3 Dec 2016 14:11:16 +0100 Subject: [PATCH 053/160] Don't deploy homedir, downloads or desktop This closes #99 --- bin/now-deploy.js | 4 ++++ lib/utils/check-path.js | 47 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 lib/utils/check-path.js diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 56918dd..de9c3f8 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -23,6 +23,7 @@ import promptOptions from '../lib/utils/prompt-options' import {handleError, error} from '../lib/error' import {fromGit, isRepoPath, gitPathParts} from '../lib/git' import readMetaData from '../lib/read-metadata' +import checkPath from '../lib/utils/check-path' const argv = minimist(process.argv.slice(2), { string: [ @@ -250,6 +251,9 @@ async function sync(token) { } } + // Make sure that directory is not too big + await checkPath(path) + if (!quiet) { if (gitRepo.main) { const gitRef = gitRepo.ref ? ` at "${chalk.bold(gitRepo.ref)}" ` : '' diff --git a/lib/utils/check-path.js b/lib/utils/check-path.js new file mode 100644 index 0000000..055abe9 --- /dev/null +++ b/lib/utils/check-path.js @@ -0,0 +1,47 @@ +// Native +import os from 'os' +import path from 'path' + +// Ours +import {error} from '../error' + +export default async dir => { + if (!dir) { + return + } + + const home = os.homedir() + let location + + const paths = { + home, + desktop: path.join(home, 'Desktop'), + downloads: path.join(home, 'Downloads') + } + + for (const locationPath in paths) { + if (!{}.hasOwnProperty.call(paths, locationPath)) { + continue + } + + if (dir === paths[locationPath]) { + location = locationPath + } + } + + let locationName + + switch (location) { + case 'home': + locationName = 'user directory' + break + case 'downloads': + locationName = 'downloads directory' + break + default: + locationName = location + } + + error(`You're trying to deploy your ${locationName}.`) + process.exit(1) +} From 79d07274ce8ecc7444c293fec24fd87bffbf2a37 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 3 Dec 2016 14:13:46 +0100 Subject: [PATCH 054/160] Regular dirs can be deployed as usual --- lib/utils/check-path.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/utils/check-path.js b/lib/utils/check-path.js index 055abe9..2fad483 100644 --- a/lib/utils/check-path.js +++ b/lib/utils/check-path.js @@ -29,6 +29,10 @@ export default async dir => { } } + if (!location) { + return + } + let locationName switch (location) { From 23aab1f0db8537904a6973a80564a010801e59bb Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 3 Dec 2016 14:16:42 +0100 Subject: [PATCH 055/160] 0.34.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 616390e..8308e96 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "0.33.2", + "version": "0.34.0", "description": "Realtime global deployments", "repository": "zeit/now", "main": "./build/lib/index", From c9808b7a6ed33753fea912471f515554fa38f642 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 3 Dec 2016 14:24:50 +0100 Subject: [PATCH 056/160] Missing import types added --- lib/utils/prompt-options.js | 1 + lib/utils/to-human-path.js | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/utils/prompt-options.js b/lib/utils/prompt-options.js index f1a09c3..2cbd7f7 100644 --- a/lib/utils/prompt-options.js +++ b/lib/utils/prompt-options.js @@ -1,3 +1,4 @@ +// Packages import chalk from 'chalk' export default function (opts) { diff --git a/lib/utils/to-human-path.js b/lib/utils/to-human-path.js index c22892b..88e3bf3 100644 --- a/lib/utils/to-human-path.js +++ b/lib/utils/to-human-path.js @@ -1,3 +1,4 @@ +// Native import {resolve} from 'path' import {homedir} from 'os' From 802e59f68082e5d51774aba0b08497587ca349b9 Mon Sep 17 00:00:00 2001 From: Jarmo Isotalo Date: Sat, 3 Dec 2016 22:15:08 +0200 Subject: [PATCH 057/160] Improve error handling for alias creation, fixes #156 --- lib/alias.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/alias.js b/lib/alias.js index 66f72fb..b6669d3 100644 --- a/lib/alias.js +++ b/lib/alias.js @@ -197,7 +197,7 @@ export default class Alias extends Now { this._agent._initAgent() const newAlias = await this.createAlias(depl, alias) - if (!newAlias || !newAlias.created) { + if (!newAlias) { throw new Error(`Unexpected error occurred while setting up alias: ${JSON.stringify(newAlias)}`) } const {created, uid} = newAlias From 3a4e070c2db448e530cc16e6b7761fb0b1ba5d27 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 5 Dec 2016 12:45:30 +0100 Subject: [PATCH 058/160] Repo slug changed --- README.md | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 31efc7f..45a6a75 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # now -[![Build Status](https://travis-ci.org/zeit/now.svg?branch=master)](https://travis-ci.org/zeit/now) +[![Build Status](https://travis-ci.org/zeit/now-cli.svg?branch=master)](https://travis-ci.org/zeit/now-cli) [![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo) [![Slack Channel](https://zeit-slackin.now.sh/badge.svg)](https://zeit.chat) -Realtime global deployments served over HTTP/2. You can find the FAQ [here](https://github.com/zeit/now/wiki/FAQ). +Realtime global deployments served over HTTP/2. You can find the FAQ [here](https://github.com/zeit/now-cli/wiki/FAQ). ## Usage diff --git a/package.json b/package.json index 8308e96..06edae8 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "now", "version": "0.34.0", "description": "Realtime global deployments", - "repository": "zeit/now", + "repository": "zeit/now-cli", "main": "./build/lib/index", "license": "MIT", "files": [ From f86d576b6c4de52444f55f778cecaf7127f730f2 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 5 Dec 2016 12:45:51 +0100 Subject: [PATCH 059/160] More explicit heading --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 45a6a75..64d96fd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# now +# now CLI [![Build Status](https://travis-ci.org/zeit/now-cli.svg?branch=master)](https://travis-ci.org/zeit/now-cli) [![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo) From 999936059f4ba56daf23c72b715657ff671d15b0 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 5 Dec 2016 12:46:24 +0100 Subject: [PATCH 060/160] 0.34.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 06edae8..626afd8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "0.34.0", + "version": "0.34.1", "description": "Realtime global deployments", "repository": "zeit/now-cli", "main": "./build/lib/index", From 1fee62c596ff34d7a385b02c0aa83d4cd43a7a9f Mon Sep 17 00:00:00 2001 From: Olli Vanhoja Date: Thu, 1 Dec 2016 17:51:47 +0200 Subject: [PATCH 061/160] Support domain name verification --- bin/now-domains.js | 33 +++++++++++++++++++++++++++------ lib/alias.js | 18 ++++++++++++++++-- lib/domains.js | 6 +++--- lib/index.js | 23 +++++++++++++++++++---- 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/bin/now-domains.js b/bin/now-domains.js index 2cddcc5..7c18533 100755 --- a/bin/now-domains.js +++ b/bin/now-domains.js @@ -16,11 +16,12 @@ import NowDomains from '../lib/domains' const argv = minimist(process.argv.slice(2), { string: ['config', 'token'], - boolean: ['help', 'debug', 'force'], + boolean: ['help', 'debug', 'external', 'force'], alias: { help: 'h', config: 'c', debug: 'd', + external: 'e', force: 'f', token: 't' } @@ -37,6 +38,7 @@ const help = () => { -h, --help Output usage information -c ${chalk.bold.underline('FILE')}, --config=${chalk.bold.underline('FILE')} Config file -d, --debug Debug mode [off] + -e, --external Use external DNS server -f, --force Skip DNS verification -t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline('TOKEN')} Login token @@ -77,6 +79,18 @@ const help = () => { ${chalk.cyan('$ now domain rm domainId')} To get the list of domain ids, use ${chalk.dim('`now domains ls`')}. + + ${chalk.gray('–')} Adding and verifying a domain name using zeit.world nameservers: + + ${chalk.cyan('$ now domain add my-app.com')} + + The command will tell you if the domain was verified succesfully. In case the domain was not verified succesfully you should retry adding the domain after some time. + + ${chalk.gray('–')} Adding and verifying a domain name using an external nameserver: + + ${chalk.cyan('$ now domain add -e my-app.com')} + + and follow the verification instructions if requested. Finally, rerun the same command after completing the verification step. `) } @@ -137,7 +151,7 @@ async function run(token) { const domains = await domain.ls() domains.sort((a, b) => new Date(b.created) - new Date(a.created)) const current = new Date() - const header = [['', 'id', 'dns', 'url', 'created'].map(s => chalk.dim(s))] + const header = [['', 'id', 'dns', 'url', 'verified', 'created'].map(s => chalk.dim(s))] const out = domains.length === 0 ? null : table(header.concat(domains.map(domain => { const ns = domain.isExternal ? 'external' : 'zeit.world' const url = chalk.underline(`https://${domain.name}`) @@ -147,9 +161,10 @@ async function run(token) { domain.uid, ns, url, + domain.verified, time ] - })), {align: ['l', 'r', 'l', 'l', 'l'], hsep: ' '.repeat(2), stringLength: strlen}) + })), {align: ['l', 'r', 'l', 'l', 'l', 'l'], hsep: ' '.repeat(2), stringLength: strlen}) const elapsed_ = ms(new Date() - start_) console.log(`> ${domains.length} domain${domains.length === 1 ? '' : 's'} found ${chalk.gray(`[${elapsed_}]`)}`) @@ -209,12 +224,18 @@ async function run(token) { const start = new Date() const name = String(args[0]) - const {uid, created} = await domain.add(name, argv.force) + const {uid, code, verified, verifyToken, created} = await domain.add(name, argv.force, argv.external) const elapsed = ms(new Date() - start) - if (created) { + if (created && verified) { console.log(`${chalk.cyan('> Success!')} Domain ${chalk.bold(chalk.underline(name))} ${chalk.dim(`(${uid})`)} added [${elapsed}]`) - } else { + } else if (verified) { + console.log(`${chalk.cyan('> Success!')} Domain ${chalk.bold(chalk.underline(name))} ${chalk.dim(`(${uid})`)} verified [${elapsed}]`) + } else if (verifyToken) { + console.log(`> Verification required: Please add the following TXT record on the external DNS server: _now.${name}: ${verifyToken}`) + } else if (code === 'not_modified') { console.log(`${chalk.cyan('> Success!')} Domain ${chalk.bold(chalk.underline(name))} ${chalk.dim(`(${uid})`)} already exists [${elapsed}]`) + } else { + console.log('> Verification required: Please rerun this command after some time') } break diff --git a/lib/alias.js b/lib/alias.js index b6669d3..1ec462e 100644 --- a/lib/alias.js +++ b/lib/alias.js @@ -119,13 +119,27 @@ export default class Alias extends Now { console.log(`> Verifying the DNS settings for ${chalk.bold(chalk.underline(alias))} (see ${chalk.underline('https://zeit.world')} for help)`) const {domain, nameservers} = await this.getNameservers(alias) + let skipDNSVerification = false if (this._debug) { console.log(`> [debug] Found domain ${domain} and nameservers ${nameservers}`) } + if (!isZeitWorld(nameservers)) { + const domainInfo = await this.getDomain(domain) + if (domainInfo.verified) { + skipDNSVerification = true + } else if (domainInfo.uid) { + const e = new Error(`> The domain ${domain} is already registered with now but additional verification is needed, please refer to 'now domain --help'.`) + e.userError = true + throw e + } + } + try { - await this.verifyOwnership(alias) + if (!skipDNSVerification) { + await this.verifyOwnership(alias) + } } catch (err) { if (err.userError) { // a user error would imply that verification failed @@ -178,7 +192,7 @@ export default class Alias extends Now { } } - if (!isZeitWorld(nameservers)) { + if (!isZeitWorld(nameservers) && !skipDNSVerification) { if (this._debug) { console.log(`> [debug] Trying to register a non-ZeitWorld domain ${domain} for the current user`) } diff --git a/lib/domains.js b/lib/domains.js index 74d18df..39a997c 100644 --- a/lib/domains.js +++ b/lib/domains.js @@ -37,15 +37,15 @@ export default class Domains extends Now { }) } - async add(domain, skipVerification) { + async add(domain, skipVerification, isExternal) { if (!domainRegex.test(domain)) { const err = new Error(`The supplied value ${chalk.bold(`"${domain}"`)} is not a valid domain.`) err.userError = true throw err } - if (skipVerification) { - return this.setupDomain(domain) + if (skipVerification || isExternal) { + return this.setupDomain(domain, {isExternal}) } let ns diff --git a/lib/index.js b/lib/index.js index e29eced..663e03e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -387,6 +387,22 @@ export default class Now extends EventEmitter { }) } + async getDomain(domain) { + return this.retry(async (bail, attempt) => { + if (this._debug) { + console.time(`> [debug] #${attempt} GET /domains/${domain}`) + } + + const res = await this._fetch(`/domains/${domain}`) + + if (this._debug) { + console.timeEnd(`> [debug] #${attempt} GET /domains/${domain}`) + } + + return await res.json() + }) + } + getNameservers(domain) { return new Promise(resolve => { let fallback = false @@ -449,8 +465,9 @@ export default class Now extends EventEmitter { console.timeEnd(`> [debug] #${attempt} POST /domains`) } + const body = await res.json() + if (res.status === 403) { - const body = await res.json() const code = body.error.code let err @@ -464,15 +481,13 @@ export default class Now extends EventEmitter { return bail(err) } - const body = await res.json() - // domain already exists if (res.status === 409) { if (this._debug) { console.log('> [debug] Domain already exists (noop)') } - return {uid: body.error.uid} + return {uid: body.error.uid, code: body.error.code} } if (res.status !== 200) { From e12c4212c950a3fec6a0569b8c733cdc756365ad Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Wed, 7 Dec 2016 18:28:45 +0100 Subject: [PATCH 062/160] Sprinkled a few newlines on there --- lib/alias.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/alias.js b/lib/alias.js index 1ec462e..1bc9094 100644 --- a/lib/alias.js +++ b/lib/alias.js @@ -15,6 +15,7 @@ export default class Alias extends Now { async ls(deployment) { if (deployment) { const target = await this.findDeployment(deployment) + if (!target) { const err = new Error(`Aliases not found by "${deployment}". Run ${chalk.dim('`now alias ls`')} to see your aliases.`) err.userError = true @@ -63,6 +64,7 @@ export default class Alias extends Now { if (this._debug) { console.log(`> [debug] matched deployment ${d.uid} by ${key} ${val}`) } + return true } @@ -71,6 +73,7 @@ export default class Alias extends Now { if (this._debug) { console.log(`> [debug] matched deployment ${d.uid} by url ${d.url}`) } + return true } @@ -127,6 +130,7 @@ export default class Alias extends Now { if (!isZeitWorld(nameservers)) { const domainInfo = await this.getDomain(domain) + if (domainInfo.verified) { skipDNSVerification = true } else if (domainInfo.uid) { From ec7cacad34afae49078b568de21c44f008b1b9c1 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Wed, 7 Dec 2016 18:29:52 +0100 Subject: [PATCH 063/160] 0.35.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 626afd8..4ece70f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "0.34.1", + "version": "0.35.0", "description": "Realtime global deployments", "repository": "zeit/now-cli", "main": "./build/lib/index", From 0e486282a0a963c5ce102f07c5622af100316757 Mon Sep 17 00:00:00 2001 From: Jarmo Isotalo Date: Thu, 8 Dec 2016 14:59:31 +0200 Subject: [PATCH 064/160] Fix unhandled promise rejection (#162) --- lib/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 663e03e..8527da9 100644 --- a/lib/index.js +++ b/lib/index.js @@ -404,7 +404,7 @@ export default class Now extends EventEmitter { } getNameservers(domain) { - return new Promise(resolve => { + return new Promise((resolve, reject) => { let fallback = false this.retry(async (bail, attempt) => { @@ -445,6 +445,8 @@ export default class Now extends EventEmitter { return ns.length }) resolve(body) + }).catch(err => { + reject(err) }) }) } From 2fdfbbdc221e720bf0ce7bfa116f5b20d311b06b Mon Sep 17 00:00:00 2001 From: Olli Vanhoja Date: Thu, 8 Dec 2016 15:07:22 +0200 Subject: [PATCH 065/160] Improve client side domain verification (#161) No need to check nameservers if the domain is already known and verified by now. --- lib/alias.js | 27 ++++++++++++++++++++------- package.json | 1 + 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/alias.js b/lib/alias.js index 1bc9094..6c05a8c 100644 --- a/lib/alias.js +++ b/lib/alias.js @@ -1,4 +1,5 @@ // Packages +import PublicSuffixList from 'publicsuffixlist' import chalk from 'chalk' // Ours @@ -9,6 +10,9 @@ import {DOMAIN_VERIFICATION_ERROR} from './errors' import Now from './' const domainRegex = /^((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}$/ +const psl = new PublicSuffixList() + +psl.initializeSync() export default class Alias extends Now { @@ -121,16 +125,18 @@ export default class Alias extends Now { console.log(`> ${chalk.bold(chalk.underline(alias))} is a custom domain.`) console.log(`> Verifying the DNS settings for ${chalk.bold(chalk.underline(alias))} (see ${chalk.underline('https://zeit.world')} for help)`) - const {domain, nameservers} = await this.getNameservers(alias) + const _domain = psl.domain(alias) + const _domainInfo = await this.getDomain(_domain) + const domainInfo = _domainInfo && !_domainInfo.error ? _domainInfo : undefined + const {domain, nameservers} = domainInfo ? {domain: _domain} : await this.getNameservers(alias) + const usingZeitWorld = domainInfo ? !domainInfo.isExternal : isZeitWorld(nameservers) let skipDNSVerification = false if (this._debug) { console.log(`> [debug] Found domain ${domain} and nameservers ${nameservers}`) } - if (!isZeitWorld(nameservers)) { - const domainInfo = await this.getDomain(domain) - + if (!usingZeitWorld && domainInfo) { if (domainInfo.verified) { skipDNSVerification = true } else if (domainInfo.uid) { @@ -150,7 +156,7 @@ export default class Alias extends Now { // in which case we attempt to correct the dns // configuration (if we can!) try { - if (isZeitWorld(nameservers)) { + if (usingZeitWorld) { console.log(`> Detected ${chalk.bold(chalk.underline('zeit.world'))} nameservers! Configuring records.`) const record = alias.substr(0, alias.length - domain.length) @@ -196,12 +202,19 @@ export default class Alias extends Now { } } - if (!isZeitWorld(nameservers) && !skipDNSVerification) { + if (!usingZeitWorld && !skipDNSVerification) { if (this._debug) { console.log(`> [debug] Trying to register a non-ZeitWorld domain ${domain} for the current user`) } - await this.setupDomain(domain, {isExternal: true}) + const {uid, verified, verifyToken, created} = await this.setupDomain(domain, {isExternal: true}) + if (created && verified) { + console.log(`${chalk.cyan('> Success!')} Domain ${chalk.bold(chalk.underline(domain))} ${chalk.dim(`(${uid})`)} added`) + } else if (verifyToken) { + const e = new Error(`> Verification required: Please add the following TXT record on the external DNS server: _now.${domain}: ${verifyToken}`) + e.userError = true + throw e + } } console.log(`> Verification ${chalk.bold('OK')}!`) diff --git a/package.json b/package.json index 4ece70f..155a89d 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "node-fetch": "1.6.3", "node-version": "1.0.0", "progress": "1.1.8", + "publicsuffixlist": "0.2.71", "resumer": "0.0.0", "semver-compare": "1.0.0", "socket.io-client": "1.7.1", From 26afd83c1af236b9b067549a56c85e8185235b0b Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Thu, 8 Dec 2016 18:09:19 +0100 Subject: [PATCH 066/160] Ability to skip confirmation when deleting deployments --- bin/now-remove.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/bin/now-remove.js b/bin/now-remove.js index 7873683..8abf396 100755 --- a/bin/now-remove.js +++ b/bin/now-remove.js @@ -14,12 +14,13 @@ import {handleError, error} from '../lib/error' const argv = minimist(process.argv.slice(2), { string: ['config', 'token'], - boolean: ['help', 'debug', 'hard'], + boolean: ['help', 'debug', 'hard', 'yes'], alias: { help: 'h', config: 'c', debug: 'd', - token: 't' + token: 't', + yes: 'y' } }) @@ -36,6 +37,7 @@ const help = () => { -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 + -y, --yes Skip confirmation ${chalk.dim('Examples:')} @@ -64,6 +66,7 @@ if (argv.help || ids.length === 0) { const debug = argv.debug const apiUrl = argv.url || 'https://api.zeit.co' const hard = argv.hard || false +const skipConfirmation = argv.yes || false if (argv.config) { cfg.setConfigFile(argv.config) @@ -147,10 +150,13 @@ async function remove(token) { } try { - const confirmation = (await readConfirmation(matches)).toLowerCase() - if (confirmation !== 'y' && confirmation !== 'yes') { - console.log('\n> Aborted') - process.exit(0) + if (!skipConfirmation) { + const confirmation = (await readConfirmation(matches)).toLowerCase() + + if (confirmation !== 'y' && confirmation !== 'yes') { + console.log('\n> Aborted') + process.exit(0) + } } const start = new Date() From 3c28d01fc7df0981aee7dfcfadc99028f873304c Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Thu, 8 Dec 2016 20:54:29 +0100 Subject: [PATCH 067/160] 0.36.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 155a89d..d448c50 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "0.35.0", + "version": "0.36.0", "description": "Realtime global deployments", "repository": "zeit/now-cli", "main": "./build/lib/index", From 03b33945d851d6e8e7c1334d35a347586971ac8a Mon Sep 17 00:00:00 2001 From: Igor Klopov Date: Fri, 9 Dec 2016 17:22:45 +0300 Subject: [PATCH 068/160] pkg@3.0.0-beta.22 fixes publicsuffixlist issue (#165) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d448c50..d354b54 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "gulp-babel": "6.1.2", "gulp-ext": "1.0.0", "gulp-task-listing": "1.0.1", - "pkg": "3.0.0-beta.21", + "pkg": "3.0.0-beta.22", "xo": "0.17.1" } } From 692bd34ced7c99e1f718994223069cd105c30ac8 Mon Sep 17 00:00:00 2001 From: Matheus Fernandes Date: Fri, 9 Dec 2016 12:32:36 -0200 Subject: [PATCH 069/160] Add `dns` entry to the global help (#164) --- bin/now-deploy.js | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index de9c3f8..411bc5b 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -73,6 +73,7 @@ const help = () => { domains [name] Manages your domain names certs [cmd] Manages your SSL certificates secrets [name] Manages your secret environment variables + dns [name] Manages your DNS records help [cmd] Displays complete help for [cmd] ${chalk.dim('Options:')} From 3a8f11b1ba486edc337cfa77f50c4a25454d73c0 Mon Sep 17 00:00:00 2001 From: Olli Vanhoja Date: Fri, 9 Dec 2016 16:44:05 +0200 Subject: [PATCH 070/160] alias set --debug: Only print nameservers if we fetched them (#166) --- lib/alias.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/alias.js b/lib/alias.js index 6c05a8c..c4ba92f 100644 --- a/lib/alias.js +++ b/lib/alias.js @@ -133,7 +133,11 @@ export default class Alias extends Now { let skipDNSVerification = false if (this._debug) { - console.log(`> [debug] Found domain ${domain} and nameservers ${nameservers}`) + if (domainInfo) { + console.log(`> [debug] Found domain ${domain} with verified:${domainInfo.verified}`) + } else { + console.log(`> [debug] Found domain ${domain} and nameservers ${nameservers}`) + } } if (!usingZeitWorld && domainInfo) { From cd9891dbc9bcb804bc409ec7d927053c3322f203 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 12 Dec 2016 10:03:17 +0100 Subject: [PATCH 071/160] 0.36.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d354b54..1601276 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "0.36.0", + "version": "0.36.1", "description": "Realtime global deployments", "repository": "zeit/now-cli", "main": "./build/lib/index", From f997a8fa61f8b4180c8fd36d276cb845386a7437 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 12 Dec 2016 18:01:37 +0100 Subject: [PATCH 072/160] List got renamed --- lib/read-metadata.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/read-metadata.js b/lib/read-metadata.js index 579aab0..eaa3eb8 100644 --- a/lib/read-metadata.js +++ b/lib/read-metadata.js @@ -6,10 +6,10 @@ import {parse as parseDockerfile} from 'docker-file-parser' const listPackage = { version: '0.0.0', scripts: { - start: 'list ./content' + start: 'serve ./content' }, dependencies: { - list: 'latest' + serve: 'latest' } } From cf5b9ad12527a65df8f6fe523ad767474cad98ec Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 12 Dec 2016 18:31:29 +0100 Subject: [PATCH 073/160] Replace publicsuffixlist with psl --- lib/alias.js | 7 ++----- package.json | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/alias.js b/lib/alias.js index c4ba92f..29c9034 100644 --- a/lib/alias.js +++ b/lib/alias.js @@ -1,5 +1,5 @@ // Packages -import PublicSuffixList from 'publicsuffixlist' +import publicSuffixList from 'psl' import chalk from 'chalk' // Ours @@ -10,9 +10,6 @@ import {DOMAIN_VERIFICATION_ERROR} from './errors' import Now from './' const domainRegex = /^((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}$/ -const psl = new PublicSuffixList() - -psl.initializeSync() export default class Alias extends Now { @@ -125,7 +122,7 @@ export default class Alias extends Now { console.log(`> ${chalk.bold(chalk.underline(alias))} is a custom domain.`) console.log(`> Verifying the DNS settings for ${chalk.bold(chalk.underline(alias))} (see ${chalk.underline('https://zeit.world')} for help)`) - const _domain = psl.domain(alias) + const _domain = publicSuffixList.parse(alias).domain const _domainInfo = await this.getDomain(_domain) const domainInfo = _domainInfo && !_domainInfo.error ? _domainInfo : undefined const {domain, nameservers} = domainInfo ? {domain: _domain} : await this.getNameservers(alias) diff --git a/package.json b/package.json index 1601276..1c51437 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "node-fetch": "1.6.3", "node-version": "1.0.0", "progress": "1.1.8", - "publicsuffixlist": "0.2.71", + "psl": "1.1.15", "resumer": "0.0.0", "semver-compare": "1.0.0", "socket.io-client": "1.7.1", From 6879ee1d4dcb8916d580d88f33481a1e723a32ba Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 12 Dec 2016 18:40:14 +0100 Subject: [PATCH 074/160] Updated dependencies --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 1c51437..a12bc52 100644 --- a/package.json +++ b/package.json @@ -68,14 +68,14 @@ "arr-flatten": "1.0.1", "array-unique": "0.3.2", "async-retry": "0.2.1", - "babel-runtime": "6.18.0", + "babel-runtime": "6.20.0", "bytes": "2.4.0", "chalk": "1.1.3", "copy-paste": "1.3.0", "cross-spawn": "5.0.1", "docker-file-parser": "0.1.0", "download": "5.0.2", - "email-prompt": "0.1.8", + "email-prompt": "0.2.0", "email-validator": "1.0.7", "fs-promise": "1.0.0", "glob": "7.1.1", @@ -91,7 +91,7 @@ "psl": "1.1.15", "resumer": "0.0.0", "semver-compare": "1.0.0", - "socket.io-client": "1.7.1", + "socket.io-client": "1.7.2", "spdy": "3.4.4", "split-array": "1.0.1", "text-table": "0.2.0", From af76505c9e02ad79f739e5c729c89c8b1973bcc4 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 12 Dec 2016 19:00:42 +0100 Subject: [PATCH 075/160] Improved flow for confirming address --- lib/login.js | 15 +++++++++++---- package.json | 1 + 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/login.js b/lib/login.js index 2de8df3..875f7ae 100644 --- a/lib/login.js +++ b/lib/login.js @@ -7,6 +7,7 @@ import chalk from 'chalk' import fetch from 'node-fetch' import {validate} from 'email-validator' import readEmail from 'email-prompt' +import ora from 'ora' // Ours import pkg from '../../package' @@ -62,13 +63,18 @@ async function register(url, {retryEmail = false} = {}) { } const {token, securityCode} = await getVerificationData(url, email) - console.log(`> Please follow the link sent to ${chalk.bold(email)} to log in.`) + if (securityCode) { console.log(`> Verify that the provided security code in the email matches ${chalk.cyan(chalk.bold(securityCode))}.`) } - process.stdout.write('> Waiting for confirmation..') + process.stdout.write('\n') + + const spinner = ora({ + text: 'Waiting for confirmation...', + color: 'black' + }).start() let final @@ -78,10 +84,11 @@ async function register(url, {retryEmail = false} = {}) { try { final = await verify(url, email, token) } catch (err) {} - - process.stdout.write('.') } while (!final) + spinner.text = 'Confirmed email address!' + spinner.stopAndPersist('✔') + process.stdout.write('\n') return {email, token: final} diff --git a/package.json b/package.json index a12bc52..ce81f1b 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "ms": "0.7.2", "node-fetch": "1.6.3", "node-version": "1.0.0", + "ora": "0.3.0", "progress": "1.1.8", "psl": "1.1.15", "resumer": "0.0.0", From aeb7f4a5db9ea60c7100e4b278ce6da0c35d61cb Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 12 Dec 2016 19:11:59 +0100 Subject: [PATCH 076/160] 0.36.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ce81f1b..6c72639 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "0.36.1", + "version": "0.36.2", "description": "Realtime global deployments", "repository": "zeit/now-cli", "main": "./build/lib/index", From 0830aabe084e3f209dfd7542ba40a73e2b0daba4 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Thu, 15 Dec 2016 08:15:13 +0100 Subject: [PATCH 077/160] Only show update message in npm version This closes #62 --- bin/now.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/bin/now.js b/bin/now.js index edbdcd2..cbcd118 100755 --- a/bin/now.js +++ b/bin/now.js @@ -22,11 +22,19 @@ const argv = minimist(process.argv.slice(2)) // options const debug = argv.debug || argv.d +// Disable updates by default +let update = false + // auto-update checking -const update = checkUpdate({debug}) +// only for the npm version, not the enclosed one +if (!process.pkg) { + update = checkUpdate({debug}) +} const exit = code => { - update.then(() => process.exit(code)) + if (update) { + update.then(() => process.exit(code)) + } // don't wait for updates more than a second // when the process really wants to exit setTimeout(() => process.exit(code), 1000) From 2276dfb5d5890e10f5b3906474a119eaee7d6005 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Thu, 15 Dec 2016 10:21:17 +0100 Subject: [PATCH 078/160] Basics for automatically assigning alias --- bin/now-deploy.js | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 411bc5b..61c98d5 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -24,12 +24,14 @@ import {handleError, error} from '../lib/error' import {fromGit, isRepoPath, gitPathParts} from '../lib/git' import readMetaData from '../lib/read-metadata' import checkPath from '../lib/utils/check-path' +import NowAlias from '../lib/alias' const argv = minimist(process.argv.slice(2), { string: [ 'config', 'token', - 'name' + 'name', + 'alias' ], boolean: [ 'help', @@ -56,7 +58,8 @@ const argv = minimist(process.argv.slice(2), { public: 'p', 'no-clipboard': 'C', 'forward-npm': 'N', - name: 'n' + name: 'n', + alias: 'a' } }) @@ -90,6 +93,7 @@ const help = () => { -e, --env Include an env var (e.g.: ${chalk.dim('`-e KEY=value`')}). Can appear many times. -C, --no-clipboard Do not attempt to copy URL to clipboard -N, --forward-npm Forward login information to install private NPM modules + -a, --alias Assign an alias to the deployment ${chalk.dim('Enforcable Types (when both package.json and Dockerfile exist):')} @@ -158,6 +162,7 @@ const deploymentName = argv.name || false const apiUrl = argv.url || 'https://api.zeit.co' const isTTY = process.stdout.isTTY const quiet = !isTTY +const autoAlias = argv.alias || false if (argv.config) { cfg.setConfigFile(argv.config) @@ -500,7 +505,7 @@ async function sync(token) { now.close() // show build logs - printLogs(now.host) + printLogs(now.host, token) } if (now.syncAmount) { @@ -537,14 +542,40 @@ async function sync(token) { now.close() // show build logs - printLogs(now.host) + printLogs(now.host, token) } } -function printLogs(host) { +const assignAlias = async token => { + const aliases = new NowAlias(apiUrl, token, {debug}) + const list = await aliases.ls() + + let related + + for (const alias of list) { + if (alias.alias === autoAlias) { + related = alias + break + } + } + + if (!related) { + error(`Alias "${autoAlias}" doesn't exist`) + return + } + + console.log(`> Assigning alias "${autoAlias}" to deployment...`) +} + +function printLogs(host, token) { // log build const logger = new Logger(host, {debug, quiet}) - logger.on('close', () => { + + logger.on('close', async () => { + if (autoAlias) { + await assignAlias(token) + } + if (!quiet) { console.log(`${chalk.cyan('> Deployment complete!')}`) } From 68a53c67f2ec188cf7a232bef475df9f0791f05d Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Thu, 15 Dec 2016 10:25:26 +0100 Subject: [PATCH 079/160] Ability to automatically assign an alias --- bin/now-deploy.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 61c98d5..21bfcf1 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -546,12 +546,13 @@ async function sync(token) { } } -const assignAlias = async token => { +const assignAlias = async (token, deployment) => { const aliases = new NowAlias(apiUrl, token, {debug}) const list = await aliases.ls() let related + // Check if alias even exists for (const alias of list) { if (alias.alias === autoAlias) { related = alias @@ -559,12 +560,16 @@ const assignAlias = async token => { } } + // Throw an error if it doesn't if (!related) { error(`Alias "${autoAlias}" doesn't exist`) return } console.log(`> Assigning alias "${autoAlias}" to deployment...`) + + // Assign alias + await aliases.set(String(deployment), String(related.alias)) } function printLogs(host, token) { @@ -573,7 +578,7 @@ function printLogs(host, token) { logger.on('close', async () => { if (autoAlias) { - await assignAlias(token) + await assignAlias(token, host) } if (!quiet) { From 09b91e8fbba5e0150a4f06c3d53f7b12725919a7 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Thu, 15 Dec 2016 10:37:23 +0100 Subject: [PATCH 080/160] Support IDs for auto aliasing --- bin/now-deploy.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 21bfcf1..854d8e4 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -10,6 +10,7 @@ import bytes from 'bytes' import chalk from 'chalk' import minimist from 'minimist' import ms from 'ms' +import publicSuffixList from 'psl' // Ours import copy from '../lib/copy' @@ -547,6 +548,8 @@ async function sync(token) { } const assignAlias = async (token, deployment) => { + const type = publicSuffixList.isValid(autoAlias) ? 'alias' : 'uid' + const aliases = new NowAlias(apiUrl, token, {debug}) const list = await aliases.ls() @@ -554,7 +557,7 @@ const assignAlias = async (token, deployment) => { // Check if alias even exists for (const alias of list) { - if (alias.alias === autoAlias) { + if (alias[type] === autoAlias) { related = alias break } @@ -566,7 +569,7 @@ const assignAlias = async (token, deployment) => { return } - console.log(`> Assigning alias "${autoAlias}" to deployment...`) + console.log(`> Assigning alias ${chalk.bold.underline(related.alias)} to deployment...`) // Assign alias await aliases.set(String(deployment), String(related.alias)) From 84342092cdac3b10c0f1800db63e70b714e779a8 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Thu, 15 Dec 2016 10:39:41 +0100 Subject: [PATCH 081/160] Better error message if alias is missing --- bin/now-deploy.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 854d8e4..2bb1998 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -565,7 +565,8 @@ const assignAlias = async (token, deployment) => { // Throw an error if it doesn't if (!related) { - error(`Alias "${autoAlias}" doesn't exist`) + const withID = type === 'uid' ? 'with ID ' : '' + error(`Alias ${withID}"${autoAlias}" doesn't exist`) return } From 0bc7d0fb50231d8d5679ae01f8d25429b9f8389d Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Thu, 15 Dec 2016 10:41:12 +0100 Subject: [PATCH 082/160] 0.37.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6c72639..e6d0b1b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "0.36.2", + "version": "0.37.0", "description": "Realtime global deployments", "repository": "zeit/now-cli", "main": "./build/lib/index", From ffd92902fc9c354cb96861dd70e644b08c9f55fe Mon Sep 17 00:00:00 2001 From: Greenkeeper Date: Sat, 17 Dec 2016 12:07:37 +0100 Subject: [PATCH 083/160] chore(package): update alpha-sort to version 2.0.0 (#174) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e6d0b1b..d9ec6a7 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "tmp-promise": "1.0.2" }, "devDependencies": { - "alpha-sort": "1.0.2", + "alpha-sort": "2.0.0", "ava": "0.17.0", "babel-plugin-transform-async-to-generator": "6.16.0", "babel-plugin-transform-runtime": "6.15.0", From 06f1584e0d385ca017d654371cb8e32ce5d640cf Mon Sep 17 00:00:00 2001 From: Greenkeeper Date: Sat, 17 Dec 2016 22:38:28 +0100 Subject: [PATCH 084/160] chore(package): update ora to version 0.4.0 (#176) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d9ec6a7..26485bf 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "ms": "0.7.2", "node-fetch": "1.6.3", "node-version": "1.0.0", - "ora": "0.3.0", + "ora": "0.4.0", "progress": "1.1.8", "psl": "1.1.15", "resumer": "0.0.0", From 0754cffa1199709eafe5fab3fe538251aa4a0dc1 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 20 Dec 2016 12:19:45 +0100 Subject: [PATCH 085/160] Tell gulp to cache --- gulpfile.babel.js | 3 +++ package.json | 1 + 2 files changed, 4 insertions(+) diff --git a/gulpfile.babel.js b/gulpfile.babel.js index a85344e..3f35ac2 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -4,6 +4,7 @@ import del from 'del' import babel from 'gulp-babel' import help from 'gulp-task-listing' import {crop as cropExt} from 'gulp-ext' +import cache from 'gulp-cached' gulp.task('help', help) @@ -14,11 +15,13 @@ gulp.task('compile', [ gulp.task('compile-lib', () => gulp.src('lib/**/*.js') + .pipe(cache('lib')) .pipe(babel()) .pipe(gulp.dest('build/lib'))) gulp.task('compile-bin', () => gulp.src('bin/*') + .pipe(cache('bin')) .pipe(babel()) .pipe(cropExt()) .pipe(gulp.dest('build/bin'))) diff --git a/package.json b/package.json index 26485bf..7248be5 100644 --- a/package.json +++ b/package.json @@ -109,6 +109,7 @@ "estraverse-fb": "1.3.1", "gulp": "3.9.1", "gulp-babel": "6.1.2", + "gulp-cached": "1.1.1", "gulp-ext": "1.0.0", "gulp-task-listing": "1.0.1", "pkg": "3.0.0-beta.22", From 45193ee497dc415df4fa4f8c6915f5178b506d02 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 20 Dec 2016 12:32:33 +0100 Subject: [PATCH 086/160] Make FAQ plural --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 64d96fd..388d4ca 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo) [![Slack Channel](https://zeit-slackin.now.sh/badge.svg)](https://zeit.chat) -Realtime global deployments served over HTTP/2. You can find the FAQ [here](https://github.com/zeit/now-cli/wiki/FAQ). +Realtime global deployments served over HTTP/2. You can find the FAQs [here](https://github.com/zeit/now-cli/wiki/FAQ). ## Usage From 2ddfeb9ca9f2a0bfdca2f91280345951328d15d9 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 20 Dec 2016 13:20:53 +0100 Subject: [PATCH 087/160] Proper script name for development --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7248be5..24af2ab 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "build" ], "scripts": { - "start": "gulp", + "dev": "gulp", "test": "xo && ava", "pretest": "gulp compile", "prepublish": "gulp compile", From 9a249649dad3d23a409a594e19e57c958057faa3 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 20 Dec 2016 13:21:33 +0100 Subject: [PATCH 088/160] New script for building added --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 24af2ab..d4c2606 100644 --- a/package.json +++ b/package.json @@ -10,9 +10,10 @@ ], "scripts": { "dev": "gulp", + "build": "gulp compile", "test": "xo && ava", - "pretest": "gulp compile", - "prepublish": "gulp compile", + "pretest": "npm run build", + "prepublish": "npm run build", "pkg": "pkg . --out-dir out" }, "pkg": { From 1aa4fd88f3ba41a38fcbb1de0dc4a941361b8856 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 20 Dec 2016 22:16:01 +0100 Subject: [PATCH 089/160] Adjusted cmd name for development --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 388d4ca..59302aa 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ $ now help 1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device 2. Link the package to the global module directory: `npm link` -3. Transpile the source code and watch for changes: `npm start` +3. Transpile the source code and watch for changes: `npm run dev` 4. You can now start using `now` from the command line! As always, you can use `npm test` to run the tests and see if your changes have broken anything. From 028e9092dfb52ddaf7655d41acaacc5ee92e298d Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 20 Dec 2016 22:17:53 +0100 Subject: [PATCH 090/160] Both now-cli and now-desktop need the same here --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d4c2606..6c14bcd 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "test": "xo && ava", "pretest": "npm run build", "prepublish": "npm run build", - "pkg": "pkg . --out-dir out" + "pack": "pkg . --out-dir out" }, "pkg": { "scripts": "build/**/*" From e803dc80f9f043d71c8647ca107efc2096cb5f12 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Wed, 21 Dec 2016 18:55:03 +0100 Subject: [PATCH 091/160] Make FAQs link to homepage --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 59302aa..568a4c7 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo) [![Slack Channel](https://zeit-slackin.now.sh/badge.svg)](https://zeit.chat) -Realtime global deployments served over HTTP/2. You can find the FAQs [here](https://github.com/zeit/now-cli/wiki/FAQ). +Realtime global deployments served over HTTP/2. You can find the FAQs [here](https://zeit.co/now#frequently-asked-questions). ## Usage From 1ce72df4fdba131a64914e94ff804173545fba5e Mon Sep 17 00:00:00 2001 From: Igor Klopov Date: Fri, 23 Dec 2016 20:24:22 +0300 Subject: [PATCH 092/160] show `Using Node.js` only for npm deployment type (#183) --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 8527da9..dc3357d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -210,7 +210,7 @@ export default class Now extends EventEmitter { } } - if (!quiet && deployment.nodeVersion) { + if (!quiet && deploymentType === 'npm' && deployment.nodeVersion) { if (engines && engines.node) { if (missingVersion) { console.log(`> Using Node.js ${chalk.bold(deployment.nodeVersion)} (default)`) From 8ab8ca53d2bb16ef49f9f963733098848bc42ce3 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Fri, 23 Dec 2016 22:11:59 +0100 Subject: [PATCH 093/160] 0.37.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6c14bcd..94e9025 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "0.37.0", + "version": "0.37.1", "description": "Realtime global deployments", "repository": "zeit/now-cli", "main": "./build/lib/index", From 14d861e6d1d41b029b191a595cc9ab8f5eda5c00 Mon Sep 17 00:00:00 2001 From: Olli Vanhoja Date: Sat, 24 Dec 2016 10:24:52 +0200 Subject: [PATCH 094/160] Show an appropriate message for incomplete deployments (#185) If syncing files fails or the user just happens to run `now ls` before the deployment is ready `https://null` is shown as an URL to the deployment. Instead of showing `null` we could show something nice. --- bin/now-list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/now-list.js b/bin/now-list.js index 61dc539..fc64491 100755 --- a/bin/now-list.js +++ b/bin/now-list.js @@ -108,7 +108,7 @@ async function list(token) { const text = sorted.map(([name, deps]) => { const t = table(deps.map(({uid, url, created}) => { - const _url = chalk.underline(`https://${url}`) + const _url = url ? chalk.underline(`https://${url}`) : 'incomplete'; const time = chalk.gray(ms(current - created) + ' ago') return [uid, _url, time] }), {align: ['l', 'r', 'l'], hsep: ' '.repeat(6), stringLength: strlen}) From 8698bd694f3396e0f55b887f7e58ed023dca2219 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 24 Dec 2016 09:30:43 +0100 Subject: [PATCH 095/160] Removed unnecessary semicolon --- bin/now-list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/now-list.js b/bin/now-list.js index fc64491..ca2a7ff 100755 --- a/bin/now-list.js +++ b/bin/now-list.js @@ -108,7 +108,7 @@ async function list(token) { const text = sorted.map(([name, deps]) => { const t = table(deps.map(({uid, url, created}) => { - const _url = url ? chalk.underline(`https://${url}`) : 'incomplete'; + const _url = url ? chalk.underline(`https://${url}`) : 'incomplete' const time = chalk.gray(ms(current - created) + ' ago') return [uid, _url, time] }), {align: ['l', 'r', 'l'], hsep: ' '.repeat(6), stringLength: strlen}) From c509dfd5d7ba03cccfed2598c13e4191018f93e7 Mon Sep 17 00:00:00 2001 From: Olli Vanhoja Date: Wed, 28 Dec 2016 23:15:55 +0200 Subject: [PATCH 096/160] Support basic file modes (#187) now-cli should pass file mode bits when creating a deployment. --- lib/index.js | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/lib/index.js b/lib/index.js index dc3357d..a03eb6d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -6,11 +6,11 @@ import EventEmitter from 'events' // Packages import bytes from 'bytes' import chalk from 'chalk' -import retry from 'async-retry' -import {parse as parseIni} from 'ini' -import {readFile} from 'fs-promise' import resumer from 'resumer' +import retry from 'async-retry' import splitArray from 'split-array' +import {parse as parseIni} from 'ini' +import {readFile, stat} from 'fs-promise' // Ours import {npm as getNpmFiles, docker as getDockerFiles} from './get-files' @@ -124,6 +124,25 @@ export default class Now extends EventEmitter { console.time('> [debug] /now/create') } + // Flatten the array to contain files to sync where each nested input + // array has a group of files with the same sha but different path + const files = await Promise.all(Array.prototype.concat.apply([], await Promise.all((Array.from(this._files)).map(async ([sha, {data, names}]) => { + return await names.map(async name => { + if (this._static && toRelative(name, this._path) !== 'package.json') { + name = this.pathInsideContent(name) + } + + const st = await stat(name) + + return { + sha, + size: data.length, + file: toRelative(name, this._path), + mode: st.mode + } + }) + })))) + const res = await this._fetch('/now/create', { method: 'POST', body: { @@ -135,21 +154,7 @@ export default class Now extends EventEmitter { description, deploymentType, registryAuthToken: authToken, - // Flatten the array to contain files to sync where each nested input - // array has a group of files with the same sha but different path - files: Array.prototype.concat.apply([], Array.from(this._files).map(([sha, {data, names}]) => { - return names.map(n => { - if (this._static && toRelative(n, this._path) !== 'package.json') { - n = this.pathInsideContent(n) - } - - return { - sha, - size: data.length, - file: toRelative(n, this._path) - } - }) - })), + files, engines } }) From 02b0a9e2d3066c70b5e8831c91e97c1bd11feca7 Mon Sep 17 00:00:00 2001 From: Olli Vanhoja Date: Thu, 29 Dec 2016 21:01:59 +0200 Subject: [PATCH 097/160] Add TXT record type to `now dns --help` (#190) TXT record support was recently added to now. --- bin/now-dns.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/now-dns.js b/bin/now-dns.js index 4f1658b..d0bf613 100755 --- a/bin/now-dns.js +++ b/bin/now-dns.js @@ -30,7 +30,7 @@ const subcommand = argv._[0] const help = () => { console.log(` ${chalk.bold('𝚫 now dns ls')} [domain] - ${chalk.bold('𝚫 now dns add')} [mx_priority] + ${chalk.bold('𝚫 now dns add')} [mx_priority] ${chalk.bold('𝚫 now dns rm')} ${chalk.dim('Options:')} From 1c7a13fe68c5ac66331e478e24f658269fd69fdc Mon Sep 17 00:00:00 2001 From: Olli Vanhoja Date: Fri, 30 Dec 2016 19:44:18 +0200 Subject: [PATCH 098/160] Add an option to copy symlinks (#191) --- bin/now-deploy.js | 5 +++++ lib/index.js | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 2bb1998..b440413 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -39,6 +39,7 @@ const argv = minimist(process.argv.slice(2), { 'version', 'debug', 'force', + 'links', 'login', 'no-clipboard', 'forward-npm', @@ -55,6 +56,7 @@ const argv = minimist(process.argv.slice(2), { force: 'f', token: 't', forceSync: 'F', + links: 'l', login: 'L', public: 'p', 'no-clipboard': 'C', @@ -90,6 +92,7 @@ const help = () => { -f, --force Force a new deployment even if nothing has changed -t ${chalk.underline('TOKEN')}, --token=${chalk.underline('TOKEN')} Login token -L, --login Configure login + -l, --links Copy symlinks without resolving their target -p, --public Deployment is public (${chalk.dim('`/_src`')} is exposed) [on for oss, off for premium] -e, --env Include an env var (e.g.: ${chalk.dim('`-e KEY=value`')}). Can appear many times. -C, --no-clipboard Do not attempt to copy URL to clipboard @@ -158,6 +161,7 @@ const clipboard = !argv['no-clipboard'] const forwardNpm = argv['forward-npm'] const forceSync = argv.forceSync const shouldLogin = argv.login +const followSymlinks = !argv.links const wantsPublic = argv.public const deploymentName = argv.name || false const apiUrl = argv.url || 'https://api.zeit.co' @@ -459,6 +463,7 @@ async function sync(token) { env, deploymentType, deploymentName, + followSymlinks, forceNew, forceSync, forwardNpm: alwaysForwardNpm || forwardNpm, diff --git a/lib/index.js b/lib/index.js index a03eb6d..7f3474d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -10,7 +10,7 @@ import resumer from 'resumer' import retry from 'async-retry' import splitArray from 'split-array' import {parse as parseIni} from 'ini' -import {readFile, stat} from 'fs-promise' +import {readFile, stat, lstat} from 'fs-promise' // Ours import {npm as getNpmFiles, docker as getDockerFiles} from './get-files' @@ -40,6 +40,7 @@ export default class Now extends EventEmitter { wantsPublic, quiet = false, env = {}, + followSymlinks = true, forceNew = false, forceSync = false, forwardNpm = false, @@ -132,7 +133,7 @@ export default class Now extends EventEmitter { name = this.pathInsideContent(name) } - const st = await stat(name) + const st = await (followSymlinks ? stat(name) : lstat(name)) return { sha, From ac07fc3ee2b826f3541e62bdec4ddb8cf05f638d Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Fri, 30 Dec 2016 23:00:15 +0100 Subject: [PATCH 099/160] 0.38.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 94e9025..e9c69be 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "0.37.1", + "version": "0.38.0", "description": "Realtime global deployments", "repository": "zeit/now-cli", "main": "./build/lib/index", From 1652fd01a1bc10d01bfa72891199aa9589767d20 Mon Sep 17 00:00:00 2001 From: Olli Vanhoja Date: Mon, 2 Jan 2017 10:18:52 +0200 Subject: [PATCH 100/160] Add auto-renew column to `now certs ls` (#195) --- bin/now-certs.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/now-certs.js b/bin/now-certs.js index 543cb85..134b89d 100755 --- a/bin/now-certs.js +++ b/bin/now-certs.js @@ -132,7 +132,7 @@ async function run(token) { list.sort((a, b) => { return a.cn.localeCompare(b.cn) }) - const header = [['', 'id', 'cn', 'created', 'expiration'].map(s => chalk.dim(s))] + const header = [['', 'id', 'cn', 'created', 'expiration', 'auto-renew'].map(s => chalk.dim(s))] const out = table(header.concat(list.map(cert => { const cn = chalk.bold(cert.cn) const time = chalk.gray(ms(cur - new Date(cert.created)) + ' ago') @@ -142,7 +142,8 @@ async function run(token) { cert.uid ? cert.uid : 'unknown', cn, time, - expiration + expiration, + cert.autoRenew ? 'yes' : 'no' ] })), {align: ['l', 'r', 'l', 'l', 'l'], hsep: ' '.repeat(2), stringLength: strlen}) From 0cc0544ec389a2e48f3637378e71da5bac972ccb Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 2 Jan 2017 14:52:06 +0100 Subject: [PATCH 101/160] Authors added --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 568a4c7..ba44047 100644 --- a/README.md +++ b/README.md @@ -34,3 +34,11 @@ $ now help 4. You can now start using `now` from the command line! As always, you can use `npm test` to run the tests and see if your changes have broken anything. + +## Authors + +- Guillermo Rauch ([@rauchg](https://twitter.com/rauchg)) - [▲ZEIT](https://zeit.co) +- Leo Lamprecht ([@notquiteleo](https://twitter.com/notquiteleo)) - [▲ZEIT](https://zeit.co) +- Tony Kovanen ([@TonyKovanen](https://twitter.com/TonyKovanen)) - [▲ZEIT](https://zeit.co) +- Olli Vanhoja ([@OVanhoja](https://twitter.com/OVanhoja)) - [▲ZEIT](https://zeit.co) +- Naoyuki Kanezawa ([@nkzawa](https://twitter.com/nkzawa)) - [▲ZEIT](https://zeit.co) From 960c80ae3f443a569ba56dbab34696d09c6696a6 Mon Sep 17 00:00:00 2001 From: Greenkeeper Date: Mon, 2 Jan 2017 17:29:08 +0100 Subject: [PATCH 102/160] chore(package): update tmp-promise to version 1.0.3 (#196) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e9c69be..45b06fa 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "spdy": "3.4.4", "split-array": "1.0.1", "text-table": "0.2.0", - "tmp-promise": "1.0.2" + "tmp-promise": "1.0.3" }, "devDependencies": { "alpha-sort": "2.0.0", From bbf1b30c4decce34a115e64201702f270eb003c3 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 2 Jan 2017 21:18:16 +0100 Subject: [PATCH 103/160] Set a default file mode for package.json --- lib/index.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/index.js b/lib/index.js index 7f3474d..c1072fb 100644 --- a/lib/index.js +++ b/lib/index.js @@ -129,17 +129,24 @@ export default class Now extends EventEmitter { // array has a group of files with the same sha but different path const files = await Promise.all(Array.prototype.concat.apply([], await Promise.all((Array.from(this._files)).map(async ([sha, {data, names}]) => { return await names.map(async name => { - if (this._static && toRelative(name, this._path) !== 'package.json') { - name = this.pathInsideContent(name) - } + let mode + + if (this._static) { + if (toRelative(name, this._path) === 'package.json') { + mode = 33261 + } else { + const st = await (followSymlinks ? stat(name) : lstat(name)) + mode = st.mode - const st = await (followSymlinks ? stat(name) : lstat(name)) + name = this.pathInsideContent(name) + } + } return { sha, size: data.length, file: toRelative(name, this._path), - mode: st.mode + mode } }) })))) From c92fd09dc50e56396b5cedfc2e8f7056e5543987 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 2 Jan 2017 21:22:20 +0100 Subject: [PATCH 104/160] 0.39.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 45b06fa..8eb45a9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "0.38.0", + "version": "0.39.0", "description": "Realtime global deployments", "repository": "zeit/now-cli", "main": "./build/lib/index", From f2a4ee0adc1beacf49f8303599c905543cf1bba3 Mon Sep 17 00:00:00 2001 From: Luke Edwards Date: Tue, 3 Jan 2017 01:22:11 -0800 Subject: [PATCH 105/160] XO Happiness (#197) * Comply to rule 'no-useless-escape' * Comply to rule 'no-case-declarations' * Comply to rule 'ava/no-ignored-test-files' --- bin/now-alias.js | 15 ++++++++------- bin/now-deploy.js | 4 ++-- bin/now-domains.js | 12 ++++++------ bin/now-remove.js | 2 +- lib/git.js | 3 ++- lib/to-host.js | 2 +- package.json | 5 +---- 7 files changed, 21 insertions(+), 22 deletions(-) diff --git a/bin/now-alias.js b/bin/now-alias.js index d7a0207..4f29f88 100755 --- a/bin/now-alias.js +++ b/bin/now-alias.js @@ -120,8 +120,8 @@ async function run(token) { const args = argv._.slice(1) switch (subcommand) { - case 'list': case 'ls': + case 'list': { if (args.length !== 0) { error(`Invalid number of arguments. Usage: ${chalk.cyan('`now alias ls`')}`) return exit(1) @@ -160,9 +160,9 @@ async function run(token) { } break - - case 'remove': + } case 'rm': + case 'remove': { const _target = String(args[0]) if (!_target) { const err = new Error('No alias id specified') @@ -201,17 +201,17 @@ async function run(token) { } break - + } case 'add': - case 'set': + case 'set': { if (args.length !== 2) { error(`Invalid number of arguments. Usage: ${chalk.cyan('`now alias set `')}`) return exit(1) } await alias.set(String(args[0]), String(args[1])) break - - default: + } + default: { if (argv._.length === 0) { await realias(alias) break @@ -228,6 +228,7 @@ async function run(token) { help() exit(1) } + } } alias.close() diff --git a/bin/now-deploy.js b/bin/now-deploy.js index b440413..50a4431 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -235,7 +235,7 @@ async function sync(token) { Object.assign(gitRepo, gitParts) const searchMessage = setTimeout(() => { - console.log(`> Didn\'t find directory. Searching on ${gitRepo.type}...`) + console.log(`> Didn't find directory. Searching on ${gitRepo.type}...`) }, 500) try { @@ -416,7 +416,7 @@ async function sync(token) { if ((key in process.env)) { console.log(`> Reading ${chalk.bold(`"${chalk.bold(key)}"`)} from your env (as no value was specified)`) // escape value if it begins with @ - val = process.env[key].replace(/^\@/, '\\@') + val = process.env[key].replace(/^@/, '\\@') } else { error(`No value specified for env ${chalk.bold(`"${chalk.bold(key)}"`)} and it was not found in your env.`) return process.exit(1) diff --git a/bin/now-domains.js b/bin/now-domains.js index 7c18533..a1f58a3 100755 --- a/bin/now-domains.js +++ b/bin/now-domains.js @@ -141,7 +141,7 @@ async function run(token) { switch (subcommand) { case 'ls': - case 'list': + case 'list': { if (args.length !== 0) { error('Invalid number of arguments') return exit(1) @@ -174,9 +174,9 @@ async function run(token) { } break - + } case 'rm': - case 'remove': + case 'remove': { if (args.length !== 1) { error('Invalid number of arguments') return exit(1) @@ -214,9 +214,9 @@ async function run(token) { exit(1) } break - + } case 'add': - case 'set': + case 'set': { if (args.length !== 1) { error('Invalid number of arguments') return exit(1) @@ -238,7 +238,7 @@ async function run(token) { console.log('> Verification required: Please rerun this command after some time') } break - + } default: error('Please specify a valid subcommand: ls | add | rm') help() diff --git a/bin/now-remove.js b/bin/now-remove.js index 8abf396..df1886f 100755 --- a/bin/now-remove.js +++ b/bin/now-remove.js @@ -128,7 +128,7 @@ async function remove(token) { const matches = deployments.filter(d => { return ids.find(id => { // `url` should match the hostname of the deployment - let u = id.replace(/^https\:\/\//i, '') + let u = id.replace(/^https:\/\//i, '') if (u.indexOf('.') === -1) { // `.now.sh` domain is implied if just the subdomain is given diff --git a/lib/git.js b/lib/git.js index c80306e..dab9c05 100644 --- a/lib/git.js +++ b/lib/git.js @@ -73,10 +73,11 @@ const downloadRepo = async repoPath => { let url switch (pathParts.type) { - case 'GitLab': + case 'GitLab': { const ref = pathParts.ref ? `?ref=${pathParts.ref}` : '' url = `https://gitlab.com/${pathParts.main}/repository/archive.tar` + ref break + } case 'Bitbucket': url = `https://bitbucket.org/${pathParts.main}/get/${pathParts.ref || 'default'}.zip` break diff --git a/lib/to-host.js b/lib/to-host.js index 1737102..dbc3894 100644 --- a/lib/to-host.js +++ b/lib/to-host.js @@ -14,5 +14,5 @@ export default function toHost(url) { // remove any path if present // `a.b.c/` => `a.b.c` - return url.replace(/(\/\/)?([^\/]+)(.*)/, '$2') + return url.replace(/(\/\/)?([^/]+)(.*)/, '$2') } diff --git a/package.json b/package.json index 8eb45a9..9035fcd 100644 --- a/package.json +++ b/package.json @@ -51,14 +51,11 @@ ], "rules": { "import/no-unresolved": 0, - "ava/no-ignored-test-files": 0, "max-depth": 0, "no-use-before-define": 0, "complexity": 0, "unicorn/no-process-exit": 0, - "no-control-regex": 0, - "no-case-declarations": 0, - "no-useless-escape": 0 + "no-control-regex": 0 } }, "bin": { From 8b7d1e60ec43eb2e5d473c59cdd16bb27c069af2 Mon Sep 17 00:00:00 2001 From: Guillermo Rauch Date: Fri, 6 Jan 2017 01:15:46 -0800 Subject: [PATCH 106/160] Improve ignore semantics. (#200) * improve ignore semantics * add files accidentally ignored previously --- lib/get-files.js | 36 +++++++++++-------- .../files-overrides-gitignore/.gitignore | 2 ++ .../files-overrides-gitignore/ignore-me.js | 1 + .../files-overrides-gitignore/package.json | 6 ++++ .../files-overrides-gitignore/test.js | 1 + .../files-overrides-gitignore/test.json | 1 + .../now-files-overrides-npmignore/.npmignore | 2 ++ .../ignore-me.js | 1 + .../package.json | 8 +++++ .../now-files-overrides-npmignore/test.js | 1 + .../now-files-overrides-npmignore/test.json | 1 + test/index.js | 18 ++++++++++ 12 files changed, 64 insertions(+), 14 deletions(-) create mode 100644 test/_fixtures/files-overrides-gitignore/.gitignore create mode 100644 test/_fixtures/files-overrides-gitignore/ignore-me.js create mode 100644 test/_fixtures/files-overrides-gitignore/package.json create mode 100644 test/_fixtures/files-overrides-gitignore/test.js create mode 100644 test/_fixtures/files-overrides-gitignore/test.json create mode 100644 test/_fixtures/now-files-overrides-npmignore/.npmignore create mode 100644 test/_fixtures/now-files-overrides-npmignore/ignore-me.js create mode 100644 test/_fixtures/now-files-overrides-npmignore/package.json create mode 100644 test/_fixtures/now-files-overrides-npmignore/test.js create mode 100644 test/_fixtures/now-files-overrides-npmignore/test.json diff --git a/lib/get-files.js b/lib/get-files.js index f540558..1fb0efe 100644 --- a/lib/get-files.js +++ b/lib/get-files.js @@ -29,9 +29,6 @@ export async function npm(path, pkg, { debug = false } = {}) { const whitelist = pkg.now && pkg.now.files ? pkg.now.files : pkg.files - - // the package.json `files` whitelist still - // honors ignores: https://docs.npmjs.com/files/package.json#files const search_ = whitelist || ['.'] // always include the "main" file @@ -44,27 +41,38 @@ export async function npm(path, pkg, { // compile list of ignored patterns and files const npmIgnore = await maybeRead(resolve(path, '.npmignore'), null) + const gitIgnore = npmIgnore === null ? + await maybeRead(resolve(path, '.gitignore')) : + null const filter = ignore().add( IGNORED + '\n' + - clearRelative(npmIgnore === null ? await maybeRead(resolve(path, '.gitignore')) : npmIgnore) + clearRelative(npmIgnore === null ? gitIgnore : npmIgnore) ).createFilter() const prefixLength = path.length + 1 - const accepts = function (file) { - const relativePath = file.substr(prefixLength) - if (relativePath === '') { - return true - } + // the package.json `files` whitelist still + // honors npmignores: https://docs.npmjs.com/files/package.json#files + // but we don't ignore if the user is explicitly listing files + // under the now namespace, or using files in combination with gitignore + const overrideIgnores = (pkg.now && pkg.now.files) || (gitIgnore !== null && pkg.files) + const accepts = overrideIgnores ? + () => true : + file => { + const relativePath = file.substr(prefixLength) + + if (relativePath === '') { + return true + } - const accepted = filter(relativePath) - if (!accepted && debug) { - console.log('> [debug] ignoring "%s"', file) + const accepted = filter(relativePath) + if (!accepted && debug) { + console.log('> [debug] ignoring "%s"', file) + } + return accepted } - return accepted - } // locate files if (debug) { diff --git a/test/_fixtures/files-overrides-gitignore/.gitignore b/test/_fixtures/files-overrides-gitignore/.gitignore new file mode 100644 index 0000000..db54e80 --- /dev/null +++ b/test/_fixtures/files-overrides-gitignore/.gitignore @@ -0,0 +1,2 @@ +ignore-me.js +test.json diff --git a/test/_fixtures/files-overrides-gitignore/ignore-me.js b/test/_fixtures/files-overrides-gitignore/ignore-me.js new file mode 100644 index 0000000..36fb240 --- /dev/null +++ b/test/_fixtures/files-overrides-gitignore/ignore-me.js @@ -0,0 +1 @@ +// this should be ignored diff --git a/test/_fixtures/files-overrides-gitignore/package.json b/test/_fixtures/files-overrides-gitignore/package.json new file mode 100644 index 0000000..d7bb129 --- /dev/null +++ b/test/_fixtures/files-overrides-gitignore/package.json @@ -0,0 +1,6 @@ +{ + "files": [ + "test.js", + "test.json" + ] +} diff --git a/test/_fixtures/files-overrides-gitignore/test.js b/test/_fixtures/files-overrides-gitignore/test.js new file mode 100644 index 0000000..d08f33f --- /dev/null +++ b/test/_fixtures/files-overrides-gitignore/test.js @@ -0,0 +1 @@ +// include me diff --git a/test/_fixtures/files-overrides-gitignore/test.json b/test/_fixtures/files-overrides-gitignore/test.json new file mode 100644 index 0000000..4c82741 --- /dev/null +++ b/test/_fixtures/files-overrides-gitignore/test.json @@ -0,0 +1 @@ +{ "include": "me" } diff --git a/test/_fixtures/now-files-overrides-npmignore/.npmignore b/test/_fixtures/now-files-overrides-npmignore/.npmignore new file mode 100644 index 0000000..db54e80 --- /dev/null +++ b/test/_fixtures/now-files-overrides-npmignore/.npmignore @@ -0,0 +1,2 @@ +ignore-me.js +test.json diff --git a/test/_fixtures/now-files-overrides-npmignore/ignore-me.js b/test/_fixtures/now-files-overrides-npmignore/ignore-me.js new file mode 100644 index 0000000..36fb240 --- /dev/null +++ b/test/_fixtures/now-files-overrides-npmignore/ignore-me.js @@ -0,0 +1 @@ +// this should be ignored diff --git a/test/_fixtures/now-files-overrides-npmignore/package.json b/test/_fixtures/now-files-overrides-npmignore/package.json new file mode 100644 index 0000000..7dc492c --- /dev/null +++ b/test/_fixtures/now-files-overrides-npmignore/package.json @@ -0,0 +1,8 @@ +{ + "now": { + "files": [ + "test.js", + "test.json" + ] + } +} diff --git a/test/_fixtures/now-files-overrides-npmignore/test.js b/test/_fixtures/now-files-overrides-npmignore/test.js new file mode 100644 index 0000000..d08f33f --- /dev/null +++ b/test/_fixtures/now-files-overrides-npmignore/test.js @@ -0,0 +1 @@ +// include me diff --git a/test/_fixtures/now-files-overrides-npmignore/test.json b/test/_fixtures/now-files-overrides-npmignore/test.json new file mode 100644 index 0000000..4c82741 --- /dev/null +++ b/test/_fixtures/now-files-overrides-npmignore/test.json @@ -0,0 +1 @@ +{ "include": "me" } diff --git a/test/index.js b/test/index.js index 6554c22..c0831c9 100644 --- a/test/index.js +++ b/test/index.js @@ -43,6 +43,24 @@ test('`files` + `.*.swp` + `.npmignore`', async t => { t.is(base(files[2]), 'files-in-package-ignore/package.json') }) +test('`files` overrides `.gitignore`', async t => { + let files = await getNpmFiles(fixture('files-overrides-gitignore')) + files = files.sort(alpha) + t.is(files.length, 3) + t.is(base(files[0]), 'files-overrides-gitignore/package.json') + t.is(base(files[1]), 'files-overrides-gitignore/test.js') + t.is(base(files[2]), 'files-overrides-gitignore/test.json') +}) + +test('`now.files` overrides `.npmignore`', async t => { + let files = await getNpmFiles(fixture('now-files-overrides-npmignore')) + files = files.sort(alpha) + t.is(files.length, 3) + t.is(base(files[0]), 'now-files-overrides-npmignore/package.json') + t.is(base(files[1]), 'now-files-overrides-npmignore/test.js') + t.is(base(files[2]), 'now-files-overrides-npmignore/test.json') +}) + test('simple', async t => { let files = await getNpmFiles(fixture('simple')) files = files.sort(alpha) From f7830c1ff81fcffe578ffe45283388473184332d Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Fri, 6 Jan 2017 10:20:35 +0100 Subject: [PATCH 107/160] 0.39.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9035fcd..0dfbc0c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "0.39.0", + "version": "0.39.1", "description": "Realtime global deployments", "repository": "zeit/now-cli", "main": "./build/lib/index", From e7de9abb9ae96155b03916c5eb387fa58c9e4579 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Fri, 6 Jan 2017 22:26:09 +0100 Subject: [PATCH 108/160] Removed terminal indicators --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ba44047..99068e2 100644 --- a/README.md +++ b/README.md @@ -11,19 +11,19 @@ Realtime global deployments served over HTTP/2. You can find the FAQs [here](htt Firstly, make sure to install the package globally: ```bash -$ npm install -g now +npm install -g now ``` -Run this in any directory: +Run this command in your terminal: ```bash -$ now +now ``` For more examples, usage instructions and other commands run: ```bash -$ now help +now help ``` ## Caught a Bug? From afc329a61c0bade5e3b98b4f51b4de67bc5e6a22 Mon Sep 17 00:00:00 2001 From: Luke Morton Date: Sat, 7 Jan 2017 06:57:41 +0000 Subject: [PATCH 109/160] Multiple aliases during deploy (#202) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A small superficial change to bin/now-deploy.js so that we can specify one or more aliases whilst deploying. **Examples** ``` now --alias a.com now --alias a.com --alias b.com ``` We handle the alias assignment serially so that the CLI output makes sense. **Some thoughts** - I’m hoping this PR can close out #172 - Aware this PR likely affects #68 - This is a superficial change, really we should update the lib/alias.js to handle multiple domains --- bin/now-deploy.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 50a4431..7a57a16 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -11,6 +11,7 @@ import chalk from 'chalk' import minimist from 'minimist' import ms from 'ms' import publicSuffixList from 'psl' +import flatten from 'arr-flatten' // Ours import copy from '../lib/copy' @@ -167,7 +168,7 @@ const deploymentName = argv.name || false const apiUrl = argv.url || 'https://api.zeit.co' const isTTY = process.stdout.isTTY const quiet = !isTTY -const autoAlias = argv.alias || false +const autoAliases = argv.alias ? flatten([argv.alias]) : [] if (argv.config) { cfg.setConfigFile(argv.config) @@ -552,7 +553,7 @@ async function sync(token) { } } -const assignAlias = async (token, deployment) => { +const assignAlias = async (autoAlias, token, deployment) => { const type = publicSuffixList.isValid(autoAlias) ? 'alias' : 'uid' const aliases = new NowAlias(apiUrl, token, {debug}) @@ -586,8 +587,8 @@ function printLogs(host, token) { const logger = new Logger(host, {debug, quiet}) logger.on('close', async () => { - if (autoAlias) { - await assignAlias(token, host) + for (const autoAlias of autoAliases) { + await assignAlias(autoAlias, token, host) } if (!quiet) { From c584f4279189aa76912e1fbf9b924f95d3e01709 Mon Sep 17 00:00:00 2001 From: Luke Edwards Date: Fri, 6 Jan 2017 22:59:59 -0800 Subject: [PATCH 110/160] copy alias to clipboard & show message (#201) * copy alias to clipboard & show message * ensure status output if not ttys or cant copy --- lib/alias.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/alias.js b/lib/alias.js index 29c9034..7477713 100644 --- a/lib/alias.js +++ b/lib/alias.js @@ -1,14 +1,23 @@ // Packages import publicSuffixList from 'psl' +import minimist from 'minimist' import chalk from 'chalk' // Ours +import copy from './copy' import toHost from './to-host' import resolve4 from './dns' import isZeitWorld from './is-zeit-world' import {DOMAIN_VERIFICATION_ERROR} from './errors' import Now from './' +const argv = minimist(process.argv.slice(2), { + boolean: ['no-clipboard'], + alias: {'no-clipboard': 'C'} +}) + +const isTTY = process.stdout.isTTY +const clipboard = !argv['no-clipboard'] const domainRegex = /^((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}$/ export default class Alias extends Now { @@ -234,7 +243,21 @@ export default class Alias extends Now { } const {created, uid} = newAlias if (created) { - console.log(`${chalk.cyan('> Success!')} Alias created ${chalk.dim(`(${uid})`)}: ${chalk.bold(chalk.underline(`https://${alias}`))} now points to ${chalk.bold(`https://${depl.url}`)} ${chalk.dim(`(${depl.uid})`)}`) + const pretty = `https://${alias}` + const output = `${chalk.cyan('> Success!')} Alias created ${chalk.dim(`(${uid})`)}: ${chalk.bold(chalk.underline(pretty))} now points to ${chalk.bold(`https://${depl.url}`)} ${chalk.dim(`(${depl.uid})`)}` + if (isTTY && clipboard) { + let append + try { + await copy(pretty) + append = '[copied to clipboard]' + } catch (err) { + append = '' + } finally { + console.log(`${output} ${append}`) + } + } else { + console.log(output) + } } else { console.log(`${chalk.cyan('> Success!')} Alias already exists ${chalk.dim(`(${uid})`)}.`) } From 9a37e9deb2a2d7efea84e4097aafbb45a8097de3 Mon Sep 17 00:00:00 2001 From: Luke Edwards Date: Sat, 7 Jan 2017 11:33:56 -0800 Subject: [PATCH 111/160] insert newline into alias-success msg (#203) --- lib/alias.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/alias.js b/lib/alias.js index 7477713..abe4c49 100644 --- a/lib/alias.js +++ b/lib/alias.js @@ -244,7 +244,7 @@ export default class Alias extends Now { const {created, uid} = newAlias if (created) { const pretty = `https://${alias}` - const output = `${chalk.cyan('> Success!')} Alias created ${chalk.dim(`(${uid})`)}: ${chalk.bold(chalk.underline(pretty))} now points to ${chalk.bold(`https://${depl.url}`)} ${chalk.dim(`(${depl.uid})`)}` + const output = `${chalk.cyan('> Success!')} Alias created ${chalk.dim(`(${uid})`)}:\n${chalk.bold(chalk.underline(pretty))} now points to ${chalk.bold(`https://${depl.url}`)} ${chalk.dim(`(${depl.uid})`)}` if (isTTY && clipboard) { let append try { From 49c7ae052da36738d9964a53b2c357eb6ca127a5 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 7 Jan 2017 22:31:12 +0100 Subject: [PATCH 112/160] 1.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0dfbc0c..70c80fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "0.39.1", + "version": "1.0.0", "description": "Realtime global deployments", "repository": "zeit/now-cli", "main": "./build/lib/index", From efb8da72e73d0bf142d213042ae0bece572106fb Mon Sep 17 00:00:00 2001 From: Luke Childs Date: Sun, 8 Jan 2017 18:29:05 +0700 Subject: [PATCH 113/160] Allow shorthand aliases with `now --alias` (#206) --- bin/now-deploy.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index 7a57a16..4bcf8af 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -569,8 +569,14 @@ const assignAlias = async (autoAlias, token, deployment) => { } } - // Throw an error if it doesn't + // If alias doesn't exist if (!related) { + // Check if the uid was actually an alias + if (type === 'uid') { + return assignAlias(`${autoAlias}.now.sh`, token, deployment) + } + + // If not, throw an error const withID = type === 'uid' ? 'with ID ' : '' error(`Alias ${withID}"${autoAlias}" doesn't exist`) return From 81940de06e78199a4e74f6671520792fdd25e6b3 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sun, 8 Jan 2017 14:41:33 +0100 Subject: [PATCH 114/160] How to get a testing token --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 99068e2..69b426a 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,8 @@ now help 1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device 2. Link the package to the global module directory: `npm link` 3. Transpile the source code and watch for changes: `npm run dev` -4. You can now start using `now` from the command line! +4. Generate a [testing token](https://zeit.co/account#api-tokens) and put it into `~/.now.json` +5. You can now start using `now` from the command line! As always, you can use `npm test` to run the tests and see if your changes have broken anything. From 10fd578a51bd18d7d903e77d3a4152d0bc5849de Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sun, 8 Jan 2017 22:45:43 +0100 Subject: [PATCH 115/160] Command for usage information --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 69b426a..6d0b0d5 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,14 @@ For more examples, usage instructions and other commands run: now help ``` +## Options + +Run this command to get a list of all available commands: + +```bash +now help +``` + ## Caught a Bug? 1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device From 8c3a40b6f8f5de4827fd4a650b2a812fc99c9137 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sun, 8 Jan 2017 22:46:17 +0100 Subject: [PATCH 116/160] Options is a sub section of usage --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6d0b0d5..a7502dc 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ For more examples, usage instructions and other commands run: now help ``` -## Options +### Options Run this command to get a list of all available commands: From 29066338d8166e6c968b180ed29ecc247dccaa45 Mon Sep 17 00:00:00 2001 From: Olli Vanhoja Date: Mon, 9 Jan 2017 10:07:43 +0200 Subject: [PATCH 117/160] Fix now alias on new domains (#207) Bail if no records are found for a domain to allow adding the records. now alias derp domain.com -d > [debug] Checking for updates. > [debug] Up to date (1.0.0). > [debug] /list: 583.880ms > [debug] matched deployment derp by url derp.now.sh > domain.com is a custom domain. > Verifying the DNS settings for domain.com (see https://zeit.world for help) > [debug] #1 GET /domains/domain.com: 271.741ms > [debug] Found domain domain.com with verified:true > [debug] No records found for "domain.com" > Verification OK! --- lib/alias.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/alias.js b/lib/alias.js index abe4c49..76944f0 100644 --- a/lib/alias.js +++ b/lib/alias.js @@ -413,9 +413,12 @@ export default class Alias extends Now { if (this._debug) { console.log(`> [debug] No records found for "${domain}"`) } - } else { - throw err + + const err = new Error(DOMAIN_VERIFICATION_ERROR) + err.userError = true + return bail(err) } + throw err } if (ips.length <= 0) { From 75de2865d694f495359f018bf5e0a76457f49dea Mon Sep 17 00:00:00 2001 From: Greenkeeper Date: Tue, 10 Jan 2017 09:28:08 +0100 Subject: [PATCH 118/160] chore(package): update ora to version 0.4.1 (#210) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 70c80fb..bb62b67 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "ms": "0.7.2", "node-fetch": "1.6.3", "node-version": "1.0.0", - "ora": "0.4.0", + "ora": "0.4.1", "progress": "1.1.8", "psl": "1.1.15", "resumer": "0.0.0", From 059918e7ee9ac55b6d074866a21a351c766a47e8 Mon Sep 17 00:00:00 2001 From: Jarmo Isotalo Date: Tue, 10 Jan 2017 12:21:53 +0200 Subject: [PATCH 119/160] Remove babel as dependecy (#209) * Remove babel as a dependency * Migrate from import foo from foo to const foo = require('foo') * Update module.exports * Update commander syntax * Update pkg config and fix stuff * Make XO happy * Fix path in tests * Fix typo * Fix cleanup * Debug pkg * Fix pkg * Fix process.argv for subcommands * Run with --harmony-async-await when supported thx igor for help with this trick :D * Use bash * Set engines.node in package.json --- bin/{now.js => now} | 34 ++++++++++---------- bin/{now-alias.js => now-alias} | 26 ++++++++-------- bin/{now-certs.js => now-certs} | 26 ++++++++-------- bin/{now-deploy.js => now-deploy} | 48 +++++++++++++++-------------- bin/{now-dns.js => now-dns} | 24 ++++++++------- bin/{now-domains.js => now-domains} | 24 ++++++++------- bin/{now-list.js => now-list} | 27 ++++++++-------- bin/{now-remove.js => now-remove} | 20 ++++++------ bin/{now-secrets.js => now-secrets} | 22 +++++++------ gulpfile.babel.js | 34 -------------------- lib/agent.js | 8 ++--- lib/alias.js | 20 ++++++------ lib/build-logger.js | 10 +++--- lib/certs.js | 4 +-- lib/cfg.js | 18 +++++++---- lib/check-update.js | 14 +++++---- lib/copy.js | 6 ++-- lib/dns.js | 5 +-- lib/domain-records.js | 4 +-- lib/domains.js | 10 +++--- lib/error.js | 13 +++++--- lib/errors.js | 11 +++++-- lib/get-files.js | 23 ++++++++------ lib/git.js | 26 ++++++++++------ lib/hash.js | 10 +++--- lib/ignored.js | 2 +- lib/indent.js | 4 ++- lib/index.js | 32 +++++++++---------- lib/is-zeit-world.js | 4 ++- lib/login.js | 22 ++++++------- lib/read-metadata.js | 10 +++--- lib/secrets.js | 4 +-- lib/strlen.js | 4 ++- lib/test.js | 4 +-- lib/to-host.js | 6 ++-- lib/ua.js | 6 ++-- lib/utils/check-path.js | 10 +++--- lib/utils/prompt-options.js | 4 +-- lib/utils/to-human-path.js | 8 +++-- package.json | 39 +++++++---------------- test/args-parsing.js | 8 ++--- test/index.js | 12 ++++---- test/to-host.js | 4 +-- 43 files changed, 331 insertions(+), 319 deletions(-) rename bin/{now.js => now} (71%) rename bin/{now-alias.js => now-alias} (94%) rename bin/{now-certs.js => now-certs} (94%) rename bin/{now-deploy.js => now-deploy} (94%) rename bin/{now-dns.js => now-dns} (92%) rename bin/{now-domains.js => now-domains} (95%) rename bin/{now-list.js => now-list} (86%) rename bin/{now-remove.js => now-remove} (92%) rename bin/{now-secrets.js => now-secrets} (94%) delete mode 100644 gulpfile.babel.js diff --git a/bin/now.js b/bin/now similarity index 71% rename from bin/now.js rename to bin/now index cbcd118..dd668da 100755 --- a/bin/now.js +++ b/bin/now @@ -1,16 +1,22 @@ -#!/usr/bin/env node +#!/bin/bash +// >&/dev/null; exec node $(node -p "process.version[1] >= 7 ? '--harmony-async-await' : '--lazy'") $0 $@ // Native -import {resolve} from 'path' +const {resolve} = require('path') // Packages -import minimist from 'minimist' -import {spawn} from 'cross-spawn' -import nodeVersion from 'node-version' +const minimist = require('minimist') +const {spawn} = require('cross-spawn') +const nodeVersion = require('node-version') +const isAsyncSupported = require('is-async-supported') +if (!isAsyncSupported()) { + require('async-to-gen/register') +} // Ours -import checkUpdate from '../lib/check-update' -import {error} from '../lib/error' +const checkUpdate = require('../lib/check-update') +const {error} = require('../lib/error') + if (nodeVersion.major < 6) { error('Now requires at least version 6 of Node. Please upgrade!') @@ -94,15 +100,9 @@ if (index > -1) { } let bin = resolve(__dirname, 'now-' + cmd) -if (process.pkg) { - args.unshift('--entrypoint', bin) - bin = process.execPath -} -const proc = spawn(bin, args, { - stdio: 'inherit', - customFds: [0, 1, 2] -}) +// Prepare process.argv for subcommand +process.argv = process.argv.slice(0, 2).concat(args); +require(bin) -proc.on('close', code => exit(code)) -proc.on('error', () => exit(1)) +// vi:syntax=javascript diff --git a/bin/now-alias.js b/bin/now-alias similarity index 94% rename from bin/now-alias.js rename to bin/now-alias index 4f29f88..c9f4fc4 100755 --- a/bin/now-alias.js +++ b/bin/now-alias @@ -1,19 +1,19 @@ -#!/usr/bin/env node +#!/usr/bin/env node --harmony-async-await // Packages -import chalk from 'chalk' -import minimist from 'minimist' -import table from 'text-table' -import ms from 'ms' +const chalk = require('chalk') +const minimist = require('minimist') +const table = require('text-table') +const ms = require('ms') // Ours -import strlen from '../lib/strlen' -import NowAlias from '../lib/alias' -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 strlen = require('../lib/strlen') +const NowAlias = require('../lib/alias') +const login = require('../lib/login') +const cfg = require('../lib/cfg') +const {error} = require('../lib/error') +const toHost = require('../lib/to-host') +const readMetaData = require('../lib/read-metadata') const argv = minimist(process.argv.slice(2), { string: ['config', 'token'], @@ -314,3 +314,5 @@ async function realias(alias) { await alias.set(source.url, target) } + +// vi:syntax=javascript diff --git a/bin/now-certs.js b/bin/now-certs similarity index 94% rename from bin/now-certs.js rename to bin/now-certs index 134b89d..fd9b1cc 100755 --- a/bin/now-certs.js +++ b/bin/now-certs @@ -1,21 +1,21 @@ -#!/usr/bin/env node +#!/usr/bin/env node --harmony-async-await // Native -import path from 'path' +const path = require('path') // Packages -import chalk from 'chalk' -import table from 'text-table' -import minimist from 'minimist' -import fs from 'fs-promise' -import ms from 'ms' +const chalk = require('chalk') +const table = require('text-table') +const minimist = require('minimist') +const fs = require('fs-promise') +const ms = require('ms') // Ours -import strlen from '../lib/strlen' -import * as cfg from '../lib/cfg' -import {handleError, error} from '../lib/error' -import NowCerts from '../lib/certs' -import login from '../lib/login' +const strlen = require('../lib/strlen') +const cfg = require('../lib/cfg') +const {handleError, error} = require('../lib/error') +const NowCerts = require('../lib/certs') +const login = require('../lib/login') const argv = minimist(process.argv.slice(2), { string: ['config', 'token', 'crt', 'key', 'ca'], @@ -291,3 +291,5 @@ async function getCertIdCn(certs, idOrCn) { return thecert } + +// vi:syntax=javascript diff --git a/bin/now-deploy.js b/bin/now-deploy similarity index 94% rename from bin/now-deploy.js rename to bin/now-deploy index 4bcf8af..decaad1 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy @@ -1,32 +1,32 @@ -#!/usr/bin/env node +#!/usr/bin/env node --harmony-async-await // Native -import {resolve} from 'path' +const {resolve} = require('path') // Packages -import Progress from 'progress' -import fs from 'fs-promise' -import bytes from 'bytes' -import chalk from 'chalk' -import minimist from 'minimist' -import ms from 'ms' -import publicSuffixList from 'psl' -import flatten from 'arr-flatten' +const Progress = require('progress') +const fs = require('fs-promise') +const bytes = require('bytes') +const chalk = require('chalk') +const minimist = require('minimist') +const ms = require('ms') +const publicSuffixList = require('psl') +const flatten = require('arr-flatten') // Ours -import copy from '../lib/copy' -import login from '../lib/login' -import * as cfg from '../lib/cfg' -import {version} from '../../package' -import Logger from '../lib/build-logger' -import Now from '../lib' -import toHumanPath from '../lib/utils/to-human-path' -import promptOptions from '../lib/utils/prompt-options' -import {handleError, error} from '../lib/error' -import {fromGit, isRepoPath, gitPathParts} from '../lib/git' -import readMetaData from '../lib/read-metadata' -import checkPath from '../lib/utils/check-path' -import NowAlias from '../lib/alias' +const copy = require('../lib/copy') +const login = require('../lib/login') +const cfg = require('../lib/cfg') +const {version} = require('../package') +const Logger = require('../lib/build-logger') +const Now = require('../lib') +const toHumanPath = require('../lib/utils/to-human-path') +const promptOptions = require('../lib/utils/prompt-options') +const {handleError, error} = require('../lib/error') +const {fromGit, isRepoPath, gitPathParts} = require('../lib/git') +const readMetaData = require('../lib/read-metadata') +const checkPath = require('../lib/utils/check-path') +const NowAlias = require('../lib/alias') const argv = minimist(process.argv.slice(2), { string: [ @@ -613,3 +613,5 @@ function printLogs(host, token) { process.exit(0) }) } + +// vi:syntax=javascript diff --git a/bin/now-dns.js b/bin/now-dns similarity index 92% rename from bin/now-dns.js rename to bin/now-dns index d0bf613..04b72af 100755 --- a/bin/now-dns.js +++ b/bin/now-dns @@ -1,18 +1,18 @@ -#!/usr/bin/env node +#!/usr/bin/env node --harmony-async-await // Packages -import chalk from 'chalk' -import minimist from 'minimist' -import ms from 'ms' -import table from 'text-table' +const chalk = require('chalk') +const minimist = require('minimist') +const ms = require('ms') +const table = require('text-table') // Ours -import * as cfg from '../lib/cfg' -import DomainRecords from '../lib/domain-records' -import indent from '../lib/indent' -import login from '../lib/login' -import strlen from '../lib/strlen' -import {handleError, error} from '../lib/error' +const cfg = require('../lib/cfg') +const DomainRecords = require('../lib/domain-records') +const indent = require('../lib/indent') +const login = require('../lib/login') +const strlen = require('../lib/strlen') +const {handleError, error} = require('../lib/error') const argv = minimist(process.argv.slice(2), { string: ['config'], @@ -200,3 +200,5 @@ function readConfirmation(record, msg) { }).resume() }) } + +// vi:syntax=javascript diff --git a/bin/now-domains.js b/bin/now-domains similarity index 95% rename from bin/now-domains.js rename to bin/now-domains index a1f58a3..277e552 100755 --- a/bin/now-domains.js +++ b/bin/now-domains @@ -1,18 +1,18 @@ -#!/usr/bin/env node +#!/usr/bin/env node --harmony-async-await // Packages -import chalk from 'chalk' -import minimist from 'minimist' -import table from 'text-table' -import ms from 'ms' +const chalk = require('chalk') +const minimist = require('minimist') +const table = require('text-table') +const ms = require('ms') // Ours -import login from '../lib/login' -import * as cfg from '../lib/cfg' -import {error} from '../lib/error' -import toHost from '../lib/to-host' -import strlen from '../lib/strlen' -import NowDomains from '../lib/domains' +const login = require('../lib/login') +const cfg = require('../lib/cfg') +const {error} = require('../lib/error') +const toHost = require('../lib/to-host') +const strlen = require('../lib/strlen') +const NowDomains = require('../lib/domains') const argv = minimist(process.argv.slice(2), { string: ['config', 'token'], @@ -296,3 +296,5 @@ function findDomain(val, list) { return false }) } + +// vi:syntax=javascript diff --git a/bin/now-list.js b/bin/now-list similarity index 86% rename from bin/now-list.js rename to bin/now-list index ca2a7ff..5069197 100755 --- a/bin/now-list.js +++ b/bin/now-list @@ -1,19 +1,20 @@ -#!/usr/bin/env node +#!/usr/bin/env node --harmony-async-await + // Packages -import fs from 'fs-promise' -import minimist from 'minimist' -import chalk from 'chalk' -import table from 'text-table' -import ms from 'ms' +const fs = require('fs-promise') +const minimist = require('minimist') +const chalk = require('chalk') +const table = require('text-table') +const ms = require('ms') // Ours -import strlen from '../lib/strlen' -import indent from '../lib/indent' -import Now from '../lib' -import login from '../lib/login' -import * as cfg from '../lib/cfg' -import {handleError, error} from '../lib/error' +const strlen = require('../lib/strlen') +const indent = require('../lib/indent') +const Now = require('../lib') +const login = require('../lib/login') +const cfg = require('../lib/cfg') +const {handleError, error} = require('../lib/error') const argv = minimist(process.argv.slice(2), { string: ['config', 'token'], @@ -151,3 +152,5 @@ async function sort(apps) { return depsB[0].created - depsA[0].created }) } + +// vi:syntax=javascript diff --git a/bin/now-remove.js b/bin/now-remove similarity index 92% rename from bin/now-remove.js rename to bin/now-remove index df1886f..816f84c 100755 --- a/bin/now-remove.js +++ b/bin/now-remove @@ -1,16 +1,16 @@ -#!/usr/bin/env node +#!/usr/bin/env node --harmony-async-await // Packages -import minimist from 'minimist' -import chalk from 'chalk' -import ms from 'ms' -import table from 'text-table' +const minimist = require('minimist') +const chalk = require('chalk') +const ms = require('ms') +const table = require('text-table') // Ours -import Now from '../lib' -import login from '../lib/login' -import * as cfg from '../lib/cfg' -import {handleError, error} from '../lib/error' +const Now = require('../lib') +const login = require('../lib/login') +const cfg = require('../lib/cfg') +const {handleError, error} = require('../lib/error') const argv = minimist(process.argv.slice(2), { string: ['config', 'token'], @@ -175,3 +175,5 @@ async function remove(token) { now.close() } + +// vi:syntax=javascript diff --git a/bin/now-secrets.js b/bin/now-secrets similarity index 94% rename from bin/now-secrets.js rename to bin/now-secrets index 7060c98..280c6f9 100755 --- a/bin/now-secrets.js +++ b/bin/now-secrets @@ -1,17 +1,17 @@ -#!/usr/bin/env node +#!/usr/bin/env node --harmony-async-await // Packages -import chalk from 'chalk' -import table from 'text-table' -import minimist from 'minimist' -import ms from 'ms' +const chalk = require('chalk') +const table = require('text-table') +const minimist = require('minimist') +const ms = require('ms') // Ours -import strlen from '../lib/strlen' -import * as cfg from '../lib/cfg' -import {handleError, error} from '../lib/error' -import NowSecrets from '../lib/secrets' -import login from '../lib/login' +const strlen = require('../lib/strlen') +const cfg = require('../lib/cfg') +const {handleError, error} = require('../lib/error') +const NowSecrets = require('../lib/secrets') +const login = require('../lib/login') const argv = minimist(process.argv.slice(2), { string: ['config', 'token'], @@ -237,3 +237,5 @@ function readConfirmation(secret) { }).resume() }) } + +// vi:syntax=javascript diff --git a/gulpfile.babel.js b/gulpfile.babel.js deleted file mode 100644 index 3f35ac2..0000000 --- a/gulpfile.babel.js +++ /dev/null @@ -1,34 +0,0 @@ -// Packages -import gulp from 'gulp' -import del from 'del' -import babel from 'gulp-babel' -import help from 'gulp-task-listing' -import {crop as cropExt} from 'gulp-ext' -import cache from 'gulp-cached' - -gulp.task('help', help) - -gulp.task('compile', [ - 'compile-lib', - 'compile-bin' -]) - -gulp.task('compile-lib', () => - gulp.src('lib/**/*.js') - .pipe(cache('lib')) - .pipe(babel()) - .pipe(gulp.dest('build/lib'))) - -gulp.task('compile-bin', () => - gulp.src('bin/*') - .pipe(cache('bin')) - .pipe(babel()) - .pipe(cropExt()) - .pipe(gulp.dest('build/bin'))) - -gulp.task('watch-lib', () => gulp.watch('lib/**/*.js', ['compile-lib'])) -gulp.task('watch-bin', () => gulp.watch('bin/*', ['compile-bin'])) -gulp.task('clean', () => del(['build'])) - -gulp.task('watch', ['watch-lib', 'watch-bin']) -gulp.task('default', ['compile', 'watch']) diff --git a/lib/agent.js b/lib/agent.js index 17f6fb3..7b03011 100644 --- a/lib/agent.js +++ b/lib/agent.js @@ -1,7 +1,7 @@ // Packages -import {parse} from 'url' -import http2 from 'spdy' -import fetch from 'node-fetch' +const {parse} = require('url') +const http2 = require('spdy') +const fetch = require('node-fetch') /** * Returns a `fetch` version with a similar @@ -14,7 +14,7 @@ import fetch from 'node-fetch' * @return {Function} fetch */ -export default class Agent { +module.exports = class Agent { constructor(url, {tls = true, debug} = {}) { this._url = url const parsed = parse(url) diff --git a/lib/alias.js b/lib/alias.js index 76944f0..51d9ce3 100644 --- a/lib/alias.js +++ b/lib/alias.js @@ -1,15 +1,15 @@ // Packages -import publicSuffixList from 'psl' -import minimist from 'minimist' -import chalk from 'chalk' +const publicSuffixList = require('psl') +const minimist = require('minimist') +const chalk = require('chalk') // Ours -import copy from './copy' -import toHost from './to-host' -import resolve4 from './dns' -import isZeitWorld from './is-zeit-world' -import {DOMAIN_VERIFICATION_ERROR} from './errors' -import Now from './' +const copy = require('./copy') +const toHost = require('./to-host') +const resolve4 = require('./dns') +const isZeitWorld = require('./is-zeit-world') +const {DOMAIN_VERIFICATION_ERROR} = require('./errors') +const Now = require('./') const argv = minimist(process.argv.slice(2), { boolean: ['no-clipboard'], @@ -20,7 +20,7 @@ const isTTY = process.stdout.isTTY const clipboard = !argv['no-clipboard'] const domainRegex = /^((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}$/ -export default class Alias extends Now { +module.exports = class Alias extends Now { async ls(deployment) { if (deployment) { diff --git a/lib/build-logger.js b/lib/build-logger.js index 6f8fdfe..81c2cb3 100644 --- a/lib/build-logger.js +++ b/lib/build-logger.js @@ -1,10 +1,10 @@ // Native -import EventEmitter from 'events' +const EventEmitter = require('events') // Packages -import ansi from 'ansi-escapes' -import io from 'socket.io-client' -import chalk from 'chalk' +const ansi = require('ansi-escapes') +const io = require('socket.io-client') +const chalk = require('chalk') class Lines { constructor(maxLines = 100) { @@ -30,7 +30,7 @@ class Lines { } } -export default class Logger extends EventEmitter { +module.exports = class Logger extends EventEmitter { constructor(host, {debug = false, quiet = false} = {}) { super() this.host = host diff --git a/lib/certs.js b/lib/certs.js index 2646fa9..46d78ed 100644 --- a/lib/certs.js +++ b/lib/certs.js @@ -1,7 +1,7 @@ // Ours -import Now from '../lib' +const Now = require('../lib') -export default class Certs extends Now { +module.exports = class Certs extends Now { ls() { return this.retry(async (bail, attempt) => { diff --git a/lib/cfg.js b/lib/cfg.js index c238730..781be23 100644 --- a/lib/cfg.js +++ b/lib/cfg.js @@ -1,17 +1,17 @@ // Native -import {homedir} from 'os' -import path from 'path' +const {homedir} = require('os') +const path = require('path') // Packages -import fs from 'fs-promise' +const fs = require('fs-promise') let file = process.env.NOW_JSON ? path.resolve(process.env.NOW_JSON) : path.resolve(homedir(), '.now.json') -export function setConfigFile(nowjson) { +function setConfigFile(nowjson) { file = path.resolve(nowjson) } -export function read() { +function read() { let existing = null try { existing = fs.readFileSync(file, 'utf8') @@ -28,7 +28,13 @@ export function read() { * @param {Object} data */ -export function merge(data) { +function merge(data) { const cfg = Object.assign({}, read(), data) fs.writeFileSync(file, JSON.stringify(cfg, null, 2)) } + +module.exports = { + setConfigFile, + read, + merge +} diff --git a/lib/check-update.js b/lib/check-update.js index 23c6579..1c6afd9 100644 --- a/lib/check-update.js +++ b/lib/check-update.js @@ -1,11 +1,11 @@ // Packages -import ms from 'ms' -import fetch from 'node-fetch' -import chalk from 'chalk' -import compare from 'semver-compare' +const ms = require('ms') +const fetch = require('node-fetch') +const chalk = require('chalk') +const compare = require('semver-compare') // Ours -import pkg from '../../package' +const pkg = require('../package') const isTTY = process.stdout.isTTY @@ -18,7 +18,7 @@ const resolvedPromise = new Promise(resolve => resolve()) * Sets up a `exit` listener to report them. */ -export default function checkUpdate(opts = {}) { +function checkUpdate(opts = {}) { if (!isTTY) { // don't attempt to check for updates // if the user is piping or redirecting @@ -93,3 +93,5 @@ function check({debug = false}) { }, () => resolve(false)) }) } + +module.exports = checkUpdate diff --git a/lib/copy.js b/lib/copy.js index 0d7eb87..63f3b22 100644 --- a/lib/copy.js +++ b/lib/copy.js @@ -1,7 +1,7 @@ // Packages -import {copy as _copy} from 'copy-paste' +const {copy: _copy} = require('copy-paste') -export default function copy(text) { +function copy(text) { return new Promise((resolve, reject) => { _copy(text, err => { if (err) { @@ -12,3 +12,5 @@ export default function copy(text) { }) }) } + +module.exports = copy diff --git a/lib/dns.js b/lib/dns.js index 16a3345..124840a 100644 --- a/lib/dns.js +++ b/lib/dns.js @@ -1,7 +1,7 @@ // Packages -import dns from 'dns' +const dns = require('dns') -export default function resolve4(host) { +function resolve4(host) { return new Promise((resolve, reject) => { return dns.resolve4(host, (err, answer) => { if (err) { @@ -12,3 +12,4 @@ export default function resolve4(host) { }) }) } +module.exports = resolve4 diff --git a/lib/domain-records.js b/lib/domain-records.js index 3d76524..fbc14f1 100644 --- a/lib/domain-records.js +++ b/lib/domain-records.js @@ -1,7 +1,7 @@ // Ours -import Now from '../lib' +const Now = require('../lib') -export default class DomainRecords extends Now { +module.exports = class DomainRecords extends Now { async getRecord(id) { const all = (await this.ls()).entries() diff --git a/lib/domains.js b/lib/domains.js index 39a997c..921da36 100644 --- a/lib/domains.js +++ b/lib/domains.js @@ -1,14 +1,14 @@ // Packages -import chalk from 'chalk' +const chalk = require('chalk') // Ours -import Now from '../lib' -import isZeitWorld from './is-zeit-world' -import {DNS_VERIFICATION_ERROR} from './errors' +const Now = require('../lib') +const isZeitWorld = require('./is-zeit-world') +const {DNS_VERIFICATION_ERROR} = require('./errors') const domainRegex = /^((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}$/ -export default class Domains extends Now { +module.exports = class Domains extends Now { async ls() { return await this.listDomains() diff --git a/lib/error.js b/lib/error.js index 9153d46..6fc7c59 100644 --- a/lib/error.js +++ b/lib/error.js @@ -1,8 +1,8 @@ // Packages -import ms from 'ms' -import chalk from 'chalk' +const ms = require('ms') +const chalk = require('chalk') -export function handleError(err) { +function handleError(err) { if (err.status === 403) { error('Authentication error. Run `now -L` or `now --login` to log-in again.') } else if (err.status === 429) { @@ -22,6 +22,11 @@ export function handleError(err) { } } -export function error(err) { +function error(err) { console.error(`> ${chalk.red('Error!')} ${err}`) } + +module.exports = { + handleError, + error +} diff --git a/lib/errors.js b/lib/errors.js index 40d1ea7..78ef0f2 100644 --- a/lib/errors.js +++ b/lib/errors.js @@ -1,12 +1,17 @@ // Packages -import chalk from 'chalk' +const chalk = require('chalk') -export const DNS_VERIFICATION_ERROR = `Please make sure that your nameservers point to ${chalk.underline('zeit.world')}. +const DNS_VERIFICATION_ERROR = `Please make sure that your nameservers point to ${chalk.underline('zeit.world')}. > Examples: (full list at ${chalk.underline('https://zeit.world')}) > ${chalk.gray('-')} ${chalk.underline('california.zeit.world')} ${chalk.dim('173.255.215.107')} > ${chalk.gray('-')} ${chalk.underline('newark.zeit.world')} ${chalk.dim('173.255.231.87')} > ${chalk.gray('-')} ${chalk.underline('london.zeit.world')} ${chalk.dim('178.62.47.76')} > ${chalk.gray('-')} ${chalk.underline('singapore.zeit.world')} ${chalk.dim('119.81.97.170')}` -export const DOMAIN_VERIFICATION_ERROR = DNS_VERIFICATION_ERROR + +const DOMAIN_VERIFICATION_ERROR = DNS_VERIFICATION_ERROR + `\n> Alternatively, ensure it resolves to ${chalk.underline('alias.zeit.co')} via ${chalk.dim('CNAME')} / ${chalk.dim('ALIAS')}.` + +module.exports = { + DNS_VERIFICATION_ERROR, + DOMAIN_VERIFICATION_ERROR +} diff --git a/lib/get-files.js b/lib/get-files.js index 1fb0efe..5df34a1 100644 --- a/lib/get-files.js +++ b/lib/get-files.js @@ -1,15 +1,15 @@ // Native -import {resolve} from 'path' +const {resolve} = require('path') // Packages -import flatten from 'arr-flatten' -import unique from 'array-unique' -import ignore from 'ignore' -import _glob from 'glob' -import {stat, readdir, readFile} from 'fs-promise' +const flatten = require('arr-flatten') +const unique = require('array-unique') +const ignore = require('ignore') +const _glob = require('glob') +const {stat, readdir, readFile} = require('fs-promise') // Ours -import IGNORED from './ignored' +const IGNORED = require('./ignored') /** * Returns a list of files in the given @@ -24,7 +24,7 @@ import IGNORED from './ignored' * @return {Array} comprehensive list of paths to sync */ -export async function npm(path, pkg, { +async function npm(path, pkg, { limit = null, debug = false } = {}) { @@ -126,7 +126,7 @@ const asAbsolute = function (path, parent) { * @return {Array} comprehensive list of paths to sync */ -export async function docker(path, { +async function docker(path, { limit = null, debug = false } = {}) { @@ -273,3 +273,8 @@ const maybeRead = async function (path, default_ = '') { const clearRelative = function (str) { return str.replace(/(\n|^)\.\//g, '$1') } + +module.exports = { + npm, + docker +} diff --git a/lib/git.js b/lib/git.js index dab9c05..4ef6337 100644 --- a/lib/git.js +++ b/lib/git.js @@ -1,13 +1,13 @@ // Native -import path from 'path' -import url from 'url' -import childProcess from 'child_process' +const path = require('path') +const url = require('url') +const childProcess = require('child_process') // Packages -import fs from 'fs-promise' -import download from 'download' -import tmp from 'tmp-promise' -import isURL from 'is-url' +const fs = require('fs-promise') +const download = require('download') +const tmp = require('tmp-promise') +const isURL = require('is-url') const cloneRepo = (parts, tmpDir) => new Promise((resolve, reject) => { let host @@ -143,7 +143,7 @@ const splittedURL = fullURL => { } } -export const gitPathParts = main => { +const gitPathParts = main => { let ref = '' if (isURL(main)) { @@ -164,7 +164,7 @@ export const gitPathParts = main => { } } -export const isRepoPath = path => { +const isRepoPath = path => { if (!path) { return false } @@ -190,7 +190,7 @@ export const isRepoPath = path => { return /[^\s\\]\/[^\s\\]/g.test(path) } -export const fromGit = async (path, debug) => { +const fromGit = async (path, debug) => { let tmpDir = false try { @@ -203,3 +203,9 @@ export const fromGit = async (path, debug) => { return tmpDir } + +module.exports = { + gitPathParts, + isRepoPath, + fromGit +} diff --git a/lib/hash.js b/lib/hash.js index ef625f0..9cd1cab 100644 --- a/lib/hash.js +++ b/lib/hash.js @@ -1,9 +1,9 @@ // Native -import {createHash} from 'crypto' -import path from 'path' +const {createHash} = require('crypto') +const path = require('path') // Packages -import {readFile} from 'fs-promise' +const {readFile} = require('fs-promise') /** * Computes hashes for the contents of each file given. @@ -12,7 +12,7 @@ import {readFile} from 'fs-promise' * @return {Map} */ -export default async function hashes(files, isStatic, pkg) { +async function hashes(files, isStatic, pkg) { const map = new Map() await Promise.all(files.map(async name => { @@ -49,3 +49,5 @@ function hash(buf) { .update(buf) .digest('hex') } + +module.exports = hashes diff --git a/lib/ignored.js b/lib/ignored.js index be110fd..b623513 100644 --- a/lib/ignored.js +++ b/lib/ignored.js @@ -1,6 +1,6 @@ // base `.gitignore` to which we add entries // supplied by the user -export default `.hg +module.exports = `.hg .git .gitmodules .svn diff --git a/lib/indent.js b/lib/indent.js index a1fa3be..f934288 100644 --- a/lib/indent.js +++ b/lib/indent.js @@ -1,3 +1,5 @@ -export default function indent(text, n) { +function indent(text, n) { return text.split('\n').map(l => ' '.repeat(n) + l).join('\n') } + +module.exports = indent diff --git a/lib/index.js b/lib/index.js index c1072fb..5908a97 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,23 +1,23 @@ // Native -import {homedir} from 'os' -import {resolve as resolvePath, join as joinPaths} from 'path' -import EventEmitter from 'events' +const {homedir} = require('os') +const {resolve: resolvePath, join: joinPaths} = require('path') +const EventEmitter = require('events') // Packages -import bytes from 'bytes' -import chalk from 'chalk' -import resumer from 'resumer' -import retry from 'async-retry' -import splitArray from 'split-array' -import {parse as parseIni} from 'ini' -import {readFile, stat, lstat} from 'fs-promise' +const bytes = require('bytes') +const chalk = require('chalk') +const resumer = require('resumer') +const retry = require('async-retry').default +const splitArray = require('split-array') +const {parse: parseIni} = require('ini') +const {readFile, stat, lstat} = require('fs-promise') // 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' +const {npm: getNpmFiles, docker: getDockerFiles} = require('./get-files') +const ua = require('./ua') +const hash = require('./hash') +const Agent = require('./agent') +const readMetaData = require('./read-metadata') // how many concurrent HTTP/2 stream uploads const MAX_CONCURRENT = 10 @@ -26,7 +26,7 @@ const MAX_CONCURRENT = 10 const IS_WIN = /^win/.test(process.platform) const SEP = IS_WIN ? '\\' : '/' -export default class Now extends EventEmitter { +module.exports = class Now extends EventEmitter { constructor(url, token, {forceNew = false, debug = false}) { super() this._token = token diff --git a/lib/is-zeit-world.js b/lib/is-zeit-world.js index 51290a8..d40ef43 100644 --- a/lib/is-zeit-world.js +++ b/lib/is-zeit-world.js @@ -20,8 +20,10 @@ const nameservers = new Set([ * by `resolveNs` from Node, assert that they're * zeit.world's. */ -export default function isZeitWorld(ns) { +function isZeitWorld(ns) { return ns.length > 1 && ns.every(host => { return nameservers.has(host) }) } + +module.exports = isZeitWorld diff --git a/lib/login.js b/lib/login.js index 875f7ae..f34653b 100644 --- a/lib/login.js +++ b/lib/login.js @@ -1,18 +1,18 @@ // Native -import os from 'os' +const os = require('os') // Packages -import {stringify as stringifyQuery} from 'querystring' -import chalk from 'chalk' -import fetch from 'node-fetch' -import {validate} from 'email-validator' -import readEmail from 'email-prompt' -import ora from 'ora' +const {stringify: stringifyQuery} = require('querystring') +const chalk = require('chalk') +const fetch = require('node-fetch') +const {validate} = require('email-validator') +const readEmail = require('email-prompt') +const ora = require('ora') // Ours -import pkg from '../../package' -import ua from './ua' -import * as cfg from './cfg' +const pkg = require('../package') +const ua = require('./ua') +const cfg = require('./cfg') async function getVerificationData(url, email) { const tokenName = `Now CLI ${os.platform()}-${os.arch()} ${pkg.version} (${os.hostname()})` @@ -94,7 +94,7 @@ async function register(url, {retryEmail = false} = {}) { return {email, token: final} } -export default async function (url) { +module.exports = async function (url) { const loginData = await register(url) cfg.merge(loginData) return loginData.token diff --git a/lib/read-metadata.js b/lib/read-metadata.js index eaa3eb8..03c12e5 100644 --- a/lib/read-metadata.js +++ b/lib/read-metadata.js @@ -1,7 +1,7 @@ -import {basename, resolve as resolvePath} from 'path' -import chalk from 'chalk' -import {readFile} from 'fs-promise' -import {parse as parseDockerfile} from 'docker-file-parser' +const {basename, resolve: resolvePath} = require('path') +const chalk = require('chalk') +const {readFile} = require('fs-promise') +const {parse: parseDockerfile} = require('docker-file-parser') const listPackage = { version: '0.0.0', @@ -13,7 +13,7 @@ const listPackage = { } } -export default async function (path, { +module.exports = async function (path, { deploymentType = 'npm', deploymentName, quiet = false, diff --git a/lib/secrets.js b/lib/secrets.js index 9b5105e..6b0451d 100644 --- a/lib/secrets.js +++ b/lib/secrets.js @@ -1,7 +1,7 @@ // Ours -import Now from '../lib' +const Now = require('../lib') -export default class Secrets extends Now { +module.exports = class Secrets extends Now { ls() { return this.listSecrets() } diff --git a/lib/strlen.js b/lib/strlen.js index 1817bea..1080706 100644 --- a/lib/strlen.js +++ b/lib/strlen.js @@ -1,3 +1,5 @@ -export default function strlen(str) { +function strlen(str) { return str.replace(/\x1b[^m]*m/g, '').length } + +module.exports = strlen diff --git a/lib/test.js b/lib/test.js index f9f0658..fae66c5 100644 --- a/lib/test.js +++ b/lib/test.js @@ -1,8 +1,8 @@ // Native -import {resolve} from 'path' +const {resolve} = require('path') // Ours -import {npm as getFiles} from './get-files' +const {npm: getFiles} = require('./get-files') getFiles(resolve('../mng-test/files-in-package')) .then(files => { diff --git a/lib/to-host.js b/lib/to-host.js index dbc3894..daae30a 100644 --- a/lib/to-host.js +++ b/lib/to-host.js @@ -1,5 +1,5 @@ // Native -import {parse} from 'url' +const {parse} = require('url') /** * Converts a valid deployment lookup parameter to a hostname. @@ -7,7 +7,7 @@ import {parse} from 'url' * google.com => google.com */ -export default function toHost(url) { +function toHost(url) { if (/^https?:\/\//.test(url)) { return parse(url).host } @@ -16,3 +16,5 @@ export default function toHost(url) { // `a.b.c/` => `a.b.c` return url.replace(/(\/\/)?([^/]+)(.*)/, '$2') } + +module.exports = toHost diff --git a/lib/ua.js b/lib/ua.js index 3ec9f83..28712e9 100644 --- a/lib/ua.js +++ b/lib/ua.js @@ -1,7 +1,7 @@ // Native -import os from 'os' +const os = require('os') // Ours -import {version} from '../../package' +const {version} = require('../package') -export default `now ${version} node-${process.version} ${os.platform()} (${os.arch()})` +module.exports = `now ${version} node-${process.version} ${os.platform()} (${os.arch()})` diff --git a/lib/utils/check-path.js b/lib/utils/check-path.js index 2fad483..ecb1d6e 100644 --- a/lib/utils/check-path.js +++ b/lib/utils/check-path.js @@ -1,11 +1,11 @@ // Native -import os from 'os' -import path from 'path' +const os = require('os') +const path = require('path') // Ours -import {error} from '../error' +const {error} = require('../error') -export default async dir => { +const checkPath = async dir => { if (!dir) { return } @@ -49,3 +49,5 @@ export default async dir => { error(`You're trying to deploy your ${locationName}.`) process.exit(1) } + +module.exports = checkPath diff --git a/lib/utils/prompt-options.js b/lib/utils/prompt-options.js index 2cbd7f7..b9db67e 100644 --- a/lib/utils/prompt-options.js +++ b/lib/utils/prompt-options.js @@ -1,7 +1,7 @@ // Packages -import chalk from 'chalk' +const chalk = require('chalk') -export default function (opts) { +module.exports = function (opts) { return new Promise((resolve, reject) => { opts.forEach(([, text], i) => { console.log(`${chalk.gray('>')} [${chalk.bold(i + 1)}] ${text}`) diff --git a/lib/utils/to-human-path.js b/lib/utils/to-human-path.js index 88e3bf3..282ec5f 100644 --- a/lib/utils/to-human-path.js +++ b/lib/utils/to-human-path.js @@ -1,6 +1,6 @@ // Native -import {resolve} from 'path' -import {homedir} from 'os' +const {resolve} = require('path') +const {homedir} = require('os') // cleaned-up `$HOME` (i.e.: no trailing slash) const HOME = resolve(homedir()) @@ -11,6 +11,8 @@ const HOME = resolve(homedir()) * `/Users/rauchg/test.js` becomes `~/test.js` */ -export default function toHumanPath(path) { +function toHumanPath(path) { return path.replace(HOME, '~') } + +module.exports = toHumanPath diff --git a/package.json b/package.json index bb62b67..aac883f 100644 --- a/package.json +++ b/package.json @@ -3,21 +3,21 @@ "version": "1.0.0", "description": "Realtime global deployments", "repository": "zeit/now-cli", - "main": "./build/lib/index", + "main": "./lib/index", "license": "MIT", "files": [ "build" ], "scripts": { "dev": "gulp", - "build": "gulp compile", "test": "xo && ava", - "pretest": "npm run build", - "prepublish": "npm run build", - "pack": "pkg . --out-dir out" + "pack": "pkg . --out-dir out --options harmony-async-await" }, "pkg": { - "scripts": "build/**/*" + "scripts": [ "./bin/*", "./lib/**/*" ] + }, + "bin": { + "now": "./bin/now" }, "ava": { "failFast": true, @@ -25,21 +25,12 @@ "test/*.js" ], "require": [ - "babel-register" + "async-to-gen/register" ] }, "greenkeeper": { "emails": false }, - "babel": { - "presets": [ - "es2015" - ], - "plugins": [ - "transform-runtime", - "transform-async-to-generator" - ] - }, "xo": { "esnext": true, "space": true, @@ -58,15 +49,15 @@ "no-control-regex": 0 } }, - "bin": { - "now": "./build/bin/now" + "engines": { + "node": ">=6.9.0" }, "dependencies": { "ansi-escapes": "1.4.0", "arr-flatten": "1.0.1", "array-unique": "0.3.2", "async-retry": "0.2.1", - "babel-runtime": "6.20.0", + "async-to-gen": "1.3.0", "bytes": "2.4.0", "chalk": "1.1.3", "copy-paste": "1.3.0", @@ -80,6 +71,7 @@ "graceful-fs": "4.1.11", "ignore": "3.2.0", "ini": "1.3.4", + "is-async-supported": "1.2.0", "is-url": "1.2.2", "minimist": "1.2.0", "ms": "0.7.2", @@ -99,17 +91,8 @@ "devDependencies": { "alpha-sort": "2.0.0", "ava": "0.17.0", - "babel-plugin-transform-async-to-generator": "6.16.0", - "babel-plugin-transform-runtime": "6.15.0", - "babel-preset-es2015": "6.18.0", - "babel-register": "6.18.0", "del": "2.2.2", "estraverse-fb": "1.3.1", - "gulp": "3.9.1", - "gulp-babel": "6.1.2", - "gulp-cached": "1.1.1", - "gulp-ext": "1.0.0", - "gulp-task-listing": "1.0.1", "pkg": "3.0.0-beta.22", "xo": "0.17.1" } diff --git a/test/args-parsing.js b/test/args-parsing.js index f56fccd..8d53ca0 100644 --- a/test/args-parsing.js +++ b/test/args-parsing.js @@ -1,6 +1,6 @@ -import path from 'path' -import test from 'ava' -import {spawn} from 'cross-spawn' +const path = require('path') +const test = require('ava') +const {spawn} = require('cross-spawn') const deployHelpMessage = '𝚫 now [options] ' const aliasHelpMessage = '𝚫 now alias ' @@ -66,7 +66,7 @@ test('"now alias --help" is the same as "now --help alias"', async t => { */ function now(...args) { return new Promise((resolve, reject) => { - const command = path.resolve(__dirname, '../build/bin/now') + const command = path.resolve(__dirname, '../bin/now') const now = spawn(command, args) let stdout = '' diff --git a/test/index.js b/test/index.js index c0831c9..0e4381f 100644 --- a/test/index.js +++ b/test/index.js @@ -1,14 +1,14 @@ // Native -import {join, resolve} from 'path' +const {join, resolve} = require('path') // Packages -import test from 'ava' -import {asc as alpha} from 'alpha-sort' -import {readFile} from 'fs-promise' +const test = require('ava') +const {asc: alpha} = require('alpha-sort') +const {readFile} = require('fs-promise') // Ours -import {npm as getNpmFiles_, docker as getDockerFiles} from '../lib/get-files' -import hash from '../lib/hash' +const {npm: getNpmFiles_, docker: getDockerFiles} = require('../lib/get-files') +const hash = require('../lib/hash') const prefix = join(__dirname, '_fixtures') + '/' const base = path => path.replace(prefix, '') diff --git a/test/to-host.js b/test/to-host.js index 22ba84c..449dff0 100644 --- a/test/to-host.js +++ b/test/to-host.js @@ -1,5 +1,5 @@ -import test from 'ava' -import toHost from '../lib/to-host' +const test = require('ava') +const toHost = require('../lib/to-host') test('simple', async t => { t.is(toHost('zeit.co'), 'zeit.co') From bf2af9d8d5bc8317bbb2dc5dbaaf46b7f187f83a Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 11:26:29 +0100 Subject: [PATCH 120/160] Properly indented pkg property --- package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index aac883f..db4475f 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,10 @@ "pack": "pkg . --out-dir out --options harmony-async-await" }, "pkg": { - "scripts": [ "./bin/*", "./lib/**/*" ] + "scripts": [ + "./bin/*", + "./lib/**/*" + ] }, "bin": { "now": "./bin/now" From 30432153503e128d9cd5f01e93ab5dc4d66fc307 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 11:27:13 +0100 Subject: [PATCH 121/160] Upload folders to npm --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index db4475f..5fd50ee 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "main": "./lib/index", "license": "MIT", "files": [ - "build" + "bin", + "lib" ], "scripts": { "dev": "gulp", From 21c235bb4cc2bc7e3e7b57309981ed54738e0d88 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 11:27:54 +0100 Subject: [PATCH 122/160] No dev script needed --- README.md | 5 ++--- package.json | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a7502dc..a867954 100644 --- a/README.md +++ b/README.md @@ -38,9 +38,8 @@ now help 1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device 2. Link the package to the global module directory: `npm link` -3. Transpile the source code and watch for changes: `npm run dev` -4. Generate a [testing token](https://zeit.co/account#api-tokens) and put it into `~/.now.json` -5. You can now start using `now` from the command line! +3. Generate a [testing token](https://zeit.co/account#api-tokens) and put it into `~/.now.json` +4. You can now start using `now` from the command line! As always, you can use `npm test` to run the tests and see if your changes have broken anything. diff --git a/package.json b/package.json index 5fd50ee..71a6e77 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "lib" ], "scripts": { - "dev": "gulp", "test": "xo && ava", "pack": "pkg . --out-dir out --options harmony-async-await" }, From 38b56b118c0829b23fa2e027b10b78f47170930d Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 11:28:27 +0100 Subject: [PATCH 123/160] There's no build directory anymore --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 71a6e77..a051eb4 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,6 @@ "space": true, "semicolon": false, "ignores": [ - "build/**", "out/**", "test/_fixtures/**" ], From b1090fe97e31b808e1833c99ceac5175067b9ac9 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 11:29:25 +0100 Subject: [PATCH 124/160] Let Travis CI decide whether or not to use sudo --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 16c715b..b37faa2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ { "language": "node_js", - "sudo": false, "node_js": "node" } From 2a26f01a95947f9296e05d7bb7cc015d9d670f2a Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 11:31:28 +0100 Subject: [PATCH 125/160] Stop pinning dependencies --- .npmrc | 1 - package.json | 80 ++++++++++++++++++++++++++-------------------------- 2 files changed, 40 insertions(+), 41 deletions(-) delete mode 100644 .npmrc diff --git a/.npmrc b/.npmrc deleted file mode 100644 index cffe8cd..0000000 --- a/.npmrc +++ /dev/null @@ -1 +0,0 @@ -save-exact=true diff --git a/package.json b/package.json index a051eb4..fe00000 100644 --- a/package.json +++ b/package.json @@ -55,47 +55,47 @@ "node": ">=6.9.0" }, "dependencies": { - "ansi-escapes": "1.4.0", - "arr-flatten": "1.0.1", - "array-unique": "0.3.2", - "async-retry": "0.2.1", - "async-to-gen": "1.3.0", - "bytes": "2.4.0", - "chalk": "1.1.3", - "copy-paste": "1.3.0", - "cross-spawn": "5.0.1", - "docker-file-parser": "0.1.0", - "download": "5.0.2", - "email-prompt": "0.2.0", - "email-validator": "1.0.7", - "fs-promise": "1.0.0", - "glob": "7.1.1", - "graceful-fs": "4.1.11", - "ignore": "3.2.0", - "ini": "1.3.4", - "is-async-supported": "1.2.0", - "is-url": "1.2.2", - "minimist": "1.2.0", - "ms": "0.7.2", - "node-fetch": "1.6.3", - "node-version": "1.0.0", - "ora": "0.4.1", - "progress": "1.1.8", - "psl": "1.1.15", - "resumer": "0.0.0", - "semver-compare": "1.0.0", - "socket.io-client": "1.7.2", - "spdy": "3.4.4", - "split-array": "1.0.1", - "text-table": "0.2.0", - "tmp-promise": "1.0.3" + "ansi-escapes": "^1.4.0", + "arr-flatten": "^1.0.1", + "array-unique": "^0.3.2", + "async-retry": "^0.2.1", + "async-to-gen": "^1.3.0", + "bytes": "^2.4.0", + "chalk": "^1.1.3", + "copy-paste": "^1.3.0", + "cross-spawn": "^5.0.1", + "docker-file-parser": "^0.1.0", + "download": "^5.0.2", + "email-prompt": "^0.2.0", + "email-validator": "^1.0.7", + "fs-promise": "^1.0.0", + "glob": "^7.1.1", + "graceful-fs": "^4.1.11", + "ignore": "^3.2.0", + "ini": "^1.3.4", + "is-async-supported": "^1.2.0", + "is-url": "^1.2.2", + "minimist": "^1.2.0", + "ms": "^0.7.2", + "node-fetch": "^1.6.3", + "node-version": "^1.0.0", + "ora": "^0.4.1", + "progress": "^1.1.8", + "psl": "^1.1.15", + "resumer": "^0.0.0", + "semver-compare": "^1.0.0", + "socket.io-client": "^1.7.2", + "spdy": "^3.4.4", + "split-array": "^1.0.1", + "text-table": "^0.2.0", + "tmp-promise": "^1.0.3" }, "devDependencies": { - "alpha-sort": "2.0.0", - "ava": "0.17.0", - "del": "2.2.2", - "estraverse-fb": "1.3.1", - "pkg": "3.0.0-beta.22", - "xo": "0.17.1" + "alpha-sort": "^2.0.0", + "ava": "^0.17.0", + "del": "^2.2.2", + "estraverse-fb": "^1.3.1", + "pkg": "^3.0.0-beta.22", + "xo": "^0.17.1" } } From 18d9de41215ebc937dc27ab620f81faae00a9e00 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 11:33:33 +0100 Subject: [PATCH 126/160] Removed main property (not needed) --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index fe00000..050fd0d 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,6 @@ "version": "1.0.0", "description": "Realtime global deployments", "repository": "zeit/now-cli", - "main": "./lib/index", "license": "MIT", "files": [ "bin", From 7e30961ae1076b6abd633469e770cc122dde5398 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 11:34:34 +0100 Subject: [PATCH 127/160] No need to ignore build directory anymore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index e9a016a..317c5c7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ # build output -build out # dependencies From 18d0963ad433f6b7cfb7dd582b56c2d37a6b1f30 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 11:36:47 +0100 Subject: [PATCH 128/160] Added a missing newline before checking support of async/await --- .gitignore | 2 +- bin/now | 1 + package.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 317c5c7..e950a29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # build output -out +packed # dependencies node_modules diff --git a/bin/now b/bin/now index dd668da..0f96f9e 100755 --- a/bin/now +++ b/bin/now @@ -9,6 +9,7 @@ const minimist = require('minimist') const {spawn} = require('cross-spawn') const nodeVersion = require('node-version') const isAsyncSupported = require('is-async-supported') + if (!isAsyncSupported()) { require('async-to-gen/register') } diff --git a/package.json b/package.json index 050fd0d..cb19838 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ ], "scripts": { "test": "xo && ava", - "pack": "pkg . --out-dir out --options harmony-async-await" + "pack": "pkg . --out-dir packed --options harmony-async-await" }, "pkg": { "scripts": [ From e981e0a218e70c0a46b0a25c32f0e90ece316b27 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 11:39:52 +0100 Subject: [PATCH 129/160] Make description match the repo's --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cb19838..11806da 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "now", "version": "1.0.0", - "description": "Realtime global deployments", + "description": "The command line interface for Now", "repository": "zeit/now-cli", "license": "MIT", "files": [ From 6186c8b06b9f50e179e10f02c6721fae4d181305 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 11:56:43 +0100 Subject: [PATCH 130/160] Start JS syntax right on top --- bin/now | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/bin/now b/bin/now index 0f96f9e..189269b 100755 --- a/bin/now +++ b/bin/now @@ -1,12 +1,12 @@ #!/bin/bash // >&/dev/null; exec node $(node -p "process.version[1] >= 7 ? '--harmony-async-await' : '--lazy'") $0 $@ +// vi:syntax=javascript // Native const {resolve} = require('path') // Packages const minimist = require('minimist') -const {spawn} = require('cross-spawn') const nodeVersion = require('node-version') const isAsyncSupported = require('is-async-supported') @@ -18,7 +18,6 @@ if (!isAsyncSupported()) { const checkUpdate = require('../lib/check-update') const {error} = require('../lib/error') - if (nodeVersion.major < 6) { error('Now requires at least version 6 of Node. Please upgrade!') process.exit(1) @@ -100,10 +99,8 @@ if (index > -1) { cmd = aliases.get(cmd) || cmd } -let bin = resolve(__dirname, 'now-' + cmd) +const bin = resolve(__dirname, 'now-' + cmd) // Prepare process.argv for subcommand -process.argv = process.argv.slice(0, 2).concat(args); +process.argv = process.argv.slice(0, 2).concat(args) require(bin) - -// vi:syntax=javascript From 06fad401bf4e5f7e22f65e355ac6c99a8235b3cb Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 11:59:56 +0100 Subject: [PATCH 131/160] Removed unused code --- bin/now | 25 ------------------------- package.json | 2 ++ 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/bin/now b/bin/now index 189269b..1afe643 100755 --- a/bin/now +++ b/bin/now @@ -6,7 +6,6 @@ const {resolve} = require('path') // Packages -const minimist = require('minimist') const nodeVersion = require('node-version') const isAsyncSupported = require('is-async-supported') @@ -15,7 +14,6 @@ if (!isAsyncSupported()) { } // Ours -const checkUpdate = require('../lib/check-update') const {error} = require('../lib/error') if (nodeVersion.major < 6) { @@ -23,29 +21,6 @@ if (nodeVersion.major < 6) { process.exit(1) } -const argv = minimist(process.argv.slice(2)) - -// options -const debug = argv.debug || argv.d - -// Disable updates by default -let update = false - -// auto-update checking -// only for the npm version, not the enclosed one -if (!process.pkg) { - update = checkUpdate({debug}) -} - -const exit = code => { - if (update) { - update.then(() => process.exit(code)) - } - // don't wait for updates more than a second - // when the process really wants to exit - setTimeout(() => process.exit(code), 1000) -} - const defaultCommand = 'deploy' const commands = new Set([ diff --git a/package.json b/package.json index 11806da..6e2b367 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,8 @@ ], "rules": { "import/no-unresolved": 0, + "import/no-unassigned-import": 0, + "import/no-dynamic-require": 0, "max-depth": 0, "no-use-before-define": 0, "complexity": 0, From d01bf29690fe2cf42d952ebcd2824618f1c2072f Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 12:03:02 +0100 Subject: [PATCH 132/160] Check for update using a package --- bin/now | 13 ++++-- lib/check-update.js | 97 --------------------------------------------- package.json | 3 +- 3 files changed, 12 insertions(+), 101 deletions(-) delete mode 100644 lib/check-update.js diff --git a/bin/now b/bin/now index 1afe643..1650075 100755 --- a/bin/now +++ b/bin/now @@ -8,19 +8,26 @@ const {resolve} = require('path') // Packages const nodeVersion = require('node-version') const isAsyncSupported = require('is-async-supported') +const updateNotifier = require('update-notifier') + +// Ours +const {error} = require('../lib/error') +const pkg = require('../package') if (!isAsyncSupported()) { require('async-to-gen/register') } -// Ours -const {error} = require('../lib/error') - if (nodeVersion.major < 6) { error('Now requires at least version 6 of Node. Please upgrade!') process.exit(1) } +// Only check for updates in the npm version +if (!process.pkg) { + updateNotifier({pkg}).notify() +} + const defaultCommand = 'deploy' const commands = new Set([ diff --git a/lib/check-update.js b/lib/check-update.js deleted file mode 100644 index 1c6afd9..0000000 --- a/lib/check-update.js +++ /dev/null @@ -1,97 +0,0 @@ -// Packages -const ms = require('ms') -const fetch = require('node-fetch') -const chalk = require('chalk') -const compare = require('semver-compare') - -// Ours -const pkg = require('../package') - -const isTTY = process.stdout.isTTY - -// if we're not in a tty the update checker -// will always return a resolved promise -const resolvedPromise = new Promise(resolve => resolve()) - -/** - * Configures auto updates. - * Sets up a `exit` listener to report them. - */ - -function checkUpdate(opts = {}) { - if (!isTTY) { - // don't attempt to check for updates - // if the user is piping or redirecting - return resolvedPromise - } - - let updateData - - const update = check(opts).then(data => { - updateData = data - - // forces the `exit` event upon Ctrl + C - process.on('SIGINT', () => { - // clean up output after ^C - process.stdout.write('\n') - process.exit(1) - }) - }, err => console.error(err.stack)) - - process.on('exit', () => { - if (updateData) { - const {current, latest, at} = updateData - const ago = ms(Date.now() - at) - console.log(`> ${chalk.white.bgRed('UPDATE NEEDED')} ` + - `Current: ${current} – ` + - `Latest ${chalk.bold(latest)} (released ${ago} ago)`) - console.log('> Run `npm install -g now` to update') - } - }) - - return update -} - -function check({debug = false}) { - return new Promise(resolve => { - if (debug) { - console.log('> [debug] Checking for updates.') - } - - fetch('https://registry.npmjs.org/now').then(res => { - if (res.status !== 200) { - if (debug) { - console.log(`> [debug] Update check error. NPM ${res.status}.`) - } - - resolve(false) - return - } - - res.json().then(data => { - const {latest} = data['dist-tags'] - const current = pkg.version - - if (compare(latest, pkg.version) === 1) { - if (debug) { - console.log(`> [debug] Needs update. Current ${current}, latest ${latest}`) - } - - resolve({ - latest, - current, - at: new Date(data.time[latest]) - }) - } else { - if (debug) { - console.log(`> [debug] Up to date (${pkg.version}).`) - } - - resolve(false) - } - }, () => resolve(false)) - }, () => resolve(false)) - }) -} - -module.exports = checkUpdate diff --git a/package.json b/package.json index 6e2b367..0136857 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,8 @@ "spdy": "^3.4.4", "split-array": "^1.0.1", "text-table": "^0.2.0", - "tmp-promise": "^1.0.3" + "tmp-promise": "^1.0.3", + "update-notifier": "^1.0.3" }, "devDependencies": { "alpha-sort": "^2.0.0", From fc8708923e09e6e9a2762b5e9bd59b798e6e914c Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 12:03:26 +0100 Subject: [PATCH 133/160] Re-enable rule for unresolved imports --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 0136857..a021cee 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,6 @@ "test/_fixtures/**" ], "rules": { - "import/no-unresolved": 0, "import/no-unassigned-import": 0, "import/no-dynamic-require": 0, "max-depth": 0, From df111b9eba08837b42dc16d410a31513104f03f3 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 12:04:58 +0100 Subject: [PATCH 134/160] Only allow process.exit in certain places --- lib/utils/check-path.js | 6 +----- package.json | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/utils/check-path.js b/lib/utils/check-path.js index ecb1d6e..8d71267 100644 --- a/lib/utils/check-path.js +++ b/lib/utils/check-path.js @@ -2,9 +2,6 @@ const os = require('os') const path = require('path') -// Ours -const {error} = require('../error') - const checkPath = async dir => { if (!dir) { return @@ -46,8 +43,7 @@ const checkPath = async dir => { locationName = location } - error(`You're trying to deploy your ${locationName}.`) - process.exit(1) + throw new Error(`You're trying to deploy your ${locationName}.`) } module.exports = checkPath diff --git a/package.json b/package.json index a021cee..b0b4999 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "max-depth": 0, "no-use-before-define": 0, "complexity": 0, - "unicorn/no-process-exit": 0, "no-control-regex": 0 } }, From 50300086316d4635c798b19ecc605684c7ebb659 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 12:20:47 +0100 Subject: [PATCH 135/160] Tell XO to ignore enclosed version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b0b4999..4e5cddd 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "space": true, "semicolon": false, "ignores": [ - "out/**", + "packed/**", "test/_fixtures/**" ], "rules": { From 9f073ad25cedda407220fd143912a601e0223805 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 18:48:56 +0100 Subject: [PATCH 136/160] Use async-to-gen for all Node versions --- bin/now | 9 ++------- bin/now-alias | 2 +- bin/now-certs | 2 +- bin/now-deploy | 2 +- bin/now-dns | 2 +- bin/now-domains | 2 +- bin/now-list | 3 +-- bin/now-remove | 2 +- bin/now-secrets | 2 +- package.json | 1 - 10 files changed, 10 insertions(+), 17 deletions(-) diff --git a/bin/now b/bin/now index 1650075..42675cc 100755 --- a/bin/now +++ b/bin/now @@ -1,22 +1,17 @@ -#!/bin/bash -// >&/dev/null; exec node $(node -p "process.version[1] >= 7 ? '--harmony-async-await' : '--lazy'") $0 $@ -// vi:syntax=javascript +#!/usr/bin/env node // Native const {resolve} = require('path') // Packages const nodeVersion = require('node-version') -const isAsyncSupported = require('is-async-supported') const updateNotifier = require('update-notifier') // Ours const {error} = require('../lib/error') const pkg = require('../package') -if (!isAsyncSupported()) { - require('async-to-gen/register') -} +require('async-to-gen/register') if (nodeVersion.major < 6) { error('Now requires at least version 6 of Node. Please upgrade!') diff --git a/bin/now-alias b/bin/now-alias index c9f4fc4..e53da28 100755 --- a/bin/now-alias +++ b/bin/now-alias @@ -1,4 +1,4 @@ -#!/usr/bin/env node --harmony-async-await +#!/usr/bin/env node // Packages const chalk = require('chalk') diff --git a/bin/now-certs b/bin/now-certs index fd9b1cc..43d854a 100755 --- a/bin/now-certs +++ b/bin/now-certs @@ -1,4 +1,4 @@ -#!/usr/bin/env node --harmony-async-await +#!/usr/bin/env node // Native const path = require('path') diff --git a/bin/now-deploy b/bin/now-deploy index decaad1..cbe4d7e 100755 --- a/bin/now-deploy +++ b/bin/now-deploy @@ -1,4 +1,4 @@ -#!/usr/bin/env node --harmony-async-await +#!/usr/bin/env node // Native const {resolve} = require('path') diff --git a/bin/now-dns b/bin/now-dns index 04b72af..a27027d 100755 --- a/bin/now-dns +++ b/bin/now-dns @@ -1,4 +1,4 @@ -#!/usr/bin/env node --harmony-async-await +#!/usr/bin/env node // Packages const chalk = require('chalk') diff --git a/bin/now-domains b/bin/now-domains index 277e552..16e27ab 100755 --- a/bin/now-domains +++ b/bin/now-domains @@ -1,4 +1,4 @@ -#!/usr/bin/env node --harmony-async-await +#!/usr/bin/env node // Packages const chalk = require('chalk') diff --git a/bin/now-list b/bin/now-list index 5069197..7c175d3 100755 --- a/bin/now-list +++ b/bin/now-list @@ -1,5 +1,4 @@ -#!/usr/bin/env node --harmony-async-await - +#!/usr/bin/env node // Packages const fs = require('fs-promise') diff --git a/bin/now-remove b/bin/now-remove index 816f84c..cbb445b 100755 --- a/bin/now-remove +++ b/bin/now-remove @@ -1,4 +1,4 @@ -#!/usr/bin/env node --harmony-async-await +#!/usr/bin/env node // Packages const minimist = require('minimist') diff --git a/bin/now-secrets b/bin/now-secrets index 280c6f9..ec93151 100755 --- a/bin/now-secrets +++ b/bin/now-secrets @@ -1,4 +1,4 @@ -#!/usr/bin/env node --harmony-async-await +#!/usr/bin/env node // Packages const chalk = require('chalk') diff --git a/package.json b/package.json index 4e5cddd..b2105e5 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,6 @@ "graceful-fs": "^4.1.11", "ignore": "^3.2.0", "ini": "^1.3.4", - "is-async-supported": "^1.2.0", "is-url": "^1.2.2", "minimist": "^1.2.0", "ms": "^0.7.2", From 56f4c2818a2880dcdbe40ae52abfff1121aa6bfe Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 18:51:50 +0100 Subject: [PATCH 137/160] Hide weird XO error in Atom --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index b2105e5..261413f 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "rules": { "import/no-unassigned-import": 0, "import/no-dynamic-require": 0, + "import/no-unresolved": 0, "max-depth": 0, "no-use-before-define": 0, "complexity": 0, From 158bf64ea2dc5d463c8198059d59bac77648c3b1 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 18:54:33 +0100 Subject: [PATCH 138/160] No need to set language type anymore --- bin/now-alias | 2 -- bin/now-certs | 2 -- bin/now-deploy | 2 -- bin/now-dns | 2 -- bin/now-domains | 2 -- bin/now-list | 2 -- bin/now-remove | 2 -- bin/now-secrets | 2 -- 8 files changed, 16 deletions(-) diff --git a/bin/now-alias b/bin/now-alias index e53da28..c8039b6 100755 --- a/bin/now-alias +++ b/bin/now-alias @@ -314,5 +314,3 @@ async function realias(alias) { await alias.set(source.url, target) } - -// vi:syntax=javascript diff --git a/bin/now-certs b/bin/now-certs index 43d854a..e86d830 100755 --- a/bin/now-certs +++ b/bin/now-certs @@ -291,5 +291,3 @@ async function getCertIdCn(certs, idOrCn) { return thecert } - -// vi:syntax=javascript diff --git a/bin/now-deploy b/bin/now-deploy index cbe4d7e..ad197af 100755 --- a/bin/now-deploy +++ b/bin/now-deploy @@ -613,5 +613,3 @@ function printLogs(host, token) { process.exit(0) }) } - -// vi:syntax=javascript diff --git a/bin/now-dns b/bin/now-dns index a27027d..b56fca2 100755 --- a/bin/now-dns +++ b/bin/now-dns @@ -200,5 +200,3 @@ function readConfirmation(record, msg) { }).resume() }) } - -// vi:syntax=javascript diff --git a/bin/now-domains b/bin/now-domains index 16e27ab..a1b87e2 100755 --- a/bin/now-domains +++ b/bin/now-domains @@ -296,5 +296,3 @@ function findDomain(val, list) { return false }) } - -// vi:syntax=javascript diff --git a/bin/now-list b/bin/now-list index 7c175d3..ff7b581 100755 --- a/bin/now-list +++ b/bin/now-list @@ -151,5 +151,3 @@ async function sort(apps) { return depsB[0].created - depsA[0].created }) } - -// vi:syntax=javascript diff --git a/bin/now-remove b/bin/now-remove index cbb445b..9a14e7c 100755 --- a/bin/now-remove +++ b/bin/now-remove @@ -175,5 +175,3 @@ async function remove(token) { now.close() } - -// vi:syntax=javascript diff --git a/bin/now-secrets b/bin/now-secrets index ec93151..4570c7f 100755 --- a/bin/now-secrets +++ b/bin/now-secrets @@ -237,5 +237,3 @@ function readConfirmation(secret) { }).resume() }) } - -// vi:syntax=javascript From 7628017eb6f2917f47af3fde777b4843a0967aa6 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 18:58:51 +0100 Subject: [PATCH 139/160] 2.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 261413f..ad3172b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "1.0.0", + "version": "2.0.0", "description": "The command line interface for Now", "repository": "zeit/now-cli", "license": "MIT", From 513ecfb7de45e7254376eb05f2b6ae9d5903767e Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 19:30:12 +0100 Subject: [PATCH 140/160] Added extensions to binaries --- bin/{now-alias => now-alias.js} | 0 bin/{now-certs => now-certs.js} | 0 bin/{now-deploy => now-deploy.js} | 0 bin/{now-dns => now-dns.js} | 0 bin/{now-domains => now-domains.js} | 0 bin/{now-list => now-list.js} | 0 bin/{now-remove => now-remove.js} | 0 bin/{now-secrets => now-secrets.js} | 0 bin/{now => now.js} | 0 package.json | 2 +- 10 files changed, 1 insertion(+), 1 deletion(-) rename bin/{now-alias => now-alias.js} (100%) rename bin/{now-certs => now-certs.js} (100%) rename bin/{now-deploy => now-deploy.js} (100%) rename bin/{now-dns => now-dns.js} (100%) rename bin/{now-domains => now-domains.js} (100%) rename bin/{now-list => now-list.js} (100%) rename bin/{now-remove => now-remove.js} (100%) rename bin/{now-secrets => now-secrets.js} (100%) rename bin/{now => now.js} (100%) diff --git a/bin/now-alias b/bin/now-alias.js similarity index 100% rename from bin/now-alias rename to bin/now-alias.js diff --git a/bin/now-certs b/bin/now-certs.js similarity index 100% rename from bin/now-certs rename to bin/now-certs.js diff --git a/bin/now-deploy b/bin/now-deploy.js similarity index 100% rename from bin/now-deploy rename to bin/now-deploy.js diff --git a/bin/now-dns b/bin/now-dns.js similarity index 100% rename from bin/now-dns rename to bin/now-dns.js diff --git a/bin/now-domains b/bin/now-domains.js similarity index 100% rename from bin/now-domains rename to bin/now-domains.js diff --git a/bin/now-list b/bin/now-list.js similarity index 100% rename from bin/now-list rename to bin/now-list.js diff --git a/bin/now-remove b/bin/now-remove.js similarity index 100% rename from bin/now-remove rename to bin/now-remove.js diff --git a/bin/now-secrets b/bin/now-secrets.js similarity index 100% rename from bin/now-secrets rename to bin/now-secrets.js diff --git a/bin/now b/bin/now.js similarity index 100% rename from bin/now rename to bin/now.js diff --git a/package.json b/package.json index ad3172b..483cb21 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ ] }, "bin": { - "now": "./bin/now" + "now": "./bin/now.js" }, "ava": { "failFast": true, From f82cbe9bc50eca0cc0c6f84a4b7d6aa9be780e0f Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 19:30:26 +0100 Subject: [PATCH 141/160] Tell pkg not to use the harmony flag --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 483cb21..bcba44f 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ ], "scripts": { "test": "xo && ava", - "pack": "pkg . --out-dir packed --options harmony-async-await" + "pack": "pkg . --out-dir packed" }, "pkg": { "scripts": [ From 03708278df90c9036be8ae36401a47ec08db2b57 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 19:42:10 +0100 Subject: [PATCH 142/160] Load sub commands using extensions --- bin/now.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/now.js b/bin/now.js index 42675cc..c679805 100755 --- a/bin/now.js +++ b/bin/now.js @@ -76,7 +76,7 @@ if (index > -1) { cmd = aliases.get(cmd) || cmd } -const bin = resolve(__dirname, 'now-' + cmd) +const bin = resolve(__dirname, 'now-' + cmd + '.js') // Prepare process.argv for subcommand process.argv = process.argv.slice(0, 2).concat(args) From dabcc64660fc1cdbccc9983c94191c197a603e77 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 19:42:27 +0100 Subject: [PATCH 143/160] 2.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bcba44f..364e50c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "2.0.0", + "version": "2.0.1", "description": "The command line interface for Now", "repository": "zeit/now-cli", "license": "MIT", From 2fa62da2d8b7ffe10db2b3e9887732eb08657b4f Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 19:59:31 +0100 Subject: [PATCH 144/160] Don't ignore modules directory when transpiling --- bin/now.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/now.js b/bin/now.js index c679805..9f0fda8 100755 --- a/bin/now.js +++ b/bin/now.js @@ -11,7 +11,9 @@ const updateNotifier = require('update-notifier') const {error} = require('../lib/error') const pkg = require('../package') -require('async-to-gen/register') +require('async-to-gen/register')({ + excludes: null +}) if (nodeVersion.major < 6) { error('Now requires at least version 6 of Node. Please upgrade!') From c46f5e66dd1b26e919568f01579880767737e72e Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 19:59:44 +0100 Subject: [PATCH 145/160] 2.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 364e50c..39773ee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "2.0.1", + "version": "2.0.2", "description": "The command line interface for Now", "repository": "zeit/now-cli", "license": "MIT", From 058c3f63abeee7b42b9d8dd76d567857f834b990 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 21:16:16 +0100 Subject: [PATCH 146/160] Make tests use the correct binary --- test/args-parsing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/args-parsing.js b/test/args-parsing.js index 8d53ca0..d9de669 100644 --- a/test/args-parsing.js +++ b/test/args-parsing.js @@ -66,7 +66,7 @@ test('"now alias --help" is the same as "now --help alias"', async t => { */ function now(...args) { return new Promise((resolve, reject) => { - const command = path.resolve(__dirname, '../bin/now') + const command = path.resolve(__dirname, '../bin/now.js') const now = spawn(command, args) let stdout = '' From a76397f0fb0f03f4dbd5b6b69cd1735045ccc19c Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 10 Jan 2017 22:53:33 +0100 Subject: [PATCH 147/160] Testing token needs to be inside its property --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a867954..9e7ccb6 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ now help 1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device 2. Link the package to the global module directory: `npm link` -3. Generate a [testing token](https://zeit.co/account#api-tokens) and put it into `~/.now.json` +3. Generate a [testing token](https://zeit.co/account#api-tokens) and put it into the `token` property within `~/.now.json` 4. You can now start using `now` from the command line! As always, you can use `npm test` to run the tests and see if your changes have broken anything. From 0b4660158a94afde1b6d3c86093bcaa0bab68843 Mon Sep 17 00:00:00 2001 From: Olli Vanhoja Date: Wed, 11 Jan 2017 15:52:40 +0200 Subject: [PATCH 148/160] Fix file mode passing for regular deployments (#214) Commit bbf1b30c4decce34a115e64201702f270eb003c3 broke file modes for regular deployments as file mode isn't retrieved anymore. --- lib/index.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/index.js b/lib/index.js index 5908a97..2de724f 100644 --- a/lib/index.js +++ b/lib/index.js @@ -128,18 +128,24 @@ module.exports = class Now extends EventEmitter { // Flatten the array to contain files to sync where each nested input // array has a group of files with the same sha but different path const files = await Promise.all(Array.prototype.concat.apply([], await Promise.all((Array.from(this._files)).map(async ([sha, {data, names}]) => { + const statFn = followSymlinks ? stat : lstat return await names.map(async name => { let mode + const getMode = async () => { + const st = await statFn(name) + return st.mode + } + if (this._static) { if (toRelative(name, this._path) === 'package.json') { mode = 33261 } else { - const st = await (followSymlinks ? stat(name) : lstat(name)) - mode = st.mode - + mode = await getMode() name = this.pathInsideContent(name) } + } else { + mode = await getMode() } return { From b997c71dd4c30703b7ebd49cb2f365e59816e59d Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Wed, 11 Jan 2017 15:01:42 +0100 Subject: [PATCH 149/160] Contextual newlines added --- bin/now-alias.js | 1 + bin/now-dns.js | 1 + bin/now-domains.js | 1 + lib/index.js | 1 + 4 files changed, 4 insertions(+) diff --git a/bin/now-alias.js b/bin/now-alias.js index c8039b6..a66a7c9 100755 --- a/bin/now-alias.js +++ b/bin/now-alias.js @@ -25,6 +25,7 @@ const argv = minimist(process.argv.slice(2), { token: 't' } }) + const subcommand = argv._[0] // options diff --git a/bin/now-dns.js b/bin/now-dns.js index b56fca2..b521350 100755 --- a/bin/now-dns.js +++ b/bin/now-dns.js @@ -24,6 +24,7 @@ const argv = minimist(process.argv.slice(2), { token: 't' } }) + const subcommand = argv._[0] // options diff --git a/bin/now-domains.js b/bin/now-domains.js index a1b87e2..a039583 100755 --- a/bin/now-domains.js +++ b/bin/now-domains.js @@ -26,6 +26,7 @@ const argv = minimist(process.argv.slice(2), { token: 't' } }) + const subcommand = argv._[0] // options diff --git a/lib/index.js b/lib/index.js index 2de724f..4cd6e99 100644 --- a/lib/index.js +++ b/lib/index.js @@ -129,6 +129,7 @@ module.exports = class Now extends EventEmitter { // array has a group of files with the same sha but different path const files = await Promise.all(Array.prototype.concat.apply([], await Promise.all((Array.from(this._files)).map(async ([sha, {data, names}]) => { const statFn = followSymlinks ? stat : lstat + return await names.map(async name => { let mode From 59734bf31bf650e08867a7da4b2ee9b0090797bd Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Wed, 11 Jan 2017 15:15:12 +0100 Subject: [PATCH 150/160] MOAR comments --- bin/now.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/now.js b/bin/now.js index 9f0fda8..0afc8c5 100755 --- a/bin/now.js +++ b/bin/now.js @@ -11,10 +11,12 @@ const updateNotifier = require('update-notifier') const {error} = require('../lib/error') const pkg = require('../package') +// Support for keywords "async" and "await" require('async-to-gen/register')({ excludes: null }) +// Throw an error if node version is too low if (nodeVersion.major < 6) { error('Now requires at least version 6 of Node. Please upgrade!') process.exit(1) @@ -25,6 +27,7 @@ if (!process.pkg) { updateNotifier({pkg}).notify() } +// This command will be run if no other sub command is specified const defaultCommand = 'deploy' const commands = new Set([ @@ -82,4 +85,6 @@ const bin = resolve(__dirname, 'now-' + cmd + '.js') // Prepare process.argv for subcommand process.argv = process.argv.slice(0, 2).concat(args) + +// Load sub command require(bin) From 5c1b239ca65cfef611518d252183d79e3fbdb838 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Wed, 11 Jan 2017 15:17:48 +0100 Subject: [PATCH 151/160] Prevent pkg from throwing a warning --- bin/now.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/now.js b/bin/now.js index 0afc8c5..38d1641 100755 --- a/bin/now.js +++ b/bin/now.js @@ -87,4 +87,5 @@ const bin = resolve(__dirname, 'now-' + cmd + '.js') process.argv = process.argv.slice(0, 2).concat(args) // Load sub command -require(bin) +// With custom parameter to make "pkg" happy +require(bin, 'may-exclude') From 0c2ef197adc3d5b2f9cddd6f359b326a3b132ce3 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Wed, 11 Jan 2017 15:17:59 +0100 Subject: [PATCH 152/160] 2.0.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 39773ee..891101b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "2.0.2", + "version": "2.0.3", "description": "The command line interface for Now", "repository": "zeit/now-cli", "license": "MIT", From 311abf3d2f04f03e0a44aa53d3e282fc7662a7e6 Mon Sep 17 00:00:00 2001 From: Olli Vanhoja Date: Sat, 14 Jan 2017 23:48:43 +0200 Subject: [PATCH 153/160] now-rm: Don't show URL for incomplete deployments (#221) Fixes this: > The following deployment will be removed permanently: XXXXXXXXXXXXXXXXXXXXXXXX https://null 21d ago --- bin/now-remove.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/now-remove.js b/bin/now-remove.js index 9a14e7c..b54472d 100755 --- a/bin/now-remove.js +++ b/bin/now-remove.js @@ -81,7 +81,7 @@ function readConfirmation(matches) { const tbl = table( matches.map(depl => { const time = chalk.gray(ms(new Date() - depl.created) + ' ago') - const url = chalk.underline(`https://${depl.url}`) + const url = depl.url ? chalk.underline(`https://${depl.url}`) : '' return [depl.uid, url, time] }), {align: ['l', 'r', 'l'], hsep: ' '.repeat(6)} From cb8403174b2807ff5884ac6b64630c6e7d44f393 Mon Sep 17 00:00:00 2001 From: Matheus Fernandes Date: Sat, 14 Jan 2017 19:48:53 -0200 Subject: [PATCH 154/160] Make clear that the alias must exist when using `--alias` (#222) --- bin/now-deploy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/now-deploy.js b/bin/now-deploy.js index ad197af..540b832 100755 --- a/bin/now-deploy.js +++ b/bin/now-deploy.js @@ -98,7 +98,7 @@ const help = () => { -e, --env Include an env var (e.g.: ${chalk.dim('`-e KEY=value`')}). Can appear many times. -C, --no-clipboard Do not attempt to copy URL to clipboard -N, --forward-npm Forward login information to install private NPM modules - -a, --alias Assign an alias to the deployment + -a, --alias Reassign an existing alias to the deployment ${chalk.dim('Enforcable Types (when both package.json and Dockerfile exist):')} From d8e4e41b8dc653e4b509f91d0797dc7df1e712b3 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 16 Jan 2017 18:57:16 +0100 Subject: [PATCH 155/160] Pinned `serve` but allowing patches --- lib/read-metadata.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/read-metadata.js b/lib/read-metadata.js index 03c12e5..de4ff57 100644 --- a/lib/read-metadata.js +++ b/lib/read-metadata.js @@ -9,7 +9,7 @@ const listPackage = { start: 'serve ./content' }, dependencies: { - serve: 'latest' + serve: '^2.4.1' } } From c45eeed38f56e01816295513511eb285705cbefd Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 16 Jan 2017 19:00:54 +0100 Subject: [PATCH 156/160] No `version` property required --- lib/read-metadata.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/read-metadata.js b/lib/read-metadata.js index de4ff57..9000be4 100644 --- a/lib/read-metadata.js +++ b/lib/read-metadata.js @@ -4,7 +4,6 @@ const {readFile} = require('fs-promise') const {parse: parseDockerfile} = require('docker-file-parser') const listPackage = { - version: '0.0.0', scripts: { start: 'serve ./content' }, From 0c02113e2ae13e608cc700ea5845111421a9a23c Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Mon, 16 Jan 2017 19:08:51 +0100 Subject: [PATCH 157/160] 2.0.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 891101b..c3673b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "2.0.3", + "version": "2.0.4", "description": "The command line interface for Now", "repository": "zeit/now-cli", "license": "MIT", From 85a68b9fe7bd6abf716caf358c64ab3b4c6768e0 Mon Sep 17 00:00:00 2001 From: Greenkeeper Date: Tue, 17 Jan 2017 11:11:36 +0100 Subject: [PATCH 158/160] chore(package): update ora to version 1.0.0 (#227) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c3673b8..5c26111 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "ms": "^0.7.2", "node-fetch": "^1.6.3", "node-version": "^1.0.0", - "ora": "^0.4.1", + "ora": "^1.0.0", "progress": "^1.1.8", "psl": "^1.1.15", "resumer": "^0.0.0", From 49de0d3331563537c2326ab3f170af801ff979a5 Mon Sep 17 00:00:00 2001 From: Matheus Fernandes Date: Tue, 17 Jan 2017 13:45:31 -0200 Subject: [PATCH 159/160] Print the error message for a aborted login in a new line (#229) --- lib/login.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/login.js b/lib/login.js index f34653b..c97ed03 100644 --- a/lib/login.js +++ b/lib/login.js @@ -55,7 +55,14 @@ function sleep(ms) { } async function register(url, {retryEmail = false} = {}) { - const email = await readEmail({invalid: retryEmail}) + let email + try { + email = await readEmail({invalid: retryEmail}) + } catch (err) { + process.stdout.write('\n') + throw err + } + process.stdout.write('\n') if (!validate(email)) { From a3a74ab2536b83cf5d41afc8097b923c2a8e4057 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 21 Jan 2017 15:12:29 +0100 Subject: [PATCH 160/160] 2.0.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5c26111..0c91755 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "now", - "version": "2.0.4", + "version": "2.0.5", "description": "The command line interface for Now", "repository": "zeit/now-cli", "license": "MIT",