mirror of
https://github.com/LukeHagar/vercel.git
synced 2026-01-01 20:29:12 +00:00
Compare commits
36 Commits
@now/routi
...
@now/stati
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbb5caf955 | ||
|
|
3f93da550b | ||
|
|
a194e0cc6e | ||
|
|
b007200bcf | ||
|
|
05d88da887 | ||
|
|
0a429bb2f3 | ||
|
|
468ccb7598 | ||
|
|
e47f6f55dc | ||
|
|
17deed91b2 | ||
|
|
cc0bd9f0a2 | ||
|
|
f6f99fef25 | ||
|
|
eb252edc7f | ||
|
|
f3213dbcdc | ||
|
|
c637da7710 | ||
|
|
ab05595582 | ||
|
|
ba8e714329 | ||
|
|
ef86bb0bd9 | ||
|
|
be18b54bfd | ||
|
|
ed168db23c | ||
|
|
236f5f4159 | ||
|
|
e44a91634e | ||
|
|
8b9426eb6c | ||
|
|
c62c57f122 | ||
|
|
c81db0c8d2 | ||
|
|
1c64990e9f | ||
|
|
f1dc7fd14a | ||
|
|
6079d4be25 | ||
|
|
2c4b8335ce | ||
|
|
9bd2f22d5c | ||
|
|
7c421f92e1 | ||
|
|
0626db51bd | ||
|
|
dc29a8b816 | ||
|
|
e00e5e18ea | ||
|
|
d0999e7937 | ||
|
|
158cfad978 | ||
|
|
9145b43a62 |
@@ -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
32
.eslintignore
Normal 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
64
.eslintrc.json
Normal 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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
2
.github/workflows/publish.yml
vendored
2
.github/workflows/publish.yml
vendored
@@ -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
1
.gitignore
vendored
@@ -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
4
.prettierrc
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingCommas": "es5"
|
||||
}
|
||||
10
README.md
10
README.md
@@ -1,9 +1,9 @@
|
||||

|
||||

