mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-11 21:07:47 +00:00
Compare commits
36 Commits
@vercel/ro
...
@vercel/py
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b52d01f809 | ||
|
|
ffefaf82a1 | ||
|
|
6d8dbfc7d6 | ||
|
|
551cd7f688 | ||
|
|
2dfb6b45cd | ||
|
|
65ae2a289e | ||
|
|
72ea3532b1 | ||
|
|
78fac00823 | ||
|
|
9e255afa37 | ||
|
|
e4be68270f | ||
|
|
9c636dc1ba | ||
|
|
c98c9996bf | ||
|
|
0fcf172a10 | ||
|
|
99e5c4a6db | ||
|
|
b8269b0111 | ||
|
|
decac0fe3f | ||
|
|
591d1686d0 | ||
|
|
5e1d5c921c | ||
|
|
603b1256c6 | ||
|
|
6957c72828 | ||
|
|
9be3650cb7 | ||
|
|
6e1ee7a7d6 | ||
|
|
767ce2cff1 | ||
|
|
bb1d0ce1b7 | ||
|
|
31f79c7de1 | ||
|
|
4c230c8436 | ||
|
|
7941f5a104 | ||
|
|
5b931afbf3 | ||
|
|
15080364b8 | ||
|
|
47e3381c6d | ||
|
|
33aefdc029 | ||
|
|
30fe76a0cf | ||
|
|
97ef88dc28 | ||
|
|
f679098d7a | ||
|
|
2b57e12ad3 | ||
|
|
c4e94ad03f |
4
.github/workflows/publish.yml
vendored
4
.github/workflows/publish.yml
vendored
@@ -26,12 +26,12 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
|
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.13.15'
|
go-version: '1.13.15'
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
|
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 14
|
node-version: 14
|
||||||
- name: Install
|
- name: Install
|
||||||
|
|||||||
8
.github/workflows/test-integration-cli.yml
vendored
8
.github/workflows/test-integration-cli.yml
vendored
@@ -25,20 +25,20 @@ jobs:
|
|||||||
echo "TURBO_REMOTE_ONLY=true" >> $GITHUB_ENV
|
echo "TURBO_REMOTE_ONLY=true" >> $GITHUB_ENV
|
||||||
echo "TURBO_TEAM=vercel" >> $GITHUB_ENV
|
echo "TURBO_TEAM=vercel" >> $GITHUB_ENV
|
||||||
echo "TURBO_TOKEN=${{ secrets.TURBO_TOKEN }}" >> $GITHUB_ENV
|
echo "TURBO_TOKEN=${{ secrets.TURBO_TOKEN }}" >> $GITHUB_ENV
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.13.15'
|
go-version: '1.13.15'
|
||||||
- uses: actions/setup-node@v2
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ matrix.node }}
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 100
|
fetch-depth: 100
|
||||||
- run: git --version
|
- run: git --version
|
||||||
- run: git fetch origin main --depth=100
|
- run: git fetch origin main --depth=100
|
||||||
- run: git fetch origin ${{ github.ref }} --depth=100
|
- run: git fetch origin ${{ github.ref }} --depth=100
|
||||||
- run: git diff origin/main...HEAD --name-only
|
- run: git diff origin/main...HEAD --name-only
|
||||||
- run: yarn install --network-timeout 1000000
|
- run: yarn install --network-timeout 1000000 --frozen-lockfile
|
||||||
- run: yarn run build
|
- run: yarn run build
|
||||||
- run: yarn test-integration-cli
|
- run: yarn test-integration-cli
|
||||||
env:
|
env:
|
||||||
|
|||||||
8
.github/workflows/test-unit.yml
vendored
8
.github/workflows/test-unit.yml
vendored
@@ -25,20 +25,20 @@ jobs:
|
|||||||
echo "TURBO_REMOTE_ONLY=true" >> $GITHUB_ENV
|
echo "TURBO_REMOTE_ONLY=true" >> $GITHUB_ENV
|
||||||
echo "TURBO_TEAM=vercel" >> $GITHUB_ENV
|
echo "TURBO_TEAM=vercel" >> $GITHUB_ENV
|
||||||
echo "TURBO_TOKEN=${{ secrets.TURBO_TOKEN }}" >> $GITHUB_ENV
|
echo "TURBO_TOKEN=${{ secrets.TURBO_TOKEN }}" >> $GITHUB_ENV
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.13.15'
|
go-version: '1.13.15'
|
||||||
- uses: actions/setup-node@v2
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ matrix.node }}
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 100
|
fetch-depth: 100
|
||||||
- run: git --version
|
- run: git --version
|
||||||
- run: git fetch origin main --depth=100
|
- run: git fetch origin main --depth=100
|
||||||
- run: git fetch origin ${{ github.ref }} --depth=100
|
- run: git fetch origin ${{ github.ref }} --depth=100
|
||||||
- run: git diff origin/main...HEAD --name-only
|
- run: git diff origin/main...HEAD --name-only
|
||||||
- run: yarn install --network-timeout 1000000
|
- run: yarn install --network-timeout 1000000 --frozen-lockfile
|
||||||
- run: yarn run build
|
- run: yarn run build
|
||||||
- run: yarn run lint
|
- run: yarn run lint
|
||||||
if: matrix.os == 'ubuntu-latest' && matrix.node == 14 # only run lint once
|
if: matrix.os == 'ubuntu-latest' && matrix.node == 14 # only run lint once
|
||||||
|
|||||||
12
.github/workflows/test.yml
vendored
12
.github/workflows/test.yml
vendored
@@ -19,14 +19,14 @@ jobs:
|
|||||||
tests: ${{ steps['set-tests'].outputs['tests'] }}
|
tests: ${{ steps['set-tests'].outputs['tests'] }}
|
||||||
dplUrl: ${{ steps.waitForTarball.outputs.url }}
|
dplUrl: ${{ steps.waitForTarball.outputs.url }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- run: git --version
|
- run: git --version
|
||||||
- run: git fetch origin main
|
- run: git fetch origin main
|
||||||
- uses: actions/setup-node@v2
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
- run: yarn install --network-timeout 1000000
|
- run: yarn install --network-timeout 1000000 --frozen-lockfile
|
||||||
- id: set-tests
|
- id: set-tests
|
||||||
run: |
|
run: |
|
||||||
TESTS_ARRAY=$(node utils/chunk-tests.js $SCRIPT_NAME)
|
TESTS_ARRAY=$(node utils/chunk-tests.js $SCRIPT_NAME)
|
||||||
@@ -58,13 +58,13 @@ jobs:
|
|||||||
echo "TURBO_REMOTE_ONLY=true" >> $GITHUB_ENV
|
echo "TURBO_REMOTE_ONLY=true" >> $GITHUB_ENV
|
||||||
echo "TURBO_TEAM=vercel" >> $GITHUB_ENV
|
echo "TURBO_TEAM=vercel" >> $GITHUB_ENV
|
||||||
echo "TURBO_TOKEN=${{ secrets.TURBO_TOKEN }}" >> $GITHUB_ENV
|
echo "TURBO_TOKEN=${{ secrets.TURBO_TOKEN }}" >> $GITHUB_ENV
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.13.15'
|
go-version: '1.13.15'
|
||||||
- uses: actions/setup-node@v2
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|||||||
@@ -115,7 +115,8 @@ export async function shouldServe(options: ShouldServeOptions) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
If this function is not defined, Vercel CLI will use the [default implementation](https://github.com/vercel/vercel/blob/52994bfe26c5f4f179bdb49783ee57ce19334631/packages/now-build-utils/src/should-serve.ts).
|
If this function is not defined, Vercel CLI will use the [default
|
||||||
|
implementation](https://github.com/vercel/vercel/blob/52994bfe26c5f4f179bdb49783ee57ce19334631/packages/now-build-utils/src/should-serve.ts).
|
||||||
|
|
||||||
### `startDevServer()`
|
### `startDevServer()`
|
||||||
|
|
||||||
@@ -189,7 +190,8 @@ If you need to share state between those steps, use the filesystem.
|
|||||||
|
|
||||||
### Directory and Cache Lifecycle
|
### Directory and Cache Lifecycle
|
||||||
|
|
||||||
When a new build is created, we pre-populate the `workPath` supplied to `analyze` with the results of the `prepareCache` step of the previous build.
|
When a new build is created, we pre-populate the `workPath` supplied to `analyze` with the results of the `prepareCache` step of the
|
||||||
|
previous build.
|
||||||
|
|
||||||
The `analyze` step can modify that directory, and it will not be re-created when it's supplied to `build` and `prepareCache`.
|
The `analyze` step can modify that directory, and it will not be re-created when it's supplied to `build` and `prepareCache`.
|
||||||
|
|
||||||
@@ -197,6 +199,77 @@ The `analyze` step can modify that directory, and it will not be re-created when
|
|||||||
|
|
||||||
The env and secrets specified by the user as `build.env` are passed to the Runtime process. This means you can access user env via `process.env` in Node.js.
|
The env and secrets specified by the user as `build.env` are passed to the Runtime process. This means you can access user env via `process.env` in Node.js.
|
||||||
|
|
||||||
|
### Supporting Large Environment
|
||||||
|
|
||||||
|
We provide the ability to support more than 4KB of environment (up to 64KB) by way of
|
||||||
|
a Lambda runtime wrapper that is added to every Lambda function we create. These are
|
||||||
|
supported by many of the existing Lambda runtimes, but custom runtimes may require
|
||||||
|
additional work.
|
||||||
|
|
||||||
|
The following Lambda runtime families have built-in support for the runtime wrapper:
|
||||||
|
|
||||||
|
- `nodejs`
|
||||||
|
- `python` (>= 3.8)
|
||||||
|
- `ruby`
|
||||||
|
- `java11`
|
||||||
|
- `java8.al2` (not `java8`)
|
||||||
|
- `dotnetcore`
|
||||||
|
|
||||||
|
If a custom runtime is based on one of these Lambda runtimes, large environment
|
||||||
|
support will be available without further configuration. Custom runtimes based on
|
||||||
|
other Lambda runtimes, including those that provide the runtime via `provided` and
|
||||||
|
`provided.al2`, must implement runtime wrapper support and indicate it via the
|
||||||
|
`supportsWrapper` flag when calling [`createLambda`](#createlambda()).
|
||||||
|
|
||||||
|
To add support for runtime wrappers to a custom runtime, first check the value of the
|
||||||
|
`AWS_LAMBDA_EXEC_WRAPPER` environment variable in the bootstrap script. Its value is
|
||||||
|
the path to the wrapper executable.
|
||||||
|
|
||||||
|
The wrapper must be passed the path to the runtime as well as any parameters that the
|
||||||
|
runtime requires. This is most easily done in a small `bootstrap` script.
|
||||||
|
|
||||||
|
In this simple `bash` example, the runtime is called directly if
|
||||||
|
`AWS_LAMBDA_EXEC_WRAPPER` has no value, otherwise the wrapper is called with the
|
||||||
|
runtime command as parameters.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
exec $AWS_LAMBDA_EXEC_WRAPPER path/to/runtime param1 param2
|
||||||
|
```
|
||||||
|
|
||||||
|
If the `bootstrap` file is not a launcher script, but the entrypoint of the runtime
|
||||||
|
itself, replace the bootstrap process with the wrapper. Pass the path and parameters
|
||||||
|
of the executing file, ensuring the `AWS_LAMBDA_EXEC_WRAPPER` environment variable is
|
||||||
|
set to blank.
|
||||||
|
|
||||||
|
This `bash` example uses `exec` to replace the running bootstrap process with the
|
||||||
|
wrapper, passing its own path and parameters.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [[ -n $AWS_LAMBDA_EXEC_WRAPPER ]]
|
||||||
|
__WRAPPER=$AWS_LAMBDA_EXEC_WRAPPER
|
||||||
|
AWS_LAMBDA_EXEC_WRAPPER=""
|
||||||
|
exec $__WRAPPER "$0" "${@}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# start the actual runtime functionality
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that unsetting the variable may not have the desired effect due to the way
|
||||||
|
Lambda spawns runtime processes. It is better to explicitly set it to blank.
|
||||||
|
|
||||||
|
The best way to replace the existing bootstrap process is with the
|
||||||
|
[`execve`](https://www.man7.org/linux/man-pages/man2/execve.2.html) syscall.
|
||||||
|
This is achieved by using `exec` in `bash` to replace the running process with the wrapper,
|
||||||
|
maintaining the same PID and environment.
|
||||||
|
|
||||||
|
Once support for runtime wrappers is included, ensure `supportsWrapper` is set to
|
||||||
|
`true` in the call to [`createLambda`](#createlambda()). This will inform the build
|
||||||
|
process to enable large environment support for this runtime.
|
||||||
|
|
||||||
### Utilities as peerDependencies
|
### Utilities as peerDependencies
|
||||||
|
|
||||||
When you publish your Runtime to npm, make sure to not specify `@vercel/build-utils` (as seen below in the API definitions) as a dependency, but rather as part of `peerDependencies`.
|
When you publish your Runtime to npm, make sure to not specify `@vercel/build-utils` (as seen below in the API definitions) as a dependency, but rather as part of `peerDependencies`.
|
||||||
@@ -304,6 +377,7 @@ This is a [class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refere
|
|||||||
- `handler: String` path to handler file and (optionally) a function name it exports
|
- `handler: String` path to handler file and (optionally) a function name it exports
|
||||||
- `runtime: LambdaRuntime` the name of the lambda runtime
|
- `runtime: LambdaRuntime` the name of the lambda runtime
|
||||||
- `environment: Object` key-value map of handler-related (aside of those passed by user) environment variables
|
- `environment: Object` key-value map of handler-related (aside of those passed by user) environment variables
|
||||||
|
- `supportsWrapper: Boolean` set to true to indicate that Lambda runtime wrappers are supported by this runtime
|
||||||
|
|
||||||
### `LambdaRuntime`
|
### `LambdaRuntime`
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,6 @@ For details on how to use Vercel, check out our [documentation](https://vercel.c
|
|||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
- [Code of Conduct](https://github.com/vercel/vercel/blob/main/.github/CODE_OF_CONDUCT.md)
|
- [Code of Conduct](./.github/CODE_OF_CONDUCT.md)
|
||||||
- [Contributing Guidelines](https://github.com/vercel/vercel/blob/main/.github/CONTRIBUTING.md)
|
- [Contributing Guidelines](./.github/CONTRIBUTING.md)
|
||||||
- [MIT License](https://github.com/vercel/vercel/blob/main/LICENSE)
|
- [MIT License](./LICENSE)
|
||||||
|
|||||||
1
examples/astro/.gitignore
vendored
1
examples/astro/.gitignore
vendored
@@ -18,3 +18,4 @@ pnpm-debug.log*
|
|||||||
|
|
||||||
# macOS-specific files
|
# macOS-specific files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
.vercel
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
README.md
|
|
||||||
@@ -1,10 +1,16 @@
|
|||||||
# Welcome to [Astro](https://astro.build)
|
# Astro
|
||||||
|
|
||||||
[](https://stackblitz.com/github/withastro/astro/tree/latest/examples/starter)
|
This directory is a brief example of an [Astro](https://astro.build/) site that can be deployed to Vercel with zero configuration.
|
||||||
|
|
||||||
> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
|
## Deploy Your Own
|
||||||
|
|
||||||
## 🚀 Project Structure
|
Deploy your own Astro project with Vercel.
|
||||||
|
|
||||||
|
[](https://vercel.com/new/clone?repository-url=https://github.com/vercel/vercel/tree/main/examples/astro&template=astro)
|
||||||
|
|
||||||
|
_Live Example: https://astro-template.vercel.app_
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
Inside of your Astro project, you'll see the following folders and files:
|
Inside of your Astro project, you'll see the following folders and files:
|
||||||
|
|
||||||
@@ -26,17 +32,15 @@ There's nothing special about `src/components/`, but that's where we like to put
|
|||||||
|
|
||||||
Any static assets, like images, can be placed in the `public/` directory.
|
Any static assets, like images, can be placed in the `public/` directory.
|
||||||
|
|
||||||
## 🧞 Commands
|
## Commands
|
||||||
|
|
||||||
All commands are run from the root of the project, from a terminal:
|
All commands are run from the root of the project, from a terminal:
|
||||||
|
|
||||||
| Command | Action |
|
| Command | Action |
|
||||||
| :---------------- | :------------------------------------------- |
|
| :--------------------- | :------------------------------------------------- |
|
||||||
| `npm install` | Installs dependencies |
|
| `npm install` | Installs dependencies |
|
||||||
| `npm run dev` | Starts local dev server at `localhost:3000` |
|
| `npm run dev` | Starts local dev server at `localhost:3000` |
|
||||||
| `npm run build` | Build your production site to `./dist/` |
|
| `npm run build` | Build your production site to `./dist/` |
|
||||||
| `npm run preview` | Preview your build locally, before deploying |
|
| `npm run preview` | Preview your build locally, before deploying |
|
||||||
|
| `npm run astro ...` | Run CLI commands like `astro add`, `astro preview` |
|
||||||
## 👀 Want to learn more?
|
| `npm run astro --help` | Get help using the Astro CLI |
|
||||||
|
|
||||||
Feel free to check [our documentation](https://github.com/withastro/astro) or jump into our [Discord server](https://astro.build/chat).
|
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "@example/basics",
|
|
||||||
"version": "0.0.1",
|
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "astro dev",
|
"dev": "astro dev",
|
||||||
"start": "astro dev",
|
"start": "astro dev",
|
||||||
"build": "astro build",
|
"build": "astro build",
|
||||||
"preview": "astro preview"
|
"preview": "astro preview",
|
||||||
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"astro": "^1.0.0-beta.20"
|
"astro": "^1.0.0-rc.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
76
examples/astro/src/components/Card.astro
Normal file
76
examples/astro/src/components/Card.astro
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
---
|
||||||
|
export interface Props {
|
||||||
|
title: string;
|
||||||
|
body: string;
|
||||||
|
href: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { href, title, body } = Astro.props as Props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<li class="link-card">
|
||||||
|
<a href={href}>
|
||||||
|
<h2>
|
||||||
|
{title}
|
||||||
|
<span>→</span>
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
{body}
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--link-gradient: linear-gradient(45deg, #4f39fa, #da62c4 30%, var(--color-border) 60%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-card {
|
||||||
|
list-style: none;
|
||||||
|
display: flex;
|
||||||
|
padding: 0.15rem;
|
||||||
|
background-image: var(--link-gradient);
|
||||||
|
background-size: 400%;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
background-position: 100%;
|
||||||
|
transition: background-position 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-card > a {
|
||||||
|
width: 100%;
|
||||||
|
text-decoration: none;
|
||||||
|
line-height: 1.4;
|
||||||
|
padding: 1em 1.3em;
|
||||||
|
border-radius: 0.35rem;
|
||||||
|
color: var(--text-color);
|
||||||
|
background-color: white;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 0;
|
||||||
|
transition: color 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 span {
|
||||||
|
display: inline-block;
|
||||||
|
transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-card:is(:hover, :focus-within) {
|
||||||
|
background-position: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-card:is(:hover, :focus-within) h2 {
|
||||||
|
color: #4f39fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-card:is(:hover, :focus-within) h2 span {
|
||||||
|
will-change: transform;
|
||||||
|
transform: translateX(2px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
---
|
|
||||||
export interface Props {
|
|
||||||
title: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { title } = Astro.props as Props;
|
|
||||||
---
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width">
|
|
||||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
|
||||||
<title>{title}</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<slot />
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--font-size-base: clamp(1rem, 0.34vw + 0.91rem, 1.19rem);
|
|
||||||
--font-size-lg: clamp(1.2rem, 0.7vw + 1.2rem, 1.5rem);
|
|
||||||
--font-size-xl: clamp(2.44rem, 2.38vw + 1.85rem, 3.75rem);
|
|
||||||
|
|
||||||
--color-text: hsl(12, 5%, 4%);
|
|
||||||
--color-bg: hsl(10, 21%, 95%);
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
font-family: system-ui, sans-serif;
|
|
||||||
font-size: var(--font-size-base);
|
|
||||||
color: var(--color-text);
|
|
||||||
background-color: var(--color-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(h1) {
|
|
||||||
font-size: var(--font-size-xl);
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(h2) {
|
|
||||||
font-size: var(--font-size-lg);
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(code) {
|
|
||||||
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
|
|
||||||
Bitstream Vera Sans Mono, Courier New, monospace;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
1
examples/astro/src/env.d.ts
vendored
Normal file
1
examples/astro/src/env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/// <reference types="astro/client" />
|
||||||
56
examples/astro/src/layouts/Layout.astro
Normal file
56
examples/astro/src/layouts/Layout.astro
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
---
|
||||||
|
export interface Props {
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { title } = Astro.props as Props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
|
<meta name="generator" content={Astro.generator} />
|
||||||
|
<title>{title}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<slot />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--font-size-base: clamp(1rem, 0.34vw + 0.91rem, 1.19rem);
|
||||||
|
--font-size-lg: clamp(1.2rem, 0.7vw + 1.2rem, 1.5rem);
|
||||||
|
--font-size-xl: clamp(2.44rem, 2.38vw + 1.85rem, 3.75rem);
|
||||||
|
|
||||||
|
--color-text: hsl(12, 5%, 4%);
|
||||||
|
--color-bg: hsl(10, 21%, 95%);
|
||||||
|
--color-border: hsl(17, 24%, 90%);
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-family: system-ui, sans-serif;
|
||||||
|
font-size: var(--font-size-base);
|
||||||
|
color: var(--color-text);
|
||||||
|
background-color: var(--color-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(h1) {
|
||||||
|
font-size: var(--font-size-xl);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(h2) {
|
||||||
|
font-size: var(--font-size-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(code) {
|
||||||
|
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
|
||||||
|
Bitstream Vera Sans Mono, Courier New, monospace;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,81 +1,52 @@
|
|||||||
---
|
---
|
||||||
import Layout from '../components/Layout.astro';
|
import Layout from '../layouts/Layout.astro';
|
||||||
|
import Card from '../components/Card.astro';
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title="Welcome to Astro.">
|
<Layout title="Welcome to Astro.">
|
||||||
<main>
|
<main>
|
||||||
<h1>Welcome to <span class="text-gradient">Astro</span></h1>
|
<h1>Welcome to <span class="text-gradient">Astro</span></h1>
|
||||||
<p class="instructions"><strong>Your first mission:</strong> tweak this message to try our hot module reloading. Check the <code>src/pages</code> directory!</p>
|
<p class="instructions">
|
||||||
|
Check out the <code>src/pages</code> directory to get started.<br />
|
||||||
|
<strong>Code Challenge:</strong> Tweak the "Welcome to Astro" message above.
|
||||||
|
</p>
|
||||||
<ul role="list" class="link-card-grid">
|
<ul role="list" class="link-card-grid">
|
||||||
<li class="link-card">
|
<Card
|
||||||
<a href="https://astro.build/integrations/">
|
href="https://docs.astro.build/"
|
||||||
<h2>Integrations <span>→</span></h2>
|
title="Documentation"
|
||||||
<p>Add component frameworks, Tailwind, Partytown, and more!</p>
|
body="Learn how Astro works and explore the official API docs."
|
||||||
</a>
|
/>
|
||||||
</li>
|
<Card
|
||||||
<li class="link-card">
|
href="https://astro.build/integrations/"
|
||||||
<a href="https://astro.build/themes/">
|
title="Integrations"
|
||||||
<h2>Themes <span>→</span></h2>
|
body="Supercharge your project with new frameworks and libraries."
|
||||||
<p>Explore a galaxy of community-built starters.</p>
|
/>
|
||||||
</a>
|
<Card
|
||||||
</li>
|
href="https://astro.build/themes/"
|
||||||
<li class="link-card">
|
title="Themes"
|
||||||
<a href="https://docs.astro.build/">
|
body="Explore a galaxy of community-built starter themes."
|
||||||
<h2>Docs <span>→</span></h2>
|
/>
|
||||||
<p>Learn our complete feature set and explore the API.</p>
|
<Card
|
||||||
</a>
|
href="https://astro.build/chat/"
|
||||||
</li>
|
title="Chat"
|
||||||
<li class="link-card">
|
body="Come say hi to our amazing Discord community. ❤️"
|
||||||
<a href="https://astro.build/chat/">
|
/>
|
||||||
<h2>Chat <span>→</span></h2>
|
|
||||||
<p>
|
|
||||||
Ask, contribute, and have fun on our community Discord
|
|
||||||
<svg
|
|
||||||
class="heart"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 512 512"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
fill="currentColor"
|
|
||||||
>
|
|
||||||
<title>heart</title>
|
|
||||||
<path d="M256 448l-30.164-27.211C118.718 322.442 48 258.61 48 179.095 48 114.221 97.918 64 162.4 64c36.399 0 70.717 16.742 93.6 43.947C278.882 80.742 313.199 64 349.6 64 414.082 64 464 114.221 464 179.095c0 79.516-70.719 143.348-177.836 241.694L256 448z" />
|
|
||||||
</svg>
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</main>
|
</main>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--color-border: hsl(17, 24%, 90%);
|
--astro-gradient: linear-gradient(0deg, #4f39fa, #da62c4);
|
||||||
--astro-gradient: linear-gradient(0deg,#4F39FA, #DA62C4);
|
|
||||||
--link-gradient: linear-gradient(45deg, #4F39FA, #DA62C4 30%, var(--color-border) 60%);
|
|
||||||
--night-sky-gradient: linear-gradient(0deg, #392362 -33%, #431f69 10%, #30216b 50%, #1f1638 100%);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h1 {
|
||||||
margin: 0;
|
margin: 2rem 0;
|
||||||
transition: color 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 span {
|
|
||||||
display: inline-block;
|
|
||||||
transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-size: 0.875em;
|
|
||||||
border: 0.1em solid var(--color-border);
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 0.15em 0.25em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
max-width: 60ch;
|
max-width: 60ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +54,7 @@ import Layout from '../components/Layout.astro';
|
|||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
background-image: var(--astro-gradient);
|
background-image: var(--astro-gradient);
|
||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
-webkit-text-fill-color: transparent;
|
-webkit-text-fill-color: transparent;
|
||||||
background-size: 100% 200%;
|
background-size: 100% 200%;
|
||||||
background-position-y: 100%;
|
background-position-y: 100%;
|
||||||
border-radius: 0.4rem;
|
border-radius: 0.4rem;
|
||||||
@@ -91,7 +62,8 @@ import Layout from '../components/Layout.astro';
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes pulse {
|
@keyframes pulse {
|
||||||
0%, 100% {
|
0%,
|
||||||
|
100% {
|
||||||
background-position-y: 0%;
|
background-position-y: 0%;
|
||||||
}
|
}
|
||||||
50% {
|
50% {
|
||||||
@@ -100,75 +72,25 @@ import Layout from '../components/Layout.astro';
|
|||||||
}
|
}
|
||||||
|
|
||||||
.instructions {
|
.instructions {
|
||||||
line-height: 1.8;
|
line-height: 1.6;
|
||||||
margin-bottom: 2rem;
|
margin: 1rem 0;
|
||||||
background-image: var(--night-sky-gradient);
|
background: #4f39fa;
|
||||||
padding: 1.5rem;
|
padding: 1rem;
|
||||||
border-radius: 0.4rem;
|
border-radius: 0.4rem;
|
||||||
color: var(--color-bg);
|
color: var(--color-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.instructions code {
|
||||||
|
font-size: 0.875em;
|
||||||
|
border: 0.1em solid var(--color-border);
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 0.15em 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
.link-card-grid {
|
.link-card-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(24ch, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(24ch, 1fr));
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link-card {
|
|
||||||
list-style: none;
|
|
||||||
display: flex;
|
|
||||||
padding: 0.15rem;
|
|
||||||
background-image: var(--link-gradient);
|
|
||||||
background-size: 400%;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
background-position: 100%;
|
|
||||||
transition: background-position 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-card > a {
|
|
||||||
width: 100%;
|
|
||||||
text-decoration: none;
|
|
||||||
line-height: 1.4;
|
|
||||||
padding: 1em 1.3em;
|
|
||||||
border-radius: 0.35rem;
|
|
||||||
color: var(--text-color);
|
|
||||||
background-color: white;
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-card:is(:hover, :focus-within) {
|
|
||||||
background-position: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-card:is(:hover, :focus-within) h2 {
|
|
||||||
color: #4F39FA;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-card:is(:hover, :focus-within) h2 span {
|
|
||||||
transform: translateX(2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.heart {
|
|
||||||
display: inline-block;
|
|
||||||
color: #DA62C4;
|
|
||||||
animation: heartbeat 3s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes heartbeat {
|
|
||||||
0%,
|
|
||||||
50%,
|
|
||||||
100% {
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
5% {
|
|
||||||
transform: scale(1.125);
|
|
||||||
}
|
|
||||||
10% {
|
|
||||||
transform: scale(1.05);
|
|
||||||
}
|
|
||||||
15% {
|
|
||||||
transform: scale(1.25);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
// Enable top-level await, and other modern ESM features.
|
|
||||||
"target": "ESNext",
|
|
||||||
"module": "ESNext",
|
|
||||||
// Enable node-style module resolution, for things like npm package imports.
|
|
||||||
"moduleResolution": "node",
|
|
||||||
// Enable JSON imports.
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
// Enable stricter transpilation for better output.
|
|
||||||
"isolatedModules": true,
|
|
||||||
// Add type definitions for our Vite runtime.
|
|
||||||
"types": ["vite/client"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/build-utils",
|
"name": "@vercel/build-utils",
|
||||||
"version": "5.2.0",
|
"version": "5.3.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.js",
|
"types": "./dist/index.d.js",
|
||||||
|
|||||||
@@ -8,17 +8,13 @@ import FileFsRef from '../file-fs-ref';
|
|||||||
|
|
||||||
export type GlobOptions = vanillaGlob_.IOptions;
|
export type GlobOptions = vanillaGlob_.IOptions;
|
||||||
|
|
||||||
interface FsFiles {
|
|
||||||
[filePath: string]: FileFsRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
const vanillaGlob = promisify(vanillaGlob_);
|
const vanillaGlob = promisify(vanillaGlob_);
|
||||||
|
|
||||||
export default async function glob(
|
export default async function glob(
|
||||||
pattern: string,
|
pattern: string,
|
||||||
opts: GlobOptions | string,
|
opts: GlobOptions | string,
|
||||||
mountpoint?: string
|
mountpoint?: string
|
||||||
): Promise<FsFiles> {
|
): Promise<Record<string, FileFsRef>> {
|
||||||
let options: GlobOptions;
|
let options: GlobOptions;
|
||||||
if (typeof opts === 'string') {
|
if (typeof opts === 'string') {
|
||||||
options = { cwd: opts };
|
options = { cwd: opts };
|
||||||
@@ -36,10 +32,11 @@ export default async function glob(
|
|||||||
throw new Error(`basePath/cwd must be an absolute path (${options.cwd})`);
|
throw new Error(`basePath/cwd must be an absolute path (${options.cwd})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const results: FsFiles = {};
|
const results: Record<string, FileFsRef> = {};
|
||||||
|
const statCache: Record<string, Stats> = {};
|
||||||
|
|
||||||
options.symlinks = {};
|
options.symlinks = {};
|
||||||
options.statCache = {};
|
options.statCache = statCache;
|
||||||
options.stat = true;
|
options.stat = true;
|
||||||
options.dot = true;
|
options.dot = true;
|
||||||
|
|
||||||
@@ -47,7 +44,7 @@ export default async function glob(
|
|||||||
|
|
||||||
for (const relativePath of files) {
|
for (const relativePath of files) {
|
||||||
const fsPath = normalizePath(path.join(options.cwd, relativePath));
|
const fsPath = normalizePath(path.join(options.cwd, relativePath));
|
||||||
let stat: Stats = options.statCache[fsPath] as Stats;
|
let stat = statCache[fsPath];
|
||||||
assert(
|
assert(
|
||||||
stat,
|
stat,
|
||||||
`statCache does not contain value for ${relativePath} (resolved to ${fsPath})`
|
`statCache does not contain value for ${relativePath} (resolved to ${fsPath})`
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const allOptions = [
|
|||||||
major: 12,
|
major: 12,
|
||||||
range: '12.x',
|
range: '12.x',
|
||||||
runtime: 'nodejs12.x',
|
runtime: 'nodejs12.x',
|
||||||
discontinueDate: new Date('2022-08-09'),
|
discontinueDate: new Date('2022-10-01'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
major: 10,
|
major: 10,
|
||||||
|
|||||||
32
packages/build-utils/src/get-prefixed-env-vars.ts
Normal file
32
packages/build-utils/src/get-prefixed-env-vars.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
type Envs = { [key: string]: string | undefined };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the framework-specific prefixed System Environment Variables.
|
||||||
|
* See https://vercel.com/docs/concepts/projects/environment-variables#system-environment-variables
|
||||||
|
* @param envPrefix - Prefix, typically from `@vercel/frameworks`
|
||||||
|
* @param envs - Environment Variables, typically from `process.env`
|
||||||
|
*/
|
||||||
|
export function getPrefixedEnvVars({
|
||||||
|
envPrefix,
|
||||||
|
envs,
|
||||||
|
}: {
|
||||||
|
envPrefix: string | undefined;
|
||||||
|
envs: Envs;
|
||||||
|
}): Envs {
|
||||||
|
const vercelSystemEnvPrefix = 'VERCEL_';
|
||||||
|
const newEnvs: Envs = {};
|
||||||
|
if (envPrefix && envs.VERCEL_URL) {
|
||||||
|
Object.keys(envs)
|
||||||
|
.filter(key => key.startsWith(vercelSystemEnvPrefix))
|
||||||
|
.forEach(key => {
|
||||||
|
const newKey = `${envPrefix}${key}`;
|
||||||
|
if (!(newKey in envs)) {
|
||||||
|
newEnvs[newKey] = envs[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Tell turbo to exclude all Vercel System Env Vars
|
||||||
|
// See https://github.com/vercel/turborepo/pull/1622
|
||||||
|
newEnvs.TURBO_CI_VENDOR_ENV_KEY = `${envPrefix}${vercelSystemEnvPrefix}`;
|
||||||
|
}
|
||||||
|
return newEnvs;
|
||||||
|
}
|
||||||
@@ -40,6 +40,7 @@ import streamToBuffer from './fs/stream-to-buffer';
|
|||||||
import debug from './debug';
|
import debug from './debug';
|
||||||
import getIgnoreFilter from './get-ignore-filter';
|
import getIgnoreFilter from './get-ignore-filter';
|
||||||
import { getPlatformEnv } from './get-platform-env';
|
import { getPlatformEnv } from './get-platform-env';
|
||||||
|
import { getPrefixedEnvVars } from './get-prefixed-env-vars';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
FileBlob,
|
FileBlob,
|
||||||
@@ -76,6 +77,7 @@ export {
|
|||||||
getDiscontinuedNodeVersions,
|
getDiscontinuedNodeVersions,
|
||||||
getSpawnOptions,
|
getSpawnOptions,
|
||||||
getPlatformEnv,
|
getPlatformEnv,
|
||||||
|
getPrefixedEnvVars,
|
||||||
streamToBuffer,
|
streamToBuffer,
|
||||||
debug,
|
debug,
|
||||||
isSymbolicLink,
|
isSymbolicLink,
|
||||||
|
|||||||
@@ -335,6 +335,7 @@ export interface ProjectSettings {
|
|||||||
directoryListing?: boolean;
|
directoryListing?: boolean;
|
||||||
gitForkProtection?: boolean;
|
gitForkProtection?: boolean;
|
||||||
commandForIgnoringBuildStep?: string | null;
|
commandForIgnoringBuildStep?: string | null;
|
||||||
|
skipGitConnectDuringLink?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BuilderV2 {
|
export interface BuilderV2 {
|
||||||
|
|||||||
87
packages/build-utils/test/unit.get-prefixed-env-vars.test.ts
vendored
Normal file
87
packages/build-utils/test/unit.get-prefixed-env-vars.test.ts
vendored
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import { getPrefixedEnvVars } from '../src';
|
||||||
|
|
||||||
|
describe('Test `getPrefixedEnvVars()`', () => {
|
||||||
|
const cases: Array<{
|
||||||
|
name: string;
|
||||||
|
args: Parameters<typeof getPrefixedEnvVars>[0];
|
||||||
|
want: ReturnType<typeof getPrefixedEnvVars>;
|
||||||
|
}> = [
|
||||||
|
{
|
||||||
|
name: 'should work with NEXT_PUBLIC_',
|
||||||
|
args: {
|
||||||
|
envPrefix: 'NEXT_PUBLIC_',
|
||||||
|
envs: {
|
||||||
|
VERCEL: '1',
|
||||||
|
VERCEL_URL: 'example.vercel.sh',
|
||||||
|
USER_ENV_VAR_NOT_VERCEL: 'example.com',
|
||||||
|
FOO: 'bar',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: {
|
||||||
|
NEXT_PUBLIC_VERCEL_URL: 'example.vercel.sh',
|
||||||
|
TURBO_CI_VENDOR_ENV_KEY: 'NEXT_PUBLIC_VERCEL_',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should work with GATSBY_',
|
||||||
|
args: {
|
||||||
|
envPrefix: 'GATSBY_',
|
||||||
|
envs: {
|
||||||
|
USER_ENV_VAR_NOT_VERCEL: 'example.com',
|
||||||
|
FOO: 'bar',
|
||||||
|
VERCEL_URL: 'example.vercel.sh',
|
||||||
|
VERCEL_ENV: 'production',
|
||||||
|
VERCEL_REGION: 'iad1',
|
||||||
|
VERCEL_GIT_COMMIT_AUTHOR_LOGIN: 'rauchg',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: {
|
||||||
|
GATSBY_VERCEL_URL: 'example.vercel.sh',
|
||||||
|
GATSBY_VERCEL_ENV: 'production',
|
||||||
|
GATSBY_VERCEL_REGION: 'iad1',
|
||||||
|
GATSBY_VERCEL_GIT_COMMIT_AUTHOR_LOGIN: 'rauchg',
|
||||||
|
TURBO_CI_VENDOR_ENV_KEY: 'GATSBY_VERCEL_',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should not return anything if no system env vars detected',
|
||||||
|
args: {
|
||||||
|
envPrefix: 'GATSBY_',
|
||||||
|
envs: {
|
||||||
|
USER_ENV_VAR_NOT_VERCEL: 'example.com',
|
||||||
|
FOO: 'bar',
|
||||||
|
BLARG_VERCEL_THING: 'fake',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should not return anything if envPrefix is empty string',
|
||||||
|
args: {
|
||||||
|
envPrefix: '',
|
||||||
|
envs: {
|
||||||
|
VERCEL: '1',
|
||||||
|
VERCEL_URL: 'example.vercel.sh',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should not return anything if envPrefix is undefined',
|
||||||
|
args: {
|
||||||
|
envPrefix: undefined,
|
||||||
|
envs: {
|
||||||
|
VERCEL: '1',
|
||||||
|
VERCEL_URL: 'example.vercel.sh',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: {},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const { name, args, want } of cases) {
|
||||||
|
it(name, () => {
|
||||||
|
expect(getPrefixedEnvVars(args)).toEqual(want);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
6
packages/build-utils/test/unit.test.ts
vendored
6
packages/build-utils/test/unit.test.ts
vendored
@@ -394,7 +394,7 @@ it('should get latest node version', async () => {
|
|||||||
it('should throw for discontinued versions', async () => {
|
it('should throw for discontinued versions', async () => {
|
||||||
// Mock a future date so that Node 8 and 10 become discontinued
|
// Mock a future date so that Node 8 and 10 become discontinued
|
||||||
const realDateNow = Date.now.bind(global.Date);
|
const realDateNow = Date.now.bind(global.Date);
|
||||||
global.Date.now = () => new Date('2022-09-01').getTime();
|
global.Date.now = () => new Date('2022-10-15').getTime();
|
||||||
|
|
||||||
expect(getSupportedNodeVersion('8.10.x', false)).rejects.toThrow();
|
expect(getSupportedNodeVersion('8.10.x', false)).rejects.toThrow();
|
||||||
expect(getSupportedNodeVersion('8.10.x', true)).rejects.toThrow();
|
expect(getSupportedNodeVersion('8.10.x', true)).rejects.toThrow();
|
||||||
@@ -436,8 +436,8 @@ it('should warn for deprecated versions, soon to be discontinued', async () => {
|
|||||||
expect(warningMessages).toStrictEqual([
|
expect(warningMessages).toStrictEqual([
|
||||||
'Error: Node.js version 10.x has reached End-of-Life. Deployments created on or after 2021-04-20 will fail to build. Please set "engines": { "node": "16.x" } in your `package.json` file to use Node.js 16.',
|
'Error: Node.js version 10.x has reached End-of-Life. Deployments created on or after 2021-04-20 will fail to build. Please set "engines": { "node": "16.x" } in your `package.json` file to use Node.js 16.',
|
||||||
'Error: Node.js version 10.x has reached End-of-Life. Deployments created on or after 2021-04-20 will fail to build. Please set Node.js Version to 16.x in your Project Settings to use Node.js 16.',
|
'Error: Node.js version 10.x has reached End-of-Life. Deployments created on or after 2021-04-20 will fail to build. Please set Node.js Version to 16.x in your Project Settings to use Node.js 16.',
|
||||||
'Error: Node.js version 12.x has reached End-of-Life. Deployments created on or after 2022-08-09 will fail to build. Please set "engines": { "node": "16.x" } in your `package.json` file to use Node.js 16.',
|
'Error: Node.js version 12.x has reached End-of-Life. Deployments created on or after 2022-10-01 will fail to build. Please set "engines": { "node": "16.x" } in your `package.json` file to use Node.js 16.',
|
||||||
'Error: Node.js version 12.x has reached End-of-Life. Deployments created on or after 2022-08-09 will fail to build. Please set Node.js Version to 16.x in your Project Settings to use Node.js 16.',
|
'Error: Node.js version 12.x has reached End-of-Life. Deployments created on or after 2022-10-01 will fail to build. Please set Node.js Version to 16.x in your Project Settings to use Node.js 16.',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
global.Date.now = realDateNow;
|
global.Date.now = realDateNow;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vercel",
|
"name": "vercel",
|
||||||
"version": "27.3.7",
|
"version": "28.0.0",
|
||||||
"preferGlobal": true,
|
"preferGlobal": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"description": "The command-line interface for Vercel",
|
"description": "The command-line interface for Vercel",
|
||||||
@@ -41,16 +41,16 @@
|
|||||||
"node": ">= 14"
|
"node": ">= 14"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vercel/build-utils": "5.2.0",
|
"@vercel/build-utils": "5.3.1",
|
||||||
"@vercel/go": "2.0.15",
|
"@vercel/go": "2.1.1",
|
||||||
"@vercel/hydrogen": "0.0.12",
|
"@vercel/hydrogen": "0.0.14",
|
||||||
"@vercel/next": "3.1.15",
|
"@vercel/next": "3.1.18",
|
||||||
"@vercel/node": "2.5.6",
|
"@vercel/node": "2.5.8",
|
||||||
"@vercel/python": "3.1.7",
|
"@vercel/python": "3.1.9",
|
||||||
"@vercel/redwood": "1.0.16",
|
"@vercel/redwood": "1.0.18",
|
||||||
"@vercel/remix": "1.0.17",
|
"@vercel/remix": "1.0.19",
|
||||||
"@vercel/ruby": "1.3.23",
|
"@vercel/ruby": "1.3.25",
|
||||||
"@vercel/static-build": "1.0.16",
|
"@vercel/static-build": "1.0.18",
|
||||||
"update-notifier": "5.1.0"
|
"update-notifier": "5.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -96,7 +96,7 @@
|
|||||||
"@types/which": "1.3.2",
|
"@types/which": "1.3.2",
|
||||||
"@types/write-json-file": "2.2.1",
|
"@types/write-json-file": "2.2.1",
|
||||||
"@types/yauzl-promise": "2.1.0",
|
"@types/yauzl-promise": "2.1.0",
|
||||||
"@vercel/client": "12.1.10",
|
"@vercel/client": "12.2.0",
|
||||||
"@vercel/frameworks": "1.1.3",
|
"@vercel/frameworks": "1.1.3",
|
||||||
"@vercel/fs-detectors": "2.0.5",
|
"@vercel/fs-detectors": "2.0.5",
|
||||||
"@vercel/fun": "1.0.4",
|
"@vercel/fun": "1.0.4",
|
||||||
@@ -118,7 +118,6 @@
|
|||||||
"chokidar": "3.3.1",
|
"chokidar": "3.3.1",
|
||||||
"codecov": "3.8.2",
|
"codecov": "3.8.2",
|
||||||
"cpy": "7.2.0",
|
"cpy": "7.2.0",
|
||||||
"credit-card": "3.0.1",
|
|
||||||
"date-fns": "1.29.0",
|
"date-fns": "1.29.0",
|
||||||
"debug": "3.1.0",
|
"debug": "3.1.0",
|
||||||
"dot": "1.1.3",
|
"dot": "1.1.3",
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ const help = () => {
|
|||||||
)} Login token
|
)} Login token
|
||||||
-S, --scope Set a custom scope
|
-S, --scope Set a custom scope
|
||||||
-N, --next Show next page of results
|
-N, --next Show next page of results
|
||||||
|
-y, --yes Skip the confirmation prompt when removing an alias
|
||||||
|
|
||||||
${chalk.dim('Examples:')}
|
${chalk.dim('Examples:')}
|
||||||
|
|
||||||
|
|||||||
@@ -1,170 +0,0 @@
|
|||||||
import ansiEscapes from 'ansi-escapes';
|
|
||||||
import chalk from 'chalk';
|
|
||||||
import ccValidator from 'credit-card';
|
|
||||||
import textInput from '../../util/input/text';
|
|
||||||
import cardBrands from '../../util/billing/card-brands';
|
|
||||||
import success from '../../util/output/success';
|
|
||||||
import wait from '../../util/output/wait';
|
|
||||||
import chars from '../../util/output/chars';
|
|
||||||
import error from '../../util/output/error';
|
|
||||||
|
|
||||||
const expDateMiddleware = data => data;
|
|
||||||
|
|
||||||
export default async function ({ creditCards, clear = false, contextName }) {
|
|
||||||
const state = {
|
|
||||||
error: undefined,
|
|
||||||
cardGroupLabel: `> ${chalk.bold(
|
|
||||||
`Enter your card details for ${chalk.bold(contextName)}`
|
|
||||||
)}`,
|
|
||||||
|
|
||||||
name: {
|
|
||||||
label: 'Full Name'.padEnd(12),
|
|
||||||
placeholder: 'John Appleseed',
|
|
||||||
validateValue: data => data.trim().length > 0,
|
|
||||||
},
|
|
||||||
|
|
||||||
cardNumber: {
|
|
||||||
label: 'Number'.padEnd(12),
|
|
||||||
mask: 'cc',
|
|
||||||
placeholder: '#### #### #### ####',
|
|
||||||
validateKeypress: (data, value) => /\d/.test(data) && value.length < 19,
|
|
||||||
validateValue: data => {
|
|
||||||
data = data.replace(/ /g, '');
|
|
||||||
const type = ccValidator.determineCardType(data);
|
|
||||||
if (!type) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return ccValidator.isValidCardNumber(data, type);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
ccv: {
|
|
||||||
label: 'CCV'.padEnd(12),
|
|
||||||
mask: 'ccv',
|
|
||||||
placeholder: '###',
|
|
||||||
validateValue: data => {
|
|
||||||
const brand = state.cardNumber.brand.toLowerCase();
|
|
||||||
return ccValidator.doesCvvMatchType(data, brand);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
expDate: {
|
|
||||||
label: 'Exp. Date'.padEnd(12),
|
|
||||||
mask: 'expDate',
|
|
||||||
placeholder: 'mm / yyyy',
|
|
||||||
middleware: expDateMiddleware,
|
|
||||||
validateValue: data => !ccValidator.isExpired(...data.split(' / ')),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
async function render() {
|
|
||||||
for (const key in state) {
|
|
||||||
if (!Object.hasOwnProperty.call(state, key)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const piece = state[key];
|
|
||||||
|
|
||||||
if (typeof piece === 'string') {
|
|
||||||
console.log(piece);
|
|
||||||
} else if (typeof piece === 'object') {
|
|
||||||
let result;
|
|
||||||
|
|
||||||
try {
|
|
||||||
/* eslint-disable no-await-in-loop */
|
|
||||||
result = await textInput({
|
|
||||||
label: `- ${piece.label}`,
|
|
||||||
initialValue: piece.initialValue || piece.value,
|
|
||||||
placeholder: piece.placeholder,
|
|
||||||
mask: piece.mask,
|
|
||||||
validateKeypress: piece.validateKeypress,
|
|
||||||
validateValue: piece.validateValue,
|
|
||||||
autoComplete: piece.autoComplete,
|
|
||||||
});
|
|
||||||
|
|
||||||
piece.value = result;
|
|
||||||
|
|
||||||
if (key === 'cardNumber') {
|
|
||||||
let brand = cardBrands[ccValidator.determineCardType(result)];
|
|
||||||
piece.brand = brand;
|
|
||||||
|
|
||||||
if (brand === 'American Express') {
|
|
||||||
state.ccv.placeholder = '#'.repeat(4);
|
|
||||||
} else {
|
|
||||||
state.ccv.placeholder = '#'.repeat(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
brand = chalk.cyan(`[${brand}]`);
|
|
||||||
const masked = chalk.gray('#### '.repeat(3)) + result.split(' ')[3];
|
|
||||||
process.stdout.write(
|
|
||||||
`${chalk.cyan(chars.tick)} ${piece.label}${masked} ${brand}\n`
|
|
||||||
);
|
|
||||||
} else if (key === 'ccv') {
|
|
||||||
process.stdout.write(
|
|
||||||
`${chalk.cyan(chars.tick)} ${piece.label}${'*'.repeat(
|
|
||||||
result.length
|
|
||||||
)}\n`
|
|
||||||
);
|
|
||||||
} else if (key === 'expDate') {
|
|
||||||
let text = result.split(' / ');
|
|
||||||
text = text[0] + chalk.gray(' / ') + text[1];
|
|
||||||
process.stdout.write(
|
|
||||||
`${chalk.cyan(chars.tick)} ${piece.label}${text}\n`
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
process.stdout.write(
|
|
||||||
`${chalk.cyan(chars.tick)} ${piece.label}${result}\n`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
if (err.message === 'USER_ABORT') {
|
|
||||||
process.exit(1);
|
|
||||||
} else {
|
|
||||||
console.error(error(err));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(''); // New line
|
|
||||||
const stopSpinner = wait(process.stderr, 'Saving card');
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await creditCards.add({
|
|
||||||
name: state.name.value,
|
|
||||||
cardNumber: state.cardNumber.value,
|
|
||||||
ccv: state.ccv.value,
|
|
||||||
expDate: state.expDate.value,
|
|
||||||
});
|
|
||||||
|
|
||||||
stopSpinner();
|
|
||||||
|
|
||||||
if (clear) {
|
|
||||||
const linesToClear = state.error ? 15 : 14;
|
|
||||||
process.stdout.write(ansiEscapes.eraseLines(linesToClear));
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
success(
|
|
||||||
`${state.cardNumber.brand || state.cardNumber.card.brand} ending in ${
|
|
||||||
res.last4 || res.card.last4
|
|
||||||
} was added to ${chalk.bold(contextName)}`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
stopSpinner();
|
|
||||||
const linesToClear = state.error ? 15 : 14;
|
|
||||||
process.stdout.write(ansiEscapes.eraseLines(linesToClear));
|
|
||||||
state.error = `${chalk.red('> Error!')} ${
|
|
||||||
err.message
|
|
||||||
} Please make sure the info is correct`;
|
|
||||||
await render();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await render();
|
|
||||||
} catch (err) {
|
|
||||||
console.erorr(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,353 +0,0 @@
|
|||||||
import chalk from 'chalk';
|
|
||||||
import ms from 'ms';
|
|
||||||
import plural from 'pluralize';
|
|
||||||
import { error } from '../../util/error';
|
|
||||||
import NowCreditCards from '../../util/credit-cards';
|
|
||||||
import indent from '../../util/output/indent';
|
|
||||||
import listInput from '../../util/input/list';
|
|
||||||
import success from '../../util/output/success';
|
|
||||||
import promptBool from '../../util/input/prompt-bool';
|
|
||||||
import info from '../../util/output/info';
|
|
||||||
import logo from '../../util/output/logo';
|
|
||||||
import addBilling from './add';
|
|
||||||
import exit from '../../util/exit';
|
|
||||||
import getScope from '../../util/get-scope.ts';
|
|
||||||
import { getPkgName } from '../../util/pkg-name.ts';
|
|
||||||
import getArgs from '../../util/get-args.ts';
|
|
||||||
import handleError from '../../util/handle-error.ts';
|
|
||||||
|
|
||||||
const help = () => {
|
|
||||||
console.log(`
|
|
||||||
${chalk.bold(`${logo} ${getPkgName()} billing`)} [options] <command>
|
|
||||||
|
|
||||||
${chalk.dim('Options:')}
|
|
||||||
|
|
||||||
ls Show all of your credit cards
|
|
||||||
add Add a new credit card
|
|
||||||
rm [id] Remove a credit card
|
|
||||||
set-default [id] Make a credit card your default one
|
|
||||||
|
|
||||||
${chalk.dim('Options:')}
|
|
||||||
|
|
||||||
-h, --help Output usage information
|
|
||||||
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
|
|
||||||
'FILE'
|
|
||||||
)} Path to the local ${'`vercel.json`'} file
|
|
||||||
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
|
|
||||||
'DIR'
|
|
||||||
)} Path to the global ${'`.vercel`'} directory
|
|
||||||
-d, --debug Debug mode [off]
|
|
||||||
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
|
|
||||||
'TOKEN'
|
|
||||||
)} Login token
|
|
||||||
-S, --scope Set a custom scope
|
|
||||||
|
|
||||||
${chalk.dim('Examples:')}
|
|
||||||
|
|
||||||
${chalk.gray('–')} Add a new credit card (interactively)
|
|
||||||
|
|
||||||
${chalk.cyan(`$ ${getPkgName()} billing add`)}
|
|
||||||
`);
|
|
||||||
};
|
|
||||||
|
|
||||||
let argv;
|
|
||||||
let subcommand;
|
|
||||||
|
|
||||||
export default async client => {
|
|
||||||
try {
|
|
||||||
argv = getArgs(client.argv.slice(2), {});
|
|
||||||
} catch (error) {
|
|
||||||
handleError(error);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
argv._ = argv._.slice(1);
|
|
||||||
|
|
||||||
subcommand = argv._[0];
|
|
||||||
|
|
||||||
if (argv['--help'] || !subcommand) {
|
|
||||||
help();
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
output,
|
|
||||||
config: { currentTeam },
|
|
||||||
} = client;
|
|
||||||
|
|
||||||
const start = new Date();
|
|
||||||
const creditCards = new NowCreditCards({
|
|
||||||
client,
|
|
||||||
currentTeam,
|
|
||||||
});
|
|
||||||
|
|
||||||
let contextName = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
({ contextName } = await getScope(client));
|
|
||||||
} catch (err) {
|
|
||||||
if (err.code === 'NOT_AUTHORIZED' || err.code === 'TEAM_DELETED') {
|
|
||||||
output.error(err.message);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
|
|
||||||
const args = argv._.slice(1);
|
|
||||||
|
|
||||||
switch (subcommand) {
|
|
||||||
case 'ls':
|
|
||||||
case 'list': {
|
|
||||||
let cards;
|
|
||||||
|
|
||||||
try {
|
|
||||||
cards = await creditCards.ls();
|
|
||||||
} catch (err) {
|
|
||||||
console.error(error(err.message));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const text = cards.sources
|
|
||||||
.map(source => {
|
|
||||||
const _default =
|
|
||||||
source.id === cards.defaultSource
|
|
||||||
? ` ${chalk.bold('(default)')}`
|
|
||||||
: '';
|
|
||||||
const id = `${chalk.gray('-')} ${chalk.cyan(
|
|
||||||
`ID: ${source.id}`
|
|
||||||
)}${_default}`;
|
|
||||||
const number = `${chalk.gray('#### ').repeat(3)}${
|
|
||||||
source.last4 || source.card.last4
|
|
||||||
}`;
|
|
||||||
|
|
||||||
return [
|
|
||||||
id,
|
|
||||||
indent(source.name || source.owner.name, 2),
|
|
||||||
indent(`${source.brand || source.card.brand} ${number}`, 2),
|
|
||||||
].join('\n');
|
|
||||||
})
|
|
||||||
.join('\n\n');
|
|
||||||
|
|
||||||
const elapsed = ms(new Date() - start);
|
|
||||||
console.log(
|
|
||||||
`> ${plural(
|
|
||||||
'card',
|
|
||||||
cards.sources.length,
|
|
||||||
true
|
|
||||||
)} found under ${chalk.bold(contextName)} ${chalk.gray(`[${elapsed}]`)}`
|
|
||||||
);
|
|
||||||
if (text) {
|
|
||||||
console.log(`\n${text}\n`);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'set-default': {
|
|
||||||
if (args.length > 1) {
|
|
||||||
console.error(error('Invalid number of arguments'));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const start = new Date();
|
|
||||||
|
|
||||||
let cards;
|
|
||||||
try {
|
|
||||||
cards = await creditCards.ls();
|
|
||||||
} catch (err) {
|
|
||||||
console.error(error(err.message));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cards.sources.length === 0) {
|
|
||||||
console.error(error('You have no credit cards to choose from'));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let cardId = args[0];
|
|
||||||
|
|
||||||
if (cardId === undefined) {
|
|
||||||
const elapsed = ms(new Date() - start);
|
|
||||||
const message = `Selecting a new default payment card for ${chalk.bold(
|
|
||||||
contextName
|
|
||||||
)} ${chalk.gray(`[${elapsed}]`)}`;
|
|
||||||
const choices = buildInquirerChoices(cards);
|
|
||||||
|
|
||||||
cardId = await listInput(client, {
|
|
||||||
message,
|
|
||||||
choices,
|
|
||||||
separator: true,
|
|
||||||
abort: 'end',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the provided cardId (in case the user
|
|
||||||
// typed `vercel billing set-default <some-id>`) is valid
|
|
||||||
if (cardId) {
|
|
||||||
const label = `Are you sure that you to set this card as the default?`;
|
|
||||||
const confirmation = await promptBool(label, {
|
|
||||||
...client,
|
|
||||||
trailing: '\n',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!confirmation) {
|
|
||||||
console.log(info('Aborted'));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const start = new Date();
|
|
||||||
await creditCards.setDefault(cardId);
|
|
||||||
|
|
||||||
const card = cards.sources.find(card => card.id === cardId);
|
|
||||||
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}]`)}`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
console.log('No changes made');
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'rm':
|
|
||||||
case 'remove': {
|
|
||||||
if (args.length > 1) {
|
|
||||||
console.error(error('Invalid number of arguments'));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const start = new Date();
|
|
||||||
let cards;
|
|
||||||
try {
|
|
||||||
cards = await creditCards.ls();
|
|
||||||
} catch (err) {
|
|
||||||
console.error(error(err.message));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cards.sources.length === 0) {
|
|
||||||
console.error(
|
|
||||||
error(
|
|
||||||
`You have no credit cards to choose from to delete under ${chalk.bold(
|
|
||||||
contextName
|
|
||||||
)}`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let cardId = args[0];
|
|
||||||
|
|
||||||
if (cardId === undefined) {
|
|
||||||
const elapsed = ms(new Date() - start);
|
|
||||||
const message = `Selecting a card to ${chalk.underline(
|
|
||||||
'remove'
|
|
||||||
)} under ${chalk.bold(contextName)} ${chalk.gray(`[${elapsed}]`)}`;
|
|
||||||
const choices = buildInquirerChoices(cards);
|
|
||||||
|
|
||||||
cardId = await listInput(client, {
|
|
||||||
message,
|
|
||||||
choices,
|
|
||||||
separator: true,
|
|
||||||
abort: 'start',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shoud check if the provided cardId (in case the user
|
|
||||||
// typed `vercel billing rm <some-id>`) is valid
|
|
||||||
if (cardId) {
|
|
||||||
const label = `Are you sure that you want to remove this card?`;
|
|
||||||
const confirmation = await promptBool(label, client);
|
|
||||||
if (!confirmation) {
|
|
||||||
console.log('Aborted');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const start = new Date();
|
|
||||||
await creditCards.rm(cardId);
|
|
||||||
|
|
||||||
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`;
|
|
||||||
// ${chalk.gray(`[${elapsed}]`)}
|
|
||||||
|
|
||||||
if (cardId === cards.defaultSource) {
|
|
||||||
if (remainingCards.length === 0) {
|
|
||||||
// The user deleted the last card in their account
|
|
||||||
text += `\n${chalk.yellow('Warning!')} You have no default card`;
|
|
||||||
} else {
|
|
||||||
// We can't guess the current default card – let's ask the API
|
|
||||||
const cards = await creditCards.ls();
|
|
||||||
const newDefaultCard = cards.sources.find(
|
|
||||||
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)}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const elapsed = ms(new Date() - start);
|
|
||||||
text += ` ${chalk.gray(`[${elapsed}]`)}`;
|
|
||||||
console.log(success(text));
|
|
||||||
} else {
|
|
||||||
console.log('No changes made');
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'add': {
|
|
||||||
await addBilling({
|
|
||||||
creditCards,
|
|
||||||
contextName,
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
console.error(
|
|
||||||
error('Please specify a valid subcommand: ls | add | rm | set-default')
|
|
||||||
);
|
|
||||||
help();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is required, otherwise we get those weird zlib errors
|
|
||||||
return exit(0);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Builds a `choices` object that can be passesd to inquirer.prompt()
|
|
||||||
function buildInquirerChoices(cards) {
|
|
||||||
return cards.sources.map(source => {
|
|
||||||
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 str = [
|
|
||||||
id,
|
|
||||||
indent(source.name || source.owner.name, 2),
|
|
||||||
indent(`${source.brand || source.card.brand} ${number}`, 2),
|
|
||||||
].join('\n');
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: str, // Will be displayed by Inquirer
|
|
||||||
value: source.id, // Will be used to identify the answer
|
|
||||||
short: source.id, // Will be displayed after the users answers
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -91,7 +91,7 @@ const help = () => {
|
|||||||
--output [path] Directory where built assets should be written to
|
--output [path] Directory where built assets should be written to
|
||||||
--prod Build a production deployment
|
--prod Build a production deployment
|
||||||
-d, --debug Debug mode [off]
|
-d, --debug Debug mode [off]
|
||||||
-y, --yes Skip the confirmation prompt
|
-y, --yes Skip the confirmation prompt about pulling environment variables and project settings when not found locally
|
||||||
|
|
||||||
${chalk.dim('Examples:')}
|
${chalk.dim('Examples:')}
|
||||||
|
|
||||||
@@ -157,7 +157,7 @@ export default async function main(client: Client): Promise<number> {
|
|||||||
client.output.print(
|
client.output.print(
|
||||||
`No Project Settings found locally. Run ${cli.getCommandName(
|
`No Project Settings found locally. Run ${cli.getCommandName(
|
||||||
'pull --yes'
|
'pull --yes'
|
||||||
)} to retreive them.`
|
)} to retrieve them.`
|
||||||
);
|
);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ export const help = () => `
|
|||||||
|
|
||||||
${chalk.dim('Basic')}
|
${chalk.dim('Basic')}
|
||||||
|
|
||||||
billing Manages the account payment methods
|
|
||||||
deploy [path] Performs a deployment ${chalk.bold(
|
deploy [path] Performs a deployment ${chalk.bold(
|
||||||
'(default)'
|
'(default)'
|
||||||
)}
|
)}
|
||||||
@@ -73,7 +72,7 @@ export const help = () => `
|
|||||||
-S, --scope Set a custom scope
|
-S, --scope Set a custom scope
|
||||||
--regions Set default regions to enable the deployment on
|
--regions Set default regions to enable the deployment on
|
||||||
--prod Create a production deployment
|
--prod Create a production deployment
|
||||||
-c, --confirm Confirm default options and skip questions
|
-y, --yes Skip questions when setting up new project using default scope and settings
|
||||||
|
|
||||||
${chalk.dim('Examples:')}
|
${chalk.dim('Examples:')}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,11 @@ import fs from 'fs-extra';
|
|||||||
import bytes from 'bytes';
|
import bytes from 'bytes';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import { join, resolve, basename } from 'path';
|
import { join, resolve, basename } from 'path';
|
||||||
import { fileNameSymbol, VercelConfig } from '@vercel/client';
|
import {
|
||||||
|
fileNameSymbol,
|
||||||
|
VALID_ARCHIVE_FORMATS,
|
||||||
|
VercelConfig,
|
||||||
|
} from '@vercel/client';
|
||||||
import code from '../../util/output/code';
|
import code from '../../util/output/code';
|
||||||
import highlight from '../../util/output/highlight';
|
import highlight from '../../util/output/highlight';
|
||||||
import { readLocalConfig } from '../../util/config/files';
|
import { readLocalConfig } from '../../util/config/files';
|
||||||
@@ -66,10 +70,11 @@ import { getDeploymentChecks } from '../../util/deploy/get-deployment-checks';
|
|||||||
import parseTarget from '../../util/deploy/parse-target';
|
import parseTarget from '../../util/deploy/parse-target';
|
||||||
import getPrebuiltJson from '../../util/deploy/get-prebuilt-json';
|
import getPrebuiltJson from '../../util/deploy/get-prebuilt-json';
|
||||||
import { createGitMeta } from '../../util/create-git-meta';
|
import { createGitMeta } from '../../util/create-git-meta';
|
||||||
|
import { isValidArchive } from '../../util/deploy/validate-archive-format';
|
||||||
import { parseEnv } from '../../util/parse-env';
|
import { parseEnv } from '../../util/parse-env';
|
||||||
import { errorToString, isErrnoException, isError } from '../../util/is-error';
|
import { errorToString, isErrnoException, isError } from '../../util/is-error';
|
||||||
|
|
||||||
export default async (client: Client) => {
|
export default async (client: Client): Promise<number> => {
|
||||||
const { output } = client;
|
const { output } = client;
|
||||||
|
|
||||||
let argv = null;
|
let argv = null;
|
||||||
@@ -87,20 +92,28 @@ export default async (client: Client) => {
|
|||||||
'--regions': String,
|
'--regions': String,
|
||||||
'--prebuilt': Boolean,
|
'--prebuilt': Boolean,
|
||||||
'--prod': Boolean,
|
'--prod': Boolean,
|
||||||
'--confirm': Boolean,
|
'--archive': String,
|
||||||
|
'--yes': Boolean,
|
||||||
'-f': '--force',
|
'-f': '--force',
|
||||||
'-p': '--public',
|
'-p': '--public',
|
||||||
'-e': '--env',
|
'-e': '--env',
|
||||||
'-b': '--build-env',
|
'-b': '--build-env',
|
||||||
'-m': '--meta',
|
'-m': '--meta',
|
||||||
'-c': '--confirm',
|
'-y': '--yes',
|
||||||
|
|
||||||
// deprecated
|
// deprecated
|
||||||
'--name': String,
|
'--name': String,
|
||||||
'-n': '--name',
|
'-n': '--name',
|
||||||
'--no-clipboard': Boolean,
|
'--no-clipboard': Boolean,
|
||||||
'--target': String,
|
'--target': String,
|
||||||
|
'--confirm': Boolean,
|
||||||
|
'-c': '--confirm',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if ('--confirm' in argv) {
|
||||||
|
output.warn('`--confirm` is deprecated, please use `--yes` instead');
|
||||||
|
argv['--yes'] = argv['--confirm'];
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error);
|
handleError(error);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -173,7 +186,7 @@ export default async (client: Client) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { path } = pathValidation;
|
const { path } = pathValidation;
|
||||||
const autoConfirm = argv['--confirm'];
|
const autoConfirm = argv['--yes'];
|
||||||
|
|
||||||
// deprecate --name
|
// deprecate --name
|
||||||
if (argv['--name']) {
|
if (argv['--name']) {
|
||||||
@@ -254,6 +267,12 @@ export default async (client: Client) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const archive = argv['--archive'];
|
||||||
|
if (typeof archive === 'string' && !isValidArchive(archive)) {
|
||||||
|
output.error(`Format must be one of: ${VALID_ARCHIVE_FORMATS.join(', ')}`);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// retrieve `project` and `org` from .vercel
|
// retrieve `project` and `org` from .vercel
|
||||||
const link = await getLinkedProject(client, path);
|
const link = await getLinkedProject(client, path);
|
||||||
|
|
||||||
@@ -538,7 +557,8 @@ export default async (client: Client) => {
|
|||||||
createArgs,
|
createArgs,
|
||||||
org,
|
org,
|
||||||
!project,
|
!project,
|
||||||
path
|
path,
|
||||||
|
archive
|
||||||
);
|
);
|
||||||
|
|
||||||
if (deployment.code === 'missing_project_settings') {
|
if (deployment.code === 'missing_project_settings') {
|
||||||
@@ -911,4 +931,6 @@ const printDeploymentStatus = async (
|
|||||||
) + newline;
|
) + newline;
|
||||||
output.print(message + link);
|
output.print(message + link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { OUTPUT_DIR } from '../../util/build/write-build-result';
|
|||||||
|
|
||||||
type Options = {
|
type Options = {
|
||||||
'--listen': string;
|
'--listen': string;
|
||||||
'--confirm': boolean;
|
'--yes': boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function dev(
|
export default async function dev(
|
||||||
@@ -38,7 +38,7 @@ export default async function dev(
|
|||||||
|
|
||||||
if (link.status === 'not_linked' && !process.env.__VERCEL_SKIP_DEV_CMD) {
|
if (link.status === 'not_linked' && !process.env.__VERCEL_SKIP_DEV_CMD) {
|
||||||
link = await setupAndLink(client, cwd, {
|
link = await setupAndLink(client, cwd, {
|
||||||
autoConfirm: opts['--confirm'],
|
autoConfirm: opts['--yes'],
|
||||||
successEmoji: 'link',
|
successEmoji: 'link',
|
||||||
setupMsg: 'Set up and develop',
|
setupMsg: 'Set up and develop',
|
||||||
});
|
});
|
||||||
@@ -54,14 +54,13 @@ export default async function dev(
|
|||||||
client.output.error(
|
client.output.error(
|
||||||
`Command ${getCommandName(
|
`Command ${getCommandName(
|
||||||
'dev'
|
'dev'
|
||||||
)} requires confirmation. Use option ${param('--confirm')} to confirm.`
|
)} requires confirmation. Use option ${param('--yes')} to confirm.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return link.exitCode;
|
return link.exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
let devCommand: string | undefined;
|
let devCommand: string | undefined;
|
||||||
let frameworkSlug: string | undefined;
|
|
||||||
let projectSettings: ProjectSettings | undefined;
|
let projectSettings: ProjectSettings | undefined;
|
||||||
let projectEnvs: ProjectEnvVariable[] = [];
|
let projectEnvs: ProjectEnvVariable[] = [];
|
||||||
let systemEnvValues: string[] = [];
|
let systemEnvValues: string[] = [];
|
||||||
@@ -77,10 +76,6 @@ export default async function dev(
|
|||||||
const framework = frameworks.find(f => f.slug === project.framework);
|
const framework = frameworks.find(f => f.slug === project.framework);
|
||||||
|
|
||||||
if (framework) {
|
if (framework) {
|
||||||
if (framework.slug) {
|
|
||||||
frameworkSlug = framework.slug;
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaults = framework.settings.devCommand.value;
|
const defaults = framework.settings.devCommand.value;
|
||||||
if (defaults) {
|
if (defaults) {
|
||||||
devCommand = defaults;
|
devCommand = defaults;
|
||||||
@@ -120,7 +115,6 @@ export default async function dev(
|
|||||||
const devServer = new DevServer(cwd, {
|
const devServer = new DevServer(cwd, {
|
||||||
output,
|
output,
|
||||||
devCommand,
|
devCommand,
|
||||||
frameworkSlug,
|
|
||||||
projectSettings,
|
projectSettings,
|
||||||
projectEnvs,
|
projectEnvs,
|
||||||
systemEnvValues,
|
systemEnvValues,
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const help = () => {
|
|||||||
-d, --debug Debug mode [off]
|
-d, --debug Debug mode [off]
|
||||||
-l, --listen [uri] Specify a URI endpoint on which to listen [0.0.0.0:3000]
|
-l, --listen [uri] Specify a URI endpoint on which to listen [0.0.0.0:3000]
|
||||||
-t, --token [token] Specify an Authorization Token
|
-t, --token [token] Specify an Authorization Token
|
||||||
--confirm Skip questions and use defaults when setting up a new project
|
-y, --yes Skip questions when setting up new project using default scope and settings
|
||||||
|
|
||||||
${chalk.dim('Examples:')}
|
${chalk.dim('Examples:')}
|
||||||
|
|
||||||
@@ -74,14 +74,22 @@ export default async function main(client: Client) {
|
|||||||
argv = getArgs(client.argv.slice(2), {
|
argv = getArgs(client.argv.slice(2), {
|
||||||
'--listen': String,
|
'--listen': String,
|
||||||
'-l': '--listen',
|
'-l': '--listen',
|
||||||
'--confirm': Boolean,
|
'--yes': Boolean,
|
||||||
|
'-y': '--yes',
|
||||||
|
|
||||||
// Deprecated
|
// Deprecated
|
||||||
'--port': Number,
|
'--port': Number,
|
||||||
'-p': '--port',
|
'-p': '--port',
|
||||||
|
'--confirm': Boolean,
|
||||||
|
'-c': '--confirm',
|
||||||
});
|
});
|
||||||
args = getSubcommand(argv._.slice(1), COMMAND_CONFIG).args;
|
args = getSubcommand(argv._.slice(1), COMMAND_CONFIG).args;
|
||||||
|
|
||||||
|
if ('--confirm' in argv) {
|
||||||
|
output.warn('`--confirm` is deprecated, please use `--yes` instead');
|
||||||
|
argv['--yes'] = argv['--confirm'];
|
||||||
|
}
|
||||||
|
|
||||||
if ('--port' in argv) {
|
if ('--port' in argv) {
|
||||||
output.warn('`--port` is deprecated, please use `--listen` instead');
|
output.warn('`--port` is deprecated, please use `--listen` instead');
|
||||||
argv['--listen'] = String(argv['--port']);
|
argv['--listen'] = String(argv['--port']);
|
||||||
|
|||||||
@@ -116,9 +116,7 @@ export default async function buy(
|
|||||||
|
|
||||||
if (buyResult instanceof ERRORS.SourceNotFound) {
|
if (buyResult instanceof ERRORS.SourceNotFound) {
|
||||||
output.error(
|
output.error(
|
||||||
`Could not purchase domain. Please add a payment method using ${getCommandName(
|
`Could not purchase domain. Please add a payment method using the dashboard.`
|
||||||
`billing add`
|
|
||||||
)}.`
|
|
||||||
);
|
);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ const help = () => {
|
|||||||
)} Login token
|
)} Login token
|
||||||
-S, --scope Set a custom scope
|
-S, --scope Set a custom scope
|
||||||
-N, --next Show next page of results
|
-N, --next Show next page of results
|
||||||
|
-y, --yes Skip the confirmation prompt when removing a domain
|
||||||
|
|
||||||
${chalk.dim('Examples:')}
|
${chalk.dim('Examples:')}
|
||||||
|
|
||||||
@@ -92,6 +93,7 @@ export default async function main(client: Client) {
|
|||||||
'--force': Boolean,
|
'--force': Boolean,
|
||||||
'--next': Number,
|
'--next': Number,
|
||||||
'-N': '--next',
|
'-N': '--next',
|
||||||
|
'-y': '--yes',
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error);
|
handleError(error);
|
||||||
|
|||||||
@@ -111,9 +111,7 @@ export default async function transferIn(
|
|||||||
|
|
||||||
if (transferInResult instanceof ERRORS.SourceNotFound) {
|
if (transferInResult instanceof ERRORS.SourceNotFound) {
|
||||||
output.error(
|
output.error(
|
||||||
`Could not purchase domain. Please add a payment method using ${getCommandName(
|
`Could not purchase domain. Please add a payment method using the dashboard.`
|
||||||
`billing add`
|
|
||||||
)}.`
|
|
||||||
);
|
);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
1
packages/cli/src/commands/env/index.ts
vendored
1
packages/cli/src/commands/env/index.ts
vendored
@@ -42,6 +42,7 @@ const help = () => {
|
|||||||
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
|
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
|
||||||
'TOKEN'
|
'TOKEN'
|
||||||
)} Login token
|
)} Login token
|
||||||
|
-y, --yes Skip the confirmation prompt when overwriting env file on pull or removing an env variable
|
||||||
|
|
||||||
${chalk.dim('Examples:')}
|
${chalk.dim('Examples:')}
|
||||||
|
|
||||||
|
|||||||
7
packages/cli/src/commands/env/pull.ts
vendored
7
packages/cli/src/commands/env/pull.ts
vendored
@@ -117,7 +117,12 @@ export default async function pull(
|
|||||||
if (exists) {
|
if (exists) {
|
||||||
oldEnv = await createEnvObject(fullPath, output);
|
oldEnv = await createEnvObject(fullPath, output);
|
||||||
if (oldEnv) {
|
if (oldEnv) {
|
||||||
deltaString = buildDeltaString(oldEnv, records);
|
// Removes any double quotes from `records`, if they exist
|
||||||
|
// We need this because double quotes are stripped from the local .env file,
|
||||||
|
// but `records` is already in the form of a JSON object that doesn't filter
|
||||||
|
// double quotes.
|
||||||
|
const newEnv = JSON.parse(JSON.stringify(records).replace(/\\"/g, ''));
|
||||||
|
deltaString = buildDeltaString(oldEnv, newEnv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
5
packages/cli/src/commands/env/rm.ts
vendored
5
packages/cli/src/commands/env/rm.ts
vendored
@@ -1,5 +1,4 @@
|
|||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import inquirer from 'inquirer';
|
|
||||||
import { Project } from '../../types';
|
import { Project } from '../../types';
|
||||||
import { Output } from '../../util/output';
|
import { Output } from '../../util/output';
|
||||||
import confirm from '../../util/input/confirm';
|
import confirm from '../../util/input/confirm';
|
||||||
@@ -45,7 +44,7 @@ export default async function rm(
|
|||||||
let [envName, envTarget, envGitBranch] = args;
|
let [envName, envTarget, envGitBranch] = args;
|
||||||
|
|
||||||
while (!envName) {
|
while (!envName) {
|
||||||
const { inputName } = await inquirer.prompt({
|
const { inputName } = await client.prompt({
|
||||||
type: 'input',
|
type: 'input',
|
||||||
name: 'inputName',
|
name: 'inputName',
|
||||||
message: `What’s the name of the variable?`,
|
message: `What’s the name of the variable?`,
|
||||||
@@ -87,7 +86,7 @@ export default async function rm(
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (envs.length > 1) {
|
while (envs.length > 1) {
|
||||||
const { id } = await inquirer.prompt({
|
const { id } = await client.prompt({
|
||||||
name: 'id',
|
name: 'id',
|
||||||
type: 'list',
|
type: 'list',
|
||||||
message: `Remove ${envName} from which Environments?`,
|
message: `Remove ${envName} from which Environments?`,
|
||||||
|
|||||||
@@ -1,21 +1,54 @@
|
|||||||
|
import { Dictionary } from '@vercel/client';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { Org, Project } from '../../types';
|
import { Org, Project, ProjectLinkData } from '../../types';
|
||||||
import Client from '../../util/client';
|
import Client from '../../util/client';
|
||||||
import { parseGitConfig, pluckRemoteUrls } from '../../util/create-git-meta';
|
import { parseGitConfig, pluckRemoteUrls } from '../../util/create-git-meta';
|
||||||
import confirm from '../../util/input/confirm';
|
import confirm from '../../util/input/confirm';
|
||||||
import list, { ListChoice } from '../../util/input/list';
|
import list, { ListChoice } from '../../util/input/list';
|
||||||
import { Output } from '../../util/output';
|
|
||||||
import link from '../../util/output/link';
|
import link from '../../util/output/link';
|
||||||
import { getCommandName } from '../../util/pkg-name';
|
import { getCommandName } from '../../util/pkg-name';
|
||||||
import {
|
import {
|
||||||
connectGitProvider,
|
connectGitProvider,
|
||||||
disconnectGitProvider,
|
disconnectGitProvider,
|
||||||
formatProvider,
|
formatProvider,
|
||||||
|
RepoInfo,
|
||||||
parseRepoUrl,
|
parseRepoUrl,
|
||||||
} from '../../util/projects/connect-git-provider';
|
printRemoteUrls,
|
||||||
|
} from '../../util/git/connect-git-provider';
|
||||||
import validatePaths from '../../util/validate-paths';
|
import validatePaths from '../../util/validate-paths';
|
||||||
|
|
||||||
|
interface GitRepoCheckParams {
|
||||||
|
client: Client;
|
||||||
|
confirm: boolean;
|
||||||
|
gitProviderLink?: ProjectLinkData;
|
||||||
|
org: Org;
|
||||||
|
gitOrg: string;
|
||||||
|
project: Project;
|
||||||
|
provider: string;
|
||||||
|
repo: string;
|
||||||
|
repoPath: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ConnectArgParams {
|
||||||
|
client: Client;
|
||||||
|
org: Org;
|
||||||
|
project: Project;
|
||||||
|
confirm: boolean;
|
||||||
|
repoInfo: RepoInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ConnectGitArgParams extends ConnectArgParams {
|
||||||
|
gitConfig: Dictionary<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PromptConnectArgParams {
|
||||||
|
client: Client;
|
||||||
|
yes: boolean;
|
||||||
|
repoInfo: RepoInfo;
|
||||||
|
remoteUrls: Dictionary<string>;
|
||||||
|
}
|
||||||
|
|
||||||
export default async function connect(
|
export default async function connect(
|
||||||
client: Client,
|
client: Client,
|
||||||
argv: any,
|
argv: any,
|
||||||
@@ -24,9 +57,10 @@ export default async function connect(
|
|||||||
org: Org | undefined
|
org: Org | undefined
|
||||||
) {
|
) {
|
||||||
const { output } = client;
|
const { output } = client;
|
||||||
const confirm = Boolean(argv['--confirm']);
|
const confirm = Boolean(argv['--yes']);
|
||||||
|
const repoArg = argv._[1];
|
||||||
|
|
||||||
if (args.length !== 0) {
|
if (args.length > 1) {
|
||||||
output.error(
|
output.error(
|
||||||
`Invalid number of arguments. Usage: ${chalk.cyan(
|
`Invalid number of arguments. Usage: ${chalk.cyan(
|
||||||
`${getCommandName('project connect')}`
|
`${getCommandName('project connect')}`
|
||||||
@@ -36,7 +70,7 @@ export default async function connect(
|
|||||||
}
|
}
|
||||||
if (!project || !org) {
|
if (!project || !org) {
|
||||||
output.error(
|
output.error(
|
||||||
`Can't find \`org\` or \`project\`. Make sure your current directory is linked to a Vercel projet by running ${getCommandName(
|
`Can't find \`org\` or \`project\`. Make sure your current directory is linked to a Vercel project by running ${getCommandName(
|
||||||
'link'
|
'link'
|
||||||
)}.`
|
)}.`
|
||||||
);
|
);
|
||||||
@@ -57,9 +91,38 @@ export default async function connect(
|
|||||||
// get project from .git
|
// get project from .git
|
||||||
const gitConfigPath = join(path, '.git/config');
|
const gitConfigPath = join(path, '.git/config');
|
||||||
const gitConfig = await parseGitConfig(gitConfigPath, output);
|
const gitConfig = await parseGitConfig(gitConfigPath, output);
|
||||||
|
|
||||||
|
if (repoArg) {
|
||||||
|
// parse repo arg
|
||||||
|
const parsedUrlArg = parseRepoUrl(repoArg);
|
||||||
|
if (!parsedUrlArg) {
|
||||||
|
output.error(
|
||||||
|
`Failed to parse URL "${repoArg}". Please ensure the URL is valid.`
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (gitConfig) {
|
||||||
|
return await connectArgWithLocalGit({
|
||||||
|
client,
|
||||||
|
org,
|
||||||
|
project,
|
||||||
|
confirm,
|
||||||
|
gitConfig,
|
||||||
|
repoInfo: parsedUrlArg,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return await connectArg({
|
||||||
|
client,
|
||||||
|
confirm,
|
||||||
|
org,
|
||||||
|
project,
|
||||||
|
repoInfo: repoArg,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!gitConfig) {
|
if (!gitConfig) {
|
||||||
output.error(
|
output.error(
|
||||||
`No local git repo found. Run ${chalk.cyan(
|
`No local Git repository found. Run ${chalk.cyan(
|
||||||
'`git clone <url>`'
|
'`git clone <url>`'
|
||||||
)} to clone a remote Git repository first.`
|
)} to clone a remote Git repository first.`
|
||||||
);
|
);
|
||||||
@@ -78,7 +141,7 @@ export default async function connect(
|
|||||||
let remoteUrl: string;
|
let remoteUrl: string;
|
||||||
|
|
||||||
if (Object.keys(remoteUrls).length > 1) {
|
if (Object.keys(remoteUrls).length > 1) {
|
||||||
output.log(`Found multiple remote URLs.`);
|
output.log('Found multiple remote URLs.');
|
||||||
remoteUrl = await selectRemoteUrl(client, remoteUrls);
|
remoteUrl = await selectRemoteUrl(client, remoteUrls);
|
||||||
} else {
|
} else {
|
||||||
// If only one is found, get it — usually "origin"
|
// If only one is found, get it — usually "origin"
|
||||||
@@ -92,8 +155,8 @@ export default async function connect(
|
|||||||
|
|
||||||
output.log(`Connecting Git remote: ${link(remoteUrl)}`);
|
output.log(`Connecting Git remote: ${link(remoteUrl)}`);
|
||||||
|
|
||||||
const parsedUrl = parseRepoUrl(remoteUrl);
|
const repoInfo = parseRepoUrl(remoteUrl);
|
||||||
if (!parsedUrl) {
|
if (!repoInfo) {
|
||||||
output.error(
|
output.error(
|
||||||
`Failed to parse Git repo data from the following remote URL: ${link(
|
`Failed to parse Git repo data from the following remote URL: ${link(
|
||||||
remoteUrl
|
remoteUrl
|
||||||
@@ -101,10 +164,176 @@ export default async function connect(
|
|||||||
);
|
);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
const { provider, org: gitOrg, repo } = parsedUrl;
|
const { provider, org: gitOrg, repo } = repoInfo;
|
||||||
const repoPath = `${gitOrg}/${repo}`;
|
const repoPath = `${gitOrg}/${repo}`;
|
||||||
let connectedRepoPath;
|
|
||||||
|
|
||||||
|
const checkAndConnect = await checkExistsAndConnect({
|
||||||
|
client,
|
||||||
|
confirm,
|
||||||
|
org,
|
||||||
|
project,
|
||||||
|
gitProviderLink,
|
||||||
|
provider,
|
||||||
|
repoPath,
|
||||||
|
gitOrg,
|
||||||
|
repo,
|
||||||
|
});
|
||||||
|
if (typeof checkAndConnect === 'number') {
|
||||||
|
return checkAndConnect;
|
||||||
|
}
|
||||||
|
|
||||||
|
output.log(
|
||||||
|
`Connected ${formatProvider(provider)} repository ${chalk.cyan(repoPath)}!`
|
||||||
|
);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function connectArg({
|
||||||
|
client,
|
||||||
|
confirm,
|
||||||
|
org,
|
||||||
|
project,
|
||||||
|
repoInfo,
|
||||||
|
}: ConnectArgParams) {
|
||||||
|
const { url: repoUrl } = repoInfo;
|
||||||
|
client.output.log(`Connecting Git remote: ${link(repoUrl)}`);
|
||||||
|
const parsedRepoArg = parseRepoUrl(repoUrl);
|
||||||
|
if (!parsedRepoArg) {
|
||||||
|
client.output.error(
|
||||||
|
`Failed to parse URL "${repoUrl}". Please ensure the URL is valid.`
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
const { provider, org: gitOrg, repo } = parsedRepoArg;
|
||||||
|
const repoPath = `${gitOrg}/${repo}`;
|
||||||
|
const connect = await checkExistsAndConnect({
|
||||||
|
client,
|
||||||
|
confirm,
|
||||||
|
org,
|
||||||
|
project,
|
||||||
|
gitProviderLink: project.link,
|
||||||
|
provider,
|
||||||
|
repoPath,
|
||||||
|
gitOrg,
|
||||||
|
repo,
|
||||||
|
});
|
||||||
|
if (typeof connect === 'number') {
|
||||||
|
return connect;
|
||||||
|
}
|
||||||
|
client.output.log(
|
||||||
|
`Connected ${formatProvider(provider)} repository ${chalk.cyan(repoPath)}!`
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function connectArgWithLocalGit({
|
||||||
|
client,
|
||||||
|
org,
|
||||||
|
project,
|
||||||
|
confirm,
|
||||||
|
gitConfig,
|
||||||
|
repoInfo,
|
||||||
|
}: ConnectGitArgParams) {
|
||||||
|
const remoteUrls = pluckRemoteUrls(gitConfig);
|
||||||
|
if (remoteUrls) {
|
||||||
|
const shouldConnect = await promptConnectArg({
|
||||||
|
client,
|
||||||
|
yes: confirm,
|
||||||
|
repoInfo,
|
||||||
|
remoteUrls,
|
||||||
|
});
|
||||||
|
if (!shouldConnect) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (shouldConnect) {
|
||||||
|
const { provider, org: gitOrg, repo, url: repoUrl } = repoInfo;
|
||||||
|
const repoPath = `${gitOrg}/${repo}`;
|
||||||
|
client.output.log(`Connecting Git remote: ${link(repoUrl)}`);
|
||||||
|
const connect = await checkExistsAndConnect({
|
||||||
|
client,
|
||||||
|
confirm,
|
||||||
|
org,
|
||||||
|
project,
|
||||||
|
gitProviderLink: project.link,
|
||||||
|
provider,
|
||||||
|
repoPath,
|
||||||
|
gitOrg,
|
||||||
|
repo,
|
||||||
|
});
|
||||||
|
if (typeof connect === 'number') {
|
||||||
|
return connect;
|
||||||
|
}
|
||||||
|
client.output.log(
|
||||||
|
`Connected ${formatProvider(provider)} repository ${chalk.cyan(
|
||||||
|
repoPath
|
||||||
|
)}!`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return await connectArg({ client, confirm, org, project, repoInfo });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function promptConnectArg({
|
||||||
|
client,
|
||||||
|
yes,
|
||||||
|
repoInfo: repoInfoFromArg,
|
||||||
|
remoteUrls,
|
||||||
|
}: PromptConnectArgParams) {
|
||||||
|
if (Object.keys(remoteUrls).length > 1) {
|
||||||
|
client.output.log(
|
||||||
|
'Found multiple Git repositories in your local Git config:'
|
||||||
|
);
|
||||||
|
printRemoteUrls(client.output, remoteUrls);
|
||||||
|
} else {
|
||||||
|
const url = Object.values(remoteUrls)[0];
|
||||||
|
const repoInfoFromGitConfig = parseRepoUrl(url);
|
||||||
|
if (!repoInfoFromGitConfig) {
|
||||||
|
client.output.error(
|
||||||
|
`Failed to parse URL "${url}". Please ensure the URL is valid.`
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
JSON.stringify(repoInfoFromGitConfig) === JSON.stringify(repoInfoFromArg)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.output.log(
|
||||||
|
`Found a repository in your local Git Config: ${chalk.cyan(
|
||||||
|
Object.values(remoteUrls)[0]
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let shouldConnect = yes;
|
||||||
|
if (!shouldConnect) {
|
||||||
|
const { url: repoUrlFromArg } = repoInfoFromArg;
|
||||||
|
shouldConnect = await confirm(
|
||||||
|
client,
|
||||||
|
`Do you still want to connect ${link(repoUrlFromArg)}?`,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
if (!shouldConnect) {
|
||||||
|
client.output.log('Aborted. Repo not connected.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return shouldConnect;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkExistsAndConnect({
|
||||||
|
client,
|
||||||
|
confirm,
|
||||||
|
org,
|
||||||
|
project,
|
||||||
|
gitProviderLink,
|
||||||
|
provider,
|
||||||
|
repoPath,
|
||||||
|
gitOrg,
|
||||||
|
repo,
|
||||||
|
}: GitRepoCheckParams) {
|
||||||
if (!gitProviderLink) {
|
if (!gitProviderLink) {
|
||||||
const connect = await connectGitProvider(
|
const connect = await connectGitProvider(
|
||||||
client,
|
client,
|
||||||
@@ -120,14 +349,14 @@ export default async function connect(
|
|||||||
const connectedProvider = gitProviderLink.type;
|
const connectedProvider = gitProviderLink.type;
|
||||||
const connectedOrg = gitProviderLink.org;
|
const connectedOrg = gitProviderLink.org;
|
||||||
const connectedRepo = gitProviderLink.repo;
|
const connectedRepo = gitProviderLink.repo;
|
||||||
connectedRepoPath = `${connectedOrg}/${connectedRepo}`;
|
const connectedRepoPath = `${connectedOrg}/${connectedRepo}`;
|
||||||
|
|
||||||
const isSameRepo =
|
const isSameRepo =
|
||||||
connectedProvider === provider &&
|
connectedProvider === provider &&
|
||||||
connectedOrg === gitOrg &&
|
connectedOrg === gitOrg &&
|
||||||
connectedRepo === repo;
|
connectedRepo === repo;
|
||||||
if (isSameRepo) {
|
if (isSameRepo) {
|
||||||
output.log(
|
client.output.log(
|
||||||
`${chalk.cyan(connectedRepoPath)} is already connected to your project.`
|
`${chalk.cyan(connectedRepoPath)} is already connected to your project.`
|
||||||
);
|
);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -135,8 +364,8 @@ export default async function connect(
|
|||||||
|
|
||||||
const shouldReplaceRepo = await confirmRepoConnect(
|
const shouldReplaceRepo = await confirmRepoConnect(
|
||||||
client,
|
client,
|
||||||
output,
|
|
||||||
confirm,
|
confirm,
|
||||||
|
connectedProvider,
|
||||||
connectedRepoPath
|
connectedRepoPath
|
||||||
);
|
);
|
||||||
if (!shouldReplaceRepo) {
|
if (!shouldReplaceRepo) {
|
||||||
@@ -155,31 +384,27 @@ export default async function connect(
|
|||||||
return connect;
|
return connect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
output.log(
|
|
||||||
`Connected ${formatProvider(provider)} repository ${chalk.cyan(repoPath)}!`
|
|
||||||
);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function confirmRepoConnect(
|
async function confirmRepoConnect(
|
||||||
client: Client,
|
client: Client,
|
||||||
output: Output,
|
|
||||||
yes: boolean,
|
yes: boolean,
|
||||||
|
connectedProvider: string,
|
||||||
connectedRepoPath: string
|
connectedRepoPath: string
|
||||||
) {
|
) {
|
||||||
let shouldReplaceProject = yes;
|
let shouldReplaceProject = yes;
|
||||||
if (!shouldReplaceProject) {
|
if (!shouldReplaceProject) {
|
||||||
shouldReplaceProject = await confirm(
|
shouldReplaceProject = await confirm(
|
||||||
client,
|
client,
|
||||||
`Looks like you already have a repository connected: ${chalk.cyan(
|
`Looks like you already have a ${formatProvider(
|
||||||
|
connectedProvider
|
||||||
|
)} repository connected: ${chalk.cyan(
|
||||||
connectedRepoPath
|
connectedRepoPath
|
||||||
)}. Do you want to replace it?`,
|
)}. Do you want to replace it?`,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
if (!shouldReplaceProject) {
|
if (!shouldReplaceProject) {
|
||||||
output.log(`Aborted. Repo not connected.`);
|
client.output.log('Aborted. Repo not connected.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return shouldReplaceProject;
|
return shouldReplaceProject;
|
||||||
@@ -187,7 +412,7 @@ async function confirmRepoConnect(
|
|||||||
|
|
||||||
async function selectRemoteUrl(
|
async function selectRemoteUrl(
|
||||||
client: Client,
|
client: Client,
|
||||||
remoteUrls: { [key: string]: string }
|
remoteUrls: Dictionary<string>
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
let choices: ListChoice[] = [];
|
let choices: ListChoice[] = [];
|
||||||
for (const [urlKey, urlValue] of Object.entries(remoteUrls)) {
|
for (const [urlKey, urlValue] of Object.entries(remoteUrls)) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Org, Project } from '../../types';
|
|||||||
import Client from '../../util/client';
|
import Client from '../../util/client';
|
||||||
import confirm from '../../util/input/confirm';
|
import confirm from '../../util/input/confirm';
|
||||||
import { getCommandName } from '../../util/pkg-name';
|
import { getCommandName } from '../../util/pkg-name';
|
||||||
import { disconnectGitProvider } from '../../util/projects/connect-git-provider';
|
import { disconnectGitProvider } from '../../util/git/connect-git-provider';
|
||||||
|
|
||||||
export default async function disconnect(
|
export default async function disconnect(
|
||||||
client: Client,
|
client: Client,
|
||||||
|
|||||||
@@ -16,21 +16,30 @@ const help = () => {
|
|||||||
|
|
||||||
${chalk.dim('Commands:')}
|
${chalk.dim('Commands:')}
|
||||||
|
|
||||||
connect Connect your Git config "origin" remote as a Git provider to your project
|
connect [url] Connect your Vercel Project to your Git repository or provide the remote URL to your Git repository
|
||||||
disconnect Disconnect the Git provider repository from your project
|
disconnect Disconnect the Git provider repository from your project
|
||||||
|
|
||||||
${chalk.dim('Options:')}
|
${chalk.dim('Options:')}
|
||||||
|
|
||||||
-h, --help Output usage information
|
-h, --help Output usage information
|
||||||
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
|
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
|
||||||
'TOKEN'
|
'TOKEN'
|
||||||
)} Login token
|
)} Login token
|
||||||
|
-y, --yes Skip questions when setting up new project using default scope and settings
|
||||||
|
|
||||||
${chalk.dim('Examples:')}
|
${chalk.dim('Examples:')}
|
||||||
|
|
||||||
${chalk.gray('–')} Connect a Git provider repository
|
${chalk.gray(
|
||||||
|
'–'
|
||||||
|
)} Connect your Vercel Project to your Git repository defined in your local .git config
|
||||||
|
|
||||||
${chalk.cyan(`$ ${getPkgName()} git connect`)}
|
${chalk.cyan(`$ ${getPkgName()} git connect`)}
|
||||||
|
|
||||||
|
${chalk.gray('–')} Connect your Vercel Project to a Git repository using the remote URL
|
||||||
|
|
||||||
|
${chalk.cyan(
|
||||||
|
`$ ${getPkgName()} git connect https://github.com/user/repo.git`
|
||||||
|
)}
|
||||||
|
|
||||||
${chalk.gray('–')} Disconnect the Git provider repository
|
${chalk.gray('–')} Disconnect the Git provider repository
|
||||||
|
|
||||||
@@ -49,7 +58,12 @@ export default async function main(client: Client) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
argv = getArgs(client.argv.slice(2), {
|
argv = getArgs(client.argv.slice(2), {
|
||||||
'--confirm': Boolean,
|
'--yes': Boolean,
|
||||||
|
'-y': '--yes',
|
||||||
|
|
||||||
|
// deprecated
|
||||||
|
'-c': '--yes',
|
||||||
|
'--confirm': '--yes',
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error);
|
handleError(error);
|
||||||
@@ -64,7 +78,7 @@ export default async function main(client: Client) {
|
|||||||
argv._ = argv._.slice(1);
|
argv._ = argv._.slice(1);
|
||||||
subcommand = argv._[0];
|
subcommand = argv._[0];
|
||||||
const args = argv._.slice(1);
|
const args = argv._.slice(1);
|
||||||
const confirm = Boolean(argv['--confirm']);
|
const confirm = Boolean(argv['--yes']);
|
||||||
const { output } = client;
|
const { output } = client;
|
||||||
|
|
||||||
let paths = [process.cwd()];
|
let paths = [process.cwd()];
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
export default new Map([
|
export default new Map([
|
||||||
['alias', 'alias'],
|
['alias', 'alias'],
|
||||||
['aliases', 'alias'],
|
['aliases', 'alias'],
|
||||||
['billing', 'billing'],
|
|
||||||
['bisect', 'bisect'],
|
['bisect', 'bisect'],
|
||||||
['build', 'build'],
|
['build', 'build'],
|
||||||
['cc', 'billing'],
|
|
||||||
['cert', 'certs'],
|
['cert', 'certs'],
|
||||||
['certs', 'certs'],
|
['certs', 'certs'],
|
||||||
['deploy', 'deploy'],
|
['deploy', 'deploy'],
|
||||||
@@ -36,6 +34,5 @@ export default new Map([
|
|||||||
['switch', 'teams'],
|
['switch', 'teams'],
|
||||||
['team', 'teams'],
|
['team', 'teams'],
|
||||||
['teams', 'teams'],
|
['teams', 'teams'],
|
||||||
['update', 'update'],
|
|
||||||
['whoami', 'whoami'],
|
['whoami', 'whoami'],
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const help = () => {
|
|||||||
-p ${chalk.bold.underline('NAME')}, --project=${chalk.bold.underline(
|
-p ${chalk.bold.underline('NAME')}, --project=${chalk.bold.underline(
|
||||||
'NAME'
|
'NAME'
|
||||||
)} Project name
|
)} Project name
|
||||||
--confirm Confirm default options and skip questions
|
-y, --yes Skip questions when setting up new project using default scope and settings
|
||||||
|
|
||||||
${chalk.dim('Examples:')}
|
${chalk.dim('Examples:')}
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ const help = () => {
|
|||||||
'–'
|
'–'
|
||||||
)} Link current directory with default options and skip questions
|
)} Link current directory with default options and skip questions
|
||||||
|
|
||||||
${chalk.cyan(`$ ${getPkgName()} link --confirm`)}
|
${chalk.cyan(`$ ${getPkgName()} link --yes`)}
|
||||||
|
|
||||||
${chalk.gray('–')} Link a specific directory to a Vercel Project
|
${chalk.gray('–')} Link a specific directory to a Vercel Project
|
||||||
|
|
||||||
@@ -49,9 +49,14 @@ const help = () => {
|
|||||||
|
|
||||||
export default async function main(client: Client) {
|
export default async function main(client: Client) {
|
||||||
const argv = getArgs(client.argv.slice(2), {
|
const argv = getArgs(client.argv.slice(2), {
|
||||||
'--confirm': Boolean,
|
'--yes': Boolean,
|
||||||
|
'-y': '--yes',
|
||||||
'--project': String,
|
'--project': String,
|
||||||
'-p': '--project',
|
'-p': '--project',
|
||||||
|
|
||||||
|
// deprecated
|
||||||
|
'--confirm': Boolean,
|
||||||
|
'-c': '--confirm',
|
||||||
});
|
});
|
||||||
|
|
||||||
if (argv['--help']) {
|
if (argv['--help']) {
|
||||||
@@ -59,10 +64,15 @@ export default async function main(client: Client) {
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('--confirm' in argv) {
|
||||||
|
client.output.warn('`--confirm` is deprecated, please use `--yes` instead');
|
||||||
|
argv['--yes'] = argv['--confirm'];
|
||||||
|
}
|
||||||
|
|
||||||
const cwd = argv._[1] || process.cwd();
|
const cwd = argv._[1] || process.cwd();
|
||||||
const link = await setupAndLink(client, cwd, {
|
const link = await setupAndLink(client, cwd, {
|
||||||
forceDelete: true,
|
forceDelete: true,
|
||||||
autoConfirm: argv['--confirm'],
|
autoConfirm: argv['--yes'],
|
||||||
projectName: argv['--project'],
|
projectName: argv['--project'],
|
||||||
successEmoji: 'success',
|
successEmoji: 'success',
|
||||||
setupMsg: 'Set up',
|
setupMsg: 'Set up',
|
||||||
@@ -73,7 +83,7 @@ export default async function main(client: Client) {
|
|||||||
client.output.error(
|
client.output.error(
|
||||||
`Command ${getCommandName(
|
`Command ${getCommandName(
|
||||||
'link'
|
'link'
|
||||||
)} requires confirmation. Use option ${param('--confirm')} to confirm.`
|
)} requires confirmation. Use option ${param('--yes')} to confirm.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return link.exitCode;
|
return link.exitCode;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import ms from 'ms';
|
import ms from 'ms';
|
||||||
import table from 'text-table';
|
import table from 'text-table';
|
||||||
|
import title from 'title';
|
||||||
import Now from '../util';
|
import Now from '../util';
|
||||||
import getArgs from '../util/get-args';
|
import getArgs from '../util/get-args';
|
||||||
import { handleError } from '../util/error';
|
import { handleError } from '../util/error';
|
||||||
import cmd from '../util/output/cmd';
|
|
||||||
import logo from '../util/output/logo';
|
import logo from '../util/output/logo';
|
||||||
import elapsed from '../util/output/elapsed';
|
import elapsed from '../util/output/elapsed';
|
||||||
import strlen from '../util/strlen';
|
import strlen from '../util/strlen';
|
||||||
@@ -14,12 +14,13 @@ import { isValidName } from '../util/is-valid-name';
|
|||||||
import getCommandFlags from '../util/get-command-flags';
|
import getCommandFlags from '../util/get-command-flags';
|
||||||
import { getPkgName, getCommandName } from '../util/pkg-name';
|
import { getPkgName, getCommandName } from '../util/pkg-name';
|
||||||
import Client from '../util/client';
|
import Client from '../util/client';
|
||||||
import { Deployment } from '../types';
|
import { Deployment } from '@vercel/client';
|
||||||
import validatePaths from '../util/validate-paths';
|
import validatePaths from '../util/validate-paths';
|
||||||
import { getLinkedProject } from '../util/projects/link';
|
import { getLinkedProject } from '../util/projects/link';
|
||||||
import { ensureLink } from '../util/ensure-link';
|
import { ensureLink } from '../util/ensure-link';
|
||||||
import getScope from '../util/get-scope';
|
import getScope from '../util/get-scope';
|
||||||
import { isAPIError } from '../util/errors-ts';
|
import { isAPIError } from '../util/errors-ts';
|
||||||
|
import { isErrnoException } from '../util/is-error';
|
||||||
|
|
||||||
const help = () => {
|
const help = () => {
|
||||||
console.log(`
|
console.log(`
|
||||||
@@ -35,7 +36,7 @@ const help = () => {
|
|||||||
'DIR'
|
'DIR'
|
||||||
)} Path to the global ${'`.vercel`'} directory
|
)} Path to the global ${'`.vercel`'} directory
|
||||||
-d, --debug Debug mode [off]
|
-d, --debug Debug mode [off]
|
||||||
--confirm Skip the confirmation prompt
|
-y, --yes Skip questions when setting up new project using default scope and settings
|
||||||
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
|
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
|
||||||
'TOKEN'
|
'TOKEN'
|
||||||
)} Login token
|
)} Login token
|
||||||
@@ -43,6 +44,7 @@ const help = () => {
|
|||||||
-m, --meta Filter deployments by metadata (e.g.: ${chalk.dim(
|
-m, --meta Filter deployments by metadata (e.g.: ${chalk.dim(
|
||||||
'`-m KEY=value`'
|
'`-m KEY=value`'
|
||||||
)}). Can appear many times.
|
)}). Can appear many times.
|
||||||
|
--prod Filter for production URLs
|
||||||
-N, --next Show next page of results
|
-N, --next Show next page of results
|
||||||
|
|
||||||
${chalk.dim('Examples:')}
|
${chalk.dim('Examples:')}
|
||||||
@@ -78,7 +80,13 @@ export default async function main(client: Client) {
|
|||||||
'-m': '--meta',
|
'-m': '--meta',
|
||||||
'--next': Number,
|
'--next': Number,
|
||||||
'-N': '--next',
|
'-N': '--next',
|
||||||
|
'--prod': Boolean,
|
||||||
|
'--yes': Boolean,
|
||||||
|
'-y': '--yes',
|
||||||
|
|
||||||
|
// deprecated
|
||||||
'--confirm': Boolean,
|
'--confirm': Boolean,
|
||||||
|
'-c': '--confirm',
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
handleError(err);
|
handleError(err);
|
||||||
@@ -87,6 +95,11 @@ export default async function main(client: Client) {
|
|||||||
|
|
||||||
const { output, config } = client;
|
const { output, config } = client;
|
||||||
|
|
||||||
|
if ('--confirm' in argv) {
|
||||||
|
output.warn('`--confirm` is deprecated, please use `--yes` instead');
|
||||||
|
argv['--yes'] = argv['--confirm'];
|
||||||
|
}
|
||||||
|
|
||||||
const { print, log, error, note, debug, spinner } = output;
|
const { print, log, error, note, debug, spinner } = output;
|
||||||
|
|
||||||
if (argv._.length > 2) {
|
if (argv._.length > 2) {
|
||||||
@@ -99,10 +112,10 @@ export default async function main(client: Client) {
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
const yes = argv['--confirm'] || false;
|
const yes = !!argv['--yes'];
|
||||||
|
const prod = argv['--prod'] || false;
|
||||||
|
|
||||||
const meta = parseMeta(argv['--meta']);
|
const meta = parseMeta(argv['--meta']);
|
||||||
const { includeScheme } = config;
|
|
||||||
|
|
||||||
let paths = [process.cwd()];
|
let paths = [process.cwd()];
|
||||||
const pathValidation = await validatePaths(client, paths);
|
const pathValidation = await validatePaths(client, paths);
|
||||||
@@ -136,11 +149,25 @@ export default async function main(client: Client) {
|
|||||||
if (typeof linkedProject === 'number') {
|
if (typeof linkedProject === 'number') {
|
||||||
return linkedProject;
|
return linkedProject;
|
||||||
}
|
}
|
||||||
link.org = linkedProject.org;
|
org = linkedProject.org;
|
||||||
link.project = linkedProject.project;
|
project = linkedProject.project;
|
||||||
|
app = project.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { contextName, team } = await getScope(client);
|
let contextName;
|
||||||
|
let team;
|
||||||
|
|
||||||
|
try {
|
||||||
|
({ contextName, team } = await getScope(client));
|
||||||
|
} catch (err: unknown) {
|
||||||
|
if (
|
||||||
|
isErrnoException(err) &&
|
||||||
|
(err.code === 'NOT_AUTHORIZED' || err.code === 'TEAM_DELETED')
|
||||||
|
) {
|
||||||
|
error(err.message);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If user passed in a custom scope, update the current team & context name
|
// If user passed in a custom scope, update the current team & context name
|
||||||
if (argv['--scope']) {
|
if (argv['--scope']) {
|
||||||
@@ -198,11 +225,15 @@ export default async function main(client: Client) {
|
|||||||
|
|
||||||
debug('Fetching deployments');
|
debug('Fetching deployments');
|
||||||
|
|
||||||
const response = await now.list(app, {
|
const response = await now.list(
|
||||||
version: 6,
|
app,
|
||||||
meta,
|
{
|
||||||
nextTimestamp,
|
version: 6,
|
||||||
});
|
meta,
|
||||||
|
nextTimestamp,
|
||||||
|
},
|
||||||
|
prod
|
||||||
|
);
|
||||||
|
|
||||||
let {
|
let {
|
||||||
deployments,
|
deployments,
|
||||||
@@ -212,6 +243,14 @@ export default async function main(client: Client) {
|
|||||||
pagination: { count: number; next: number };
|
pagination: { count: number; next: number };
|
||||||
} = response;
|
} = response;
|
||||||
|
|
||||||
|
let showUsername = false;
|
||||||
|
for (const deployment of deployments) {
|
||||||
|
const username = deployment.creator?.username;
|
||||||
|
if (username !== contextName) {
|
||||||
|
showUsername = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (app && !deployments.length) {
|
if (app && !deployments.length) {
|
||||||
debug(
|
debug(
|
||||||
'No deployments: attempting to find deployment that matches supplied app name'
|
'No deployments: attempting to find deployment that matches supplied app name'
|
||||||
@@ -247,37 +286,36 @@ export default async function main(client: Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log(
|
log(
|
||||||
`Deployments under ${chalk.bold(contextName)} ${elapsed(
|
`${prod ? `Production deployments` : `Deployments`} for ${chalk.bold(
|
||||||
Date.now() - start
|
app
|
||||||
)}`
|
)} under ${chalk.bold(contextName)} ${elapsed(Date.now() - start)}`
|
||||||
);
|
);
|
||||||
|
|
||||||
// information to help the user find other deployments or instances
|
// information to help the user find other deployments or instances
|
||||||
if (app == null) {
|
log(
|
||||||
log(
|
`To list more deployments for a project, run ${getCommandName(
|
||||||
`To list more deployments for a project run ${cmd(
|
'ls [project]'
|
||||||
`${getCommandName('ls [project]')}`
|
)}.`
|
||||||
)}`
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
print('\n');
|
print('\n');
|
||||||
|
|
||||||
|
const headers = ['Age', 'Deployment', 'Status', 'Duration'];
|
||||||
|
if (showUsername) headers.push('Username');
|
||||||
|
|
||||||
client.output.print(
|
client.output.print(
|
||||||
`${table(
|
`${table(
|
||||||
[
|
[
|
||||||
['project', 'latest deployment', 'state', 'age', 'username'].map(
|
headers.map(header => chalk.bold(chalk.cyan(header))),
|
||||||
header => chalk.dim(header)
|
|
||||||
),
|
|
||||||
...deployments
|
...deployments
|
||||||
.sort(sortRecent())
|
.sort(sortRecent())
|
||||||
.map(dep => [
|
.map(dep => [
|
||||||
[
|
[
|
||||||
getProjectName(dep),
|
|
||||||
chalk.bold((includeScheme ? 'https://' : '') + dep.url),
|
|
||||||
stateString(dep.state),
|
|
||||||
chalk.gray(ms(Date.now() - dep.createdAt)),
|
chalk.gray(ms(Date.now() - dep.createdAt)),
|
||||||
dep.creator.username,
|
`https://${dep.url}`,
|
||||||
|
stateString(dep.state || ''),
|
||||||
|
chalk.gray(getDeploymentDuration(dep)),
|
||||||
|
showUsername ? chalk.gray(dep.creator?.username) : '',
|
||||||
],
|
],
|
||||||
])
|
])
|
||||||
// flatten since the previous step returns a nested
|
// flatten since the previous step returns a nested
|
||||||
@@ -290,8 +328,8 @@ export default async function main(client: Client) {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
align: ['l', 'l', 'r', 'l', 'l'],
|
align: ['l', 'l', 'l', 'l', 'l'],
|
||||||
hsep: ' '.repeat(4),
|
hsep: ' '.repeat(5),
|
||||||
stringLength: strlen,
|
stringLength: strlen,
|
||||||
}
|
}
|
||||||
).replace(/^/gm, ' ')}\n\n`
|
).replace(/^/gm, ' ')}\n\n`
|
||||||
@@ -307,27 +345,36 @@ export default async function main(client: Client) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProjectName(d: Deployment) {
|
export function getDeploymentDuration(dep: Deployment): string {
|
||||||
// We group both file and files into a single project
|
if (!dep || !dep.ready || !dep.buildingAt) {
|
||||||
if (d.name === 'file') {
|
return '?';
|
||||||
return 'files';
|
|
||||||
}
|
}
|
||||||
|
const duration = ms(dep.ready - dep.buildingAt);
|
||||||
return d.name;
|
if (duration === '0ms') {
|
||||||
|
return '--';
|
||||||
|
}
|
||||||
|
return duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
// renders the state string
|
// renders the state string
|
||||||
export function stateString(s: string) {
|
export function stateString(s: string) {
|
||||||
|
const CIRCLE = '● ';
|
||||||
|
// make `s` title case
|
||||||
|
const sTitle = title(s);
|
||||||
switch (s) {
|
switch (s) {
|
||||||
case 'INITIALIZING':
|
case 'INITIALIZING':
|
||||||
return chalk.yellow(s);
|
case 'BUILDING':
|
||||||
|
case 'DEPLOYING':
|
||||||
|
case 'ANALYZING':
|
||||||
|
return chalk.yellow(CIRCLE) + sTitle;
|
||||||
case 'ERROR':
|
case 'ERROR':
|
||||||
return chalk.red(s);
|
return chalk.red(CIRCLE) + sTitle;
|
||||||
|
|
||||||
case 'READY':
|
case 'READY':
|
||||||
return s;
|
return chalk.green(CIRCLE) + sTitle;
|
||||||
|
case 'QUEUED':
|
||||||
|
return chalk.white(CIRCLE) + sTitle;
|
||||||
|
case 'CANCELED':
|
||||||
|
return chalk.gray(sTitle);
|
||||||
default:
|
default:
|
||||||
return chalk.gray('UNKNOWN');
|
return chalk.gray('UNKNOWN');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import ms from 'ms';
|
import ms from 'ms';
|
||||||
import table from 'text-table';
|
import table from 'text-table';
|
||||||
|
import { Project } from '../../types';
|
||||||
import Client from '../../util/client';
|
import Client from '../../util/client';
|
||||||
import getCommandFlags from '../../util/get-command-flags';
|
import getCommandFlags from '../../util/get-command-flags';
|
||||||
import { getCommandName } from '../../util/pkg-name';
|
import { getCommandName } from '../../util/pkg-name';
|
||||||
@@ -34,10 +35,10 @@ export default async function list(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
projects: list,
|
projects: projectList,
|
||||||
pagination,
|
pagination,
|
||||||
}: {
|
}: {
|
||||||
projects: [{ name: string; updatedAt: number }];
|
projects: Project[];
|
||||||
pagination: { count: number; next: number };
|
pagination: { count: number; next: number };
|
||||||
} = await client.fetch(projectsUrl, {
|
} = await client.fetch(projectsUrl, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
@@ -48,39 +49,48 @@ export default async function list(
|
|||||||
const elapsed = ms(Date.now() - start);
|
const elapsed = ms(Date.now() - start);
|
||||||
|
|
||||||
output.log(
|
output.log(
|
||||||
`${list.length > 0 ? 'Projects' : 'No projects'} found under ${chalk.bold(
|
`${
|
||||||
contextName
|
projectList.length > 0 ? 'Projects' : 'No projects'
|
||||||
)} ${chalk.gray(`[${elapsed}]`)}`
|
} found under ${chalk.bold(contextName)} ${chalk.gray(`[${elapsed}]`)}`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (list.length > 0) {
|
if (projectList.length > 0) {
|
||||||
const cur = Date.now();
|
const tablePrint = table(
|
||||||
const header = [['', 'name', 'updated'].map(title => chalk.dim(title))];
|
[
|
||||||
|
['Project Name', 'Latest Production URL', 'Updated'].map(header =>
|
||||||
const out = table(
|
chalk.bold(chalk.cyan(header))
|
||||||
header.concat(
|
),
|
||||||
list.map(secret => [
|
...projectList
|
||||||
'',
|
.map(project => [
|
||||||
chalk.bold(secret.name),
|
[
|
||||||
chalk.gray(`${ms(cur - secret.updatedAt)} ago`),
|
chalk.bold(project.name),
|
||||||
])
|
getLatestProdUrl(project),
|
||||||
),
|
chalk.gray(ms(Date.now() - project.updatedAt)),
|
||||||
|
],
|
||||||
|
])
|
||||||
|
.flat(),
|
||||||
|
],
|
||||||
{
|
{
|
||||||
align: ['l', 'l', 'l'],
|
align: ['l', 'l', 'l'],
|
||||||
hsep: ' '.repeat(2),
|
hsep: ' '.repeat(3),
|
||||||
stringLength: strlen,
|
stringLength: strlen,
|
||||||
}
|
}
|
||||||
);
|
).replace(/^/gm, ' ');
|
||||||
|
output.print(`\n${tablePrint}\n\n`);
|
||||||
if (out) {
|
|
||||||
output.print(`\n${out}\n\n`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pagination && pagination.count === 20) {
|
if (pagination && pagination.count === 20) {
|
||||||
const flags = getCommandFlags(argv, ['_', '--next', '-N', '-d', '-y']);
|
const flags = getCommandFlags(argv, ['_', '--next', '-N', '-d', '-y']);
|
||||||
const nextCmd = `project ls${flags} --next ${pagination.next}`;
|
const nextCmd = `project ls${flags} --next ${pagination.next}`;
|
||||||
output.log(`To display the next page run ${getCommandName(nextCmd)}`);
|
output.log(`To display the next page, run ${getCommandName(nextCmd)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getLatestProdUrl(project: Project): string {
|
||||||
|
const alias =
|
||||||
|
project.alias?.filter(al => al.deployment)?.[0]?.domain ||
|
||||||
|
project.alias?.[0]?.domain;
|
||||||
|
if (alias) return 'https://' + alias;
|
||||||
|
return '--';
|
||||||
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const help = () => {
|
|||||||
)} Path to the global ${'`.vercel`'} directory
|
)} Path to the global ${'`.vercel`'} directory
|
||||||
-d, --debug Debug mode [off]
|
-d, --debug Debug mode [off]
|
||||||
--environment [environment] Deployment environment [development]
|
--environment [environment] Deployment environment [development]
|
||||||
-y, --yes Skip the confirmation prompt
|
-y, --yes Skip questions when setting up new project using default scope and settings
|
||||||
|
|
||||||
${chalk.dim('Examples:')}
|
${chalk.dim('Examples:')}
|
||||||
|
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
import chalk from 'chalk';
|
|
||||||
|
|
||||||
import cmd from '../util/output/cmd';
|
|
||||||
import logo from '../util/output/logo';
|
|
||||||
import handleError from '../util/handle-error';
|
|
||||||
import getArgs from '../util/get-args';
|
|
||||||
import Client from '../util/client';
|
|
||||||
import getUpdateCommand from '../util/get-update-command';
|
|
||||||
import { getPkgName, getTitleName } from '../util/pkg-name';
|
|
||||||
|
|
||||||
const help = () => {
|
|
||||||
console.log(`
|
|
||||||
${chalk.bold(`${logo} ${getPkgName()} update`)} [options]
|
|
||||||
|
|
||||||
${chalk.dim('Options:')}
|
|
||||||
|
|
||||||
-h, --help Output usage information
|
|
||||||
-d, --debug Debug mode [off]
|
|
||||||
-c ${chalk.bold.underline('NAME')}, --channel=${chalk.bold.underline(
|
|
||||||
'NAME'
|
|
||||||
)} Specify which release channel to install [stable]
|
|
||||||
-r ${chalk.bold.underline('VERSION')}, --release=${chalk.bold.underline(
|
|
||||||
'VERSION'
|
|
||||||
)} Specfic version to install (overrides \`--channel\`)
|
|
||||||
-y, --yes Skip the confirmation prompt
|
|
||||||
|
|
||||||
${chalk.dim('Examples:')}
|
|
||||||
|
|
||||||
${chalk.gray('–')} Update ${getTitleName()} CLI to the latest "canary" version
|
|
||||||
|
|
||||||
${chalk.cyan(`$ ${getPkgName()} update --channel=canary`)}
|
|
||||||
`);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default async function main(client: Client): Promise<number> {
|
|
||||||
let argv;
|
|
||||||
const { output } = client;
|
|
||||||
|
|
||||||
try {
|
|
||||||
argv = getArgs(client.argv.slice(2), {
|
|
||||||
'--channel': String,
|
|
||||||
'-c': '--channel',
|
|
||||||
'--release': String,
|
|
||||||
'-V': '--release',
|
|
||||||
'--yes': Boolean,
|
|
||||||
'-y': '--yes',
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
handleError(err);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argv['--help']) {
|
|
||||||
help();
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
output.log(
|
|
||||||
`Please run ${cmd(
|
|
||||||
await getUpdateCommand()
|
|
||||||
)} to update ${getTitleName()} CLI`
|
|
||||||
);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -323,14 +323,7 @@ const main = async () => {
|
|||||||
client.argv.push('-h');
|
client.argv.push('-h');
|
||||||
}
|
}
|
||||||
|
|
||||||
const subcommandsWithoutToken = [
|
const subcommandsWithoutToken = ['login', 'logout', 'help', 'init', 'build'];
|
||||||
'login',
|
|
||||||
'logout',
|
|
||||||
'help',
|
|
||||||
'init',
|
|
||||||
'update',
|
|
||||||
'build',
|
|
||||||
];
|
|
||||||
|
|
||||||
// Prompt for login if there is no current token
|
// Prompt for login if there is no current token
|
||||||
if (
|
if (
|
||||||
@@ -505,9 +498,6 @@ const main = async () => {
|
|||||||
case 'alias':
|
case 'alias':
|
||||||
func = require('./commands/alias').default;
|
func = require('./commands/alias').default;
|
||||||
break;
|
break;
|
||||||
case 'billing':
|
|
||||||
func = require('./commands/billing').default;
|
|
||||||
break;
|
|
||||||
case 'bisect':
|
case 'bisect':
|
||||||
func = require('./commands/bisect').default;
|
func = require('./commands/bisect').default;
|
||||||
break;
|
break;
|
||||||
@@ -571,9 +561,6 @@ const main = async () => {
|
|||||||
case 'teams':
|
case 'teams':
|
||||||
func = require('./commands/teams').default;
|
func = require('./commands/teams').default;
|
||||||
break;
|
break;
|
||||||
case 'update':
|
|
||||||
func = require('./commands/update').default;
|
|
||||||
break;
|
|
||||||
case 'whoami':
|
case 'whoami':
|
||||||
func = require('./commands/whoami').default;
|
func = require('./commands/whoami').default;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ export interface GlobalConfig {
|
|||||||
'// Note'?: string;
|
'// Note'?: string;
|
||||||
'// Docs'?: string;
|
'// Docs'?: string;
|
||||||
currentTeam?: string;
|
currentTeam?: string;
|
||||||
includeScheme?: string;
|
|
||||||
collectMetrics?: boolean;
|
collectMetrics?: boolean;
|
||||||
api?: string;
|
api?: string;
|
||||||
|
|
||||||
@@ -142,6 +141,7 @@ export type Deployment = {
|
|||||||
meta: {
|
meta: {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
};
|
};
|
||||||
|
alias?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Alias = {
|
export type Alias = {
|
||||||
@@ -211,6 +211,7 @@ export interface ProjectAliasTarget {
|
|||||||
configuredBy?: null | 'CNAME' | 'A';
|
configuredBy?: null | 'CNAME' | 'A';
|
||||||
configuredChangedAt?: null | number;
|
configuredChangedAt?: null | number;
|
||||||
configuredChangeAttempts?: [number, number];
|
configuredChangeAttempts?: [number, number];
|
||||||
|
deployment?: Deployment | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Secret {
|
export interface Secret {
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"VISA": "Visa",
|
|
||||||
"MASTERCARD": "MasterCard",
|
|
||||||
"AMERICANEXPRESS": "American Express",
|
|
||||||
"DINERSCLUB": "Diners Club",
|
|
||||||
"DISCOVER": "Discover",
|
|
||||||
"JCB": "JCB"
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,7 @@ import mapCertError from '../certs/map-cert-error';
|
|||||||
import { Org } from '../../types';
|
import { Org } from '../../types';
|
||||||
import Now, { CreateOptions } from '..';
|
import Now, { CreateOptions } from '..';
|
||||||
import Client from '../client';
|
import Client from '../client';
|
||||||
import { DeploymentError } from '../../../../client/dist';
|
import { ArchiveFormat, DeploymentError } from '@vercel/client';
|
||||||
|
|
||||||
export default async function createDeploy(
|
export default async function createDeploy(
|
||||||
client: Client,
|
client: Client,
|
||||||
@@ -16,10 +16,18 @@ export default async function createDeploy(
|
|||||||
createArgs: CreateOptions,
|
createArgs: CreateOptions,
|
||||||
org: Org,
|
org: Org,
|
||||||
isSettingUpProject: boolean,
|
isSettingUpProject: boolean,
|
||||||
cwd?: string
|
cwd?: string,
|
||||||
|
archive?: ArchiveFormat
|
||||||
): Promise<any | DeploymentError> {
|
): Promise<any | DeploymentError> {
|
||||||
try {
|
try {
|
||||||
return await now.create(paths, createArgs, org, isSettingUpProject, cwd);
|
return await now.create(
|
||||||
|
paths,
|
||||||
|
createArgs,
|
||||||
|
org,
|
||||||
|
isSettingUpProject,
|
||||||
|
archive,
|
||||||
|
cwd
|
||||||
|
);
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
if (ERRORS_TS.isAPIError(err)) {
|
if (ERRORS_TS.isAPIError(err)) {
|
||||||
if (err.code === 'rate_limited') {
|
if (err.code === 'rate_limited') {
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ import bytes from 'bytes';
|
|||||||
import Progress from 'progress';
|
import Progress from 'progress';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import {
|
import {
|
||||||
|
ArchiveFormat,
|
||||||
createDeployment,
|
createDeployment,
|
||||||
DeploymentOptions,
|
DeploymentOptions,
|
||||||
VercelClientOptions,
|
VercelClientOptions,
|
||||||
} from '@vercel/client';
|
} from '@vercel/client';
|
||||||
import { Output } from '../output';
|
import { Output } from '../output';
|
||||||
// @ts-ignore
|
|
||||||
import Now from '../../util';
|
import Now from '../../util';
|
||||||
import { Org } from '../../types';
|
import { Org } from '../../types';
|
||||||
import ua from '../ua';
|
import ua from '../ua';
|
||||||
@@ -32,6 +32,7 @@ export default async function processDeployment({
|
|||||||
cwd,
|
cwd,
|
||||||
projectName,
|
projectName,
|
||||||
isSettingUpProject,
|
isSettingUpProject,
|
||||||
|
archive,
|
||||||
skipAutoDetectionConfirmation,
|
skipAutoDetectionConfirmation,
|
||||||
...args
|
...args
|
||||||
}: {
|
}: {
|
||||||
@@ -48,6 +49,7 @@ export default async function processDeployment({
|
|||||||
prebuilt: boolean;
|
prebuilt: boolean;
|
||||||
projectName: string;
|
projectName: string;
|
||||||
isSettingUpProject: boolean;
|
isSettingUpProject: boolean;
|
||||||
|
archive?: ArchiveFormat;
|
||||||
skipAutoDetectionConfirmation?: boolean;
|
skipAutoDetectionConfirmation?: boolean;
|
||||||
cwd?: string;
|
cwd?: string;
|
||||||
rootDirectory?: string;
|
rootDirectory?: string;
|
||||||
@@ -87,14 +89,13 @@ export default async function processDeployment({
|
|||||||
prebuilt,
|
prebuilt,
|
||||||
rootDirectory,
|
rootDirectory,
|
||||||
skipAutoDetectionConfirmation,
|
skipAutoDetectionConfirmation,
|
||||||
|
archive,
|
||||||
};
|
};
|
||||||
|
|
||||||
output.spinner(
|
const deployingSpinnerVal = isSettingUpProject
|
||||||
isSettingUpProject
|
? 'Setting up project'
|
||||||
? 'Setting up project'
|
: `Deploying ${chalk.bold(`${org.slug}/${projectName}`)}`;
|
||||||
: `Deploying ${chalk.bold(`${org.slug}/${projectName}`)}`,
|
output.spinner(deployingSpinnerVal, 0);
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
// collect indications to show the user once
|
// collect indications to show the user once
|
||||||
// the deployment is done
|
// the deployment is done
|
||||||
@@ -107,12 +108,11 @@ export default async function processDeployment({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (event.type === 'file-count') {
|
if (event.type === 'file-count') {
|
||||||
debug(
|
const { total, missing, uploads } = event.payload;
|
||||||
`Total files ${event.payload.total.size}, ${event.payload.missing.length} changed`
|
debug(`Total files ${total.size}, ${missing.length} changed`);
|
||||||
);
|
|
||||||
|
|
||||||
const missingSize = event.payload.missing
|
const missingSize = missing
|
||||||
.map((sha: string) => event.payload.total.get(sha).data.length)
|
.map((sha: string) => total.get(sha).data.length)
|
||||||
.reduce((a: number, b: number) => a + b, 0);
|
.reduce((a: number, b: number) => a + b, 0);
|
||||||
|
|
||||||
output.stopSpinner();
|
output.stopSpinner();
|
||||||
@@ -123,6 +123,26 @@ export default async function processDeployment({
|
|||||||
total: missingSize,
|
total: missingSize,
|
||||||
clear: true,
|
clear: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bar.tick(0);
|
||||||
|
|
||||||
|
uploads.forEach((e: any) =>
|
||||||
|
e.on('progress', () => {
|
||||||
|
if (!bar) return;
|
||||||
|
|
||||||
|
const totalBytesUploaded = uploads.reduce((acc: number, e: any) => {
|
||||||
|
return acc + e.bytesUploaded;
|
||||||
|
}, 0);
|
||||||
|
// set the current progress bar value
|
||||||
|
bar.curr = totalBytesUploaded;
|
||||||
|
// trigger rendering
|
||||||
|
bar.tick(0);
|
||||||
|
|
||||||
|
if (bar.complete) {
|
||||||
|
output.spinner(deployingSpinnerVal, 0);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type === 'file-uploaded') {
|
if (event.type === 'file-uploaded') {
|
||||||
@@ -131,10 +151,6 @@ export default async function processDeployment({
|
|||||||
event.payload.file.data.length
|
event.payload.file.data.length
|
||||||
)})`
|
)})`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (bar) {
|
|
||||||
bar.tick(event.payload.file.data.length);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type === 'created') {
|
if (event.type === 'created') {
|
||||||
|
|||||||
7
packages/cli/src/util/deploy/validate-archive-format.ts
Normal file
7
packages/cli/src/util/deploy/validate-archive-format.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { ArchiveFormat, VALID_ARCHIVE_FORMATS } from '@vercel/client';
|
||||||
|
|
||||||
|
const validArchiveFormats = new Set<string>(VALID_ARCHIVE_FORMATS);
|
||||||
|
|
||||||
|
export function isValidArchive(archive: string): archive is ArchiveFormat {
|
||||||
|
return validArchiveFormats.has(archive);
|
||||||
|
}
|
||||||
59
packages/cli/src/util/dev/parse-query-string.ts
Normal file
59
packages/cli/src/util/dev/parse-query-string.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* This function is necessary to account for the difference between
|
||||||
|
* `?a=` and `?a` because native `url.parse(str, true)` can't tell.
|
||||||
|
* @param querystring - The querystring to parse, also known as the "search" string.
|
||||||
|
*/
|
||||||
|
export function parseQueryString(
|
||||||
|
querystring?: string
|
||||||
|
): Record<string, string[]> {
|
||||||
|
const query: Record<string, string[]> = Object.create(null);
|
||||||
|
if (!querystring || !querystring.startsWith('?') || querystring === '?') {
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
const params = querystring.slice(1).split('&');
|
||||||
|
for (let param of params) {
|
||||||
|
let [key, value] = param.split('=');
|
||||||
|
if (key !== undefined) {
|
||||||
|
key = decodeURIComponent(key);
|
||||||
|
}
|
||||||
|
if (value !== undefined) {
|
||||||
|
value = decodeURIComponent(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
let existing = query[key];
|
||||||
|
if (!existing) {
|
||||||
|
existing = [];
|
||||||
|
query[key] = existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
existing.push(value);
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is necessary to account for the difference between
|
||||||
|
* `?a=` and `?a` because native `url.format({ query })` can't tell.
|
||||||
|
* @param query - The query object to stringify.
|
||||||
|
*/
|
||||||
|
export function formatQueryString(
|
||||||
|
query: Record<string, string[]> | undefined
|
||||||
|
): string | undefined {
|
||||||
|
if (!query) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
let s = '';
|
||||||
|
let prefix = '?';
|
||||||
|
for (let [key, values] of Object.entries(query)) {
|
||||||
|
for (let value of values) {
|
||||||
|
s += prefix;
|
||||||
|
s += encodeURIComponent(key);
|
||||||
|
if (value !== undefined) {
|
||||||
|
s += '=';
|
||||||
|
s += encodeURIComponent(value);
|
||||||
|
}
|
||||||
|
prefix = '&';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s || undefined;
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import DevServer from './server';
|
|||||||
|
|
||||||
import { VercelConfig, HttpHeadersConfig, RouteResult } from './types';
|
import { VercelConfig, HttpHeadersConfig, RouteResult } from './types';
|
||||||
import { isHandler, Route, HandleValue } from '@vercel/routing-utils';
|
import { isHandler, Route, HandleValue } from '@vercel/routing-utils';
|
||||||
|
import { parseQueryString } from './parse-query-string';
|
||||||
|
|
||||||
export function resolveRouteParameters(
|
export function resolveRouteParameters(
|
||||||
str: string,
|
str: string,
|
||||||
@@ -56,7 +57,8 @@ export async function devRouter(
|
|||||||
phase?: HandleValue | null
|
phase?: HandleValue | null
|
||||||
): Promise<RouteResult> {
|
): Promise<RouteResult> {
|
||||||
let result: RouteResult | undefined;
|
let result: RouteResult | undefined;
|
||||||
let { query, pathname: reqPathname = '/' } = url.parse(reqUrl, true);
|
let { pathname: reqPathname = '/', search: reqSearch } = url.parse(reqUrl);
|
||||||
|
const reqQuery = parseQueryString(reqSearch);
|
||||||
const combinedHeaders: HttpHeadersConfig = { ...previousHeaders };
|
const combinedHeaders: HttpHeadersConfig = { ...previousHeaders };
|
||||||
let status: number | undefined;
|
let status: number | undefined;
|
||||||
let isContinue = false;
|
let isContinue = false;
|
||||||
@@ -174,7 +176,7 @@ export async function devRouter(
|
|||||||
isDestUrl,
|
isDestUrl,
|
||||||
status: routeConfig.status || status,
|
status: routeConfig.status || status,
|
||||||
headers: combinedHeaders,
|
headers: combinedHeaders,
|
||||||
uri_args: query,
|
query: reqQuery,
|
||||||
matched_route: routeConfig,
|
matched_route: routeConfig,
|
||||||
matched_route_idx: idx,
|
matched_route_idx: idx,
|
||||||
phase,
|
phase,
|
||||||
@@ -184,17 +186,19 @@ export async function devRouter(
|
|||||||
if (!destPath.startsWith('/')) {
|
if (!destPath.startsWith('/')) {
|
||||||
destPath = `/${destPath}`;
|
destPath = `/${destPath}`;
|
||||||
}
|
}
|
||||||
const destParsed = url.parse(destPath, true);
|
const { pathname: destPathname = '/', search: destSearch } =
|
||||||
Object.assign(destParsed.query, query);
|
url.parse(destPath);
|
||||||
|
const destQuery = parseQueryString(destSearch);
|
||||||
|
Object.assign(destQuery, reqQuery);
|
||||||
result = {
|
result = {
|
||||||
found: true,
|
found: true,
|
||||||
dest: destParsed.pathname || '/',
|
dest: destPathname,
|
||||||
continue: isContinue,
|
continue: isContinue,
|
||||||
userDest: Boolean(routeConfig.dest),
|
userDest: Boolean(routeConfig.dest),
|
||||||
isDestUrl,
|
isDestUrl,
|
||||||
status: routeConfig.status || status,
|
status: routeConfig.status || status,
|
||||||
headers: combinedHeaders,
|
headers: combinedHeaders,
|
||||||
uri_args: destParsed.query,
|
query: destQuery,
|
||||||
matched_route: routeConfig,
|
matched_route: routeConfig,
|
||||||
matched_route_idx: idx,
|
matched_route_idx: idx,
|
||||||
phase,
|
phase,
|
||||||
@@ -212,7 +216,7 @@ export async function devRouter(
|
|||||||
continue: isContinue,
|
continue: isContinue,
|
||||||
status,
|
status,
|
||||||
isDestUrl: false,
|
isDestUrl: false,
|
||||||
uri_args: query,
|
query: reqQuery,
|
||||||
headers: combinedHeaders,
|
headers: combinedHeaders,
|
||||||
phase,
|
phase,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ import { ProjectEnvVariable, ProjectSettings } from '../../types';
|
|||||||
import exposeSystemEnvs from './expose-system-envs';
|
import exposeSystemEnvs from './expose-system-envs';
|
||||||
import { treeKill } from '../tree-kill';
|
import { treeKill } from '../tree-kill';
|
||||||
import { nodeHeadersToFetchHeaders } from './headers';
|
import { nodeHeadersToFetchHeaders } from './headers';
|
||||||
|
import { formatQueryString, parseQueryString } from './parse-query-string';
|
||||||
import {
|
import {
|
||||||
errorToString,
|
errorToString,
|
||||||
isErrnoException,
|
isErrnoException,
|
||||||
@@ -131,7 +132,6 @@ export default class DevServer {
|
|||||||
public output: Output;
|
public output: Output;
|
||||||
public proxy: httpProxy;
|
public proxy: httpProxy;
|
||||||
public envConfigs: EnvConfigs;
|
public envConfigs: EnvConfigs;
|
||||||
public frameworkSlug?: string;
|
|
||||||
public files: BuilderInputs;
|
public files: BuilderInputs;
|
||||||
public address: string;
|
public address: string;
|
||||||
public devCacheDir: string;
|
public devCacheDir: string;
|
||||||
@@ -175,7 +175,6 @@ export default class DevServer {
|
|||||||
this.address = '';
|
this.address = '';
|
||||||
this.devCommand = options.devCommand;
|
this.devCommand = options.devCommand;
|
||||||
this.projectSettings = options.projectSettings;
|
this.projectSettings = options.projectSettings;
|
||||||
this.frameworkSlug = options.frameworkSlug;
|
|
||||||
this.caseSensitive = false;
|
this.caseSensitive = false;
|
||||||
this.apiDir = null;
|
this.apiDir = null;
|
||||||
this.apiExtensions = new Set();
|
this.apiExtensions = new Set();
|
||||||
@@ -1398,9 +1397,11 @@ export default class DevServer {
|
|||||||
|
|
||||||
const getReqUrl = (rr: RouteResult): string | undefined => {
|
const getReqUrl = (rr: RouteResult): string | undefined => {
|
||||||
if (rr.dest) {
|
if (rr.dest) {
|
||||||
if (rr.uri_args) {
|
if (rr.query) {
|
||||||
const destParsed = url.parse(rr.dest, true);
|
const destParsed = url.parse(rr.dest);
|
||||||
Object.assign(destParsed.query, rr.uri_args);
|
const destQuery = parseQueryString(destParsed.search);
|
||||||
|
Object.assign(destQuery, rr.query);
|
||||||
|
destParsed.search = formatQueryString(destQuery);
|
||||||
return url.format(destParsed);
|
return url.format(destParsed);
|
||||||
}
|
}
|
||||||
return rr.dest;
|
return rr.dest;
|
||||||
@@ -1535,9 +1536,8 @@ export default class DevServer {
|
|||||||
|
|
||||||
// Retain orginal pathname, but override query parameters from the rewrite
|
// Retain orginal pathname, but override query parameters from the rewrite
|
||||||
const beforeRewriteUrl = req.url || '/';
|
const beforeRewriteUrl = req.url || '/';
|
||||||
const rewriteUrlParsed = url.parse(beforeRewriteUrl, true);
|
const rewriteUrlParsed = url.parse(beforeRewriteUrl);
|
||||||
delete rewriteUrlParsed.search;
|
rewriteUrlParsed.search = url.parse(rewritePath).search;
|
||||||
rewriteUrlParsed.query = url.parse(rewritePath, true).query;
|
|
||||||
req.url = url.format(rewriteUrlParsed);
|
req.url = url.format(rewriteUrlParsed);
|
||||||
debug(
|
debug(
|
||||||
`Rewrote incoming HTTP URL from "${beforeRewriteUrl}" to "${req.url}"`
|
`Rewrote incoming HTTP URL from "${beforeRewriteUrl}" to "${req.url}"`
|
||||||
@@ -1596,9 +1596,10 @@ export default class DevServer {
|
|||||||
|
|
||||||
if (routeResult.isDestUrl) {
|
if (routeResult.isDestUrl) {
|
||||||
// Mix the `routes` result dest query params into the req path
|
// Mix the `routes` result dest query params into the req path
|
||||||
const destParsed = url.parse(routeResult.dest, true);
|
const destParsed = url.parse(routeResult.dest);
|
||||||
delete destParsed.search;
|
const destQuery = parseQueryString(destParsed.search);
|
||||||
Object.assign(destParsed.query, routeResult.uri_args);
|
Object.assign(destQuery, routeResult.query);
|
||||||
|
destParsed.search = formatQueryString(destQuery);
|
||||||
const destUrl = url.format(destParsed);
|
const destUrl = url.format(destParsed);
|
||||||
|
|
||||||
debug(`ProxyPass: ${destUrl}`);
|
debug(`ProxyPass: ${destUrl}`);
|
||||||
@@ -1739,7 +1740,7 @@ export default class DevServer {
|
|||||||
throw new Error('Expected Route Result but none was found.');
|
throw new Error('Expected Route Result but none was found.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { dest, headers, uri_args } = routeResult;
|
const { dest, query, headers } = routeResult;
|
||||||
|
|
||||||
// Set any headers defined in the matched `route` config
|
// Set any headers defined in the matched `route` config
|
||||||
for (const [name, value] of Object.entries(headers)) {
|
for (const [name, value] of Object.entries(headers)) {
|
||||||
@@ -1775,10 +1776,11 @@ export default class DevServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.setResponseHeaders(res, requestId);
|
this.setResponseHeaders(res, requestId);
|
||||||
const origUrl = url.parse(req.url || '/', true);
|
const origUrl = url.parse(req.url || '/');
|
||||||
delete origUrl.search;
|
const origQuery = parseQueryString(origUrl.search);
|
||||||
origUrl.pathname = dest;
|
origUrl.pathname = dest;
|
||||||
Object.assign(origUrl.query, uri_args);
|
Object.assign(origQuery, query);
|
||||||
|
origUrl.search = formatQueryString(origQuery);
|
||||||
req.url = url.format(origUrl);
|
req.url = url.format(origUrl);
|
||||||
return proxyPass(req, res, upstream, this, requestId, false);
|
return proxyPass(req, res, upstream, this, requestId, false);
|
||||||
}
|
}
|
||||||
@@ -1800,10 +1802,11 @@ export default class DevServer {
|
|||||||
Array.isArray(buildResult.routes) &&
|
Array.isArray(buildResult.routes) &&
|
||||||
buildResult.routes.length > 0
|
buildResult.routes.length > 0
|
||||||
) {
|
) {
|
||||||
const origUrl = url.parse(req.url || '/', true);
|
const origUrl = url.parse(req.url || '/');
|
||||||
delete origUrl.search;
|
const origQuery = parseQueryString(origUrl.search);
|
||||||
origUrl.pathname = dest;
|
origUrl.pathname = dest;
|
||||||
Object.assign(origUrl.query, uri_args);
|
Object.assign(origQuery, query);
|
||||||
|
origUrl.search = formatQueryString(origQuery);
|
||||||
const newUrl = url.format(origUrl);
|
const newUrl = url.format(origUrl);
|
||||||
debug(
|
debug(
|
||||||
`Checking build result's ${buildResult.routes.length} \`routes\` to match ${newUrl}`
|
`Checking build result's ${buildResult.routes.length} \`routes\` to match ${newUrl}`
|
||||||
@@ -1899,11 +1902,13 @@ export default class DevServer {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Mix in the routing based query parameters
|
// Mix in the routing based query parameters
|
||||||
const parsed = url.parse(req.url || '/', true);
|
const origUrl = url.parse(req.url || '/');
|
||||||
Object.assign(parsed.query, uri_args);
|
const origQuery = parseQueryString(origUrl.search);
|
||||||
|
Object.assign(origQuery, query);
|
||||||
|
origUrl.search = formatQueryString(origQuery);
|
||||||
req.url = url.format({
|
req.url = url.format({
|
||||||
pathname: parsed.pathname,
|
pathname: origUrl.pathname,
|
||||||
query: parsed.query,
|
search: origUrl.search,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add the Vercel platform proxy request headers
|
// Add the Vercel platform proxy request headers
|
||||||
@@ -2019,11 +2024,13 @@ export default class DevServer {
|
|||||||
requestId = generateRequestId(this.podId, true);
|
requestId = generateRequestId(this.podId, true);
|
||||||
|
|
||||||
// Mix the `routes` result dest query params into the req path
|
// Mix the `routes` result dest query params into the req path
|
||||||
const parsed = url.parse(req.url || '/', true);
|
const origUrl = url.parse(req.url || '/');
|
||||||
Object.assign(parsed.query, uri_args);
|
const origQuery = parseQueryString(origUrl.search);
|
||||||
|
Object.assign(origQuery, query);
|
||||||
|
origUrl.search = formatQueryString(origQuery);
|
||||||
const path = url.format({
|
const path = url.format({
|
||||||
pathname: parsed.pathname,
|
pathname: origUrl.pathname,
|
||||||
query: parsed.query,
|
search: origUrl.search,
|
||||||
});
|
});
|
||||||
|
|
||||||
const body = await rawBody(req);
|
const body = await rawBody(req);
|
||||||
@@ -2210,7 +2217,10 @@ export default class DevServer {
|
|||||||
// Because of child process 'pipe' below, isTTY will be false.
|
// Because of child process 'pipe' below, isTTY will be false.
|
||||||
// Most frameworks use `chalk`/`supports-color` so we enable it anyway.
|
// Most frameworks use `chalk`/`supports-color` so we enable it anyway.
|
||||||
FORCE_COLOR: process.stdout.isTTY ? '1' : '0',
|
FORCE_COLOR: process.stdout.isTTY ? '1' : '0',
|
||||||
...(this.frameworkSlug === 'create-react-app' ? { BROWSER: 'none' } : {}),
|
// Prevent framework dev servers from automatically opening a web
|
||||||
|
// browser window, since it will not be the port that `vc dev`
|
||||||
|
// is listening on and thus will be missing Vercel features.
|
||||||
|
BROWSER: 'none',
|
||||||
...process.env,
|
...process.env,
|
||||||
...this.envConfigs.allEnv,
|
...this.envConfigs.allEnv,
|
||||||
PORT: `${port}`,
|
PORT: `${port}`,
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ export { VercelConfig };
|
|||||||
export interface DevServerOptions {
|
export interface DevServerOptions {
|
||||||
output: Output;
|
output: Output;
|
||||||
devCommand?: string;
|
devCommand?: string;
|
||||||
frameworkSlug?: string;
|
|
||||||
projectSettings?: ProjectSettings;
|
projectSettings?: ProjectSettings;
|
||||||
systemEnvValues?: string[];
|
systemEnvValues?: string[];
|
||||||
projectEnvs?: ProjectEnvVariable[];
|
projectEnvs?: ProjectEnvVariable[];
|
||||||
@@ -146,8 +145,8 @@ export interface RouteResult {
|
|||||||
status?: number;
|
status?: number;
|
||||||
// "headers": <object of the added response header values>
|
// "headers": <object of the added response header values>
|
||||||
headers: HttpHeadersConfig;
|
headers: HttpHeadersConfig;
|
||||||
// "uri_args": <object (key=value) list of new uri args to be passed along to dest >
|
// "query": <object (key=values) of new uri args to be passed along to dest>
|
||||||
uri_args?: { [key: string]: any };
|
query?: Record<string, string[]>;
|
||||||
// "matched_route": <object of the route spec that matched>
|
// "matched_route": <object of the route spec that matched>
|
||||||
matched_route?: Route;
|
matched_route?: Route;
|
||||||
// "matched_route_idx": <integer of the index of the route matched>
|
// "matched_route_idx": <integer of the index of the route matched>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ type LinkResult = {
|
|||||||
org: Org;
|
org: Org;
|
||||||
project: Project;
|
project: Project;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function ensureLink(
|
export async function ensureLink(
|
||||||
commandName: string,
|
commandName: string,
|
||||||
client: Client,
|
client: Client,
|
||||||
|
|||||||
@@ -152,9 +152,7 @@ export class SourceNotFound extends NowError<'SOURCE_NOT_FOUND', {}> {
|
|||||||
super({
|
super({
|
||||||
code: 'SOURCE_NOT_FOUND',
|
code: 'SOURCE_NOT_FOUND',
|
||||||
meta: {},
|
meta: {},
|
||||||
message: `Not able to purchase. Please add a payment method using ${getCommandName(
|
message: `Not able to purchase. Please add a payment method using the dashboard.`,
|
||||||
`billing add`
|
|
||||||
)}.`,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,22 @@ import { Org } from '../../types';
|
|||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import link from '../output/link';
|
import link from '../output/link';
|
||||||
import { isAPIError } from '../errors-ts';
|
import { isAPIError } from '../errors-ts';
|
||||||
|
import { Output } from '../output';
|
||||||
|
import { Dictionary } from '@vercel/client';
|
||||||
|
|
||||||
|
export interface RepoInfo {
|
||||||
|
url: string;
|
||||||
|
provider: string;
|
||||||
|
org: string;
|
||||||
|
repo: string;
|
||||||
|
}
|
||||||
|
|
||||||
export async function disconnectGitProvider(
|
export async function disconnectGitProvider(
|
||||||
client: Client,
|
client: Client,
|
||||||
org: Org,
|
org: Org,
|
||||||
projectId: string
|
projectId: string
|
||||||
) {
|
) {
|
||||||
const fetchUrl = `/v4/projects/${projectId}/link?${stringify({
|
const fetchUrl = `/v9/projects/${projectId}/link?${stringify({
|
||||||
teamId: org.type === 'team' ? org.id : undefined,
|
teamId: org.type === 'team' ? org.id : undefined,
|
||||||
})}`;
|
})}`;
|
||||||
return client.fetch(fetchUrl, {
|
return client.fetch(fetchUrl, {
|
||||||
@@ -28,7 +37,7 @@ export async function connectGitProvider(
|
|||||||
type: string,
|
type: string,
|
||||||
repo: string
|
repo: string
|
||||||
) {
|
) {
|
||||||
const fetchUrl = `/v4/projects/${projectId}/link?${stringify({
|
const fetchUrl = `/v9/projects/${projectId}/link?${stringify({
|
||||||
teamId: org.type === 'team' ? org.id : undefined,
|
teamId: org.type === 'team' ? org.id : undefined,
|
||||||
})}`;
|
})}`;
|
||||||
try {
|
try {
|
||||||
@@ -43,22 +52,21 @@ export async function connectGitProvider(
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
if (isAPIError(err)) {
|
const apiError = isAPIError(err);
|
||||||
if (
|
if (
|
||||||
err.meta?.action === 'Install GitHub App' ||
|
apiError &&
|
||||||
err.code === 'repo_not_found'
|
(err.action === 'Install GitHub App' || err.code === 'repo_not_found')
|
||||||
) {
|
) {
|
||||||
client.output.error(
|
client.output.error(
|
||||||
`Failed to link ${chalk.cyan(
|
`Failed to link ${chalk.cyan(
|
||||||
repo
|
repo
|
||||||
)}. Make sure there aren't any typos and that you have access to the repository if it's private.`
|
)}. Make sure there aren't any typos and that you have access to the repository if it's private.`
|
||||||
);
|
);
|
||||||
} else if (err.action === 'Add a Login Connection') {
|
} else if (apiError && err.action === 'Add a Login Connection') {
|
||||||
client.output.error(
|
client.output.error(
|
||||||
err.message.replace(repo, chalk.cyan(repo)) +
|
err.message.replace(repo, chalk.cyan(repo)) +
|
||||||
`\nVisit ${link(err.link)} for more information.`
|
`\nVisit ${link(err.link)} for more information.`
|
||||||
);
|
);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
client.output.error(
|
client.output.error(
|
||||||
`Failed to connect the ${formatProvider(
|
`Failed to connect the ${formatProvider(
|
||||||
@@ -83,15 +91,13 @@ export function formatProvider(type: string): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseRepoUrl(originUrl: string): {
|
export function parseRepoUrl(originUrl: string): RepoInfo | null {
|
||||||
provider: string;
|
|
||||||
org: string;
|
|
||||||
repo: string;
|
|
||||||
} | null {
|
|
||||||
const isSSH = originUrl.startsWith('git@');
|
const isSSH = originUrl.startsWith('git@');
|
||||||
// Matches all characters between (// or @) and (.com or .org)
|
// Matches all characters between (// or @) and (.com or .org)
|
||||||
// eslint-disable-next-line prefer-named-capture-group
|
// eslint-disable-next-line prefer-named-capture-group
|
||||||
const provider = /(?<=(\/\/|@)).*(?=(\.com|\.org))/.exec(originUrl);
|
const provider =
|
||||||
|
/(?<=(\/\/|@)).*(?=(\.com|\.org))/.exec(originUrl)?.[0] ||
|
||||||
|
originUrl.replace('www.', '').split('.')[0];
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -104,8 +110,8 @@ export function parseRepoUrl(originUrl: string): {
|
|||||||
repo = originUrl.split('/')[1]?.replace('.git', '');
|
repo = originUrl.split('/')[1]?.replace('.git', '');
|
||||||
} else {
|
} else {
|
||||||
// Assume https:// or git://
|
// Assume https:// or git://
|
||||||
org = originUrl.split('/')[3];
|
org = originUrl.replace('//', '').split('/')[1];
|
||||||
repo = originUrl.split('/')[4]?.replace('.git', '');
|
repo = originUrl.replace('//', '').split('/')[2]?.replace('.git', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!org || !repo) {
|
if (!org || !repo) {
|
||||||
@@ -113,8 +119,17 @@ export function parseRepoUrl(originUrl: string): {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
provider: provider[0],
|
url: originUrl,
|
||||||
|
provider,
|
||||||
org,
|
org,
|
||||||
repo,
|
repo,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
export function printRemoteUrls(
|
||||||
|
output: Output,
|
||||||
|
remoteUrls: Dictionary<string>
|
||||||
|
) {
|
||||||
|
for (const [name, url] of Object.entries(remoteUrls)) {
|
||||||
|
output.print(` • ${name}: ${chalk.cyan(url)}\n`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ import printIndications from './print-indications';
|
|||||||
import { GitMetadata, Org } from '../types';
|
import { GitMetadata, Org } from '../types';
|
||||||
import { VercelConfig } from './dev/types';
|
import { VercelConfig } from './dev/types';
|
||||||
import Client, { FetchOptions, isJSONObject } from './client';
|
import Client, { FetchOptions, isJSONObject } from './client';
|
||||||
import { Dictionary } from '@vercel/client';
|
import { ArchiveFormat, Dictionary } from '@vercel/client';
|
||||||
|
|
||||||
export interface NowOptions {
|
export interface NowOptions {
|
||||||
client: Client;
|
client: Client;
|
||||||
@@ -131,6 +131,7 @@ export default class Now extends EventEmitter {
|
|||||||
}: CreateOptions,
|
}: CreateOptions,
|
||||||
org: Org,
|
org: Org,
|
||||||
isSettingUpProject: boolean,
|
isSettingUpProject: boolean,
|
||||||
|
archive?: ArchiveFormat,
|
||||||
cwd?: string
|
cwd?: string
|
||||||
) {
|
) {
|
||||||
let hashes: any = {};
|
let hashes: any = {};
|
||||||
@@ -168,6 +169,7 @@ export default class Now extends EventEmitter {
|
|||||||
org,
|
org,
|
||||||
projectName: name,
|
projectName: name,
|
||||||
isSettingUpProject,
|
isSettingUpProject,
|
||||||
|
archive,
|
||||||
skipAutoDetectionConfirmation,
|
skipAutoDetectionConfirmation,
|
||||||
cwd,
|
cwd,
|
||||||
prebuilt,
|
prebuilt,
|
||||||
@@ -330,7 +332,8 @@ export default class Now extends EventEmitter {
|
|||||||
|
|
||||||
async list(
|
async list(
|
||||||
app?: string,
|
app?: string,
|
||||||
{ version = 4, meta = {}, nextTimestamp }: ListOptions = {}
|
{ version = 4, meta = {}, nextTimestamp }: ListOptions = {},
|
||||||
|
prod?: boolean
|
||||||
) {
|
) {
|
||||||
const fetchRetry = async (url: string, options: FetchOptions = {}) => {
|
const fetchRetry = async (url: string, options: FetchOptions = {}) => {
|
||||||
return this.retry(
|
return this.retry(
|
||||||
@@ -393,6 +396,9 @@ export default class Now extends EventEmitter {
|
|||||||
if (nextTimestamp) {
|
if (nextTimestamp) {
|
||||||
query.set('until', String(nextTimestamp));
|
query.set('until', String(nextTimestamp));
|
||||||
}
|
}
|
||||||
|
if (prod) {
|
||||||
|
query.set('target', 'production');
|
||||||
|
}
|
||||||
|
|
||||||
const response = await fetchRetry(`/v${version}/now/deployments?${query}`);
|
const response = await fetchRetry(`/v${version}/now/deployments?${query}`);
|
||||||
return response;
|
return response;
|
||||||
|
|||||||
107
packages/cli/src/util/link/add-git-connection.ts
Normal file
107
packages/cli/src/util/link/add-git-connection.ts
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
import { Dictionary } from '@vercel/client';
|
||||||
|
import { parseRepoUrl } from '../git/connect-git-provider';
|
||||||
|
import Client from '../client';
|
||||||
|
import { Org, Project, ProjectSettings } from '../../types';
|
||||||
|
import { handleOptions } from './handle-options';
|
||||||
|
import {
|
||||||
|
promptGitConnectMultipleUrls,
|
||||||
|
promptGitConnectSingleUrl,
|
||||||
|
} from './git-connect-prompts';
|
||||||
|
|
||||||
|
function getProjectSettings(project: Project): ProjectSettings {
|
||||||
|
return {
|
||||||
|
createdAt: project.createdAt,
|
||||||
|
framework: project.framework,
|
||||||
|
devCommand: project.devCommand,
|
||||||
|
installCommand: project.installCommand,
|
||||||
|
buildCommand: project.buildCommand,
|
||||||
|
outputDirectory: project.outputDirectory,
|
||||||
|
rootDirectory: project.rootDirectory,
|
||||||
|
directoryListing: project.directoryListing,
|
||||||
|
nodeVersion: project.nodeVersion,
|
||||||
|
skipGitConnectDuringLink: project.skipGitConnectDuringLink,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function addGitConnection(
|
||||||
|
client: Client,
|
||||||
|
org: Org,
|
||||||
|
project: Project,
|
||||||
|
remoteUrls: Dictionary<string>,
|
||||||
|
settings?: ProjectSettings
|
||||||
|
): Promise<number | void> {
|
||||||
|
if (!settings) {
|
||||||
|
settings = getProjectSettings(project);
|
||||||
|
}
|
||||||
|
if (Object.keys(remoteUrls).length === 1) {
|
||||||
|
return addSingleGitRemote(
|
||||||
|
client,
|
||||||
|
org,
|
||||||
|
project,
|
||||||
|
remoteUrls,
|
||||||
|
settings || project
|
||||||
|
);
|
||||||
|
} else if (Object.keys(remoteUrls).length > 1 && !project.link) {
|
||||||
|
return addMultipleGitRemotes(
|
||||||
|
client,
|
||||||
|
org,
|
||||||
|
project,
|
||||||
|
remoteUrls,
|
||||||
|
settings || project
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addSingleGitRemote(
|
||||||
|
client: Client,
|
||||||
|
org: Org,
|
||||||
|
project: Project,
|
||||||
|
remoteUrls: Dictionary<string>,
|
||||||
|
settings: ProjectSettings
|
||||||
|
) {
|
||||||
|
const [remoteName, remoteUrl] = Object.entries(remoteUrls)[0];
|
||||||
|
const repoInfo = parseRepoUrl(remoteUrl);
|
||||||
|
if (!repoInfo) {
|
||||||
|
client.output.debug(`Could not parse repo url ${repoInfo}.`);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
const { org: parsedOrg, repo, provider } = repoInfo;
|
||||||
|
const alreadyLinked =
|
||||||
|
project.link &&
|
||||||
|
project.link.org === parsedOrg &&
|
||||||
|
project.link.repo === repo &&
|
||||||
|
project.link.type === provider;
|
||||||
|
if (alreadyLinked) {
|
||||||
|
client.output.debug('Project already linked. Skipping...');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const replace =
|
||||||
|
project.link &&
|
||||||
|
(project.link.org !== parsedOrg ||
|
||||||
|
project.link.repo !== repo ||
|
||||||
|
project.link.type !== provider);
|
||||||
|
const shouldConnect = await promptGitConnectSingleUrl(
|
||||||
|
client,
|
||||||
|
project,
|
||||||
|
remoteName,
|
||||||
|
remoteUrl,
|
||||||
|
replace
|
||||||
|
);
|
||||||
|
return handleOptions(shouldConnect, client, org, project, settings, repoInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addMultipleGitRemotes(
|
||||||
|
client: Client,
|
||||||
|
org: Org,
|
||||||
|
project: Project,
|
||||||
|
remoteUrls: Dictionary<string>,
|
||||||
|
settings: ProjectSettings
|
||||||
|
) {
|
||||||
|
client.output.log('Found multiple Git remote URLs in Git config.');
|
||||||
|
const remoteUrlOrOptions = await promptGitConnectMultipleUrls(
|
||||||
|
client,
|
||||||
|
remoteUrls
|
||||||
|
);
|
||||||
|
return handleOptions(remoteUrlOrOptions, client, org, project, settings);
|
||||||
|
}
|
||||||
86
packages/cli/src/util/link/git-connect-prompts.ts
Normal file
86
packages/cli/src/util/link/git-connect-prompts.ts
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import { Dictionary } from '@vercel/client';
|
||||||
|
import chalk from 'chalk';
|
||||||
|
import { Project } from '../../types';
|
||||||
|
import Client from '../client';
|
||||||
|
import { formatProvider } from '../git/connect-git-provider';
|
||||||
|
import list from '../input/list';
|
||||||
|
export async function promptGitConnectSingleUrl(
|
||||||
|
client: Client,
|
||||||
|
project: Project,
|
||||||
|
remoteName: string,
|
||||||
|
remoteUrl: string,
|
||||||
|
hasDiffConnectedProvider = false
|
||||||
|
) {
|
||||||
|
const { output } = client;
|
||||||
|
if (hasDiffConnectedProvider) {
|
||||||
|
const currentRepoPath = `${project.link!.org}/${project.link!.repo}`;
|
||||||
|
const currentProvider = project.link!.type;
|
||||||
|
output.print('\n');
|
||||||
|
output.log(
|
||||||
|
`Found Git remote URL ${chalk.cyan(
|
||||||
|
remoteUrl
|
||||||
|
)}, which is different from the connected ${formatProvider(
|
||||||
|
currentProvider
|
||||||
|
)} repository ${chalk.cyan(currentRepoPath)}.`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
output.print('\n');
|
||||||
|
output.log(
|
||||||
|
`Found local Git remote "${remoteName}": ${chalk.cyan(remoteUrl)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return await list(client, {
|
||||||
|
message: hasDiffConnectedProvider
|
||||||
|
? 'Do you want to replace it?'
|
||||||
|
: `Do you want to connect "${remoteName}" to your Vercel project?`,
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
name: 'Yes',
|
||||||
|
value: 'yes',
|
||||||
|
short: 'yes',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'No',
|
||||||
|
value: 'no',
|
||||||
|
short: 'no',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Do not ask again for this project',
|
||||||
|
value: 'opt-out',
|
||||||
|
short: 'no (opt out)',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function promptGitConnectMultipleUrls(
|
||||||
|
client: Client,
|
||||||
|
remoteUrls: Dictionary<string>
|
||||||
|
) {
|
||||||
|
const staticOptions = [
|
||||||
|
{
|
||||||
|
name: 'No',
|
||||||
|
value: 'no',
|
||||||
|
short: 'no',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Do not ask again for this project',
|
||||||
|
value: 'opt-out',
|
||||||
|
short: 'no (opt out)',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
let choices = [];
|
||||||
|
for (const url of Object.values(remoteUrls)) {
|
||||||
|
choices.push({
|
||||||
|
name: url,
|
||||||
|
value: url,
|
||||||
|
short: url,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
choices = choices.concat(staticOptions);
|
||||||
|
|
||||||
|
return await list(client, {
|
||||||
|
message: 'Do you want to connect a Git repository to your Vercel project?',
|
||||||
|
choices,
|
||||||
|
});
|
||||||
|
}
|
||||||
98
packages/cli/src/util/link/handle-options.ts
Normal file
98
packages/cli/src/util/link/handle-options.ts
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import chalk from 'chalk';
|
||||||
|
import { Org, Project, ProjectSettings } from '../../types';
|
||||||
|
import Client from '../client';
|
||||||
|
import {
|
||||||
|
connectGitProvider,
|
||||||
|
disconnectGitProvider,
|
||||||
|
formatProvider,
|
||||||
|
RepoInfo,
|
||||||
|
parseRepoUrl,
|
||||||
|
} from '../git/connect-git-provider';
|
||||||
|
import { Output } from '../output';
|
||||||
|
import { getCommandName } from '../pkg-name';
|
||||||
|
import updateProject from '../projects/update-project';
|
||||||
|
|
||||||
|
export async function handleOptions(
|
||||||
|
option: string,
|
||||||
|
client: Client,
|
||||||
|
org: Org,
|
||||||
|
project: Project,
|
||||||
|
settings: ProjectSettings,
|
||||||
|
repoInfo?: RepoInfo
|
||||||
|
) {
|
||||||
|
const { output } = client;
|
||||||
|
if (option === 'no') {
|
||||||
|
skip(output);
|
||||||
|
return;
|
||||||
|
} else if (option === 'opt-out') {
|
||||||
|
optOut(client, project, settings);
|
||||||
|
return;
|
||||||
|
} else if (option !== '') {
|
||||||
|
// Option is "yes" or a URL
|
||||||
|
|
||||||
|
// Ensure parsed url exists
|
||||||
|
if (!repoInfo) {
|
||||||
|
const _repoInfo = parseRepoUrl(option);
|
||||||
|
if (!_repoInfo) {
|
||||||
|
output.debug(`Could not parse repo url ${option}.`);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
repoInfo = _repoInfo;
|
||||||
|
}
|
||||||
|
return connect(client, org, project, repoInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function optOut(
|
||||||
|
client: Client,
|
||||||
|
project: Project,
|
||||||
|
settings: ProjectSettings
|
||||||
|
) {
|
||||||
|
settings.skipGitConnectDuringLink = true;
|
||||||
|
await updateProject(client, project.name, settings);
|
||||||
|
client.output
|
||||||
|
.log(`Opted out. You can re-enable this prompt by visiting the Settings > Git page on the
|
||||||
|
dashboard for this Project.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function skip(output: Output) {
|
||||||
|
output.log('Skipping...');
|
||||||
|
output.log(
|
||||||
|
`You can connect a Git repository in the future by running ${getCommandName(
|
||||||
|
'git connect'
|
||||||
|
)}.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function connect(
|
||||||
|
client: Client,
|
||||||
|
org: Org,
|
||||||
|
project: Project,
|
||||||
|
repoInfo: RepoInfo
|
||||||
|
): Promise<number | void> {
|
||||||
|
const { output } = client;
|
||||||
|
const { provider, org: parsedOrg, repo } = repoInfo;
|
||||||
|
const repoPath = `${parsedOrg}/${repo}`;
|
||||||
|
|
||||||
|
output.log('Connecting...');
|
||||||
|
|
||||||
|
if (project.link) {
|
||||||
|
await disconnectGitProvider(client, org, project.id);
|
||||||
|
}
|
||||||
|
const connect = await connectGitProvider(
|
||||||
|
client,
|
||||||
|
org,
|
||||||
|
project.id,
|
||||||
|
provider,
|
||||||
|
repoPath
|
||||||
|
);
|
||||||
|
if (connect !== 1) {
|
||||||
|
output.log(
|
||||||
|
`Connected ${formatProvider(provider)} repository ${chalk.cyan(
|
||||||
|
repoPath
|
||||||
|
)}!`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return connect;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,8 @@ import { EmojiLabel } from '../emoji';
|
|||||||
import createDeploy from '../deploy/create-deploy';
|
import createDeploy from '../deploy/create-deploy';
|
||||||
import Now, { CreateOptions } from '../index';
|
import Now, { CreateOptions } from '../index';
|
||||||
import { isAPIError } from '../errors-ts';
|
import { isAPIError } from '../errors-ts';
|
||||||
|
import { getRemoteUrls } from '../create-git-meta';
|
||||||
|
import { addGitConnection } from './add-git-connection';
|
||||||
|
|
||||||
export interface SetupAndLinkOptions {
|
export interface SetupAndLinkOptions {
|
||||||
forceDelete?: boolean;
|
forceDelete?: boolean;
|
||||||
@@ -128,6 +130,19 @@ export default async function setupAndLink(
|
|||||||
} else {
|
} else {
|
||||||
const project = projectOrNewProjectName;
|
const project = projectOrNewProjectName;
|
||||||
|
|
||||||
|
const remoteUrls = await getRemoteUrls(join(path, '.git/config'), output);
|
||||||
|
if (remoteUrls && !project.skipGitConnectDuringLink) {
|
||||||
|
const connectGit = await addGitConnection(
|
||||||
|
client,
|
||||||
|
org,
|
||||||
|
project,
|
||||||
|
remoteUrls
|
||||||
|
);
|
||||||
|
if (typeof connectGit === 'number') {
|
||||||
|
return { status: 'error', exitCode: connectGit };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await linkFolderToProject(
|
await linkFolderToProject(
|
||||||
output,
|
output,
|
||||||
path,
|
path,
|
||||||
@@ -241,6 +256,21 @@ export default async function setupAndLink(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const project = await createProject(client, newProjectName);
|
const project = await createProject(client, newProjectName);
|
||||||
|
|
||||||
|
const remoteUrls = await getRemoteUrls(join(path, '.git/config'), output);
|
||||||
|
if (remoteUrls) {
|
||||||
|
const connectGit = await addGitConnection(
|
||||||
|
client,
|
||||||
|
org,
|
||||||
|
project,
|
||||||
|
remoteUrls,
|
||||||
|
settings
|
||||||
|
);
|
||||||
|
if (typeof connectGit === 'number') {
|
||||||
|
return { status: 'error', exitCode: connectGit };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await updateProject(client, project.id, settings);
|
await updateProject(client, project.id, settings);
|
||||||
Object.assign(project, settings);
|
Object.assign(project, settings);
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export default async function createProject(
|
|||||||
) {
|
) {
|
||||||
const project = await client.fetch<Project>('/v1/projects', {
|
const project = await client.fetch<Project>('/v1/projects', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({ name: projectName }),
|
body: { name: projectName },
|
||||||
});
|
});
|
||||||
return project;
|
return project;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Client from '../client';
|
import Client from '../client';
|
||||||
import { ProjectSettings } from '../../types';
|
import type { JSONObject, ProjectSettings } from '../../types';
|
||||||
|
|
||||||
interface ProjectSettingsResponse extends ProjectSettings {
|
interface ProjectSettingsResponse extends ProjectSettings {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -13,11 +13,14 @@ export default async function updateProject(
|
|||||||
prjNameOrId: string,
|
prjNameOrId: string,
|
||||||
settings: ProjectSettings
|
settings: ProjectSettings
|
||||||
) {
|
) {
|
||||||
|
// `ProjectSettings` is technically compatible with JSONObject
|
||||||
|
const body = settings as JSONObject;
|
||||||
|
|
||||||
const res = await client.fetch<ProjectSettingsResponse>(
|
const res = await client.fetch<ProjectSettingsResponse>(
|
||||||
`/v2/projects/${encodeURIComponent(prjNameOrId)}`,
|
`/v2/projects/${encodeURIComponent(prjNameOrId)}`,
|
||||||
{
|
{
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
body: JSON.stringify(settings),
|
body,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return res;
|
return res;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import stripAnsi from 'strip-ansi';
|
||||||
|
|
||||||
export default function strlen(str: string) {
|
export default function strlen(str: string) {
|
||||||
return str.replace(/\u001b[^m]*m/g, '').length;
|
return stripAnsi(str).length;
|
||||||
}
|
}
|
||||||
|
|||||||
7
packages/cli/test/dev/fixtures/vite-dev/.gitignore
vendored
Normal file
7
packages/cli/test/dev/fixtures/vite-dev/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
.vercel
|
||||||
|
!public
|
||||||
13
packages/cli/test/dev/fixtures/vite-dev/index.html
Normal file
13
packages/cli/test/dev/fixtures/vite-dev/index.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Vite App</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
16
packages/cli/test/dev/fixtures/vite-dev/package.json
Normal file
16
packages/cli/test/dev/fixtures/vite-dev/package.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite --port $PORT",
|
||||||
|
"build": "vite build",
|
||||||
|
"serve": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"vue": "3.2.37"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-vue": "1.10.2",
|
||||||
|
"@vue/compiler-sfc": "3.2.37",
|
||||||
|
"vite": "2.9.14"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
packages/cli/test/dev/fixtures/vite-dev/public/favicon.ico
Normal file
BIN
packages/cli/test/dev/fixtures/vite-dev/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
22
packages/cli/test/dev/fixtures/vite-dev/src/App.vue
Normal file
22
packages/cli/test/dev/fixtures/vite-dev/src/App.vue
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<template>
|
||||||
|
<img alt="Vue logo" src="./assets/logo.png" />
|
||||||
|
<HelloWorld msg="Hello Vue 3 + Vite" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import HelloWorld from './components/HelloWorld.vue'
|
||||||
|
|
||||||
|
// This starter template is using Vue 3 experimental <script setup> SFCs
|
||||||
|
// Check out https://github.com/vuejs/rfcs/blob/script-setup-2/active-rfcs/0000-script-setup.md
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#app {
|
||||||
|
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
text-align: center;
|
||||||
|
color: #2c3e50;
|
||||||
|
margin-top: 60px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
BIN
packages/cli/test/dev/fixtures/vite-dev/src/assets/logo.png
Normal file
BIN
packages/cli/test/dev/fixtures/vite-dev/src/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
@@ -0,0 +1,33 @@
|
|||||||
|
<template>
|
||||||
|
<h1>{{ msg }}</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a href="https://vitejs.dev/guide/features.html" target="_blank">
|
||||||
|
Vite Documentation
|
||||||
|
</a>
|
||||||
|
|
|
||||||
|
<a href="https://v3.vuejs.org/" target="_blank">Vue 3 Documentation</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<button type="button" @click="state.count++">count is: {{ state.count }}</button>
|
||||||
|
<p>
|
||||||
|
Edit
|
||||||
|
<code>components/HelloWorld.vue</code> to test hot module replacement.
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { defineProps, reactive } from 'vue'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
msg: String
|
||||||
|
})
|
||||||
|
|
||||||
|
const state = reactive({ count: 0 })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
a {
|
||||||
|
color: #42b983;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
4
packages/cli/test/dev/fixtures/vite-dev/src/main.js
Normal file
4
packages/cli/test/dev/fixtures/vite-dev/src/main.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { createApp } from 'vue';
|
||||||
|
import App from './App.vue';
|
||||||
|
|
||||||
|
createApp(App).mount('#app');
|
||||||
7
packages/cli/test/dev/fixtures/vite-dev/vite.config.js
Normal file
7
packages/cli/test/dev/fixtures/vite-dev/vite.config.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import vue from '@vitejs/plugin-vue';
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [vue()],
|
||||||
|
});
|
||||||
359
packages/cli/test/dev/fixtures/vite-dev/yarn.lock
Normal file
359
packages/cli/test/dev/fixtures/vite-dev/yarn.lock
Normal file
@@ -0,0 +1,359 @@
|
|||||||
|
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@babel/parser@^7.16.4":
|
||||||
|
version "7.18.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.11.tgz#68bb07ab3d380affa9a3f96728df07969645d2d9"
|
||||||
|
integrity sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==
|
||||||
|
|
||||||
|
"@esbuild/linux-loong64@0.14.54":
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz#de2a4be678bd4d0d1ffbb86e6de779cde5999028"
|
||||||
|
integrity sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==
|
||||||
|
|
||||||
|
"@vitejs/plugin-vue@1.10.2":
|
||||||
|
version "1.10.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-1.10.2.tgz#d718479e2789d8a94b63e00f23f1898ba239253a"
|
||||||
|
integrity sha512-/QJ0Z9qfhAFtKRY+r57ziY4BSbGUTGsPRMpB/Ron3QPwBZM4OZAZHdTa4a8PafCwU5DTatXG8TMDoP8z+oDqJw==
|
||||||
|
|
||||||
|
"@vue/compiler-core@3.2.37":
|
||||||
|
version "3.2.37"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.37.tgz#b3c42e04c0e0f2c496ff1784e543fbefe91e215a"
|
||||||
|
integrity sha512-81KhEjo7YAOh0vQJoSmAD68wLfYqJvoiD4ulyedzF+OEk/bk6/hx3fTNVfuzugIIaTrOx4PGx6pAiBRe5e9Zmg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/parser" "^7.16.4"
|
||||||
|
"@vue/shared" "3.2.37"
|
||||||
|
estree-walker "^2.0.2"
|
||||||
|
source-map "^0.6.1"
|
||||||
|
|
||||||
|
"@vue/compiler-dom@3.2.37":
|
||||||
|
version "3.2.37"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.37.tgz#10d2427a789e7c707c872da9d678c82a0c6582b5"
|
||||||
|
integrity sha512-yxJLH167fucHKxaqXpYk7x8z7mMEnXOw3G2q62FTkmsvNxu4FQSu5+3UMb+L7fjKa26DEzhrmCxAgFLLIzVfqQ==
|
||||||
|
dependencies:
|
||||||
|
"@vue/compiler-core" "3.2.37"
|
||||||
|
"@vue/shared" "3.2.37"
|
||||||
|
|
||||||
|
"@vue/compiler-sfc@3.2.37":
|
||||||
|
version "3.2.37"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.37.tgz#3103af3da2f40286edcd85ea495dcb35bc7f5ff4"
|
||||||
|
integrity sha512-+7i/2+9LYlpqDv+KTtWhOZH+pa8/HnX/905MdVmAcI/mPQOBwkHHIzrsEsucyOIZQYMkXUiTkmZq5am/NyXKkg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/parser" "^7.16.4"
|
||||||
|
"@vue/compiler-core" "3.2.37"
|
||||||
|
"@vue/compiler-dom" "3.2.37"
|
||||||
|
"@vue/compiler-ssr" "3.2.37"
|
||||||
|
"@vue/reactivity-transform" "3.2.37"
|
||||||
|
"@vue/shared" "3.2.37"
|
||||||
|
estree-walker "^2.0.2"
|
||||||
|
magic-string "^0.25.7"
|
||||||
|
postcss "^8.1.10"
|
||||||
|
source-map "^0.6.1"
|
||||||
|
|
||||||
|
"@vue/compiler-ssr@3.2.37":
|
||||||
|
version "3.2.37"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.37.tgz#4899d19f3a5fafd61524a9d1aee8eb0505313cff"
|
||||||
|
integrity sha512-7mQJD7HdXxQjktmsWp/J67lThEIcxLemz1Vb5I6rYJHR5vI+lON3nPGOH3ubmbvYGt8xEUaAr1j7/tIFWiEOqw==
|
||||||
|
dependencies:
|
||||||
|
"@vue/compiler-dom" "3.2.37"
|
||||||
|
"@vue/shared" "3.2.37"
|
||||||
|
|
||||||
|
"@vue/reactivity-transform@3.2.37":
|
||||||
|
version "3.2.37"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.37.tgz#0caa47c4344df4ae59f5a05dde2a8758829f8eca"
|
||||||
|
integrity sha512-IWopkKEb+8qpu/1eMKVeXrK0NLw9HicGviJzhJDEyfxTR9e1WtpnnbYkJWurX6WwoFP0sz10xQg8yL8lgskAZg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/parser" "^7.16.4"
|
||||||
|
"@vue/compiler-core" "3.2.37"
|
||||||
|
"@vue/shared" "3.2.37"
|
||||||
|
estree-walker "^2.0.2"
|
||||||
|
magic-string "^0.25.7"
|
||||||
|
|
||||||
|
"@vue/reactivity@3.2.37":
|
||||||
|
version "3.2.37"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.2.37.tgz#5bc3847ac58828e2b78526e08219e0a1089f8848"
|
||||||
|
integrity sha512-/7WRafBOshOc6m3F7plwzPeCu/RCVv9uMpOwa/5PiY1Zz+WLVRWiy0MYKwmg19KBdGtFWsmZ4cD+LOdVPcs52A==
|
||||||
|
dependencies:
|
||||||
|
"@vue/shared" "3.2.37"
|
||||||
|
|
||||||
|
"@vue/runtime-core@3.2.37":
|
||||||
|
version "3.2.37"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.2.37.tgz#7ba7c54bb56e5d70edfc2f05766e1ca8519966e3"
|
||||||
|
integrity sha512-JPcd9kFyEdXLl/i0ClS7lwgcs0QpUAWj+SKX2ZC3ANKi1U4DOtiEr6cRqFXsPwY5u1L9fAjkinIdB8Rz3FoYNQ==
|
||||||
|
dependencies:
|
||||||
|
"@vue/reactivity" "3.2.37"
|
||||||
|
"@vue/shared" "3.2.37"
|
||||||
|
|
||||||
|
"@vue/runtime-dom@3.2.37":
|
||||||
|
version "3.2.37"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.2.37.tgz#002bdc8228fa63949317756fb1e92cdd3f9f4bbd"
|
||||||
|
integrity sha512-HimKdh9BepShW6YozwRKAYjYQWg9mQn63RGEiSswMbW+ssIht1MILYlVGkAGGQbkhSh31PCdoUcfiu4apXJoPw==
|
||||||
|
dependencies:
|
||||||
|
"@vue/runtime-core" "3.2.37"
|
||||||
|
"@vue/shared" "3.2.37"
|
||||||
|
csstype "^2.6.8"
|
||||||
|
|
||||||
|
"@vue/server-renderer@3.2.37":
|
||||||
|
version "3.2.37"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.2.37.tgz#840a29c8dcc29bddd9b5f5ffa22b95c0e72afdfc"
|
||||||
|
integrity sha512-kLITEJvaYgZQ2h47hIzPh2K3jG8c1zCVbp/o/bzQOyvzaKiCquKS7AaioPI28GNxIsE/zSx+EwWYsNxDCX95MA==
|
||||||
|
dependencies:
|
||||||
|
"@vue/compiler-ssr" "3.2.37"
|
||||||
|
"@vue/shared" "3.2.37"
|
||||||
|
|
||||||
|
"@vue/shared@3.2.37":
|
||||||
|
version "3.2.37"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.37.tgz#8e6adc3f2759af52f0e85863dfb0b711ecc5c702"
|
||||||
|
integrity sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw==
|
||||||
|
|
||||||
|
csstype@^2.6.8:
|
||||||
|
version "2.6.17"
|
||||||
|
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.17.tgz#4cf30eb87e1d1a005d8b6510f95292413f6a1c0e"
|
||||||
|
integrity sha512-u1wmTI1jJGzCJzWndZo8mk4wnPTZd1eOIYTYvuEyOQGfmDl3TrabCCfKnOC86FZwW/9djqTl933UF/cS425i9A==
|
||||||
|
|
||||||
|
esbuild-android-64@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz#505f41832884313bbaffb27704b8bcaa2d8616be"
|
||||||
|
integrity sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==
|
||||||
|
|
||||||
|
esbuild-android-arm64@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz#8ce69d7caba49646e009968fe5754a21a9871771"
|
||||||
|
integrity sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==
|
||||||
|
|
||||||
|
esbuild-darwin-64@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz#24ba67b9a8cb890a3c08d9018f887cc221cdda25"
|
||||||
|
integrity sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==
|
||||||
|
|
||||||
|
esbuild-darwin-arm64@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz#3f7cdb78888ee05e488d250a2bdaab1fa671bf73"
|
||||||
|
integrity sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==
|
||||||
|
|
||||||
|
esbuild-freebsd-64@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz#09250f997a56ed4650f3e1979c905ffc40bbe94d"
|
||||||
|
integrity sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==
|
||||||
|
|
||||||
|
esbuild-freebsd-arm64@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz#bafb46ed04fc5f97cbdb016d86947a79579f8e48"
|
||||||
|
integrity sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==
|
||||||
|
|
||||||
|
esbuild-linux-32@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz#e2a8c4a8efdc355405325033fcebeb941f781fe5"
|
||||||
|
integrity sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==
|
||||||
|
|
||||||
|
esbuild-linux-64@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz#de5fdba1c95666cf72369f52b40b03be71226652"
|
||||||
|
integrity sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==
|
||||||
|
|
||||||
|
esbuild-linux-arm64@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz#dae4cd42ae9787468b6a5c158da4c84e83b0ce8b"
|
||||||
|
integrity sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==
|
||||||
|
|
||||||
|
esbuild-linux-arm@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz#a2c1dff6d0f21dbe8fc6998a122675533ddfcd59"
|
||||||
|
integrity sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==
|
||||||
|
|
||||||
|
esbuild-linux-mips64le@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz#d9918e9e4cb972f8d6dae8e8655bf9ee131eda34"
|
||||||
|
integrity sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==
|
||||||
|
|
||||||
|
esbuild-linux-ppc64le@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz#3f9a0f6d41073fb1a640680845c7de52995f137e"
|
||||||
|
integrity sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==
|
||||||
|
|
||||||
|
esbuild-linux-riscv64@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz#618853c028178a61837bc799d2013d4695e451c8"
|
||||||
|
integrity sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==
|
||||||
|
|
||||||
|
esbuild-linux-s390x@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz#d1885c4c5a76bbb5a0fe182e2c8c60eb9e29f2a6"
|
||||||
|
integrity sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==
|
||||||
|
|
||||||
|
esbuild-netbsd-64@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz#69ae917a2ff241b7df1dbf22baf04bd330349e81"
|
||||||
|
integrity sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==
|
||||||
|
|
||||||
|
esbuild-openbsd-64@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz#db4c8495287a350a6790de22edea247a57c5d47b"
|
||||||
|
integrity sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==
|
||||||
|
|
||||||
|
esbuild-sunos-64@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz#54287ee3da73d3844b721c21bc80c1dc7e1bf7da"
|
||||||
|
integrity sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==
|
||||||
|
|
||||||
|
esbuild-windows-32@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz#f8aaf9a5667630b40f0fb3aa37bf01bbd340ce31"
|
||||||
|
integrity sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==
|
||||||
|
|
||||||
|
esbuild-windows-64@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz#bf54b51bd3e9b0f1886ffdb224a4176031ea0af4"
|
||||||
|
integrity sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==
|
||||||
|
|
||||||
|
esbuild-windows-arm64@0.14.54:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz#937d15675a15e4b0e4fafdbaa3a01a776a2be982"
|
||||||
|
integrity sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==
|
||||||
|
|
||||||
|
esbuild@^0.14.27:
|
||||||
|
version "0.14.54"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.54.tgz#8b44dcf2b0f1a66fc22459943dccf477535e9aa2"
|
||||||
|
integrity sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==
|
||||||
|
optionalDependencies:
|
||||||
|
"@esbuild/linux-loong64" "0.14.54"
|
||||||
|
esbuild-android-64 "0.14.54"
|
||||||
|
esbuild-android-arm64 "0.14.54"
|
||||||
|
esbuild-darwin-64 "0.14.54"
|
||||||
|
esbuild-darwin-arm64 "0.14.54"
|
||||||
|
esbuild-freebsd-64 "0.14.54"
|
||||||
|
esbuild-freebsd-arm64 "0.14.54"
|
||||||
|
esbuild-linux-32 "0.14.54"
|
||||||
|
esbuild-linux-64 "0.14.54"
|
||||||
|
esbuild-linux-arm "0.14.54"
|
||||||
|
esbuild-linux-arm64 "0.14.54"
|
||||||
|
esbuild-linux-mips64le "0.14.54"
|
||||||
|
esbuild-linux-ppc64le "0.14.54"
|
||||||
|
esbuild-linux-riscv64 "0.14.54"
|
||||||
|
esbuild-linux-s390x "0.14.54"
|
||||||
|
esbuild-netbsd-64 "0.14.54"
|
||||||
|
esbuild-openbsd-64 "0.14.54"
|
||||||
|
esbuild-sunos-64 "0.14.54"
|
||||||
|
esbuild-windows-32 "0.14.54"
|
||||||
|
esbuild-windows-64 "0.14.54"
|
||||||
|
esbuild-windows-arm64 "0.14.54"
|
||||||
|
|
||||||
|
estree-walker@^2.0.2:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
|
||||||
|
integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
|
||||||
|
|
||||||
|
fsevents@~2.3.2:
|
||||||
|
version "2.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
||||||
|
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
||||||
|
|
||||||
|
function-bind@^1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||||
|
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
|
||||||
|
|
||||||
|
has@^1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
|
||||||
|
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
|
||||||
|
dependencies:
|
||||||
|
function-bind "^1.1.1"
|
||||||
|
|
||||||
|
is-core-module@^2.9.0:
|
||||||
|
version "2.10.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed"
|
||||||
|
integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==
|
||||||
|
dependencies:
|
||||||
|
has "^1.0.3"
|
||||||
|
|
||||||
|
magic-string@^0.25.7:
|
||||||
|
version "0.25.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
|
||||||
|
integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==
|
||||||
|
dependencies:
|
||||||
|
sourcemap-codec "^1.4.4"
|
||||||
|
|
||||||
|
nanoid@^3.3.4:
|
||||||
|
version "3.3.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
|
||||||
|
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
|
||||||
|
|
||||||
|
path-parse@^1.0.7:
|
||||||
|
version "1.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
||||||
|
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
|
||||||
|
|
||||||
|
picocolors@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
|
||||||
|
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
|
||||||
|
|
||||||
|
postcss@^8.1.10, postcss@^8.4.13:
|
||||||
|
version "8.4.16"
|
||||||
|
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.16.tgz#33a1d675fac39941f5f445db0de4db2b6e01d43c"
|
||||||
|
integrity sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==
|
||||||
|
dependencies:
|
||||||
|
nanoid "^3.3.4"
|
||||||
|
picocolors "^1.0.0"
|
||||||
|
source-map-js "^1.0.2"
|
||||||
|
|
||||||
|
resolve@^1.22.0:
|
||||||
|
version "1.22.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
|
||||||
|
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
|
||||||
|
dependencies:
|
||||||
|
is-core-module "^2.9.0"
|
||||||
|
path-parse "^1.0.7"
|
||||||
|
supports-preserve-symlinks-flag "^1.0.0"
|
||||||
|
|
||||||
|
rollup@^2.59.0:
|
||||||
|
version "2.77.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.77.2.tgz#6b6075c55f9cc2040a5912e6e062151e42e2c4e3"
|
||||||
|
integrity sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g==
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
|
source-map-js@^1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
||||||
|
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
||||||
|
|
||||||
|
source-map@^0.6.1:
|
||||||
|
version "0.6.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||||
|
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||||
|
|
||||||
|
sourcemap-codec@^1.4.4:
|
||||||
|
version "1.4.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
|
||||||
|
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
|
||||||
|
|
||||||
|
supports-preserve-symlinks-flag@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
|
||||||
|
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
|
||||||
|
|
||||||
|
vite@2.9.14:
|
||||||
|
version "2.9.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/vite/-/vite-2.9.14.tgz#c438324c6594afd1050df3777da981dee988bb1b"
|
||||||
|
integrity sha512-P/UCjSpSMcE54r4mPak55hWAZPlyfS369svib/gpmz8/01L822lMPOJ/RYW6tLCe1RPvMvOsJ17erf55bKp4Hw==
|
||||||
|
dependencies:
|
||||||
|
esbuild "^0.14.27"
|
||||||
|
postcss "^8.4.13"
|
||||||
|
resolve "^1.22.0"
|
||||||
|
rollup "^2.59.0"
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
|
vue@3.2.37:
|
||||||
|
version "3.2.37"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.37.tgz#da220ccb618d78579d25b06c7c21498ca4e5452e"
|
||||||
|
integrity sha512-bOKEZxrm8Eh+fveCqS1/NkG/n6aMidsI6hahas7pa0w/l7jkbssJVsRhVDs07IdDq7h9KHswZOgItnwJAgtVtQ==
|
||||||
|
dependencies:
|
||||||
|
"@vue/compiler-dom" "3.2.37"
|
||||||
|
"@vue/compiler-sfc" "3.2.37"
|
||||||
|
"@vue/runtime-dom" "3.2.37"
|
||||||
|
"@vue/server-renderer" "3.2.37"
|
||||||
|
"@vue/shared" "3.2.37"
|
||||||
@@ -1045,3 +1045,20 @@ test('[vercel dev] validate rewrites', async () => {
|
|||||||
/Invalid vercel\.json - `rewrites\[0\].destination` should be string/m
|
/Invalid vercel\.json - `rewrites\[0\].destination` should be string/m
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'[vercel dev] should correctly proxy to vite dev',
|
||||||
|
testFixtureStdio(
|
||||||
|
'vite-dev',
|
||||||
|
async (testPath: any) => {
|
||||||
|
const url = '/src/App.vue?vue&type=style&index=0&lang.css';
|
||||||
|
// The first request should return the HTML template
|
||||||
|
await testPath(200, url, /<template>/gm);
|
||||||
|
// The second request should return the HMR JS
|
||||||
|
await testPath(200, url, /__vite__createHotContext/gm);
|
||||||
|
// Home page should always return HTML
|
||||||
|
await testPath(200, '/', /<title>Vite App<\/title>/gm);
|
||||||
|
},
|
||||||
|
{ skipDeploy: true }
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ function testFixtureStdio(
|
|||||||
? ['--scope', process.env.VERCEL_TEAM_ID]
|
? ['--scope', process.env.VERCEL_TEAM_ID]
|
||||||
: []),
|
: []),
|
||||||
'link',
|
'link',
|
||||||
'--confirm',
|
'--yes',
|
||||||
],
|
],
|
||||||
{ cwd, stdio: 'pipe', reject: false }
|
{ cwd, stdio: 'pipe', reject: false }
|
||||||
);
|
);
|
||||||
|
|||||||
1
packages/cli/test/fixtures/unit/commands/deploy/archive/.gitignore
vendored
Normal file
1
packages/cli/test/fixtures/unit/commands/deploy/archive/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
!.vercel
|
||||||
4
packages/cli/test/fixtures/unit/commands/deploy/archive/.vercel/project.json
vendored
Normal file
4
packages/cli/test/fixtures/unit/commands/deploy/archive/.vercel/project.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"orgId": "team_dummy",
|
||||||
|
"projectId": "archive"
|
||||||
|
}
|
||||||
1
packages/cli/test/fixtures/unit/commands/deploy/archive/index.html
vendored
Normal file
1
packages/cli/test/fixtures/unit/commands/deploy/archive/index.html
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<h1>hi</h1>
|
||||||
3
packages/cli/test/fixtures/unit/commands/deploy/archive/style.css
vendored
Normal file
3
packages/cli/test/fixtures/unit/commands/deploy/archive/style.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
body {
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
2
packages/cli/test/fixtures/unit/link-connect-git/multiple-remotes/.gitignore
vendored
Normal file
2
packages/cli/test/fixtures/unit/link-connect-git/multiple-remotes/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
!.vercel
|
||||||
|
.vercel
|
||||||
16
packages/cli/test/fixtures/unit/link-connect-git/multiple-remotes/git/config
generated
vendored
Normal file
16
packages/cli/test/fixtures/unit/link-connect-git/multiple-remotes/git/config
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[core]
|
||||||
|
repositoryformatversion = 0
|
||||||
|
filemode = true
|
||||||
|
bare = false
|
||||||
|
logallrefupdates = true
|
||||||
|
ignorecase = true
|
||||||
|
precomposeunicode = true
|
||||||
|
[remote "origin"]
|
||||||
|
url = https://github.com/user/repo.git
|
||||||
|
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||||
|
[remote "secondary"]
|
||||||
|
url = https://github.com/user2/repo2.git
|
||||||
|
fetch = +refs/heads/*:refs/remotes/secondary/*
|
||||||
|
[remote "gitlab"]
|
||||||
|
url = https://gitlab.com/user/repo.git
|
||||||
|
fetch = +refs/heads/*:refs/remotes/gitlab/*
|
||||||
2
packages/cli/test/fixtures/unit/link-connect-git/single-remote-existing-link/.gitignore
vendored
Normal file
2
packages/cli/test/fixtures/unit/link-connect-git/single-remote-existing-link/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
!.vercel
|
||||||
|
.vercel
|
||||||
13
packages/cli/test/fixtures/unit/link-connect-git/single-remote-existing-link/git/config
generated
vendored
Normal file
13
packages/cli/test/fixtures/unit/link-connect-git/single-remote-existing-link/git/config
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[core]
|
||||||
|
repositoryformatversion = 0
|
||||||
|
filemode = true
|
||||||
|
bare = false
|
||||||
|
logallrefupdates = true
|
||||||
|
ignorecase = true
|
||||||
|
precomposeunicode = true
|
||||||
|
[remote "origin"]
|
||||||
|
url = https://github.com/user2/repo2.git
|
||||||
|
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||||
|
[branch "master"]
|
||||||
|
remote = origin
|
||||||
|
merge = refs/heads/master
|
||||||
2
packages/cli/test/fixtures/unit/link-connect-git/single-remote/.gitignore
vendored
Normal file
2
packages/cli/test/fixtures/unit/link-connect-git/single-remote/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
!.vercel
|
||||||
|
.vercel
|
||||||
13
packages/cli/test/fixtures/unit/link-connect-git/single-remote/git/config
generated
vendored
Normal file
13
packages/cli/test/fixtures/unit/link-connect-git/single-remote/git/config
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[core]
|
||||||
|
repositoryformatversion = 0
|
||||||
|
filemode = true
|
||||||
|
bare = false
|
||||||
|
logallrefupdates = true
|
||||||
|
ignorecase = true
|
||||||
|
precomposeunicode = true
|
||||||
|
[remote "origin"]
|
||||||
|
url = https://github.com/user/repo.git
|
||||||
|
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||||
|
[branch "master"]
|
||||||
|
remote = origin
|
||||||
|
merge = refs/heads/master
|
||||||
2
packages/cli/test/fixtures/unit/vercel-env-pull-delta-quotes/.env
vendored
Normal file
2
packages/cli/test/fixtures/unit/vercel-env-pull-delta-quotes/.env
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
NEW_VAR=testvalue
|
||||||
|
SPECIAL_FLAG=1
|
||||||
2
packages/cli/test/fixtures/unit/vercel-env-pull-delta-quotes/.env.testquotes
vendored
Normal file
2
packages/cli/test/fixtures/unit/vercel-env-pull-delta-quotes/.env.testquotes
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
NEW_VAR="testvalue"
|
||||||
|
SPECIAL_FLAG=1
|
||||||
1
packages/cli/test/fixtures/unit/vercel-env-pull-delta-quotes/.gitignore
vendored
Normal file
1
packages/cli/test/fixtures/unit/vercel-env-pull-delta-quotes/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
!.vercel
|
||||||
4
packages/cli/test/fixtures/unit/vercel-env-pull-delta-quotes/.vercel/project.json
vendored
Normal file
4
packages/cli/test/fixtures/unit/vercel-env-pull-delta-quotes/.vercel/project.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"orgId": "team_dummy",
|
||||||
|
"projectId": "env-pull-delta-quotes"
|
||||||
|
}
|
||||||
@@ -8,7 +8,9 @@ export function readOutputStream(
|
|||||||
let output: string = '';
|
let output: string = '';
|
||||||
let lines = 0;
|
let lines = 0;
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
reject();
|
reject(
|
||||||
|
new Error(`Was waiting for ${length} lines, but only received ${chunks.length}`)
|
||||||
|
);
|
||||||
}, 3000);
|
}, 3000);
|
||||||
|
|
||||||
client.stderr.resume();
|
client.stderr.resume();
|
||||||
|
|||||||
180
packages/cli/test/integration.js
vendored
180
packages/cli/test/integration.js
vendored
@@ -126,7 +126,7 @@ ${stdout}
|
|||||||
async function vcLink(t, projectPath) {
|
async function vcLink(t, projectPath) {
|
||||||
const { exitCode, stderr, stdout } = await execa(
|
const { exitCode, stderr, stdout } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
['link', '--confirm', ...defaultArgs],
|
['link', '--yes', ...defaultArgs],
|
||||||
{
|
{
|
||||||
reject: false,
|
reject: false,
|
||||||
cwd: projectPath,
|
cwd: projectPath,
|
||||||
@@ -658,7 +658,7 @@ test('[vc link] with vercel.json configuration overrides should create a valid d
|
|||||||
|
|
||||||
const { exitCode, stderr, stdout } = await execa(
|
const { exitCode, stderr, stdout } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
['link', '--confirm', ...defaultArgs],
|
['link', '--yes', ...defaultArgs],
|
||||||
{
|
{
|
||||||
reject: false,
|
reject: false,
|
||||||
cwd: directory,
|
cwd: directory,
|
||||||
@@ -683,7 +683,7 @@ test('deploy using only now.json with `redirects` defined', async t => {
|
|||||||
|
|
||||||
const { exitCode, stderr, stdout } = await execa(
|
const { exitCode, stderr, stdout } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
[target, ...defaultArgs, '--confirm'],
|
[target, ...defaultArgs, '--yes'],
|
||||||
{
|
{
|
||||||
reject: false,
|
reject: false,
|
||||||
}
|
}
|
||||||
@@ -703,14 +703,7 @@ test('deploy using --local-config flag v2', async t => {
|
|||||||
|
|
||||||
const { exitCode, stderr, stdout } = await execa(
|
const { exitCode, stderr, stdout } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
[
|
['deploy', target, '--local-config', configPath, ...defaultArgs, '--yes'],
|
||||||
'deploy',
|
|
||||||
target,
|
|
||||||
'--local-config',
|
|
||||||
configPath,
|
|
||||||
...defaultArgs,
|
|
||||||
'--confirm',
|
|
||||||
],
|
|
||||||
{
|
{
|
||||||
reject: false,
|
reject: false,
|
||||||
}
|
}
|
||||||
@@ -747,7 +740,7 @@ test('deploy fails using --local-config flag with non-existent path', async t =>
|
|||||||
'--local-config',
|
'--local-config',
|
||||||
'does-not-exist.json',
|
'does-not-exist.json',
|
||||||
...defaultArgs,
|
...defaultArgs,
|
||||||
'--confirm',
|
'--yes',
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
reject: false,
|
reject: false,
|
||||||
@@ -772,7 +765,7 @@ test('deploy using --local-config flag above target', async t => {
|
|||||||
'--local-config',
|
'--local-config',
|
||||||
'./now-root.json',
|
'./now-root.json',
|
||||||
...defaultArgs,
|
...defaultArgs,
|
||||||
'--confirm',
|
'--yes',
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
cwd: root,
|
cwd: root,
|
||||||
@@ -801,7 +794,7 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
|||||||
async function vcLink() {
|
async function vcLink() {
|
||||||
const { exitCode, stderr, stdout } = await execa(
|
const { exitCode, stderr, stdout } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
['link', '--confirm', ...defaultArgs],
|
['link', '--yes', ...defaultArgs],
|
||||||
{
|
{
|
||||||
reject: false,
|
reject: false,
|
||||||
cwd: target,
|
cwd: target,
|
||||||
@@ -1345,7 +1338,7 @@ test('deploy with metadata containing "=" in the value', async t => {
|
|||||||
|
|
||||||
const { exitCode, stderr, stdout } = await execa(
|
const { exitCode, stderr, stdout } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
[target, ...defaultArgs, '--confirm', '--meta', 'someKey=='],
|
[target, ...defaultArgs, '--yes', '--meta', 'someKey=='],
|
||||||
{ reject: false }
|
{ reject: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1421,7 +1414,7 @@ test('should add secret with hyphen prefix', async t => {
|
|||||||
formatOutput({ stderr: secretCall.stderr, stdout: secretCall.stdout })
|
formatOutput({ stderr: secretCall.stderr, stdout: secretCall.stdout })
|
||||||
);
|
);
|
||||||
|
|
||||||
let targetCall = await execa(binaryPath, [...defaultArgs, '--confirm'], {
|
let targetCall = await execa(binaryPath, [...defaultArgs, '--yes'], {
|
||||||
cwd: target,
|
cwd: target,
|
||||||
reject: false,
|
reject: false,
|
||||||
});
|
});
|
||||||
@@ -1475,7 +1468,7 @@ test('ignore files specified in .nowignore', async t => {
|
|||||||
'--name',
|
'--name',
|
||||||
session,
|
session,
|
||||||
...defaultArgs,
|
...defaultArgs,
|
||||||
'--confirm',
|
'--yes',
|
||||||
];
|
];
|
||||||
const targetCall = await execa(binaryPath, args, {
|
const targetCall = await execa(binaryPath, args, {
|
||||||
cwd: directory,
|
cwd: directory,
|
||||||
@@ -1503,7 +1496,7 @@ test('ignore files specified in .nowignore via allowlist', async t => {
|
|||||||
'--name',
|
'--name',
|
||||||
session,
|
session,
|
||||||
...defaultArgs,
|
...defaultArgs,
|
||||||
'--confirm',
|
'--yes',
|
||||||
];
|
];
|
||||||
const targetCall = await execa(binaryPath, args, {
|
const targetCall = await execa(binaryPath, args, {
|
||||||
cwd: directory,
|
cwd: directory,
|
||||||
@@ -1545,23 +1538,6 @@ test('list the scopes', async t => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('list the payment methods', async t => {
|
|
||||||
const { stdout, stderr, exitCode } = await execa(
|
|
||||||
binaryPath,
|
|
||||||
['billing', 'ls', ...defaultArgs],
|
|
||||||
{
|
|
||||||
reject: false,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log(stderr);
|
|
||||||
console.log(stdout);
|
|
||||||
console.log(exitCode);
|
|
||||||
|
|
||||||
t.is(exitCode, 0);
|
|
||||||
t.true(stdout.startsWith(`> 0 cards found under ${contextName}`));
|
|
||||||
});
|
|
||||||
|
|
||||||
test('domains inspect', async t => {
|
test('domains inspect', async t => {
|
||||||
const domainName = `inspect-${contextName}-${Math.random()
|
const domainName = `inspect-${contextName}-${Math.random()
|
||||||
.toString()
|
.toString()
|
||||||
@@ -1575,7 +1551,7 @@ test('domains inspect', async t => {
|
|||||||
`-V`,
|
`-V`,
|
||||||
`2`,
|
`2`,
|
||||||
`--name=${projectName}`,
|
`--name=${projectName}`,
|
||||||
'--confirm',
|
'--yes',
|
||||||
'--public',
|
'--public',
|
||||||
]);
|
]);
|
||||||
t.is(output.exitCode, 0, formatOutput(output));
|
t.is(output.exitCode, 0, formatOutput(output));
|
||||||
@@ -1708,44 +1684,6 @@ test('try to move an invalid domain', async t => {
|
|||||||
t.is(exitCode, 1);
|
t.is(exitCode, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('try to set default without existing payment method', async t => {
|
|
||||||
const { stderr, stdout, exitCode } = await execa(
|
|
||||||
binaryPath,
|
|
||||||
['billing', 'set-default', ...defaultArgs],
|
|
||||||
{
|
|
||||||
reject: false,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log(stderr);
|
|
||||||
console.log(stdout);
|
|
||||||
console.log(exitCode);
|
|
||||||
|
|
||||||
t.is(exitCode, 0);
|
|
||||||
t.true(stderr.includes('You have no credit cards to choose from'));
|
|
||||||
});
|
|
||||||
|
|
||||||
test('try to remove a non-existing payment method', async t => {
|
|
||||||
const { stderr, stdout, exitCode } = await execa(
|
|
||||||
binaryPath,
|
|
||||||
['billing', 'rm', 'card_d2j32d9382jr928rd', ...defaultArgs],
|
|
||||||
{
|
|
||||||
reject: false,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log(stderr);
|
|
||||||
console.log(stdout);
|
|
||||||
console.log(exitCode);
|
|
||||||
|
|
||||||
t.is(exitCode, 0);
|
|
||||||
t.true(
|
|
||||||
stderr.includes(
|
|
||||||
`You have no credit cards to choose from to delete under ${contextName}`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disabled 2 tests because these temp users don't have certs
|
* Disabled 2 tests because these temp users don't have certs
|
||||||
test('create wildcard alias for deployment', async t => {
|
test('create wildcard alias for deployment', async t => {
|
||||||
@@ -1811,7 +1749,7 @@ test('ensure we render a warning for deployments with no files', async t => {
|
|||||||
'--name',
|
'--name',
|
||||||
session,
|
session,
|
||||||
...defaultArgs,
|
...defaultArgs,
|
||||||
'--confirm',
|
'--yes',
|
||||||
'--force',
|
'--force',
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
@@ -1939,7 +1877,7 @@ test('ensure the `scope` property works with email', async t => {
|
|||||||
session,
|
session,
|
||||||
...defaultArgs,
|
...defaultArgs,
|
||||||
'--force',
|
'--force',
|
||||||
'--confirm',
|
'--yes',
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
reject: false,
|
reject: false,
|
||||||
@@ -1979,7 +1917,7 @@ test('ensure the `scope` property works with username', async t => {
|
|||||||
session,
|
session,
|
||||||
...defaultArgs,
|
...defaultArgs,
|
||||||
'--force',
|
'--force',
|
||||||
'--confirm',
|
'--yes',
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
reject: false,
|
reject: false,
|
||||||
@@ -2012,7 +1950,7 @@ test('try to create a builds deployments with wrong now.json', async t => {
|
|||||||
|
|
||||||
const { stderr, stdout, exitCode } = await execa(
|
const { stderr, stdout, exitCode } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
[directory, '--public', ...defaultArgs, '--confirm'],
|
[directory, '--public', ...defaultArgs, '--yes'],
|
||||||
{
|
{
|
||||||
reject: false,
|
reject: false,
|
||||||
}
|
}
|
||||||
@@ -2037,7 +1975,7 @@ test('try to create a builds deployments with wrong vercel.json', async t => {
|
|||||||
|
|
||||||
const { stderr, stdout, exitCode } = await execa(
|
const { stderr, stdout, exitCode } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
[directory, '--public', ...defaultArgs, '--confirm'],
|
[directory, '--public', ...defaultArgs, '--yes'],
|
||||||
{
|
{
|
||||||
reject: false,
|
reject: false,
|
||||||
}
|
}
|
||||||
@@ -2061,7 +1999,7 @@ test('try to create a builds deployments with wrong `build.env` property', async
|
|||||||
|
|
||||||
const { stderr, stdout, exitCode } = await execa(
|
const { stderr, stdout, exitCode } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
['--public', ...defaultArgs, '--confirm'],
|
['--public', ...defaultArgs, '--yes'],
|
||||||
{
|
{
|
||||||
cwd: directory,
|
cwd: directory,
|
||||||
reject: false,
|
reject: false,
|
||||||
@@ -2093,7 +2031,7 @@ test('create a builds deployments with no actual builds', async t => {
|
|||||||
session,
|
session,
|
||||||
...defaultArgs,
|
...defaultArgs,
|
||||||
'--force',
|
'--force',
|
||||||
'--confirm',
|
'--yes',
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
reject: false,
|
reject: false,
|
||||||
@@ -2120,7 +2058,7 @@ test('create a staging deployment', async t => {
|
|||||||
directory,
|
directory,
|
||||||
'--target=staging',
|
'--target=staging',
|
||||||
...args,
|
...args,
|
||||||
'--confirm',
|
'--yes',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
console.log(targetCall.stderr);
|
console.log(targetCall.stderr);
|
||||||
@@ -2150,7 +2088,7 @@ test('create a production deployment', async t => {
|
|||||||
directory,
|
directory,
|
||||||
'--target=production',
|
'--target=production',
|
||||||
...args,
|
...args,
|
||||||
'--confirm',
|
'--yes',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
console.log(targetCall.stderr);
|
console.log(targetCall.stderr);
|
||||||
@@ -2211,7 +2149,7 @@ test('use build-env', async t => {
|
|||||||
|
|
||||||
const { stdout, stderr, exitCode } = await execa(
|
const { stdout, stderr, exitCode } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
[directory, '--public', ...defaultArgs, '--confirm'],
|
[directory, '--public', ...defaultArgs, '--yes'],
|
||||||
{
|
{
|
||||||
reject: false,
|
reject: false,
|
||||||
}
|
}
|
||||||
@@ -2244,7 +2182,7 @@ test('use `--debug` CLI flag', async t => {
|
|||||||
session,
|
session,
|
||||||
'--debug',
|
'--debug',
|
||||||
...defaultArgs,
|
...defaultArgs,
|
||||||
'--confirm',
|
'--yes',
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
reject: false,
|
reject: false,
|
||||||
@@ -2276,7 +2214,7 @@ test('try to deploy non-existing path', async t => {
|
|||||||
|
|
||||||
const { stderr, stdout, exitCode } = await execa(
|
const { stderr, stdout, exitCode } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
[session, ...defaultArgs, '--confirm'],
|
[session, ...defaultArgs, '--yes'],
|
||||||
{
|
{
|
||||||
reject: false,
|
reject: false,
|
||||||
}
|
}
|
||||||
@@ -2296,7 +2234,7 @@ test('try to deploy with non-existing team', async t => {
|
|||||||
|
|
||||||
const { stderr, stdout, exitCode } = await execa(
|
const { stderr, stdout, exitCode } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
[target, '--scope', session, ...defaultArgs, '--confirm'],
|
[target, '--scope', session, ...defaultArgs, '--yes'],
|
||||||
{
|
{
|
||||||
reject: false,
|
reject: false,
|
||||||
}
|
}
|
||||||
@@ -2434,7 +2372,7 @@ test('try to revert a deployment and assign the automatic aliases', async t => {
|
|||||||
stdout: deploymentUrl,
|
stdout: deploymentUrl,
|
||||||
stderr,
|
stderr,
|
||||||
exitCode,
|
exitCode,
|
||||||
} = await execute([firstDeployment, '--confirm']);
|
} = await execute([firstDeployment, '--yes']);
|
||||||
|
|
||||||
t.is(exitCode, 0, formatOutput({ stderr, stdout: deploymentUrl }));
|
t.is(exitCode, 0, formatOutput({ stderr, stdout: deploymentUrl }));
|
||||||
|
|
||||||
@@ -2455,7 +2393,7 @@ test('try to revert a deployment and assign the automatic aliases', async t => {
|
|||||||
stdout: deploymentUrl,
|
stdout: deploymentUrl,
|
||||||
stderr,
|
stderr,
|
||||||
exitCode,
|
exitCode,
|
||||||
} = await execute([secondDeployment, '--confirm']);
|
} = await execute([secondDeployment, '--yes']);
|
||||||
|
|
||||||
t.is(exitCode, 0, formatOutput({ stderr, stdout: deploymentUrl }));
|
t.is(exitCode, 0, formatOutput({ stderr, stdout: deploymentUrl }));
|
||||||
|
|
||||||
@@ -2478,7 +2416,7 @@ test('try to revert a deployment and assign the automatic aliases', async t => {
|
|||||||
stdout: deploymentUrl,
|
stdout: deploymentUrl,
|
||||||
stderr,
|
stderr,
|
||||||
exitCode,
|
exitCode,
|
||||||
} = await execute([firstDeployment, '--confirm']);
|
} = await execute([firstDeployment, '--yes']);
|
||||||
|
|
||||||
t.is(exitCode, 0, formatOutput({ stderr, stdout: deploymentUrl }));
|
t.is(exitCode, 0, formatOutput({ stderr, stdout: deploymentUrl }));
|
||||||
|
|
||||||
@@ -2560,7 +2498,7 @@ test('`vercel rm` removes a deployment', async t => {
|
|||||||
'-V',
|
'-V',
|
||||||
2,
|
2,
|
||||||
'--force',
|
'--force',
|
||||||
'--confirm',
|
'--yes',
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
reject: false,
|
reject: false,
|
||||||
@@ -2616,7 +2554,7 @@ test('`vercel rm` 404 exits quickly', async t => {
|
|||||||
|
|
||||||
test('render build errors', async t => {
|
test('render build errors', async t => {
|
||||||
const deploymentPath = fixture('failing-build');
|
const deploymentPath = fixture('failing-build');
|
||||||
const output = await execute([deploymentPath, '--confirm']);
|
const output = await execute([deploymentPath, '--yes']);
|
||||||
|
|
||||||
console.log(output.stderr);
|
console.log(output.stderr);
|
||||||
console.log(output.stdout);
|
console.log(output.stdout);
|
||||||
@@ -2690,12 +2628,7 @@ test('vercel hasOwnProperty not a valid subcommand', async t => {
|
|||||||
|
|
||||||
test('create zero-config deployment', async t => {
|
test('create zero-config deployment', async t => {
|
||||||
const fixturePath = fixture('zero-config-next-js');
|
const fixturePath = fixture('zero-config-next-js');
|
||||||
const output = await execute([
|
const output = await execute([fixturePath, '--force', '--public', '--yes']);
|
||||||
fixturePath,
|
|
||||||
'--force',
|
|
||||||
'--public',
|
|
||||||
'--confirm',
|
|
||||||
]);
|
|
||||||
|
|
||||||
console.log('isCanary', isCanary);
|
console.log('isCanary', isCanary);
|
||||||
console.log(output.stderr);
|
console.log(output.stderr);
|
||||||
@@ -2726,12 +2659,7 @@ test('create zero-config deployment', async t => {
|
|||||||
|
|
||||||
test('next unsupported functions config shows warning link', async t => {
|
test('next unsupported functions config shows warning link', async t => {
|
||||||
const fixturePath = fixture('zero-config-next-js-functions-warning');
|
const fixturePath = fixture('zero-config-next-js-functions-warning');
|
||||||
const output = await execute([
|
const output = await execute([fixturePath, '--force', '--public', '--yes']);
|
||||||
fixturePath,
|
|
||||||
'--force',
|
|
||||||
'--public',
|
|
||||||
'--confirm',
|
|
||||||
]);
|
|
||||||
|
|
||||||
console.log('isCanary', isCanary);
|
console.log('isCanary', isCanary);
|
||||||
console.log(output.stderr);
|
console.log(output.stderr);
|
||||||
@@ -2819,7 +2747,7 @@ test('vercel secret rm', async t => {
|
|||||||
|
|
||||||
test('deploy a Lambda with 128MB of memory', async t => {
|
test('deploy a Lambda with 128MB of memory', async t => {
|
||||||
const directory = fixture('lambda-with-128-memory');
|
const directory = fixture('lambda-with-128-memory');
|
||||||
const output = await execute([directory, '--confirm']);
|
const output = await execute([directory, '--yes']);
|
||||||
|
|
||||||
t.is(output.exitCode, 0, formatOutput(output));
|
t.is(output.exitCode, 0, formatOutput(output));
|
||||||
|
|
||||||
@@ -2836,7 +2764,7 @@ test('deploy a Lambda with 128MB of memory', async t => {
|
|||||||
|
|
||||||
test('fail to deploy a Lambda with an incorrect value for of memory', async t => {
|
test('fail to deploy a Lambda with an incorrect value for of memory', async t => {
|
||||||
const directory = fixture('lambda-with-200-memory');
|
const directory = fixture('lambda-with-200-memory');
|
||||||
const output = await execute([directory, '--confirm']);
|
const output = await execute([directory, '--yes']);
|
||||||
|
|
||||||
t.is(output.exitCode, 1, formatOutput(output));
|
t.is(output.exitCode, 1, formatOutput(output));
|
||||||
t.regex(output.stderr, /steps of 64/gm, formatOutput(output));
|
t.regex(output.stderr, /steps of 64/gm, formatOutput(output));
|
||||||
@@ -2845,7 +2773,7 @@ test('fail to deploy a Lambda with an incorrect value for of memory', async t =>
|
|||||||
|
|
||||||
test('deploy a Lambda with 3 seconds of maxDuration', async t => {
|
test('deploy a Lambda with 3 seconds of maxDuration', async t => {
|
||||||
const directory = fixture('lambda-with-3-second-timeout');
|
const directory = fixture('lambda-with-3-second-timeout');
|
||||||
const output = await execute([directory, '--confirm']);
|
const output = await execute([directory, '--yes']);
|
||||||
|
|
||||||
t.is(output.exitCode, 0, formatOutput(output));
|
t.is(output.exitCode, 0, formatOutput(output));
|
||||||
|
|
||||||
@@ -2872,7 +2800,7 @@ test('deploy a Lambda with 3 seconds of maxDuration', async t => {
|
|||||||
|
|
||||||
test('fail to deploy a Lambda with an incorrect value for maxDuration', async t => {
|
test('fail to deploy a Lambda with an incorrect value for maxDuration', async t => {
|
||||||
const directory = fixture('lambda-with-1000-second-timeout');
|
const directory = fixture('lambda-with-1000-second-timeout');
|
||||||
const output = await execute([directory, '--confirm']);
|
const output = await execute([directory, '--yes']);
|
||||||
|
|
||||||
t.is(output.exitCode, 1, formatOutput(output));
|
t.is(output.exitCode, 1, formatOutput(output));
|
||||||
t.regex(
|
t.regex(
|
||||||
@@ -2895,7 +2823,7 @@ test('invalid `--token`', async t => {
|
|||||||
|
|
||||||
test('deploy a Lambda with a specific runtime', async t => {
|
test('deploy a Lambda with a specific runtime', async t => {
|
||||||
const directory = fixture('lambda-with-php-runtime');
|
const directory = fixture('lambda-with-php-runtime');
|
||||||
const output = await execute([directory, '--public', '--confirm']);
|
const output = await execute([directory, '--public', '--yes']);
|
||||||
|
|
||||||
t.is(output.exitCode, 0, formatOutput(output));
|
t.is(output.exitCode, 0, formatOutput(output));
|
||||||
|
|
||||||
@@ -2907,7 +2835,7 @@ test('deploy a Lambda with a specific runtime', async t => {
|
|||||||
|
|
||||||
test('fail to deploy a Lambda with a specific runtime but without a locked version', async t => {
|
test('fail to deploy a Lambda with a specific runtime but without a locked version', async t => {
|
||||||
const directory = fixture('lambda-with-invalid-runtime');
|
const directory = fixture('lambda-with-invalid-runtime');
|
||||||
const output = await execute([directory, '--confirm']);
|
const output = await execute([directory, '--yes']);
|
||||||
|
|
||||||
t.is(output.exitCode, 1, formatOutput(output));
|
t.is(output.exitCode, 1, formatOutput(output));
|
||||||
t.regex(
|
t.regex(
|
||||||
@@ -2957,7 +2885,7 @@ test('assign a domain to a project', async t => {
|
|||||||
const domain = `project-domain.${contextName}.vercel.app`;
|
const domain = `project-domain.${contextName}.vercel.app`;
|
||||||
const directory = fixture('static-deployment');
|
const directory = fixture('static-deployment');
|
||||||
|
|
||||||
const deploymentOutput = await execute([directory, '--public', '--confirm']);
|
const deploymentOutput = await execute([directory, '--public', '--yes']);
|
||||||
t.is(deploymentOutput.exitCode, 0, formatOutput(deploymentOutput));
|
t.is(deploymentOutput.exitCode, 0, formatOutput(deploymentOutput));
|
||||||
|
|
||||||
const host = deploymentOutput.stdout.trim().replace('https://', '');
|
const host = deploymentOutput.stdout.trim().replace('https://', '');
|
||||||
@@ -2977,7 +2905,7 @@ test('assign a domain to a project', async t => {
|
|||||||
|
|
||||||
test('ensure `github` and `scope` are not sent to the API', async t => {
|
test('ensure `github` and `scope` are not sent to the API', async t => {
|
||||||
const directory = fixture('github-and-scope-config');
|
const directory = fixture('github-and-scope-config');
|
||||||
const output = await execute([directory, '--confirm']);
|
const output = await execute([directory, '--yes']);
|
||||||
|
|
||||||
t.is(output.exitCode, 0, formatOutput(output));
|
t.is(output.exitCode, 0, formatOutput(output));
|
||||||
});
|
});
|
||||||
@@ -3292,7 +3220,7 @@ test('deploy with `VERCEL_ORG_ID` and `VERCEL_PROJECT_ID`', async t => {
|
|||||||
const directory = fixture('static-deployment');
|
const directory = fixture('static-deployment');
|
||||||
|
|
||||||
// generate `.vercel`
|
// generate `.vercel`
|
||||||
await execute([directory, '--confirm']);
|
await execute([directory, '--yes']);
|
||||||
|
|
||||||
const link = require(path.join(directory, '.vercel/project.json'));
|
const link = require(path.join(directory, '.vercel/project.json'));
|
||||||
await remove(path.join(directory, '.vercel'));
|
await remove(path.join(directory, '.vercel'));
|
||||||
@@ -3343,7 +3271,7 @@ test('deploy shows notice when project in `.vercel` does not exists', async t =>
|
|||||||
test('use `rootDirectory` from project when deploying', async t => {
|
test('use `rootDirectory` from project when deploying', async t => {
|
||||||
const directory = fixture('project-root-directory');
|
const directory = fixture('project-root-directory');
|
||||||
|
|
||||||
const firstResult = await execute([directory, '--confirm', '--public']);
|
const firstResult = await execute([directory, '--yes', '--public']);
|
||||||
t.is(firstResult.exitCode, 0, formatOutput(firstResult));
|
t.is(firstResult.exitCode, 0, formatOutput(firstResult));
|
||||||
|
|
||||||
const { host: firstHost } = new URL(firstResult.stdout);
|
const { host: firstHost } = new URL(firstResult.stdout);
|
||||||
@@ -3438,7 +3366,7 @@ test('deploys with only now.json and README.md', async t => {
|
|||||||
|
|
||||||
const { exitCode, stderr, stdout } = await execa(
|
const { exitCode, stderr, stdout } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
[...defaultArgs, '--confirm'],
|
[...defaultArgs, '--yes'],
|
||||||
{
|
{
|
||||||
cwd: directory,
|
cwd: directory,
|
||||||
reject: false,
|
reject: false,
|
||||||
@@ -3457,7 +3385,7 @@ test('deploys with only vercel.json and README.md', async t => {
|
|||||||
|
|
||||||
const { exitCode, stderr, stdout } = await execa(
|
const { exitCode, stderr, stdout } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
[...defaultArgs, '--confirm'],
|
[...defaultArgs, '--yes'],
|
||||||
{
|
{
|
||||||
cwd: directory,
|
cwd: directory,
|
||||||
reject: false,
|
reject: false,
|
||||||
@@ -3476,7 +3404,7 @@ test('reject conflicting `vercel.json` and `now.json` files', async t => {
|
|||||||
|
|
||||||
const { exitCode, stderr, stdout } = await execa(
|
const { exitCode, stderr, stdout } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
[...defaultArgs, '--confirm'],
|
[...defaultArgs, '--yes'],
|
||||||
{
|
{
|
||||||
cwd: directory,
|
cwd: directory,
|
||||||
reject: false,
|
reject: false,
|
||||||
@@ -3515,7 +3443,7 @@ test('deploy gatsby twice and print cached directories', async t => {
|
|||||||
const pkg = JSON.parse(packageJsonOriginal);
|
const pkg = JSON.parse(packageJsonOriginal);
|
||||||
|
|
||||||
async function tryDeploy(cwd) {
|
async function tryDeploy(cwd) {
|
||||||
await execa(binaryPath, [...defaultArgs, '--public', '--confirm'], {
|
await execa(binaryPath, [...defaultArgs, '--public', '--yes'], {
|
||||||
cwd,
|
cwd,
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
reject: true,
|
reject: true,
|
||||||
@@ -3553,7 +3481,7 @@ test('deploy pnpm twice using pnp and symlink=false', async t => {
|
|||||||
session,
|
session,
|
||||||
...defaultArgs,
|
...defaultArgs,
|
||||||
'--public',
|
'--public',
|
||||||
'--confirm',
|
'--yes',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3581,7 +3509,7 @@ test('reject deploying with wrong team .vercel config', async t => {
|
|||||||
|
|
||||||
const { exitCode, stderr, stdout } = await execa(
|
const { exitCode, stderr, stdout } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
[...defaultArgs, '--confirm'],
|
[...defaultArgs, '--yes'],
|
||||||
{
|
{
|
||||||
cwd: directory,
|
cwd: directory,
|
||||||
reject: false,
|
reject: false,
|
||||||
@@ -3601,7 +3529,7 @@ test('reject deploying with invalid token', async t => {
|
|||||||
const directory = fixture('unauthorized-vercel-config');
|
const directory = fixture('unauthorized-vercel-config');
|
||||||
const { exitCode, stderr, stdout } = await execa(
|
const { exitCode, stderr, stdout } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
[...defaultArgs, '--confirm'],
|
[...defaultArgs, '--yes'],
|
||||||
{
|
{
|
||||||
cwd: directory,
|
cwd: directory,
|
||||||
reject: false,
|
reject: false,
|
||||||
@@ -3658,7 +3586,7 @@ test('[vc link] should show prompts to set up project', async t => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[vc link --confirm] should not show prompts and autolink', async t => {
|
test('[vc link --yes] should not show prompts and autolink', async t => {
|
||||||
const dir = fixture('project-link-confirm');
|
const dir = fixture('project-link-confirm');
|
||||||
|
|
||||||
// remove previously linked project if it exists
|
// remove previously linked project if it exists
|
||||||
@@ -3666,7 +3594,7 @@ test('[vc link --confirm] should not show prompts and autolink', async t => {
|
|||||||
|
|
||||||
const { exitCode, stderr, stdout } = await execa(
|
const { exitCode, stderr, stdout } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
['link', '--confirm', ...defaultArgs],
|
['link', '--yes', ...defaultArgs],
|
||||||
{ cwd: dir, reject: false }
|
{ cwd: dir, reject: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -3701,7 +3629,7 @@ test('[vc link] should not duplicate paths in .gitignore', async t => {
|
|||||||
|
|
||||||
const { exitCode, stderr, stdout } = await execa(
|
const { exitCode, stderr, stdout } = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
['link', '--confirm', ...defaultArgs],
|
['link', '--yes', ...defaultArgs],
|
||||||
{
|
{
|
||||||
cwd: dir,
|
cwd: dir,
|
||||||
reject: false,
|
reject: false,
|
||||||
@@ -3875,7 +3803,7 @@ test('[vc link] should support the `--project` flag', async t => {
|
|||||||
|
|
||||||
const [user, output] = await Promise.all([
|
const [user, output] = await Promise.all([
|
||||||
fetchTokenInformation(token),
|
fetchTokenInformation(token),
|
||||||
execute(['link', '--confirm', '--project', projectName, directory]),
|
execute(['link', '--yes', '--project', projectName, directory]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
t.is(output.exitCode, 0, formatOutput(output));
|
t.is(output.exitCode, 0, formatOutput(output));
|
||||||
@@ -3996,7 +3924,7 @@ test('vercel.json configuration overrides in an existing project do not prompt u
|
|||||||
const deployment = await execa(
|
const deployment = await execa(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
[directory, ...defaultArgs, '--public'].concat(
|
[directory, ...defaultArgs, '--public'].concat(
|
||||||
autoConfirm ? ['--confirm'] : []
|
autoConfirm ? ['--yes'] : []
|
||||||
),
|
),
|
||||||
{ reject: false }
|
{ reject: false }
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -94,7 +94,9 @@ export class MockClient extends Client {
|
|||||||
this.output = new Output(this.stderr);
|
this.output = new Output(this.stderr);
|
||||||
|
|
||||||
this.argv = [];
|
this.argv = [];
|
||||||
this.authConfig = {};
|
this.authConfig = {
|
||||||
|
token: 'token_dummy',
|
||||||
|
};
|
||||||
this.config = {};
|
this.config = {};
|
||||||
this.localConfig = {};
|
this.localConfig = {};
|
||||||
|
|
||||||
|
|||||||
@@ -7,17 +7,25 @@ import { Build, User } from '../../src/types';
|
|||||||
let deployments = new Map<string, Deployment>();
|
let deployments = new Map<string, Deployment>();
|
||||||
let deploymentBuilds = new Map<Deployment, Build[]>();
|
let deploymentBuilds = new Map<Deployment, Build[]>();
|
||||||
|
|
||||||
|
type State = Deployment['readyState'];
|
||||||
|
|
||||||
export function useDeployment({
|
export function useDeployment({
|
||||||
creator,
|
creator,
|
||||||
|
state = 'READY',
|
||||||
}: {
|
}: {
|
||||||
creator: Pick<User, 'id' | 'email' | 'name'>;
|
creator: Pick<User, 'id' | 'email' | 'name' | 'username'>;
|
||||||
|
state?: State;
|
||||||
}) {
|
}) {
|
||||||
const createdAt = Date.now();
|
const createdAt = Date.now();
|
||||||
const url = new URL(chance().url());
|
const url = new URL(chance().url());
|
||||||
|
const name = chance().name();
|
||||||
|
const id = `dpl_${chance().guid()}`;
|
||||||
|
|
||||||
const deployment: Deployment = {
|
const deployment: Deployment = {
|
||||||
id: `dpl_${chance().guid()}`,
|
id,
|
||||||
url: url.hostname,
|
url: url.hostname,
|
||||||
name: '',
|
inspectorUrl: `https://vercel.com/team/project/${id.replace('dpl_', '')}`,
|
||||||
|
name,
|
||||||
meta: {},
|
meta: {},
|
||||||
regions: [],
|
regions: [],
|
||||||
routes: [],
|
routes: [],
|
||||||
@@ -26,19 +34,24 @@ export function useDeployment({
|
|||||||
version: 2,
|
version: 2,
|
||||||
createdAt,
|
createdAt,
|
||||||
createdIn: 'sfo1',
|
createdIn: 'sfo1',
|
||||||
|
buildingAt: Date.now(),
|
||||||
ownerId: creator.id,
|
ownerId: creator.id,
|
||||||
creator: {
|
creator: {
|
||||||
uid: creator.id,
|
uid: creator.id,
|
||||||
email: creator.email,
|
email: creator.email,
|
||||||
username: creator.name,
|
name: creator.name,
|
||||||
|
username: creator.username,
|
||||||
},
|
},
|
||||||
readyState: 'READY',
|
readyState: state,
|
||||||
|
state: state,
|
||||||
|
ready: createdAt + 30000,
|
||||||
env: {},
|
env: {},
|
||||||
build: { env: {} },
|
build: { env: {} },
|
||||||
target: 'production',
|
target: 'production',
|
||||||
alias: [],
|
alias: [],
|
||||||
aliasAssigned: true,
|
aliasAssigned: true,
|
||||||
aliasError: null,
|
aliasError: null,
|
||||||
|
inspectorUrl: `https://vercel.com/${creator.name}/${id}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
deployments.set(deployment.id, deployment);
|
deployments.set(deployment.id, deployment);
|
||||||
@@ -47,6 +60,43 @@ export function useDeployment({
|
|||||||
return deployment;
|
return deployment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useDeploymentMissingProjectSettings() {
|
||||||
|
client.scenario.post('/:version/deployments', (_req, res) => {
|
||||||
|
res.status(400).json({
|
||||||
|
error: {
|
||||||
|
code: 'missing_project_settings',
|
||||||
|
message:
|
||||||
|
'The `projectSettings` object is required for new projects, but is missing in the deployment payload',
|
||||||
|
framework: {
|
||||||
|
name: 'Other',
|
||||||
|
slug: null,
|
||||||
|
logo: 'https://raw.githubusercontent.com/vercel/vercel/main/packages/frameworks/logos/other.svg',
|
||||||
|
description: 'No framework or an unoptimized framework.',
|
||||||
|
settings: {
|
||||||
|
installCommand: {
|
||||||
|
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
|
||||||
|
},
|
||||||
|
buildCommand: {
|
||||||
|
placeholder: '`npm run vercel-build` or `npm run build`',
|
||||||
|
value: null,
|
||||||
|
},
|
||||||
|
devCommand: { placeholder: 'None', value: null },
|
||||||
|
outputDirectory: { placeholder: '`public` if it exists, or `.`' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
projectSettings: {
|
||||||
|
devCommand: null,
|
||||||
|
installCommand: null,
|
||||||
|
buildCommand: null,
|
||||||
|
outputDirectory: null,
|
||||||
|
rootDirectory: null,
|
||||||
|
framework: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
deployments = new Map();
|
deployments = new Map();
|
||||||
deploymentBuilds = new Map();
|
deploymentBuilds = new Map();
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user