mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-27 03:39:11 +00:00
Compare commits
200 Commits
@vercel/ne
...
@vercel/st
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f43e413ba5 | ||
|
|
0945d24cbe | ||
|
|
a8ecf40d6f | ||
|
|
2995781a58 | ||
|
|
e2096c268d | ||
|
|
663d8e6437 | ||
|
|
153ca440fa | ||
|
|
c5e0cb4812 | ||
|
|
5bf1fe4c74 | ||
|
|
011f836aa7 | ||
|
|
ec107d7c91 | ||
|
|
0d27ae3b1a | ||
|
|
08da4b9c92 | ||
|
|
877f09ff5c | ||
|
|
5cca9b6c5c | ||
|
|
4af242af86 | ||
|
|
0cbdae1411 | ||
|
|
85dd667781 | ||
|
|
7d3dda7341 | ||
|
|
2144d0b2a9 | ||
|
|
976e6aedf9 | ||
|
|
6328751e14 | ||
|
|
8cb49a5136 | ||
|
|
3fa4f344cc | ||
|
|
27610896ed | ||
|
|
b9dae36e37 | ||
|
|
1537ff9c38 | ||
|
|
7e0317775f | ||
|
|
2dd27976b3 | ||
|
|
25e2b7efba | ||
|
|
3d23d1270c | ||
|
|
fde40e731a | ||
|
|
f353527421 | ||
|
|
c1cdfb3e75 | ||
|
|
fc413707d0 | ||
|
|
e842a8870e | ||
|
|
d1b0dbe3a7 | ||
|
|
d614709308 | ||
|
|
d5b588bc06 | ||
|
|
4a8622a10d | ||
|
|
6469ef1b8c | ||
|
|
b8d42a521b | ||
|
|
b1e8c9cb6e | ||
|
|
7c30b13ccb | ||
|
|
e5e757de34 | ||
|
|
2661f56347 | ||
|
|
b1c14cde03 | ||
|
|
8dd6d021df | ||
|
|
88ec6e69d6 | ||
|
|
a6f2e7b136 | ||
|
|
e906365909 | ||
|
|
7b01a07394 | ||
|
|
ce4633fe4d | ||
|
|
fdf86fda03 | ||
|
|
56178e6a46 | ||
|
|
5439d7c0c9 | ||
|
|
c670e51712 | ||
|
|
b56639b624 | ||
|
|
12bbae098c | ||
|
|
9969f0ba18 | ||
|
|
24e1e3c3be | ||
|
|
b61674cb2d | ||
|
|
cae60155f3 | ||
|
|
a91bde5287 | ||
|
|
0750517af9 | ||
|
|
70f6782954 | ||
|
|
5f1e37ee16 | ||
|
|
680d666fdc | ||
|
|
06a5dccfed | ||
|
|
f85df894c0 | ||
|
|
e9ec779f1c | ||
|
|
4333d1e6b2 | ||
|
|
493a31091d | ||
|
|
8d7206f5b6 | ||
|
|
4bf2ca55ff | ||
|
|
5e5332fbc9 | ||
|
|
281ec776a5 | ||
|
|
ee8f9292b4 | ||
|
|
027bce00b3 | ||
|
|
ca1f41200a | ||
|
|
834b3e652b | ||
|
|
5c6941d18c | ||
|
|
761ede2482 | ||
|
|
1d01703dc3 | ||
|
|
7021279b28 | ||
|
|
28acf50bdf | ||
|
|
718bbd365a | ||
|
|
7e791ee080 | ||
|
|
13769106cb | ||
|
|
aa734efc6c | ||
|
|
acc10e47c7 | ||
|
|
6a0e1e0b66 | ||
|
|
3468922108 | ||
|
|
e4895d979b | ||
|
|
733ff5ed85 | ||
|
|
0867f11a6a | ||
|
|
a6de052ed2 | ||
|
|
f5d48ec3bc | ||
|
|
6ec1180798 | ||
|
|
36db62a491 | ||
|
|
f9266e069f | ||
|
|
8163a153df | ||
|
|
c5e6bd1a7a | ||
|
|
c2f1bebd1f | ||
|
|
3138415533 | ||
|
|
8f6813bb63 | ||
|
|
734499fc03 | ||
|
|
f06988d914 | ||
|
|
71ac16220b | ||
|
|
8b3a4146af | ||
|
|
cfea31e6cf | ||
|
|
7090fec110 | ||
|
|
bc7c80fb9b | ||
|
|
91406abdb0 | ||
|
|
a5af8381ce | ||
|
|
2230ea6cc1 | ||
|
|
f057f0421b | ||
|
|
42c0b32a8d | ||
|
|
d61a1a7988 | ||
|
|
c438bbb362 | ||
|
|
cb5eef0eb5 | ||
|
|
79dee367cf | ||
|
|
dea58dea7e | ||
|
|
fecebfa7fa | ||
|
|
94d5612dce | ||
|
|
3eaf58bb74 | ||
|
|
e63cf40153 | ||
|
|
709c9509f4 | ||
|
|
6107c1ed22 | ||
|
|
7a0f377afe | ||
|
|
a04bf557fc | ||
|
|
b6736e82cf | ||
|
|
7923056bc0 | ||
|
|
71ff193ea3 | ||
|
|
c21d93de44 | ||
|
|
0039c8b5ce | ||
|
|
49c7178567 | ||
|
|
b038b29614 | ||
|
|
7a249a2284 | ||
|
|
a5e32ec31d | ||
|
|
bc5afe24c4 | ||
|
|
5070e3bbbd | ||
|
|
4ad1cbbd7d | ||
|
|
4f4e09477d | ||
|
|
cd35071f60 | ||
|
|
f373c94508 | ||
|
|
553c001eb0 | ||
|
|
f6c3a95783 | ||
|
|
c0bcef0ca4 | ||
|
|
4cd77608e8 | ||
|
|
e6b2980eba | ||
|
|
67e20a6ede | ||
|
|
c63679ea0a | ||
|
|
4280166df4 | ||
|
|
18ae78137c | ||
|
|
ebe4058073 | ||
|
|
942e76840e | ||
|
|
57515d2d07 | ||
|
|
ef30a46c03 | ||
|
|
113b8ac87b | ||
|
|
b56ac2717d | ||
|
|
aa8957ab10 | ||
|
|
c6c19354e8 | ||
|
|
96b2502133 | ||
|
|
2df0262675 | ||
|
|
1e47bbf32f | ||
|
|
00813a3945 | ||
|
|
a73ec6343f | ||
|
|
4bd70d4b6e | ||
|
|
c7bcea4081 | ||
|
|
aab95532d6 | ||
|
|
1b18c853c2 | ||
|
|
1663db7ca3 | ||
|
|
e80247fb99 | ||
|
|
a19edc985b | ||
|
|
4fd593ac09 | ||
|
|
1b0d72aba5 | ||
|
|
c52a59809e | ||
|
|
cdf55b3b1a | ||
|
|
8de42e0a70 | ||
|
|
7ff321310f | ||
|
|
2da72bc5e4 | ||
|
|
46950633f4 | ||
|
|
44b1dfe7c5 | ||
|
|
0278c7b7b9 | ||
|
|
761db597be | ||
|
|
671e63e7b8 | ||
|
|
f7bdc6cc26 | ||
|
|
e94a153b2f | ||
|
|
74e639a772 | ||
|
|
f00b08a820 | ||
|
|
6cdd38d130 | ||
|
|
2c950d47ae | ||
|
|
71b9f3a94b | ||
|
|
91b7f6dcd9 | ||
|
|
ba10fb4dd4 | ||
|
|
18c1c45ce3 | ||
|
|
67e556bc80 | ||
|
|
7235000181 | ||
|
|
5124d431ea |
18
.github/CODEOWNERS
vendored
18
.github/CODEOWNERS
vendored
@@ -1,16 +1,20 @@
|
||||
# Documentation
|
||||
# https://help.github.com/en/articles/about-code-owners
|
||||
|
||||
* @TooTallNate @EndangeredMassa @styfle @cb1kenobi @Ethan-Arrowood
|
||||
/.github/workflows @TooTallNate @EndangeredMassa @styfle @cb1kenobi @Ethan-Arrowood @ijjk
|
||||
/packages/fs-detectors @TooTallNate @EndangeredMassa @styfle @cb1kenobi @Ethan-Arrowood @agadzik @chloetedder
|
||||
/packages/next @TooTallNate @EndangeredMassa @styfle @cb1kenobi @Ethan-Arrowood @ijjk
|
||||
/packages/routing-utils @TooTallNate @EndangeredMassa @styfle @cb1kenobi @Ethan-Arrowood @ijjk
|
||||
/packages/edge @vercel/edge-compute
|
||||
# Restricted Paths
|
||||
* @TooTallNate @EndangeredMassa @styfle @cb1kenobi @Ethan-Arrowood @trek
|
||||
/.github/workflows @TooTallNate @EndangeredMassa @styfle @cb1kenobi @Ethan-Arrowood @trek @ijjk
|
||||
/packages/fs-detectors @TooTallNate @EndangeredMassa @styfle @cb1kenobi @Ethan-Arrowood @trek @agadzik @chloetedder
|
||||
/packages/next @TooTallNate @EndangeredMassa @styfle @cb1kenobi @Ethan-Arrowood @trek @ijjk
|
||||
/packages/routing-utils @TooTallNate @EndangeredMassa @styfle @cb1kenobi @Ethan-Arrowood @trek @ijjk
|
||||
/packages/edge @vercel/compute
|
||||
/examples @leerob
|
||||
/examples/create-react-app @Timer
|
||||
/examples/nextjs @timneutkens @ijjk @styfle
|
||||
/examples/hugo @styfle
|
||||
/examples/jekyll @styfle
|
||||
/examples/zola @styfle
|
||||
/packages/node @TooTallNate @EndangeredMassa @styfle @cb1kenobi @Ethan-Arrowood @Kikobeats
|
||||
/packages/node @TooTallNate @EndangeredMassa @styfle @cb1kenobi @Ethan-Arrowood @trek @Kikobeats
|
||||
|
||||
# Unrestricted Paths
|
||||
.changeset/
|
||||
|
||||
1
.github/CONTRIBUTING.md
vendored
1
.github/CONTRIBUTING.md
vendored
@@ -15,7 +15,6 @@ git clone https://github.com/vercel/vercel
|
||||
cd vercel
|
||||
corepack enable
|
||||
pnpm install
|
||||
pnpm bootstrap
|
||||
pnpm build
|
||||
pnpm lint
|
||||
pnpm test-unit
|
||||
|
||||
4
.github/DISCUSSION_TEMPLATE/general.yml
vendored
4
.github/DISCUSSION_TEMPLATE/general.yml
vendored
@@ -2,7 +2,9 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
> **Note**: For discussions not related to Vercel CLI or Runtimes, please visit the [Vercel Community](https://github.com/orgs/vercel/discussions)
|
||||
**Note**: This category is intended for discussions related to Vercel CLI or Runtimes.
|
||||
|
||||
If you post in this repository seeking help with other Vercel tools and features, it may be missed by our support team. For help with topics other than the CLI and Runtimes, please visit the [Vercel Community](https://github.com/orgs/vercel/discussions).
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
|
||||
6
.github/DISCUSSION_TEMPLATE/help.yml
vendored
6
.github/DISCUSSION_TEMPLATE/help.yml
vendored
@@ -2,9 +2,11 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
> **Note**: For discussions not related to Vercel CLI or Runtimes, please visit the [Vercel Community](https://github.com/orgs/vercel/discussions/categories/help)
|
||||
**Note**: This category is intended for discussions related to Vercel CLI or Runtimes.
|
||||
|
||||
If you post in this repository seeking help with other Vercel tools and features, it may be missed by our support team. For help with topics other than the CLI and Runtimes, please visit the [Vercel Community](https://github.com/orgs/vercel/discussions).
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Problem Description
|
||||
label: Question
|
||||
validations:
|
||||
required: true
|
||||
|
||||
4
.github/DISCUSSION_TEMPLATE/ideas.yml
vendored
4
.github/DISCUSSION_TEMPLATE/ideas.yml
vendored
@@ -2,7 +2,9 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
> **Note**: For discussions not related to Vercel CLI or Runtimes, please visit the [Vercel Community](https://github.com/orgs/vercel/discussions/categories/ideas)
|
||||
**Note**: This category is intended for sharing ideas related to Vercel CLI or Runtimes.
|
||||
|
||||
Please visit the [Vercel Community](https://github.com/orgs/vercel/discussions) to share ideas for other Vercel tools and features.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Idea
|
||||
|
||||
10
.github/DISCUSSION_TEMPLATE/polls.yml
vendored
10
.github/DISCUSSION_TEMPLATE/polls.yml
vendored
@@ -1,10 +0,0 @@
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
> **Note**: For discussions not related to Vercel CLI or Runtimes, please visit the [Vercel Community](https://github.com/orgs/vercel/discussions)
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
validations:
|
||||
required: true
|
||||
@@ -2,7 +2,9 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
> **Note**: For discussions not related to Vercel CLI or Runtimes, please visit the [Vercel Community](https://github.com/orgs/vercel/discussions)
|
||||
**Note**: This category is intended for discussions related to Vercel CLI or Runtimes.
|
||||
|
||||
For topics related to other Vercel features, please visit the [Vercel Community](https://github.com/orgs/vercel/discussions).
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
|
||||
5
.github/DISCUSSION_TEMPLATE/temporary.yml
vendored
5
.github/DISCUSSION_TEMPLATE/temporary.yml
vendored
@@ -1,5 +0,0 @@
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
> **Note**: This category should not be used for new discussions. Please visit the [Vercel Community](https://github.com/orgs/vercel/discussions)
|
||||
25
.github/workflows/release.yml
vendored
25
.github/workflows/release.yml
vendored
@@ -23,6 +23,9 @@ jobs:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Fetch git tags
|
||||
run: git fetch origin 'refs/tags/*:refs/tags/*'
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
@@ -47,8 +50,8 @@ jobs:
|
||||
id: changesets
|
||||
uses: changesets/action@v1
|
||||
with:
|
||||
version: pnpm version:prepare
|
||||
publish: pnpm release
|
||||
version: pnpm ci:version
|
||||
publish: pnpm ci:publish
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GH_TOKEN_PULL_REQUESTS }}
|
||||
NPM_CONFIG_PROVENANCE: 'true'
|
||||
@@ -56,15 +59,6 @@ jobs:
|
||||
GA_TRACKING_ID: ${{ secrets.GA_TRACKING_ID }}
|
||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||
|
||||
- name: Set latest Release to `vercel` (if a Publish Happened)
|
||||
if: steps.changesets.outputs.published == 'true'
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
github-token: ${{ secrets.GH_TOKEN_PULL_REQUESTS }}
|
||||
script: |
|
||||
const script = require('./utils/update-latest-release.js')
|
||||
await script({ github, context })
|
||||
|
||||
- name: Trigger Update (if a Publish Happened)
|
||||
if: steps.changesets.outputs.published == 'true'
|
||||
uses: actions/github-script@v6
|
||||
@@ -73,3 +67,12 @@ jobs:
|
||||
script: |
|
||||
const script = require('./utils/trigger-update-workflow.js')
|
||||
await script({ github, context })
|
||||
|
||||
- name: Set latest Release to `vercel` (if a Publish Happened)
|
||||
if: steps.changesets.outputs.published == 'true'
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
github-token: ${{ secrets.GH_TOKEN_PULL_REQUESTS }}
|
||||
script: |
|
||||
const script = require('./utils/update-latest-release.js')
|
||||
await script({ github, context })
|
||||
|
||||
16
.github/workflows/test-lint.yml
vendored
16
.github/workflows/test-lint.yml
vendored
@@ -19,6 +19,22 @@ concurrency:
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
||||
|
||||
jobs:
|
||||
enforce-changeset:
|
||||
name: Enforce Changeset
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'pull_request' && github.event.pull_request.title != 'Version Packages'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: main
|
||||
- run: git checkout ${{ github.event.pull_request.head.ref }}
|
||||
- name: install pnpm@8.3.1
|
||||
run: npm i -g pnpm@8.3.1
|
||||
- run: pnpm install
|
||||
# Enforce a changeset file to be present
|
||||
- run: pnpm exec changeset status --since=main
|
||||
|
||||
test:
|
||||
name: Lint
|
||||
timeout-minutes: 10
|
||||
|
||||
26
.github/workflows/test.yml
vendored
26
.github/workflows/test.yml
vendored
@@ -41,7 +41,7 @@ jobs:
|
||||
echo "Files to test:"
|
||||
echo "$TESTS_ARRAY"
|
||||
echo "tests=$TESTS_ARRAY" >> $GITHUB_OUTPUT
|
||||
- uses: patrickedqvist/wait-for-vercel-preview@ae34b392ef30297f2b672f9afb3c329bde9bd487
|
||||
- uses: patrickedqvist/wait-for-vercel-preview@bfdff514ff78a669f2536e9f4dd4ef5813a704a2
|
||||
id: waitForTarball
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -81,11 +81,11 @@ jobs:
|
||||
run: echo | openssl s_client -showcerts -servername 'api.vercel.com' -connect 76.76.21.21:443
|
||||
|
||||
- name: Build ${{matrix.packageName}} and all its dependencies
|
||||
run: node utils/gen.js && node_modules/.bin/turbo run build --cache-dir=".turbo" --scope=${{matrix.packageName}} --include-dependencies --no-deps
|
||||
run: node utils/gen.js && node_modules/.bin/turbo run build --cache-dir=".turbo" --log-order=stream --scope=${{matrix.packageName}} --include-dependencies --no-deps
|
||||
env:
|
||||
FORCE_COLOR: '1'
|
||||
- name: Test ${{matrix.packageName}}
|
||||
run: node utils/gen.js && node_modules/.bin/turbo run test --cache-dir=".turbo" --scope=${{matrix.packageName}} --no-deps -- ${{ join(matrix.testPaths, ' ') }}
|
||||
run: node utils/gen.js && node_modules/.bin/turbo run test --cache-dir=".turbo" --log-order=stream --scope=${{matrix.packageName}} --no-deps -- ${{ join(matrix.testPaths, ' ') }}
|
||||
shell: bash
|
||||
env:
|
||||
VERCEL_CLI_VERSION: ${{ needs.setup.outputs.dplUrl }}/tarballs/vercel.tgz
|
||||
@@ -97,11 +97,21 @@ jobs:
|
||||
if: matrix.runner != 'windows-latest'
|
||||
run: echo | openssl s_client -showcerts -servername 'api.vercel.com' -connect 76.76.21.21:443
|
||||
|
||||
conclusion:
|
||||
summary:
|
||||
name: Summary
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
if: always()
|
||||
needs:
|
||||
- test
|
||||
runs-on: ubuntu-latest
|
||||
name: E2E
|
||||
steps:
|
||||
- name: Done
|
||||
run: echo "Done."
|
||||
- name: Check All
|
||||
run: |-
|
||||
for status in ${{ join(needs.*.result, ' ') }}
|
||||
do
|
||||
if [ "$status" != "success" ] && [ "$status" != "skipped" ]
|
||||
then
|
||||
echo "Some checks failed"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -32,4 +32,4 @@ packages/**/test/fixtures
|
||||
packages/**/test/dev/fixtures
|
||||
packages/**/test/build-fixtures
|
||||
packages/**/test/cache-fixtures
|
||||
|
||||
packages/cli/src/util/dev/templates/*.ts
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
You ran `vercel dev` inside a project that contains a `vercel.json` file with `env` or `build.env` properties that use [Vercel Secrets](https://vercel.com/docs/concepts/projects/environment-variables).
|
||||
|
||||
In order to use environment variables in your project locally that have values defined using the Vercel Secrets format (e.g. `@my-secret-value`), you will need to provide the value as an environment variable using a `.env`.
|
||||
In order to use environment variables in your project locally that have values defined using the Vercel Secrets format (e.g. `@my-secret-value`), you will need to provide the value as an environment variable using a `.env.local`.
|
||||
|
||||
We require this to ensure your app works as you intend it to, in the development environment, and to provide you with a way to mirror or separate private environment variables within your applications, for example when connecting to a database.
|
||||
|
||||
@@ -12,11 +12,11 @@ Read below for how to address this error.
|
||||
|
||||
#### Possible Ways to Fix It
|
||||
|
||||
The error message will list environment variables that are required and which file they are required to be included in `.env`.
|
||||
The error message will list environment variables that are required and which file they are required to be included in `.env.local`.
|
||||
|
||||
If the file does not exist yet, please create the file that the error message mentions and insert the missing environment variable into it.
|
||||
|
||||
For example, if the error message shows that the environment variable `TEST` is missing from `.env`, then the `.env` file should look like this:
|
||||
For example, if the error message shows that the environment variable `TEST` is missing from `.env.local`, then the `.env.local` file should look like this:
|
||||
|
||||
```
|
||||
TEST=value
|
||||
|
||||
@@ -44,6 +44,5 @@
|
||||
"react-use": "^17.4.0",
|
||||
"title": "^3.4.4",
|
||||
"typographic-base": "^1.0.4"
|
||||
},
|
||||
"author": "nrajlich"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(25%, auto));
|
||||
width: var(--max-width);
|
||||
max-width: 100%;
|
||||
width: var(--max-width);
|
||||
}
|
||||
|
||||
.card {
|
||||
|
||||
861
examples/nextjs/package-lock.json
generated
861
examples/nextjs/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,9 +9,9 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint": "8.40.0",
|
||||
"eslint-config-next": "13.4.2",
|
||||
"next": "13.4.2",
|
||||
"eslint": "8.46.0",
|
||||
"eslint-config-next": "13.4.13",
|
||||
"next": "13.4.13",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
}
|
||||
|
||||
@@ -45,4 +45,4 @@ Locally preview production build:
|
||||
npm run preview
|
||||
```
|
||||
|
||||
Checkout the [deployment documentation](https://v3.nuxtjs.org/guide/deploy/presets) for more information.
|
||||
Checkout the [deployment documentation](https://nuxt.com/docs/getting-started/deployment#presets) for more information.
|
||||
|
||||
2
examples/package.json
vendored
2
examples/package.json
vendored
@@ -9,6 +9,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "27.4.1",
|
||||
"@vercel/frameworks": "1.3.0"
|
||||
"@vercel/frameworks": "1.5.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "preact build",
|
||||
"build": "NODE_OPTIONS=--openssl-legacy-provider preact build",
|
||||
"serve": "sirv build --port 8080 --cors --single",
|
||||
"dev": "preact watch",
|
||||
"lint": "eslint src",
|
||||
"test": "jest"
|
||||
},
|
||||
"engines": {
|
||||
"node": "16.x"
|
||||
"node": "18.x"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "preact",
|
||||
@@ -17,19 +17,19 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"enzyme": "^3.10.0",
|
||||
"enzyme-adapter-preact-pure": "^2.0.0",
|
||||
"eslint": "^6.0.1",
|
||||
"eslint-config-preact": "^1.1.0",
|
||||
"jest": "^24.9.0",
|
||||
"jest-preset-preact": "^1.0.0",
|
||||
"preact-cli": "^3.0.0",
|
||||
"sirv-cli": "1.0.3"
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-adapter-preact-pure": "^4.1.0",
|
||||
"eslint": "^8.41.0",
|
||||
"eslint-config-preact": "^1.3.0",
|
||||
"jest": "^29.5.0",
|
||||
"jest-preset-preact": "^4.0.4",
|
||||
"preact-cli": "^3.4.5",
|
||||
"sirv-cli": "2.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"preact": "^10.3.2",
|
||||
"preact-render-to-string": "^5.1.4",
|
||||
"preact-router": "^3.2.1"
|
||||
"preact": "^10.15.0",
|
||||
"preact-render-to-string": "6.0.3",
|
||||
"preact-router": "^4.1.1"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "jest-preset-preact",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,4 @@
|
||||
/** @type {import('eslint').Linter.Config} */
|
||||
module.exports = {
|
||||
extends: ["@remix-run/eslint-config", "@remix-run/eslint-config/node"],
|
||||
};
|
||||
|
||||
7
examples/remix/.gitignore
vendored
7
examples/remix/.gitignore
vendored
@@ -1,11 +1,12 @@
|
||||
node_modules
|
||||
|
||||
.cache
|
||||
/.cache
|
||||
/build
|
||||
/public/build
|
||||
.env
|
||||
|
||||
.vercel
|
||||
.output
|
||||
|
||||
/build/
|
||||
/public/build
|
||||
/api/index.js
|
||||
/api/index.js.map
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { MetaFunction } from "@vercel/remix";
|
||||
import { cssBundleHref } from "@remix-run/css-bundle";
|
||||
import {
|
||||
Links,
|
||||
LiveReload,
|
||||
@@ -8,17 +8,18 @@ import {
|
||||
ScrollRestoration,
|
||||
} from "@remix-run/react";
|
||||
import { Analytics } from "@vercel/analytics/react";
|
||||
import type { LinksFunction } from "@vercel/remix";
|
||||
|
||||
export const meta: MetaFunction = () => ({
|
||||
charset: "utf-8",
|
||||
title: "New Remix App",
|
||||
viewport: "width=device-width,initial-scale=1",
|
||||
});
|
||||
export const links: LinksFunction = () => [
|
||||
...(cssBundleHref ? [{ rel: "stylesheet", href: cssBundleHref }] : []),
|
||||
];
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<Meta />
|
||||
<Links />
|
||||
</head>
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import type { V2_MetaFunction } from "@vercel/remix";
|
||||
|
||||
export const meta: V2_MetaFunction = () => [{ title: "New Remix App" }];
|
||||
|
||||
export default function Index() {
|
||||
return (
|
||||
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
|
||||
@@ -1,5 +1,9 @@
|
||||
import type { V2_MetaFunction } from "@vercel/remix";
|
||||
|
||||
export const config = { runtime: "edge" };
|
||||
|
||||
export const meta: V2_MetaFunction = () => [{ title: "Remix@Edge | New Remix App" }];
|
||||
|
||||
export default function Edge() {
|
||||
return (
|
||||
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
|
||||
|
||||
@@ -3,24 +3,28 @@
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"build": "remix build",
|
||||
"dev": "remix dev"
|
||||
"dev": "remix dev",
|
||||
"start": "remix-serve build",
|
||||
"typecheck": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@remix-run/node": "^1.15.0",
|
||||
"@remix-run/react": "^1.15.0",
|
||||
"@remix-run/serve": "^1.15.0",
|
||||
"@remix-run/css-bundle": "^1.18.0",
|
||||
"@remix-run/node": "^1.18.0",
|
||||
"@remix-run/react": "^1.18.0",
|
||||
"@remix-run/serve": "^1.18.0",
|
||||
"@vercel/analytics": "^0.1.11",
|
||||
"@vercel/remix": "^1.15.0",
|
||||
"@vercel/remix": "^1.18.0",
|
||||
"isbot": "^3.6.8",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@remix-run/dev": "^1.15.0",
|
||||
"@remix-run/eslint-config": "^1.15.0",
|
||||
"@remix-run/dev": "^1.18.0",
|
||||
"@remix-run/eslint-config": "^1.18.0",
|
||||
"@types/react": "^18.0.25",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"eslint": "^8.28.0",
|
||||
"typescript": "^4.9.3"
|
||||
"typescript": "^5.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
|
||||
7492
examples/remix/pnpm-lock.yaml
generated
7492
examples/remix/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,15 @@
|
||||
/**
|
||||
* @type {import('@remix-run/dev').AppConfig}
|
||||
*/
|
||||
/** @type {import('@remix-run/dev').AppConfig} */
|
||||
module.exports = {
|
||||
ignoredRouteFiles: ['**/.*'],
|
||||
future: {
|
||||
v2_dev: true,
|
||||
v2_errorBoundary: true,
|
||||
v2_headers: true,
|
||||
v2_meta: true,
|
||||
v2_normalizeFormMethod: true,
|
||||
v2_routeConvention: true,
|
||||
},
|
||||
ignoredRouteFiles: ["**/.*"],
|
||||
serverModuleFormat: "cjs",
|
||||
// appDirectory: "app",
|
||||
// assetsBuildDirectory: "public/build",
|
||||
// serverBuildPath: "build/index.js",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Saber Example
|
||||
|
||||
This directory is a brief example of a [Saber](https://saber.land) site that can be deployed to Vercel with zero configuration.
|
||||
This directory is a brief example of a [Saber](https://saber.egoist.dev) site that can be deployed to Vercel with zero configuration.
|
||||
|
||||
## Deploy Your Own
|
||||
|
||||
|
||||
@@ -5,4 +5,4 @@ layout: page
|
||||
|
||||
This is the Saber port of the base Jekyll theme. Check out the [GitHub project](https://github.com/egoist/saber-theme-minima) for detailed usages.
|
||||
|
||||
You can find out more info about customizing your theme, as well as basic Saber usage documentation at https://saber.land
|
||||
You can find out more info about customizing your theme, as well as basic Saber usage documentation at https://saber.egoist.dev
|
||||
|
||||
@@ -7,18 +7,18 @@
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"solid-start-vercel": "^0.2.0",
|
||||
"typescript": "^4.8.3",
|
||||
"vite": "^3.1.0"
|
||||
"solid-start-vercel": "^0.2.26",
|
||||
"typescript": "^5.0.4",
|
||||
"vite": "^4.3.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"@solidjs/meta": "^0.28.2",
|
||||
"@solidjs/router": "^0.5.0",
|
||||
"solid-js": "^1.6.0",
|
||||
"solid-start": "^0.2.0",
|
||||
"undici": "^5.11.0"
|
||||
"@solidjs/meta": "^0.28.5",
|
||||
"@solidjs/router": "^0.8.2",
|
||||
"solid-js": "^1.7.5",
|
||||
"solid-start": "^0.2.26",
|
||||
"undici": "^5.22.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "16.x"
|
||||
"node": "18.x"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
4
examples/storybook/vercel.json
Normal file
4
examples/storybook/vercel.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"framework": "storybook",
|
||||
"buildCommand": "storybook build"
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ['eslint:recommended', 'prettier'],
|
||||
plugins: ['svelte3'],
|
||||
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
|
||||
extends: ['eslint:recommended', 'plugin:svelte/recommended', 'prettier'],
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2020
|
||||
ecmaVersion: 2020,
|
||||
extraFileExtensions: ['.svelte']
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
engine-strict=true
|
||||
resolution-mode=highest
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
# create-svelte
|
||||
# SvelteKit Demo app
|
||||
|
||||
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
|
||||
The official demo app for SvelteKit, hosted on Vercel.
|
||||
|
||||
## Creating a project
|
||||
## Deploy Your Own
|
||||
|
||||
If you're seeing this, you've probably already done this step. Congrats!
|
||||
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fvercel%2Ftree%2Fmain%2Fexamples%2Fsveltekit-1&project-name=sveltekit-vercel&repository-name=sveltekit-vercel&demo-title=SvelteKit%20%2B%20Vercel&demo-url=https%3A%2F%2Fsveltekit-template.vercel.app%2F)
|
||||
|
||||
```bash
|
||||
# create a new project in the current directory
|
||||
npm create svelte@latest
|
||||
|
||||
# create a new project in my-app
|
||||
npm create svelte@latest my-app
|
||||
```
|
||||
_Live Example: https://sveltekit-template.vercel.app_
|
||||
|
||||
## Developing
|
||||
|
||||
@@ -35,4 +29,8 @@ npm run build
|
||||
|
||||
You can preview the production build with `npm run preview`.
|
||||
|
||||
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
|
||||
## Speed Insights
|
||||
|
||||
Once deployed on Vercel, you can benefit from [Speed Insights](https://vercel.com/docs/concepts/speed-insights) simply by navigating to Vercel's dashboard, clicking on the 'Speed Insights' tab, and enabling the product.
|
||||
|
||||
You will get data once your application will be re-deployed and will receive visitors.
|
||||
|
||||
@@ -16,19 +16,20 @@
|
||||
"@fontsource/fira-mono": "^4.5.10",
|
||||
"@neoconfetti/svelte": "^1.0.0",
|
||||
"@playwright/test": "^1.28.1",
|
||||
"@sveltejs/adapter-vercel": "^1.0.0",
|
||||
"@sveltejs/kit": "^1.0.0",
|
||||
"@sveltejs/adapter-vercel": "^3.0.0",
|
||||
"@sveltejs/kit": "^1.5.0",
|
||||
"@types/cookie": "^0.5.1",
|
||||
"eslint": "^8.28.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-svelte3": "^4.0.0",
|
||||
"eslint-plugin-svelte": "^2.26.0",
|
||||
"prettier": "^2.8.0",
|
||||
"prettier-plugin-svelte": "^2.8.1",
|
||||
"svelte": "^3.54.0",
|
||||
"svelte-check": "^2.9.2",
|
||||
"typescript": "^4.9.3",
|
||||
"vite": "^4.0.0",
|
||||
"vitest": "^0.25.3"
|
||||
"svelte-check": "^3.0.1",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^4.3.0",
|
||||
"vitest": "^0.25.3",
|
||||
"web-vitals": "^3.3.1"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ const config = {
|
||||
command: 'npm run build && npm run preview',
|
||||
port: 4173
|
||||
},
|
||||
testDir: 'tests'
|
||||
testDir: 'tests',
|
||||
testMatch: /(.+\.)?(test|spec)\.[jt]s/
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
||||
786
examples/sveltekit-1/pnpm-lock.yaml
generated
786
examples/sveltekit-1/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
15
examples/sveltekit-1/src/app.d.ts
vendored
15
examples/sveltekit-1/src/app.d.ts
vendored
@@ -1,9 +1,12 @@
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
// and what to do when importing types
|
||||
declare namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface Platform {}
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
|
||||
63
examples/sveltekit-1/src/lib/vitals.js
Normal file
63
examples/sveltekit-1/src/lib/vitals.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import { onCLS, onFCP, onFID, onLCP, onTTFB } from 'web-vitals';
|
||||
|
||||
const vitalsUrl = 'https://vitals.vercel-analytics.com/v1/vitals';
|
||||
|
||||
function getConnectionSpeed() {
|
||||
// @ts-ignore
|
||||
return navigator?.connection?.effectiveType ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("web-vitals").Metric} metric
|
||||
* @param {{ params: { [s: string]: any; } | ArrayLike<any>; path: string; analyticsId: string; debug: boolean; }} options
|
||||
*/
|
||||
function sendToAnalytics(metric, options) {
|
||||
const page = Object.entries(options.params).reduce(
|
||||
(acc, [key, value]) => acc.replace(value, `[${key}]`),
|
||||
options.path
|
||||
);
|
||||
|
||||
const body = {
|
||||
dsn: options.analyticsId,
|
||||
id: metric.id,
|
||||
page,
|
||||
href: location.href,
|
||||
event_name: metric.name,
|
||||
value: metric.value.toString(),
|
||||
speed: getConnectionSpeed()
|
||||
};
|
||||
|
||||
if (options.debug) {
|
||||
console.log('[Web Vitals]', metric.name, JSON.stringify(body, null, 2));
|
||||
}
|
||||
|
||||
const blob = new Blob([new URLSearchParams(body).toString()], {
|
||||
// This content type is necessary for `sendBeacon`
|
||||
type: 'application/x-www-form-urlencoded'
|
||||
});
|
||||
if (navigator.sendBeacon) {
|
||||
navigator.sendBeacon(vitalsUrl, blob);
|
||||
} else
|
||||
fetch(vitalsUrl, {
|
||||
body: blob,
|
||||
method: 'POST',
|
||||
credentials: 'omit',
|
||||
keepalive: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} options
|
||||
*/
|
||||
export function webVitals(options) {
|
||||
try {
|
||||
console.log(`[Web Vitals] for page ${options.path}`);
|
||||
onFID((metric) => sendToAnalytics(metric, options));
|
||||
onTTFB((metric) => sendToAnalytics(metric, options));
|
||||
onLCP((metric) => sendToAnalytics(metric, options));
|
||||
onCLS((metric) => sendToAnalytics(metric, options));
|
||||
onFCP((metric) => sendToAnalytics(metric, options));
|
||||
} catch (err) {
|
||||
console.error(`[Web Vitals] for page ${options.path}`, err);
|
||||
}
|
||||
}
|
||||
6
examples/sveltekit-1/src/routes/+layout.server.js
Normal file
6
examples/sveltekit-1/src/routes/+layout.server.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import { env } from '$env/dynamic/private';
|
||||
|
||||
/** @type {import('./$types').LayoutServerLoad} */
|
||||
export function load() {
|
||||
return { analyticsId: env.VERCEL_ANALYTICS_ID };
|
||||
}
|
||||
@@ -1,6 +1,20 @@
|
||||
<script>
|
||||
import { browser } from '$app/environment';
|
||||
import { page } from '$app/stores';
|
||||
import { webVitals } from '$lib/vitals';
|
||||
import Header from './Header.svelte';
|
||||
import './styles.css';
|
||||
|
||||
/** @type {import('./$types').LayoutServerData} */
|
||||
export let data;
|
||||
|
||||
$: if (browser && data?.analyticsId) {
|
||||
webVitals({
|
||||
path: $page.url.pathname,
|
||||
params: $page.params,
|
||||
analyticsId: data.analyticsId
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="app">
|
||||
|
||||
@@ -107,11 +107,11 @@
|
||||
<a class="how-to-play" href="/sverdle/how-to-play">How to play</a>
|
||||
|
||||
<div class="grid" class:playing={!won} class:bad-guess={form?.badGuess}>
|
||||
{#each Array(6) as _, row}
|
||||
{#each Array.from(Array(6).keys()) as row (row)}
|
||||
{@const current = row === i}
|
||||
<h2 class="visually-hidden">Row {row + 1}</h2>
|
||||
<div class="row" class:current>
|
||||
{#each Array(5) as _, column}
|
||||
{#each Array.from(Array(5).keys()) as column (column)}
|
||||
{@const answer = data.answers[row]?.[column]}
|
||||
{@const value = data.guesses[row]?.[column] ?? ''}
|
||||
{@const selected = current && column === data.guesses[row].length}
|
||||
|
||||
@@ -2,5 +2,5 @@ import { expect, test } from '@playwright/test';
|
||||
|
||||
test('about page has expected h1', async ({ page }) => {
|
||||
await page.goto('/about');
|
||||
expect(await page.textContent('h1')).toBe('About this app');
|
||||
await expect(page.getByRole('heading', { name: 'About this app' })).toBeVisible();
|
||||
});
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
/** @type {import('vite').UserConfig} */
|
||||
const config = {
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()],
|
||||
test: {
|
||||
include: ['src/**/*.{test,spec}.{js,ts}']
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
||||
});
|
||||
|
||||
@@ -6,20 +6,20 @@
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"engines": {
|
||||
"node": "16.x"
|
||||
"node": "18.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": "^3.6.5",
|
||||
"vue": "^3.0.0"
|
||||
"core-js": "^3.30.2",
|
||||
"vue": "^3.3.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"@vue/compiler-sfc": "^3.0.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-vue": "^7.0.0"
|
||||
"@vue/cli-plugin-babel": "~5.0.8",
|
||||
"@vue/cli-plugin-eslint": "~5.0.8",
|
||||
"@vue/cli-service": "~5.0.8",
|
||||
"@vue/compiler-sfc": "^3.3.4",
|
||||
"@babel/eslint-parser": "^7.21.8",
|
||||
"eslint": "^8.4.1",
|
||||
"eslint-plugin-vue": "^9.14.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
@@ -31,7 +31,7 @@
|
||||
"eslint:recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"parser": "babel-eslint"
|
||||
"parser": "@babel/eslint-parser"
|
||||
},
|
||||
"rules": {}
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
28
internals/constants/CHANGELOG.md
Normal file
28
internals/constants/CHANGELOG.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# @vercel-internals/constants
|
||||
|
||||
## 1.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Create new help output and arg parsing for deploy command ([#10090](https://github.com/vercel/vercel/pull/10090))
|
||||
|
||||
## 1.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`346892210`](https://github.com/vercel/vercel/commit/3468922108f411482a72acd0331f0f2ee52a6d4c)]:
|
||||
- @vercel/build-utils@6.8.0
|
||||
|
||||
## 1.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`cd35071f6`](https://github.com/vercel/vercel/commit/cd35071f609d615d47bc04634c123b33768436cb)]:
|
||||
- @vercel/build-utils@6.7.5
|
||||
|
||||
## 1.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`c7bcea408`](https://github.com/vercel/vercel/commit/c7bcea408131df2d65338e50ce319a6d8e4a8a82)]:
|
||||
- @vercel/build-utils@6.7.4
|
||||
@@ -1,17 +1,15 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@vercel-internals/constants",
|
||||
"version": "1.0.4",
|
||||
"types": "dist/index.d.ts",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "6.3.2",
|
||||
"@vercel/routing-utils": "2.1.10"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@vercel-internals/tsconfig": "*",
|
||||
"@vercel-internals/tsconfig": "1.0.0",
|
||||
"@vercel/style-guide": "4.0.2",
|
||||
"typescript": "4.9.4"
|
||||
}
|
||||
|
||||
@@ -3,3 +3,7 @@ export const PROJECT_ENV_TARGET = [
|
||||
'preview',
|
||||
'development',
|
||||
] as const;
|
||||
|
||||
export const LOGO = '▲' as const;
|
||||
export const NAME = 'vercel' as const;
|
||||
export const TITLE = 'Vercel' as const;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@vercel-internals/get-package-json",
|
||||
"version": "1.0.0",
|
||||
"types": "dist/index.d.ts",
|
||||
"main": "dist/index.js",
|
||||
"files": [
|
||||
@@ -14,7 +15,7 @@
|
||||
"devDependencies": {
|
||||
"@types/jest": "29.5.0",
|
||||
"@types/node": "14.14.31",
|
||||
"@vercel-internals/tsconfig": "*",
|
||||
"@vercel-internals/tsconfig": "1.0.0",
|
||||
"@vercel/style-guide": "4.0.2",
|
||||
"jest": "29.5.0",
|
||||
"ts-jest": "29.1.0",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@vercel-internals/tsconfig",
|
||||
"version": "1.0.0",
|
||||
"description": "Node.js tsconfig file based on `@vercel/style-guide`",
|
||||
"files": [
|
||||
"tsconfig.json"
|
||||
|
||||
47
internals/types/CHANGELOG.md
Normal file
47
internals/types/CHANGELOG.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# @vercel-internals/types
|
||||
|
||||
## 1.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`a8ecf40d6`](https://github.com/vercel/vercel/commit/a8ecf40d6f50e2fc8b13b02c8ef50b3dcafad3a6)]:
|
||||
- @vercel/build-utils@6.8.3
|
||||
|
||||
## 1.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`0750517af`](https://github.com/vercel/vercel/commit/0750517af99aea41410d4f1f772ce427699554e7)]:
|
||||
- @vercel/build-utils@6.8.2
|
||||
|
||||
## 1.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`7021279b2`](https://github.com/vercel/vercel/commit/7021279b284f314a4d1bdbb4306b4c22291efa08), [`718bbd365`](https://github.com/vercel/vercel/commit/718bbd365a50271a980bdca231ca801a0eead32b)]:
|
||||
- @vercel/build-utils@6.8.1
|
||||
- @vercel-internals/constants@1.0.4
|
||||
|
||||
## 1.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`346892210`](https://github.com/vercel/vercel/commit/3468922108f411482a72acd0331f0f2ee52a6d4c)]:
|
||||
- @vercel/build-utils@6.8.0
|
||||
- @vercel-internals/constants@1.0.3
|
||||
|
||||
## 1.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`cd35071f6`](https://github.com/vercel/vercel/commit/cd35071f609d615d47bc04634c123b33768436cb)]:
|
||||
- @vercel/build-utils@6.7.5
|
||||
- @vercel-internals/constants@1.0.2
|
||||
|
||||
## 1.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`c7bcea408`](https://github.com/vercel/vercel/commit/c7bcea408131df2d65338e50ce319a6d8e4a8a82)]:
|
||||
- @vercel/build-utils@6.7.4
|
||||
- @vercel-internals/constants@1.0.1
|
||||
99
internals/types/index.d.ts
vendored
99
internals/types/index.d.ts
vendored
@@ -1,5 +1,6 @@
|
||||
import type { BuilderFunctions } from '@vercel/build-utils';
|
||||
import type { Readable, Writable } from 'stream';
|
||||
import type * as tty from 'tty';
|
||||
import type { Route } from '@vercel/routing-utils';
|
||||
import { PROJECT_ENV_TARGET } from '@vercel-internals/constants';
|
||||
|
||||
@@ -157,6 +158,7 @@ export type Deployment = {
|
||||
errorLink?: string;
|
||||
errorMessage?: string | null;
|
||||
errorStep?: string;
|
||||
forced?: boolean;
|
||||
functions?: BuilderFunctions | null;
|
||||
gitSource?: {
|
||||
org?: string;
|
||||
@@ -183,6 +185,7 @@ export type Deployment = {
|
||||
ownerId?: string;
|
||||
plan?: 'enterprise' | 'hobby' | 'oss' | 'pro';
|
||||
previewCommentsEnabled?: boolean;
|
||||
private?: boolean;
|
||||
projectId?: string;
|
||||
projectSettings?: {
|
||||
buildCommand?: string | null;
|
||||
@@ -353,7 +356,7 @@ export interface Project extends ProjectSettings {
|
||||
link?: ProjectLinkData;
|
||||
alias?: ProjectAliasTarget[];
|
||||
latestDeployments?: Partial<Deployment>[];
|
||||
lastRollbackTarget: RollbackTarget | null;
|
||||
lastAliasRequest?: LastAliasRequest | null;
|
||||
}
|
||||
|
||||
export interface Org {
|
||||
@@ -363,31 +366,77 @@ export interface Org {
|
||||
}
|
||||
|
||||
export interface ProjectLink {
|
||||
/**
|
||||
* ID of the Vercel Project.
|
||||
*/
|
||||
projectId: string;
|
||||
/**
|
||||
* User or Team ID of the owner of the Vercel Project.
|
||||
*/
|
||||
orgId: string;
|
||||
/**
|
||||
* When linked as a repository, contains the absolute path
|
||||
* to the root directory of the repository.
|
||||
*/
|
||||
repoRoot?: string;
|
||||
/**
|
||||
* When linked as a repository, contains the relative path
|
||||
* to the selected project root directory.
|
||||
*/
|
||||
projectRootDirectory?: string;
|
||||
}
|
||||
|
||||
export interface PaginationOptions {
|
||||
prev: number;
|
||||
/**
|
||||
* Amount of items in the current page.
|
||||
* @example 20
|
||||
*/
|
||||
count: number;
|
||||
next?: number;
|
||||
/**
|
||||
* Timestamp that must be used to request the next page.
|
||||
* @example 1540095775951
|
||||
*/
|
||||
next: number | null;
|
||||
/**
|
||||
* Timestamp that must be used to request the previous page.
|
||||
* @example 1540095775951
|
||||
*/
|
||||
prev: number | null;
|
||||
}
|
||||
|
||||
export type ProjectLinkResult =
|
||||
| { status: 'linked'; org: Org; project: Project }
|
||||
| { status: 'not_linked'; org: null; project: null }
|
||||
| {
|
||||
status: 'error';
|
||||
exitCode: number;
|
||||
reason?:
|
||||
| 'HEADLESS'
|
||||
| 'NOT_AUTHORIZED'
|
||||
| 'TEAM_DELETED'
|
||||
| 'PATH_IS_FILE'
|
||||
| 'INVALID_ROOT_DIRECTORY'
|
||||
| 'MISSING_PROJECT_SETTINGS';
|
||||
};
|
||||
export type ProjectLinked = {
|
||||
status: 'linked';
|
||||
org: Org;
|
||||
project: Project;
|
||||
repoRoot?: string;
|
||||
};
|
||||
|
||||
export type ProjectNotLinked = {
|
||||
status: 'not_linked';
|
||||
org: null;
|
||||
project: null;
|
||||
};
|
||||
|
||||
export type ProjectLinkedError = {
|
||||
status: 'error';
|
||||
exitCode: number;
|
||||
reason?:
|
||||
| 'HEADLESS'
|
||||
| 'NOT_AUTHORIZED'
|
||||
| 'TEAM_DELETED'
|
||||
| 'PATH_IS_FILE'
|
||||
| 'INVALID_ROOT_DIRECTORY'
|
||||
| 'MISSING_PROJECT_SETTINGS';
|
||||
};
|
||||
|
||||
export type ProjectLinkResult =
|
||||
| ProjectLinked
|
||||
| ProjectNotLinked
|
||||
| ProjectLinkedError;
|
||||
|
||||
/**
|
||||
* @deprecated - `RollbackJobStatus` has been replace by `LastAliasRequest['jobStatus']`.
|
||||
*/
|
||||
export type RollbackJobStatus =
|
||||
| 'pending'
|
||||
| 'in-progress'
|
||||
@@ -395,6 +444,10 @@ export type RollbackJobStatus =
|
||||
| 'failed'
|
||||
| 'skipped';
|
||||
|
||||
/**
|
||||
* @deprecated - `RollbackTarget` has been renamed to `LastAliasRequest` so it can
|
||||
* be shared with "promote".
|
||||
*/
|
||||
export interface RollbackTarget {
|
||||
fromDeploymentId: string;
|
||||
jobStatus: RollbackJobStatus;
|
||||
@@ -402,6 +455,14 @@ export interface RollbackTarget {
|
||||
toDeploymentId: string;
|
||||
}
|
||||
|
||||
export interface LastAliasRequest {
|
||||
fromDeploymentId: string;
|
||||
jobStatus: 'pending' | 'in-progress' | 'succeeded' | 'failed' | 'skipped';
|
||||
requestedAt: number;
|
||||
toDeploymentId: string;
|
||||
type: 'rollback' | 'promote';
|
||||
}
|
||||
|
||||
export interface Token {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -571,6 +632,6 @@ export interface WritableTTY extends Writable {
|
||||
|
||||
export interface Stdio {
|
||||
stdin: ReadableTTY;
|
||||
stdout: WritableTTY;
|
||||
stderr: WritableTTY;
|
||||
stdout: tty.WriteStream;
|
||||
stderr: tty.WriteStream;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@vercel-internals/types",
|
||||
"version": "1.0.6",
|
||||
"types": "index.d.ts",
|
||||
"main": "index.d.ts",
|
||||
"dependencies": {
|
||||
"@types/node": "14.14.31",
|
||||
"@vercel-internals/constants": "*",
|
||||
"@vercel/build-utils": "6.3.2",
|
||||
"@vercel/routing-utils": "2.1.10"
|
||||
"@vercel-internals/constants": "1.0.4",
|
||||
"@vercel/build-utils": "6.8.3",
|
||||
"@vercel/routing-utils": "2.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vercel-internals/tsconfig": "*",
|
||||
"@vercel-internals/tsconfig": "1.0.0",
|
||||
"@vercel/style-guide": "4.0.2",
|
||||
"typescript": "4.9.4"
|
||||
}
|
||||
|
||||
13
lerna.json
13
lerna.json
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"npmClient": "pnpm",
|
||||
"useWorkspaces": true,
|
||||
"packages": ["packages/*"],
|
||||
"command": {
|
||||
"publish": {
|
||||
"npmClient": "npm",
|
||||
"allowBranch": ["main"],
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
}
|
||||
},
|
||||
"version": "independent"
|
||||
}
|
||||
@@ -21,6 +21,7 @@
|
||||
"eslint-plugin-jest": "26.1.5",
|
||||
"execa": "3.2.0",
|
||||
"fs-extra": "11.1.0",
|
||||
"glob": "10.2.3",
|
||||
"husky": "7.0.4",
|
||||
"jest": "29.5.0",
|
||||
"json5": "2.1.1",
|
||||
@@ -31,7 +32,7 @@
|
||||
"source-map-support": "0.5.12",
|
||||
"ts-eager": "2.0.2",
|
||||
"ts-jest": "29.1.0",
|
||||
"turbo": "1.9.4",
|
||||
"turbo": "1.10.12",
|
||||
"typescript": "4.9.5"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -47,8 +48,8 @@
|
||||
"prettier-check": "prettier --check .",
|
||||
"prepare": "husky install",
|
||||
"pack": "cd utils && node -r ts-eager/register ./pack.ts",
|
||||
"version:prepare": "changeset version && pnpm install --no-frozen-lockfile",
|
||||
"release": "changeset publish"
|
||||
"ci:version": "changeset version && pnpm install --no-frozen-lockfile",
|
||||
"ci:publish": "pnpm publish -r && changeset tag"
|
||||
},
|
||||
"lint-staged": {
|
||||
"./{*,{api,packages,test,utils}/**/*}.{js,ts}": [
|
||||
|
||||
43
packages/build-utils/CHANGELOG.md
Normal file
43
packages/build-utils/CHANGELOG.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# @vercel/build-utils
|
||||
|
||||
## 6.8.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix `getPrefixedEnvVars()` to handle `VERCEL_BRANCH_URL` ([#10315](https://github.com/vercel/vercel/pull/10315))
|
||||
|
||||
## 6.8.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Push back `nodejs16.x` discontinue date to `2024-02-06` ([#10209](https://github.com/vercel/vercel/pull/10209))
|
||||
|
||||
## 6.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Revert "[build-utils] Allow file-ref sema to be controlled through env flag" ([#10167](https://github.com/vercel/vercel/pull/10167))
|
||||
|
||||
## 6.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Add `getNodeBinPaths()` and `traverseUpDirectories()` functions ([#10150](https://github.com/vercel/vercel/pull/10150))
|
||||
|
||||
## 6.7.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Publish missing build-utils ([`cd35071f6`](https://github.com/vercel/vercel/commit/cd35071f609d615d47bc04634c123b33768436cb))
|
||||
|
||||
## 6.7.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Remove usage of `env` from Edge Functions and Middleware ([#10018](https://github.com/vercel/vercel/pull/10018))
|
||||
|
||||
## 6.7.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Deprecate Node.js 14.x and 16.x with warning ([#9976](https://github.com/vercel/vercel/pull/9976))
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/build-utils",
|
||||
"version": "6.7.2",
|
||||
"version": "6.8.3",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
|
||||
@@ -27,12 +27,6 @@ export class EdgeFunction {
|
||||
*/
|
||||
files: Files;
|
||||
|
||||
/**
|
||||
* Extra environment variables in use for the user code, to be
|
||||
* assigned to the edge function.
|
||||
*/
|
||||
envVarsInUse?: string[];
|
||||
|
||||
/**
|
||||
* Extra binary files to be included in the edge function
|
||||
*/
|
||||
@@ -50,7 +44,6 @@ export class EdgeFunction {
|
||||
this.deploymentTarget = params.deploymentTarget;
|
||||
this.entrypoint = params.entrypoint;
|
||||
this.files = params.files;
|
||||
this.envVarsInUse = params.envVarsInUse;
|
||||
this.assets = params.assets;
|
||||
this.regions = params.regions;
|
||||
this.framework = params.framework;
|
||||
|
||||
@@ -5,13 +5,7 @@ import path from 'path';
|
||||
import Sema from 'async-sema';
|
||||
import { FileBase } from './types';
|
||||
|
||||
const DEFAULT_SEMA = 20;
|
||||
const semaToPreventEMFILE = new Sema(
|
||||
parseInt(
|
||||
process.env.VERCEL_INTERNAL_FILE_FS_REF_SEMA || String(DEFAULT_SEMA),
|
||||
10
|
||||
) || DEFAULT_SEMA
|
||||
);
|
||||
const semaToPreventEMFILE = new Sema(20);
|
||||
|
||||
interface FileFsRefOptions {
|
||||
mode?: number;
|
||||
|
||||
@@ -12,13 +12,7 @@ interface FileRefOptions {
|
||||
mutable?: boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_SEMA = 5;
|
||||
const semaToDownloadFromS3 = new Sema(
|
||||
parseInt(
|
||||
process.env.VERCEL_INTERNAL_FILE_REF_SEMA || String(DEFAULT_SEMA),
|
||||
10
|
||||
) || DEFAULT_SEMA
|
||||
);
|
||||
const semaToDownloadFromS3 = new Sema(5);
|
||||
|
||||
class BailableError extends Error {
|
||||
public bail: boolean;
|
||||
|
||||
@@ -6,8 +6,18 @@ import debug from '../debug';
|
||||
function getOptions() {
|
||||
const options = [
|
||||
{ major: 18, range: '18.x', runtime: 'nodejs18.x' },
|
||||
{ major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
||||
{ major: 14, range: '14.x', runtime: 'nodejs14.x' },
|
||||
{
|
||||
major: 16,
|
||||
range: '16.x',
|
||||
runtime: 'nodejs16.x',
|
||||
discontinueDate: new Date('2024-02-06'),
|
||||
},
|
||||
{
|
||||
major: 14,
|
||||
range: '14.x',
|
||||
runtime: 'nodejs14.x',
|
||||
discontinueDate: new Date('2023-08-15'),
|
||||
},
|
||||
{
|
||||
major: 12,
|
||||
range: '12.x',
|
||||
|
||||
@@ -44,23 +44,33 @@ export interface ScanParentDirsResult {
|
||||
lockfileVersion?: number;
|
||||
}
|
||||
|
||||
export interface WalkParentDirsProps {
|
||||
export interface TraverseUpDirectoriesProps {
|
||||
/**
|
||||
* The highest directory, typically the workPath root of the project.
|
||||
* If this directory is reached and it doesn't contain the file, null is returned.
|
||||
*/
|
||||
base: string;
|
||||
/**
|
||||
* The directory to start searching, typically the same directory of the entrypoint.
|
||||
* If this directory doesn't contain the file, the parent is checked, etc.
|
||||
* The directory to start iterating from, typically the same directory of the entrypoint.
|
||||
*/
|
||||
start: string;
|
||||
/**
|
||||
* The highest directory, typically the workPath root of the project.
|
||||
*/
|
||||
base?: string;
|
||||
}
|
||||
|
||||
export interface WalkParentDirsProps
|
||||
extends Required<TraverseUpDirectoriesProps> {
|
||||
/**
|
||||
* The name of the file to search for, typically `package.json` or `Gemfile`.
|
||||
*/
|
||||
filename: string;
|
||||
}
|
||||
|
||||
export interface WalkParentDirsMultiProps
|
||||
extends Required<TraverseUpDirectoriesProps> {
|
||||
/**
|
||||
* The name of the file to search for, typically `package.json` or `Gemfile`.
|
||||
*/
|
||||
filenames: string[];
|
||||
}
|
||||
|
||||
export interface SpawnOptionsExtended extends SpawnOptions {
|
||||
/**
|
||||
* Pretty formatted command that is being spawned for logging purposes.
|
||||
@@ -131,6 +141,24 @@ export async function execCommand(command: string, options: SpawnOptions = {}) {
|
||||
return true;
|
||||
}
|
||||
|
||||
export function* traverseUpDirectories({
|
||||
start,
|
||||
base,
|
||||
}: TraverseUpDirectoriesProps) {
|
||||
let current: string | undefined = path.normalize(start);
|
||||
const normalizedRoot = base ? path.normalize(base) : undefined;
|
||||
while (current) {
|
||||
yield current;
|
||||
if (current === normalizedRoot) break;
|
||||
// Go up one directory
|
||||
const next = path.join(current, '..');
|
||||
current = next === current ? undefined : next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `getNodeBinPaths()` instead.
|
||||
*/
|
||||
export async function getNodeBinPath({
|
||||
cwd,
|
||||
}: {
|
||||
@@ -141,6 +169,15 @@ export async function getNodeBinPath({
|
||||
return path.join(dir, 'node_modules', '.bin');
|
||||
}
|
||||
|
||||
export function getNodeBinPaths({
|
||||
start,
|
||||
base,
|
||||
}: TraverseUpDirectoriesProps): string[] {
|
||||
return Array.from(traverseUpDirectories({ start, base })).map(dir =>
|
||||
path.join(dir, 'node_modules/.bin')
|
||||
);
|
||||
}
|
||||
|
||||
async function chmodPlusX(fsPath: string) {
|
||||
const s = await fs.stat(fsPath);
|
||||
const newMode = s.mode | 64 | 8 | 1; // eslint-disable-line no-bitwise
|
||||
@@ -297,22 +334,14 @@ export async function walkParentDirs({
|
||||
}: WalkParentDirsProps): Promise<string | null> {
|
||||
assert(path.isAbsolute(base), 'Expected "base" to be absolute path');
|
||||
assert(path.isAbsolute(start), 'Expected "start" to be absolute path');
|
||||
let parent = '';
|
||||
|
||||
for (let current = start; base.length <= current.length; current = parent) {
|
||||
const fullPath = path.join(current, filename);
|
||||
for (const dir of traverseUpDirectories({ start, base })) {
|
||||
const fullPath = path.join(dir, filename);
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
if (await fs.pathExists(fullPath)) {
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
parent = path.dirname(current);
|
||||
|
||||
if (parent === current) {
|
||||
// Reached root directory of the filesystem
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -322,14 +351,9 @@ async function walkParentDirsMulti({
|
||||
base,
|
||||
start,
|
||||
filenames,
|
||||
}: {
|
||||
base: string;
|
||||
start: string;
|
||||
filenames: string[];
|
||||
}): Promise<(string | undefined)[]> {
|
||||
let parent = '';
|
||||
for (let current = start; base.length <= current.length; current = parent) {
|
||||
const fullPaths = filenames.map(f => path.join(current, f));
|
||||
}: WalkParentDirsMultiProps): Promise<(string | undefined)[]> {
|
||||
for (const dir of traverseUpDirectories({ start, base })) {
|
||||
const fullPaths = filenames.map(f => path.join(dir, f));
|
||||
const existResults = await Promise.all(
|
||||
fullPaths.map(f => fs.pathExists(f))
|
||||
);
|
||||
@@ -338,13 +362,6 @@ async function walkParentDirsMulti({
|
||||
if (foundOneOrMore) {
|
||||
return fullPaths.map((f, i) => (existResults[i] ? f : undefined));
|
||||
}
|
||||
|
||||
parent = path.dirname(current);
|
||||
|
||||
if (parent === current) {
|
||||
// Reached root directory of the filesystem
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
|
||||
@@ -14,7 +14,12 @@ export function getPrefixedEnvVars({
|
||||
envs: Envs;
|
||||
}): Envs {
|
||||
const vercelSystemEnvPrefix = 'VERCEL_';
|
||||
const allowed = ['VERCEL_URL', 'VERCEL_ENV', 'VERCEL_REGION'];
|
||||
const allowed = [
|
||||
'VERCEL_URL',
|
||||
'VERCEL_ENV',
|
||||
'VERCEL_REGION',
|
||||
'VERCEL_BRANCH_URL',
|
||||
];
|
||||
const newEnvs: Envs = {};
|
||||
if (envPrefix && envs.VERCEL_URL) {
|
||||
Object.keys(envs)
|
||||
|
||||
@@ -30,7 +30,9 @@ import {
|
||||
getNodeVersion,
|
||||
getSpawnOptions,
|
||||
getNodeBinPath,
|
||||
getNodeBinPaths,
|
||||
scanParentDirs,
|
||||
traverseUpDirectories,
|
||||
} from './fs/run-user-scripts';
|
||||
import {
|
||||
getLatestNodeVersion,
|
||||
@@ -43,6 +45,7 @@ import { getPlatformEnv } from './get-platform-env';
|
||||
import { getPrefixedEnvVars } from './get-prefixed-env-vars';
|
||||
import { cloneEnv } from './clone-env';
|
||||
import { hardLinkDir } from './hard-link-dir';
|
||||
import { validateNpmrc } from './validate-npmrc';
|
||||
|
||||
export {
|
||||
FileBlob,
|
||||
@@ -67,6 +70,7 @@ export {
|
||||
spawnCommand,
|
||||
walkParentDirs,
|
||||
getNodeBinPath,
|
||||
getNodeBinPaths,
|
||||
runNpmInstall,
|
||||
runBundleInstall,
|
||||
runPipInstall,
|
||||
@@ -88,6 +92,8 @@ export {
|
||||
getIgnoreFilter,
|
||||
cloneEnv,
|
||||
hardLinkDir,
|
||||
traverseUpDirectories,
|
||||
validateNpmrc,
|
||||
};
|
||||
|
||||
export { EdgeFunction } from './edge-function';
|
||||
|
||||
26
packages/build-utils/src/validate-npmrc.ts
Normal file
26
packages/build-utils/src/validate-npmrc.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { join } from 'path';
|
||||
import { readFile } from 'fs/promises';
|
||||
|
||||
/**
|
||||
* Checks if there is a `.npmrc` in the cwd (project root) and makes sure it
|
||||
* doesn't contain a `use-node-version`. This config setting is not supported
|
||||
* since it causes the package manager to install the Node.js version which in
|
||||
* the case of newer Node.js versions is not compatible with AWS due to
|
||||
* outdated GLIBC binaries.
|
||||
*
|
||||
* @see https://pnpm.io/npmrc#use-node-version
|
||||
*
|
||||
* @param cwd The current working directory (e.g. project root);
|
||||
*/
|
||||
export async function validateNpmrc(cwd: string): Promise<void> {
|
||||
const npmrc = await readFile(join(cwd, '.npmrc'), 'utf-8').catch(err => {
|
||||
if (err.code !== 'ENOENT') throw err;
|
||||
});
|
||||
|
||||
const nodeRegExp = /(?<!#.*)use-node-version/;
|
||||
if (npmrc?.match(nodeRegExp)) {
|
||||
throw new Error(
|
||||
'Detected unsupported "use-node-version" in your ".npmrc". Please use "engines" in your "package.json" instead.'
|
||||
);
|
||||
}
|
||||
}
|
||||
2
packages/build-utils/test/fixtures/29-npmrc/comment-use-node-version/.npmrc
vendored
Normal file
2
packages/build-utils/test/fixtures/29-npmrc/comment-use-node-version/.npmrc
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
foo=bar
|
||||
# use-node-version=16.16.0
|
||||
1
packages/build-utils/test/fixtures/29-npmrc/good/.npmrc
vendored
Normal file
1
packages/build-utils/test/fixtures/29-npmrc/good/.npmrc
vendored
Normal file
@@ -0,0 +1 @@
|
||||
foo=bar
|
||||
3
packages/build-utils/test/fixtures/29-npmrc/has-use-node-version/.npmrc
vendored
Normal file
3
packages/build-utils/test/fixtures/29-npmrc/has-use-node-version/.npmrc
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
foo=bar
|
||||
# the next line is not supported
|
||||
use-node-version=16.16.0
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": "16.14.0"
|
||||
"node": "18.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": "14.x"
|
||||
"node": "18.x"
|
||||
}
|
||||
}
|
||||
|
||||
17
packages/build-utils/test/unit.get-node-bin-paths.test.ts
vendored
Normal file
17
packages/build-utils/test/unit.get-node-bin-paths.test.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import { join } from 'path';
|
||||
import { getNodeBinPaths } from '../src/fs/run-user-scripts';
|
||||
|
||||
describe('getNodeBinPaths()', () => {
|
||||
const cwd = process.cwd();
|
||||
|
||||
it('should return array of `node_modules/.bin` paths', () => {
|
||||
const start = join(cwd, 'foo/bar/baz');
|
||||
const paths = getNodeBinPaths({ start, base: cwd });
|
||||
expect(paths).toEqual([
|
||||
join(cwd, 'foo/bar/baz/node_modules/.bin'),
|
||||
join(cwd, 'foo/bar/node_modules/.bin'),
|
||||
join(cwd, 'foo/node_modules/.bin'),
|
||||
join(cwd, 'node_modules/.bin'),
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -13,6 +13,8 @@ describe('Test `getPrefixedEnvVars()`', () => {
|
||||
envs: {
|
||||
VERCEL: '1',
|
||||
VERCEL_URL: 'example.vercel.sh',
|
||||
VERCEL_ENV: 'production',
|
||||
VERCEL_BRANCH_URL: 'example-git-main-acme.vercel.app',
|
||||
USER_ENV_VAR_NOT_VERCEL: 'example.com',
|
||||
VERCEL_ARTIFACTS_TOKEN: 'abc123',
|
||||
FOO: 'bar',
|
||||
@@ -20,6 +22,8 @@ describe('Test `getPrefixedEnvVars()`', () => {
|
||||
},
|
||||
want: {
|
||||
NEXT_PUBLIC_VERCEL_URL: 'example.vercel.sh',
|
||||
NEXT_PUBLIC_VERCEL_ENV: 'production',
|
||||
NEXT_PUBLIC_VERCEL_BRANCH_URL: 'example-git-main-acme.vercel.app',
|
||||
TURBO_CI_VENDOR_ENV_KEY: 'NEXT_PUBLIC_VERCEL_',
|
||||
},
|
||||
},
|
||||
|
||||
66
packages/build-utils/test/unit.test.ts
vendored
66
packages/build-utils/test/unit.test.ts
vendored
@@ -140,20 +140,20 @@ it('should ignore node version in vercel dev getNodeVersion()', async () => {
|
||||
|
||||
it('should select project setting from config when no package.json is found and fallback undefined', async () => {
|
||||
expect(
|
||||
await getNodeVersion('/tmp', undefined, { nodeVersion: '16.x' }, {})
|
||||
).toHaveProperty('range', '16.x');
|
||||
await getNodeVersion('/tmp', undefined, { nodeVersion: '18.x' }, {})
|
||||
).toHaveProperty('range', '18.x');
|
||||
expect(warningMessages).toStrictEqual([]);
|
||||
});
|
||||
|
||||
it('should select project setting from config when no package.json is found and fallback is null', async () => {
|
||||
expect(
|
||||
await getNodeVersion('/tmp', null as any, { nodeVersion: '16.x' }, {})
|
||||
).toHaveProperty('range', '16.x');
|
||||
await getNodeVersion('/tmp', null as any, { nodeVersion: '18.x' }, {})
|
||||
).toHaveProperty('range', '18.x');
|
||||
expect(warningMessages).toStrictEqual([]);
|
||||
});
|
||||
|
||||
it('should select project setting from fallback when no package.json is found', async () => {
|
||||
expect(await getNodeVersion('/tmp', '16.x')).toHaveProperty('range', '16.x');
|
||||
expect(await getNodeVersion('/tmp', '18.x')).toHaveProperty('range', '18.x');
|
||||
expect(warningMessages).toStrictEqual([]);
|
||||
});
|
||||
|
||||
@@ -165,9 +165,9 @@ it('should prefer package.json engines over project setting from config and warn
|
||||
{ nodeVersion: '12.x' },
|
||||
{}
|
||||
)
|
||||
).toHaveProperty('range', '14.x');
|
||||
).toHaveProperty('range', '18.x');
|
||||
expect(warningMessages).toStrictEqual([
|
||||
'Warning: Due to "engines": { "node": "14.x" } in your `package.json` file, the Node.js Version defined in your Project Settings ("12.x") will not apply. Learn More: http://vercel.link/node-version',
|
||||
'Warning: Due to "engines": { "node": "18.x" } in your `package.json` file, the Node.js Version defined in your Project Settings ("12.x") will not apply. Learn More: http://vercel.link/node-version',
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -179,9 +179,9 @@ it('should warn when package.json engines is exact version', async () => {
|
||||
{},
|
||||
{}
|
||||
)
|
||||
).toHaveProperty('range', '16.x');
|
||||
).toHaveProperty('range', '18.x');
|
||||
expect(warningMessages).toStrictEqual([
|
||||
'Warning: Detected "engines": { "node": "16.14.0" } in your `package.json` with major.minor.patch, but only major Node.js Version can be selected. Learn More: http://vercel.link/node-version',
|
||||
'Warning: Detected "engines": { "node": "18.2.0" } in your `package.json` with major.minor.patch, but only major Node.js Version can be selected. Learn More: http://vercel.link/node-version',
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -204,30 +204,30 @@ it('should not warn when package.json engines matches project setting from confi
|
||||
await getNodeVersion(
|
||||
path.join(__dirname, 'pkg-engine-node'),
|
||||
undefined,
|
||||
{ nodeVersion: '14' },
|
||||
{ nodeVersion: '18' },
|
||||
{}
|
||||
)
|
||||
).toHaveProperty('range', '14.x');
|
||||
).toHaveProperty('range', '18.x');
|
||||
expect(warningMessages).toStrictEqual([]);
|
||||
|
||||
expect(
|
||||
await getNodeVersion(
|
||||
path.join(__dirname, 'pkg-engine-node'),
|
||||
undefined,
|
||||
{ nodeVersion: '14.x' },
|
||||
{ nodeVersion: '18.x' },
|
||||
{}
|
||||
)
|
||||
).toHaveProperty('range', '14.x');
|
||||
).toHaveProperty('range', '18.x');
|
||||
expect(warningMessages).toStrictEqual([]);
|
||||
|
||||
expect(
|
||||
await getNodeVersion(
|
||||
path.join(__dirname, 'pkg-engine-node'),
|
||||
undefined,
|
||||
{ nodeVersion: '<15' },
|
||||
{ nodeVersion: '<19' },
|
||||
{}
|
||||
)
|
||||
).toHaveProperty('range', '14.x');
|
||||
).toHaveProperty('range', '18.x');
|
||||
expect(warningMessages).toStrictEqual([]);
|
||||
});
|
||||
|
||||
@@ -238,7 +238,7 @@ it('should get latest node version', async () => {
|
||||
it('should throw for discontinued versions', async () => {
|
||||
// Mock a future date so that Node 8 and 10 become discontinued
|
||||
const realDateNow = Date.now.bind(global.Date);
|
||||
global.Date.now = () => new Date('2022-10-15').getTime();
|
||||
global.Date.now = () => new Date('2024-02-13').getTime();
|
||||
|
||||
expect(getSupportedNodeVersion('8.10.x', false)).rejects.toThrow();
|
||||
expect(getSupportedNodeVersion('8.10.x', true)).rejects.toThrow();
|
||||
@@ -246,12 +246,18 @@ it('should throw for discontinued versions', async () => {
|
||||
expect(getSupportedNodeVersion('10.x', true)).rejects.toThrow();
|
||||
expect(getSupportedNodeVersion('12.x', false)).rejects.toThrow();
|
||||
expect(getSupportedNodeVersion('12.x', true)).rejects.toThrow();
|
||||
expect(getSupportedNodeVersion('14.x', false)).rejects.toThrow();
|
||||
expect(getSupportedNodeVersion('14.x', true)).rejects.toThrow();
|
||||
expect(getSupportedNodeVersion('16.x', false)).rejects.toThrow();
|
||||
expect(getSupportedNodeVersion('16.x', true)).rejects.toThrow();
|
||||
|
||||
const discontinued = getDiscontinuedNodeVersions();
|
||||
expect(discontinued.length).toBe(3);
|
||||
expect(discontinued[0]).toHaveProperty('range', '12.x');
|
||||
expect(discontinued[1]).toHaveProperty('range', '10.x');
|
||||
expect(discontinued[2]).toHaveProperty('range', '8.10.x');
|
||||
expect(discontinued.length).toBe(5);
|
||||
expect(discontinued[0]).toHaveProperty('range', '16.x');
|
||||
expect(discontinued[1]).toHaveProperty('range', '14.x');
|
||||
expect(discontinued[2]).toHaveProperty('range', '12.x');
|
||||
expect(discontinued[3]).toHaveProperty('range', '10.x');
|
||||
expect(discontinued[4]).toHaveProperty('range', '8.10.x');
|
||||
|
||||
global.Date.now = realDateNow;
|
||||
});
|
||||
@@ -277,11 +283,31 @@ it('should warn for deprecated versions, soon to be discontinued', async () => {
|
||||
'major',
|
||||
12
|
||||
);
|
||||
expect(await getSupportedNodeVersion('14.x', false)).toHaveProperty(
|
||||
'major',
|
||||
14
|
||||
);
|
||||
expect(await getSupportedNodeVersion('14.x', true)).toHaveProperty(
|
||||
'major',
|
||||
14
|
||||
);
|
||||
expect(await getSupportedNodeVersion('16.x', false)).toHaveProperty(
|
||||
'major',
|
||||
16
|
||||
);
|
||||
expect(await getSupportedNodeVersion('16.x', true)).toHaveProperty(
|
||||
'major',
|
||||
16
|
||||
);
|
||||
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": "18.x" } in your `package.json` file to use Node.js 18.',
|
||||
'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 18.x in your Project Settings to use Node.js 18.',
|
||||
'Error: Node.js version 12.x has reached End-of-Life. Deployments created on or after 2022-10-03 will fail to build. Please set "engines": { "node": "18.x" } in your `package.json` file to use Node.js 18.',
|
||||
'Error: Node.js version 12.x has reached End-of-Life. Deployments created on or after 2022-10-03 will fail to build. Please set Node.js Version to 18.x in your Project Settings to use Node.js 18.',
|
||||
'Error: Node.js version 14.x has reached End-of-Life. Deployments created on or after 2023-08-15 will fail to build. Please set "engines": { "node": "18.x" } in your `package.json` file to use Node.js 18.',
|
||||
'Error: Node.js version 14.x has reached End-of-Life. Deployments created on or after 2023-08-15 will fail to build. Please set Node.js Version to 18.x in your Project Settings to use Node.js 18.',
|
||||
'Error: Node.js version 16.x has reached End-of-Life. Deployments created on or after 2024-02-06 will fail to build. Please set "engines": { "node": "18.x" } in your `package.json` file to use Node.js 18.',
|
||||
'Error: Node.js version 16.x has reached End-of-Life. Deployments created on or after 2024-02-06 will fail to build. Please set Node.js Version to 18.x in your Project Settings to use Node.js 18.',
|
||||
]);
|
||||
|
||||
global.Date.now = realDateNow;
|
||||
|
||||
50
packages/build-utils/test/unit.traverse-up-directories.test.ts
vendored
Normal file
50
packages/build-utils/test/unit.traverse-up-directories.test.ts
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
import { traverseUpDirectories } from '../src/fs/run-user-scripts';
|
||||
|
||||
const isWindows = process.platform === 'win32';
|
||||
|
||||
describe('traverseUpDirectories()', () => {
|
||||
test.each(
|
||||
isWindows
|
||||
? [
|
||||
{
|
||||
start: 'C:\\foo\\bar\\baz',
|
||||
expected: ['C:\\foo\\bar\\baz', 'C:\\foo\\bar', 'C:\\foo', 'C:\\'],
|
||||
},
|
||||
{
|
||||
start: 'C:\\foo\\..\\bar\\.\\baz',
|
||||
expected: ['C:\\bar\\baz', 'C:\\bar', 'C:\\'],
|
||||
},
|
||||
{
|
||||
start: 'C:\\foo\\bar\\baz\\another',
|
||||
base: 'C:\\foo\\bar',
|
||||
expected: [
|
||||
'C:\\foo\\bar\\baz\\another',
|
||||
'C:\\foo\\bar\\baz',
|
||||
'C:\\foo\\bar',
|
||||
],
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
start: '/foo/bar/baz',
|
||||
expected: ['/foo/bar/baz', '/foo/bar', '/foo', '/'],
|
||||
},
|
||||
{
|
||||
start: '/foo/../bar/./baz',
|
||||
expected: ['/bar/baz', '/bar', '/'],
|
||||
},
|
||||
{
|
||||
start: '/foo/bar/baz/another',
|
||||
base: '/foo/bar',
|
||||
expected: ['/foo/bar/baz/another', '/foo/bar/baz', '/foo/bar'],
|
||||
},
|
||||
]
|
||||
)(
|
||||
'should traverse start="$start", base="$base"',
|
||||
({ start, base, expected }) => {
|
||||
expect(Array.from(traverseUpDirectories({ start, base }))).toEqual(
|
||||
expected
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
22
packages/build-utils/test/unit.validate-npmrc.test.ts
vendored
Normal file
22
packages/build-utils/test/unit.validate-npmrc.test.ts
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import { join } from 'path';
|
||||
import { validateNpmrc } from '../src/validate-npmrc';
|
||||
|
||||
const fixture = (name: string) => join(__dirname, 'fixtures', '29-npmrc', name);
|
||||
|
||||
describe('validateNpmrc', () => {
|
||||
it('should not error with no use-node-version', async () => {
|
||||
await expect(validateNpmrc(fixture('good'))).resolves.toBe(undefined);
|
||||
});
|
||||
|
||||
it('should throw when use-node-version is found', async () => {
|
||||
await expect(
|
||||
validateNpmrc(fixture('has-use-node-version'))
|
||||
).rejects.toThrow('Detected unsupported');
|
||||
});
|
||||
|
||||
it('should not error when use-node-version is commented out', async () => {
|
||||
await expect(
|
||||
validateNpmrc(fixture('comment-use-node-version'))
|
||||
).resolves.toBe(undefined);
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,324 @@
|
||||
# vercel
|
||||
|
||||
## 31.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Be looser in tests with mock server urls ([#10300](https://github.com/vercel/vercel/pull/10300))
|
||||
|
||||
- Handle calls for deployment aliases when mocking deployments ([#10303](https://github.com/vercel/vercel/pull/10303))
|
||||
|
||||
- Remove unused code ([#10309](https://github.com/vercel/vercel/pull/10309))
|
||||
|
||||
- Updated dependencies [[`5bf1fe4c7`](https://github.com/vercel/vercel/commit/5bf1fe4c743f6be3f7d5a24447ea5b083a68dc67), [`a8ecf40d6`](https://github.com/vercel/vercel/commit/a8ecf40d6f50e2fc8b13b02c8ef50b3dcafad3a6), [`08da4b9c9`](https://github.com/vercel/vercel/commit/08da4b9c923501d9d28eb6e3f26f4605fee83042), [`0945d24cb`](https://github.com/vercel/vercel/commit/0945d24cbe901ca3f0eedd011251ad499c72d472)]:
|
||||
- @vercel/next@3.9.4
|
||||
- @vercel/build-utils@6.8.3
|
||||
- @vercel/remix-builder@1.10.0
|
||||
- @vercel/node@2.15.9
|
||||
- @vercel/static-build@1.3.45
|
||||
|
||||
## 31.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Migrate list command to new structure ([#10284](https://github.com/vercel/vercel/pull/10284))
|
||||
|
||||
- Migrate whoami command to new structure ([#10266](https://github.com/vercel/vercel/pull/10266))
|
||||
|
||||
- Migrate logs command to new structure ([#10281](https://github.com/vercel/vercel/pull/10281))
|
||||
|
||||
- Migrate login command to new structure ([#10283](https://github.com/vercel/vercel/pull/10283))
|
||||
|
||||
- Migrate pull command to new structure ([#10280](https://github.com/vercel/vercel/pull/10280))
|
||||
|
||||
- Migrate logout command to new structure ([#10282](https://github.com/vercel/vercel/pull/10282))
|
||||
|
||||
- Migrate build command to new structure ([#10286](https://github.com/vercel/vercel/pull/10286))
|
||||
|
||||
- Migrate inspect command to new structure ([#10277](https://github.com/vercel/vercel/pull/10277))
|
||||
|
||||
- Migrate redeploy command to new structure ([#10279](https://github.com/vercel/vercel/pull/10279))
|
||||
|
||||
- Migrate link command to new structure ([#10285](https://github.com/vercel/vercel/pull/10285))
|
||||
|
||||
- Update spacing of --help output for CLI ([#10287](https://github.com/vercel/vercel/pull/10287))
|
||||
|
||||
- Updated dependencies [[`4af242af8`](https://github.com/vercel/vercel/commit/4af242af8633e58b6a9bf920564416da3ef22ad4), [`0cbdae141`](https://github.com/vercel/vercel/commit/0cbdae1411aa7936ff7dfe551919ca5e56cd6e98), [`85dd66778`](https://github.com/vercel/vercel/commit/85dd667781693539d753d587566e53964bbe189d)]:
|
||||
- @vercel/node@2.15.8
|
||||
- @vercel/remix-builder@1.9.1
|
||||
- @vercel/static-build@1.3.44
|
||||
|
||||
## 31.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Migrate bisect command to new structure ([#10276](https://github.com/vercel/vercel/pull/10276))
|
||||
|
||||
- Migrate remove command to new structure ([#10268](https://github.com/vercel/vercel/pull/10268))
|
||||
|
||||
- Updated dependencies [[`fc413707d`](https://github.com/vercel/vercel/commit/fc413707d017e234d5013b761d885f65f9b981bc)]:
|
||||
- @vercel/node@2.15.7
|
||||
- @vercel/static-build@1.3.43
|
||||
|
||||
## 31.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Add a "Global Options" section to help output ([#10250](https://github.com/vercel/vercel/pull/10250))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`d1b0dbe3a`](https://github.com/vercel/vercel/commit/d1b0dbe3a7d8754286aa2b7ba0c8b55d3adafdea), [`4a8622a10`](https://github.com/vercel/vercel/commit/4a8622a10d52260cb629a1c4a6f797ade05ea154), [`6469ef1b8`](https://github.com/vercel/vercel/commit/6469ef1b8ce37e93f50ab4a108aa0953d7631fe8)]:
|
||||
- @vercel/remix-builder@1.9.0
|
||||
- @vercel/next@3.9.3
|
||||
|
||||
## 31.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`7c30b13cc`](https://github.com/vercel/vercel/commit/7c30b13ccb79bdf0ac240282bba4c084f1d0d122)]:
|
||||
- @vercel/next@3.9.2
|
||||
|
||||
## 31.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Add 'Environment' column to 'vc list' with new '--environment' filter and pipe URLs to stdout ([#10239](https://github.com/vercel/vercel/pull/10239))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Update `proxy-agent` to v6.3.0 ([#10226](https://github.com/vercel/vercel/pull/10226))
|
||||
|
||||
- Use `getNodeBinPaths()` in `vc dev` ([#10225](https://github.com/vercel/vercel/pull/10225))
|
||||
|
||||
- Updated dependencies [[`b1c14cde0`](https://github.com/vercel/vercel/commit/b1c14cde03f94b2c15ba12c9be9d19c72df2fdbb), [`ce4633fe4`](https://github.com/vercel/vercel/commit/ce4633fe4d00cb5c251cdabbfab08f39ec3f3b5f)]:
|
||||
- @vercel/next@3.9.1
|
||||
- @vercel/static-build@1.3.42
|
||||
|
||||
## 31.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Detect multiple frameworks within the same root directory during `vc link --repo` ([#10203](https://github.com/vercel/vercel/pull/10203))
|
||||
|
||||
- Updated dependencies [[`b56639b62`](https://github.com/vercel/vercel/commit/b56639b624e9ad1df048a4c85083e26888696060), [`cae60155f`](https://github.com/vercel/vercel/commit/cae60155f34883f08a5e4f51b547e2a1a5fee694), [`c670e5171`](https://github.com/vercel/vercel/commit/c670e51712022193e078bd68b055f7e61013015d), [`5439d7c0c`](https://github.com/vercel/vercel/commit/5439d7c0c9b79e7161bf4fa84ffdb357365f9e7e)]:
|
||||
- @vercel/node@2.15.6
|
||||
- @vercel/next@3.9.0
|
||||
- @vercel/remix-builder@1.8.18
|
||||
- @vercel/static-build@1.3.41
|
||||
|
||||
## 31.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix redeploy target to be undefined when null ([#10201](https://github.com/vercel/vercel/pull/10201))
|
||||
|
||||
- Respect forbidden API responses ([#10178](https://github.com/vercel/vercel/pull/10178))
|
||||
|
||||
- Update `supports-hyperlinks` to v3 ([#10208](https://github.com/vercel/vercel/pull/10208))
|
||||
|
||||
- Updated dependencies [[`0750517af`](https://github.com/vercel/vercel/commit/0750517af99aea41410d4f1f772ce427699554e7)]:
|
||||
- @vercel/build-utils@6.8.2
|
||||
- @vercel/static-build@1.3.40
|
||||
- @vercel/node@2.15.5
|
||||
- @vercel/remix-builder@1.8.17
|
||||
|
||||
## 31.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Allow additional project settings in `createProject()` ([#10172](https://github.com/vercel/vercel/pull/10172))
|
||||
|
||||
- Run local Project detection during `vc link --repo`. ([#10094](https://github.com/vercel/vercel/pull/10094))
|
||||
This allows for creation of new Projects that do not yet exist under the selected scope.
|
||||
|
||||
- Redeploy command no longer redeploys preview deployments to production ([#10186](https://github.com/vercel/vercel/pull/10186))
|
||||
|
||||
- Added trailing new line at end of help output ([#10170](https://github.com/vercel/vercel/pull/10170))
|
||||
|
||||
- Create new help output and arg parsing for deploy command ([#10090](https://github.com/vercel/vercel/pull/10090))
|
||||
|
||||
- [cli] Remove `preinstall` script ([#10157](https://github.com/vercel/vercel/pull/10157))
|
||||
|
||||
- Updated dependencies [[`7021279b2`](https://github.com/vercel/vercel/commit/7021279b284f314a4d1bdbb4306b4c22291efa08), [`5e5332fbc`](https://github.com/vercel/vercel/commit/5e5332fbc9317a8f3cc4ed0b72ec1a2c76020891), [`027bce00b`](https://github.com/vercel/vercel/commit/027bce00b3821d9b4a8f7ec320cd1c43ab9f4215)]:
|
||||
- @vercel/build-utils@6.8.1
|
||||
- @vercel/node@2.15.4
|
||||
- @vercel/remix-builder@1.8.16
|
||||
- @vercel/static-build@1.3.39
|
||||
|
||||
## 31.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`aa734efc6`](https://github.com/vercel/vercel/commit/aa734efc6c42badd4aa9bf64487904aa64e9bd49)]:
|
||||
- @vercel/next@3.8.8
|
||||
|
||||
## 31.0.0
|
||||
|
||||
### Major Changes
|
||||
|
||||
- Update `vc dev` redirect response to match production behavior ([#10143](https://github.com/vercel/vercel/pull/10143))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- require `--yes` to promote preview deployment ([#10135](https://github.com/vercel/vercel/pull/10135))
|
||||
|
||||
- [cli] Optimize write build result for vc build ([#10154](https://github.com/vercel/vercel/pull/10154))
|
||||
|
||||
- Only show relevant Project matches in Project selector ([#10114](https://github.com/vercel/vercel/pull/10114))
|
||||
|
||||
- [cli] Fix error message when token is invalid ([#10131](https://github.com/vercel/vercel/pull/10131))
|
||||
|
||||
- Updated dependencies [[`e4895d979`](https://github.com/vercel/vercel/commit/e4895d979b57e369e0618481c5974243887d72cc), [`346892210`](https://github.com/vercel/vercel/commit/3468922108f411482a72acd0331f0f2ee52a6d4c), [`346892210`](https://github.com/vercel/vercel/commit/3468922108f411482a72acd0331f0f2ee52a6d4c), [`a6de052ed`](https://github.com/vercel/vercel/commit/a6de052ed2f09cc80bf4c2d0f06bedd267a63cdc)]:
|
||||
- @vercel/next@3.8.7
|
||||
- @vercel/static-build@1.3.38
|
||||
- @vercel/build-utils@6.8.0
|
||||
- @vercel/remix-builder@1.8.15
|
||||
- @vercel/node@2.15.3
|
||||
|
||||
## 30.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [cli] do not force auto-assign value on deployments ([#10110](https://github.com/vercel/vercel/pull/10110))
|
||||
|
||||
- Updated dependencies [[`91406abdb`](https://github.com/vercel/vercel/commit/91406abdb0c332152fc6c7c1e4bd3a872b084434), [`2230ea6cc`](https://github.com/vercel/vercel/commit/2230ea6cc1b84c1f03227a4e197b7684635b5955), [`8b3a4146a`](https://github.com/vercel/vercel/commit/8b3a4146af68d2b7288c80a5b919d832dba929b5)]:
|
||||
- @vercel/node@2.15.2
|
||||
- @vercel/remix-builder@1.8.14
|
||||
- @vercel/static-build@1.3.37
|
||||
|
||||
## 30.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [cli] vc env pull should add `.env*.local` to `.gitignore` ([#10085](https://github.com/vercel/vercel/pull/10085))
|
||||
|
||||
- [cli] Fix team validation bug where you are apart of a team ([#10092](https://github.com/vercel/vercel/pull/10092))
|
||||
|
||||
- Add support for `vc dev` command with repo link ([#10082](https://github.com/vercel/vercel/pull/10082))
|
||||
|
||||
- Add support for `vc deploy --prebuilt` command with repo link ([#10083](https://github.com/vercel/vercel/pull/10083))
|
||||
|
||||
- Move readme copy logic to a helper function for `vc link` ([#10084](https://github.com/vercel/vercel/pull/10084))
|
||||
|
||||
- Add support for `vc pull` command with repo link ([#10078](https://github.com/vercel/vercel/pull/10078))
|
||||
|
||||
- Add support for `vc build` command with repo link ([#10075](https://github.com/vercel/vercel/pull/10075))
|
||||
|
||||
## 30.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`a04bf557f`](https://github.com/vercel/vercel/commit/a04bf557fc6e1080a117428977d0993dec78b004)]:
|
||||
- @vercel/node@2.15.1
|
||||
- @vercel/static-build@1.3.36
|
||||
|
||||
## 30.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [node] Add isomorphic functions ([#9947](https://github.com/vercel/vercel/pull/9947))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Add `client.fetchPaginated()` helper function ([#10054](https://github.com/vercel/vercel/pull/10054))
|
||||
|
||||
- Updated dependencies [[`bc5afe24c`](https://github.com/vercel/vercel/commit/bc5afe24c4547dbf798b939199e8212c4b34038e), [`49c717856`](https://github.com/vercel/vercel/commit/49c7178567ec5bcebe633b598c8c9c0e1aa40fbb), [`0039c8b5c`](https://github.com/vercel/vercel/commit/0039c8b5cea975316a62c4f6aaca5d66d731cc0d)]:
|
||||
- @vercel/node@2.15.0
|
||||
- @vercel/remix-builder@1.8.13
|
||||
- @vercel/static-build@1.3.35
|
||||
|
||||
## 30.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Publish missing build-utils ([`cd35071f6`](https://github.com/vercel/vercel/commit/cd35071f609d615d47bc04634c123b33768436cb))
|
||||
|
||||
- Updated dependencies [[`cd35071f6`](https://github.com/vercel/vercel/commit/cd35071f609d615d47bc04634c123b33768436cb)]:
|
||||
- @vercel/build-utils@6.7.5
|
||||
- @vercel/node@2.14.5
|
||||
- @vercel/remix-builder@1.8.12
|
||||
- @vercel/static-build@1.3.34
|
||||
|
||||
## 30.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [cli] vc build ignore '.env\*' & ignore files for '@vercel/static' ([#10056](https://github.com/vercel/vercel/pull/10056))
|
||||
|
||||
- [cli] Ensure .npmrc does not contain use-node-version ([#10049](https://github.com/vercel/vercel/pull/10049))
|
||||
|
||||
## 30.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- New `vc promote` command ([#9984](https://github.com/vercel/vercel/pull/9984))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Support `deploy` subcommand in "repo linked" mode ([#10013](https://github.com/vercel/vercel/pull/10013))
|
||||
|
||||
- [cli] Update `vc rollback` to use `lastRequestAlias` instead of `lastRollbackTarget` ([#10019](https://github.com/vercel/vercel/pull/10019))
|
||||
|
||||
- Fix `--cwd` flag with a relative path for `env`, `link`, `promote`, and `rollback` subcommands ([#10031](https://github.com/vercel/vercel/pull/10031))
|
||||
|
||||
- Updated dependencies [[`c6c19354e`](https://github.com/vercel/vercel/commit/c6c19354e852cfc1338b223058c4b07fdc71c723), [`b56ac2717`](https://github.com/vercel/vercel/commit/b56ac2717d6769eb400f9746f0a05431929b4501), [`c63679ea0`](https://github.com/vercel/vercel/commit/c63679ea0a6bc48c0759ccf3c0c0a8106bd324f0), [`c7bcea408`](https://github.com/vercel/vercel/commit/c7bcea408131df2d65338e50ce319a6d8e4a8a82)]:
|
||||
- @vercel/next@3.8.6
|
||||
- @vercel/build-utils@6.7.4
|
||||
- @vercel/node@2.14.4
|
||||
- @vercel/remix-builder@1.8.11
|
||||
- @vercel/static-build@1.3.33
|
||||
|
||||
## 30.0.0
|
||||
|
||||
### Major Changes
|
||||
|
||||
- Change `vc env pull` default output file to `.env.local` ([#9892](https://github.com/vercel/vercel/pull/9892))
|
||||
|
||||
- Remove `--platform-version` global common arg ([#9807](https://github.com/vercel/vercel/pull/9807))
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [cli] implement `vc deploy --prod --skip-build` ([#9836](https://github.com/vercel/vercel/pull/9836))
|
||||
|
||||
- New `vc redeploy` command ([#9956](https://github.com/vercel/vercel/pull/9956))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix `vercel git connect` command when passing a URL parameter ([#9967](https://github.com/vercel/vercel/pull/9967))
|
||||
|
||||
## 29.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Add `vercel link --repo` flag to link to repository (multiple projects), rather than an individual project (alpha) ([#8931](https://github.com/vercel/vercel/pull/8931))
|
||||
|
||||
## 29.3.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @vercel/static-build@1.3.32
|
||||
|
||||
## 29.3.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`2c950d47a`](https://github.com/vercel/vercel/commit/2c950d47aeb22a3de16f983259ea6f37a4555189), [`71b9f3a94`](https://github.com/vercel/vercel/commit/71b9f3a94b7922607f8f24bf7b2bd1742e62cc05), [`f00b08a82`](https://github.com/vercel/vercel/commit/f00b08a82085c3a63059f34f67f10ced92f2979c)]:
|
||||
- @vercel/static-build@1.3.31
|
||||
- @vercel/build-utils@6.7.3
|
||||
- @vercel/next@3.8.5
|
||||
- @vercel/node@2.14.3
|
||||
- @vercel/remix-builder@1.8.10
|
||||
|
||||
## 29.3.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`67e556bc8`](https://github.com/vercel/vercel/commit/67e556bc80c821c233120a2ec1611adb8e195baa), [`ba10fb4dd`](https://github.com/vercel/vercel/commit/ba10fb4dd4155a75df79b98a0c43a6c42eac7b62)]:
|
||||
- @vercel/remix-builder@1.8.9
|
||||
- @vercel/next@3.8.4
|
||||
|
||||
## 29.3.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel",
|
||||
"version": "29.3.3",
|
||||
"version": "31.2.3",
|
||||
"preferGlobal": true,
|
||||
"license": "Apache-2.0",
|
||||
"description": "The command-line interface for Vercel",
|
||||
@@ -11,7 +11,6 @@
|
||||
"directory": "packages/cli"
|
||||
},
|
||||
"scripts": {
|
||||
"preinstall": "node ./scripts/preinstall.js",
|
||||
"test": "jest --env node --verbose --bail",
|
||||
"test-unit": "pnpm test test/unit/",
|
||||
"test-e2e": "rimraf test/fixtures/integration && pnpm test test/integration-1.test.ts test/integration-2.test.ts test/integration-3.test.ts",
|
||||
@@ -32,20 +31,20 @@
|
||||
"node": ">= 14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "6.7.2",
|
||||
"@vercel/build-utils": "6.8.3",
|
||||
"@vercel/go": "2.5.1",
|
||||
"@vercel/hydrogen": "0.0.64",
|
||||
"@vercel/next": "3.8.3",
|
||||
"@vercel/node": "2.14.2",
|
||||
"@vercel/next": "3.9.4",
|
||||
"@vercel/node": "2.15.9",
|
||||
"@vercel/python": "3.1.60",
|
||||
"@vercel/redwood": "1.1.15",
|
||||
"@vercel/remix-builder": "1.8.8",
|
||||
"@vercel/remix-builder": "1.10.0",
|
||||
"@vercel/ruby": "1.3.76",
|
||||
"@vercel/static-build": "1.3.30"
|
||||
"@vercel/static-build": "1.3.45"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@alex_neo/jest-expect-message": "1.0.5",
|
||||
"@edge-runtime/node-utils": "2.0.3",
|
||||
"@edge-runtime/node-utils": "2.1.0",
|
||||
"@next/env": "11.1.2",
|
||||
"@sentry/node": "5.5.0",
|
||||
"@sindresorhus/slugify": "0.11.0",
|
||||
@@ -85,13 +84,13 @@
|
||||
"@types/which": "3.0.0",
|
||||
"@types/write-json-file": "2.2.1",
|
||||
"@types/yauzl-promise": "2.1.0",
|
||||
"@vercel-internals/constants": "*",
|
||||
"@vercel-internals/get-package-json": "*",
|
||||
"@vercel-internals/types": "*",
|
||||
"@vercel/client": "12.5.0",
|
||||
"@vercel-internals/constants": "1.0.4",
|
||||
"@vercel-internals/get-package-json": "1.0.0",
|
||||
"@vercel-internals/types": "1.0.6",
|
||||
"@vercel/client": "12.6.6",
|
||||
"@vercel/error-utils": "1.0.10",
|
||||
"@vercel/frameworks": "1.4.2",
|
||||
"@vercel/fs-detectors": "3.9.2",
|
||||
"@vercel/frameworks": "1.5.0",
|
||||
"@vercel/fs-detectors": "4.1.1",
|
||||
"@vercel/fun": "1.0.4",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"@vercel/routing-utils": "2.2.1",
|
||||
@@ -119,6 +118,7 @@
|
||||
"escape-html": "1.0.3",
|
||||
"esm": "3.1.4",
|
||||
"execa": "3.2.0",
|
||||
"expect": "29.5.0",
|
||||
"express": "4.17.1",
|
||||
"fast-deep-equal": "3.1.3",
|
||||
"find-up": "4.1.0",
|
||||
@@ -149,7 +149,7 @@
|
||||
"pluralize": "7.0.0",
|
||||
"promisepipe": "3.0.0",
|
||||
"proxy": "2.0.0",
|
||||
"proxy-agent": "6.1.1",
|
||||
"proxy-agent": "6.3.0",
|
||||
"psl": "1.1.31",
|
||||
"qr-image": "3.2.0",
|
||||
"raw-body": "2.4.1",
|
||||
@@ -157,8 +157,7 @@
|
||||
"semver": "5.5.0",
|
||||
"serve-handler": "6.1.1",
|
||||
"strip-ansi": "6.0.1",
|
||||
"stripe": "5.1.0",
|
||||
"supports-hyperlinks": "2.2.0",
|
||||
"supports-hyperlinks": "3.0.0",
|
||||
"tar-fs": "1.16.3",
|
||||
"test-listen": "1.1.0",
|
||||
"text-table": "0.2.0",
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
const { join } = require('path');
|
||||
const { statSync } = require('fs');
|
||||
const pkg = require('../package');
|
||||
|
||||
function error(command) {
|
||||
console.error('> Error:', command);
|
||||
}
|
||||
|
||||
function debug(str) {
|
||||
if (
|
||||
process.argv.find(str => str === '--debug') ||
|
||||
process.env.PREINSTALL_DEBUG
|
||||
) {
|
||||
console.log(`[debug] [${new Date().toISOString()}]`, str);
|
||||
}
|
||||
}
|
||||
|
||||
function isYarn() {
|
||||
return process.env.npm_config_heading !== 'npm';
|
||||
}
|
||||
|
||||
function isGlobal() {
|
||||
const cmd = JSON.parse(process.env.npm_config_argv || '{ "original": [] }');
|
||||
|
||||
return isYarn()
|
||||
? cmd.original.includes('global')
|
||||
: Boolean(process.env.npm_config_global);
|
||||
}
|
||||
|
||||
function isVercel() {
|
||||
return pkg.name === 'vercel';
|
||||
}
|
||||
|
||||
function validateNodeVersion() {
|
||||
let semver = '>= 0';
|
||||
let major = '1';
|
||||
|
||||
try {
|
||||
major = process.versions.node.split('.')[0];
|
||||
const pkg = require('../package.json');
|
||||
semver = pkg.engines.node;
|
||||
} catch (e) {
|
||||
debug('Failed to read package.json engines');
|
||||
}
|
||||
|
||||
const isValid = eval(`${major} ${semver}`);
|
||||
return { isValid, expected: semver, actual: process.versions.node };
|
||||
}
|
||||
|
||||
function isInNodeModules(name) {
|
||||
try {
|
||||
const nodeModules = join(__dirname, '..', '..');
|
||||
const stat = statSync(join(nodeModules, name));
|
||||
return stat.isDirectory();
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
if (!isGlobal()) {
|
||||
debug('Skipping preinstall since Vercel CLI is being installed locally');
|
||||
return;
|
||||
}
|
||||
|
||||
const ver = validateNodeVersion();
|
||||
|
||||
if (!ver.isValid) {
|
||||
error(
|
||||
`Detected unsupported Node.js version.\n` +
|
||||
`Expected "${ver.expected}" but found "${ver.actual}".\n` +
|
||||
`Please update to the latest Node.js LTS version to install Vercel CLI.`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (isVercel() && isInNodeModules('now')) {
|
||||
const uninstall = isYarn()
|
||||
? 'yarn global remove now'
|
||||
: 'npm uninstall -g now';
|
||||
console.error(`NOTE: Run \`${uninstall}\` to uninstall \`now\`\n`);
|
||||
}
|
||||
}
|
||||
|
||||
process.on('unhandledRejection', err => {
|
||||
console.error('Unhandled Rejection:');
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
process.on('uncaughtException', err => {
|
||||
console.error('Uncaught Exception:');
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
main().catch(err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -24,7 +24,9 @@ export const help = () => `
|
||||
ls | list [app] Lists deployments
|
||||
login [email] Logs into your account or creates a new one
|
||||
logout Logs out of your account
|
||||
promote [url|id] Promote an existing deployment to current
|
||||
pull [path] Pull your Project Settings from the cloud
|
||||
redeploy [url|id] Rebuild and deploy a previous deployment.
|
||||
rollback [url|id] Quickly revert back to a previous deployment
|
||||
switch [scope] Switches between teams and your personal account
|
||||
|
||||
|
||||
69
packages/cli/src/commands/bisect/command.ts
Normal file
69
packages/cli/src/commands/bisect/command.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { Command } from '../help';
|
||||
import { getPkgName } from '../../util/pkg-name';
|
||||
|
||||
export const bisectCommand: Command = {
|
||||
name: 'bisect',
|
||||
description: 'Bisect the current project interactively.',
|
||||
arguments: [],
|
||||
options: [
|
||||
{
|
||||
name: 'bad',
|
||||
description: 'Known bad URL',
|
||||
argument: 'URL',
|
||||
shorthand: 'b',
|
||||
type: 'string',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'good',
|
||||
description: 'Known good URL',
|
||||
argument: 'URL',
|
||||
shorthand: 'g',
|
||||
type: 'string',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'open',
|
||||
description: 'Automatically open each URL in the browser',
|
||||
argument: 'URL',
|
||||
shorthand: 'o',
|
||||
type: 'string',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'path',
|
||||
description: 'Subpath of the deployment URL to test',
|
||||
argument: 'URL',
|
||||
shorthand: 'p',
|
||||
type: 'string',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'run',
|
||||
description: 'Test script to run for each deployment',
|
||||
argument: 'URL',
|
||||
shorthand: 'r',
|
||||
type: 'string',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
name: 'Bisect the current project interactively',
|
||||
value: `${getPkgName()} bisect`,
|
||||
},
|
||||
{
|
||||
name: 'Bisect with a known bad deployment',
|
||||
value: `${getPkgName()} bisect --bad example-310pce9i0.vercel.app`,
|
||||
},
|
||||
{
|
||||
name: 'Automated bisect with a run script',
|
||||
value: `${getPkgName()} bisect --run ./test.sh`,
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -6,57 +6,21 @@ import chalk, { Chalk } from 'chalk';
|
||||
import { URLSearchParams, parse } from 'url';
|
||||
|
||||
import box from '../../util/output/box';
|
||||
import sleep from '../../util/sleep';
|
||||
import formatDate from '../../util/format-date';
|
||||
import link from '../../util/output/link';
|
||||
import logo from '../../util/output/logo';
|
||||
import getArgs from '../../util/get-args';
|
||||
import Client from '../../util/client';
|
||||
import { getPkgName } from '../../util/pkg-name';
|
||||
import { Deployment, PaginationOptions } from '@vercel-internals/types';
|
||||
import { Deployment } from '@vercel-internals/types';
|
||||
import { normalizeURL } from '../../util/bisect/normalize-url';
|
||||
import getScope from '../../util/get-scope';
|
||||
import getDeployment from '../../util/get-deployment';
|
||||
import { help } from '../help';
|
||||
import { bisectCommand } from './command';
|
||||
|
||||
interface Deployments {
|
||||
deployments: Deployment[];
|
||||
pagination: PaginationOptions;
|
||||
}
|
||||
|
||||
const pkgName = getPkgName();
|
||||
|
||||
const help = () => {
|
||||
console.log(`
|
||||
${chalk.bold(`${logo} ${pkgName} bisect`)} [options]
|
||||
|
||||
${chalk.dim('Options:')}
|
||||
|
||||
-h, --help Output usage information
|
||||
-d, --debug Debug mode [off]
|
||||
--no-color No color mode [off]
|
||||
-b, --bad Known bad URL
|
||||
-g, --good Known good URL
|
||||
-o, --open Automatically open each URL in the browser
|
||||
-p, --path Subpath of the deployment URL to test
|
||||
-r, --run Test script to run for each deployment
|
||||
|
||||
${chalk.dim('Examples:')}
|
||||
|
||||
${chalk.gray('–')} Bisect the current project interactively
|
||||
|
||||
${chalk.cyan(`$ ${pkgName} bisect`)}
|
||||
|
||||
${chalk.gray('–')} Bisect with a known bad deployment
|
||||
|
||||
${chalk.cyan(`$ ${pkgName} bisect --bad example-310pce9i0.vercel.app`)}
|
||||
|
||||
${chalk.gray('–')} Automated bisect with a run script
|
||||
|
||||
${chalk.cyan(`$ ${pkgName} bisect --run ./test.sh`)}
|
||||
`);
|
||||
};
|
||||
|
||||
export default async function main(client: Client): Promise<number> {
|
||||
export default async function bisect(client: Client): Promise<number> {
|
||||
const { output } = client;
|
||||
const scope = await getScope(client);
|
||||
const { contextName } = scope;
|
||||
@@ -75,7 +39,7 @@ export default async function main(client: Client): Promise<number> {
|
||||
});
|
||||
|
||||
if (argv['--help']) {
|
||||
help();
|
||||
output.print(help(bisectCommand, { columns: client.stderr.columns }));
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -206,44 +170,34 @@ export default async function main(client: Client): Promise<number> {
|
||||
|
||||
// Fetch all the project's "READY" deployments with the pagination API
|
||||
let deployments: Deployment[] = [];
|
||||
let next: number | undefined = badDeployment.createdAt + 1;
|
||||
do {
|
||||
const query = new URLSearchParams();
|
||||
query.set('projectId', projectId);
|
||||
if (badDeployment.target) {
|
||||
query.set('target', badDeployment.target);
|
||||
}
|
||||
query.set('limit', '100');
|
||||
query.set('state', 'READY');
|
||||
if (next) {
|
||||
query.set('until', String(next));
|
||||
}
|
||||
|
||||
const res = await client.fetch<Deployments>(`/v6/deployments?${query}`, {
|
||||
const query = new URLSearchParams();
|
||||
query.set('projectId', projectId);
|
||||
if (badDeployment.target) {
|
||||
query.set('target', badDeployment.target);
|
||||
}
|
||||
query.set('state', 'READY');
|
||||
query.set('until', String(badDeployment.createdAt + 1));
|
||||
|
||||
for await (const chunk of client.fetchPaginated<Deployments>(
|
||||
`/v6/deployments?${query}`,
|
||||
{
|
||||
accountId: badDeployment.ownerId,
|
||||
});
|
||||
|
||||
next = res.pagination.next;
|
||||
|
||||
let newDeployments = res.deployments;
|
||||
}
|
||||
)) {
|
||||
let newDeployments = chunk.deployments;
|
||||
|
||||
// If we have the "good" deployment in this chunk, then we're done
|
||||
for (let i = 0; i < newDeployments.length; i++) {
|
||||
if (newDeployments[i].url === good) {
|
||||
// grab all deployments up until the good one
|
||||
newDeployments = newDeployments.slice(0, i);
|
||||
next = undefined;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
deployments = deployments.concat(newDeployments);
|
||||
|
||||
if (next) {
|
||||
// Small sleep to avoid rate limiting
|
||||
await sleep(100);
|
||||
}
|
||||
} while (next);
|
||||
}
|
||||
|
||||
if (!deployments.length) {
|
||||
output.error(
|
||||
|
||||
46
packages/cli/src/commands/build/command.ts
Normal file
46
packages/cli/src/commands/build/command.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { Command } from '../help';
|
||||
import { getPkgName } from '../../util/pkg-name';
|
||||
|
||||
export const buildCommand: Command = {
|
||||
name: 'build',
|
||||
description: 'Build the project.',
|
||||
arguments: [],
|
||||
options: [
|
||||
{
|
||||
name: 'prod',
|
||||
description: 'Build a production deployment',
|
||||
shorthand: null,
|
||||
type: 'string',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'output',
|
||||
description: 'Directory where built assets should be written to',
|
||||
shorthand: null,
|
||||
argument: 'PATH',
|
||||
type: 'string',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'yes',
|
||||
description:
|
||||
'Skip the confirmation prompt about pulling environment variables and project settings when not found locally',
|
||||
shorthand: 'y',
|
||||
type: 'boolean',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
name: 'Build the project',
|
||||
value: `${getPkgName()} build`,
|
||||
},
|
||||
{
|
||||
name: 'Build the project in a specific directory',
|
||||
value: `${getPkgName()} build --cwd ./path-to-project`,
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1,7 +1,10 @@
|
||||
import fs from 'fs-extra';
|
||||
import chalk from 'chalk';
|
||||
import dotenv from 'dotenv';
|
||||
import semver from 'semver';
|
||||
import minimatch from 'minimatch';
|
||||
import { join, normalize, relative, resolve, sep } from 'path';
|
||||
import frameworks from '@vercel/frameworks';
|
||||
import {
|
||||
getDiscontinuedNodeVersions,
|
||||
normalizePath,
|
||||
@@ -17,13 +20,14 @@ import {
|
||||
BuildResultV3,
|
||||
NowBuildError,
|
||||
Cron,
|
||||
validateNpmrc,
|
||||
} from '@vercel/build-utils';
|
||||
import {
|
||||
detectBuilders,
|
||||
detectFrameworkRecord,
|
||||
detectFrameworkVersion,
|
||||
LocalFileSystemDetector,
|
||||
} from '@vercel/fs-detectors';
|
||||
import minimatch from 'minimatch';
|
||||
import {
|
||||
appendRoutesToPhase,
|
||||
getTransformedRoutes,
|
||||
@@ -34,39 +38,37 @@ import {
|
||||
import { fileNameSymbol } from '@vercel/client';
|
||||
import type { VercelConfig } from '@vercel/client';
|
||||
|
||||
import pull from './pull';
|
||||
import { staticFiles as getFiles } from '../util/get-files';
|
||||
import Client from '../util/client';
|
||||
import getArgs from '../util/get-args';
|
||||
import cmd from '../util/output/cmd';
|
||||
import * as cli from '../util/pkg-name';
|
||||
import cliPkg from '../util/pkg';
|
||||
import readJSONFile from '../util/read-json-file';
|
||||
import { CantParseJSONFile } from '../util/errors-ts';
|
||||
import pull from '../pull';
|
||||
import { staticFiles as getFiles } from '../../util/get-files';
|
||||
import Client from '../../util/client';
|
||||
import getArgs from '../../util/get-args';
|
||||
import cmd from '../../util/output/cmd';
|
||||
import * as cli from '../../util/pkg-name';
|
||||
import cliPkg from '../../util/pkg';
|
||||
import readJSONFile from '../../util/read-json-file';
|
||||
import { CantParseJSONFile } from '../../util/errors-ts';
|
||||
import {
|
||||
pickOverrides,
|
||||
ProjectLinkAndSettings,
|
||||
readProjectSettings,
|
||||
} from '../util/projects/project-settings';
|
||||
import { VERCEL_DIR } from '../util/projects/link';
|
||||
import confirm from '../util/input/confirm';
|
||||
import { emoji, prependEmoji } from '../util/emoji';
|
||||
import stamp from '../util/output/stamp';
|
||||
} from '../../util/projects/project-settings';
|
||||
import { getProjectLink, VERCEL_DIR } from '../../util/projects/link';
|
||||
import confirm from '../../util/input/confirm';
|
||||
import { emoji, prependEmoji } from '../../util/emoji';
|
||||
import stamp from '../../util/output/stamp';
|
||||
import {
|
||||
OUTPUT_DIR,
|
||||
PathOverride,
|
||||
writeBuildResult,
|
||||
} from '../util/build/write-build-result';
|
||||
import { importBuilders } from '../util/build/import-builders';
|
||||
import { initCorepack, cleanupCorepack } from '../util/build/corepack';
|
||||
import { sortBuilders } from '../util/build/sort-builders';
|
||||
import { toEnumerableError } from '../util/error';
|
||||
import { validateConfig } from '../util/validate-config';
|
||||
|
||||
import { setMonorepoDefaultSettings } from '../util/build/monorepo';
|
||||
import frameworks from '@vercel/frameworks';
|
||||
import { detectFrameworkVersion } from '@vercel/fs-detectors';
|
||||
import semver from 'semver';
|
||||
} from '../../util/build/write-build-result';
|
||||
import { importBuilders } from '../../util/build/import-builders';
|
||||
import { initCorepack, cleanupCorepack } from '../../util/build/corepack';
|
||||
import { sortBuilders } from '../../util/build/sort-builders';
|
||||
import { toEnumerableError } from '../../util/error';
|
||||
import { validateConfig } from '../../util/validate-config';
|
||||
import { setMonorepoDefaultSettings } from '../../util/build/monorepo';
|
||||
import { help } from '../help';
|
||||
import { buildCommand } from './command';
|
||||
|
||||
type BuildResult = BuildResultV2 | BuildResultV3;
|
||||
|
||||
@@ -103,36 +105,8 @@ export interface BuildsManifest {
|
||||
builds?: SerializedBuilder[];
|
||||
}
|
||||
|
||||
const help = () => {
|
||||
return console.log(`
|
||||
${chalk.bold(`${cli.logo} ${cli.name} build`)}
|
||||
|
||||
${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
|
||||
--cwd [path] The current working directory
|
||||
--output [path] Directory where built assets should be written to
|
||||
--prod Build a production deployment
|
||||
-d, --debug Debug mode [off]
|
||||
--no-color No color mode [off]
|
||||
-y, --yes Skip the confirmation prompt about pulling environment variables and project settings when not found locally
|
||||
|
||||
${chalk.dim('Examples:')}
|
||||
|
||||
${chalk.gray('-')} Build the project
|
||||
|
||||
${chalk.cyan(`$ ${cli.name} build`)}
|
||||
${chalk.cyan(`$ ${cli.name} build --cwd ./path-to-project`)}
|
||||
`);
|
||||
};
|
||||
|
||||
export default async function main(client: Client): Promise<number> {
|
||||
let { cwd } = client;
|
||||
const { output } = client;
|
||||
|
||||
// Ensure that `vc build` is not being invoked recursively
|
||||
@@ -161,20 +135,33 @@ export default async function main(client: Client): Promise<number> {
|
||||
});
|
||||
|
||||
if (argv['--help']) {
|
||||
help();
|
||||
output.print(help(buildCommand, { columns: client.stderr.columns }));
|
||||
return 2;
|
||||
}
|
||||
|
||||
const cwd = process.cwd();
|
||||
|
||||
// Build `target` influences which environment variables will be used
|
||||
const target = argv['--prod'] ? 'production' : 'preview';
|
||||
const yes = Boolean(argv['--yes']);
|
||||
|
||||
try {
|
||||
await validateNpmrc(cwd);
|
||||
} catch (err) {
|
||||
output.prettyError(err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If repo linked, update `cwd` to the repo root
|
||||
const link = await getProjectLink(client, cwd);
|
||||
const projectRootDirectory = link?.projectRootDirectory ?? '';
|
||||
if (link?.repoRoot) {
|
||||
cwd = client.cwd = link.repoRoot;
|
||||
}
|
||||
|
||||
// TODO: read project settings from the API, fall back to local `project.json` if that fails
|
||||
|
||||
// Read project settings, and pull them from Vercel if necessary
|
||||
let project = await readProjectSettings(join(cwd, VERCEL_DIR));
|
||||
const vercelDir = join(cwd, projectRootDirectory, VERCEL_DIR);
|
||||
let project = await readProjectSettings(vercelDir);
|
||||
const isTTY = process.stdin.isTTY;
|
||||
while (!project?.settings) {
|
||||
let confirmed = yes;
|
||||
@@ -201,6 +188,7 @@ export default async function main(client: Client): Promise<number> {
|
||||
return 0;
|
||||
}
|
||||
const { argv: originalArgv } = client;
|
||||
client.cwd = join(cwd, projectRootDirectory);
|
||||
client.argv = [
|
||||
...originalArgv.slice(0, 2),
|
||||
'pull',
|
||||
@@ -211,12 +199,13 @@ export default async function main(client: Client): Promise<number> {
|
||||
if (result !== 0) {
|
||||
return result;
|
||||
}
|
||||
client.cwd = cwd;
|
||||
client.argv = originalArgv;
|
||||
project = await readProjectSettings(join(cwd, VERCEL_DIR));
|
||||
project = await readProjectSettings(vercelDir);
|
||||
}
|
||||
|
||||
// Delete output directory from potential previous build
|
||||
const defaultOutputDir = join(cwd, OUTPUT_DIR);
|
||||
const defaultOutputDir = join(cwd, projectRootDirectory, OUTPUT_DIR);
|
||||
const outputDir = argv['--output']
|
||||
? resolve(argv['--output'])
|
||||
: defaultOutputDir;
|
||||
@@ -235,7 +224,12 @@ export default async function main(client: Client): Promise<number> {
|
||||
const envToUnset = new Set<string>(['VERCEL', 'NOW_BUILDER']);
|
||||
|
||||
try {
|
||||
const envPath = join(cwd, VERCEL_DIR, `.env.${target}.local`);
|
||||
const envPath = join(
|
||||
cwd,
|
||||
projectRootDirectory,
|
||||
VERCEL_DIR,
|
||||
`.env.${target}.local`
|
||||
);
|
||||
// TODO (maybe?): load env vars from the API, fall back to the local file if that fails
|
||||
const dotenvResult = dotenv.config({
|
||||
path: envPath,
|
||||
@@ -1,50 +0,0 @@
|
||||
import chalk from 'chalk';
|
||||
import logo from '../../util/output/logo';
|
||||
import { getPkgName } from '../../util/pkg-name';
|
||||
|
||||
export const help = () => {
|
||||
return `
|
||||
${chalk.bold(`${logo} ${getPkgName()} [deploy]`)} [path-to-project] [options]
|
||||
|
||||
--prod Create a production deployment
|
||||
-p, --public Deployment is public (${chalk.dim(
|
||||
'`/_src`'
|
||||
)} is exposed)
|
||||
-e, --env Include an env var during run time (e.g.: ${chalk.dim(
|
||||
'`-e KEY=value`'
|
||||
)}). Can appear many times.
|
||||
-b, --build-env Similar to ${chalk.dim(
|
||||
'`--env`'
|
||||
)} but for build time only.
|
||||
-m, --meta Add metadata for the deployment (e.g.: ${chalk.dim(
|
||||
'`-m KEY=value`'
|
||||
)}). Can appear many times.
|
||||
--no-wait Don't wait for the deployment to finish
|
||||
-f, --force Force a new deployment even if nothing has changed
|
||||
--with-cache Retain build cache when using "--force"
|
||||
--regions Set default regions to enable the deployment on
|
||||
|
||||
${chalk.dim('Examples:')}
|
||||
|
||||
${chalk.gray('–')} Deploy the current directory
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()}`)}
|
||||
|
||||
${chalk.gray('–')} Deploy a custom path
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} /usr/src/project`)}
|
||||
|
||||
${chalk.gray('–')} Deploy with Environment Variables
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} -e NODE_ENV=production`)}
|
||||
|
||||
${chalk.gray('–')} Deploy with prebuilt outputs
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} build`)}
|
||||
${chalk.cyan(`$ ${getPkgName()} deploy --prebuilt`)}
|
||||
|
||||
${chalk.gray('–')} Write Deployment URL to a file
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} > deployment-url.txt`)}
|
||||
`;
|
||||
};
|
||||
181
packages/cli/src/commands/deploy/command.ts
Normal file
181
packages/cli/src/commands/deploy/command.ts
Normal file
@@ -0,0 +1,181 @@
|
||||
import { Command } from '../help';
|
||||
|
||||
export const deployCommand: Command = {
|
||||
name: 'deploy',
|
||||
description:
|
||||
'Deploy your project to Vercel. The `deploy` command is the default command for the Vercel CLI, and can be omitted (`vc deploy my-app` equals `vc my-app`).',
|
||||
arguments: [
|
||||
{
|
||||
name: 'project-path',
|
||||
required: false,
|
||||
},
|
||||
],
|
||||
options: [
|
||||
{
|
||||
name: 'force',
|
||||
shorthand: 'f',
|
||||
type: 'boolean',
|
||||
deprecated: false,
|
||||
description: 'Force a new deployment even if nothing has changed',
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'with-cache',
|
||||
shorthand: null,
|
||||
type: 'boolean',
|
||||
deprecated: false,
|
||||
description: 'Retain build cache when using "--force"',
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'public',
|
||||
shorthand: 'p',
|
||||
type: 'boolean',
|
||||
deprecated: false,
|
||||
description: 'Deployment is public (`/_src`) is exposed)',
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'env',
|
||||
shorthand: 'e',
|
||||
type: 'string',
|
||||
argument: 'key=value',
|
||||
deprecated: false,
|
||||
multi: true,
|
||||
description:
|
||||
'Specify environment variables during run-time (e.g. `-e KEY1=value1 -e KEY2=value2`)',
|
||||
},
|
||||
{
|
||||
name: 'build-env',
|
||||
shorthand: 'b',
|
||||
type: 'string',
|
||||
argument: 'key=value',
|
||||
deprecated: false,
|
||||
multi: true,
|
||||
description:
|
||||
'Specify environment variables during build-time (e.g. `-b KEY1=value1 -b KEY2=value2`)',
|
||||
},
|
||||
{
|
||||
name: 'meta',
|
||||
shorthand: 'm',
|
||||
type: 'string',
|
||||
argument: 'key=value',
|
||||
deprecated: false,
|
||||
multi: true,
|
||||
description:
|
||||
'Specify metadata for the deployment (e.g. `-m KEY1=value1 -m KEY2=value2`)',
|
||||
},
|
||||
{
|
||||
name: 'regions',
|
||||
shorthand: null,
|
||||
type: 'string',
|
||||
deprecated: false,
|
||||
description: 'Set default regions to enable the deployment on',
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'prebuilt',
|
||||
shorthand: null,
|
||||
type: 'boolean',
|
||||
deprecated: false,
|
||||
description:
|
||||
'Use in combination with `vc build`. Deploy an existing build',
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'prod',
|
||||
shorthand: null,
|
||||
type: 'boolean',
|
||||
deprecated: false,
|
||||
description: 'Create a production deployment',
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'archive',
|
||||
shorthand: null,
|
||||
type: 'string',
|
||||
deprecated: false,
|
||||
description:
|
||||
'Compress the deployment code into a file before uploading it',
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'no-wait',
|
||||
shorthand: null,
|
||||
type: 'boolean',
|
||||
deprecated: false,
|
||||
description: "Don't wait for the deployment to finish",
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'skip-domain',
|
||||
shorthand: null,
|
||||
type: 'boolean',
|
||||
deprecated: false,
|
||||
description: undefined,
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'yes',
|
||||
shorthand: 'y',
|
||||
type: 'boolean',
|
||||
deprecated: false,
|
||||
description: 'Use default options to skip all prompts',
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
shorthand: 'n',
|
||||
type: 'string',
|
||||
deprecated: true,
|
||||
description: 'Provide a Vercel Project name',
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'no-clipboard',
|
||||
shorthand: null,
|
||||
type: 'boolean',
|
||||
deprecated: true,
|
||||
description: 'Do not copy deployment URL to clipboard',
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'target',
|
||||
shorthand: null,
|
||||
type: 'string',
|
||||
deprecated: true,
|
||||
description: 'Specify the target deployment environment',
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'confirm',
|
||||
shorthand: 'c',
|
||||
type: 'boolean',
|
||||
deprecated: true,
|
||||
description: 'Use default options to skip all prompts',
|
||||
multi: false,
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
name: 'Deploy the current directory',
|
||||
value: 'vercel',
|
||||
},
|
||||
{
|
||||
name: 'Deploy a custom path',
|
||||
value: 'vercel /usr/src/project',
|
||||
},
|
||||
{
|
||||
name: 'Deploy with run-time Environment Variables',
|
||||
value: 'vercel -e NODE_ENV=production',
|
||||
},
|
||||
{
|
||||
name: 'Deploy with prebuilt outputs',
|
||||
value: ['vercel build', 'vercel deploy --prebuilt'],
|
||||
},
|
||||
{
|
||||
name: 'Write Deployment URL to a file',
|
||||
value: 'vercel > deployment-url.txt',
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -2,7 +2,7 @@ import ms from 'ms';
|
||||
import fs from 'fs-extra';
|
||||
import bytes from 'bytes';
|
||||
import chalk from 'chalk';
|
||||
import { join, resolve, basename } from 'path';
|
||||
import { join, resolve } from 'path';
|
||||
import {
|
||||
fileNameSymbol,
|
||||
VALID_ARCHIVE_FORMATS,
|
||||
@@ -21,7 +21,6 @@ import stamp from '../../util/output/stamp';
|
||||
import createDeploy from '../../util/deploy/create-deploy';
|
||||
import getDeployment from '../../util/get-deployment';
|
||||
import parseMeta from '../../util/parse-meta';
|
||||
import linkStyle from '../../util/output/link';
|
||||
import param from '../../util/output/param';
|
||||
import {
|
||||
BuildsRateLimited,
|
||||
@@ -59,9 +58,7 @@ import validatePaths, {
|
||||
validateRootDirectory,
|
||||
} from '../../util/validate-paths';
|
||||
import { getCommandName } from '../../util/pkg-name';
|
||||
import { getPreferredPreviewURL } from '../../util/deploy/get-preferred-preview-url';
|
||||
import { Output } from '../../util/output';
|
||||
import { help } from './args';
|
||||
import { getDeploymentChecks } from '../../util/deploy/get-deployment-checks';
|
||||
import parseTarget from '../../util/deploy/parse-target';
|
||||
import getPrebuiltJson from '../../util/deploy/get-prebuilt-json';
|
||||
@@ -70,45 +67,39 @@ import { isValidArchive } from '../../util/deploy/validate-archive-format';
|
||||
import { parseEnv } from '../../util/parse-env';
|
||||
import { errorToString, isErrnoException, isError } from '@vercel/error-utils';
|
||||
import { pickOverrides } from '../../util/projects/project-settings';
|
||||
import { isDeploying } from '../../util/deploy/is-deploying';
|
||||
import type { Deployment } from '@vercel-internals/types';
|
||||
import { printDeploymentStatus } from '../../util/deploy/print-deployment-status';
|
||||
import { help } from '../help';
|
||||
import { deployCommand } from './command';
|
||||
|
||||
export default async (client: Client): Promise<number> => {
|
||||
const { output } = client;
|
||||
|
||||
let argv = null;
|
||||
|
||||
try {
|
||||
argv = getArgs(client.argv.slice(2), {
|
||||
'--force': Boolean,
|
||||
'--with-cache': Boolean,
|
||||
'--public': Boolean,
|
||||
'--env': [String],
|
||||
'--build-env': [String],
|
||||
'--meta': [String],
|
||||
// This is not an array in favor of matching
|
||||
// the config property name.
|
||||
'--regions': String,
|
||||
'--prebuilt': Boolean,
|
||||
'--prod': Boolean,
|
||||
'--archive': String,
|
||||
'--no-wait': Boolean,
|
||||
'--yes': Boolean,
|
||||
'-f': '--force',
|
||||
'-p': '--public',
|
||||
'-e': '--env',
|
||||
'-b': '--build-env',
|
||||
'-m': '--meta',
|
||||
'-y': '--yes',
|
||||
const argOptions: {
|
||||
[k: string]:
|
||||
| BooleanConstructor
|
||||
| StringConstructor
|
||||
| string
|
||||
| [StringConstructor];
|
||||
} = {};
|
||||
for (const option of deployCommand.options) {
|
||||
argOptions[`--${option.name}`] =
|
||||
option.type === 'boolean' ? Boolean : String;
|
||||
if (option.shorthand) {
|
||||
argOptions[`-${option.shorthand}`] = `--${option.name}`;
|
||||
}
|
||||
if (
|
||||
option.name === 'env' ||
|
||||
option.name === 'build-env' ||
|
||||
option.name === 'meta'
|
||||
) {
|
||||
argOptions[`--${option.name}`] = [String];
|
||||
}
|
||||
}
|
||||
|
||||
// deprecated
|
||||
'--name': String,
|
||||
'-n': '--name',
|
||||
'--no-clipboard': Boolean,
|
||||
'--target': String,
|
||||
'--confirm': Boolean,
|
||||
'-c': '--confirm',
|
||||
});
|
||||
try {
|
||||
argv = getArgs(client.argv.slice(2), argOptions);
|
||||
|
||||
if ('--confirm' in argv) {
|
||||
output.warn('`--confirm` is deprecated, please use `--yes` instead');
|
||||
@@ -120,7 +111,7 @@ export default async (client: Client): Promise<number> => {
|
||||
}
|
||||
|
||||
if (argv['--help']) {
|
||||
output.print(help());
|
||||
output.print(help(deployCommand, { columns: client.stderr.columns }));
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -132,24 +123,19 @@ export default async (client: Client): Promise<number> => {
|
||||
if (argv._.length > 0) {
|
||||
// If path is relative: resolve
|
||||
// if path is absolute: clear up strange `/` etc
|
||||
paths = argv._.map(item => resolve(process.cwd(), item));
|
||||
paths = argv._.map(item => resolve(client.cwd, item));
|
||||
} else {
|
||||
paths = [process.cwd()];
|
||||
paths = [client.cwd];
|
||||
}
|
||||
|
||||
// check paths
|
||||
const pathValidation = await validatePaths(client, paths);
|
||||
|
||||
if (!pathValidation.valid) {
|
||||
return pathValidation.exitCode;
|
||||
}
|
||||
|
||||
let localConfig = client.localConfig || readLocalConfig(paths[0]);
|
||||
|
||||
for (const path of paths) {
|
||||
try {
|
||||
await fs.stat(path);
|
||||
} catch (err) {
|
||||
output.error(
|
||||
`The specified file or directory "${basename(path)}" does not exist.`
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (localConfig) {
|
||||
const { version } = localConfig;
|
||||
const file = highlight(localConfig[fileNameSymbol]!);
|
||||
@@ -178,14 +164,7 @@ export default async (client: Client): Promise<number> => {
|
||||
|
||||
const quiet = !client.stdout.isTTY;
|
||||
|
||||
// check paths
|
||||
const pathValidation = await validatePaths(client, paths);
|
||||
|
||||
if (!pathValidation.valid) {
|
||||
return pathValidation.exitCode;
|
||||
}
|
||||
|
||||
const { path } = pathValidation;
|
||||
let { path: cwd } = pathValidation;
|
||||
const autoConfirm = argv['--yes'];
|
||||
|
||||
// deprecate --name
|
||||
@@ -217,56 +196,6 @@ export default async (client: Client): Promise<number> => {
|
||||
return target;
|
||||
}
|
||||
|
||||
// build `--prebuilt`
|
||||
if (argv['--prebuilt']) {
|
||||
const prebuiltExists = await fs.pathExists(join(path, '.vercel/output'));
|
||||
if (!prebuiltExists) {
|
||||
error(
|
||||
`The ${param(
|
||||
'--prebuilt'
|
||||
)} option was used, but no prebuilt output found in ".vercel/output". Run ${getCommandName(
|
||||
'build'
|
||||
)} to generate a local build.`
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const prebuiltBuild = await getPrebuiltJson(path);
|
||||
|
||||
// Ensure that there was not a build error
|
||||
const prebuiltError =
|
||||
prebuiltBuild?.error ||
|
||||
prebuiltBuild?.builds?.find(build => 'error' in build)?.error;
|
||||
if (prebuiltError) {
|
||||
output.log(
|
||||
`Prebuilt deployment cannot be created because ${getCommandName(
|
||||
'build'
|
||||
)} failed with error:\n`
|
||||
);
|
||||
prettyError(prebuiltError);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Ensure that the deploy target matches the build target
|
||||
const assumedTarget = target || 'preview';
|
||||
if (prebuiltBuild?.target && prebuiltBuild.target !== assumedTarget) {
|
||||
let specifyTarget = '';
|
||||
if (prebuiltBuild.target === 'production') {
|
||||
specifyTarget = ` --prod`;
|
||||
}
|
||||
|
||||
prettyError({
|
||||
message: `The ${param(
|
||||
'--prebuilt'
|
||||
)} option was used with the target environment "${assumedTarget}", but the prebuilt output found in ".vercel/output" was built with target environment "${
|
||||
prebuiltBuild.target
|
||||
}". Please run ${getCommandName(`--prebuilt${specifyTarget}`)}.`,
|
||||
link: 'https://vercel.link/prebuilt-environment-mismatch',
|
||||
});
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
const archive = argv['--archive'];
|
||||
if (typeof archive === 'string' && !isValidArchive(archive)) {
|
||||
output.error(`Format must be one of: ${VALID_ARCHIVE_FORMATS.join(', ')}`);
|
||||
@@ -274,7 +203,7 @@ export default async (client: Client): Promise<number> => {
|
||||
}
|
||||
|
||||
// retrieve `project` and `org` from .vercel
|
||||
const link = await getLinkedProject(client, path);
|
||||
const link = await getLinkedProject(client, cwd);
|
||||
|
||||
if (link.status === 'error') {
|
||||
return link.exitCode;
|
||||
@@ -291,7 +220,7 @@ export default async (client: Client): Promise<number> => {
|
||||
autoConfirm ||
|
||||
(await confirm(
|
||||
client,
|
||||
`Set up and deploy ${chalk.cyan(`“${toHumanPath(path)}”`)}?`,
|
||||
`Set up and deploy ${chalk.cyan(`“${toHumanPath(cwd)}”`)}?`,
|
||||
true
|
||||
));
|
||||
|
||||
@@ -338,7 +267,7 @@ export default async (client: Client): Promise<number> => {
|
||||
|
||||
if (typeof projectOrNewProjectName === 'string') {
|
||||
newProjectName = projectOrNewProjectName;
|
||||
rootDirectory = await inputRootDirectory(client, path, autoConfirm);
|
||||
rootDirectory = await inputRootDirectory(client, cwd, autoConfirm);
|
||||
} else {
|
||||
project = projectOrNewProjectName;
|
||||
rootDirectory = project.rootDirectory;
|
||||
@@ -346,8 +275,8 @@ export default async (client: Client): Promise<number> => {
|
||||
|
||||
// we can already link the project
|
||||
await linkFolderToProject(
|
||||
output,
|
||||
path,
|
||||
client,
|
||||
cwd,
|
||||
{
|
||||
projectId: project.id,
|
||||
orgId: org.id,
|
||||
@@ -359,11 +288,76 @@ export default async (client: Client): Promise<number> => {
|
||||
}
|
||||
}
|
||||
|
||||
// For repo-style linking, reset the path to the root of the repository
|
||||
if (link.status === 'linked' && link.repoRoot) {
|
||||
cwd = link.repoRoot;
|
||||
}
|
||||
|
||||
// At this point `org` should be populated
|
||||
if (!org) {
|
||||
throw new Error(`"org" is not defined`);
|
||||
}
|
||||
|
||||
// build `--prebuilt`
|
||||
if (argv['--prebuilt']) {
|
||||
// For repo-style linking, update `cwd` to be the Project
|
||||
// subdirectory when `rootDirectory` setting is defined
|
||||
if (
|
||||
link.status === 'linked' &&
|
||||
link.repoRoot &&
|
||||
link.project.rootDirectory
|
||||
) {
|
||||
cwd = join(cwd, link.project.rootDirectory);
|
||||
}
|
||||
|
||||
const prebuiltExists = await fs.pathExists(join(cwd, '.vercel/output'));
|
||||
if (!prebuiltExists) {
|
||||
error(
|
||||
`The ${param(
|
||||
'--prebuilt'
|
||||
)} option was used, but no prebuilt output found in ".vercel/output". Run ${getCommandName(
|
||||
'build'
|
||||
)} to generate a local build.`
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const prebuiltBuild = await getPrebuiltJson(cwd);
|
||||
|
||||
// Ensure that there was not a build error
|
||||
const prebuiltError =
|
||||
prebuiltBuild?.error ||
|
||||
prebuiltBuild?.builds?.find(build => 'error' in build)?.error;
|
||||
if (prebuiltError) {
|
||||
output.log(
|
||||
`Prebuilt deployment cannot be created because ${getCommandName(
|
||||
'build'
|
||||
)} failed with error:\n`
|
||||
);
|
||||
prettyError(prebuiltError);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Ensure that the deploy target matches the build target
|
||||
const assumedTarget = target || 'preview';
|
||||
if (prebuiltBuild?.target && prebuiltBuild.target !== assumedTarget) {
|
||||
let specifyTarget = '';
|
||||
if (prebuiltBuild.target === 'production') {
|
||||
specifyTarget = ` --prod`;
|
||||
}
|
||||
|
||||
prettyError({
|
||||
message: `The ${param(
|
||||
'--prebuilt'
|
||||
)} option was used with the target environment "${assumedTarget}", but the prebuilt output found in ".vercel/output" was built with target environment "${
|
||||
prebuiltBuild.target
|
||||
}". Please run ${getCommandName(`--prebuilt${specifyTarget}`)}.`,
|
||||
link: 'https://vercel.link/prebuilt-environment-mismatch',
|
||||
});
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the `contextName` and `currentTeam` as specified by the
|
||||
// Project Settings, so that API calls happen with the proper scope
|
||||
const contextName = org.slug;
|
||||
@@ -373,14 +367,14 @@ export default async (client: Client): Promise<number> => {
|
||||
// and upload the entire directory.
|
||||
const sourcePath =
|
||||
rootDirectory && !sourceFilesOutsideRootDirectory
|
||||
? join(path, rootDirectory)
|
||||
: path;
|
||||
? join(cwd, rootDirectory)
|
||||
: cwd;
|
||||
|
||||
if (
|
||||
rootDirectory &&
|
||||
(await validateRootDirectory(
|
||||
output,
|
||||
path,
|
||||
cwd,
|
||||
sourcePath,
|
||||
project
|
||||
? `To change your Project Settings, go to https://vercel.com/${org?.slug}/${project.name}/settings`
|
||||
@@ -393,7 +387,7 @@ export default async (client: Client): Promise<number> => {
|
||||
// If Root Directory is used we'll try to read the config
|
||||
// from there instead and use it if it exists.
|
||||
if (rootDirectory) {
|
||||
const rootDirectoryConfig = readLocalConfig(join(path, rootDirectory));
|
||||
const rootDirectoryConfig = readLocalConfig(join(cwd, rootDirectory));
|
||||
|
||||
if (rootDirectoryConfig) {
|
||||
debug(`Read local config from root directory (${rootDirectory})`);
|
||||
@@ -469,7 +463,7 @@ export default async (client: Client): Promise<number> => {
|
||||
parseMeta(argv['--meta'])
|
||||
);
|
||||
|
||||
const gitMetadata = await createGitMeta(path, output, project);
|
||||
const gitMetadata = await createGitMeta(cwd, output, project);
|
||||
|
||||
// Merge dotenv config, `env` from vercel.json, and `--env` / `-e` arguments
|
||||
const deploymentEnv = Object.assign(
|
||||
@@ -520,6 +514,9 @@ export default async (client: Client): Promise<number> => {
|
||||
}
|
||||
|
||||
try {
|
||||
// if this flag is not set, use `undefined` to allow the project setting to be used
|
||||
const autoAssignCustomDomains = argv['--skip-domain'] ? false : undefined;
|
||||
|
||||
const createArgs: CreateOptions = {
|
||||
name,
|
||||
env: deploymentEnv,
|
||||
@@ -543,6 +540,7 @@ export default async (client: Client): Promise<number> => {
|
||||
target,
|
||||
skipAutoDetectionConfirmation: autoConfirm,
|
||||
noWait,
|
||||
autoAssignCustomDomains,
|
||||
};
|
||||
|
||||
if (!localConfig.builds || localConfig.builds.length === 0) {
|
||||
@@ -559,11 +557,11 @@ export default async (client: Client): Promise<number> => {
|
||||
client,
|
||||
now,
|
||||
contextName,
|
||||
[sourcePath],
|
||||
sourcePath,
|
||||
createArgs,
|
||||
org,
|
||||
!project,
|
||||
path,
|
||||
cwd,
|
||||
archive
|
||||
);
|
||||
|
||||
@@ -595,11 +593,11 @@ export default async (client: Client): Promise<number> => {
|
||||
client,
|
||||
now,
|
||||
contextName,
|
||||
[sourcePath],
|
||||
sourcePath,
|
||||
createArgs,
|
||||
org,
|
||||
false,
|
||||
path
|
||||
cwd
|
||||
);
|
||||
}
|
||||
|
||||
@@ -728,7 +726,7 @@ export default async (client: Client): Promise<number> => {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return printDeploymentStatus(output, client, deployment, deployStamp, noWait);
|
||||
return printDeploymentStatus(client, deployment, deployStamp, noWait);
|
||||
};
|
||||
|
||||
function handleCreateDeployError(
|
||||
@@ -835,112 +833,3 @@ const addProcessEnv = async (
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const printDeploymentStatus = async (
|
||||
output: Output,
|
||||
client: Client,
|
||||
{
|
||||
readyState,
|
||||
alias: aliasList,
|
||||
aliasError,
|
||||
target,
|
||||
indications,
|
||||
url: deploymentUrl,
|
||||
aliasWarning,
|
||||
}: {
|
||||
readyState: Deployment['readyState'];
|
||||
alias: string[];
|
||||
aliasError: Error;
|
||||
target: string;
|
||||
indications: any;
|
||||
url: string;
|
||||
aliasWarning?: {
|
||||
code: string;
|
||||
message: string;
|
||||
link?: string;
|
||||
action?: string;
|
||||
};
|
||||
},
|
||||
deployStamp: () => string,
|
||||
noWait: boolean
|
||||
) => {
|
||||
indications = indications || [];
|
||||
const isProdDeployment = target === 'production';
|
||||
|
||||
let isStillBuilding = false;
|
||||
if (noWait) {
|
||||
if (isDeploying(readyState)) {
|
||||
isStillBuilding = true;
|
||||
output.print(
|
||||
prependEmoji(
|
||||
'Note: Deployment is still processing...',
|
||||
emoji('notice')
|
||||
) + '\n'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isStillBuilding && readyState !== 'READY') {
|
||||
output.error(
|
||||
`Your deployment failed. Please retry later. More: https://err.sh/vercel/deployment-error`
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (aliasError) {
|
||||
output.warn(
|
||||
`Failed to assign aliases${
|
||||
aliasError.message ? `: ${aliasError.message}` : ''
|
||||
}`
|
||||
);
|
||||
} else {
|
||||
// print preview/production url
|
||||
let previewUrl: string;
|
||||
// if `noWait` is true, then use the deployment url, not an alias
|
||||
if (!noWait && Array.isArray(aliasList) && aliasList.length > 0) {
|
||||
const previewUrlInfo = await getPreferredPreviewURL(client, aliasList);
|
||||
if (previewUrlInfo) {
|
||||
previewUrl = previewUrlInfo.previewUrl;
|
||||
} else {
|
||||
previewUrl = `https://${deploymentUrl}`;
|
||||
}
|
||||
} else {
|
||||
// fallback to deployment url
|
||||
previewUrl = `https://${deploymentUrl}`;
|
||||
}
|
||||
|
||||
output.print(
|
||||
prependEmoji(
|
||||
`${isProdDeployment ? 'Production' : 'Preview'}: ${chalk.bold(
|
||||
previewUrl
|
||||
)} ${deployStamp()}`,
|
||||
emoji('success')
|
||||
) + `\n`
|
||||
);
|
||||
}
|
||||
|
||||
if (aliasWarning?.message) {
|
||||
indications.push({
|
||||
type: 'warning',
|
||||
payload: aliasWarning.message,
|
||||
link: aliasWarning.link,
|
||||
action: aliasWarning.action,
|
||||
});
|
||||
}
|
||||
|
||||
const newline = '\n';
|
||||
for (let indication of indications) {
|
||||
const message =
|
||||
prependEmoji(chalk.dim(indication.payload), emoji(indication.type)) +
|
||||
newline;
|
||||
let link = '';
|
||||
if (indication.link)
|
||||
link =
|
||||
chalk.dim(
|
||||
`${indication.action || 'Learn More'}: ${linkStyle(indication.link)}`
|
||||
) + newline;
|
||||
output.print(message + link);
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -57,8 +57,15 @@ export default async function dev(
|
||||
|
||||
let projectSettings: ProjectSettings | undefined;
|
||||
let envValues: Record<string, string> = {};
|
||||
let repoRoot: string | undefined;
|
||||
if (link.status === 'linked') {
|
||||
const { project, org } = link;
|
||||
|
||||
// If repo linked, update `cwd` to the repo root
|
||||
if (link.repoRoot) {
|
||||
repoRoot = cwd = link.repoRoot;
|
||||
}
|
||||
|
||||
client.config.currentTeam = org.type === 'team' ? org.id : undefined;
|
||||
|
||||
projectSettings = project;
|
||||
@@ -76,6 +83,7 @@ export default async function dev(
|
||||
output,
|
||||
projectSettings,
|
||||
envValues,
|
||||
repoRoot,
|
||||
});
|
||||
|
||||
// listen to SIGTERM for graceful shutdown
|
||||
|
||||
6
packages/cli/src/commands/env/index.ts
vendored
6
packages/cli/src/commands/env/index.ts
vendored
@@ -26,7 +26,7 @@ const help = () => {
|
||||
ls [environment] [gitbranch] List all variables for the specified Environment
|
||||
add [name] [environment] [gitbranch] Add an Environment Variable (see examples below)
|
||||
rm [name] [environment] [gitbranch] Remove an Environment Variable (see examples below)
|
||||
pull [filename] Pull all Development Environment Variables from the cloud and write to a file [.env]
|
||||
pull [filename] Pull all Development Environment Variables from the cloud and write to a file [.env.local]
|
||||
|
||||
${chalk.dim('Options:')}
|
||||
|
||||
@@ -130,10 +130,9 @@ export default async function main(client: Client) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
const cwd = argv['--cwd'] || process.cwd();
|
||||
const subArgs = argv._.slice(1);
|
||||
const { subcommand, args } = getSubcommand(subArgs, COMMAND_CONFIG);
|
||||
const { output, config } = client;
|
||||
const { cwd, output, config } = client;
|
||||
|
||||
const target = argv['--environment']?.toLowerCase() || 'development';
|
||||
if (!isValidEnvTarget(target)) {
|
||||
@@ -168,6 +167,7 @@ export default async function main(client: Client) {
|
||||
case 'pull':
|
||||
return pull(
|
||||
client,
|
||||
link,
|
||||
project,
|
||||
target,
|
||||
argv,
|
||||
|
||||
27
packages/cli/src/commands/env/pull.ts
vendored
27
packages/cli/src/commands/env/pull.ts
vendored
@@ -2,7 +2,11 @@ import chalk from 'chalk';
|
||||
import { outputFile } from 'fs-extra';
|
||||
import { closeSync, openSync, readSync } from 'fs';
|
||||
import { resolve } from 'path';
|
||||
import type { Project, ProjectEnvTarget } from '@vercel-internals/types';
|
||||
import type {
|
||||
Project,
|
||||
ProjectEnvTarget,
|
||||
ProjectLinked,
|
||||
} from '@vercel-internals/types';
|
||||
import Client from '../../util/client';
|
||||
import { emoji, prependEmoji } from '../../util/emoji';
|
||||
import confirm from '../../util/input/confirm';
|
||||
@@ -19,6 +23,7 @@ import {
|
||||
createEnvObject,
|
||||
} from '../../util/env/diff-env-files';
|
||||
import { isErrnoException } from '@vercel/error-utils';
|
||||
import { addToGitIgnore } from '../../util/link/add-to-gitignore';
|
||||
|
||||
const CONTENTS_PREFIX = '# Created by Vercel CLI\n';
|
||||
|
||||
@@ -51,6 +56,7 @@ function tryReadHeadSync(path: string, length: number) {
|
||||
|
||||
export default async function pull(
|
||||
client: Client,
|
||||
link: ProjectLinked,
|
||||
project: Project,
|
||||
environment: ProjectEnvTarget,
|
||||
opts: Partial<Options>,
|
||||
@@ -67,7 +73,7 @@ export default async function pull(
|
||||
}
|
||||
|
||||
// handle relative or absolute filename
|
||||
const [filename = '.env'] = args;
|
||||
const [filename = '.env.local'] = args;
|
||||
const fullPath = resolve(cwd, filename);
|
||||
const skipConfirmation = opts['--yes'];
|
||||
const gitBranch = opts['--git-branch'];
|
||||
@@ -136,11 +142,22 @@ export default async function pull(
|
||||
output.log('No changes found.');
|
||||
}
|
||||
|
||||
let isGitIgnoreUpdated = false;
|
||||
if (filename === '.env.local') {
|
||||
// When the file is `.env.local`, we also add it to `.gitignore`
|
||||
// to avoid accidentally committing it to git.
|
||||
// We use '.env*.local' to match the default .gitignore from
|
||||
// create-next-app template. See:
|
||||
// https://github.com/vercel/next.js/blob/06abd634899095b6cc28e6e8315b1e8b9c8df939/packages/create-next-app/templates/app/js/gitignore#L28
|
||||
const rootPath = link.repoRoot ?? cwd;
|
||||
isGitIgnoreUpdated = await addToGitIgnore(rootPath, '.env*.local');
|
||||
}
|
||||
|
||||
output.print(
|
||||
`${prependEmoji(
|
||||
`${exists ? 'Updated' : 'Created'} ${chalk.bold(
|
||||
filename
|
||||
)} file ${chalk.gray(pullStamp())}`,
|
||||
`${exists ? 'Updated' : 'Created'} ${chalk.bold(filename)} file ${
|
||||
isGitIgnoreUpdated ? 'and added it to .gitignore' : ''
|
||||
} ${chalk.gray(pullStamp())}`,
|
||||
emoji('success')
|
||||
)}\n`
|
||||
);
|
||||
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
parseRepoUrl,
|
||||
printRemoteUrls,
|
||||
} from '../../util/git/connect-git-provider';
|
||||
import validatePaths from '../../util/validate-paths';
|
||||
|
||||
interface GitRepoCheckParams {
|
||||
client: Client;
|
||||
@@ -56,7 +55,7 @@ export default async function connect(
|
||||
project: Project | undefined,
|
||||
org: Org | undefined
|
||||
) {
|
||||
const { output } = client;
|
||||
const { cwd, output } = client;
|
||||
const confirm = Boolean(argv['--yes']);
|
||||
const repoArg = argv._[1];
|
||||
|
||||
@@ -77,19 +76,11 @@ export default async function connect(
|
||||
return 1;
|
||||
}
|
||||
|
||||
let paths = [process.cwd()];
|
||||
|
||||
const validate = await validatePaths(client, paths);
|
||||
if (!validate.valid) {
|
||||
return validate.exitCode;
|
||||
}
|
||||
const { path } = validate;
|
||||
|
||||
const gitProviderLink = project.link;
|
||||
client.config.currentTeam = org.type === 'team' ? org.id : undefined;
|
||||
|
||||
// get project from .git
|
||||
const gitConfigPath = join(path, '.git/config');
|
||||
const gitConfigPath = join(cwd, '.git/config');
|
||||
const gitConfig = await parseGitConfig(gitConfigPath, output);
|
||||
|
||||
if (repoArg) {
|
||||
@@ -116,7 +107,7 @@ export default async function connect(
|
||||
confirm,
|
||||
org,
|
||||
project,
|
||||
repoInfo: repoArg,
|
||||
repoInfo: parsedUrlArg,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import getInvalidSubcommand from '../../util/get-invalid-subcommand';
|
||||
import handleError from '../../util/handle-error';
|
||||
import logo from '../../util/output/logo';
|
||||
import { getPkgName } from '../../util/pkg-name';
|
||||
import validatePaths from '../../util/validate-paths';
|
||||
import connect from './connect';
|
||||
import disconnect from './disconnect';
|
||||
|
||||
@@ -81,16 +80,9 @@ export default async function main(client: Client) {
|
||||
subcommand = argv._[0];
|
||||
const args = argv._.slice(1);
|
||||
const autoConfirm = Boolean(argv['--yes']);
|
||||
const { output } = client;
|
||||
const { cwd, output } = client;
|
||||
|
||||
let paths = [process.cwd()];
|
||||
const pathValidation = await validatePaths(client, paths);
|
||||
if (!pathValidation.valid) {
|
||||
return pathValidation.exitCode;
|
||||
}
|
||||
const { path } = pathValidation;
|
||||
|
||||
const linkedProject = await ensureLink('git', client, path, { autoConfirm });
|
||||
const linkedProject = await ensureLink('git', client, cwd, { autoConfirm });
|
||||
if (typeof linkedProject === 'number') {
|
||||
return linkedProject;
|
||||
}
|
||||
|
||||
320
packages/cli/src/commands/help.ts
Normal file
320
packages/cli/src/commands/help.ts
Normal file
@@ -0,0 +1,320 @@
|
||||
import chalk from 'chalk';
|
||||
import stripAnsi from 'strip-ansi';
|
||||
import { LOGO, NAME } from '@vercel-internals/constants';
|
||||
|
||||
const INDENT = ' '.repeat(2);
|
||||
const NEWLINE = '\n';
|
||||
|
||||
export interface CommandOption {
|
||||
name: string;
|
||||
shorthand: string | null;
|
||||
type: 'boolean' | 'string';
|
||||
argument?: string;
|
||||
deprecated: boolean;
|
||||
description?: string;
|
||||
multi: boolean;
|
||||
}
|
||||
export interface CommandArgument {
|
||||
name: string;
|
||||
required: boolean;
|
||||
}
|
||||
export interface CommandExample {
|
||||
name: string;
|
||||
value: string | string[];
|
||||
}
|
||||
export interface Command {
|
||||
name: string;
|
||||
description: string;
|
||||
arguments: CommandArgument[];
|
||||
options: CommandOption[];
|
||||
examples: CommandExample[];
|
||||
}
|
||||
|
||||
const globalCommandOptions: CommandOption[] = [
|
||||
{
|
||||
name: 'help',
|
||||
shorthand: 'h',
|
||||
type: 'string',
|
||||
description: 'Output usage information',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'version',
|
||||
shorthand: 'v',
|
||||
type: 'string',
|
||||
description: 'Output the version number',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'cwd',
|
||||
shorthand: null,
|
||||
type: 'string',
|
||||
argument: 'DIR',
|
||||
description:
|
||||
'Sets the current working directory for a single run of a command',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'local-config',
|
||||
shorthand: 'A',
|
||||
type: 'string',
|
||||
argument: 'FILE',
|
||||
description: 'Path to the local `vercel.json` file',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'global-config',
|
||||
shorthand: 'Q',
|
||||
type: 'string',
|
||||
argument: 'DIR',
|
||||
description: 'Path to the global `.vercel` directory',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'debug',
|
||||
shorthand: 'd',
|
||||
type: 'string',
|
||||
description: 'Debug mode (default off)',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'no-color',
|
||||
shorthand: null,
|
||||
type: 'string',
|
||||
description: 'No color mode (default off)',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'scope',
|
||||
shorthand: 'S',
|
||||
type: 'string',
|
||||
description: 'Set a custom scope',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'token',
|
||||
shorthand: 't',
|
||||
type: 'string',
|
||||
argument: 'TOKEN',
|
||||
description: 'Login token',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
];
|
||||
|
||||
export function calcLineLength(line: string[]) {
|
||||
return stripAnsi(lineToString(line)).length;
|
||||
}
|
||||
|
||||
// Insert spaces in between non-whitespace items only
|
||||
export function lineToString(line: string[]) {
|
||||
let string = '';
|
||||
for (let i = 0; i < line.length; i++) {
|
||||
if (i === line.length - 1) {
|
||||
string += line[i];
|
||||
} else {
|
||||
const curr = line[i];
|
||||
const next = line[i + 1];
|
||||
string += curr;
|
||||
if (curr.trim() !== '' && next.trim() !== '') {
|
||||
string += ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
export function outputArrayToString(outputArray: (string | null)[]) {
|
||||
return outputArray.filter(line => line !== null).join(NEWLINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: `▲ vercel deploy [path] [options]`
|
||||
* @param command
|
||||
* @returns
|
||||
*/
|
||||
export function buildCommandSynopsisLine(command: Command) {
|
||||
const line: string[] = [
|
||||
INDENT,
|
||||
LOGO,
|
||||
chalk.bold(NAME),
|
||||
chalk.bold(command.name),
|
||||
];
|
||||
if (command.arguments.length > 0) {
|
||||
for (const argument of command.arguments) {
|
||||
line.push(argument.required ? argument.name : `[${argument.name}]`);
|
||||
}
|
||||
}
|
||||
if (command.options.length > 0) {
|
||||
line.push('[options]');
|
||||
}
|
||||
|
||||
line.push(NEWLINE);
|
||||
return lineToString(line);
|
||||
}
|
||||
|
||||
export function buildCommandOptionLines(
|
||||
commandOptions: CommandOption[],
|
||||
options: BuildHelpOutputOptions,
|
||||
sectionTitle: String
|
||||
) {
|
||||
// Filter out deprecated and intentionally undocumented options
|
||||
commandOptions = commandOptions.filter(
|
||||
option => !option.deprecated && option.description !== undefined
|
||||
);
|
||||
|
||||
if (commandOptions.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Initialize output array with header and empty line
|
||||
const outputArray: string[] = [`${INDENT}${chalk.dim(sectionTitle)}:`, ''];
|
||||
|
||||
// Start building option lines
|
||||
const optionLines: string[][] = [];
|
||||
// Sort command options alphabetically
|
||||
commandOptions.sort((a, b) =>
|
||||
a.name < b.name ? -1 : a.name > b.name ? 1 : 0
|
||||
);
|
||||
// Keep track of longest "start" of an option line to determine description spacing
|
||||
let maxLineStartLength = 0;
|
||||
// Iterate over options and create the "start" of each option (e.g. ` -b, --build-env <key=value>`)
|
||||
for (const option of commandOptions) {
|
||||
const startLine: string[] = [INDENT, INDENT, INDENT];
|
||||
if (option.shorthand) {
|
||||
startLine.push(`-${option.shorthand},`);
|
||||
}
|
||||
startLine.push(`--${option.name}`);
|
||||
if (option.argument) {
|
||||
startLine.push(`<${option.argument}>`);
|
||||
}
|
||||
// the length includes the INDENT
|
||||
const lineLength = calcLineLength(startLine);
|
||||
maxLineStartLength = Math.max(lineLength, maxLineStartLength);
|
||||
optionLines.push(startLine);
|
||||
}
|
||||
/*
|
||||
* Iterate over in-progress option lines to add space-filler and description
|
||||
* For Example:
|
||||
* | --archive My description starts here.
|
||||
* |
|
||||
* | -b, --build-env <key=value> Start of description here then
|
||||
* | it wraps here.
|
||||
* |
|
||||
* | -e, --env <key=value> My description is short.
|
||||
*
|
||||
* Breaking down option lines:
|
||||
* | -b, --build-env <key=value> Start of description here then
|
||||
* |[][ ][][ ]
|
||||
* |↑ ↑ ↑ ↑
|
||||
* |1 2 3 4
|
||||
* | it wraps here.
|
||||
* |[][ ][ ]
|
||||
* |↑ ↑ ↑
|
||||
* |5 6 7
|
||||
* | 1, 5 = indent
|
||||
* | 2 = start
|
||||
* | 3, 6 = space-filler
|
||||
* | 4, 7 = description
|
||||
*/
|
||||
for (let i = 0; i < optionLines.length; i++) {
|
||||
const optionLine = optionLines[i];
|
||||
const option = commandOptions[i];
|
||||
// Add only 2 spaces to the longest line, and then make all shorter lines the same length.
|
||||
optionLine.push(
|
||||
' '.repeat(2 + (maxLineStartLength - calcLineLength(optionLine)))
|
||||
);
|
||||
|
||||
// Descriptions may be longer than max line length. Wrap them to the same column as the first description line
|
||||
const lines: string[][] = [optionLine];
|
||||
if (option.description) {
|
||||
for (const descriptionWord of option.description.split(' ')) {
|
||||
// insert a new line when the next word would match or exceed the maximum line length
|
||||
if (
|
||||
calcLineLength(lines[lines.length - 1]) +
|
||||
stripAnsi(descriptionWord).length >=
|
||||
options.columns
|
||||
) {
|
||||
// initialize the new line with the necessary whitespace. The INDENT is apart of `maxLineStartLength`
|
||||
lines.push([' '.repeat(maxLineStartLength + 2)]);
|
||||
}
|
||||
// insert the word to the current last line
|
||||
lines[lines.length - 1].push(descriptionWord);
|
||||
}
|
||||
}
|
||||
// for every line, transform into a string and push it to the output
|
||||
for (const line of lines) {
|
||||
outputArray.push(lineToString(line));
|
||||
}
|
||||
}
|
||||
|
||||
return `${outputArrayToString(outputArray)}${NEWLINE}`;
|
||||
}
|
||||
|
||||
export function buildCommandExampleLines(command: Command) {
|
||||
const outputArray: string[] = [`${INDENT}${chalk.dim('Examples:')}`, ''];
|
||||
for (const example of command.examples) {
|
||||
const nameLine: string[] = [INDENT];
|
||||
nameLine.push(chalk.gray('-'));
|
||||
nameLine.push(example.name);
|
||||
outputArray.push(lineToString(nameLine));
|
||||
outputArray.push('');
|
||||
const buildValueLine = (value: string) => {
|
||||
return lineToString([INDENT, INDENT, chalk.cyan(`$ ${value}`)]);
|
||||
};
|
||||
if (Array.isArray(example.value)) {
|
||||
for (const line of example.value) {
|
||||
outputArray.push(buildValueLine(line));
|
||||
}
|
||||
} else {
|
||||
outputArray.push(buildValueLine(example.value));
|
||||
}
|
||||
outputArray.push('');
|
||||
}
|
||||
|
||||
return outputArrayToString(outputArray);
|
||||
}
|
||||
|
||||
function buildDescriptionLine(command: Command) {
|
||||
const line: string[] = [INDENT, command.description, NEWLINE];
|
||||
return lineToString(line);
|
||||
}
|
||||
|
||||
interface BuildHelpOutputOptions {
|
||||
columns: number;
|
||||
}
|
||||
|
||||
export function buildHelpOutput(
|
||||
command: Command,
|
||||
options: BuildHelpOutputOptions
|
||||
) {
|
||||
const outputArray: (string | null)[] = [
|
||||
'',
|
||||
buildCommandSynopsisLine(command),
|
||||
buildDescriptionLine(command),
|
||||
buildCommandOptionLines(command.options, options, 'Options'),
|
||||
buildCommandOptionLines(globalCommandOptions, options, 'Global Options'),
|
||||
buildCommandExampleLines(command),
|
||||
'',
|
||||
];
|
||||
|
||||
return outputArrayToString(outputArray);
|
||||
}
|
||||
|
||||
export interface HelpOptions {
|
||||
columns?: number;
|
||||
}
|
||||
|
||||
export function help(command: Command, options: HelpOptions) {
|
||||
return buildHelpOutput(command, {
|
||||
columns: options.columns ?? 80,
|
||||
});
|
||||
}
|
||||
@@ -26,7 +26,9 @@ export default new Map([
|
||||
['ls', 'list'],
|
||||
['project', 'project'],
|
||||
['projects', 'project'],
|
||||
['promote', 'promote'],
|
||||
['pull', 'pull'],
|
||||
['redeploy', 'redeploy'],
|
||||
['remove', 'remove'],
|
||||
['rm', 'remove'],
|
||||
['rollback', 'rollback'],
|
||||
|
||||
50
packages/cli/src/commands/inspect/command.ts
Normal file
50
packages/cli/src/commands/inspect/command.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { Command } from '../help';
|
||||
import { getPkgName } from '../../util/pkg-name';
|
||||
|
||||
export const inspectCommand: Command = {
|
||||
name: 'inspect',
|
||||
description: 'Show information about a deployment.',
|
||||
arguments: [
|
||||
{
|
||||
name: 'url',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
options: [
|
||||
{
|
||||
name: 'timeout',
|
||||
description: 'Time to wait for deployment completion [3m]',
|
||||
argument: 'TIME',
|
||||
shorthand: null,
|
||||
type: 'string',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
{
|
||||
name: 'wait',
|
||||
description: 'Blocks until deployment completes',
|
||||
shorthand: null,
|
||||
type: 'string',
|
||||
deprecated: false,
|
||||
multi: false,
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
name: 'Get information about a deployment by its unique URL',
|
||||
value: `${getPkgName()} inspect my-deployment-ji2fjij2.vercel.app`,
|
||||
},
|
||||
{
|
||||
name: 'Get information about the deployment an alias points to',
|
||||
value: `${getPkgName()} inspect my-deployment.vercel.app`,
|
||||
},
|
||||
{
|
||||
name: 'Get information about a deployment by piping in the URL',
|
||||
value: `echo my-deployment.vercel.app | ${getPkgName()} inspect`,
|
||||
},
|
||||
{
|
||||
name: 'Wait up to 90 seconds for deployment to complete',
|
||||
value: `${getPkgName()} inspect my-deployment.vercel.app --wait --timeout 90s`,
|
||||
},
|
||||
],
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user