mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-11 04:22:13 +00:00
Compare commits
117 Commits
vercel@20.
...
@vercel/py
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
726d3924ae | ||
|
|
d3e6c2d335 | ||
|
|
f9ed84a5c9 | ||
|
|
88a815b5f0 | ||
|
|
9f49743ea4 | ||
|
|
0ac3ae19c0 | ||
|
|
e7920fd783 | ||
|
|
b4c13470df | ||
|
|
2a797b77b9 | ||
|
|
85a34126df | ||
|
|
92889c5376 | ||
|
|
66a7fa30b8 | ||
|
|
a7ba405503 | ||
|
|
84145245ba | ||
|
|
90d2e8b63b | ||
|
|
0d31fe8018 | ||
|
|
37d747c241 | ||
|
|
3f052d905f | ||
|
|
0b60467d2f | ||
|
|
4384a6104f | ||
|
|
f40f95ff37 | ||
|
|
90c05250b0 | ||
|
|
030880fe74 | ||
|
|
02bc88f33b | ||
|
|
38ff557cad | ||
|
|
47c34842d5 | ||
|
|
d21b215ad0 | ||
|
|
5827737fd5 | ||
|
|
a9e078d410 | ||
|
|
b4d9b17fb8 | ||
|
|
02c55bf634 | ||
|
|
08af15055f | ||
|
|
0597aaa5e4 | ||
|
|
176856a1ea | ||
|
|
375a55ebed | ||
|
|
7d33a05581 | ||
|
|
0377c8b737 | ||
|
|
662d546388 | ||
|
|
8c514b5608 | ||
|
|
a6ec53d9d3 | ||
|
|
3ad5903f70 | ||
|
|
3cf155e999 | ||
|
|
d9a298d97c | ||
|
|
487d3c8554 | ||
|
|
9d0bfd3656 | ||
|
|
ec75333569 | ||
|
|
51aab912a2 | ||
|
|
670b2653c0 | ||
|
|
f71686fdad | ||
|
|
ec9c8ce150 | ||
|
|
a2048fc6d3 | ||
|
|
09ff9cda9f | ||
|
|
3a4d6f7848 | ||
|
|
9a0d676c0d | ||
|
|
25cd7b9e6e | ||
|
|
f926d5516c | ||
|
|
4603383850 | ||
|
|
c0c57889c8 | ||
|
|
85908a0524 | ||
|
|
503b9a2429 | ||
|
|
eac8f32ae7 | ||
|
|
3f76fefde6 | ||
|
|
79ddc5746b | ||
|
|
9a14615b43 | ||
|
|
6d6ccbdc25 | ||
|
|
704424ec58 | ||
|
|
c471127c69 | ||
|
|
c02dc9ac49 | ||
|
|
dd10e8cc77 | ||
|
|
cf69c2398c | ||
|
|
e48707571f | ||
|
|
6051fe6f0c | ||
|
|
2b3ba8a14f | ||
|
|
25bea3f83e | ||
|
|
b3e1828ebe | ||
|
|
e0e2a8e87e | ||
|
|
37ec89796d | ||
|
|
d3e2a4c4db | ||
|
|
ece3645914 | ||
|
|
fee386493b | ||
|
|
d95ed184ab | ||
|
|
aef8e6388e | ||
|
|
ba43e88603 | ||
|
|
e61f9740c4 | ||
|
|
c4b010fe8b | ||
|
|
db18eb091f | ||
|
|
360e62d172 | ||
|
|
8c3cd0332d | ||
|
|
f5f276021e | ||
|
|
9fbec823f3 | ||
|
|
18c3dd3a63 | ||
|
|
5a4a20b33f | ||
|
|
4489ed0c85 | ||
|
|
359f23daf1 | ||
|
|
4ef92e85db | ||
|
|
659c4d6ccd | ||
|
|
e93d477df8 | ||
|
|
f64625655b | ||
|
|
25a8189997 | ||
|
|
25c3e627cf | ||
|
|
1d6d8b530f | ||
|
|
e821cc0ae7 | ||
|
|
8ecbdc5d03 | ||
|
|
895224985b | ||
|
|
0f42a63c03 | ||
|
|
81e4c9e6fe | ||
|
|
a0a29dc836 | ||
|
|
c1f9d51d7a | ||
|
|
422f0558c1 | ||
|
|
f064ae2908 | ||
|
|
58c3e636f0 | ||
|
|
d5081367f3 | ||
|
|
0ee88366ff | ||
|
|
9ae42c9e92 | ||
|
|
62b8df4a8d | ||
|
|
73ec7f3018 | ||
|
|
2d24a75ca6 |
9
.github/CONTRIBUTING.md
vendored
9
.github/CONTRIBUTING.md
vendored
@@ -94,12 +94,3 @@ Sometimes you want to test changes to a Builder against an existing project, may
|
||||
4. Run `vercel *.tgz` to upload the tarball file and get a URL
|
||||
5. Edit any existing `vercel.json` project and replace `use` with the URL
|
||||
6. Run `vercel` or `vercel dev` to deploy with the experimental Builder
|
||||
|
||||
## Add a New Framework
|
||||
|
||||
You can add support for a new Framework by creating a Pull Request for this repository and following the steps below:
|
||||
|
||||
1. Add the Framework to the `@vercel/frameworks` package: The file is located in `./packages/frameworks/frameworks.json`. You can copy the structure of an existing one and adjust the required fields. Note that the `settings` property either contains a `value` or a `placeholder`. The `value` property is used when something is not configurable, the `placeholder` is used when something is configurable and can be changed with configuration. An example would be the Output Directory for Hugo, it's `public` by default but can be changed through its config file, so we use `placeholder` with an explanation of what can be used.
|
||||
2. Add an example to the `./examples` directory: The name of the directory should equal the slug of the framework used in `@vercel/frameworks`. The `.github/EXAMPLE_README_TEMPLATE.md` file can be used to create a `README.md` file for the example.
|
||||
3. Update the `@vercel/static-build` package: The file `./packages/now-static-build/src/frameworks.ts` has to be extended. You can add default routes that will always be applied to projects that use this Framework or specify some paths that will be cached to speed up the build process.
|
||||
4. After your Pull Request has been merged and released, other users can select the example on the Vercel dashboard and deploy it.
|
||||
|
||||
2
.github/workflows/test-integration-dev.yml
vendored
2
.github/workflows/test-integration-dev.yml
vendored
@@ -11,7 +11,7 @@ on:
|
||||
jobs:
|
||||
test:
|
||||
name: Dev
|
||||
timeout-minutes: 45
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -6,5 +6,5 @@ You're running Vercel CLI in a non-terminal context and there are no credentials
|
||||
|
||||
#### Possible Ways to Fix It
|
||||
|
||||
- Specify a value for the `--token` flag (this needs to be the token of the user account as which you'd like to act). You can either get the token from the `./vercel/auth.json` file located in your user directory or [from the dashboard](https://vercel.com/account/tokens).
|
||||
- Ensure that both `~/vercel/auth.json` and `~/vercel/config.json` exist
|
||||
- Specify a value for the `--token` flag (this needs to be the token of the user account as which you'd like to act). You can create a new token on your [Settings page](https://vercel.com/account/tokens).
|
||||
- Run `vercel login` to sign in and generate a new token
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { NowRequest, NowResponse } from '@now/node';
|
||||
import { NowRequest, NowResponse } from '@vercel/node';
|
||||
|
||||
export default (_req: NowRequest, res: NowResponse) => {
|
||||
const date = new Date().toString();
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"react-helmet": "^5.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@now/node": "^1.3.0"
|
||||
"@vercel/node": "1.8.5"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "gatsby develop",
|
||||
|
||||
@@ -1107,15 +1107,6 @@
|
||||
"@nodelib/fs.scandir" "2.1.3"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@now/node@^1.3.0":
|
||||
version "1.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@now/node/-/node-1.7.1.tgz#764a0c6bcb24967f8014c4f73ad238c292996fe3"
|
||||
integrity sha512-+srVKopsVTPDR3u9eOjJryZroLTrPp8XEOuIDGBdfFcJuS7qpAomctSbfyA7WNyjC0ExtUxELqBg5sAedG5+2g==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
ts-node "8.9.1"
|
||||
typescript "3.9.3"
|
||||
|
||||
"@pieh/friendly-errors-webpack-plugin@1.7.0-chalk-2":
|
||||
version "1.7.0-chalk-2"
|
||||
resolved "https://registry.yarnpkg.com/@pieh/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.7.0-chalk-2.tgz#2e9da9d3ade9d18d013333eb408c457d04eabac0"
|
||||
@@ -1409,6 +1400,15 @@
|
||||
dependencies:
|
||||
wonka "^4.0.14"
|
||||
|
||||
"@vercel/node@1.8.5":
|
||||
version "1.8.5"
|
||||
resolved "https://registry.yarnpkg.com/@vercel/node/-/node-1.8.5.tgz#2c8b9532f1bb25734a9964c52973386ed78022d4"
|
||||
integrity sha512-1iw7FSR8Oau6vZB1MWfBnA5q2a/IqRHiSZSbt8lz0dyTF599q8pc5GcSv/TvmrYaEGzh3+N0S4cbmuMCqVlwJg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
ts-node "8.9.1"
|
||||
typescript "3.9.3"
|
||||
|
||||
"@webassemblyjs/ast@1.9.0":
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964"
|
||||
|
||||
@@ -14,6 +14,10 @@ Open [http://localhost:3000](http://localhost:3000) with your browser to see the
|
||||
|
||||
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
|
||||
|
||||
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
|
||||
|
||||
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "10.0.0",
|
||||
"next": "10.0.5",
|
||||
"react": "17.0.1",
|
||||
"react-dom": "17.0.1"
|
||||
}
|
||||
|
||||
@@ -76,7 +76,6 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
max-width: 800px;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/build-utils",
|
||||
"version": "2.6.0",
|
||||
"version": "2.8.0",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
|
||||
@@ -43,9 +43,8 @@ export function sortFiles(fileA: string, fileB: string) {
|
||||
export function detectApiExtensions(builders: Builder[]): Set<string> {
|
||||
return new Set<string>(
|
||||
builders
|
||||
.filter(
|
||||
b =>
|
||||
b.config && b.config.zeroConfig && b.src && b.src.startsWith('api/')
|
||||
.filter((b): b is Builder & { src: string } =>
|
||||
Boolean(b.config && b.config.zeroConfig && b.src?.startsWith('api/'))
|
||||
)
|
||||
.map(b => extname(b.src))
|
||||
.filter(Boolean)
|
||||
@@ -56,22 +55,28 @@ export function detectApiDirectory(builders: Builder[]): string | null {
|
||||
// TODO: We eventually want to save the api directory to
|
||||
// builder.config.apiDirectory so it is only detected once
|
||||
const found = builders.some(
|
||||
b => b.config && b.config.zeroConfig && b.src.startsWith('api/')
|
||||
b => b.config && b.config.zeroConfig && b.src?.startsWith('api/')
|
||||
);
|
||||
return found ? 'api' : null;
|
||||
}
|
||||
|
||||
// TODO: Replace this function with `config.outputDirectory`
|
||||
function getPublicBuilder(builders: Builder[]): Builder | null {
|
||||
const builder = builders.find(
|
||||
builder =>
|
||||
function getPublicBuilder(
|
||||
builders: Builder[]
|
||||
): (Builder & { src: string }) | null {
|
||||
for (const builder of builders) {
|
||||
if (
|
||||
typeof builder.src === 'string' &&
|
||||
isOfficialRuntime('static', builder.use) &&
|
||||
/^.*\/\*\*\/\*$/.test(builder.src) &&
|
||||
builder.config &&
|
||||
builder.config.zeroConfig === true
|
||||
);
|
||||
) {
|
||||
return builder as Builder & { src: string };
|
||||
}
|
||||
}
|
||||
|
||||
return builder || null;
|
||||
return null;
|
||||
}
|
||||
export function detectOutputDirectory(builders: Builder[]): string | null {
|
||||
// TODO: We eventually want to save the output directory to
|
||||
@@ -361,7 +366,7 @@ function maybeGetApiBuilder(
|
||||
return null;
|
||||
}
|
||||
|
||||
const match = apiMatches.find(({ src }) => {
|
||||
const match = apiMatches.find(({ src = '**' }) => {
|
||||
return src === fileName || minimatch(fileName, src);
|
||||
});
|
||||
|
||||
@@ -989,7 +994,6 @@ function getRouteResult(
|
||||
rewriteRoutes.push({
|
||||
src: '^/api(/.*)?$',
|
||||
status: 404,
|
||||
continue: true,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -165,8 +165,8 @@ export function getSpawnOptions(
|
||||
export async function getNodeVersion(
|
||||
destPath: string,
|
||||
_nodeVersion?: string,
|
||||
_config?: Config,
|
||||
meta?: Meta
|
||||
config: Config = {},
|
||||
meta: Meta = {}
|
||||
): Promise<NodeVersion> {
|
||||
if (meta && meta.isDev) {
|
||||
// Use the system-installed version of `node` in PATH for `vercel dev`
|
||||
@@ -174,13 +174,22 @@ export async function getNodeVersion(
|
||||
return { ...latest, runtime: 'nodejs' };
|
||||
}
|
||||
const { packageJson } = await scanParentDirs(destPath, true);
|
||||
let range: string | undefined;
|
||||
let { nodeVersion } = config;
|
||||
let isAuto = true;
|
||||
if (packageJson && packageJson.engines && packageJson.engines.node) {
|
||||
range = packageJson.engines.node;
|
||||
if (
|
||||
nodeVersion &&
|
||||
nodeVersion !== packageJson.engines.node &&
|
||||
!meta.isDev
|
||||
) {
|
||||
console.warn(
|
||||
'Warning: Due to `engines` existing in your `package.json` file, the Node.js Version defined in your Project Settings will not apply. Learn More: http://vercel.link/node-version'
|
||||
);
|
||||
}
|
||||
nodeVersion = packageJson.engines.node;
|
||||
isAuto = false;
|
||||
}
|
||||
return getSupportedNodeVersion(range, isAuto);
|
||||
return getSupportedNodeVersion(nodeVersion, isAuto);
|
||||
}
|
||||
|
||||
async function scanParentDirs(destPath: string, readPackageJson = false) {
|
||||
@@ -292,6 +301,11 @@ export async function runNpmInstall(
|
||||
opts.prettyCommand = 'yarn install';
|
||||
command = 'yarn';
|
||||
commandArgs = ['install', ...args];
|
||||
|
||||
// Yarn v2 PnP mode may be activated, so force "node-modules" linker style
|
||||
if (!env.YARN_NODE_LINKER) {
|
||||
env.YARN_NODE_LINKER = 'node-modules';
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.NPM_ONLY_PRODUCTION) {
|
||||
@@ -388,10 +402,17 @@ export async function runPackageJsonScript(
|
||||
prettyCommand,
|
||||
});
|
||||
} else {
|
||||
// Yarn v2 PnP mode may be activated, so force "node-modules" linker style
|
||||
const env: typeof process.env = { ...spawnOpts?.env };
|
||||
if (!env.YARN_NODE_LINKER) {
|
||||
env.YARN_NODE_LINKER = 'node-modules';
|
||||
}
|
||||
|
||||
const prettyCommand = `yarn run ${scriptName}`;
|
||||
console.log(`Running "${prettyCommand}"`);
|
||||
await spawnAsync('yarn', ['run', scriptName], {
|
||||
...spawnOpts,
|
||||
env,
|
||||
cwd: destPath,
|
||||
prettyCommand,
|
||||
});
|
||||
|
||||
@@ -336,7 +336,7 @@ export interface NodeVersion {
|
||||
|
||||
export interface Builder {
|
||||
use: string;
|
||||
src: string;
|
||||
src?: string;
|
||||
config?: Config;
|
||||
}
|
||||
|
||||
|
||||
5
packages/now-build-utils/test/fixtures/19-yarn-v2/api/index.js
vendored
Normal file
5
packages/now-build-utils/test/fixtures/19-yarn-v2/api/index.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
const { camelCase } = require('camel-case');
|
||||
|
||||
module.exports = (req, res) => {
|
||||
res.end(camelCase('camel-case module is working'));
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [{ "src": "package.json", "use": "@vercel/static-build" }],
|
||||
"probes": [{ "path": "/", "mustContain": "Svelte app" }]
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
"svelte": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"camel-case": "^4.1.2",
|
||||
"sirv-cli": "^0.4.4"
|
||||
}
|
||||
}
|
||||
|
||||
11
packages/now-build-utils/test/fixtures/19-yarn-v2/vercel.json
vendored
Normal file
11
packages/now-build-utils/test/fixtures/19-yarn-v2/vercel.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{ "src": "package.json", "use": "@vercel/static-build" },
|
||||
{ "src": "api/index.js", "use": "@vercel/node" }
|
||||
],
|
||||
"probes": [
|
||||
{ "path": "/", "mustContain": "Svelte app" },
|
||||
{ "path": "/api", "mustContain": "camelCaseModuleIsWorking" }
|
||||
]
|
||||
}
|
||||
@@ -270,6 +270,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"camel-case@npm:^4.1.2":
|
||||
version: 4.1.2
|
||||
resolution: "camel-case@npm:4.1.2"
|
||||
dependencies:
|
||||
pascal-case: ^3.1.2
|
||||
tslib: ^2.0.3
|
||||
checksum: 3/0b8dcfb424c9497e45984b88ef005c66bdf8e877e36365aedfc3cf73182684fde5a14cf2c526579c0351a5f27dc39a00f1edecc25d43606075fea948c504e37f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"caseless@npm:~0.12.0":
|
||||
version: 0.12.0
|
||||
resolution: "caseless@npm:0.12.0"
|
||||
@@ -850,6 +860,15 @@ fsevents@~2.1.2:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lower-case@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "lower-case@npm:2.0.2"
|
||||
dependencies:
|
||||
tslib: ^2.0.3
|
||||
checksum: 3/aabaca9cef65f7564a1005b625664527e4d169e363101e65773f8f6ff2fdcf09884a3bc02990cd7a62cf05f3538114af25ee7bef553f1ca3208c8a77ac75cbfa
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"magic-string@npm:^0.25.2":
|
||||
version: 0.25.7
|
||||
resolution: "magic-string@npm:0.25.7"
|
||||
@@ -944,6 +963,16 @@ fsevents@~2.1.2:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"no-case@npm:^3.0.4":
|
||||
version: 3.0.4
|
||||
resolution: "no-case@npm:3.0.4"
|
||||
dependencies:
|
||||
lower-case: ^2.0.2
|
||||
tslib: ^2.0.3
|
||||
checksum: 3/84db4909caec37504c6655f995a004067f8733be8cd8d849f1578661b60a1685e086325fa4e1a5e8ce94e7416c1d0f037e2a00f635a14457183de80ab4fc7612
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"node-gyp@npm:latest":
|
||||
version: 6.1.0
|
||||
resolution: "node-gyp@npm:6.1.0"
|
||||
@@ -1057,6 +1086,16 @@ fsevents@~2.1.2:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pascal-case@npm:^3.1.2":
|
||||
version: 3.1.2
|
||||
resolution: "pascal-case@npm:3.1.2"
|
||||
dependencies:
|
||||
no-case: ^3.0.4
|
||||
tslib: ^2.0.3
|
||||
checksum: 3/31708cecab221482edc81e2bd9b9d8282d72d4f1443b31f39725aa23768c5e42d93c4c014f1bc90f7f074e2a70d5091e4892ea370e550affc9ccf1d33c900bcd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-is-absolute@npm:^1.0.0":
|
||||
version: 1.0.1
|
||||
resolution: "path-is-absolute@npm:1.0.1"
|
||||
@@ -1447,6 +1486,7 @@ fsevents@~2.1.2:
|
||||
dependencies:
|
||||
"@rollup/plugin-commonjs": ^12.0.0
|
||||
"@rollup/plugin-node-resolve": ^8.0.0
|
||||
camel-case: ^4.1.2
|
||||
rollup: ^2.3.4
|
||||
rollup-plugin-livereload: ^1.0.0
|
||||
rollup-plugin-svelte: ^5.0.3
|
||||
@@ -1517,6 +1557,13 @@ fsevents@~2.1.2:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tslib@npm:^2.0.3":
|
||||
version: 2.0.3
|
||||
resolution: "tslib@npm:2.0.3"
|
||||
checksum: 3/447bfca5deaa157806c3f77eaba74d05dd0b38b014e47ce79d98b5c77ce7d91b00a687ba13ca1b5a74d35ca1098ac7a072c0a97fad06f0266612f2a03a6c8e8f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tunnel-agent@npm:^0.6.0":
|
||||
version: 0.6.0
|
||||
resolution: "tunnel-agent@npm:0.6.0"
|
||||
|
||||
@@ -39,7 +39,7 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
|
||||
|
||||
// few foreign tests
|
||||
|
||||
const buildersToTestWith = ['now-next', 'now-node', 'now-static-build'];
|
||||
const buildersToTestWith = ['now-node'];
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const builder of buildersToTestWith) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": "10.x"
|
||||
}
|
||||
@@ -182,7 +182,7 @@ describe('Test `detectBuilders`', () => {
|
||||
|
||||
const { builders } = await detectBuilders(files);
|
||||
expect(builders!.length).toBe(7);
|
||||
expect(builders!.some(b => b.src.endsWith('_test.go'))).toBe(false);
|
||||
expect(builders!.some(b => b.src!.endsWith('_test.go'))).toBe(false);
|
||||
});
|
||||
|
||||
it('just public', async () => {
|
||||
@@ -1341,7 +1341,7 @@ describe('Test `detectBuilders` with `featHandleMiss=true`', () => {
|
||||
featHandleMiss,
|
||||
});
|
||||
expect(builders!.length).toBe(7);
|
||||
expect(builders!.some(b => b.src.endsWith('_test.go'))).toBe(false);
|
||||
expect(builders!.some(b => b.src!.endsWith('_test.go'))).toBe(false);
|
||||
expect(errorRoutes!.length).toBe(1);
|
||||
expect((errorRoutes![0] as Source).status).toBe(404);
|
||||
});
|
||||
@@ -2393,7 +2393,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
expect(errorRoutes).toStrictEqual([
|
||||
@@ -2495,7 +2494,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2533,7 +2531,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2571,7 +2568,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2604,7 +2600,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2632,7 +2627,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2663,7 +2657,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2690,7 +2683,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2725,7 +2717,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
expect(errorRoutes).toStrictEqual([
|
||||
@@ -2820,7 +2811,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2853,7 +2843,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2887,7 +2876,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2913,7 +2901,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2937,7 +2924,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2962,7 +2948,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2983,7 +2968,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -3018,7 +3002,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -3076,7 +3059,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -3109,7 +3091,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -3143,7 +3124,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -3162,7 +3142,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -3186,7 +3165,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -3211,7 +3189,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -3232,7 +3209,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
46
packages/now-build-utils/test/unit.test.js
vendored
46
packages/now-build-utils/test/unit.test.js
vendored
@@ -24,6 +24,19 @@ async function expectBuilderError(promise, pattern) {
|
||||
);
|
||||
}
|
||||
|
||||
let warningMessages;
|
||||
const originalConsoleWarn = console.warn;
|
||||
beforeEach(() => {
|
||||
warningMessages = [];
|
||||
console.warn = m => {
|
||||
warningMessages.push(m);
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
console.warn = originalConsoleWarn;
|
||||
});
|
||||
|
||||
it('should re-create symlinks properly', async () => {
|
||||
if (process.platform === 'win32') {
|
||||
console.log('Skipping test on windows');
|
||||
@@ -150,6 +163,39 @@ it('should ignore node version in vercel dev getNodeVersion()', async () => {
|
||||
).toHaveProperty('runtime', 'nodejs');
|
||||
});
|
||||
|
||||
it('should select project setting from config when no package.json is found', async () => {
|
||||
expect(
|
||||
await getNodeVersion('/tmp', undefined, { nodeVersion: '10.x' }, {})
|
||||
).toHaveProperty('range', '10.x');
|
||||
expect(warningMessages).toStrictEqual([]);
|
||||
});
|
||||
|
||||
it('should prefer package.json engines over project setting from config and warn', async () => {
|
||||
expect(
|
||||
await getNodeVersion(
|
||||
path.join(__dirname, 'pkg-engine-node'),
|
||||
undefined,
|
||||
{ nodeVersion: '12.x' },
|
||||
{}
|
||||
)
|
||||
).toHaveProperty('range', '10.x');
|
||||
expect(warningMessages).toStrictEqual([
|
||||
'Warning: Due to `engines` existing in your `package.json` file, the Node.js Version defined in your Project Settings will not apply. Learn More: http://vercel.link/node-version',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not warn when package.json engines matches project setting from config', async () => {
|
||||
expect(
|
||||
await getNodeVersion(
|
||||
path.join(__dirname, 'pkg-engine-node'),
|
||||
undefined,
|
||||
{ nodeVersion: '10.x' },
|
||||
{}
|
||||
)
|
||||
).toHaveProperty('range', '10.x');
|
||||
expect(warningMessages).toStrictEqual([]);
|
||||
});
|
||||
|
||||
it('should get latest node version', async () => {
|
||||
expect(await getLatestNodeVersion()).toHaveProperty('major', 12);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel",
|
||||
"version": "20.1.3",
|
||||
"version": "21.2.1-canary.0",
|
||||
"preferGlobal": true,
|
||||
"license": "Apache-2.0",
|
||||
"description": "The command-line interface for Vercel",
|
||||
@@ -61,11 +61,11 @@
|
||||
"node": ">= 10"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "2.6.0",
|
||||
"@vercel/go": "1.1.6",
|
||||
"@vercel/node": "1.8.5",
|
||||
"@vercel/python": "1.2.3",
|
||||
"@vercel/ruby": "1.2.4",
|
||||
"@vercel/build-utils": "2.8.0",
|
||||
"@vercel/go": "1.1.7",
|
||||
"@vercel/node": "1.9.0",
|
||||
"@vercel/python": "1.2.5-canary.0",
|
||||
"@vercel/ruby": "1.2.5",
|
||||
"update-notifier": "4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -2,7 +2,6 @@ import chalk from 'chalk';
|
||||
|
||||
import { handleError } from '../../util/error';
|
||||
|
||||
import createOutput from '../../util/output';
|
||||
import getArgs from '../../util/get-args';
|
||||
import getSubcommand from '../../util/get-subcommand';
|
||||
import logo from '../../util/output/logo';
|
||||
@@ -92,15 +91,14 @@ export default async function main(ctx) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
const output = createOutput({ debug: argv['--debug'] });
|
||||
const { subcommand, args } = getSubcommand(argv._.slice(1), COMMAND_CONFIG);
|
||||
|
||||
switch (subcommand) {
|
||||
case 'ls':
|
||||
return ls(ctx, argv, args, output);
|
||||
return ls(ctx, argv, args);
|
||||
case 'rm':
|
||||
return rm(ctx, argv, args, output);
|
||||
return rm(ctx, argv, args);
|
||||
default:
|
||||
return set(ctx, argv, args, output);
|
||||
return set(ctx, argv, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,10 @@ import strlen from '../../util/strlen.ts';
|
||||
import getCommandFlags from '../../util/get-command-flags';
|
||||
import { getCommandName } from '../../util/pkg-name.ts';
|
||||
|
||||
export default async function ls(ctx, opts, args, output) {
|
||||
export default async function ls(ctx, opts, args) {
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
@@ -23,6 +24,7 @@ export default async function ls(ctx, opts, args, output) {
|
||||
token,
|
||||
currentTeam,
|
||||
debug: debugEnabled,
|
||||
output,
|
||||
});
|
||||
let contextName = null;
|
||||
|
||||
@@ -47,6 +49,7 @@ export default async function ls(ctx, opts, args, output) {
|
||||
token,
|
||||
debug: debugEnabled,
|
||||
currentTeam,
|
||||
output,
|
||||
});
|
||||
const lsStamp = stamp();
|
||||
let cancelWait;
|
||||
|
||||
@@ -12,9 +12,10 @@ import { isValidName } from '../../util/is-valid-name';
|
||||
import findAliasByAliasOrId from '../../util/alias/find-alias-by-alias-or-id';
|
||||
import { getCommandName } from '../../util/pkg-name.ts';
|
||||
|
||||
export default async function rm(ctx, opts, args, output) {
|
||||
export default async function rm(ctx, opts, args) {
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
@@ -25,6 +26,7 @@ export default async function rm(ctx, opts, args, output) {
|
||||
token,
|
||||
currentTeam,
|
||||
debug: debugEnabled,
|
||||
output,
|
||||
});
|
||||
let contextName = null;
|
||||
|
||||
@@ -39,8 +41,13 @@ export default async function rm(ctx, opts, args, output) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
// $FlowFixMe
|
||||
const now = new Now({ apiUrl, token, debug: debugEnabled, currentTeam });
|
||||
const now = new Now({
|
||||
apiUrl,
|
||||
token,
|
||||
debug: debugEnabled,
|
||||
currentTeam,
|
||||
output,
|
||||
});
|
||||
const [aliasOrId] = args;
|
||||
|
||||
if (args.length !== 1) {
|
||||
|
||||
@@ -29,11 +29,11 @@ type Options = {
|
||||
export default async function set(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
) {
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
localConfig,
|
||||
} = ctx;
|
||||
@@ -49,6 +49,7 @@ export default async function set(
|
||||
token,
|
||||
currentTeam,
|
||||
debug: debugEnabled,
|
||||
output,
|
||||
});
|
||||
|
||||
let user: User;
|
||||
|
||||
@@ -14,7 +14,6 @@ import addBilling from './add';
|
||||
import exit from '../../util/exit';
|
||||
import Client from '../../util/client.ts';
|
||||
import getScope from '../../util/get-scope.ts';
|
||||
import createOutput from '../../util/output';
|
||||
import { getPkgName } from '../../util/pkg-name.ts';
|
||||
|
||||
const help = () => {
|
||||
@@ -90,8 +89,9 @@ function buildInquirerChoices(cards) {
|
||||
const _default =
|
||||
source.id === cards.defaultSource ? ` ${chalk.bold('(default)')}` : '';
|
||||
const id = `${chalk.cyan(`ID: ${source.id}`)}${_default}`;
|
||||
const number = `${chalk.gray('#### ').repeat(3)}${source.last4 ||
|
||||
source.card.last4}`;
|
||||
const number = `${chalk.gray('#### ').repeat(3)}${
|
||||
source.last4 || source.card.last4
|
||||
}`;
|
||||
const str = [
|
||||
id,
|
||||
indent(source.name || source.owner.name, 2),
|
||||
@@ -106,11 +106,16 @@ function buildInquirerChoices(cards) {
|
||||
});
|
||||
}
|
||||
|
||||
async function run({ token, config: { currentTeam } }) {
|
||||
async function run({ token, output, config: { currentTeam } }) {
|
||||
const start = new Date();
|
||||
const creditCards = new NowCreditCards({ apiUrl, token, debug, currentTeam });
|
||||
const output = createOutput({ debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug });
|
||||
const creditCards = new NowCreditCards({
|
||||
apiUrl,
|
||||
token,
|
||||
debug,
|
||||
currentTeam,
|
||||
output,
|
||||
});
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug, output });
|
||||
let contextName = null;
|
||||
|
||||
try {
|
||||
@@ -147,8 +152,9 @@ async function run({ token, config: { currentTeam } }) {
|
||||
const id = `${chalk.gray('-')} ${chalk.cyan(
|
||||
`ID: ${source.id}`
|
||||
)}${_default}`;
|
||||
const number = `${chalk.gray('#### ').repeat(3)}${source.last4 ||
|
||||
source.card.last4}`;
|
||||
const number = `${chalk.gray('#### ').repeat(3)}${
|
||||
source.last4 || source.card.last4
|
||||
}`;
|
||||
|
||||
return [
|
||||
id,
|
||||
@@ -231,8 +237,9 @@ async function run({ token, config: { currentTeam } }) {
|
||||
const elapsed = ms(new Date() - start);
|
||||
console.log(
|
||||
success(
|
||||
`${card.brand || card.card.brand} ending in ${card.last4 ||
|
||||
card.card.last4} is now the default ${chalk.gray(`[${elapsed}]`)}`
|
||||
`${card.brand || card.card.brand} ending in ${
|
||||
card.last4 || card.card.last4
|
||||
} is now the default ${chalk.gray(`[${elapsed}]`)}`
|
||||
)
|
||||
);
|
||||
} else {
|
||||
@@ -301,9 +308,9 @@ async function run({ token, config: { currentTeam } }) {
|
||||
const deletedCard = cards.sources.find(card => card.id === cardId);
|
||||
const remainingCards = cards.sources.filter(card => card.id !== cardId);
|
||||
|
||||
let text = `${deletedCard.brand ||
|
||||
deletedCard.card.brand} ending in ${deletedCard.last4 ||
|
||||
deletedCard.card.last4} was deleted`;
|
||||
let text = `${deletedCard.brand || deletedCard.card.brand} ending in ${
|
||||
deletedCard.last4 || deletedCard.card.last4
|
||||
} was deleted`;
|
||||
// ${chalk.gray(`[${elapsed}]`)}
|
||||
|
||||
if (cardId === cards.defaultSource) {
|
||||
@@ -317,11 +324,11 @@ async function run({ token, config: { currentTeam } }) {
|
||||
card => card.id === cards.defaultCardId
|
||||
);
|
||||
|
||||
text += `\n${newDefaultCard.brand ||
|
||||
newDefaultCard.card.brand} ending in ${newDefaultCard.last4 ||
|
||||
newDefaultCard.card.last4} in now default for ${chalk.bold(
|
||||
contextName
|
||||
)}`;
|
||||
text += `\n${
|
||||
newDefaultCard.brand || newDefaultCard.card.brand
|
||||
} ending in ${
|
||||
newDefaultCard.last4 || newDefaultCard.card.last4
|
||||
} in now default for ${chalk.bold(contextName)}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import stamp from '../../util/output/stamp';
|
||||
import createCertFromFile from '../../util/certs/create-cert-from-file';
|
||||
import createCertForCns from '../../util/certs/create-cert-for-cns';
|
||||
import { NowContext } from '../../types';
|
||||
import { Output } from '../../util/output';
|
||||
import { getCommandName } from '../../util/pkg-name';
|
||||
|
||||
interface Options {
|
||||
@@ -22,11 +21,11 @@ interface Options {
|
||||
async function add(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
): Promise<number> {
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
@@ -49,6 +48,7 @@ async function add(
|
||||
token,
|
||||
currentTeam,
|
||||
debug: debugEnabled,
|
||||
output,
|
||||
});
|
||||
|
||||
try {
|
||||
@@ -62,7 +62,13 @@ async function add(
|
||||
throw err;
|
||||
}
|
||||
|
||||
const now = new Now({ apiUrl, token, debug: debugEnabled, currentTeam });
|
||||
const now = new Now({
|
||||
apiUrl,
|
||||
token,
|
||||
debug: debugEnabled,
|
||||
currentTeam,
|
||||
output,
|
||||
});
|
||||
|
||||
if (overwite) {
|
||||
output.error('Overwrite option is deprecated');
|
||||
@@ -71,7 +77,7 @@ async function add(
|
||||
}
|
||||
|
||||
if (crtPath || keyPath || caPath) {
|
||||
if (args.length !== 0 || (!crtPath || !keyPath || !caPath)) {
|
||||
if (args.length !== 0 || !crtPath || !keyPath || !caPath) {
|
||||
output.error(
|
||||
`Invalid number of arguments to create a custom certificate entry. Usage:`
|
||||
);
|
||||
|
||||
@@ -3,7 +3,6 @@ import chalk from 'chalk';
|
||||
// @ts-ignore
|
||||
import { handleError } from '../../util/error';
|
||||
|
||||
import createOutput from '../../util/output';
|
||||
import getArgs from '../../util/get-args';
|
||||
import getSubcommand from '../../util/get-subcommand';
|
||||
import logo from '../../util/output/logo';
|
||||
@@ -104,17 +103,17 @@ export default async function main(ctx: NowContext) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const output = createOutput({ debug: argv['--debug'] });
|
||||
const { output } = ctx;
|
||||
const { subcommand, args } = getSubcommand(argv._.slice(1), COMMAND_CONFIG);
|
||||
switch (subcommand) {
|
||||
case 'issue':
|
||||
return issue(ctx, argv, args, output);
|
||||
return issue(ctx, argv, args);
|
||||
case 'ls':
|
||||
return ls(ctx, argv, args, output);
|
||||
return ls(ctx, argv, args);
|
||||
case 'rm':
|
||||
return rm(ctx, argv, args, output);
|
||||
return rm(ctx, argv, args);
|
||||
case 'add':
|
||||
return add(ctx, argv, args, output);
|
||||
return add(ctx, argv, args);
|
||||
case 'renew':
|
||||
output.error('Renewing certificates is deprecated, issue a new one.');
|
||||
return 1;
|
||||
|
||||
@@ -28,11 +28,11 @@ type Options = {
|
||||
export default async function issue(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
) {
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
@@ -55,6 +55,7 @@ export default async function issue(
|
||||
token,
|
||||
currentTeam,
|
||||
debug: debugEnabled,
|
||||
output,
|
||||
});
|
||||
let contextName = null;
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import getScope from '../../util/get-scope';
|
||||
import stamp from '../../util/output/stamp';
|
||||
import getCerts from '../../util/certs/get-certs';
|
||||
import strlen from '../../util/strlen';
|
||||
import { Output } from '../../util/output';
|
||||
import { NowContext, Cert } from '../../types';
|
||||
import getCommandFlags from '../../util/get-command-flags';
|
||||
import { getCommandName } from '../../util/pkg-name';
|
||||
@@ -21,17 +20,17 @@ interface Options {
|
||||
async function ls(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
): Promise<number> {
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
const { apiUrl } = ctx;
|
||||
const { '--debug': debug, '--next': nextTimestamp } = opts;
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug, output });
|
||||
let contextName = null;
|
||||
|
||||
try {
|
||||
@@ -48,7 +47,7 @@ async function ls(
|
||||
output.error('Please provide a number for flag --next');
|
||||
return 1;
|
||||
}
|
||||
const now = new Now({ apiUrl, token, debug, currentTeam });
|
||||
const now = new Now({ apiUrl, token, debug, currentTeam, output });
|
||||
const lsStamp = stamp();
|
||||
|
||||
if (args.length !== 0) {
|
||||
|
||||
@@ -18,21 +18,17 @@ type Options = {
|
||||
'--debug': boolean;
|
||||
};
|
||||
|
||||
async function rm(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
) {
|
||||
async function rm(ctx: NowContext, opts: Options, args: string[]) {
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
const { apiUrl } = ctx;
|
||||
const rmStamp = stamp();
|
||||
const debug = opts['--debug'];
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug, output });
|
||||
|
||||
let contextName = null;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import { resolve, basename } from 'path';
|
||||
import { fileNameSymbol } from '@vercel/client';
|
||||
import Client from '../../util/client.ts';
|
||||
import getScope from '../../util/get-scope.ts';
|
||||
import createOutput from '../../util/output';
|
||||
import code from '../../util/output/code';
|
||||
import highlight from '../../util/output/highlight';
|
||||
import { readLocalConfig } from '../../util/config/files';
|
||||
@@ -15,6 +14,7 @@ import deploy from './latest';
|
||||
export default async ctx => {
|
||||
const {
|
||||
authConfig,
|
||||
output,
|
||||
config: { currentTeam },
|
||||
apiUrl,
|
||||
} = ctx;
|
||||
@@ -48,7 +48,6 @@ export default async ctx => {
|
||||
localConfig = readLocalConfig(paths[0]);
|
||||
}
|
||||
const debugEnabled = argv['--debug'];
|
||||
const output = createOutput({ debug: debugEnabled });
|
||||
const stats = {};
|
||||
|
||||
if (argv['--help']) {
|
||||
@@ -74,6 +73,7 @@ export default async ctx => {
|
||||
apiUrl,
|
||||
token: authConfig.token,
|
||||
currentTeam,
|
||||
output,
|
||||
debug: debugEnabled,
|
||||
});
|
||||
try {
|
||||
|
||||
@@ -233,8 +233,7 @@ export default async function main(
|
||||
const paths = Object.keys(stats);
|
||||
const debugEnabled = argv['--debug'];
|
||||
|
||||
// $FlowFixMe
|
||||
const isTTY = process.stdout.isTTY;
|
||||
const { isTTY } = process.stdout;
|
||||
const quiet = !isTTY;
|
||||
|
||||
// check paths
|
||||
@@ -263,6 +262,7 @@ export default async function main(
|
||||
apiUrl: ctx.apiUrl,
|
||||
token: ctx.authConfig.token,
|
||||
debug: debugEnabled,
|
||||
output,
|
||||
});
|
||||
|
||||
// retrieve `project` and `org` from .vercel
|
||||
@@ -645,6 +645,7 @@ export default async function main(
|
||||
token: ctx.authConfig.token,
|
||||
currentTeam: org.id,
|
||||
debug: debugEnabled,
|
||||
output,
|
||||
}),
|
||||
err.meta.domain,
|
||||
contextName
|
||||
@@ -727,6 +728,7 @@ export default async function main(
|
||||
token: ctx.authConfig.token,
|
||||
currentTeam: org.type === 'team' ? org.id : null,
|
||||
debug: debugEnabled,
|
||||
output,
|
||||
}),
|
||||
deployment,
|
||||
deployStamp,
|
||||
|
||||
@@ -2,16 +2,15 @@ import { resolve, join } from 'path';
|
||||
|
||||
import DevServer from '../../util/dev/server';
|
||||
import parseListen from '../../util/dev/parse-listen';
|
||||
import { Output } from '../../util/output';
|
||||
import { NowContext } from '../../types';
|
||||
import { NowContext, ProjectEnvVariable } from '../../types';
|
||||
import Client from '../../util/client';
|
||||
import { getLinkedProject } from '../../util/projects/link';
|
||||
import { getFrameworks } from '../../util/get-frameworks';
|
||||
import { isSettingValue } from '../../util/is-setting-value';
|
||||
import { ProjectSettings, ProjectEnvTarget } from '../../types';
|
||||
import { ProjectSettings } from '../../types';
|
||||
import getDecryptedEnvRecords from '../../util/get-decrypted-env-records';
|
||||
import { Env } from '@vercel/build-utils';
|
||||
import setupAndLink from '../../util/link/setup-and-link';
|
||||
import getSystemEnvValues from '../../util/env/get-system-env-values';
|
||||
|
||||
type Options = {
|
||||
'--debug'?: boolean;
|
||||
@@ -22,9 +21,9 @@ type Options = {
|
||||
export default async function dev(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
) {
|
||||
const { output } = ctx;
|
||||
const [dir = '.'] = args;
|
||||
let cwd = resolve(dir);
|
||||
const listen = parseListen(opts['--listen'] || '3000');
|
||||
@@ -35,6 +34,7 @@ export default async function dev(
|
||||
token: ctx.authConfig.token,
|
||||
currentTeam: ctx.config.currentTeam,
|
||||
debug,
|
||||
output,
|
||||
});
|
||||
|
||||
// retrieve dev command
|
||||
@@ -49,7 +49,6 @@ export default async function dev(
|
||||
|
||||
link = await setupAndLink(
|
||||
ctx,
|
||||
output,
|
||||
cwd,
|
||||
forceDelete,
|
||||
autoConfirm,
|
||||
@@ -70,7 +69,8 @@ export default async function dev(
|
||||
let devCommand: string | undefined;
|
||||
let frameworkSlug: string | undefined;
|
||||
let projectSettings: ProjectSettings | undefined;
|
||||
let environmentVars: Env | undefined;
|
||||
let projectEnvs: ProjectEnvVariable[] = [];
|
||||
let systemEnvValues: string[] = [];
|
||||
if (link.status === 'linked') {
|
||||
const { project, org } = link;
|
||||
client.currentTeam = org.type === 'team' ? org.id : undefined;
|
||||
@@ -98,12 +98,12 @@ export default async function dev(
|
||||
cwd = join(cwd, project.rootDirectory);
|
||||
}
|
||||
|
||||
environmentVars = await getDecryptedEnvRecords(
|
||||
output,
|
||||
client,
|
||||
project,
|
||||
ProjectEnvTarget.Development
|
||||
);
|
||||
[{ envs: projectEnvs }, { systemEnvValues }] = await Promise.all([
|
||||
getDecryptedEnvRecords(output, client, project.id),
|
||||
project.autoExposeSystemEnvs
|
||||
? getSystemEnvValues(output, client, project.id)
|
||||
: { systemEnvValues: [] },
|
||||
]);
|
||||
}
|
||||
|
||||
const devServer = new DevServer(cwd, {
|
||||
@@ -112,7 +112,8 @@ export default async function dev(
|
||||
devCommand,
|
||||
frameworkSlug,
|
||||
projectSettings,
|
||||
environmentVars,
|
||||
projectEnvs,
|
||||
systemEnvValues,
|
||||
});
|
||||
|
||||
process.once('SIGINT', () => devServer.stop());
|
||||
|
||||
@@ -7,7 +7,6 @@ import getSubcommand from '../../util/get-subcommand';
|
||||
import { NowContext } from '../../types';
|
||||
import { NowError } from '../../util/now-error';
|
||||
import handleError from '../../util/handle-error';
|
||||
import createOutput from '../../util/output/create-output';
|
||||
import logo from '../../util/output/logo';
|
||||
import cmd from '../../util/output/cmd';
|
||||
import highlight from '../../util/output/highlight';
|
||||
@@ -51,7 +50,7 @@ const help = () => {
|
||||
export default async function main(ctx: NowContext) {
|
||||
let argv;
|
||||
let args;
|
||||
let output;
|
||||
const { output } = ctx;
|
||||
|
||||
try {
|
||||
argv = getArgs(ctx.argv.slice(2), {
|
||||
@@ -63,9 +62,7 @@ export default async function main(ctx: NowContext) {
|
||||
'--port': Number,
|
||||
'-p': '--port',
|
||||
});
|
||||
const debug = argv['--debug'];
|
||||
args = getSubcommand(argv._.slice(1), COMMAND_CONFIG).args;
|
||||
output = createOutput({ debug });
|
||||
|
||||
if ('--port' in argv) {
|
||||
output.warn('`--port` is deprecated, please use `--listen` instead');
|
||||
@@ -120,7 +117,7 @@ export default async function main(ctx: NowContext) {
|
||||
}
|
||||
|
||||
try {
|
||||
return await dev(ctx, argv, args, output);
|
||||
return await dev(ctx, argv, args);
|
||||
} catch (err) {
|
||||
if (err.code === 'ENOTFOUND') {
|
||||
// Error message will look like the following:
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
DNSInvalidType,
|
||||
} from '../../util/errors-ts';
|
||||
import { NowContext } from '../../types';
|
||||
import { Output } from '../../util/output';
|
||||
import addDNSRecord from '../../util/dns/add-dns-record';
|
||||
import Client from '../../util/client';
|
||||
import getScope from '../../util/get-scope';
|
||||
@@ -22,17 +21,17 @@ type Options = {
|
||||
export default async function add(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
) {
|
||||
const {
|
||||
apiUrl,
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
const { apiUrl } = ctx;
|
||||
const debug = opts['--debug'];
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug, output });
|
||||
let contextName = null;
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import chalk from 'chalk';
|
||||
import { NowContext } from '../../types';
|
||||
import { Output } from '../../util/output';
|
||||
import Client from '../../util/client';
|
||||
import getScope from '../../util/get-scope';
|
||||
import { DomainNotFound, InvalidDomain } from '../../util/errors-ts';
|
||||
@@ -15,17 +14,17 @@ type Options = {
|
||||
export default async function add(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
) {
|
||||
const {
|
||||
apiUrl,
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
const { apiUrl } = ctx;
|
||||
const debug = opts['--debug'];
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug, output });
|
||||
let contextName = null;
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { NowContext } from '../../types';
|
||||
import createOutput from '../../util/output';
|
||||
import getArgs from '../../util/get-args';
|
||||
import getSubcommand from '../../util/get-subcommand';
|
||||
import handleError from '../../util/handle-error';
|
||||
@@ -112,16 +111,15 @@ export default async function main(ctx: NowContext) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
const output = createOutput({ debug: argv['--debug'] });
|
||||
const { subcommand, args } = getSubcommand(argv._.slice(1), COMMAND_CONFIG);
|
||||
switch (subcommand) {
|
||||
case 'add':
|
||||
return add(ctx, argv, args, output);
|
||||
return add(ctx, argv, args);
|
||||
case 'import':
|
||||
return importZone(ctx, argv, args, output);
|
||||
return importZone(ctx, argv, args);
|
||||
case 'rm':
|
||||
return rm(ctx, argv, args, output);
|
||||
return rm(ctx, argv, args);
|
||||
default:
|
||||
return ls(ctx, argv, args, output);
|
||||
return ls(ctx, argv, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import chalk from 'chalk';
|
||||
import ms from 'ms';
|
||||
import { Output } from '../../util/output';
|
||||
import { DomainNotFound } from '../../util/errors-ts';
|
||||
import { DNSRecord, NowContext } from '../../types';
|
||||
import Client from '../../util/client';
|
||||
@@ -22,17 +21,17 @@ type Options = {
|
||||
export default async function ls(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
) {
|
||||
const {
|
||||
apiUrl,
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
const { apiUrl } = ctx;
|
||||
const { '--debug': debug, '--next': nextTimestamp } = opts;
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug, output });
|
||||
let contextName = null;
|
||||
|
||||
try {
|
||||
|
||||
@@ -17,17 +17,17 @@ type Options = {
|
||||
export default async function rm(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
) {
|
||||
const {
|
||||
apiUrl,
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
const { apiUrl } = ctx;
|
||||
const debug = opts['--debug'];
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug, output });
|
||||
|
||||
try {
|
||||
await getScope(client);
|
||||
@@ -100,12 +100,7 @@ function readConfirmation(
|
||||
process.stdin
|
||||
.on('data', d => {
|
||||
process.stdin.pause();
|
||||
resolve(
|
||||
d
|
||||
.toString()
|
||||
.trim()
|
||||
.toLowerCase() === 'y'
|
||||
);
|
||||
resolve(d.toString().trim().toLowerCase() === 'y');
|
||||
})
|
||||
.resume();
|
||||
});
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { NowContext } from '../../types';
|
||||
import { Output } from '../../util/output';
|
||||
import * as ERRORS from '../../util/errors-ts';
|
||||
import Client from '../../util/client';
|
||||
import formatNSTable from '../../util/format-ns-table';
|
||||
@@ -24,18 +23,18 @@ type Options = {
|
||||
export default async function add(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
) {
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
const { apiUrl } = ctx;
|
||||
const debug = opts['--debug'];
|
||||
const force = opts['--force'];
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug, output });
|
||||
let contextName = null;
|
||||
|
||||
try {
|
||||
|
||||
@@ -2,7 +2,6 @@ import chalk from 'chalk';
|
||||
import psl from 'psl';
|
||||
|
||||
import { NowContext } from '../../types';
|
||||
import { Output } from '../../util/output';
|
||||
import * as ERRORS from '../../util/errors-ts';
|
||||
import Client from '../../util/client';
|
||||
import getDomainPrice from '../../util/domains/get-domain-price';
|
||||
@@ -21,17 +20,17 @@ type Options = {
|
||||
export default async function buy(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
) {
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
const { apiUrl } = ctx;
|
||||
const debug = opts['--debug'];
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug, output });
|
||||
let contextName = null;
|
||||
|
||||
try {
|
||||
@@ -70,7 +69,10 @@ export default async function buy(
|
||||
}
|
||||
|
||||
const availableStamp = stamp();
|
||||
const domainPrice = await getDomainPrice(client, domainName);
|
||||
const [domainPrice, renewalPrice] = await Promise.all([
|
||||
getDomainPrice(client, domainName),
|
||||
getDomainPrice(client, domainName, 'renewal'),
|
||||
]);
|
||||
|
||||
if (domainPrice instanceof Error) {
|
||||
output.prettyError(domainPrice);
|
||||
@@ -102,12 +104,21 @@ export default async function buy(
|
||||
return 0;
|
||||
}
|
||||
|
||||
const autoRenew = await promptBool(
|
||||
renewalPrice.period === 1
|
||||
? `Auto renew yearly for ${chalk.bold(`$${price}`)}?`
|
||||
: `Auto renew every ${renewalPrice.period} years for ${chalk.bold(
|
||||
`$${price}`
|
||||
)}?`,
|
||||
{ defaultValue: true }
|
||||
);
|
||||
|
||||
let buyResult;
|
||||
const purchaseStamp = stamp();
|
||||
const stopPurchaseSpinner = output.spinner('Purchasing');
|
||||
|
||||
try {
|
||||
buyResult = await purchaseDomain(client, domainName, price);
|
||||
buyResult = await purchaseDomain(client, domainName, price, autoRenew);
|
||||
} catch (err) {
|
||||
stopPurchaseSpinner();
|
||||
output.error(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { NowContext } from '../../types';
|
||||
import createOutput from '../../util/output';
|
||||
import getArgs from '../../util/get-args';
|
||||
import getSubcommand from '../../util/get-subcommand';
|
||||
import handleError from '../../util/handle-error';
|
||||
@@ -106,24 +105,23 @@ export default async function main(ctx: NowContext) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
const output = createOutput({ debug: argv['--debug'] });
|
||||
const { subcommand, args } = getSubcommand(argv._.slice(1), COMMAND_CONFIG);
|
||||
switch (subcommand) {
|
||||
case 'add':
|
||||
return add(ctx, argv, args, output);
|
||||
return add(ctx, argv, args);
|
||||
case 'inspect':
|
||||
return inspect(ctx, argv, args, output);
|
||||
return inspect(ctx, argv, args);
|
||||
case 'move':
|
||||
return move(ctx, argv, args, output);
|
||||
return move(ctx, argv, args);
|
||||
case 'buy':
|
||||
return buy(ctx, argv, args, output);
|
||||
return buy(ctx, argv, args);
|
||||
case 'rm':
|
||||
return rm(ctx, argv, args, output);
|
||||
return rm(ctx, argv, args);
|
||||
case 'transferIn':
|
||||
return transferIn(ctx, argv, args, output);
|
||||
return transferIn(ctx, argv, args);
|
||||
case 'verify':
|
||||
return verify(ctx, argv, args, output);
|
||||
return verify(ctx, argv, args);
|
||||
default:
|
||||
return ls(ctx, argv, args, output);
|
||||
return ls(ctx, argv, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,17 +24,17 @@ type Options = {
|
||||
export default async function inspect(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
) {
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
const { apiUrl } = ctx;
|
||||
const debug = opts['--debug'];
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug, output });
|
||||
|
||||
let contextName = null;
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import Client from '../../util/client';
|
||||
import getDomains from '../../util/domains/get-domains';
|
||||
import getScope from '../../util/get-scope';
|
||||
import stamp from '../../util/output/stamp';
|
||||
import { Output } from '../../util/output';
|
||||
import formatTable from '../../util/format-table';
|
||||
import { formatDateWithoutTime } from '../../util/format-date';
|
||||
import { Domain, NowContext } from '../../types';
|
||||
@@ -24,17 +23,17 @@ type Options = {
|
||||
export default async function ls(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
) {
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
const { apiUrl } = ctx;
|
||||
const { '--debug': debug, '--next': nextTimestamp } = opts;
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug, output });
|
||||
let contextName = null;
|
||||
|
||||
if (typeof nextTimestamp !== undefined && Number.isNaN(nextTimestamp)) {
|
||||
|
||||
@@ -2,7 +2,6 @@ import chalk from 'chalk';
|
||||
import plural from 'pluralize';
|
||||
|
||||
import { NowContext, User, Team } from '../../types';
|
||||
import { Output } from '../../util/output';
|
||||
import * as ERRORS from '../../util/errors-ts';
|
||||
import Client from '../../util/client';
|
||||
import getScope from '../../util/get-scope';
|
||||
@@ -25,17 +24,17 @@ type Options = {
|
||||
export default async function move(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
) {
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
const { apiUrl } = ctx;
|
||||
const debug = opts['--debug'];
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug, output });
|
||||
let contextName = null;
|
||||
let user = null;
|
||||
|
||||
|
||||
@@ -26,17 +26,17 @@ type Options = {
|
||||
export default async function rm(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
) {
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
const { apiUrl } = ctx;
|
||||
const debug = opts['--debug'];
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug, output });
|
||||
const [domainName] = args;
|
||||
let contextName = null;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { NowContext } from '../../types';
|
||||
import { Output } from '../../util/output';
|
||||
import * as ERRORS from '../../util/errors-ts';
|
||||
import Client from '../../util/client';
|
||||
import getScope from '../../util/get-scope';
|
||||
@@ -24,17 +23,17 @@ type Options = {
|
||||
export default async function transferIn(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
) {
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
const { apiUrl } = ctx;
|
||||
const debug = opts['--debug'];
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug, output });
|
||||
let contextName = null;
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { NowContext } from '../../types';
|
||||
import { Output } from '../../util/output';
|
||||
import { NowBuildError } from '@vercel/build-utils';
|
||||
import { getCommandName } from '../../util/pkg-name';
|
||||
|
||||
export default async function verify(
|
||||
_ctx: NowContext,
|
||||
{ output }: NowContext,
|
||||
_opts: {},
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
) {
|
||||
const [domainName] = args;
|
||||
|
||||
|
||||
26
packages/now-cli/src/commands/env/add.ts
vendored
26
packages/now-cli/src/commands/env/add.ts
vendored
@@ -18,7 +18,7 @@ import withSpinner from '../../util/with-spinner';
|
||||
import { emoji, prependEmoji } from '../../util/emoji';
|
||||
import { isKnownError } from '../../util/env/known-error';
|
||||
import { getCommandName } from '../../util/pkg-name';
|
||||
import { SYSTEM_ENV_VALUES } from '../../util/env/system-env';
|
||||
import getSystemEnvValues from '../../util/env/get-system-env-values';
|
||||
|
||||
type Options = {
|
||||
'--debug': boolean;
|
||||
@@ -91,7 +91,10 @@ export default async function add(
|
||||
name: `Secret (can be created using ${getCommandName('secret add')})`,
|
||||
value: ProjectEnvType.Secret,
|
||||
},
|
||||
{ name: 'Provided by System', value: ProjectEnvType.System },
|
||||
{
|
||||
name: 'Reference to System Environment Variable',
|
||||
value: ProjectEnvType.System,
|
||||
},
|
||||
],
|
||||
})) as { inputEnvType: ProjectEnvType };
|
||||
|
||||
@@ -112,11 +115,24 @@ export default async function add(
|
||||
}
|
||||
}
|
||||
|
||||
const { envs } = await getEnvVariables(output, client, project.id);
|
||||
const [{ envs }, { systemEnvValues }] = await Promise.all([
|
||||
getEnvVariables(output, client, project.id),
|
||||
getSystemEnvValues(output, client, project.id),
|
||||
]);
|
||||
const existing = new Set(
|
||||
envs.filter(r => r.key === envName).map(r => r.target)
|
||||
);
|
||||
const choices = getEnvTargetChoices().filter(c => !existing.has(c.value));
|
||||
const choices = getEnvTargetChoices().filter(c => {
|
||||
// hide Development if "Secret" is chosen
|
||||
if (
|
||||
envType === ProjectEnvType.Secret &&
|
||||
c.value === ProjectEnvTarget.Development
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !existing.has(c.value);
|
||||
});
|
||||
|
||||
if (choices.length === 0) {
|
||||
output.error(
|
||||
@@ -182,7 +198,7 @@ export default async function add(
|
||||
name: 'systemEnvValue',
|
||||
type: 'list',
|
||||
message: `What’s the value of ${envName}?`,
|
||||
choices: SYSTEM_ENV_VALUES.map(value => ({ name: value, value })),
|
||||
choices: systemEnvValues.map(value => ({ name: value, value })),
|
||||
});
|
||||
|
||||
envValue = systemEnvValue;
|
||||
|
||||
7
packages/now-cli/src/commands/env/index.ts
vendored
7
packages/now-cli/src/commands/env/index.ts
vendored
@@ -1,7 +1,6 @@
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { NowContext } from '../../types';
|
||||
import createOutput from '../../util/output';
|
||||
import getArgs from '../../util/get-args';
|
||||
import getSubcommand from '../../util/get-subcommand';
|
||||
import getInvalidSubcommand from '../../util/get-invalid-subcommand';
|
||||
@@ -109,15 +108,15 @@ export default async function main(ctx: NowContext) {
|
||||
}
|
||||
|
||||
const debug = argv['--debug'];
|
||||
const output = createOutput({ debug });
|
||||
const { subcommand, args } = getSubcommand(argv._.slice(1), COMMAND_CONFIG);
|
||||
const {
|
||||
authConfig: { token },
|
||||
apiUrl,
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
const { apiUrl } = ctx;
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug, output });
|
||||
const link = await getLinkedProject(output, client);
|
||||
if (link.status === 'error') {
|
||||
return link.exitCode;
|
||||
|
||||
30
packages/now-cli/src/commands/env/pull.ts
vendored
30
packages/now-cli/src/commands/env/pull.ts
vendored
@@ -1,5 +1,5 @@
|
||||
import chalk from 'chalk';
|
||||
import { ProjectEnvTarget, Project } from '../../types';
|
||||
import { Project } from '../../types';
|
||||
import { Output } from '../../util/output';
|
||||
import confirm from '../../util/input/confirm';
|
||||
import Client from '../../util/client';
|
||||
@@ -12,7 +12,8 @@ import { promises, openSync, closeSync, readSync } from 'fs';
|
||||
import { emoji, prependEmoji } from '../../util/emoji';
|
||||
import { getCommandName } from '../../util/pkg-name';
|
||||
const { writeFile } = promises;
|
||||
import { Env } from '@vercel/build-utils';
|
||||
import exposeSystemEnvs from '../../util/dev/expose-system-envs';
|
||||
import getSystemEnvValues from '../../util/env/get-system-env-values';
|
||||
|
||||
const CONTENTS_PREFIX = '# Created by Vercel CLI\n';
|
||||
|
||||
@@ -84,15 +85,22 @@ export default async function pull(
|
||||
);
|
||||
const pullStamp = stamp();
|
||||
|
||||
const records: Env = await withSpinner(
|
||||
'Downloading',
|
||||
async () =>
|
||||
await getDecryptedEnvRecords(
|
||||
output,
|
||||
client,
|
||||
project,
|
||||
ProjectEnvTarget.Development
|
||||
)
|
||||
const [
|
||||
{ envs: projectEnvs },
|
||||
{ systemEnvValues },
|
||||
] = await withSpinner('Downloading', () =>
|
||||
Promise.all([
|
||||
getDecryptedEnvRecords(output, client, project.id),
|
||||
project.autoExposeSystemEnvs
|
||||
? getSystemEnvValues(output, client, project.id)
|
||||
: { systemEnvValues: [] },
|
||||
])
|
||||
);
|
||||
|
||||
const records = exposeSystemEnvs(
|
||||
projectEnvs,
|
||||
systemEnvValues,
|
||||
project.autoExposeSystemEnvs
|
||||
);
|
||||
|
||||
const contents =
|
||||
|
||||
@@ -4,7 +4,6 @@ import getArgs from '../../util/get-args';
|
||||
import getSubcommand from '../../util/get-subcommand';
|
||||
import { NowContext } from '../../types';
|
||||
import handleError from '../../util/handle-error';
|
||||
import createOutput from '../../util/output/create-output';
|
||||
import logo from '../../util/output/logo';
|
||||
import error from '../../util/output/error';
|
||||
import init from './init';
|
||||
@@ -47,7 +46,6 @@ const help = () => {
|
||||
export default async function main(ctx: NowContext) {
|
||||
let argv;
|
||||
let args;
|
||||
let output;
|
||||
|
||||
try {
|
||||
argv = getArgs(ctx.argv.slice(2), {
|
||||
@@ -55,7 +53,6 @@ export default async function main(ctx: NowContext) {
|
||||
'-f': Boolean,
|
||||
});
|
||||
args = getSubcommand(argv._.slice(1), COMMAND_CONFIG).args;
|
||||
output = createOutput({ debug: argv['--debug'] });
|
||||
} catch (err) {
|
||||
handleError(err);
|
||||
return 1;
|
||||
@@ -67,15 +64,15 @@ export default async function main(ctx: NowContext) {
|
||||
}
|
||||
|
||||
if (argv._.length > 3) {
|
||||
output.error('Too much arguments.');
|
||||
ctx.output.error('Too much arguments.');
|
||||
return 1;
|
||||
}
|
||||
|
||||
try {
|
||||
return await init(ctx, argv, args, output);
|
||||
return await init(ctx, argv, args);
|
||||
} catch (err) {
|
||||
console.log(error(err.message));
|
||||
output.debug(err.stack);
|
||||
ctx.output.debug(err.stack);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,9 +34,9 @@ const EXAMPLE_API = 'https://now-example-files.zeit.sh';
|
||||
export default async function init(
|
||||
ctx: NowContext,
|
||||
opts: Options,
|
||||
args: string[],
|
||||
output: Output
|
||||
args: string[]
|
||||
) {
|
||||
const { output } = ctx;
|
||||
const [name, dir] = args;
|
||||
const force = opts['-f'] || opts['--force'];
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import getArgs from '../util/get-args';
|
||||
import buildsList from '../util/output/builds';
|
||||
import routesList from '../util/output/routes';
|
||||
import indent from '../util/output/indent';
|
||||
import createOutput from '../util/output';
|
||||
import Now from '../util';
|
||||
import logo from '../util/output/logo';
|
||||
import elapsed from '../util/output/elapsed.ts';
|
||||
@@ -59,9 +58,13 @@ export default async function main(ctx) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
const apiUrl = ctx.apiUrl;
|
||||
const {
|
||||
apiUrl,
|
||||
output,
|
||||
authConfig: { token },
|
||||
config,
|
||||
} = ctx;
|
||||
const debugEnabled = argv['--debug'];
|
||||
const output = createOutput({ debug: debugEnabled });
|
||||
const { print, log, error } = output;
|
||||
|
||||
// extract the first parameter
|
||||
@@ -73,16 +76,13 @@ export default async function main(ctx) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const {
|
||||
authConfig: { token },
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
const client = new Client({
|
||||
apiUrl,
|
||||
token,
|
||||
currentTeam,
|
||||
debug: debugEnabled,
|
||||
output,
|
||||
});
|
||||
let contextName = null;
|
||||
|
||||
@@ -90,25 +90,30 @@ export default async function main(ctx) {
|
||||
({ contextName } = await getScope(client));
|
||||
} catch (err) {
|
||||
if (err.code === 'NOT_AUTHORIZED' || err.code === 'TEAM_DELETED') {
|
||||
output.error(err.message);
|
||||
error(err.message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
const now = new Now({ apiUrl, token, debug: debugEnabled, currentTeam });
|
||||
const now = new Now({
|
||||
apiUrl,
|
||||
token,
|
||||
debug: debugEnabled,
|
||||
currentTeam,
|
||||
output,
|
||||
});
|
||||
|
||||
// resolve the deployment, since we might have been given an alias
|
||||
const depFetchStart = Date.now();
|
||||
const cancelWait = output.spinner(
|
||||
output.spinner(
|
||||
`Fetching deployment "${deploymentIdOrHost}" in ${chalk.bold(contextName)}`
|
||||
);
|
||||
|
||||
try {
|
||||
deployment = await now.findDeployment(deploymentIdOrHost);
|
||||
} catch (err) {
|
||||
cancelWait();
|
||||
if (err.status === 404) {
|
||||
error(
|
||||
`Failed to find deployment "${deploymentIdOrHost}" in ${chalk.bold(
|
||||
@@ -136,7 +141,6 @@ export default async function main(ctx) {
|
||||
? await now.fetch(`/v1/now/deployments/${id}/builds`)
|
||||
: { builds: [] };
|
||||
|
||||
cancelWait();
|
||||
log(
|
||||
`Fetched deployment "${url}" in ${chalk.bold(contextName)} ${elapsed(
|
||||
Date.now() - depFetchStart
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import chalk from 'chalk';
|
||||
import { NowContext } from '../../types';
|
||||
import createOutput from '../../util/output';
|
||||
import getArgs from '../../util/get-args';
|
||||
import getSubcommand from '../../util/get-subcommand';
|
||||
import handleError from '../../util/handle-error';
|
||||
@@ -66,8 +65,6 @@ export default async function main(ctx: NowContext) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
const debug = argv['--debug'];
|
||||
const output = createOutput({ debug });
|
||||
const { args } = getSubcommand(argv._.slice(1), COMMAND_CONFIG);
|
||||
const path = args[0] || process.cwd();
|
||||
const autoConfirm = argv['--confirm'];
|
||||
@@ -75,7 +72,6 @@ export default async function main(ctx: NowContext) {
|
||||
|
||||
const link = await setupAndLink(
|
||||
ctx,
|
||||
output,
|
||||
path,
|
||||
forceDelete,
|
||||
autoConfirm,
|
||||
|
||||
@@ -3,12 +3,10 @@ import ms from 'ms';
|
||||
import table from 'text-table';
|
||||
import Now from '../util';
|
||||
import getArgs from '../util/get-args';
|
||||
import createOutput from '../util/output';
|
||||
import { handleError } from '../util/error';
|
||||
import cmd from '../util/output/cmd.ts';
|
||||
import logo from '../util/output/logo';
|
||||
import elapsed from '../util/output/elapsed.ts';
|
||||
import wait from '../util/output/wait';
|
||||
import strlen from '../util/strlen.ts';
|
||||
import Client from '../util/client.ts';
|
||||
import getScope from '../util/get-scope.ts';
|
||||
@@ -51,12 +49,6 @@ const help = () => {
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} ls my-app`)}
|
||||
|
||||
${chalk.gray(
|
||||
'–'
|
||||
)} List all deployments and all instances for the app ${chalk.dim('`my-app`')}
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} ls my-app --all`)}
|
||||
|
||||
${chalk.gray('–')} Filter deployments by metadata
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} ls -m key1=value1 -m key2=value2`)}
|
||||
@@ -84,11 +76,15 @@ export default async function main(ctx) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const debugEnabled = argv['--debug'];
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
apiUrl,
|
||||
config,
|
||||
} = ctx;
|
||||
|
||||
const { print, log, error, note, debug } = createOutput({
|
||||
debug: debugEnabled,
|
||||
});
|
||||
const debugEnabled = argv['--debug'];
|
||||
const { print, log, error, note, debug, spinner } = output;
|
||||
|
||||
if (argv._.length > 2) {
|
||||
error(`${getCommandName('ls [app]')} accepts at most one argument`);
|
||||
@@ -98,24 +94,19 @@ export default async function main(ctx) {
|
||||
let app = argv._[1];
|
||||
let host = null;
|
||||
|
||||
const apiUrl = ctx.apiUrl;
|
||||
|
||||
if (argv['--help']) {
|
||||
help();
|
||||
return 0;
|
||||
}
|
||||
|
||||
const meta = parseMeta(argv['--meta']);
|
||||
const {
|
||||
authConfig: { token },
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam, includeScheme } = config;
|
||||
const client = new Client({
|
||||
apiUrl,
|
||||
token,
|
||||
currentTeam,
|
||||
debug: debugEnabled,
|
||||
output,
|
||||
});
|
||||
let contextName = null;
|
||||
|
||||
@@ -137,11 +128,15 @@ export default async function main(ctx) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const stopSpinner = wait(
|
||||
`Fetching deployments in ${chalk.bold(contextName)}`
|
||||
);
|
||||
spinner(`Fetching deployments in ${chalk.bold(contextName)}`);
|
||||
|
||||
const now = new Now({ apiUrl, token, debug: debugEnabled, currentTeam });
|
||||
const now = new Now({
|
||||
apiUrl,
|
||||
token,
|
||||
debug: debugEnabled,
|
||||
output,
|
||||
currentTeam,
|
||||
});
|
||||
const start = new Date();
|
||||
|
||||
if (app && !isValidName(app)) {
|
||||
@@ -162,7 +157,6 @@ export default async function main(ctx) {
|
||||
const hostParts = asHost.split('-');
|
||||
|
||||
if (hostParts < 2) {
|
||||
stopSpinner();
|
||||
error('Only deployment hostnames are allowed, no aliases');
|
||||
return 1;
|
||||
}
|
||||
@@ -171,19 +165,12 @@ export default async function main(ctx) {
|
||||
host = asHost;
|
||||
}
|
||||
|
||||
let response;
|
||||
|
||||
try {
|
||||
debug('Fetching deployments');
|
||||
response = await now.list(app, {
|
||||
version: 6,
|
||||
meta,
|
||||
nextTimestamp,
|
||||
});
|
||||
} catch (err) {
|
||||
stopSpinner();
|
||||
throw err;
|
||||
}
|
||||
debug('Fetching deployments');
|
||||
const response = await now.list(app, {
|
||||
version: 6,
|
||||
meta,
|
||||
nextTimestamp,
|
||||
});
|
||||
|
||||
let { deployments, pagination } = response;
|
||||
|
||||
@@ -199,7 +186,6 @@ export default async function main(ctx) {
|
||||
if (err.status === 404) {
|
||||
debug('Ignore findDeployment 404');
|
||||
} else {
|
||||
stopSpinner();
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@@ -216,7 +202,6 @@ export default async function main(ctx) {
|
||||
deployments = deployments.filter(deployment => deployment.url === host);
|
||||
}
|
||||
|
||||
stopSpinner();
|
||||
log(
|
||||
`Deployments under ${chalk.bold(contextName)} ${elapsed(
|
||||
Date.now() - start
|
||||
|
||||
@@ -19,7 +19,6 @@ import getGlobalPathConfig 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';
|
||||
import { prependEmoji, emoji } from '../util/emoji';
|
||||
import { getCommandName, getPkgName } from '../util/pkg-name.ts';
|
||||
@@ -141,15 +140,12 @@ const login = async ctx => {
|
||||
await exit(0);
|
||||
}
|
||||
|
||||
const debugEnabled = argv['--debug'];
|
||||
const output = createOutput({ debug: debugEnabled });
|
||||
const { apiUrl, output } = ctx;
|
||||
|
||||
argv._ = argv._.slice(1);
|
||||
|
||||
const apiUrl = ctx.apiUrl;
|
||||
let email;
|
||||
let emailIsValid = false;
|
||||
let stopSpinner;
|
||||
|
||||
const possibleAddress = argv._[0];
|
||||
|
||||
@@ -190,19 +186,18 @@ const login = async ctx => {
|
||||
let verificationToken;
|
||||
let securityCode;
|
||||
|
||||
stopSpinner = output.spinner('Sending you an email');
|
||||
output.spinner('Sending you an email');
|
||||
|
||||
try {
|
||||
const data = await executeLogin(apiUrl, email);
|
||||
verificationToken = data.token;
|
||||
securityCode = data.securityCode;
|
||||
} catch (err) {
|
||||
stopSpinner();
|
||||
console.log(error(err.message));
|
||||
output.error(err.message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
stopSpinner();
|
||||
output.stopSpinner();
|
||||
|
||||
// Clear up `Sending email` success message
|
||||
process.stdout.write(eraseLines(possibleAddress ? 1 : 2));
|
||||
@@ -215,7 +210,7 @@ const login = async ctx => {
|
||||
)}.\n`
|
||||
);
|
||||
|
||||
stopSpinner = output.spinner('Waiting for your confirmation');
|
||||
output.spinner('Waiting for your confirmation');
|
||||
|
||||
let token;
|
||||
|
||||
@@ -228,14 +223,13 @@ const login = async ctx => {
|
||||
// /now/registraton is currently returning plain text in that case
|
||||
// we just wait for the user to click on the link
|
||||
} else {
|
||||
stopSpinner();
|
||||
console.log(err.message);
|
||||
output.error(err.message);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stopSpinner();
|
||||
output.stopSpinner();
|
||||
console.log(ok('Email confirmed'));
|
||||
|
||||
// There's no need to save the user since we always
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
} from '../util/config/files';
|
||||
import getArgs from '../util/get-args';
|
||||
import { NowContext } from '../types';
|
||||
import createOutput, { Output } from '../util/output';
|
||||
import { Output } from '../util/output';
|
||||
import { getPkgName } from '../util/pkg-name';
|
||||
|
||||
const help = () => {
|
||||
@@ -54,9 +54,7 @@ export default async function main(ctx: NowContext): Promise<number> {
|
||||
return 2;
|
||||
}
|
||||
|
||||
const debugEnabled = argv['--debug'];
|
||||
const output = createOutput({ debug: debugEnabled });
|
||||
return logout(ctx.apiUrl, output);
|
||||
return logout(ctx.apiUrl, ctx.output);
|
||||
}
|
||||
|
||||
const logout = async (apiUrl: string, output: Output) => {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import mri from 'mri';
|
||||
import chalk from 'chalk';
|
||||
import Now from '../util';
|
||||
import createOutput from '../util/output';
|
||||
import logo from '../util/output/logo';
|
||||
import elapsed from '../util/output/elapsed.ts';
|
||||
import { maybeURL, normalizeURL } from '../util/url';
|
||||
@@ -59,7 +58,6 @@ export default async function main(ctx) {
|
||||
let deploymentIdOrURL;
|
||||
|
||||
let debug;
|
||||
let apiUrl;
|
||||
let head;
|
||||
let limit;
|
||||
let follow;
|
||||
@@ -87,8 +85,12 @@ export default async function main(ctx) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
const debugEnabled = argv.debug;
|
||||
const output = createOutput({ debug: debugEnabled });
|
||||
const {
|
||||
authConfig: { token },
|
||||
apiUrl,
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
|
||||
try {
|
||||
since = argv.since ? toTimestamp(argv.since) : 0;
|
||||
@@ -117,7 +119,6 @@ export default async function main(ctx) {
|
||||
}
|
||||
|
||||
debug = argv.debug;
|
||||
apiUrl = ctx.apiUrl;
|
||||
|
||||
head = argv.head;
|
||||
limit = typeof argv.n === 'number' ? argv.n : 100;
|
||||
@@ -125,17 +126,14 @@ export default async function main(ctx) {
|
||||
if (follow) until = 0;
|
||||
outputMode = argv.output in logPrinters ? argv.output : 'short';
|
||||
|
||||
const {
|
||||
authConfig: { token },
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
const now = new Now({ apiUrl, token, debug, currentTeam });
|
||||
const now = new Now({ apiUrl, token, debug, currentTeam, output });
|
||||
const client = new Client({
|
||||
apiUrl,
|
||||
token,
|
||||
currentTeam,
|
||||
debug: debugEnabled,
|
||||
debug,
|
||||
output,
|
||||
});
|
||||
let contextName = null;
|
||||
|
||||
@@ -206,6 +204,7 @@ export default async function main(ctx) {
|
||||
quiet: false,
|
||||
debug,
|
||||
findOpts: findOpts1,
|
||||
output,
|
||||
});
|
||||
|
||||
const printedEventIds = new Set();
|
||||
@@ -232,6 +231,7 @@ export default async function main(ctx) {
|
||||
quiet: false,
|
||||
debug,
|
||||
findOpts: findOpts2,
|
||||
output,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -324,7 +324,7 @@ function printLogRaw(log) {
|
||||
|
||||
if (log.object) {
|
||||
console.log(log.object);
|
||||
} else {
|
||||
} else if (typeof log.text === 'string') {
|
||||
console.log(
|
||||
log.text
|
||||
.replace(/\n$/, '')
|
||||
|
||||
@@ -8,7 +8,6 @@ import exit from '../util/exit';
|
||||
import Client from '../util/client.ts';
|
||||
import logo from '../util/output/logo';
|
||||
import getScope from '../util/get-scope';
|
||||
import createOutput from '../util/output';
|
||||
import getCommandFlags from '../util/get-command-flags';
|
||||
import wait from '../util/output/wait';
|
||||
import { getPkgName, getCommandName } from '../util/pkg-name.ts';
|
||||
@@ -76,13 +75,12 @@ const main = async ctx => {
|
||||
return exit(2);
|
||||
}
|
||||
|
||||
const output = createOutput({ debug });
|
||||
|
||||
const {
|
||||
authConfig: { token },
|
||||
config: { currentTeam },
|
||||
output,
|
||||
} = ctx;
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug, output });
|
||||
|
||||
let contextName = null;
|
||||
|
||||
@@ -288,12 +286,7 @@ function readConfirmation(projectName) {
|
||||
process.stdin
|
||||
.on('data', d => {
|
||||
process.stdin.pause();
|
||||
resolve(
|
||||
d
|
||||
.toString()
|
||||
.trim()
|
||||
.toLowerCase() === 'y'
|
||||
);
|
||||
resolve(d.toString().trim().toLowerCase() === 'y');
|
||||
})
|
||||
.resume();
|
||||
});
|
||||
|
||||
@@ -5,7 +5,6 @@ import plural from 'pluralize';
|
||||
import table from 'text-table';
|
||||
import Now from '../util';
|
||||
import getAliases from '../util/alias/get-aliases';
|
||||
import createOutput from '../util/output';
|
||||
import logo from '../util/output/logo';
|
||||
import elapsed from '../util/output/elapsed.ts';
|
||||
import { normalizeURL } from '../util/url';
|
||||
@@ -79,12 +78,16 @@ export default async function main(ctx) {
|
||||
|
||||
argv._ = argv._.slice(1);
|
||||
|
||||
const apiUrl = ctx.apiUrl;
|
||||
const {
|
||||
apiUrl,
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const hard = argv.hard || false;
|
||||
const skipConfirmation = argv.yes || false;
|
||||
const ids = argv._;
|
||||
const debugEnabled = argv.debug;
|
||||
const output = createOutput({ debug: debugEnabled });
|
||||
const { success, error, log } = output;
|
||||
|
||||
if (argv.help || ids[0] === 'help') {
|
||||
@@ -107,16 +110,13 @@ export default async function main(ctx) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const {
|
||||
authConfig: { token },
|
||||
config,
|
||||
} = ctx;
|
||||
const { currentTeam } = config;
|
||||
const client = new Client({
|
||||
apiUrl,
|
||||
token,
|
||||
currentTeam,
|
||||
debug: debugEnabled,
|
||||
output,
|
||||
});
|
||||
let contextName = null;
|
||||
|
||||
@@ -235,11 +235,9 @@ export default async function main(ctx) {
|
||||
}
|
||||
|
||||
if (!skipConfirmation) {
|
||||
const confirmation = (await readConfirmation(
|
||||
deployments,
|
||||
projects,
|
||||
output
|
||||
)).toLowerCase();
|
||||
const confirmation = (
|
||||
await readConfirmation(deployments, projects, output)
|
||||
).toLowerCase();
|
||||
|
||||
if (confirmation !== 'y' && confirmation !== 'yes') {
|
||||
output.log('Aborted');
|
||||
@@ -248,7 +246,13 @@ export default async function main(ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
const now = new Now({ apiUrl, token, debug: debugEnabled, currentTeam });
|
||||
const now = new Now({
|
||||
apiUrl,
|
||||
token,
|
||||
debug: debugEnabled,
|
||||
currentTeam,
|
||||
output,
|
||||
});
|
||||
const start = new Date();
|
||||
|
||||
await Promise.all([
|
||||
|
||||
@@ -9,7 +9,6 @@ import exit from '../util/exit';
|
||||
import logo from '../util/output/logo';
|
||||
import Client from '../util/client.ts';
|
||||
import getScope from '../util/get-scope.ts';
|
||||
import createOutput from '../util/output';
|
||||
import confirm from '../util/input/confirm';
|
||||
import getCommandFlags from '../util/get-command-flags';
|
||||
import getPrefixedFlags from '../util/get-prefixed-flags';
|
||||
@@ -104,10 +103,10 @@ const main = async ctx => {
|
||||
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
config: { currentTeam },
|
||||
} = ctx;
|
||||
const output = createOutput({ debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug });
|
||||
const client = new Client({ apiUrl, token, currentTeam, debug, output });
|
||||
let contextName = null;
|
||||
|
||||
try {
|
||||
@@ -139,7 +138,7 @@ export default async ctx => {
|
||||
};
|
||||
|
||||
async function run({ output, token, contextName, currentTeam, ctx }) {
|
||||
const secrets = new NowSecrets({ apiUrl, token, debug, currentTeam });
|
||||
const secrets = new NowSecrets({ apiUrl, token, debug, currentTeam, output });
|
||||
const args = argv._.slice(1);
|
||||
const start = Date.now();
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ const help = () => {
|
||||
${chalk.gray('–')} Invite new members (interactively)
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} teams invite`)}
|
||||
|
||||
|
||||
${chalk.gray('–')} Paginate results, where ${chalk.dim(
|
||||
'`1584722256178`'
|
||||
)} is the time in milliseconds since the UNIX epoch.
|
||||
@@ -97,10 +97,11 @@ const main = async ctx => {
|
||||
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
|
||||
return run({ token, config });
|
||||
return run({ token, config, output });
|
||||
};
|
||||
|
||||
export default async ctx => {
|
||||
@@ -112,7 +113,7 @@ export default async ctx => {
|
||||
}
|
||||
};
|
||||
|
||||
async function run({ token, config }) {
|
||||
async function run({ token, config, output }) {
|
||||
const { currentTeam } = config;
|
||||
const teams = new NowTeams({ apiUrl, token, debug, currentTeam });
|
||||
const args = argv._;
|
||||
@@ -126,6 +127,7 @@ async function run({ token, config }) {
|
||||
config,
|
||||
apiUrl,
|
||||
token,
|
||||
output,
|
||||
argv,
|
||||
});
|
||||
break;
|
||||
@@ -138,6 +140,7 @@ async function run({ token, config }) {
|
||||
apiUrl,
|
||||
token,
|
||||
debug,
|
||||
output,
|
||||
});
|
||||
break;
|
||||
}
|
||||
@@ -154,6 +157,7 @@ async function run({ token, config }) {
|
||||
config,
|
||||
apiUrl,
|
||||
token,
|
||||
output,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import success from '../../util/output/success';
|
||||
import getUser from '../../util/get-user.ts';
|
||||
import Client from '../../util/client.ts';
|
||||
import { getCommandName } from '../../util/pkg-name.ts';
|
||||
import createOutput from '../../util/output';
|
||||
|
||||
const validateEmail = data => regexEmail.test(data.trim()) || data.length === 0;
|
||||
|
||||
@@ -65,8 +64,8 @@ export default async function ({
|
||||
noopMsg = 'No changes made',
|
||||
apiUrl,
|
||||
token,
|
||||
output,
|
||||
} = {}) {
|
||||
const output = createOutput();
|
||||
const { currentTeam: currentTeamId } = config;
|
||||
|
||||
const stopSpinner = wait('Fetching teams');
|
||||
@@ -77,7 +76,7 @@ export default async function ({
|
||||
stopSpinner();
|
||||
|
||||
const stopUserSpinner = wait('Fetching user information');
|
||||
const client = new Client({ apiUrl, token });
|
||||
const client = new Client({ apiUrl, token, output });
|
||||
let user;
|
||||
try {
|
||||
user = await getUser(client);
|
||||
|
||||
@@ -8,7 +8,6 @@ import info from '../../util/output/info';
|
||||
import error from '../../util/output/error';
|
||||
import chars from '../../util/output/chars';
|
||||
import table from '../../util/output/table';
|
||||
import createOutput from '../../util/output';
|
||||
import getUser from '../../util/get-user.ts';
|
||||
import Client from '../../util/client.ts';
|
||||
import getPrefixedFlags from '../../util/get-prefixed-flags';
|
||||
@@ -16,9 +15,8 @@ import { getPkgName } from '../../util/pkg-name.ts';
|
||||
import getCommandFlags from '../../util/get-command-flags';
|
||||
import cmd from '../../util/output/cmd.ts';
|
||||
|
||||
export default async function({ teams, config, apiUrl, token, argv }) {
|
||||
export default async function ({ teams, config, apiUrl, token, output, argv }) {
|
||||
const { next } = argv;
|
||||
const output = createOutput({ debug: argv['--debug'] });
|
||||
|
||||
if (typeof next !== 'undefined' && !Number.isInteger(next)) {
|
||||
output.error('Please provide a number for flag --next');
|
||||
@@ -36,7 +34,7 @@ export default async function({ teams, config, apiUrl, token, argv }) {
|
||||
stopSpinner();
|
||||
|
||||
const stopUserSpinner = wait('Fetching user information');
|
||||
const client = new Client({ apiUrl, token, currentTeam });
|
||||
const client = new Client({ apiUrl, token, currentTeam, output });
|
||||
let user;
|
||||
try {
|
||||
user = await getUser(client);
|
||||
|
||||
@@ -24,22 +24,21 @@ const updateCurrentTeam = (config, newTeam) => {
|
||||
writeToConfigFile(config);
|
||||
};
|
||||
|
||||
export default async function({ apiUrl, token, debug, args, config }) {
|
||||
let stopSpinner = wait('Fetching teams');
|
||||
export default async function ({ apiUrl, token, debug, args, config, output }) {
|
||||
let stopSpinner;
|
||||
output.spinner('Fetching teams');
|
||||
|
||||
// We're loading the teams here without `currentTeam`, so that
|
||||
// people can use `vercel switch` in the case that their
|
||||
// current team was deleted.
|
||||
const teams = new NowTeams({ apiUrl, token, debug });
|
||||
const teams = new NowTeams({ apiUrl, token, debug, output });
|
||||
const list = (await teams.ls()).teams;
|
||||
|
||||
let { currentTeam } = config;
|
||||
const accountIsCurrent = !currentTeam;
|
||||
|
||||
stopSpinner();
|
||||
|
||||
const stopUserSpinner = wait('Fetching user information');
|
||||
const client = new Client({ apiUrl, token });
|
||||
output.spinner('Fetching user information');
|
||||
const client = new Client({ apiUrl, token, output });
|
||||
let user;
|
||||
try {
|
||||
user = await getUser(client);
|
||||
@@ -52,8 +51,6 @@ export default async function({ apiUrl, token, debug, args, config }) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
stopUserSpinner();
|
||||
|
||||
if (accountIsCurrent) {
|
||||
currentTeam = {
|
||||
slug: user.username || user.email,
|
||||
|
||||
@@ -5,7 +5,6 @@ import logo from '../util/output/logo';
|
||||
import handleError from '../util/handle-error';
|
||||
import getArgs from '../util/get-args';
|
||||
import { NowContext } from '../types';
|
||||
import createOutput from '../util/output';
|
||||
import getUpdateCommand from '../util/get-update-command';
|
||||
import { getPkgName, getTitleName } from '../util/pkg-name';
|
||||
|
||||
@@ -35,6 +34,7 @@ const help = () => {
|
||||
|
||||
export default async function main(ctx: NowContext): Promise<number> {
|
||||
let argv;
|
||||
const { output } = ctx;
|
||||
|
||||
try {
|
||||
argv = getArgs(ctx.argv.slice(2), {
|
||||
@@ -55,8 +55,6 @@ export default async function main(ctx: NowContext): Promise<number> {
|
||||
return 2;
|
||||
}
|
||||
|
||||
const debugEnabled = argv['--debug'];
|
||||
const output = createOutput({ debug: debugEnabled });
|
||||
output.log(
|
||||
`Please run ${cmd(
|
||||
await getUpdateCommand()
|
||||
|
||||
@@ -4,7 +4,6 @@ import logo from '../util/output/logo';
|
||||
import { handleError } from '../util/error';
|
||||
import Client from '../util/client.ts';
|
||||
import getScope from '../util/get-scope.ts';
|
||||
import createOutput from '../util/output';
|
||||
import { getPkgName } from '../util/pkg-name.ts';
|
||||
|
||||
const help = () => {
|
||||
@@ -55,10 +54,10 @@ const main = async ctx => {
|
||||
const debug = argv['--debug'];
|
||||
const {
|
||||
authConfig: { token },
|
||||
output,
|
||||
apiUrl,
|
||||
} = ctx;
|
||||
const output = createOutput({ debug });
|
||||
const client = new Client({ apiUrl, token, debug });
|
||||
const client = new Client({ apiUrl, token, debug, output });
|
||||
let contextName = null;
|
||||
|
||||
try {
|
||||
|
||||
@@ -291,7 +291,7 @@ const main = async argv_ => {
|
||||
|
||||
let authConfig = null;
|
||||
|
||||
const subcommandsWithoutToken = ['login', 'help', 'init', 'dev', 'update'];
|
||||
const subcommandsWithoutToken = ['login', 'help', 'init', 'update'];
|
||||
|
||||
if (authConfigExists) {
|
||||
try {
|
||||
@@ -346,6 +346,7 @@ const main = async argv_ => {
|
||||
|
||||
// the context object to supply to the providers or the commands
|
||||
const ctx = {
|
||||
output,
|
||||
config,
|
||||
authConfig,
|
||||
localConfig,
|
||||
@@ -536,7 +537,7 @@ const main = async argv_ => {
|
||||
!(targetCommand === 'teams' && argv._[3] !== 'invite')
|
||||
) {
|
||||
let user = null;
|
||||
const client = new Client({ apiUrl, token });
|
||||
const client = new Client({ apiUrl, token, output });
|
||||
|
||||
try {
|
||||
user = await getUser(client);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { NowConfig } from './util/dev/types';
|
||||
import { Output } from './util/output';
|
||||
|
||||
export type ThenArg<T> = T extends Promise<infer U> ? U : T;
|
||||
|
||||
@@ -8,6 +9,7 @@ export interface NowContext {
|
||||
authConfig: {
|
||||
token: string;
|
||||
};
|
||||
output: Output;
|
||||
config: {
|
||||
currentTeam: string;
|
||||
updateChannel: string;
|
||||
@@ -230,6 +232,8 @@ export interface ProjectSettings {
|
||||
buildCommand?: string | null;
|
||||
outputDirectory?: string | null;
|
||||
rootDirectory?: string | null;
|
||||
autoExposeSystemEnvs?: boolean;
|
||||
directoryListing?: boolean;
|
||||
}
|
||||
|
||||
export interface Project extends ProjectSettings {
|
||||
@@ -243,6 +247,7 @@ export interface Project extends ProjectSettings {
|
||||
framework?: string | null;
|
||||
rootDirectory?: string | null;
|
||||
latestDeployments?: Partial<Deployment>[];
|
||||
autoExposeSystemEnvs?: boolean;
|
||||
}
|
||||
|
||||
export interface Org {
|
||||
|
||||
@@ -33,6 +33,7 @@ export default class Client extends EventEmitter {
|
||||
forceNew = false,
|
||||
withCache = false,
|
||||
debug = false,
|
||||
output = createOutput({ debug }),
|
||||
}: {
|
||||
apiUrl: string;
|
||||
token: string;
|
||||
@@ -40,13 +41,14 @@ export default class Client extends EventEmitter {
|
||||
forceNew?: boolean;
|
||||
withCache?: boolean;
|
||||
debug?: boolean;
|
||||
output?: Output;
|
||||
}) {
|
||||
super();
|
||||
this._token = token;
|
||||
this._debug = debug;
|
||||
this._forceNew = forceNew;
|
||||
this._withCache = withCache;
|
||||
this._output = createOutput({ debug });
|
||||
this._output = output;
|
||||
this._apiUrl = apiUrl;
|
||||
this._onRetry = this._onRetry.bind(this);
|
||||
this.currentTeam = currentTeam;
|
||||
|
||||
@@ -100,11 +100,7 @@ export default async function processDeployment({
|
||||
skipAutoDetectionConfirmation,
|
||||
};
|
||||
|
||||
let queuedSpinner = null;
|
||||
let buildSpinner = null;
|
||||
let deploySpinner = null;
|
||||
|
||||
const deployingSpinner = output.spinner(
|
||||
output.spinner(
|
||||
isSettingUpProject
|
||||
? 'Setting up project'
|
||||
: `Deploying ${chalk.bold(`${org.slug}/${projectName}`)}`,
|
||||
@@ -138,16 +134,7 @@ export default async function processDeployment({
|
||||
.map((sha: string) => event.payload.total.get(sha).data.length)
|
||||
.reduce((a: number, b: number) => a + b, 0);
|
||||
|
||||
if (queuedSpinner) {
|
||||
queuedSpinner();
|
||||
}
|
||||
if (buildSpinner) {
|
||||
buildSpinner();
|
||||
}
|
||||
if (deploySpinner) {
|
||||
deploySpinner();
|
||||
}
|
||||
deployingSpinner();
|
||||
output.stopSpinner();
|
||||
bar = new Progress(`${chalk.gray('>')} Upload [:bar] :percent :etas`, {
|
||||
width: 20,
|
||||
complete: '=',
|
||||
@@ -170,8 +157,6 @@ export default async function processDeployment({
|
||||
}
|
||||
|
||||
if (event.type === 'created') {
|
||||
deployingSpinner();
|
||||
|
||||
if (bar && !bar.complete) {
|
||||
bar.tick(bar.total + 1);
|
||||
}
|
||||
@@ -191,63 +176,36 @@ export default async function processDeployment({
|
||||
|
||||
now.url = event.payload.url;
|
||||
|
||||
output.stopSpinner();
|
||||
|
||||
printInspectUrl(output, event.payload.url, deployStamp, org.slug);
|
||||
|
||||
if (quiet) {
|
||||
process.stdout.write(`https://${event.payload.url}`);
|
||||
}
|
||||
|
||||
if (queuedSpinner === null) {
|
||||
queuedSpinner =
|
||||
event.payload.readyState === 'QUEUED'
|
||||
? output.spinner('Queued', 0)
|
||||
: output.spinner('Building', 0);
|
||||
}
|
||||
output.spinner(
|
||||
event.payload.readyState === 'QUEUED' ? 'Queued' : 'Building',
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
if (event.type === 'building') {
|
||||
if (queuedSpinner) {
|
||||
queuedSpinner();
|
||||
}
|
||||
|
||||
if (buildSpinner === null) {
|
||||
buildSpinner = output.spinner('Building', 0);
|
||||
}
|
||||
output.spinner('Building', 0);
|
||||
}
|
||||
|
||||
if (event.type === 'canceled') {
|
||||
if (queuedSpinner) {
|
||||
queuedSpinner();
|
||||
}
|
||||
if (buildSpinner) {
|
||||
buildSpinner();
|
||||
}
|
||||
output.stopSpinner();
|
||||
return event.payload;
|
||||
}
|
||||
|
||||
if (event.type === 'ready') {
|
||||
if (queuedSpinner) {
|
||||
queuedSpinner();
|
||||
}
|
||||
if (buildSpinner) {
|
||||
buildSpinner();
|
||||
}
|
||||
|
||||
deploySpinner = output.spinner('Completing', 0);
|
||||
output.spinner('Completing', 0);
|
||||
}
|
||||
|
||||
// Handle error events
|
||||
if (event.type === 'error') {
|
||||
if (queuedSpinner) {
|
||||
queuedSpinner();
|
||||
}
|
||||
if (buildSpinner) {
|
||||
buildSpinner();
|
||||
}
|
||||
if (deploySpinner) {
|
||||
deploySpinner();
|
||||
}
|
||||
deployingSpinner();
|
||||
output.stopSpinner();
|
||||
|
||||
const error = await now.handleDeploymentError(event.payload, {
|
||||
hashes,
|
||||
@@ -263,32 +221,12 @@ export default async function processDeployment({
|
||||
|
||||
// Handle alias-assigned event
|
||||
if (event.type === 'alias-assigned') {
|
||||
if (queuedSpinner) {
|
||||
queuedSpinner();
|
||||
}
|
||||
if (buildSpinner) {
|
||||
buildSpinner();
|
||||
}
|
||||
if (deploySpinner) {
|
||||
deploySpinner();
|
||||
}
|
||||
deployingSpinner();
|
||||
|
||||
event.payload.indications = indications;
|
||||
return event.payload;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (queuedSpinner) {
|
||||
queuedSpinner();
|
||||
}
|
||||
if (buildSpinner) {
|
||||
buildSpinner();
|
||||
}
|
||||
if (deploySpinner) {
|
||||
deploySpinner();
|
||||
}
|
||||
deployingSpinner();
|
||||
output.stopSpinner();
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import chalk from 'chalk';
|
||||
import execa from 'execa';
|
||||
import semver from 'semver';
|
||||
import npa from 'npm-package-arg';
|
||||
@@ -8,9 +9,10 @@ import { mkdirp, readJSON, writeJSON } from 'fs-extra';
|
||||
import { NowBuildError, PackageJson } from '@vercel/build-utils';
|
||||
import cliPkg from '../pkg';
|
||||
|
||||
import { NoBuilderCacheError } from '../errors-ts';
|
||||
import cmd from '../output/cmd';
|
||||
import { Output } from '../output';
|
||||
import { getDistTag } from '../get-dist-tag';
|
||||
import { NoBuilderCacheError } from '../errors-ts';
|
||||
|
||||
import * as staticBuilder from './static-builder';
|
||||
import { BuilderWithPackage } from './types';
|
||||
@@ -261,7 +263,9 @@ async function npmInstall(
|
||||
throw new NowBuildError({
|
||||
message:
|
||||
(result as any).code === 'ENOENT'
|
||||
? '`npm` is not installed'
|
||||
? `Command not found: ${chalk.cyan(
|
||||
'npm'
|
||||
)}\nPlease ensure that ${cmd('npm')} is properly installed`
|
||||
: 'Failed to install `vercel dev` dependencies',
|
||||
code: 'NPM_INSTALL_ERROR',
|
||||
link: 'https://vercel.link/npm-install-failed-dev',
|
||||
|
||||
@@ -149,8 +149,8 @@ export async function executeBuild(
|
||||
filesRemoved,
|
||||
// This env distiniction is only necessary to maintain
|
||||
// backwards compatibility with the `@vercel/next` builder.
|
||||
env: envConfigs.runEnv,
|
||||
buildEnv: envConfigs.buildEnv,
|
||||
env: { ...envConfigs.runEnv },
|
||||
buildEnv: { ...envConfigs.buildEnv },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -280,7 +280,6 @@ export async function executeBuild(
|
||||
path = extensionless;
|
||||
}
|
||||
|
||||
delete output[path];
|
||||
output[path] = value;
|
||||
});
|
||||
|
||||
@@ -402,7 +401,7 @@ export async function getBuildMatches(
|
||||
const builds = nowConfig.builds || [{ src: '**', use: '@vercel/static' }];
|
||||
|
||||
for (const buildConfig of builds) {
|
||||
let { src, use } = buildConfig;
|
||||
let { src = '**', use, config = {} } = buildConfig;
|
||||
|
||||
if (!use) {
|
||||
continue;
|
||||
@@ -437,6 +436,15 @@ export async function getBuildMatches(
|
||||
|
||||
for (const file of files) {
|
||||
src = relative(cwd, file);
|
||||
|
||||
// Remove the output directory prefix
|
||||
if (config.zeroConfig && config.outputDirectory) {
|
||||
const outputMatch = config.outputDirectory + '/';
|
||||
if (src.startsWith(outputMatch)) {
|
||||
src = src.slice(outputMatch.length);
|
||||
}
|
||||
}
|
||||
|
||||
const builderWithPkg = await getBuilder(use, output);
|
||||
matches.push({
|
||||
...buildConfig,
|
||||
|
||||
41
packages/now-cli/src/util/dev/expose-system-envs.ts
Normal file
41
packages/now-cli/src/util/dev/expose-system-envs.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { ProjectEnvType, ProjectEnvVariable } from '../../types';
|
||||
import { Env } from '@vercel/build-utils';
|
||||
|
||||
function getSystemEnvValue(
|
||||
systemEnvRef: string,
|
||||
{ vercelUrl }: { vercelUrl?: string }
|
||||
) {
|
||||
if (systemEnvRef === 'VERCEL_URL') {
|
||||
return vercelUrl || '';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
export default function exposeSystemEnvs(
|
||||
projectEnvs: ProjectEnvVariable[],
|
||||
systemEnvValues: string[],
|
||||
autoExposeSystemEnvs: boolean | undefined,
|
||||
vercelUrl?: string
|
||||
) {
|
||||
const envs: Env = {};
|
||||
|
||||
if (autoExposeSystemEnvs) {
|
||||
envs['VERCEL'] = '1';
|
||||
envs['VERCEL_ENV'] = 'development';
|
||||
|
||||
for (const key of systemEnvValues) {
|
||||
envs[key] = getSystemEnvValue(key, { vercelUrl });
|
||||
}
|
||||
}
|
||||
|
||||
for (let env of projectEnvs) {
|
||||
if (env.type === ProjectEnvType.System) {
|
||||
envs[env.key] = getSystemEnvValue(env.value, { vercelUrl });
|
||||
} else {
|
||||
envs[env.key] = env.value;
|
||||
}
|
||||
}
|
||||
|
||||
return envs;
|
||||
}
|
||||
@@ -43,6 +43,7 @@ import {
|
||||
} from '@vercel/build-utils';
|
||||
import _frameworks, { Framework } from '@vercel/frameworks';
|
||||
|
||||
import cmd from '../output/cmd';
|
||||
import link from '../output/link';
|
||||
import { Output } from '../output';
|
||||
import { relative } from '../path-helpers';
|
||||
@@ -85,7 +86,8 @@ import {
|
||||
HttpHeadersConfig,
|
||||
EnvConfigs,
|
||||
} from './types';
|
||||
import { ProjectSettings } from '../../types';
|
||||
import { ProjectEnvVariable, ProjectSettings } from '../../types';
|
||||
import exposeSystemEnvs from './expose-system-envs';
|
||||
|
||||
const frameworkList = _frameworks as Framework[];
|
||||
const frontendRuntimeSet = new Set(
|
||||
@@ -149,14 +151,16 @@ export default class DevServer {
|
||||
private updateBuildersTimeout: NodeJS.Timeout | undefined;
|
||||
private startPromise: Promise<void> | null;
|
||||
|
||||
private environmentVars: Env | undefined;
|
||||
private systemEnvValues: string[];
|
||||
private projectEnvs: ProjectEnvVariable[];
|
||||
|
||||
constructor(cwd: string, options: DevServerOptions) {
|
||||
this.cwd = cwd;
|
||||
this.debug = options.debug;
|
||||
this.output = options.output;
|
||||
this.envConfigs = { buildEnv: {}, runEnv: {}, allEnv: {} };
|
||||
this.environmentVars = options.environmentVars;
|
||||
this.systemEnvValues = options.systemEnvValues || [];
|
||||
this.projectEnvs = options.projectEnvs || [];
|
||||
this.files = {};
|
||||
this.address = '';
|
||||
this.devCommand = options.devCommand;
|
||||
@@ -491,7 +495,7 @@ export default class DevServer {
|
||||
const dotenv = await fs.readFile(filePath, 'utf8');
|
||||
this.output.debug(`Using local env: ${filePath}`);
|
||||
env = parseDotenv(dotenv);
|
||||
env = this.populateVercelEnvVars(env);
|
||||
env = this.injectSystemValuesInDotenv(env);
|
||||
} catch (err) {
|
||||
if (err.code !== 'ENOENT') {
|
||||
throw err;
|
||||
@@ -642,10 +646,30 @@ export default class DevServer {
|
||||
|
||||
let allEnv = { ...buildEnv, ...runEnv };
|
||||
|
||||
// If no .env/.build.env is present, fetch and use cloud environment variables
|
||||
// If no .env/.build.env is present, use cloud environment variables
|
||||
if (Object.keys(allEnv).length === 0) {
|
||||
const cloudEnv = this.populateVercelEnvVars(this.environmentVars);
|
||||
allEnv = runEnv = buildEnv = cloudEnv;
|
||||
const cloudEnv = exposeSystemEnvs(
|
||||
this.projectEnvs || [],
|
||||
this.systemEnvValues || [],
|
||||
this.projectSettings?.autoExposeSystemEnvs,
|
||||
new URL(this.address).host
|
||||
);
|
||||
|
||||
allEnv = { ...cloudEnv };
|
||||
runEnv = { ...cloudEnv };
|
||||
buildEnv = { ...cloudEnv };
|
||||
}
|
||||
|
||||
// legacy NOW_REGION env variable
|
||||
runEnv['NOW_REGION'] = 'dev1';
|
||||
buildEnv['NOW_REGION'] = 'dev1';
|
||||
allEnv['NOW_REGION'] = 'dev1';
|
||||
|
||||
// mirror how VERCEL_REGION is injected in prod/preview
|
||||
// only inject in `runEnvs`, because `allEnvs` is exposed to dev command
|
||||
// and should not contain VERCEL_REGION
|
||||
if (this.projectSettings?.autoExposeSystemEnvs) {
|
||||
runEnv['VERCEL_REGION'] = 'dev1';
|
||||
}
|
||||
|
||||
this.envConfigs = { buildEnv, runEnv, allEnv };
|
||||
@@ -753,23 +777,15 @@ export default class DevServer {
|
||||
return merged;
|
||||
}
|
||||
|
||||
populateVercelEnvVars(env: Env | undefined): Env {
|
||||
if (!env) {
|
||||
return {};
|
||||
}
|
||||
|
||||
injectSystemValuesInDotenv(env: Env): Env {
|
||||
for (const name of Object.keys(env)) {
|
||||
if (name === 'VERCEL_URL') {
|
||||
const host = new URL(this.address).host;
|
||||
env['VERCEL_URL'] = host;
|
||||
env['VERCEL_URL'] = new URL(this.address).host;
|
||||
} else if (name === 'VERCEL_REGION') {
|
||||
env['VERCEL_REGION'] = 'dev1';
|
||||
}
|
||||
}
|
||||
|
||||
// Always set NOW_REGION to match production
|
||||
env['NOW_REGION'] = 'dev1';
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
@@ -871,7 +887,7 @@ export default class DevServer {
|
||||
})
|
||||
.catch(err => {
|
||||
this.updateBuildersPromise = null;
|
||||
this.output.error(`Failed to update builders: ${err.message}`);
|
||||
this.output.prettyError(err);
|
||||
this.output.debug(err.stack);
|
||||
});
|
||||
}, ms('30s'));
|
||||
@@ -1658,15 +1674,24 @@ export default class DevServer {
|
||||
isDev: true,
|
||||
requestPath,
|
||||
devCacheDir,
|
||||
env: envConfigs.runEnv,
|
||||
buildEnv: envConfigs.buildEnv,
|
||||
env: { ...envConfigs.runEnv },
|
||||
buildEnv: { ...envConfigs.buildEnv },
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
// `startDevServer()` threw an error. Most likely this means the dev
|
||||
// server process exited before sending the port information message
|
||||
// (missing dependency at runtime, for example).
|
||||
debug(`Error starting "${builderPkg.name}" dev server: ${err}`);
|
||||
if (err.code === 'ENOENT') {
|
||||
err.message = `Command not found: ${chalk.cyan(
|
||||
err.path,
|
||||
...err.spawnargs
|
||||
)}\nPlease ensure that ${cmd(err.path)} is properly installed`;
|
||||
err.link = 'https://vercel.link/command-not-found';
|
||||
}
|
||||
|
||||
this.output.prettyError(err);
|
||||
|
||||
await this.sendError(
|
||||
req,
|
||||
res,
|
||||
@@ -1879,6 +1904,12 @@ export default class DevServer {
|
||||
requestPath: string,
|
||||
nowRequestId: string
|
||||
): boolean {
|
||||
// If the "directory listing" feature is disabled in the
|
||||
// Project's settings, then don't render the directory listing
|
||||
if (this.projectSettings?.directoryListing === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let prefix = requestPath;
|
||||
if (prefix.length > 0 && !prefix.endsWith('/')) {
|
||||
prefix += '/';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { basename, extname, join } from 'path';
|
||||
import {
|
||||
FileFsRef,
|
||||
BuildOptions,
|
||||
shouldServe as defaultShouldServe,
|
||||
ShouldServeOptions,
|
||||
} from '@vercel/build-utils';
|
||||
import { BuildResult } from './types';
|
||||
@@ -11,50 +11,32 @@ export const version = 2;
|
||||
export function build({
|
||||
files,
|
||||
entrypoint,
|
||||
config,
|
||||
config: { zeroConfig, outputDirectory },
|
||||
}: BuildOptions): BuildResult {
|
||||
let path = entrypoint;
|
||||
const outputDir = config.zeroConfig ? config.outputDirectory : '';
|
||||
const outputMatch = outputDir + '/';
|
||||
if (outputDir && path.startsWith(outputMatch)) {
|
||||
// static output files are moved to the root directory
|
||||
path = path.slice(outputMatch.length);
|
||||
}
|
||||
const output = {
|
||||
[path]: files[entrypoint] as FileFsRef,
|
||||
const path =
|
||||
zeroConfig && outputDirectory
|
||||
? `${outputDirectory}/${entrypoint}`
|
||||
: entrypoint;
|
||||
return {
|
||||
output: {
|
||||
[entrypoint]: files[path] as FileFsRef,
|
||||
},
|
||||
routes: [],
|
||||
watch: [path],
|
||||
};
|
||||
const watch = [path];
|
||||
|
||||
return { output, routes: [], watch };
|
||||
}
|
||||
|
||||
export function shouldServe({
|
||||
entrypoint,
|
||||
files,
|
||||
requestPath,
|
||||
config = {},
|
||||
}: ShouldServeOptions) {
|
||||
let outputPrefix = '';
|
||||
const outputDir = config.zeroConfig ? config.outputDirectory : '';
|
||||
const outputMatch = outputDir + '/';
|
||||
if (outputDir && entrypoint.startsWith(outputMatch)) {
|
||||
// static output files are moved to the root directory
|
||||
entrypoint = entrypoint.slice(outputMatch.length);
|
||||
outputPrefix = outputMatch;
|
||||
export function shouldServe(_opts: ShouldServeOptions) {
|
||||
const opts = { ..._opts };
|
||||
let {
|
||||
config: { zeroConfig, outputDirectory },
|
||||
} = opts;
|
||||
|
||||
// Add the output directory prefix
|
||||
if (zeroConfig && outputDirectory) {
|
||||
opts.entrypoint = `${outputDirectory}/${opts.entrypoint}`;
|
||||
opts.requestPath = `${outputDirectory}/${opts.requestPath}`;
|
||||
}
|
||||
const isMatch = (f: string) => entrypoint === f && outputPrefix + f in files;
|
||||
|
||||
if (isIndex(entrypoint)) {
|
||||
const indexPath = join(requestPath, basename(entrypoint));
|
||||
if (isMatch(indexPath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return isMatch(requestPath);
|
||||
}
|
||||
|
||||
function isIndex(path: string): boolean {
|
||||
const ext = extname(path);
|
||||
const name = basename(path, ext);
|
||||
return name === 'index';
|
||||
return defaultShouldServe(opts);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
import { NowConfig } from '@vercel/client';
|
||||
import { HandleValue, Route } from '@vercel/routing-utils';
|
||||
import { Output } from '../output';
|
||||
import { ProjectSettings } from '../../types';
|
||||
import { ProjectEnvVariable, ProjectSettings } from '../../types';
|
||||
|
||||
export { NowConfig };
|
||||
|
||||
@@ -27,7 +27,8 @@ export interface DevServerOptions {
|
||||
devCommand?: string;
|
||||
frameworkSlug?: string;
|
||||
projectSettings?: ProjectSettings;
|
||||
environmentVars?: Env;
|
||||
systemEnvValues?: string[];
|
||||
projectEnvs?: ProjectEnvVariable[];
|
||||
}
|
||||
|
||||
export interface EnvConfigs {
|
||||
@@ -49,6 +50,7 @@ export interface EnvConfigs {
|
||||
|
||||
export interface BuildMatch extends BuildConfig {
|
||||
entrypoint: string;
|
||||
src: string;
|
||||
builderWithPkg: BuilderWithPackage;
|
||||
buildOutput: BuilderOutputs;
|
||||
buildResults: Map<string | null, BuildResult>;
|
||||
|
||||
@@ -12,11 +12,12 @@ type Response = {
|
||||
export default async function purchaseDomain(
|
||||
client: Client,
|
||||
name: string,
|
||||
expectedPrice: number
|
||||
expectedPrice: number,
|
||||
renew: boolean = true
|
||||
) {
|
||||
try {
|
||||
return await client.fetch<Response>(`/v3/domains/buy`, {
|
||||
body: { name, expectedPrice },
|
||||
body: { name, expectedPrice, renew },
|
||||
method: 'POST',
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import { Output } from '../output';
|
||||
import Client from '../client';
|
||||
import { Secret } from '../../types';
|
||||
|
||||
export default async function getDecryptedSecret(
|
||||
output: Output,
|
||||
client: Client,
|
||||
secretId: string
|
||||
): Promise<string> {
|
||||
if (!secretId) {
|
||||
return '';
|
||||
}
|
||||
output.debug(`Fetching decrypted secret ${secretId}`);
|
||||
const url = `/v2/now/secrets/${secretId}?decrypt=true`;
|
||||
const secret = await client.fetch<Secret>(url);
|
||||
return secret.value;
|
||||
}
|
||||
12
packages/now-cli/src/util/env/get-system-env-values.ts
vendored
Normal file
12
packages/now-cli/src/util/env/get-system-env-values.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Output } from '../output';
|
||||
import Client from '../client';
|
||||
|
||||
export default async function getSystemEnvValues(
|
||||
output: Output,
|
||||
client: Client,
|
||||
projectId: string
|
||||
) {
|
||||
output.debug(`Fetching System Environment Values of project ${projectId}`);
|
||||
const url = `/v6/projects/${projectId}/system-env-values`;
|
||||
return client.fetch<{ systemEnvValues: string[] }>(url);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Output } from '../output';
|
||||
import Client from '../client';
|
||||
import { ProjectEnvTarget, Secret, ProjectEnvVariableV5 } from '../../types';
|
||||
import { ProjectEnvTarget, ProjectEnvVariableV5 } from '../../types';
|
||||
|
||||
export default async function removeEnvRecord(
|
||||
output: Output,
|
||||
@@ -18,32 +18,7 @@ export default async function removeEnvRecord(
|
||||
envName
|
||||
)}${qs}`;
|
||||
|
||||
const env = await client.fetch<ProjectEnvVariableV5>(urlProject, {
|
||||
await client.fetch<ProjectEnvVariableV5>(urlProject, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
|
||||
if (env && env.value) {
|
||||
const idOrName = env.value.startsWith('@') ? env.value.slice(1) : env.value;
|
||||
const urlSecret = `/v2/now/secrets/${idOrName}`;
|
||||
let secret: Secret | undefined;
|
||||
|
||||
try {
|
||||
secret = await client.fetch<Secret>(urlSecret);
|
||||
} catch (error) {
|
||||
if (error && error.status === 404) {
|
||||
// User likely deleted the secret before the env var, so we can still report success
|
||||
output.debug(
|
||||
`Skipped ${env.key} because secret ${idOrName} was already deleted`
|
||||
);
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Since integrations add global secrets, we must only delete if the secret was
|
||||
// specifically added to this project
|
||||
if (secret && secret.projectId === projectId) {
|
||||
await client.fetch<Secret>(urlSecret, { method: 'DELETE' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
32
packages/now-cli/src/util/env/system-env.ts
vendored
32
packages/now-cli/src/util/env/system-env.ts
vendored
@@ -1,32 +0,0 @@
|
||||
export const SYSTEM_ENV_VALUES = [
|
||||
'VERCEL_URL',
|
||||
'VERCEL_GITHUB_COMMIT_ORG',
|
||||
'VERCEL_GITHUB_COMMIT_REF',
|
||||
'VERCEL_GITHUB_ORG',
|
||||
'VERCEL_GITHUB_DEPLOYMENT',
|
||||
'VERCEL_GITHUB_COMMIT_REPO',
|
||||
'VERCEL_GITHUB_REPO',
|
||||
'VERCEL_GITHUB_COMMIT_AUTHOR_LOGIN',
|
||||
'VERCEL_GITHUB_COMMIT_AUTHOR_NAME',
|
||||
'VERCEL_GITHUB_COMMIT_SHA',
|
||||
'VERCEL_GITLAB_DEPLOYMENT',
|
||||
'VERCEL_GITLAB_PROJECT_NAMESPACE',
|
||||
'VERCEL_GITLAB_PROJECT_NAME',
|
||||
'VERCEL_GITLAB_PROJECT_ID',
|
||||
'VERCEL_GITLAB_PROJECT_PATH',
|
||||
'VERCEL_GITLAB_COMMIT_REF',
|
||||
'VERCEL_GITLAB_COMMIT_SHA',
|
||||
'VERCEL_GITLAB_COMMIT_MESSAGE',
|
||||
'VERCEL_GITLAB_COMMIT_AUTHOR_LOGIN',
|
||||
'VERCEL_GITLAB_COMMIT_AUTHOR_NAME',
|
||||
'VERCEL_BITBUCKET_DEPLOYMENT',
|
||||
'VERCEL_BITBUCKET_REPO_OWNER',
|
||||
'VERCEL_BITBUCKET_REPO_SLUG',
|
||||
'VERCEL_BITBUCKET_REPO_NAME',
|
||||
'VERCEL_BITBUCKET_COMMIT_REF',
|
||||
'VERCEL_BITBUCKET_COMMIT_SHA',
|
||||
'VERCEL_BITBUCKET_COMMIT_MESSAGE',
|
||||
'VERCEL_BITBUCKET_COMMIT_AUTHOR_NAME',
|
||||
'VERCEL_BITBUCKET_COMMIT_AUTHOR_URL',
|
||||
'VERCEL_BITBUCKET_COMMIT_AUTHOR_AVATAR',
|
||||
];
|
||||
@@ -7,16 +7,21 @@ import { eraseLines } from 'ansi-escapes';
|
||||
import jsonlines from 'jsonlines';
|
||||
import retry from 'async-retry';
|
||||
|
||||
// Utilities
|
||||
import createOutput from './output';
|
||||
|
||||
async function printEvents(
|
||||
now,
|
||||
deploymentIdOrURL,
|
||||
currentTeam = null,
|
||||
{ mode, onOpen = () => {}, onEvent, quiet, debugEnabled, findOpts } = {}
|
||||
{
|
||||
mode,
|
||||
onOpen = () => {},
|
||||
onEvent,
|
||||
quiet,
|
||||
debugEnabled,
|
||||
findOpts,
|
||||
output,
|
||||
} = {}
|
||||
) {
|
||||
const { log, debug } = createOutput({ debug: debugEnabled });
|
||||
const { log, debug } = output;
|
||||
|
||||
let onOpenCalled = false;
|
||||
function callOnOpenOnce() {
|
||||
|
||||
@@ -1,52 +1,65 @@
|
||||
import getEnvVariables from './env/get-env-records';
|
||||
import getDecryptedSecret from './env/get-decrypted-secret';
|
||||
import Client from './client';
|
||||
import { Output } from './output/create-output';
|
||||
import { ProjectEnvTarget, Project, ProjectEnvType } from '../types';
|
||||
|
||||
import { Env } from '@vercel/build-utils';
|
||||
import {
|
||||
ProjectEnvTarget,
|
||||
ProjectEnvType,
|
||||
ProjectEnvVariable,
|
||||
Secret,
|
||||
} from '../types';
|
||||
import getEnvRecords from './env/get-env-records';
|
||||
|
||||
export default async function getDecryptedEnvRecords(
|
||||
output: Output,
|
||||
client: Client,
|
||||
project: Project,
|
||||
target: ProjectEnvTarget
|
||||
): Promise<Env> {
|
||||
const { envs } = await getEnvVariables(output, client, project.id, target);
|
||||
const decryptedValues = await Promise.all(
|
||||
envs.map(async env => {
|
||||
if (env.type === ProjectEnvType.System) {
|
||||
return { value: '', found: true };
|
||||
} else if (env.type === ProjectEnvType.Plaintext) {
|
||||
return { value: env.value, found: true };
|
||||
projectId: string
|
||||
): Promise<{ envs: ProjectEnvVariable[] }> {
|
||||
const { envs } = await getEnvRecords(
|
||||
output,
|
||||
client,
|
||||
projectId,
|
||||
ProjectEnvTarget.Development
|
||||
);
|
||||
|
||||
const envsWithDecryptedSecrets = await Promise.all(
|
||||
envs.map(async ({ type, key, value }) => {
|
||||
// it's not possible to create secret env variables for development
|
||||
// anymore but we keep this because legacy env variables with "decryptable"
|
||||
// secret values still exit in our system
|
||||
if (type === ProjectEnvType.Secret) {
|
||||
try {
|
||||
const secretIdOrName = value;
|
||||
|
||||
if (!secretIdOrName) {
|
||||
return { type, key, value: '', found: true };
|
||||
}
|
||||
|
||||
output.debug(`Fetching decrypted secret ${secretIdOrName}`);
|
||||
const secret = await client.fetch<Secret>(
|
||||
`/v2/now/secrets/${secretIdOrName}?decrypt=true`
|
||||
);
|
||||
|
||||
return { type, key, value: secret.value, found: true };
|
||||
} catch (error) {
|
||||
if (error && error.status === 404) {
|
||||
return { type, key, value: '', found: false };
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const value = await getDecryptedSecret(output, client, env.value);
|
||||
return { value, found: true };
|
||||
} catch (error) {
|
||||
if (error && error.status === 404) {
|
||||
return { value: '', found: false };
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
return { type, key, value, found: true };
|
||||
})
|
||||
);
|
||||
|
||||
const results: Env = {};
|
||||
for (let i = 0; i < decryptedValues.length; i++) {
|
||||
const { key } = envs[i];
|
||||
const { value, found } = decryptedValues[i];
|
||||
|
||||
if (!found) {
|
||||
for (let env of envsWithDecryptedSecrets) {
|
||||
if (!env.found) {
|
||||
output.print('');
|
||||
output.warn(
|
||||
`Unable to download variable ${key} because associated secret was deleted`
|
||||
`Unable to download variable ${env.key} because associated secret was deleted`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
results[key] = value ? value : '';
|
||||
}
|
||||
return results;
|
||||
|
||||
return { envs: envsWithDecryptedSecrets };
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ export default class Now extends EventEmitter {
|
||||
forceNew = false,
|
||||
withCache = false,
|
||||
debug = false,
|
||||
output = createOutput({ debug }),
|
||||
}) {
|
||||
super();
|
||||
|
||||
@@ -30,7 +31,7 @@ export default class Now extends EventEmitter {
|
||||
this._debug = debug;
|
||||
this._forceNew = forceNew;
|
||||
this._withCache = withCache;
|
||||
this._output = createOutput({ debug });
|
||||
this._output = output;
|
||||
this._apiUrl = apiUrl;
|
||||
this._onRetry = this._onRetry.bind(this);
|
||||
this.currentTeam = currentTeam;
|
||||
|
||||
@@ -23,7 +23,7 @@ export default async function promptBool(label: string, options: Options = {}) {
|
||||
trailing = '',
|
||||
} = options;
|
||||
|
||||
return new Promise(resolve => {
|
||||
return new Promise<boolean>(resolve => {
|
||||
const isRaw = Boolean(stdin && stdin.isRaw);
|
||||
|
||||
if (stdin) {
|
||||
|
||||
@@ -3,7 +3,6 @@ import chalk from 'chalk';
|
||||
import { remove } from 'fs-extra';
|
||||
import { NowContext, ProjectLinkResult, ProjectSettings } from '../../types';
|
||||
import { NowConfig } from '../dev/types';
|
||||
import { Output } from '../output';
|
||||
import {
|
||||
getLinkedProject,
|
||||
linkFolderToProject,
|
||||
@@ -30,7 +29,6 @@ import Now from '../index';
|
||||
|
||||
export default async function setupAndLink(
|
||||
ctx: NowContext,
|
||||
output: Output,
|
||||
path: string,
|
||||
forceDelete: boolean,
|
||||
autoConfirm: boolean,
|
||||
@@ -39,15 +37,17 @@ export default async function setupAndLink(
|
||||
): Promise<ProjectLinkResult> {
|
||||
const {
|
||||
authConfig: { token },
|
||||
apiUrl,
|
||||
output,
|
||||
config,
|
||||
} = ctx;
|
||||
const { apiUrl } = ctx;
|
||||
const debug = output.isDebugEnabled();
|
||||
const client = new Client({
|
||||
apiUrl,
|
||||
token,
|
||||
currentTeam: config.currentTeam,
|
||||
debug,
|
||||
output,
|
||||
});
|
||||
|
||||
const isFile = !isDirectory(path);
|
||||
@@ -161,6 +161,7 @@ export default async function setupAndLink(
|
||||
apiUrl,
|
||||
token,
|
||||
debug,
|
||||
output,
|
||||
currentTeam: client.currentTeam,
|
||||
});
|
||||
const createArgs: any = {
|
||||
|
||||
@@ -3,16 +3,33 @@ import boxen from 'boxen';
|
||||
import { format } from 'util';
|
||||
import { Console } from 'console';
|
||||
import renderLink from './link';
|
||||
import wait from './wait';
|
||||
import wait, { StopSpinner } from './wait';
|
||||
|
||||
export type Output = ReturnType<typeof createOutput>;
|
||||
export type Output = ReturnType<typeof _createOutput>;
|
||||
|
||||
export interface OutputOptions {
|
||||
debug?: boolean;
|
||||
}
|
||||
|
||||
// Singleton
|
||||
let instance: Output | null = null;
|
||||
|
||||
export default function createOutput(opts?: OutputOptions) {
|
||||
if (!instance) {
|
||||
instance = _createOutput(opts);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
function _createOutput({ debug: debugEnabled = false }: OutputOptions = {}) {
|
||||
let spinner: StopSpinner | null = null;
|
||||
|
||||
export default function createOutput({ debug: debugEnabled = false } = {}) {
|
||||
function isDebugEnabled() {
|
||||
return debugEnabled;
|
||||
}
|
||||
|
||||
function print(str: string) {
|
||||
stopSpinner();
|
||||
process.stderr.write(str);
|
||||
}
|
||||
|
||||
@@ -94,18 +111,32 @@ export default function createOutput({ debug: debugEnabled = false } = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
function spinner(message: string, delay: number = 300) {
|
||||
function setSpinner(message: string, delay: number = 300): StopSpinner {
|
||||
if (debugEnabled) {
|
||||
debug(`Spinner invoked (${message}) with a ${delay}ms delay`);
|
||||
let isEnded = false;
|
||||
return () => {
|
||||
const stop = (() => {
|
||||
if (isEnded) return;
|
||||
isEnded = true;
|
||||
debug(`Spinner ended (${message})`);
|
||||
};
|
||||
}) as StopSpinner;
|
||||
stop.text = message;
|
||||
return stop;
|
||||
}
|
||||
|
||||
return wait(message, delay);
|
||||
if (spinner) {
|
||||
spinner.text = message;
|
||||
} else {
|
||||
spinner = wait(message, delay);
|
||||
}
|
||||
return spinner;
|
||||
}
|
||||
|
||||
function stopSpinner() {
|
||||
if (spinner) {
|
||||
spinner();
|
||||
spinner = null;
|
||||
}
|
||||
}
|
||||
|
||||
const c = {
|
||||
@@ -141,6 +172,7 @@ export default function createOutput({ debug: debugEnabled = false } = {}) {
|
||||
dim,
|
||||
time,
|
||||
note,
|
||||
spinner,
|
||||
spinner: setSpinner,
|
||||
stopSpinner,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export { default, Output } from './create-output';
|
||||
export { StopSpinner } from './wait';
|
||||
|
||||
@@ -2,28 +2,50 @@ import ora from 'ora';
|
||||
import chalk from 'chalk';
|
||||
import eraseLines from './erase-lines';
|
||||
|
||||
export default function wait(msg: string, delay: number = 300, _ora = ora) {
|
||||
let spinner: ReturnType<typeof _ora>;
|
||||
let running = false;
|
||||
export interface StopSpinner {
|
||||
(): void;
|
||||
text: string;
|
||||
}
|
||||
|
||||
const planned = setTimeout(() => {
|
||||
export default function wait(
|
||||
msg: string,
|
||||
delay: number = 300,
|
||||
_ora = ora
|
||||
): StopSpinner {
|
||||
let spinner: ReturnType<typeof _ora> | null = null;
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
spinner = _ora(chalk.gray(msg));
|
||||
spinner.color = 'gray';
|
||||
spinner.start();
|
||||
running = true;
|
||||
}, delay);
|
||||
|
||||
const cancel = () => {
|
||||
clearTimeout(planned);
|
||||
if (running) {
|
||||
const stop = () => {
|
||||
clearTimeout(timeout);
|
||||
if (spinner) {
|
||||
spinner.stop();
|
||||
spinner = null;
|
||||
process.stderr.write(eraseLines(1));
|
||||
running = false;
|
||||
}
|
||||
process.removeListener('nowExit', cancel);
|
||||
};
|
||||
|
||||
stop.text = msg;
|
||||
|
||||
// Allow `text` property to update the text while the spinner is in action
|
||||
Object.defineProperty(stop, 'text', {
|
||||
get() {
|
||||
return msg;
|
||||
},
|
||||
|
||||
set(v: string) {
|
||||
msg = v;
|
||||
if (spinner) {
|
||||
spinner.text = chalk.gray(v);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
process.on('nowExit', cancel);
|
||||
return cancel;
|
||||
process.once('nowExit', stop);
|
||||
return stop;
|
||||
}
|
||||
|
||||
4
packages/now-cli/test/dev/fixtures/30-next-image-optimization/.gitignore
vendored
Normal file
4
packages/now-cli/test/dev/fixtures/30-next-image-optimization/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
.next
|
||||
!public
|
||||
yarn.lock
|
||||
.vercel
|
||||
@@ -1,10 +1,12 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "canary",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6"
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import Image from 'next/image';
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<h1>Home Page</h1>
|
||||
<hr />
|
||||
<h2>Optimized</h2>
|
||||
<Image src="/test.png" width="400" height="400" />
|
||||
<hr />
|
||||
<h2>Original</h2>
|
||||
<img src="/test.png" width="400" height="400" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user