Compare commits

...

36 Commits

Author SHA1 Message Date
Andy Bitz
fbb5caf955 Publish
- gatsby-plugin-now@1.2.1-canary.0
 - @now/build-utils@1.0.0-canary.2
 - now@16.1.3-canary.6
 - @now/go@0.5.11-canary.3
 - @now/next@1.0.0-canary.2
 - @now/node@1.0.0-canary.2
 - @now/static-build@0.9.9-canary.3
2019-09-03 09:57:03 +02:00
Andy
3f93da550b [now-build-utils][now-next][now-node] Bump version (#2942)
* [now-build-utils][now-next][now-node] Bump version

* Bump build-utils in @now-cli
2019-09-03 07:53:19 +00:00
Luc
a194e0cc6e [gatsby-plugin-now] Add new package w/support for Gatsby Redirects (#2897)
* add gatsby-plugin-now

* add test

* adjust with lerna

* fix test

* add tests to circleci

* add support for defaultRoutes functions

* add defaultRoutes to gatsby

* fix types

* add test case for gatsby redirects

* remove gatsby, react, react-dom from monorepo deps

* chmod +x build.sh

* add missing build script in fixtures

* do stuff during tests to avoid persistence issue

* move tests setup to build step

* copy gatsby plugin files in test case

* bring back ncc step

* prettier gatsby-plugin-now

* add missing semicolons

* remove eslint, prettier from plugin

* persist build step copied file

* fetch without following redirects

* add files in package.json

* remove force

* fix tests probes

* fetch location is not raw location

* fix test

* add readme

* fix type error

* adjust tests

* add support for `force`

* add tests for `force`

* adjust tests again

* gatsby-plugin-now@1.1.0

* `"` -> `'`

* tweak redirect names in test by precaution

* change file name and delete when consumed

* format files

* gatsby-plugin-now@1.2.0

* Apply suggestions from code review

Co-Authored-By: Steven <steven@ceriously.com>

* tests -> test

* add --verbose

* adjust circleci to persist fixtures

* trigger tests

* add repository and homepage in package.json

* glob files after `defaultRoute` invocation
2019-09-03 04:19:32 +00:00
Andy
b007200bcf [now-node][now-next] Skip installing user dependencies for now dev (#2926)
* Skip installing user dependencies for `now dev`

* Update type

* Install dependecies for test

* Add comma-dangle for @now/next

* Revert "Add comma-dangle for @now/next"

This reverts commit 720d5630f309ec44eb65e280af29db5b14bd50eb.

* Add trailing commas

* Reset typescript update

* Add trailing commas

* Bump @zeit/node-file-trace

* Readd trailing comma

* Bump @zeit/node-file-trace in @now/node
2019-09-02 19:35:48 +00:00
Sophearak Tha
05d88da887 [now-cli] Remove annotate from now logs (#2937)
* Remove annotate from `now logs`

* Filter out runtime logs to be consistency with dashboard logs

* Add integration test
2019-09-02 16:32:45 +00:00
Sophearak Tha
0a429bb2f3 [now-go] Add GO_BUILD_FLAGS support for go build custom flags (#2916)
* Add `GO_BUILD_FLAGS` support for go build custom flags

* Using string-argv package

* Simplify condition
2019-09-02 15:45:13 +00:00
Joe Haddad
468ccb7598 [now-next] Create default file with correct target (#2924) 2019-09-02 13:28:36 +00:00
Andy Bitz
e47f6f55dc Publish
- now@16.1.3-canary.5
2019-09-02 15:11:14 +02:00
Nathan Rajlich
17deed91b2 [now-cli] Update pcre-to-regexp to v1.0.0 (#2932)
No improvements, per say, but the module has been converted to
TypeScript so it supplies its own type definitions now, and we
can delete our hand-crafted typings from this repo.
2019-09-02 12:47:25 +00:00
Nathan Rajlich
cc0bd9f0a2 [now-cli] Use xdg-app-paths for now dev cache dir (#2921)
* [now-cli] Use `xdg-app-paths` for `now dev` cache dir

For consistency, because #2877 uses this module.
No need for multiple modules that do the same thing.

* Update `@zeit/fun` to v0.9.3
2019-09-01 14:25:26 +00:00
Steven
f6f99fef25 Publish
- now@16.1.3-canary.4
 - @now/go@0.5.11-canary.2
 - @now/node@0.12.8-canary.3
2019-08-30 14:36:09 -04:00
Nathan Rajlich
eb252edc7f [now-cli] Output --json to stdout for now alias ls <url> (#2922)
Fixes #1337.
2019-08-30 18:29:28 +00:00
Sophearak Tha
f3213dbcdc [now-node] Cleanup debug output (#2927)
* Ensure traced files have annotate present in all lines

* Remove traced file logs

* Remove `compiling es module file` log

* Cleanup debug output
2019-08-30 16:42:23 +00:00
Sophearak Tha
c637da7710 [now-go] Fix analyze.go fails to parse source file with comments (#2911)
* Fix `analyze.go` fails to parse source file with comments

* Add more tests

* Improve fallback

* Improve check for http.HandlerFunc signature`
2019-08-30 15:32:51 +00:00
Joe Haddad
ab05595582 Publish
- @now/build-utils@0.9.14-canary.2
 - @now/cgi@0.1.5-canary.1
 - now@16.1.3-canary.3
 - now-client@5.1.1-canary.1
 - @now/go@0.5.11-canary.1
 - @now/next@0.7.1-canary.3
 - @now/node-bridge@1.2.4-canary.2
 - @now/node@0.12.8-canary.2
 - @now/python@0.2.17-canary.1
 - @now/routing-utils@1.2.3-canary.1
 - @now/ruby@0.1.5-canary.2
 - @now/static-build@0.9.9-canary.2
2019-08-29 23:15:18 -04:00
JJ Kasper
ba8e714329 [now-next] Use patched version of yazl and trace API pages separate (#2919)
* Update to trace API files separately and use modified yazl

* Remove jszip dependency

* Pin yazl dependency and add types

* Update more types
2019-08-30 02:40:45 +00:00
Luc
ef86bb0bd9 [tests] Unify .editorconfig (#2920) 2019-08-29 23:56:10 +00:00
Andy
be18b54bfd [now-cli] Improve check for update command (#2915)
* [now-cli] Improve check for update command

* Use path.sep

* Fix build
2019-08-29 23:47:53 +00:00
Max Strübing
ed168db23c [now-cli] Use XDG standard instead of writing to home directory (#2877)
* Use XDG standard instead of writing to home directory

* Fix typos

* Use dependencies as dev dependencies

* Remove lodash dependency

* Use xdg-app-paths instead of xdg-portable

* use find instead of filter(...)[0]
2019-08-29 23:04:47 +00:00
Luc
236f5f4159 [tests] Unify linting and autoformatting (#2914)
* add prettier and eslint on root

* remove eslint from now-cli

* adjust root package.json

* adjust eslintignore

* adjust now-cli rules

* remove @zeit/git-hooks in packages

* adjust now-client eslint config

* add lint-staged and hook on pre-commit

* add pre-commit script

* replace @zeit/git-hooks with husky

* remove unnecessary script

* fix eslint errors

* trigger tests

* fix fixable errors

* fix fixable errors (bis)

* revert two changes
2019-08-29 19:17:40 +00:00
Steven
e44a91634e [now-cli] Update readme and links (#2886)
* Update readme and links

* Fix readme image

* Fix homepage

* Update banner image to v3
2019-08-29 16:47:36 +00:00
Naoyuki Kanezawa
8b9426eb6c [tests] Remove fixtures files for integration tests (#2910) 2019-08-29 13:57:26 +00:00
Nathan Rajlich
c62c57f122 [now-cli] Implement continue: true with dest (#2908)
Closes #2685.
2019-08-29 12:39:55 +00:00
Nathan Rajlich
c81db0c8d2 [now-cli] Use a Map for the valid sub-commands (#2913)
Otherwise, JavaScript Object built-ins such as `hasOwnProperty` are
incorrectly considered a valid subcommand, but fail afterwards with
a `require()` error and confusing error message.
2019-08-29 07:56:36 +00:00
Naoyuki Kanezawa
1c64990e9f [now-cli] fix login test (#2909) 2019-08-29 05:45:40 +00:00
Joe Haddad
f1dc7fd14a Publish
- now@16.1.3-canary.2
 - @now/next@0.7.1-canary.2
 - @now/node-bridge@1.2.4-canary.1
 - @now/node@0.12.8-canary.1
 - @now/ruby@0.1.5-canary.1
 - @now/static-build@0.9.9-canary.1
2019-08-28 21:18:57 -04:00
Nathan Rajlich
6079d4be25 [now-cli] Remove deprecated @now/php builder from bundled builders tarball (#2907)
`@now/php` has been deprecated in favor of community-maintained
`now-php`, so don't bundle the deprecated builder with Now CLI.
2019-08-29 00:42:06 +00:00
Andy
2c4b8335ce [now-cli] Allow to fetch more certificates with paging (#2905)
* [now-cli] Allow to fetch more certificates with paging

* Linting

* Update packages/now-cli/src/commands/certs/ls.js

Co-Authored-By: Nathan Rajlich <n@n8.io>
2019-08-28 23:51:10 +00:00
JJ Kasper
9bd2f22d5c [now-next] Optimize lambda creation (#2892)
* Optimize zipping lambdas for now-next

* Update to use jszip to get around bug in yazl

* Add pseudo layer utils

* Apply suggestions from code review

Co-Authored-By: Joe Haddad <joe.haddad@zeit.co>

* Update sema concurrency from tests

* Update packages/now-next/src/index.ts

* Use custom types to fix broken @types package

* Add license header

* Revert "Use custom types to fix broken @types package"

This reverts commit 82441285155f6e0899c43dffdd5e000ecbd7b1b6.

* Fix CI Yarn installation

* TypeScript types should never be hoisted

* Fix all typechecking
2019-08-28 22:43:26 +00:00
Andy
7c421f92e1 [now-cli] Validate inputs for alias, list and remove (#2903)
* [now-cli] Validate inputs for alias, list and remove

* Log test output

* Add more logging to test

* Change to execa

* Use `split`

* Only validate when it exists
2019-08-28 21:30:27 +00:00
Andy
0626db51bd [now-cli] Change success message after login (#2898)
* [now-cli] Change success message after login

* Linting

* Test now login

* Linting

* Revert "Test now login"

This reverts commit 690360db3f148552a456b4ee1bd2a59b8d09216c.

* Revert "Linting"

This reverts commit 3d5ebfaa76ecdcc2152c8344c8e1205b241abe09.

* Adjust test

* Remove binaryPath from args

* Fix loggin test
2019-08-28 22:41:56 +02:00
Kaito Sugimoto
dc29a8b816 [now-cli] Update now alias warning for --prod (#2902) 2019-08-28 18:27:21 +00:00
Joe Haddad
e00e5e18ea Publish
- @now/build-utils@0.9.14-canary.1
 - now@16.1.3-canary.1
 - @now/next@0.7.1-canary.1
2019-08-28 08:28:56 -04:00
Joe Haddad
d0999e7937 [now-build-utils] Add mutable option for backwards compatibility (#2895) 2019-08-28 05:29:34 +00:00
Joe Haddad
158cfad978 [now-next] Do not add initial files to lambda (#2894) 2019-08-28 02:14:02 +00:00
Andy
9145b43a62 [now alias] Improve alias support (#2787)
This enables https://github.com/zeit/now-cli/pull/2747 from @nkzawa again.

We had to revert the previous one, because we didn't want to include it in
the next stable release.

This further makes sure that we don't display `https://` in front of a
wildcard alias, since `https://*.mydomain.tld` is not a valid URL.
2019-08-28 00:47:39 +00:00
171 changed files with 12649 additions and 1591 deletions

View File

@@ -1,6 +1,5 @@
version: 2
jobs:
install:
docker:
- image: circleci/node:10
@@ -11,9 +10,9 @@ jobs:
- checkout
- restore_cache:
keys:
- v1-dependencies-{{ checksum "yarn.lock" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- v1-dependencies-{{ checksum "yarn.lock" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- run:
name: Updating apt packages
command: sudo apt-get update
@@ -22,10 +21,11 @@ jobs:
command: sudo apt-get install golang-go
- run:
name: Installing Dependencies
command: yarn install
command: yarn install --check-files --frozen-lockfile
- save_cache:
paths:
- node_modules
- packages/gatsby-plugin-now/node_modules
- packages/now-build-utils/node_modules
- packages/now-cgi/node_modules
- packages/now-cli/node_modules
@@ -43,6 +43,7 @@ jobs:
root: .
paths:
- node_modules
- packages/gatsby-plugin-now/node_modules
- packages/now-build-utils/node_modules
- packages/now-cgi/node_modules
- packages/now-cli/node_modules
@@ -75,6 +76,7 @@ jobs:
- persist_to_workspace:
root: .
paths:
- packages/gatsby-plugin-now/test/fixtures
- packages/now-build-utils/dist
- packages/now-cgi/dist
- packages/now-cli/dist
@@ -91,6 +93,7 @@ jobs:
- packages/now-routing-utils/dist
- packages/now-ruby/dist
- packages/now-static-build/dist
- packages/now-static-build/test/fixtures/10a-gatsby-redirects/plugins
test-lint:
docker:

32
.eslintignore Normal file
View File

@@ -0,0 +1,32 @@
node_modules
dist
# gatsby-plugin-now
packages/gatsby-plugin-now/test/fixtures
# now-cli
packages/now-cli/@types
packages/now-cli/download
packages/now-cli/dist
packages/now-cli/test/fixtures
packages/now-cli/test/dev/fixtures
packages/now-cli/bin
packages/now-cli/link
packages/now-cli/src/util/dev/templates/*.ts
# now-client
packages/now-client/tests/fixtures
packages/now-client/lib
# now-next
packages/now-next/test/fixtures
# now-node
packages/now-node/src/bridge.ts
packages/now-node/test/fixtures
# now-node-bridge
packages/now-node-bridge/bridge.*
# now-static-build
packages/now-static-build/test/fixtures

64
.eslintrc.json Normal file
View File

@@ -0,0 +1,64 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"modules": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
"prettier/@typescript-eslint"
],
"env": {
"node": true,
"jest": true,
"es6": true
},
"rules": {
"require-atomic-updates": 0,
"@typescript-eslint/ban-ts-ignore": 0,
"@typescript-eslint/camelcase": 0,
"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/no-use-before-define": 0
},
"overrides": [
{
"files": ["**/*.js"],
"rules": {
"@typescript-eslint/no-var-requires": "off"
}
},
{
"files": ["packages/now-cli/**/*"],
"rules": {
"lines-between-class-members": 0,
"no-async-promise-executor": 0,
"no-control-regex": 0,
"no-empty": 0,
"prefer-const": 0,
"prefer-destructuring": 0,
"@typescript-eslint/ban-types": 0,
"@typescript-eslint/consistent-type-assertions": 0,
"@typescript-eslint/member-delimiter-style": 0,
"@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-inferrable-types": 0,
"@typescript-eslint/no-var-requires": 0
}
},
{
"files": ["packages/now-client/**/*"],
"rules": {
"prefer-const": 0,
"require-atomic-updates": 0,
"@typescript-eslint/ban-ts-ignore": 0,
"@typescript-eslint/no-explicit-any": 0
}
}
]
}

View File

@@ -24,7 +24,7 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
- name: Install
run: yarn install --pure-lockfile
run: yarn install --check-files --frozen-lockfile
- name: Build
run: yarn build
- name: Publish

1
.gitignore vendored
View File

@@ -16,3 +16,4 @@ packages/now-cli/test/**/node_modules
packages/now-cli/test/dev/fixtures/08-hugo/hugo
packages/now-cli/test/dev/fixtures/**/dist
packages/now-cli/test/dev/fixtures/**/public
packages/now-cli/test/fixtures/integration

4
.prettierrc Normal file
View File

@@ -0,0 +1,4 @@
{
"singleQuote": true,
"trailingCommas": "es5"
}

View File

@@ -1,9 +1,9 @@
![now](https://assets.zeit.co/image/upload/v1542240976/repositories/now-cli/now-cli-repo-banner-v2.png)
![now](https://assets.zeit.co/image/upload/v1542240976/repositories/now-cli/now-cli-repo-banner-v3.png)
[![Build Status](https://circleci.com/gh/zeit/now-cli.svg?&style=shield)](https://circleci.com/gh/zeit/workflows/now-cli)
[![Build Status](https://circleci.com/gh/zeit/now.svg?&style=shield)](https://circleci.com/gh/zeit/workflows/now)
[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/zeit)
**Note**: The [canary](https://github.com/zeit/now-cli/tree/canary) branch is under heavy development the stable release branch is [master](https://github.com/zeit/now-cli/tree/master).
**Note**: The [canary](https://github.com/zeit/now/tree/canary) branch is under heavy development the stable release branch is [master](https://github.com/zeit/now/tree/master).
## Usage
@@ -34,8 +34,8 @@ For details on how to use Now CLI, check out our [documentation](https://zeit.co
4. Link the package to the global module directory: `yarn link`
5. You can now start using `now` anywhere inside the command line
As always, you should use `yarn test` to run the tests and see if your changes have broken anything.
As always, you should use `yarn test-unit` to run the tests and see if your changes have broken anything.
## How to Create a Release
If you have write access to this repository, you can read more about how to publish a release [here](https://github.com/zeit/now-cli/wiki/Creating-a-Release).
If you have write access to this repository, you can read more about how to publish a release [here](https://github.com/zeit/now/wiki/Creating-a-Release).

View File

@@ -1,32 +1,60 @@
{
"name": "now-builders",
"version": "0.0.0",
"private": true,
"license": "MIT",
"workspaces": [
"packages/*"
],
"dependencies": {
"lerna": "3.16.4"
},
"devDependencies": {
"@zeit/ncc": "0.20.4",
"async-retry": "1.2.3",
"buffer-replace": "1.0.0",
"node-fetch": "2.6.0"
},
"scripts": {
"lerna": "lerna",
"bootstrap": "lerna bootstrap",
"publish-stable": "git checkout master && git pull && lerna version --exact",
"publish-canary": "git checkout canary && git pull && lerna version prerelease --preid canary --exact",
"publish-from-github": "./.circleci/publish.sh",
"build": "node run.js build all",
"test-lint": "node run.js test-lint",
"test-unit": "node run.js test-unit",
"test-integration": "node run.js test-integration",
"test-integration-once": "node run.js test-integration-once",
"test-integration-now-dev": "node run.js test-integration-now-dev"
"name": "now-builders",
"version": "0.0.0",
"private": true,
"license": "MIT",
"workspaces": {
"packages": [
"packages/*"
],
"nohoist": [
"**/@types/**"
]
},
"dependencies": {
"lerna": "3.16.4"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "2.0.0",
"@typescript-eslint/parser": "2.0.0",
"@zeit/ncc": "0.20.4",
"async-retry": "1.2.3",
"buffer-replace": "1.0.0",
"eslint": "6.2.2",
"eslint-config-prettier": "6.1.0",
"husky": "3.0.4",
"lint-staged": "9.2.5",
"node-fetch": "2.6.0",
"prettier": "1.18.2"
},
"scripts": {
"lerna": "lerna",
"bootstrap": "lerna bootstrap",
"publish-stable": "git checkout master && git pull && lerna version --exact",
"publish-canary": "git checkout canary && git pull && lerna version prerelease --preid canary --exact",
"publish-from-github": "./.circleci/publish.sh",
"build": "node run.js build all",
"test-lint": "node run.js test-lint",
"test-unit": "node run.js test-unit",
"test-integration": "node run.js test-integration",
"test-integration-once": "node run.js test-integration-once",
"test-integration-now-dev": "node run.js test-integration-now-dev",
"lint": "eslint . --ext .ts,.js"
},
"lint-staged": {
"*.{js,ts}": [
"prettier --write",
"eslint",
"git add"
],
"*.{json,md}": [
"prettier --write",
"git add"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
}
}

View File

@@ -0,0 +1,6 @@
#!/bin/bash
set -euo pipefail
# build fixtures for tests
yarn --cwd test/fixtures install
yarn --cwd test/fixtures run build

View File

@@ -0,0 +1,33 @@
const path = require('path');
const writeFile = require('util').promisify(require('fs').writeFile);
const REDIRECT_FILE_NAME = '__now_routes_g4t5bY.json';
exports.onPostBuild = async ({ store }) => {
const { redirects, program } = store.getState();
if (!redirects.length === 0) {
return;
}
const routes = [{ handle: 'filesystem' }];
for (const redirect of redirects) {
const route = {
src: redirect.fromPath,
status: redirect.statusCode || (redirect.isPermanent ? 301 : 302),
headers: { Location: redirect.toPath }
};
if (redirect.force) {
routes.unshift(route);
} else {
routes.push(route);
}
}
await writeFile(
path.join(program.directory, 'public', REDIRECT_FILE_NAME),
JSON.stringify(routes)
);
};

View File

@@ -0,0 +1 @@
// noop

View File

@@ -0,0 +1,32 @@
{
"name": "gatsby-plugin-now",
"version": "1.2.1-canary.0",
"main": "index.js",
"license": "MIT",
"homepage": "https://github.com/zeit/now/tree/canary/packages/gatsby-plugin-now",
"repository": {
"type": "git",
"url": "https://github.com/zeit/now.git",
"directory": "packages/gatsby-plugin-now"
},
"scripts": {
"build": "./build.sh",
"test-integration-once": "jest --verbose"
},
"files": [
"index.js",
"gatsby-node.js"
],
"peerDependencies": {
"gatsby": ">=2.0.0"
},
"devDependencies": {
"jest": "24.9.0"
},
"jest": {
"testPathIgnorePatterns": [
"/node_modules/",
"<rootDir>/test/fixtures/"
]
}
}

View File

@@ -0,0 +1,24 @@
# gatsby-plugin-now
This plugin generates [Now Routes](https://zeit.co/docs/v2/advanced/routes) for [redirects](https://www.gatsbyjs.org/docs/actions/#createRedirect) you configured for to your Gatsby project.
### Usage
1. Install the plugin:
```
npm install gatsby-plugin-now --save-dev
```
2. Add it to the configuration file:
```
// gatsby-config.js
module.exports = {
plugins: [
'gatsby-plugin-now'
]
}
```
3. [Deploy your project to ZEIT Now](https://www.gatsbyjs.org/docs/deploying-to-zeit-now/)

View File

@@ -0,0 +1,86 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`test generated now routes 1`] = `
Array [
Object {
"headers": Object {
"Location": "/",
},
"src": "/my-special-redirect",
"status": 302,
},
Object {
"handle": "filesystem",
},
Object {
"headers": Object {
"Location": "/page-2",
},
"src": "/page2",
"status": 301,
},
Object {
"headers": Object {
"Location": "/page-2/",
},
"src": "/page2/",
"status": 301,
},
Object {
"headers": Object {
"Location": "/",
},
"src": "/orange",
"status": 302,
},
Object {
"headers": Object {
"Location": "/",
},
"src": "/grape",
"status": 302,
},
Object {
"headers": Object {
"Location": "/page-2/",
},
"src": "/blue",
"status": 302,
},
Object {
"headers": Object {
"Location": "/page-2/",
},
"src": "/randirect",
"status": 302,
},
Object {
"headers": Object {
"Location": "/",
},
"src": "/juice",
"status": 302,
},
Object {
"headers": Object {
"Location": "/",
},
"src": "/soda",
"status": 302,
},
Object {
"headers": Object {
"Location": "/page-2/",
},
"src": "/donut",
"status": 302,
},
Object {
"headers": Object {
"Location": "/page-2/",
},
"src": "/randorect",
"status": 302,
},
]
`;

View File

@@ -0,0 +1,4 @@
public
node_modules
.cache
yarn.lock

View File

@@ -0,0 +1,3 @@
module.exports = {
plugins: [{ resolve: require.resolve('../../') }]
};

View File

@@ -0,0 +1,105 @@
'use strict';
// Implement the Gatsby API “createPages”. This is called once the
// data layer is bootstrapped to let plugins create pages from data.
exports.createPages = ({ actions }) => {
// need createRedirect action in actions collection
// to make the redirection magic happen.
// https://www.gatsbyjs.org/docs/bound-action-creators/
const { createRedirect } = actions;
// Lets set up some string consts to use thoroughout the following.
// MDN > JavaScript reference > Statements and declarations
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
// Maybe we usually redirect to page 2, with trailing slash.
const page2Path = `/page-2/`;
// But sometimes to homepage.
const homePath = `/`;
// One-off redirect, note trailing slash missing on fromPath and
// toPath here.
createRedirect({
fromPath: `/page2`,
isPermanent: true,
redirectInBrowser: true,
toPath: `/page-2`
});
// Another one-off redirect, note trailing slash on toPath here.
// This time we want trailing slash on toPath so we use
// page2Path. Need to handle trailing-slashed and non-trailing-
// slashed fromPaths separately, Gatsby serves page components
// at either version by default, but we need to explicitly redirect
// both versions independently, more on page components:
// Docs > Building with Components
// https://www.gatsbyjs.org/docs/building-with-components/
// and handling trailing slashes:
// Docs > Creating and modifying pages > Removing trailing slashes
// https://www.gatsbyjs.org/docs/creating-and-modifying-pages/#removing-trailing-slashes
createRedirect({
fromPath: `/page2/`,
isPermanent: true,
redirectInBrowser: true,
toPath: page2Path
});
// One approach to handle several redirects at once is to create an
// array of from/to path pairs.
let redirectBatch1 = [
{ f: `/orange`, t: `/` },
// We could use homePath and page2Path directly here.
{ f: `/grape`, t: homePath },
{ f: `/blue`, t: page2Path },
// or leave to empty and swap for page2Path later on.
{ f: `/randirect`, t: `` }
];
// Then we can loop through the array of object literals to create
// each redirect. A for loop would do the trick
for (var { f: f, t: t } of redirectBatch1) {
// Here we swap any empty toPath values for trusty page 2 via
// page2Path.
if (t === ``) {
t = page2Path;
}
createRedirect({
fromPath: f,
redirectInBrowser: true,
toPath: t
});
// Uncomment next line to see loop in action during build
// console.log('\nRedirecting:\n' + f + '\nTo:\n' + t + '\n');
// or check .cache/redirects.json post-compile.
}
// A more modern approach might use forEach rather than for...of
// Compare
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration#for...of_statement
// and
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
let redirectBatch2 = [
{ f: `/juice`, t: `/` },
{ f: `/soda`, t: `/` },
{ f: `/donut`, t: page2Path },
{ f: `/randorect`, t: `` }
];
redirectBatch2.forEach(({ f, t }) => {
if (t === ``) {
t = page2Path;
}
createRedirect({
fromPath: f,
redirectInBrowser: true,
toPath: t
});
// Uncomment next line to see forEach in action during build
// console.log('\nRedirecting:\n' + f + '\nTo:\n' + t + '\n');
});
createRedirect({
fromPath: '/my-special-redirect',
toPath: homePath,
force: true
});
};

View File

@@ -0,0 +1,11 @@
{
"name": "fixtures",
"dependencies": {
"gatsby": "2.14.0",
"react": "16.9.0",
"react-dom": "16.9.0"
},
"scripts": {
"build": "gatsby build"
}
}

View File

@@ -0,0 +1,9 @@
import React from 'react';
const IndexPage = () => (
<div>
<h1>Hi people</h1>
</div>
);
export default IndexPage;

View File

@@ -0,0 +1,5 @@
test('test generated now routes', async () => {
const nowRoutes = require('./fixtures/public/__now_routes_g4t5bY.json');
expect(nowRoutes).toMatchSnapshot();
});

View File

@@ -1,6 +1,6 @@
{
"name": "@now/build-utils",
"version": "0.9.14-canary.0",
"version": "1.0.0-canary.2",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",

View File

@@ -10,20 +10,20 @@ interface Options {
tag?: 'canary' | 'latest' | string;
}
const src: string = 'package.json';
const src = 'package.json';
const config: Config = { zeroConfig: true };
const MISSING_BUILD_SCRIPT_ERROR: ErrorResponse = {
code: 'missing_build_script',
message:
'Your `package.json` file is missing a `build` property inside the `script` property.' +
'\nMore details: https://zeit.co/docs/v2/advanced/platform/frequently-asked-questions#missing-build-script',
'\nMore details: https://zeit.co/docs/v2/advanced/platform/frequently-asked-questions#missing-build-script'
};
// Static builders are special cased in `@now/static-build`
function getBuilders(): Map<string, Builder> {
return new Map<string, Builder>([
['next', { src, use: '@now/next', config }],
['next', { src, use: '@now/next', config }]
]);
}
@@ -35,7 +35,7 @@ function getApiBuilders(): Builder[] {
{ src: 'api/**/*.ts', use: '@now/node', config },
{ src: 'api/**/*.go', use: '@now/go', config },
{ src: 'api/**/*.py', use: '@now/python', config },
{ src: 'api/**/*.rb', use: '@now/ruby', config },
{ src: 'api/**/*.rb', use: '@now/ruby', config }
];
}
@@ -96,8 +96,8 @@ async function detectApiBuilders(files: string[]): Promise<Builder[]> {
.sort(sortFiles)
.filter(ignoreApiFilter)
.map(file => {
const result = getApiBuilders().find(
({ src }): boolean => minimatch(file, src)
const result = getApiBuilders().find(({ src }): boolean =>
minimatch(file, src)
);
return result ? { ...result, src: file } : null;
@@ -138,7 +138,7 @@ export async function detectBuilders(
builders.push({
use: '@now/static',
src: 'public/**/*',
config,
config
});
} else if (builders.length > 0) {
// We can't use pattern matching, since `!(api)` and `!(api)/**/*`
@@ -150,7 +150,7 @@ export async function detectBuilders(
.map(name => ({
use: '@now/static',
src: name,
config,
config
}))
);
}
@@ -177,6 +177,6 @@ export async function detectBuilders(
return {
builders: builders.length ? builders : null,
errors: errors.length ? errors : null,
errors: errors.length ? errors : null
};
}

View File

@@ -43,37 +43,35 @@ function getSegmentName(segment: string): string | null {
function createRouteFromPath(filePath: string): Route {
const parts = filePath.split('/');
let counter: number = 1;
let counter = 1;
const query: string[] = [];
const srcParts = parts.map(
(segment, index): string => {
const name = getSegmentName(segment);
const isLast = index === parts.length - 1;
const srcParts = parts.map((segment, index): string => {
const name = getSegmentName(segment);
const isLast = index === parts.length - 1;
if (name !== null) {
// We can't use `URLSearchParams` because `$` would get escaped
query.push(`${name}=$${counter++}`);
return `([^\\/]+)`;
} else if (isLast) {
const { name: fileName, ext } = parsePath(segment);
const isIndex = fileName === 'index';
const prefix = isIndex ? '\\/' : '';
if (name !== null) {
// We can't use `URLSearchParams` because `$` would get escaped
query.push(`${name}=$${counter++}`);
return `([^\\/]+)`;
} else if (isLast) {
const { name: fileName, ext } = parsePath(segment);
const isIndex = fileName === 'index';
const prefix = isIndex ? '\\/' : '';
const names = [
prefix,
prefix + escapeName(fileName),
prefix + escapeName(fileName) + escapeName(ext),
].filter(Boolean);
const names = [
prefix,
prefix + escapeName(fileName),
prefix + escapeName(fileName) + escapeName(ext)
].filter(Boolean);
// Either filename with extension, filename without extension
// or nothing when the filename is `index`
return `(${names.join('|')})${isIndex ? '?' : ''}`;
}
return segment;
// Either filename with extension, filename without extension
// or nothing when the filename is `index`
return `(${names.join('|')})${isIndex ? '?' : ''}`;
}
);
return segment;
});
const { name: fileName } = parsePath(filePath);
const isIndex = fileName === 'index';
@@ -230,8 +228,8 @@ async function detectApiRoutes(files: string[]): Promise<RoutesResult> {
message:
`The segment "${conflictingSegment}" occurres more than ` +
`one time in your path "${file}". Please make sure that ` +
`every segment in a path is unique`,
},
`every segment in a path is unique`
}
};
}
@@ -251,8 +249,8 @@ async function detectApiRoutes(files: string[]): Promise<RoutesResult> {
message:
`Two or more files have conflicting paths or names. ` +
`Please make sure path segments and filenames, without their extension, are unique. ` +
`The path "${file}" has conflicts with ${messagePaths}`,
},
`The path "${file}" has conflicts with ${messagePaths}`
}
};
}
@@ -263,7 +261,7 @@ async function detectApiRoutes(files: string[]): Promise<RoutesResult> {
if (defaultRoutes.length) {
defaultRoutes.push({
status: 404,
src: '/api(\\/.*)?$',
src: '/api(\\/.*)?$'
});
}
@@ -289,7 +287,7 @@ export async function detectRoutes(
if (routesResult.defaultRoutes && hasPublicBuilder(builders)) {
routesResult.defaultRoutes.push({
src: '/(.*)',
dest: '/public/$1',
dest: '/public/$1'
});
}

View File

@@ -8,6 +8,7 @@ import { File } from './types';
interface FileRefOptions {
mode?: number;
digest: string;
mutable?: boolean;
}
const semaToDownloadFromS3 = new Sema(5);
@@ -25,13 +26,15 @@ export default class FileRef implements File {
public type: 'FileRef';
public mode: number;
public digest: string;
private mutable: boolean;
constructor({ mode = 0o100644, digest }: FileRefOptions) {
constructor({ mode = 0o100644, digest, mutable = false }: FileRefOptions) {
assert(typeof mode === 'number');
assert(typeof digest === 'string');
this.type = 'FileRef';
this.mode = mode;
this.digest = digest;
this.mutable = mutable;
}
async toStreamAsync(): Promise<NodeJS.ReadableStream> {
@@ -40,9 +43,11 @@ export default class FileRef implements File {
const [digestType, digestHash] = this.digest.split(':');
if (digestType === 'sha') {
// This CloudFront URL edge caches the `now-files` S3 bucket to prevent
// overloading it
// overloading it. Mutable files cannot be cached.
// `https://now-files.s3.amazonaws.com/${digestHash}`
url = `https://dmmcy0pwk6bqi.cloudfront.net/${digestHash}`;
url = this.mutable
? `https://now-files.s3.amazonaws.com/${digestHash}`
: `https://dmmcy0pwk6bqi.cloudfront.net/${digestHash}`;
} else if (digestType === 'sha+ephemeral') {
// This URL is currently only used for cache files that constantly
// change. We shouldn't cache it on CloudFront because it'd always be a

View File

@@ -1,6 +1,7 @@
import assert from 'assert';
import fs from 'fs-extra';
import path from 'path';
import debug from '../debug';
import spawn from 'cross-spawn';
import { SpawnOptions } from 'child_process';
import { deprecate } from 'util';
@@ -128,8 +129,14 @@ async function scanParentDirs(destPath: string, readPackageJson = false) {
export async function runNpmInstall(
destPath: string,
args: string[] = [],
spawnOpts?: SpawnOptions
spawnOpts?: SpawnOptions,
meta?: Meta
) {
if (meta && meta.isDev) {
debug('Skipping dependency installation because dev mode is enabled');
return;
}
assert(path.isAbsolute(destPath));
let commandArgs = args;

View File

@@ -185,8 +185,8 @@ export interface ShouldServeOptions {
}
export interface PackageJson {
name: string;
version: string;
name?: string;
version?: string;
engines?: {
[key: string]: string;
node: string;

View File

@@ -1,20 +1,16 @@
/* global beforeAll, expect, it, jest */
const path = require('path');
const fs = require('fs-extra');
// eslint-disable-next-line import/no-extraneous-dependencies
const execa = require('execa');
const assert = require('assert');
const { createZip } = require('../dist/lambda');
const {
glob, download, detectBuilders, detectRoutes,
} = require('../');
const { glob, download, detectBuilders, detectRoutes } = require('../');
const {
getSupportedNodeVersion,
defaultSelection,
defaultSelection
} = require('../dist/fs/node-version');
const {
packAndDeploy,
testDeployment,
testDeployment
} = require('../../../test/lib/deployment/test-deployment');
jest.setTimeout(4 * 60 * 1000);
@@ -42,7 +38,7 @@ it('should re-create symlinks properly', async () => {
const [linkStat, aStat] = await Promise.all([
fs.lstat(path.join(outDir, 'link.txt')),
fs.lstat(path.join(outDir, 'a.txt')),
fs.lstat(path.join(outDir, 'a.txt'))
]);
assert(linkStat.isSymbolicLink());
assert(aStat.isFile());
@@ -64,7 +60,7 @@ it('should create zip files with symlinks properly', async () => {
const [linkStat, aStat] = await Promise.all([
fs.lstat(path.join(outDir, 'link.txt')),
fs.lstat(path.join(outDir, 'a.txt')),
fs.lstat(path.join(outDir, 'a.txt'))
]);
assert(linkStat.isSymbolicLink());
assert(aStat.isFile());
@@ -86,33 +82,33 @@ it('should match all semver ranges', () => {
// See https://docs.npmjs.com/files/package.json#engines
expect(getSupportedNodeVersion('10.0.0')).resolves.toHaveProperty(
'major',
10,
10
);
expect(getSupportedNodeVersion('10.x')).resolves.toHaveProperty('major', 10);
expect(getSupportedNodeVersion('>=10')).resolves.toHaveProperty('major', 10);
expect(getSupportedNodeVersion('>=10.3.0')).resolves.toHaveProperty(
'major',
10,
10
);
expect(getSupportedNodeVersion('8.5.0 - 10.5.0')).resolves.toHaveProperty(
'major',
10,
10
);
expect(getSupportedNodeVersion('>=9.0.0')).resolves.toHaveProperty(
'major',
10,
10
);
expect(getSupportedNodeVersion('>=9.5.0 <=10.5.0')).resolves.toHaveProperty(
'major',
10,
10
);
expect(getSupportedNodeVersion('~10.5.0')).resolves.toHaveProperty(
'major',
10,
10
);
expect(getSupportedNodeVersion('^10.5.0')).resolves.toHaveProperty(
'major',
10,
10
);
});
@@ -124,7 +120,7 @@ it('should support require by path for legacy builders', () => {
const glob2 = require('@now/build-utils/fs/glob.js');
const rename2 = require('@now/build-utils/fs/rename.js');
const {
runNpmInstall: runNpmInstall2,
runNpmInstall: runNpmInstall2
} = require('@now/build-utils/fs/run-user-scripts.js');
const streamToBuffer2 = require('@now/build-utils/fs/stream-to-buffer.js');
@@ -162,8 +158,8 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
await expect(
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture),
),
path.join(fixturesPath, fixture)
)
).resolves.toBeDefined();
});
}
@@ -176,7 +172,7 @@ const buildersToTestWith = ['now-next', 'now-node', 'now-static-build'];
for (const builder of buildersToTestWith) {
const fixturesPath2 = path.resolve(
__dirname,
`../../${builder}/test/fixtures`,
`../../${builder}/test/fixtures`
);
// eslint-disable-next-line no-restricted-syntax
@@ -188,8 +184,8 @@ for (const builder of buildersToTestWith) {
await expect(
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath2, fixture),
),
path.join(fixturesPath2, fixture)
)
).resolves.toBeDefined();
});
}
@@ -210,7 +206,7 @@ it('Test `detectBuilders`', async () => {
// package.json + no build + next
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
dependencies: { next: '9.0.0' }
};
const files = ['package.json', 'pages/index.js'];
const { builders, errors } = await detectBuilders(files, pkg);
@@ -222,7 +218,7 @@ it('Test `detectBuilders`', async () => {
// package.json + no build + next
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
devDependencies: { next: '9.0.0' }
};
const files = ['package.json', 'pages/index.js'];
const { builders, errors } = await detectBuilders(files, pkg);
@@ -286,7 +282,7 @@ it('Test `detectBuilders`', async () => {
const files = [
'api/_utils/handler.js',
'api/[endpoint]/.helper.js',
'api/[endpoint]/[id].js',
'api/[endpoint]/[id].js'
];
const { builders } = await detectBuilders(files);
@@ -299,7 +295,7 @@ it('Test `detectBuilders`', async () => {
// api + next + public
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
devDependencies: { next: '9.0.0' }
};
const files = ['package.json', 'api/endpoint.js', 'public/index.html'];
@@ -315,7 +311,7 @@ it('Test `detectBuilders`', async () => {
// api + next + raw static
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
devDependencies: { next: '9.0.0' }
};
const files = ['package.json', 'api/endpoint.js', 'index.html'];
@@ -347,7 +343,7 @@ it('Test `detectBuilders`', async () => {
'api/endpoint.js',
'public/index.html',
'public/favicon.ico',
'README.md',
'README.md'
];
const { builders } = await detectBuilders(files);
@@ -371,7 +367,7 @@ it('Test `detectBuilders`', async () => {
// next + public
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
devDependencies: { next: '9.0.0' }
};
const files = ['package.json', 'public/index.html', 'README.md'];
@@ -385,7 +381,7 @@ it('Test `detectBuilders`', async () => {
// nuxt
const pkg = {
scripts: { build: 'nuxt build' },
dependencies: { nuxt: '2.8.1' },
dependencies: { nuxt: '2.8.1' }
};
const files = ['package.json', 'pages/index.js'];
@@ -437,12 +433,12 @@ it('Test `detectBuilders`', async () => {
// package.json + api + canary
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
dependencies: { next: '9.0.0' }
};
const files = [
'pages/index.js',
'api/[endpoint].js',
'api/[endpoint]/[id].js',
'api/[endpoint]/[id].js'
];
const { builders } = await detectBuilders(files, pkg, { tag: 'canary' });
@@ -456,12 +452,12 @@ it('Test `detectBuilders`', async () => {
// package.json + api + latest
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
dependencies: { next: '9.0.0' }
};
const files = [
'pages/index.js',
'api/[endpoint].js',
'api/[endpoint]/[id].js',
'api/[endpoint]/[id].js'
];
const { builders } = await detectBuilders(files, pkg, { tag: 'latest' });
@@ -475,12 +471,12 @@ it('Test `detectBuilders`', async () => {
// package.json + api + random tag
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
dependencies: { next: '9.0.0' }
};
const files = [
'pages/index.js',
'api/[endpoint].js',
'api/[endpoint]/[id].js',
'api/[endpoint]/[id].js'
];
const { builders } = await detectBuilders(files, pkg, { tag: 'haha' });
@@ -549,7 +545,7 @@ it('Test `detectRoutes`', async () => {
const files = [
'public/index.html',
'api/[endpoint].js',
'api/[endpoint]/[id].js',
'api/[endpoint]/[id].js'
];
const { builders } = await detectBuilders(files);
@@ -564,7 +560,7 @@ it('Test `detectRoutes`', async () => {
{
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
devDependencies: { next: '9.0.0' }
};
const files = ['public/index.html', 'api/[endpoint].js'];
@@ -592,7 +588,7 @@ it('Test `detectRoutes`', async () => {
expect(defaultRoutes.length).toBe(3);
expect(defaultRoutes[0].src).toBe(
'^/api/date(\\/|\\/index|\\/index\\.js)?$',
'^/api/date(\\/|\\/index|\\/index\\.js)?$'
);
expect(defaultRoutes[0].dest).toBe('/api/date/index.js');
expect(defaultRoutes[1].src).toBe('^/api/(date|date\\.js)$');
@@ -607,7 +603,7 @@ it('Test `detectRoutes`', async () => {
expect(defaultRoutes.length).toBe(3);
expect(defaultRoutes[0].src).toBe(
'^/api/([^\\/]+)(\\/|\\/index|\\/index\\.js)?$',
'^/api/([^\\/]+)(\\/|\\/index|\\/index\\.js)?$'
);
expect(defaultRoutes[0].dest).toBe('/api/[date]/index.js?date=$1');
expect(defaultRoutes[1].src).toBe('^/api/(date|date\\.js)$');
@@ -621,7 +617,7 @@ it('Test `detectRoutes`', async () => {
'api/users/index.ts',
'api/users/index.d.ts',
'api/food.ts',
'api/ts/gold.ts',
'api/ts/gold.ts'
];
const { builders } = await detectBuilders(files);
const { defaultRoutes } = await detectRoutes(files, builders);
@@ -645,39 +641,39 @@ it('Test `detectBuilders` and `detectRoutes`', async () => {
{
path: '/api/my-endpoint',
mustContain: 'my-endpoint',
status: 200,
status: 200
},
{
path: '/api/other-endpoint',
mustContain: 'other-endpoint',
status: 200,
status: 200
},
{
path: '/api/team/zeit',
mustContain: 'team/zeit',
status: 200,
status: 200
},
{
path: '/api/user/myself',
mustContain: 'user/myself',
status: 200,
status: 200
},
{
path: '/api/not-okay/',
status: 404,
status: 404
},
{
path: '/api',
status: 404,
status: 404
},
{
path: '/api/',
status: 404,
status: 404
},
{
path: '/',
mustContain: 'hello from index.txt',
},
mustContain: 'hello from index.txt'
}
];
const { builders } = await detectBuilders(files, pkg);
@@ -686,12 +682,12 @@ it('Test `detectBuilders` and `detectRoutes`', async () => {
const nowConfig = { builds: builders, routes: defaultRoutes, probes };
await fs.writeFile(
path.join(fixture, 'now.json'),
JSON.stringify(nowConfig, null, 2),
JSON.stringify(nowConfig, null, 2)
);
const deployment = await testDeployment(
{ builderUrl, buildUtilsUrl },
fixture,
fixture
);
expect(deployment).toBeDefined();
});
@@ -705,32 +701,32 @@ it('Test `detectBuilders` and `detectRoutes` with `index` files', async () => {
const probes = [
{
path: '/api/not-okay',
status: 404,
status: 404
},
{
path: '/api',
mustContain: 'hello from api/index.js',
status: 200,
status: 200
},
{
path: '/api/',
mustContain: 'hello from api/index.js',
status: 200,
status: 200
},
{
path: '/api/index',
mustContain: 'hello from api/index.js',
status: 200,
status: 200
},
{
path: '/api/index.js',
mustContain: 'hello from api/index.js',
status: 200,
status: 200
},
{
path: '/api/date.js',
mustContain: 'hello from api/date.js',
status: 200,
status: 200
},
{
// Someone might expect this to be `date.js`,
@@ -739,27 +735,27 @@ it('Test `detectBuilders` and `detectRoutes` with `index` files', async () => {
// so it is not special cased
path: '/api/date',
mustContain: 'hello from api/date/index.js',
status: 200,
status: 200
},
{
path: '/api/date/',
mustContain: 'hello from api/date/index.js',
status: 200,
status: 200
},
{
path: '/api/date/index',
mustContain: 'hello from api/date/index.js',
status: 200,
status: 200
},
{
path: '/api/date/index.js',
mustContain: 'hello from api/date/index.js',
status: 200,
status: 200
},
{
path: '/',
mustContain: 'hello from index.txt',
},
mustContain: 'hello from index.txt'
}
];
const { builders } = await detectBuilders(files, pkg);
@@ -768,12 +764,12 @@ it('Test `detectBuilders` and `detectRoutes` with `index` files', async () => {
const nowConfig = { builds: builders, routes: defaultRoutes, probes };
await fs.writeFile(
path.join(fixture, 'now.json'),
JSON.stringify(nowConfig, null, 2),
JSON.stringify(nowConfig, null, 2)
);
const deployment = await testDeployment(
{ builderUrl, buildUtilsUrl },
fixture,
fixture
);
expect(deployment).toBeDefined();
});

View File

@@ -1,32 +0,0 @@
root = true
[*]
indent_style = tab
indent_size = 4
tab_width = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[{*.json,*.json.example,*.gyp,*.yml}]
indent_style = space
indent_size = 2
[*.py]
indent_style = space
indent_size = 4
[*.md]
trim_trailing_whitespace = false
# Ideal settings - some plugins might support these.
[*.js]
quote_type = single
[{*.c,*.cc,*.h,*.hh,*.cpp,*.hpp,*.m,*.mm,*.mpp,*.js,*.java,*.go,*.rs,*.php,*.ng,*.jsx,*.ts,*.d,*.cs,*.swift}]
curly_bracket_next_line = false
spaces_around_operators = true
spaces_around_brackets = outside
# close enough to 1TB
indent_brace_style = K&R

View File

@@ -1,2 +1 @@
node_modules
handler

View File

@@ -1,17 +1,15 @@
const path = require('path');
const { mkdirp, copyFile } = require('fs-extra');
const glob = require('@now/build-utils/fs/glob'); // eslint-disable-line import/no-extraneous-dependencies
const download = require('@now/build-utils/fs/download'); // eslint-disable-line import/no-extraneous-dependencies
const { createLambda } = require('@now/build-utils/lambda'); // eslint-disable-line import/no-extraneous-dependencies
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory'); // eslint-disable-line import/no-extraneous-dependencies
const { shouldServe } = require('@now/build-utils'); // eslint-disable-line import/no-extraneous-dependencies
const glob = require('@now/build-utils/fs/glob');
const download = require('@now/build-utils/fs/download');
const { createLambda } = require('@now/build-utils/lambda');
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory');
const { shouldServe } = require('@now/build-utils');
exports.analyze = ({ files, entrypoint }) => files[entrypoint].digest;
exports.build = async ({
workPath, files, entrypoint, meta,
}) => {
exports.build = async ({ workPath, files, entrypoint, meta }) => {
console.log('downloading files...');
const outDir = await getWritableDirectory();
@@ -26,7 +24,7 @@ exports.build = async ({
// For now only the entrypoint file is copied into the lambda
await copyFile(
path.join(workPath, entrypoint),
path.join(outDir, entrypoint),
path.join(outDir, entrypoint)
);
const lambda = await createLambda({
@@ -34,12 +32,12 @@ exports.build = async ({
handler: 'handler',
runtime: 'go1.x',
environment: {
SCRIPT_FILENAME: entrypoint,
},
SCRIPT_FILENAME: entrypoint
}
});
return {
[entrypoint]: lambda,
[entrypoint]: lambda
};
};

View File

@@ -1,6 +1,6 @@
{
"name": "@now/cgi",
"version": "0.1.5-canary.0",
"version": "0.1.5-canary.1",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -1,8 +0,0 @@
@types
download
dist
test/fixtures
test/dev/fixtures
bin
link
src/util/dev/templates/*.ts

View File

@@ -1,86 +0,0 @@
module.exports = {
'extends': [
'airbnb',
'prettier'
],
'parser': '@typescript-eslint/parser',
'parserOptions': {
'ecmaVersion': 2018,
'sourceType': 'module',
'modules': true
},
'plugins': [
'@typescript-eslint'
],
'settings': {
'import/resolver': {
'typescript': {
}
}
},
'rules': {
'quotes': [
2,
'single',
{
'allowTemplateLiterals': true
}
],
'class-methods-use-this': 0,
'consistent-return': 0,
'func-names': 0,
'global-require': 0,
'guard-for-in': 0,
'import/no-duplicates': 0,
'import/no-dynamic-require': 0,
'import/no-extraneous-dependencies': 0,
'import/prefer-default-export': 0,
'lines-between-class-members': 0,
'no-await-in-loop': 0,
'no-bitwise': 0,
'no-console': 0,
'no-continue': 0,
'no-control-regex': 0,
'no-empty': 0,
'no-loop-func': 0,
'no-nested-ternary': 0,
'no-param-reassign': 0,
'no-plusplus': 0,
'no-restricted-globals': 0,
'no-restricted-syntax': 0,
'no-shadow': 0,
'no-underscore-dangle': 0,
'no-use-before-define': 0,
'prefer-const': 0,
'prefer-destructuring': 0,
'camelcase': 0,
'no-unused-vars': 0, // in favor of '@typescript-eslint/no-unused-vars'
// 'indent': 0 // in favor of '@typescript-eslint/indent'
'@typescript-eslint/no-unused-vars': 'warn',
// '@typescript-eslint/indent': ['error', 2] // this might conflict with a lot ongoing changes
'@typescript-eslint/no-array-constructor': 'error',
'@typescript-eslint/adjacent-overload-signatures': 'error',
'@typescript-eslint/class-name-casing': 'error',
'@typescript-eslint/interface-name-prefix': 'error',
'@typescript-eslint/no-empty-interface': 'error',
'@typescript-eslint/no-inferrable-types': 'error',
'@typescript-eslint/no-misused-new': 'error',
'@typescript-eslint/no-namespace': 'error',
'@typescript-eslint/no-non-null-assertion': 'error',
'@typescript-eslint/no-parameter-properties': 'error',
'@typescript-eslint/no-triple-slash-reference': 'error',
'@typescript-eslint/prefer-namespace-keyword': 'error',
'@typescript-eslint/type-annotation-spacing': 'error',
// '@typescript-eslint/array-type': 'error',
// '@typescript-eslint/ban-types': 'error',
// '@typescript-eslint/explicit-function-return-type': 'warn',
// '@typescript-eslint/explicit-member-accessibility': 'error',
// '@typescript-eslint/member-delimiter-style': 'error',
// '@typescript-eslint/no-angle-bracket-type-assertion': 'error',
// '@typescript-eslint/no-explicit-any': 'warn',
// '@typescript-eslint/no-object-literal-type-assertion': 'error',
// '@typescript-eslint/no-use-before-define': 'error',
// '@typescript-eslint/no-var-requires': 'error',
// '@typescript-eslint/prefer-interface': 'error'
}
}

View File

@@ -1,3 +0,0 @@
declare module 'cache-or-tmp-directory' {
export default function (appName: string) : string | null
}

View File

@@ -1,3 +0,0 @@
declare module 'pcre-to-regexp' {
export default function (pattern: string, keys?: string[]): RegExp
}

View File

@@ -1,10 +1,7 @@
![now](https://assets.zeit.co/image/upload/v1542240976/repositories/now-cli/now-cli-repo-banner-v2.png)
![now](https://assets.zeit.co/image/upload/v1542240976/repositories/now-cli/now-cli-repo-banner-v3.png)
[![Build Status](https://circleci.com/gh/zeit/now-cli.svg?&style=shield)](https://circleci.com/gh/zeit/workflows/now-cli)
[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/zeit)
**Note**: The [canary](https://github.com/zeit/now-cli/tree/canary) branch is under heavy development the stable release branch is [master](https://github.com/zeit/now-cli/tree/master).
## Usage
To install the latest version of Now CLI, visit [zeit.co/download](https://zeit.co/download) or run this command:
@@ -25,17 +22,3 @@ now # Deploy to the cloud
## Documentation
For details on how to use Now CLI, check out our [documentation](https://zeit.co/docs).
## 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. Install dependencies with `yarn install`
3. Compile the code: `yarn build`
4. Link the package to the global module directory: `yarn link`
5. You can now start using `now` anywhere inside the command line
As always, you should use `yarn test` to run the tests and see if your changes have broken anything.
## How to Create a Release
If you have write access to this repository, you can read more about how to publish a release [here](https://github.com/zeit/now-cli/wiki/Creating-a-Release).

View File

@@ -1,22 +1,25 @@
{
"name": "now",
"version": "16.1.3-canary.0",
"version": "16.1.3-canary.6",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Now",
"repository": "zeit/now-cli",
"homepage": "https://zeit.co",
"repository": {
"type": "git",
"url": "https://github.com/zeit/now.git",
"directory": "packages/now-cli"
},
"scripts": {
"test": "yarn test-lint",
"preinstall": "node ./scripts/preinstall.js",
"test-unit": "nyc ava test/*unit.js --serial --fail-fast --verbose",
"test-integration": "ava test/integration.js --serial --fail-fast",
"test-integration-now-dev": "ava test/dev/integration.js --serial --fail-fast --verbose",
"test-lint": "eslint . --ext .js,.ts",
"prepublishOnly": "yarn build",
"coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov",
"build": "ts-node ./scripts/build.ts",
"build-dev": "ts-node ./scripts/build.ts --dev",
"format-modified": "prettier --parser typescript --write --single-quote `git diff --name-only HEAD * | grep -e \".*\\.ts$\" -e \".*\\.js$\" | xargs echo`"
"test-lint": "eslint . --ext .ts,.js --ignore-path ../../.eslintignore"
},
"nyc": {
"include": [
@@ -37,12 +40,6 @@
"instrument": true,
"all": true
},
"git": {
"pre-commit": [
"test-lint",
"format-modified"
]
},
"bin": {
"now": "./dist/index.js"
},
@@ -64,12 +61,11 @@
"node": ">= 8.11"
},
"devDependencies": {
"@now/build-utils": "0.9.14-canary.0",
"@now/build-utils": "1.0.0-canary.2",
"@now/go": "latest",
"@now/next": "latest",
"@now/node": "latest",
"@now/php": "latest",
"@now/routing-utils": "1.2.3-canary.0",
"@now/routing-utils": "1.2.3-canary.1",
"@now/static-build": "latest",
"@sentry/node": "5.5.0",
"@types/ansi-escapes": "3.0.0",
@@ -101,11 +97,8 @@
"@types/universal-analytics": "0.4.2",
"@types/which": "1.3.1",
"@types/write-json-file": "2.2.1",
"@typescript-eslint/eslint-plugin": "1.6.0",
"@typescript-eslint/parser": "1.1.0",
"@zeit/dockerignore": "0.0.5",
"@zeit/fun": "0.9.1",
"@zeit/git-hooks": "0.1.4",
"@zeit/fun": "0.9.3",
"@zeit/ncc": "0.18.5",
"@zeit/source-map-support": "0.6.2",
"ajv": "6.10.2",
@@ -118,7 +111,6 @@
"async-sema": "2.1.4",
"ava": "2.2.0",
"bytes": "3.0.0",
"cache-or-tmp-directory": "1.0.0",
"chalk": "2.4.2",
"chokidar": "2.1.6",
"clipboardy": "2.1.0",
@@ -137,13 +129,6 @@
"email-validator": "1.1.1",
"epipebomb": "1.0.0",
"escape-html": "1.0.3",
"eslint": "5.16.0",
"eslint-config-airbnb": "17.1.0",
"eslint-config-prettier": "4.1.0",
"eslint-import-resolver-typescript": "1.1.1",
"eslint-plugin-import": "2.16.0",
"eslint-plugin-jsx-a11y": "6.2.1",
"eslint-plugin-react": "7.12.4",
"esm": "3.1.4",
"execa": "1.0.0",
"fetch-h2": "2.0.3",
@@ -165,10 +150,9 @@
"npm-package-arg": "6.1.0",
"nyc": "13.2.0",
"ora": "3.4.0",
"pcre-to-regexp": "0.0.5",
"pcre-to-regexp": "1.0.0",
"pluralize": "7.0.0",
"pre-commit": "1.2.2",
"prettier": "1.16.2",
"printf": "0.2.5",
"progress": "2.0.3",
"promisepipe": "3.0.0",
@@ -197,6 +181,7 @@
"which": "1.3.1",
"which-promise": "1.0.0",
"write-json-file": "2.2.0",
"xdg-app-paths": "5.1.0",
"yarn": "1.17.3"
}
}

View File

@@ -11,7 +11,10 @@ import strlen from '../../util/strlen.ts';
import wait from '../../util/output/wait';
export default async function ls(ctx, opts, args, output) {
const { authConfig: { token }, config } = ctx;
const {
authConfig: { token },
config
} = ctx;
const { currentTeam } = config;
const { apiUrl } = ctx;
const { '--debug': debugEnabled } = opts;
@@ -48,15 +51,13 @@ export default async function ls(ctx, opts, args, output) {
return 1;
}
if (!opts['--json']) {
cancelWait = wait(
args[0]
? `Fetching alias details for "${args[0]}" under ${chalk.bold(
contextName
)}`
: `Fetching aliases under ${chalk.bold(contextName)}`
);
}
cancelWait = wait(
args[0]
? `Fetching alias details for "${args[0]}" under ${chalk.bold(
contextName
)}`
: `Fetching aliases under ${chalk.bold(contextName)}`
);
const aliases = await getAliases(now);
if (cancelWait) cancelWait();
@@ -72,7 +73,7 @@ export default async function ls(ctx, opts, args, output) {
}
if (opts['--json']) {
output.print(JSON.stringify({ rules: alias.rules }, null, 2));
console.log(JSON.stringify({ rules: alias.rules }, null, 2));
} else {
const rules = alias.rules || [];
output.log(
@@ -105,11 +106,11 @@ function printAliasTable(aliases) {
a.rules && a.rules.length
? chalk.cyan(`[${plural('rule', a.rules.length, true)}]`)
: // for legacy reasons, we might have situations
// where the deployment was deleted and the alias
// not collected appropriately, and we need to handle it
a.deployment && a.deployment.url
? a.deployment.url
: chalk.gray(''),
// where the deployment was deleted and the alias
// not collected appropriately, and we need to handle it
a.deployment && a.deployment.url
? a.deployment.url
: chalk.gray(''),
a.alias,
ms(Date.now() - new Date(a.created))
])

View File

@@ -9,6 +9,7 @@ import removeAliasById from '../../util/alias/remove-alias-by-id';
import stamp from '../../util/output/stamp.ts';
import strlen from '../../util/strlen.ts';
import promptBool from '../../util/prompt-bool';
import { isValidName } from '../../util/is-valid-name';
import findAliasByAliasOrId from '../../util/alias/find-alias-by-alias-or-id';
export default async function rm(ctx, opts, args, output) {
@@ -39,11 +40,6 @@ export default async function rm(ctx, opts, args, output) {
const now = new Now({ apiUrl, token, debug: debugEnabled, currentTeam });
const [aliasOrId] = args;
if (!aliasOrId) {
output.error(`${cmd('now alias rm <alias>')} expects one argument`);
return 1;
}
if (args.length !== 1) {
output.error(
`Invalid number of arguments. Usage: ${chalk.cyan(
@@ -53,6 +49,17 @@ export default async function rm(ctx, opts, args, output) {
return 1;
}
if (!aliasOrId) {
output.error(`${cmd('now alias rm <alias>')} expects one argument`);
return 1;
}
// E.g. "/" would not be a valid alias or id
if (!isValidName(aliasOrId)) {
output.error(`The provided argument "${aliasOrId}" is not a valid alias`);
return 1;
}
const alias = await findAliasByAliasOrId(output, now, aliasOrId);
if (!alias) {
output.error(

View File

@@ -17,8 +17,10 @@ import getTargetsForAlias from '../../util/alias/get-targets-for-alias';
import humanizePath from '../../util/humanize-path';
import setupDomain from '../../util/domains/setup-domain';
import stamp from '../../util/output/stamp';
import { isValidName } from '../../util/is-valid-name';
import upsertPathAlias from '../../util/alias/upsert-path-alias';
import handleCertError from '../../util/certs/handle-cert-error';
import isWildcardAlias from '../../util/alias/is-wildcard-alias';
type Options = {
'--debug': boolean;
@@ -77,6 +79,16 @@ export default async function set(
return 1;
}
if (!isValidName(args[0])) {
output.error(`The provided argument "${args[0]}" is not a valid deployment`);
return 1;
}
if (!isValidName(args[1])) {
output.error(`The provided argument "${args[1]}" is not a valid domain`);
return 1;
}
// Read the path alias rules in case there is is given
const rules = await getRulesFromFile(rulesPath);
if (rules instanceof ERRORS.FileNotFound) {
@@ -215,9 +227,12 @@ export default async function set(
if (handleResult === 1) {
return 1;
}
const prefix = isWildcardAlias(handleResult.alias) ? '' : 'https://';
console.log(
`${chalk.cyan('> Success!')} ${chalk.bold(
`https://${handleResult.alias}`
`${prefix}${handleResult.alias}`
)} now points to https://${deployment.url} ${setStamp()}`
);
}

View File

@@ -79,6 +79,7 @@ export default async function main(ctx) {
'--challenge-only': Boolean,
'--overwrite': Boolean,
'--output': String,
'--after': String,
'--crt': String,
'--key': String,
'--ca': String

View File

@@ -4,10 +4,12 @@ import plural from 'pluralize';
import psl from 'psl';
import table from 'text-table';
import Now from '../../util';
import cmd from '../../util/output/cmd';
import Client from '../../util/client.ts';
import getScope from '../../util/get-scope.ts';
import stamp from '../../util/output/stamp.ts';
import getCerts from '../../util/certs/get-certs';
import { CertNotFound } from '../../util/errors-ts';
import strlen from '../../util/strlen.ts';
async function ls(ctx, opts, args, output) {
@@ -15,6 +17,7 @@ async function ls(ctx, opts, args, output) {
const { currentTeam } = config;
const { apiUrl } = ctx;
const debug = opts['--debug'];
const after = opts['--after'];
const client = new Client({ apiUrl, token, currentTeam, debug });
let contextName = null;
@@ -41,16 +44,34 @@ async function ls(ctx, opts, args, output) {
}
// Get the list of certificates
const certs = sortByCn(await getCerts(output, now));
const certificates = await getCerts(output, now, { after }).catch(err => err);
if (certificates instanceof CertNotFound) {
output.error(certificates.message);
return 1;
}
if (certificates instanceof Error) {
throw certificates;
}
const { uid: lastCert } = certificates[certificates.length - 1];
const certs = sortByCn(certificates);
output.log(
`${plural('certificate', certs.length, true)} found under ${chalk.bold(
contextName
)} ${lsStamp()}`
);
if (certs.length >= 100) {
output.note(`There may be more certificates that can be retrieved with ${cmd(`now ${process.argv.slice(2).join(' ')} --after=${lastCert}`)}.`);
}
if (certs.length > 0) {
console.log(formatCertsTable(certs));
}
return 0;
}

View File

@@ -41,6 +41,7 @@ import {
import { SchemaValidationFailed } from '../../util/errors';
import purchaseDomainIfAvailable from '../../util/domains/purchase-domain-if-available';
import handleCertError from '../../util/certs/handle-cert-error';
import isWildcardAlias from '../../util/alias/is-wildcard-alias';
const addProcessEnv = async (log, env) => {
let val;
@@ -71,7 +72,7 @@ const addProcessEnv = async (log, env) => {
};
const deploymentErrorMsg = `Your deployment failed. Please retry later. More: https://err.sh/now/deployment-error`;
const prepareAlias = input => `https://${input}`;
const prepareAlias = input => isWildcardAlias(input) ? input : `https://${input}`;
const printDeploymentStatus = async (
output,

View File

@@ -202,7 +202,6 @@ const promptForEnvFields = async (list: string[]) => {
});
}
// eslint-disable-next-line import/no-unassigned-import
require('../../util/input/patch-inquirer');
log('Please enter values for the following environment variables:');

View File

@@ -1,39 +0,0 @@
export default {
alias: 'alias',
aliases: 'alias',
billing: 'billing',
cc: 'billing',
cert: 'certs',
certs: 'certs',
deploy: 'deploy',
'deploy-v1': 'deploy',
'deploy-v2': 'deploy',
dev: 'dev',
dns: 'dns',
domain: 'domains',
domains: 'domains',
downgrade: 'upgrade',
help: 'help',
init: 'init',
inspect: 'inspect',
list: 'list',
ln: 'alias',
log: 'logs',
login: 'login',
logout: 'logout',
logs: 'logs',
ls: 'list',
project: 'projects',
projects: 'projects',
remove: 'remove',
rm: 'remove',
scale: 'scale',
secret: 'secrets',
secrets: 'secrets',
switch: 'teams',
team: 'teams',
teams: 'teams',
update: 'update',
upgrade: 'upgrade',
whoami: 'whoami'
};

View File

@@ -0,0 +1,39 @@
export default new Map([
[ 'alias', 'alias'],
[ 'aliases', 'alias'],
[ 'billing', 'billing'],
[ 'cc', 'billing'],
[ 'cert', 'certs'],
[ 'certs', 'certs'],
[ 'deploy', 'deploy'],
[ 'deploy-v1', 'deploy'],
[ 'deploy-v2', 'deploy'],
[ 'dev', 'dev'],
[ 'dns', 'dns'],
[ 'domain', 'domains'],
[ 'domains', 'domains'],
[ 'downgrade', 'upgrade'],
[ 'help', 'help'],
[ 'init', 'init'],
[ 'inspect', 'inspect'],
[ 'list', 'list'],
[ 'ln', 'alias'],
[ 'log', 'logs'],
[ 'login', 'login'],
[ 'logout', 'logout'],
[ 'logs', 'logs'],
[ 'ls', 'list'],
[ 'project', 'projects'],
[ 'projects', 'projects'],
[ 'remove', 'remove'],
[ 'rm', 'remove'],
[ 'scale', 'scale'],
[ 'secret', 'secrets'],
[ 'secrets', 'secrets'],
[ 'switch', 'teams'],
[ 'team', 'teams'],
[ 'teams', 'teams'],
[ 'update', 'update'],
[ 'upgrade', 'upgrade'],
[ 'whoami', 'whoami']
]);

View File

@@ -17,6 +17,7 @@ import Client from '../util/client.ts';
import getScope from '../util/get-scope.ts';
import toHost from '../util/to-host';
import parseMeta from '../util/parse-meta';
import { isValidName } from '../util/is-valid-name';
const help = () => {
console.log(`
@@ -135,6 +136,11 @@ export default async function main(ctx) {
return 1;
}
if (app && !isValidName(app)) {
error(`The provided argument "${app}" is not a valid project name`);
return 1;
}
// Some people are using entire domains as app names, so
// we need to account for this here
if (app && toHost(app).endsWith('.now.sh')) {

View File

@@ -5,8 +5,8 @@ import promptEmail from 'email-prompt';
import ms from 'ms';
import { validate as validateEmail } from 'email-validator';
import chalk from 'chalk';
import mri from 'mri';
import ua from '../util/ua.ts';
import getArgs from '../util/get-args';
import error from '../util/output/error';
import aborted from '../util/output/aborted';
import wait from '../util/output/wait';
@@ -14,15 +14,16 @@ import highlight from '../util/output/highlight';
import info from '../util/output/info';
import ok from '../util/output/ok';
import cmd from '../util/output/cmd.ts';
import ready from '../util/output/ready';
import param from '../util/output/param.ts';
import eraseLines from '../util/output/erase-lines';
import sleep from '../util/sleep';
import { handleError } from '../util/error';
import { writeToAuthConfigFile, writeToConfigFile } from '../util/config/files';
import getNowDir from '../util/config/global-path';
import hp from '../util/humanize-path';
import logo from '../util/output/logo';
import exit from '../util/exit';
import createOutput from '../util/output';
import executeLogin from '../util/login/login.ts'
const debug = debugFactory('now:sh:login');
@@ -128,18 +129,23 @@ const readEmail = async () => {
};
const login = async ctx => {
const argv = mri(ctx.argv.slice(2), {
boolean: ['help'],
alias: {
help: 'h'
}
});
let argv;
try {
argv = getArgs(ctx.argv.slice(2));
} catch (err) {
handleError(err);
return 1;
}
if (argv.help) {
help();
await exit(0);
}
const debugEnabled = argv['--debug'];
const output = createOutput({ debug: debugEnabled });
argv._ = argv._.slice(1);
const apiUrl = ctx.apiUrl;
@@ -247,12 +253,11 @@ const login = async ctx => {
writeToAuthConfigFile(ctx.authConfig);
writeToConfigFile(ctx.config);
output.debug(`Saved credentials in "${hp(getNowDir())}"`);
console.log(
ready(
`Authentication token and personal details saved in ${param(
hp(getNowDir())
)}`
)
`${chalk.cyan('> Congratulations!')} ` +
`You are now logged in. In order to deploy something, run ${cmd('now')}.`
);
return ctx;

View File

@@ -136,7 +136,10 @@ export default async function main(ctx) {
types = argv.all ? [] : ['command', 'stdout', 'stderr', 'exit'];
outputMode = argv.output in logPrinters ? argv.output : 'short';
const { authConfig: { token }, config } = ctx;
const {
authConfig: { token },
config
} = ctx;
const { currentTeam } = config;
const now = new Now({ apiUrl, token, debug, currentTeam });
const client = new Client({
@@ -295,10 +298,25 @@ function printLogShort(log) {
const date = new Date(log.created).toISOString();
data.split('\n').forEach((line, i) => {
if (line.includes('START RequestId:') || line.includes('END RequestId:')) {
return;
}
if (line.includes('REPORT RequestId:')) {
line = line.substring(line.indexOf('Duration:'), line.length);
}
if (i === 0) {
console.log(`${chalk.dim(date)} ${line}`);
console.log(
`${chalk.dim(date)} ${line.replace('[now-builder-debug] ', '')}`
);
} else {
console.log(`${' '.repeat(date.length)} ${line}`);
console.log(
`${' '.repeat(date.length)} ${line.replace(
'[now-builder-debug] ',
''
)}`
);
}
});

View File

@@ -14,6 +14,7 @@ import { normalizeURL } from '../util/url';
import Client from '../util/client.ts';
import getScope from '../util/get-scope.ts';
import { NowError } from '../util/now-error';
import { isValidName } from '../util/is-valid-name';
import removeProject from '../util/projects/remove-project';
import getProjectByIdOrName from '../util/projects/get-project-by-id-or-name';
import getDeploymentByIdOrHost from '../util/deploy/get-deployment-by-id-or-host';
@@ -96,6 +97,13 @@ export default async function main(ctx) {
return 2;
}
const invalidName = ids.find(name => !isValidName(name));
if (invalidName) {
error(`The provided argument "${invalidName}" is not a valid deployment or project`);
return 1;
}
const {
authConfig: { token },
config

View File

@@ -20,7 +20,7 @@ import {
getDefaultAuthConfig
} from './util/config/get-default';
import hp from './util/humanize-path';
import commands from './commands';
import commands from './commands/index.ts';
import * as configFiles from './util/config/files';
import pkg from './util/pkg.ts';
import createOutput from './util/output';
@@ -339,7 +339,7 @@ const main = async argv_ => {
const targetPath = join(process.cwd(), targetOrSubcommand);
const targetPathExists = existsSync(targetPath);
const subcommandExists =
GLOBAL_COMMANDS.has(targetOrSubcommand) || commands[targetOrSubcommand];
GLOBAL_COMMANDS.has(targetOrSubcommand) || commands.has(targetOrSubcommand);
if (targetPathExists && subcommandExists) {
console.error(
@@ -456,7 +456,7 @@ const main = async argv_ => {
}
const scope = argv['--scope'] || argv['--team'] || localConfig.scope;
const targetCommand = commands[subcommand];
const targetCommand = commands.get(subcommand);
if (argv['--team']) {
output.warn(`The ${param('--team')} flag is deprecated. Please use ${param('--scope')} instead.`);

View File

@@ -0,0 +1,5 @@
import isWildcardAlias from './is-wildcard-alias';
export default function extractDomain(alias: string) {
return isWildcardAlias(alias) ? alias.slice(2) : alias;
}

View File

@@ -7,7 +7,7 @@ export default async function getInferredTargets(
output: Output,
config: Config
) {
output.warn(`The ${cmd('now alias')} command (no arguments) was deprecated in favour of ${cmd('now --target production')}.`);
output.warn(`The ${cmd('now alias')} command (no arguments) was deprecated in favour of ${cmd('now --prod')}.`);
// This field is deprecated, warn about it
if (config.aliases) {

View File

@@ -0,0 +1,3 @@
export default function isWildcardAlias(alias: string) {
return alias.startsWith('*.');
}

View File

@@ -2,7 +2,7 @@ import { NowError } from '../now-error';
import { Output } from '../output';
import Client from '../client';
import createCertForCns from './create-cert-for-cns';
import getWildcardCnsForDomain from './get-wildcard-cns-for-domain';
import getWildcardCnsForAlias from './get-wildcard-cns-for-alias';
import joinWords from '../output/join-words';
import stamp from '../output/stamp';
import wait from '../output/wait';
@@ -14,7 +14,7 @@ export default async function createCertificateForAlias(
alias: string,
shouldBeWildcard: boolean
) {
const cns = shouldBeWildcard ? getWildcardCnsForDomain(alias) : [alias];
const cns = shouldBeWildcard ? getWildcardCnsForAlias(alias) : [alias];
const cancelMessage = wait(`Generating a certificate...`);
const certStamp = stamp();
const cert = await createCertForCns(client, cns, context);

View File

@@ -1,12 +1,43 @@
import { URLSearchParams } from 'url';
import Client from '../client';
import { Output } from '../output';
import { Cert } from '../../types';
import getCertById from './get-cert-by-id';
import { CertNotFound } from '../errors-ts';
type Response = {
certs: Cert[];
};
export default async function getCerts(output: Output, client: Client) {
const { certs } = await client.fetch<Response>(`/v3/now/certs`);
return certs;
function sortByCreated(a: Cert, b: Cert) {
const dateA = new Date(a.created);
const dateB = new Date(b.created);
if (dateA > dateB) {
return -1;
}
if (dateA < dateB) {
return 1;
}
return 0;
}
export default async function getCerts(output: Output, client: Client, options?: { after?: string; }) {
const query = new URLSearchParams({ limit: '100' });
if (options && options.after) {
const lastCert = await getCertById(output, client, options.after);
if (lastCert instanceof CertNotFound) {
throw lastCert;
}
query.set('until', new Date(lastCert.created).getTime().toString());
}
const { certs } = await client.fetch<Response>(`/v3/now/certs?${query}`);
return certs.sort(sortByCreated);
}

View File

@@ -1,15 +1,21 @@
import psl from 'psl';
import { InvalidDomain } from '../errors-ts';
import isWildcardAlias from '../alias/is-wildcard-alias';
import extractDomain from '../alias/extract-domain';
export default function getWildcardCNSForDomain(rawDomain: string) {
const parsedDomain = psl.parse(rawDomain);
export default function getWildcardCNSForAlias(alias: string) {
if (isWildcardAlias(alias)) {
return [extractDomain(alias), alias];
}
const parsedDomain = psl.parse(alias);
if (parsedDomain.error) {
throw new InvalidDomain(rawDomain);
throw new InvalidDomain(alias);
}
const { domain, subdomain } = parsedDomain;
if (!domain) {
throw new InvalidDomain(rawDomain);
throw new InvalidDomain(alias);
}
const secondLevel =

View File

@@ -1,12 +1,28 @@
// Native
import { homedir } from 'os';
import fs from 'fs';
import path from 'path';
// Packages
import mri from 'mri';
import XDGAppPaths from 'xdg-app-paths';
const getNowDir = () => {
// The `homeConfigPath` is the legacy configuration path located in the users home directory.
const homeConfigPath: string = path.join(homedir(), '.now');
// Returns whether a directory exists
const isDirectory = (path: string): boolean => {
try {
return fs.lstatSync(path).isDirectory();
} catch (_) {
// We don't care which kind of error occured, it isn't a directory anyway.
return false;
}
};
// Returns in which directory the config should be present
const getNowDir = (): string => {
const args = mri(process.argv.slice(2), {
string: ['global-config'],
alias: {
@@ -15,12 +31,18 @@ const getNowDir = () => {
});
const customPath = args['global-config'];
const xdgConfigPaths = XDGAppPaths('now').dataDirs();
const possibleConfigPaths = [homeConfigPath, ...xdgConfigPaths];
if (!customPath) {
return path.join(homedir(), '.now');
}
return path.resolve(customPath);
// customPath is the preferred location
// the legacy home directory config path is the second most wanted location
// otherwise the first matching xdg-config-path is used which already exists
// at last the first best xdg-config-path is used
return (
(customPath && path.resolve(customPath)) ||
possibleConfigPaths.find(configPath => isDirectory(configPath)) ||
xdgConfigPaths[0]
);
};
export default getNowDir;

View File

@@ -8,7 +8,7 @@ import { createHash } from 'crypto';
import { createGunzip } from 'zlib';
import { join, resolve } from 'path';
import { funCacheDir } from '@zeit/fun';
import cacheDirectory from 'cache-or-tmp-directory';
import XDGAppPaths from 'xdg-app-paths';
import {
createReadStream,
mkdirp,
@@ -80,7 +80,7 @@ export async function prepareCacheDir() {
const { NOW_BUILDER_CACHE_DIR } = process.env;
const designated = NOW_BUILDER_CACHE_DIR
? resolve(NOW_BUILDER_CACHE_DIR)
: cacheDirectory('co.zeit.now');
: XDGAppPaths('co.zeit.now').cache();
if (!designated) {
throw new NoBuilderCacheError();

View File

@@ -26,13 +26,13 @@ export function resolveRouteParameters(
}
export default async function(
reqPath: string = '/',
reqUrl: string = '/',
reqMethod?: string,
routes?: RouteConfig[],
devServer?: DevServer
): Promise<RouteResult> {
let found: RouteResult | undefined;
let { query, pathname: reqPathname = '/' } = url.parse(reqPath, true);
let { query, pathname: reqPathname = '/' } = url.parse(reqUrl, true);
const combinedHeaders: HttpHeadersConfig = {};
// Try route match
@@ -85,6 +85,7 @@ export default async function(
}
if (routeConfig.continue) {
reqPathname = destPath;
continue;
}

View File

@@ -35,10 +35,7 @@ import {
staticFiles as getFiles,
getAllProjectFiles
} from '../get-files';
import {
validateNowConfigBuilds,
validateNowConfigRoutes
} from './validate';
import { validateNowConfigBuilds, validateNowConfigRoutes } from './validate';
import isURL from './is-url';
import devRouter from './router';
@@ -251,7 +248,9 @@ export default class DevServer {
filesChangedArray,
filesRemovedArray
).catch((err: Error) => {
this.output.warn(`An error occurred while rebuilding ${match.src}:`);
this.output.warn(
`An error occurred while rebuilding ${match.src}:`
);
console.error(err.stack);
});
} else {
@@ -810,7 +809,10 @@ export default class DevServer {
await Promise.all(ops);
} catch (err) {
// Node 8 doesn't have a code for that error
if (err.code === 'ERR_SERVER_NOT_RUNNING' || err.message === 'Not running') {
if (
err.code === 'ERR_SERVER_NOT_RUNNING' ||
err.message === 'Not running'
) {
process.exit(exitCode || 0);
} else {
throw err;
@@ -1111,7 +1113,7 @@ export default class DevServer {
await this.blockingBuildsPromise;
}
const { dest, status, headers = {}, uri_args } = await devRouter(
const { dest, status, headers, uri_args } = await devRouter(
req.url,
req.method,
routes,

View File

@@ -155,7 +155,7 @@ export interface RouteResult {
// "status": <integer in case exit code is intended to be changed>
status?: number;
// "headers": <object of the added response header values>
headers?: HttpHeadersConfig;
headers: HttpHeadersConfig;
// "uri_args": <object (key=value) list of new uri args to be passed along to dest >
uri_args?: { [key: string]: any };
// "matched_route": <object of the route spec that matched>

View File

@@ -8,6 +8,7 @@ import Client from '../client';
import maybeGetDomainByName from './maybe-get-domain-by-name';
import purchaseDomainIfAvailable from './purchase-domain-if-available';
import verifyDomain from './verify-domain';
import extractDomain from '../alias/extract-domain';
export default async function setupDomain(
output: Output,
@@ -15,7 +16,8 @@ export default async function setupDomain(
alias: string,
contextName: string
) {
const parsedDomain = psl.parse(alias);
const aliasDomain = extractDomain(alias);
const parsedDomain = psl.parse(aliasDomain);
if (parsedDomain.error) {
return new ERRORS.InvalidDomain(alias, parsedDomain.error.message);
}
@@ -60,7 +62,7 @@ export default async function setupDomain(
const purchased = await purchaseDomainIfAvailable(
output,
client,
alias,
aliasDomain,
contextName
);
if (purchased instanceof NowError) {

View File

@@ -1,5 +1,5 @@
import { Stats } from 'fs';
import { dirname, join, resolve } from 'path';
import {sep, dirname, join, resolve } from 'path';
import { readJSON, lstat, readlink, readFile, realpath } from 'fs-extra';
import { version } from '../../package.json';
@@ -58,11 +58,20 @@ async function getConfigPrefix() {
async function isGlobal() {
try {
// This is true for e.g. nvm, node path will be equal to now path
if (dirname(process.argv[0]) === dirname(process.argv[1])) {
return true;
}
const isWindows = process.platform === 'win32';
const defaultPath = isWindows ? process.env.APPDATA : '/usr/local/lib'
const installPath = await realpath(resolve(__dirname));
if (installPath.includes(['', 'yarn', 'global', 'node_modules', ''].join(sep))) {
return true;
}
const prefixPath = (
process.env.PREFIX ||
process.env.npm_config_prefix ||

View File

@@ -2,7 +2,6 @@ import inquirer from 'inquirer';
import stripAnsi from 'strip-ansi';
import eraseLines from '../output/erase-lines';
// eslint-disable-next-line import/no-unassigned-import
import './patch-inquirer';
function getLength(string) {

View File

@@ -0,0 +1,9 @@
// Soft validation to prevent invalid API calls
export function isValidName(name: string = ''): boolean {
// The name must have at least one different character.
// We need to do it this way to still allow project names
// with different characters, like other languages, but
// prevent API calls like `https://api.zeit.co/v5/now/deployments/%2F`
const blacklist = ':/#?&@%+~'.split('');
return !name.split('').every(c => blacklist.includes(c));
}

View File

@@ -1,4 +1,3 @@
/* eslint-disable import/no-unresolved */
import path from 'path';
import pkg from '../../package.json';

View File

@@ -255,3 +255,22 @@ test('[dev-router] match with catch-all with no prefix slash', async t => {
matched_route_idx: 0
});
});
test('[dev-router] `continue: true` with `dest`', async t => {
const routesConfig = [
{ src: '/(.*)', dest: '/www/$1', continue: true },
{ src: '^/www/(a\\/([^\\/]+?)(?:\\/)?)$', dest: 'http://localhost:5000/$1' }
];
const result = await devRouter('/a/foo', 'GET', routesConfig);
t.deepEqual(result, {
found: true,
dest: 'http://localhost:5000/a/foo',
status: undefined,
headers: {},
uri_args: {},
matched_route: routesConfig[1],
matched_route_idx: 1,
userDest: false
});
});

View File

View File

@@ -1,6 +0,0 @@
FROM alpine
ARG NONCE
RUN mkdir /public
RUN echo $NONCE > /public/index.html

View File

@@ -1 +0,0 @@
{"version":1,"type":"static"}

View File

@@ -1,6 +0,0 @@
FROM alpine
ARG FOO
RUN mkdir /public
RUN echo $FOO > /public/index.html

View File

@@ -1 +0,0 @@
{"version":1,"type":"static","build":{"env":{"FOO":"bar"}}}

View File

@@ -1,12 +0,0 @@
{
"version": 2,
"routes": [
{
"src": "/(.*)",
"status": 301,
"headers": {
"Location": "https://google.com"
}
}
]
}

View File

@@ -1 +0,0 @@
<span>test</span

View File

@@ -1 +0,0 @@
{"builder": 1, "type": "static"}

View File

@@ -1,6 +0,0 @@
<form action="/contact.php" method="POST">
Post message for now-builders-ci-bot-255 right here:
<textarea name="Message" />
<button>Submit</button>
</form>

View File

@@ -1,6 +0,0 @@
{
"version": 2,
"builds": [
{ "src": "*.html", "use": "@now/static" }
]
}

View File

@@ -1 +0,0 @@
<span>test alias</span

View File

@@ -1 +0,0 @@
{ "alias": "test.now.sh", "builds": [ { "src": "*.html", "use": "@now/static" } ] }

View File

@@ -1 +0,0 @@
<span>test scope email</span

View File

@@ -1 +0,0 @@
{ "scope": "now-builders-ci-bot-255@zeit.pub", "builds": [ { "src": "*.html", "use": "@now/static" } ], "version": 2 }

View File

@@ -1 +0,0 @@
<span>test scope username</span

View File

@@ -1 +0,0 @@
{ "scope": "now-builders-ci-bot-255", "builds": [ { "src": "*.html", "use": "@now/static" } ] }

View File

@@ -1,13 +0,0 @@
FROM mhart/alpine-node:latest
LABEL name "now-cli-dockerfile-now-builders-ci-bot-255"
RUN mkdir /app
WORKDIR /app
COPY package.json /app
RUN yarn
COPY index.js /app
EXPOSE 3000
CMD ["yarn", "start"]

View File

@@ -1,4 +0,0 @@
module.exports = () => ({
id: 'now-builders-ci-bot-255'
})

View File

@@ -1,3 +0,0 @@
{
"version": 1
}

View File

@@ -1,12 +0,0 @@
{
"name": "node-test-now-builders-ci-bot-255",
"main": "index.js",
"license": "MIT",
"scripts": {
"start": "micro"
},
"dependencies": {
"micro": "latest"
}
}

View File

@@ -1 +0,0 @@
{"scripts":{"build":"echo hello && exit 1"}}

View File

@@ -1,4 +0,0 @@
module.exports = () => ({
id: 'now-builders-ci-bot-255'
})

View File

@@ -1,3 +0,0 @@
{
"version": 1
}

View File

@@ -1,12 +0,0 @@
{
"name": "node-test-now-builders-ci-bot-255",
"main": "index.js",
"license": "MIT",
"scripts": {
"start": "micro"
},
"dependencies": {
"micro": "latest"
}
}

View File

@@ -1,5 +0,0 @@
{
"scripts": {
"dev": "now dev"
}
}

View File

@@ -1 +0,0 @@
{"name":"now-revert-alias-1"}

View File

@@ -1 +0,0 @@
{"version":2,"name":"now-revert-alias-c57c0734d878","builds":[{"src":"*.json","use":"@now/static"}]}

View File

@@ -1 +0,0 @@
{"name":"now-revert-alias-2"}

View File

@@ -1 +0,0 @@
{"version":2,"name":"now-revert-alias-c57c0734d878","builds":[{"src":"*.json","use":"@now/static"}]}

View File

@@ -1,5 +0,0 @@
FROM alpine
RUN mkdir /public
RUN echo hello > /public/index.html

View File

@@ -1 +0,0 @@
{"version": 1, "type": "static"}

Some files were not shown because too many files have changed in this diff Show More