From 04e50b24e49a9d573ad7ff431268ac735a31d9b4 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Fri, 25 Nov 2016 15:13:17 +0100 Subject: [PATCH 01/26] 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 02/26] 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 03/26] 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 04/26] 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 05/26] 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 06/26] 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 07/26] 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 08/26] 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 5e5545789fbfd2520fa682318d081f387f67fdda Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sat, 26 Nov 2016 12:19:49 +0100 Subject: [PATCH 09/26] 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 10/26] 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 11/26] 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 12/26] 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 13/26] 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 14/26] 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 15/26] 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 16/26] 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 9d7746f9ed51d5a1407c3fc133bd876553b1849d Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Sun, 27 Nov 2016 22:14:56 +0100 Subject: [PATCH 17/26] 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 18/26] 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 19/26] 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 20/26] 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 21/26] 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 22/26] 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 23/26] 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 24/26] 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 25/26] 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 26/26] 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