|
||||
|
||||
[](https://circleci.com/gh/zeit/workflows/now-cli)
|
||||
[](https://circleci.com/gh/zeit/workflows/now)
|
||||
[](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).
|
||||
|
||||
86
package.json
86
package.json
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
6
packages/gatsby-plugin-now/build.sh
Executable file
6
packages/gatsby-plugin-now/build.sh
Executable 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
|
||||
33
packages/gatsby-plugin-now/gatsby-node.js
Normal file
33
packages/gatsby-plugin-now/gatsby-node.js
Normal 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)
|
||||
);
|
||||
};
|
||||
1
packages/gatsby-plugin-now/index.js
Normal file
1
packages/gatsby-plugin-now/index.js
Normal file
@@ -0,0 +1 @@
|
||||
// noop
|
||||
32
packages/gatsby-plugin-now/package.json
Normal file
32
packages/gatsby-plugin-now/package.json
Normal 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/"
|
||||
]
|
||||
}
|
||||
}
|
||||
24
packages/gatsby-plugin-now/readme.md
Normal file
24
packages/gatsby-plugin-now/readme.md
Normal 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/)
|
||||
@@ -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,
|
||||
},
|
||||
]
|
||||
`;
|
||||
4
packages/gatsby-plugin-now/test/fixtures/.gitignore
vendored
Normal file
4
packages/gatsby-plugin-now/test/fixtures/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
public
|
||||
node_modules
|
||||
.cache
|
||||
yarn.lock
|
||||
3
packages/gatsby-plugin-now/test/fixtures/gatsby-config.js
vendored
Normal file
3
packages/gatsby-plugin-now/test/fixtures/gatsby-config.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
plugins: [{ resolve: require.resolve('../../') }]
|
||||
};
|
||||
105
packages/gatsby-plugin-now/test/fixtures/gatsby-node.js
vendored
Normal file
105
packages/gatsby-plugin-now/test/fixtures/gatsby-node.js
vendored
Normal 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;
|
||||
|
||||
// Let’s 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
|
||||
});
|
||||
};
|
||||
11
packages/gatsby-plugin-now/test/fixtures/package.json
vendored
Normal file
11
packages/gatsby-plugin-now/test/fixtures/package.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
||||
9
packages/gatsby-plugin-now/test/fixtures/src/pages/index.js
vendored
Normal file
9
packages/gatsby-plugin-now/test/fixtures/src/pages/index.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
const IndexPage = () => (
|
||||
<div>
|
||||
<h1>Hi people</h1>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default IndexPage;
|
||||
5
packages/gatsby-plugin-now/test/index.test.js
vendored
Normal file
5
packages/gatsby-plugin-now/test/index.test.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
test('test generated now routes', async () => {
|
||||
const nowRoutes = require('./fixtures/public/__now_routes_g4t5bY.json');
|
||||
|
||||
expect(nowRoutes).toMatchSnapshot();
|
||||
});
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -185,8 +185,8 @@ export interface ShouldServeOptions {
|
||||
}
|
||||
|
||||
export interface PackageJson {
|
||||
name: string;
|
||||
version: string;
|
||||
name?: string;
|
||||
version?: string;
|
||||
engines?: {
|
||||
[key: string]: string;
|
||||
node: string;
|
||||
|
||||
128
packages/now-build-utils/test/test.js
vendored
128
packages/now-build-utils/test/test.js
vendored
@@ -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();
|
||||
});
|
||||
|
||||
@@ -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
|
||||
1
packages/now-cgi/.gitignore
vendored
1
packages/now-cgi/.gitignore
vendored
@@ -1,2 +1 @@
|
||||
node_modules
|
||||
handler
|
||||
|
||||
@@ -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
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@now/cgi",
|
||||
"version": "0.1.5-canary.0",
|
||||
"version": "0.1.5-canary.1",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
@types
|
||||
download
|
||||
dist
|
||||
test/fixtures
|
||||
test/dev/fixtures
|
||||
bin
|
||||
link
|
||||
src/util/dev/templates/*.ts
|
||||
@@ -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'
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
declare module 'cache-or-tmp-directory' {
|
||||
export default function (appName: string) : string | null
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
declare module 'pcre-to-regexp' {
|
||||
export default function (pattern: string, keys?: string[]): RegExp
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||

|
||||

|
||||
|
||||
[](https://circleci.com/gh/zeit/workflows/now-cli)
|
||||
[](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).
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
])
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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()}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:');
|
||||
|
||||
@@ -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'
|
||||
};
|
||||
39
packages/now-cli/src/commands/index.ts
Normal file
39
packages/now-cli/src/commands/index.ts
Normal 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']
|
||||
]);
|
||||
@@ -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')) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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] ',
|
||||
''
|
||||
)}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.`);
|
||||
|
||||
5
packages/now-cli/src/util/alias/extract-domain.ts
Normal file
5
packages/now-cli/src/util/alias/extract-domain.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import isWildcardAlias from './is-wildcard-alias';
|
||||
|
||||
export default function extractDomain(alias: string) {
|
||||
return isWildcardAlias(alias) ? alias.slice(2) : alias;
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
3
packages/now-cli/src/util/alias/is-wildcard-alias.ts
Normal file
3
packages/now-cli/src/util/alias/is-wildcard-alias.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function isWildcardAlias(alias: string) {
|
||||
return alias.startsWith('*.');
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 =
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
9
packages/now-cli/src/util/is-valid-name.ts
Normal file
9
packages/now-cli/src/util/is-valid-name.ts
Normal 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));
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable import/no-unresolved */
|
||||
import path from 'path';
|
||||
import pkg from '../../package.json';
|
||||
|
||||
|
||||
19
packages/now-cli/test/dev-router.unit.js
vendored
19
packages/now-cli/test/dev-router.unit.js
vendored
@@ -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
|
||||
});
|
||||
});
|
||||
|
||||
0
packages/now-cli/test/fixtures/integration/.gitkeep
vendored
Normal file
0
packages/now-cli/test/fixtures/integration/.gitkeep
vendored
Normal file
@@ -1,6 +0,0 @@
|
||||
|
||||
FROM alpine
|
||||
ARG NONCE
|
||||
RUN mkdir /public
|
||||
RUN echo $NONCE > /public/index.html
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"version":1,"type":"static"}
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
FROM alpine
|
||||
ARG FOO
|
||||
RUN mkdir /public
|
||||
RUN echo $FOO > /public/index.html
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"version":1,"type":"static","build":{"env":{"FOO":"bar"}}}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"version": 2,
|
||||
"routes": [
|
||||
{
|
||||
"src": "/(.*)",
|
||||
"status": 301,
|
||||
"headers": {
|
||||
"Location": "https://google.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<span>test</span
|
||||
@@ -1 +0,0 @@
|
||||
{"builder": 1, "type": "static"}
|
||||
@@ -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>
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{ "src": "*.html", "use": "@now/static" }
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<span>test alias</span
|
||||
@@ -1 +0,0 @@
|
||||
{ "alias": "test.now.sh", "builds": [ { "src": "*.html", "use": "@now/static" } ] }
|
||||
@@ -1 +0,0 @@
|
||||
<span>test scope email</span
|
||||
@@ -1 +0,0 @@
|
||||
{ "scope": "now-builders-ci-bot-255@zeit.pub", "builds": [ { "src": "*.html", "use": "@now/static" } ], "version": 2 }
|
||||
@@ -1 +0,0 @@
|
||||
<span>test scope username</span
|
||||
@@ -1 +0,0 @@
|
||||
{ "scope": "now-builders-ci-bot-255", "builds": [ { "src": "*.html", "use": "@now/static" } ] }
|
||||
@@ -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"]
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
module.exports = () => ({
|
||||
id: 'now-builders-ci-bot-255'
|
||||
})
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"version": 1
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
|
||||
{
|
||||
"name": "node-test-now-builders-ci-bot-255",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "micro"
|
||||
},
|
||||
"dependencies": {
|
||||
"micro": "latest"
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"scripts":{"build":"echo hello && exit 1"}}
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
module.exports = () => ({
|
||||
id: 'now-builders-ci-bot-255'
|
||||
})
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"version": 1
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
|
||||
{
|
||||
"name": "node-test-now-builders-ci-bot-255",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "micro"
|
||||
},
|
||||
"dependencies": {
|
||||
"micro": "latest"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"scripts": {
|
||||
"dev": "now dev"
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"name":"now-revert-alias-1"}
|
||||
@@ -1 +0,0 @@
|
||||
{"version":2,"name":"now-revert-alias-c57c0734d878","builds":[{"src":"*.json","use":"@now/static"}]}
|
||||
@@ -1 +0,0 @@
|
||||
{"name":"now-revert-alias-2"}
|
||||
@@ -1 +0,0 @@
|
||||
{"version":2,"name":"now-revert-alias-c57c0734d878","builds":[{"src":"*.json","use":"@now/static"}]}
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
FROM alpine
|
||||
RUN mkdir /public
|
||||
RUN echo hello > /public/index.html
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"version": 1, "type": "static"}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user