Compare commits

..

89 Commits

Author SHA1 Message Date
Steven
b626f3fe57 Publish Stable
- @vercel/frameworks@0.0.14
 - @vercel/build-utils@2.3.0
 - @vercel/cgi@1.0.5
 - vercel@19.0.0
 - @vercel/client@8.0.0
 - @vercel/go@1.1.0
 - @vercel/next@2.6.0
 - @vercel/node-bridge@1.3.0
 - @vercel/node@1.6.0
 - @vercel/python@1.2.0
 - @vercel/routing-utils@1.8.2
 - @vercel/ruby@1.2.0
 - @vercel/static-build@0.17.0
2020-05-07 18:52:35 -04:00
Steven
96bc0c9bee Publish Canary
- vercel@18.0.1-canary.24
2020-05-07 17:56:40 -04:00
Steven
f4ff8c0268 [now-cli] Change precedence of auth directory (#4299) 2020-05-07 23:55:35 +02:00
Steven
1a5681f287 [now-cli] Add getTitleName() and update getCommandName() (#4296)
This PR adds two functions:

* `getTitleName()` - used to get the uppercase Vercel or Now package name, for example `vercel --version`
* `getCommandName()` - used to get the `vercel` command followed by subcommands, for example in error suggestions
2020-05-07 21:24:15 +00:00
Ana Trajkovska
88b66ae646 Publish Canary
- vercel@18.0.1-canary.23
2020-05-07 22:37:48 +02:00
Ana Trajkovska
db0124782a Implement pagination for vercel teams ls (#4294)
* Implement pagination for `now teams ls`

* Set default empty object

* Use output logger

* Trigger build
2020-05-07 22:36:54 +02:00
Nathan Rajlich
a7a5d4d169 [now-cli] Special case @vercel/static when updating builders (#4295) 2020-05-07 19:40:52 +00:00
Nathan Rajlich
4b39e96c28 Ensure the npm registry is used during "Publish" workflow (#4286)
Unset the `npm_config_registry` env var which yarn overwrites to the
yarn registry, which we don't want since the `.npmrc` file that gets
created is configured to the npm registry.
2020-05-07 19:00:16 +00:00
Steven
f459db9f83 [now-cli] Add e2e test for vercel.json and .vercelignore (#4292)
This PR adds a test for a deployment as well as `now dev` to ensure both `vercel.json` and `.vercelignore` are applied.

I also fixed the remaining test helpers to work with `vercel.json`.
2020-05-07 18:04:37 +00:00
Ana Trajkovska
ad19021969 Publish Canary
- vercel@18.0.1-canary.22
2020-05-07 18:54:37 +02:00
Ana Trajkovska
95e41874e4 Replace now with vercel in pagination message (#4290) 2020-05-07 18:49:15 +02:00
Ana Trajkovska
4d20a1d77b Publish Canary
- vercel@18.0.1-canary.21
2020-05-07 14:56:28 +02:00
Ana Trajkovska
325ee261cb Implement pagination for now dns ls (#4257) 2020-05-07 14:53:08 +02:00
Nathan Rajlich
2e0cee490d Publish Canary
- @vercel/build-utils@2.2.2-canary.8
 - vercel@18.0.1-canary.20
 - @vercel/client@7.1.1-canary.5
 - @vercel/go@1.0.8-canary.2
 - @vercel/next@2.5.5-canary.7
 - @vercel/node@1.5.2-canary.9
 - @vercel/python@1.1.7-canary.3
 - @vercel/ruby@1.1.1-canary.2
 - @vercel/static-build@0.16.1-canary.6
2020-05-06 22:16:10 -07:00
Nathan Rajlich
8a9b67a3f3 [now-build-utils] Use @now runtimes for zero-config (#4284)
* [now-build-utils] Use `@now` runtimes for zero-config

This is a temporary change until the `@vercel` runtimes work in
production.

* Temporary fix to E2E
2020-05-06 22:09:06 -07:00
Nathan Rajlich
f1d9a5da96 [now-build-utils][now-cli] Fix isOfficialRuntime() edge case bug (#4282)
Fixes a bug where `isOfficialRuntime('static', '@now/static-build')` was returning `true` when it should have been `false`.

And use the function from `@vercel/build-utils` in Vercel CLI.
2020-05-07 03:33:35 +00:00
Nathan Rajlich
8d9c463e1f [now-cli] Update references to Now CLI as Vercel CLI (#4279)
Update references to Now CLI as Vercel CLI 

Co-authored-by: Steven <steven@ceriously.com>
2020-05-06 21:15:20 -04:00
Steven
e07e8f841a [now-cli] Add special case for .vercel.app (#4281)
There are a few places the CLI needs to know about the special suffix `.now.sh` so we also need to include the upcoming `.vercel.app` suffix.
2020-05-07 01:09:21 +00:00
Steven
0b8a2c0dab [now-cli] Update README.md image (#4278)
This PR updates the name, logo, and tagline.

This will look correct in both light mode and dark mode and the text is no longer part of the image.
2020-05-06 19:44:24 -04:00
Shu Ding
9c2b7132fa add cors headers (#4280) 2020-05-07 07:40:29 +08:00
Steven
d4639a5108 [now-cli] Rename bin to support vercel and vc (#4277)
We want to make sure the bin matches the [installed package name](https://docs.npmjs.com/files/package.json#bin).

This means `npm i -g now` will remain `now` and `npm i -g vercel` will use `vercel` as the binary name.

This allows support for different versions on one machine such as `npm i -g now@17 vercel@19` for example.

In addition, we will also install a shorthand `vc` so you can do `vc env pull` for example.
2020-05-06 23:12:06 +00:00
Steven
ba25004ea8 [all] Check for VERCEL_ environment variables with getPlatformEnv() (#4274)
Added the following env vars, most are undocumented but its good to be consistent:

- `VERCEL_REGION`
- `VERCEL_DEBUG`
- `VERCEL_BUILDER_DEBUG`
- `VERCEL_TOKEN`
- `__VERCEL_SKIP_DEV_CMD`

I also updated the error code prefixes to remove `NOW_`.
There `code` isn't used anywhere, this is just to make it unique and a little shorter.
2020-05-06 22:13:12 +00:00
Steven
639a9b03d2 [now-cli][now-go][now-python] Use `<project>/.vercel/cache' dir during dev (#4273)
We renamed `.now` to `.vercel` in #4234 but still fallback to `.now` if it exists. This is because we don't want users to have to re-link all their existing projects. So we need to make sure that the Runtimes know which directory to use for caching. This PR introduces the `devCacheDir` for this purpose.
2020-05-06 19:23:39 +00:00
Nathan Rajlich
28ffdfbeef Add logging to debug failed npm publish for legacy package names in CI (#4266)
As you can see in https://github.com/zeit/now/runs/647945621,
the final step for publishing the legacy `@now` packages failed
with a 401 error from npm.

This additional logging an to attempt to debug why that is happening.
2020-05-06 18:22:09 +00:00
Steven
5e222d3c03 [tests] Fix cancel workflow pattern (#4264)
Sometimes, the "Cancel" workflow wouldn't run because it didn't match the branch name.
This PR will fix the glob to match any branch name.

- `*`: Matches zero or more characters, but does not match the `/` character.
- `**`: Matches zero or more of any character.

https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet
2020-05-06 02:14:55 +00:00
Steven
94c8464728 [now-node][now-static-build] Add test for timezone utc (#4265)
This PR adds a couple tests to ensure that the timezone offset is `0` meaning [UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time).
2020-05-06 01:14:35 +00:00
Nathan Rajlich
898478d1e1 Publish Canary
- @vercel/frameworks@0.0.14-canary.0
 - @vercel/build-utils@2.2.2-canary.7
 - @vercel/cgi@1.0.5-canary.1
 - vercel@18.0.1-canary.19
 - @vercel/client@7.1.1-canary.4
 - @vercel/go@1.0.8-canary.1
 - @vercel/next@2.5.5-canary.6
 - @vercel/node-bridge@1.2.7-canary.3
 - @vercel/node@1.5.2-canary.8
 - @vercel/python@1.1.7-canary.2
 - @vercel/routing-utils@1.8.2-canary.5
 - @vercel/ruby@1.1.1-canary.1
 - @vercel/static-build@0.16.1-canary.5
2020-05-05 17:11:39 -07:00
Nathan Rajlich
8a68211cad [all] Rename packages to vercel and add logic to publish legacy package names to npm (#4233)
https://vercel.com/blog/zeit-is-now-vercel

* Updates all org packages from `@now` to `@vercel`
* Updates Now CLI package name from `now` to `vercel`
  * Packages contains `"bin"` entries for _both_ `vercel` and `now` in the package.json
* Updates `now-client` package name to `@vercel/client` (org scoped, for authenticity)

There is also a new `publish-legacy.sh` script which ensures that all the legacy package names (i.e. `now`, `now-client`, `@now/node`, etc.) will still be published as well.

We will remove this legacy publishing logic on Jan 1, 2021.
2020-05-05 23:43:57 +00:00
Steven
2765207c93 Publish Canary
- @now/build-utils@2.2.2-canary.6
 - now@18.0.1-canary.18
 - now-client@7.1.1-canary.3
 - @now/routing-utils@1.8.2-canary.4
 - @now/static-build@0.16.1-canary.4
2020-05-05 15:06:47 -04:00
Steven
6b52cfdbc7 [now-cli][now-client] Add support for vercel config files (#4234)
This PR renames the CLI and config files to `vercel`.

https://vercel.com/blog/zeit-is-now-vercel

### Complete
- [x] Help menus and error messages should print cli name from `package.json`
- [x] `now.json` => `vercel.json`
- [x] `.nowignore` => `.vercelignore`
- [x] `~/.now` => `~/.vercel`
- [x] `<project>/.now/project.json` => `<project>/.vercel/project.json`

### TODO
I'm going to do the remaining work in a follow-up PR:
- [ ] `<project>/.now/cache` => `<project>/.vercel/cache` (Runtimes sometimes use this)
- [ ] `NOW_*` special cased environment variables
- [ ] `*.now.sh` special cased url suffix
2020-05-05 14:58:05 -04:00
Ana Trajkovska
f474fa1b8c Publish Canary
- now@18.0.1-canary.17
2020-05-05 01:48:14 +02:00
Ana Trajkovska
2cdee19804 [now-cli] Implement pagination for now env ls (#4200)
This PR implements pagination for listing environment variables for a project.
2020-05-04 23:47:05 +00:00
Steven
e9066a3ead Publish Canary
- @now/build-utils@2.2.2-canary.5
 - now@18.0.1-canary.16
 - @now/node@1.5.2-canary.7
2020-05-04 14:37:51 -04:00
Luc
1461fbe331 [tests] add "no only" and "no skip" eslint rules (#4229)
* add "no only" and "no skip" eslint rules

* ignore irrelevant eslint error

Co-authored-by: Steven <steven@ceriously.com>
2020-05-02 11:35:49 +02:00
Nathan Rajlich
099bc6dbf6 Temporarily revert @TooTallNate's now dev updates (#4231)
Needs more time for testing, and we are preparing a new stable release.

This will be un-reverted after the stable release is tagged.
2020-05-02 00:52:21 +00:00
Steven
fe0d762aca Revert "[now-routing-utils] Fix redirect // when cleanUrls and trailingSlash enabled" (#4232)
Reverts zeit/now#4227

This somehow got merged even though the tests didn't pass. Reverting until it can be merged cleanly.
2020-05-01 22:59:53 +00:00
Steven
07c9c0bb6e [now-routing-utils] Fix redirect // when cleanUrls and trailingSlash enabled (#4227)
This PR fixed a corner case when the user defined both `cleanUrls: true` and `trailingSlash: true` and then visited `/index.html` which would attempt to redirect to the invalid `//` path.
2020-05-01 20:44:39 +00:00
Steven
243018b736 [now-cli] Fix CORS headers in now dev (#4225)
This PR fixes a bug where the headers were not applied when exiting with a status code such as 204.

This is a common pattern for CORS where you want `OPTIONS` method respond with 204 status due to a preflight request.

I also updated the test suite to support the `method` property and ensured a body with empty string is asserted.
2020-05-01 14:29:36 -04:00
JJ Kasper
99436b986a Publish Canary
- @now/build-utils@2.2.2-canary.4
 - now@18.0.1-canary.15
 - now-client@7.1.1-canary.2
 - @now/next@2.5.5-canary.5
 - @now/node@1.5.2-canary.6
 - @now/static-build@0.16.1-canary.3
2020-05-01 13:23:17 -05:00
JJ Kasper
dfdef0f6fd [now-next] Update to pass dynamic page values in the query (#4196)
As discussed this updates to leverage the new named regexes and route keys output in the `routes-manifest.json` to pass the dyname page values in the query to ensure we're handling edge cases with the new custom routes support

Note: the `yarnPreferOffline` change is unrelated and was added to make debugging easier as the build can fail when using this option and the cache is invalid for some packages. 

x-ref: https://github.com/zeit/next.js/pull/12250
2020-05-01 18:08:09 +00:00
Steven
921327d878 [api] Update build script (#4224)
In PR #3514, we added a `/api` directory for functions and a `/public` directory which was created at build time.

This moves the build script to be `now-build` so we don't don't need to build everything in the repo and also no longer need to special case the git env vars.
2020-05-01 09:42:40 -04:00
Arunoda Susiripala
c48fd3e891 Update README.md 2020-05-01 12:18:51 +05:30
Nathan Rajlich
5142e32bed [now-cli] Update now dev HTML templates to use "Vercel" (#4216) 2020-05-01 00:25:01 +00:00
Steven
d360169b06 [now dev] Fix handle: miss override headers (#4217)
Fixes a bug with `now dev` where headers from the `miss` phase were overriding when they shouldn't be.

```json
{
  "version": 2,
  "routes": [
    {
      "handle": "filesystem"
    },
    {
      "src": "/([^/]+)",
      "headers": { "override": "one" },
      "dest": "/blog/$1",
      "check": true
    },
    {
      "handle": "miss"
    },
    {
      "src": "/(.*)",
      "dest": "/src/$1",
      "check": true
    },
    {
      "src": "/src/blog/([^/]+)",
      "headers": { "test": "1", "override": "two" },
      "dest": "/src/blog/$1.html",
      "check": true
    }
  ]
}
```
2020-04-30 23:51:02 +00:00
Nathan Rajlich
7b1893b9f7 [now-node] Use project env vars in startDevServer() and respect NODEJS_HELPERS env var (#4211)
Depends on #4210.
2020-04-30 15:12:46 -07:00
Steven
fb07360b71 [tests] Run now dev tests agains real deployments (#4183)
This PR makes sure that all the `now dev` tests have a corresponding deployment and each assert is also compared to the deployment.

If you want to opt-out of this behavior, for example a test that is meant for specific dev functionality, then there is an option `skipDeploy: true`.

This also fixes a bug where headers were not assigned during proxying to a dev server.
2020-04-30 17:36:32 -04:00
Nathan Rajlich
3a00aed989 [now-cli] Pass in env vars to startDevServer() in now dev (#4210)
The Runtime is expected to set up these env vars in the dev server
child processes that it spawns.
2020-04-30 14:32:29 -07:00
JJ Kasper
64944f8926 [now-cli] (Major) Upload .env files but ignore .local files (#4205)
As discussed this updates to no longer ignore all `.env` files by default and only ignores local env files which matches what we default the `.gitignore` to in our default `create-next-app` [template](20b62de8d7/packages/create-next-app/templates/default/gitignore (L26-L30))

A separate docs PR has been made here https://github.com/zeit/docs/pull/1808 which can be landed after this PR
2020-04-30 21:13:53 +00:00
Nathan Rajlich
5e4eee4db1 [now-cli] Only update build matches once per HTTP request (#4212)
Minor optimization since the "serve" function sometimes gets invoked
recursively.
2020-04-30 20:34:30 +00:00
Nathan Rajlich
a1a5e0ef0d [now-node] Make "without helpers" config option work as expected in startDevServer() (#4208) 2020-04-30 10:49:29 -07:00
Steven
91b9b7f880 Publish Canary
- now@18.0.1-canary.14
 - @now/node@1.5.2-canary.5
2020-04-30 09:20:16 -04:00
Nathan Rajlich
8e29924165 [now-node] Add TypeScript support to startDevServer() (#4185)
Using `ts-node`, with asynchronous type checking via `tsc --no-emit`.

This also removes `ncc` of `typescript` during the build in favor of
having typescript be a regular npm "dependency".
2020-04-30 09:19:30 -04:00
Luis Alvarez D
9083b558f0 Switch to Vercel in the command help for now domains (#4193)
Noticed that we still say `Zeit` while using the now cli.

The inspect command still points to zeit.co when I tested it some hours ago but that seems to be fixed already 😄
2020-04-29 18:19:16 +00:00
Ana Trajkovska
0bf8c3751b Publish Canary
- @now/cgi@1.0.5-canary.0
 - now@18.0.1-canary.13
 - now-client@7.1.1-canary.1
 - @now/next@2.5.5-canary.4
 - @now/node-bridge@1.2.7-canary.2
 - @now/node@1.5.2-canary.4
 - @now/python@1.1.7-canary.1
2020-04-29 12:52:06 +02:00
Ana Trajkovska
3ef832fdbe [now-cli] Implement pagination for now projects ls (#4186)
* Implement pagination for `now projects ls`

* Fix spacing
2020-04-29 12:50:05 +02:00
Nathan Rajlich
4bc6ebe286 [now-cli] Assert 200 status code in dev server unit tests (#4184) 2020-04-28 15:42:25 -07:00
Steven
5660474739 [tests] Remove test.only() so all tests will execute (#4180)
Fix a regression from #4160, specifically bab5794641acbf2ae3f419faf0b1d3565fbf1de3 that was preventing the CLI tests from running.
2020-04-28 19:52:38 +00:00
Nathan Rajlich
e85a62703c [now-cli] Use yarn for now dev integration tests (#4175)
This was switched to `npm` for debugging purposes in #4124, but at this
point we can switch it back to `yarn` so the tests don't take as long.

Co-authored-by: Leo Lamprecht <leo@zeit.co>
2020-04-28 21:09:49 +02:00
Steven
3a3cfd4d7b [tests] Fix remaining lint errors (#4179)
As a follow up to #4178, this fixes the final lint errors so we can run in CI.

Since lint is very quick, about 8 seconds, we can run it on the entire repo instead of only changed files.

I also disabled a couple rules that were leading to 500 warnings we would likely never change.
2020-04-28 11:37:10 -04:00
Nimish Gupta
9570d64b67 fix: removed linting errors on yarn lint (#4178) 2020-04-28 09:11:46 -04:00
Nathan Rajlich
e77ea00e9d Publish Canary
- now@18.0.1-canary.12
2020-04-27 18:22:41 -07:00
Nathan Rajlich
aebe77d222 [now-cli] Make nowCliPkg parameter non-optional (#4173)
To prevent bugs like https://github.com/zeit/now/pull/4163.
2020-04-27 18:21:05 -07:00
Nathan Rajlich
53cb2cc4c5 [now-cli] Don't print "Error starting dev server" message by default (#4172)
It's not useful information and distracts from whatever the actual error
message was from the dev server, which is what the user is actually
interested in.
2020-04-28 01:20:33 +00:00
Arunoda Susiripala
4d75ed5117 [now-cli] Allow to accept equal sign(=) as a value for meta (#4160)
Currently if the value is `=` it will throw an error from the API.
2020-04-28 00:18:51 +00:00
Nathan Rajlich
e6c84dd70b [now-cli] Add 1 minute timeout to now login integration tests (#4166) 2020-04-27 23:21:50 +00:00
Nathan Rajlich
d51f0d0f06 [now-cli] Remove "Stopping now dev server" message (#4165) 2020-04-27 15:01:23 -07:00
JJ Kasper
4cd35c48a2 Publish Canary
- now@18.0.1-canary.11
 - @now/next@2.5.5-canary.3
2020-04-27 16:48:43 -05:00
JJ Kasper
69ac4f3eb8 [now-next] Update error throwing to use NowBuildError (#4167)
Per https://github.com/zeit/now/pull/4161#discussion_r416042826 this updates to use `NowBuildError` for our errors instead of the standard `Error` instance
2020-04-27 20:40:32 +00:00
Nathan Rajlich
2c9cbe20f3 [now-cli] Fix logic to not install bundled runtimes into cache dir for now dev (#4163) 2020-04-27 12:21:29 -07:00
Ana Trajkovska
4ddd2f016c Publish Canary
- @now/build-utils@2.2.2-canary.3
 - now@18.0.1-canary.10
 - @now/next@2.5.5-canary.2
 - @now/routing-utils@1.8.2-canary.3
2020-04-27 20:56:36 +02:00
JJ Kasper
76f61cbbf0 [now-next] Provide a better error when failing to load routes-manifest (#4161)
This updates the error message shown when we fail to load the `routes-manifest` which appears to be happening most often when an incorrect output directory is configured for a Next.js application
2020-04-27 18:05:03 +00:00
YuLe
23fe8affec [now-cli] Use imported pkg instead of require("../package.json") (#4159) 2020-04-27 10:32:33 -07:00
Steven
5334caad54 [api] Use 405 method not allowed (#4148)
I was doing a diff and noticed this returns the wrong status code.

This PR changes the unknown method response to [405 Method Not Allowed](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405) status code.
2020-04-27 11:38:22 -04:00
Steven
103e4117c3 [now-routing-utils] Add support for permanent in redirects (#4150)
This adds `permanent` for `redirects` defined in Next.js RFC https://github.com/zeit/next.js/issues/9081

```json
{
  "redirects": [
    { "source": "/foo", "destination": "/api/foo", "permanent": true }
  ]
}
```
2020-04-27 11:37:15 -04:00
Ana Trajkovska
3e774d0531 Implement pagination for now dns ls <domain> (#4134)
Co-authored-by: Nathan Rajlich <n@n8.io>
2020-04-27 15:26:53 +02:00
Nathan Rajlich
5e2139f408 Publish Canary
- now@18.0.1-canary.9
2020-04-24 17:33:32 -07:00
Nathan Rajlich
55e4bffcd2 [now-cli] Add the core Runtimes as npm dependencies for now dev (#4117)
Rather than creating a `builders.tar.gz` file with the core Runtimes and
bundling that tarball with Now CLI, simply have them be regular npm
dependencies so that they are installed into Now CLI's `node_modules`
directory.

When one of the core runtimes is specified for a build, the runtime will be
required as a regular module dependency of Now CLI, and the builders cache
will never touched.

Bundled runtimes are also no longer updated, making the runtime versions
pinned to the version of Now CLI.

Logic for the builders cache directory still remains, but will now only be
used when using a Community Runtime (or development tarball URL).
2020-04-25 00:19:58 +00:00
Nathan Rajlich
de3a066934 [now-cli] Use npx to invoke ncc in build script (#4146)
The previous file path for ncc isn't always reliable during development,
depending on which directory `yarn` is invoked in inside the monorepo.

Using `npx` ensures the version specified in the now-cli `package.json`
is used even if it's installed at the root of the monorepo.
2020-04-24 20:05:25 +00:00
Steven
257b0ca5b6 Publish Canary
- now@18.0.1-canary.8
2020-04-24 14:09:01 -04:00
Nathan Rajlich
e826d48814 [now-cli] Remove yarn as a dev dependency (#4141)
Remove yarn dependency since it is no longer used.

Co-authored-by: Steven <steven@ceriously.com>
2020-04-24 12:06:00 -04:00
Nathan Rajlich
d4ecfb04bb [now-cli] Update chokidar to v3.3.1 (#4142)
For Node 14 support:

> npm WARN deprecated chokidar@2.1.8: Chokidar 2 will break on node v14+.
> Upgrade to chokidar 3 with 15x less dependencies.
2020-04-24 09:25:21 -04:00
Steven
cad10e1918 [now-cli] (Major) Change project settings inheritance (#4135)
When Now CLI 17 introduce the `.now` directory with project settings, it started assuming that the current project scope should be used for all commands. This made `now switch` do nothing unless you changed the current directory.

This PR is a _major_ semver change so that the only commands that inherit the project settings are:

- `now deploy`
- `now dev`
- `now env`

For example, `now ls` will not observe project settings and instead observe `now switch`.
2020-04-24 13:06:01 +00:00
Nathan Rajlich
1e221c48f9 [now-cli] Ensure the builders.tar.gz file is finished extracting (#4124)
`now dev` integration tests have been failing as of recently with failures to require Runtime builders from the builder cache. Upon investigation, it turns out that the `builders.tar.gz` file was not being completely extracted since the integration tests complete quickly and then kill the Now CLI process, which has not yet completed the extraction.

Fix is to ensure the tarball extraction promise is fully resolved before cleanly shutting down.

Also now applying the clean shutdown logic upon `SIGTERM` signal, which is what the integration tests send to shut down the Now CLI process.
2020-04-23 21:49:20 +00:00
Nathan Rajlich
15221bf19c [now-cli] Add the x-vercel-id and x-vercel-cache response headers to now dev (#4137)
Matches current production.
2020-04-23 12:58:25 -07:00
Paco
2513fecaf4 [examples] Update vercel.svg in Next.js example (#4128)
* Update vercel.svg in Next.js example

* Update to thinner variant
2020-04-23 12:42:08 -07:00
Nathan Rajlich
d723d985e3 [now-cli] Prevent infinite loop for Runtime "module not found" in now dev (#4126) 2020-04-23 12:41:47 -07:00
Steven
2d0a71946b Publish Canary
- now@18.0.1-canary.7
 - @now/static-build@0.16.1-canary.2
2020-04-22 17:55:24 -04:00
Steven
4b7af4d7d3 [now-cli] Fix flicker from file upload progress bar (#4125)
This PR fixes a bug where deploying a new project would flicker between two states: the upload progress bar and "Setting up Project" spinner.
2020-04-22 17:48:47 -04:00
Steven
8e3f4a1ca2 [now-static-build] Add tests for gem install of native deps (#4123)
These tests ensure we can install native dependencies with `gem install` such as:
- `rmagic`
- `ruby-vips`

Co-authored-by: Nathan Rajlich <n@n8.io>
2020-04-22 16:25:44 -04:00
455 changed files with 8233 additions and 8617 deletions

View File

@@ -92,7 +92,7 @@ Sometimes you want to test changes to a Builder against an existing project, may
2. Run `yarn build` to compile typescript and other build steps 2. Run `yarn build` to compile typescript and other build steps
3. Run `npm pack` to create a tarball file 3. Run `npm pack` to create a tarball file
4. Run `now *.tgz` to upload the tarball file and get a URL 4. Run `now *.tgz` to upload the tarball file and get a URL
5. Edit any existing `now.json` project and replace `use` with the URL 5. Edit any existing `vercel.json` project and replace `use` with the URL
6. Run `now` or `now dev` to deploy with the experimental Builder 6. Run `now` or `now dev` to deploy with the experimental Builder
## Add a New Framework ## Add a New Framework

View File

@@ -2,7 +2,7 @@ name: Cancel
on: on:
push: push:
branches: branches:
- '*' - '**'
- '!master' - '!master'
jobs: jobs:

View File

@@ -22,9 +22,6 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- run: git fetch origin master --depth=10 - run: git fetch origin master --depth=10
- run: git fetch origin ${{ github.ref }} --depth=10 - run: git fetch origin ${{ github.ref }} --depth=10
- name: Install Hugo
if: matrix.os == 'macos-latest'
run: curl -L -O https://github.com/gohugoio/hugo/releases/download/v0.56.0/hugo_0.56.0_macOS-64bit.tar.gz && tar -xzf hugo_0.56.0_macOS-64bit.tar.gz && mv ./hugo packages/now-cli/test/dev/fixtures/08-hugo/
- run: yarn install - run: yarn install
- run: yarn run build - run: yarn run build
- uses: actions/setup-node@v1 - uses: actions/setup-node@v1

View File

@@ -11,7 +11,7 @@ on:
jobs: jobs:
test: test:
name: Dev name: Dev
timeout-minutes: 30 timeout-minutes: 45
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -31,3 +31,6 @@ jobs:
with: with:
node-version: ${{ matrix.node }} node-version: ${{ matrix.node }}
- run: yarn test-integration-dev --clean false - run: yarn test-integration-dev --clean false
env:
ZEIT_TEAM_TOKEN: ${{ secrets.ZEIT_TEAM_TOKEN }}
ZEIT_REGISTRATION_URL: ${{ secrets.ZEIT_REGISTRATION_URL }}

View File

@@ -25,9 +25,10 @@ jobs:
- uses: actions/setup-node@v1 - uses: actions/setup-node@v1
- run: yarn install - run: yarn install
- run: yarn run build - run: yarn run build
- run: yarn run test-lint - run: yarn run lint
if: matrix.os == 'ubuntu-latest' && matrix.node == 12 # only run lint once
- run: yarn run test-unit --clean false - run: yarn run test-unit --clean false
- run: yarn workspace now run coverage - run: yarn workspace vercel run coverage
if: matrix.os == 'ubuntu-latest' && matrix.node == 12 # only run once if: matrix.os == 'ubuntu-latest' && matrix.node == 12 # only run coverage once
env: env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

3
.gitignore vendored
View File

@@ -6,6 +6,7 @@ npm-debug.log
yarn-error.log yarn-error.log
.nyc_output .nyc_output
coverage coverage
coverage.lcov
*.swp *.swp
*.bak *.bak
*.tgz *.tgz
@@ -19,6 +20,8 @@ packages/now-cli/test/**/node_modules
packages/now-cli/test/dev/fixtures/08-hugo/hugo packages/now-cli/test/dev/fixtures/08-hugo/hugo
packages/now-cli/test/dev/fixtures/**/dist packages/now-cli/test/dev/fixtures/**/dist
packages/now-cli/test/dev/fixtures/**/public packages/now-cli/test/dev/fixtures/**/public
packages/now-cli/test/dev/fixtures/**/.now
packages/now-cli/test/dev/fixtures/**/.vercel
packages/now-cli/test/fixtures/integration packages/now-cli/test/fixtures/integration
test/lib/deployment/failed-page.txt test/lib/deployment/failed-page.txt
.DS_Store .DS_Store

View File

@@ -3,7 +3,7 @@
The following page is a reference for how to create a Runtime using the available Runtime API. The following page is a reference for how to create a Runtime using the available Runtime API.
A Runtime is an npm module that exposes a `build` function and optionally an `analyze` function and `prepareCache` function. A Runtime is an npm module that exposes a `build` function and optionally an `analyze` function and `prepareCache` function.
Official Runtimes are published to [npmjs.com](https://npmjs.com) as a package and referenced in the `use` property of the `now.json` configuration file. Official Runtimes are published to [npmjs.com](https://npmjs.com) as a package and referenced in the `use` property of the `vercel.json` configuration file.
However, the `use` property will work with any [npm install argument](https://docs.npmjs.com/cli/install) such as a git repo url which is useful for testing your Runtime. However, the `use` property will work with any [npm install argument](https://docs.npmjs.com/cli/install) such as a git repo url which is useful for testing your Runtime.
See the [Runtimes Documentation](https://vercel.com/docs/runtimes) to view example usage. See the [Runtimes Documentation](https://vercel.com/docs/runtimes) to view example usage.
@@ -143,7 +143,7 @@ The exported functions [`analyze`](#analyze), [`build`](#build), and [`prepareCa
- `entrypoint`: Name of entrypoint file for this particular build job. Value `files[entrypoint]` is guaranteed to exist and be a valid [File](#files) reference. `entrypoint` is always a discrete file and never a glob, since globs are expanded into separate builds at deployment time. - `entrypoint`: Name of entrypoint file for this particular build job. Value `files[entrypoint]` is guaranteed to exist and be a valid [File](#files) reference. `entrypoint` is always a discrete file and never a glob, since globs are expanded into separate builds at deployment time.
- `workPath`: A writable temporary directory where you are encouraged to perform your build process. This directory will be populated with the restored cache from the previous run (if any) for [`analyze`](#analyze) and [`build`](#build). - `workPath`: A writable temporary directory where you are encouraged to perform your build process. This directory will be populated with the restored cache from the previous run (if any) for [`analyze`](#analyze) and [`build`](#build).
- `cachePath`: A writable temporary directory where you can build a cache for the next run. This is only passed to `prepareCache`. - `cachePath`: A writable temporary directory where you can build a cache for the next run. This is only passed to `prepareCache`.
- `config`: An arbitrary object passed from by the user in the [Build definition](#defining-the-build-step) in `now.json`. - `config`: An arbitrary object passed from by the user in the [Build definition](#defining-the-build-step) in `vercel.json`.
## Examples ## Examples

View File

@@ -1,11 +1,15 @@
![now](https://assets.zeit.co/image/upload/v1581518533/repositories/now-cli/v4.png) <p align="center">
<img src="https://assets.vercel.com/image/upload/v1588805858/repositories/vercel/logo.png" height="96">
<h3 align="center">Vercel</h3>
<p align="center">Develop. Preview. Ship.</p>
</p>
[![CI Status](https://badgen.net/github/checks/zeit/now?label=CI)](https://github.com/zeit/now/actions?workflow=CI) [![CI Status](https://badgen.net/github/checks/zeit/now?label=CI)](https://github.com/zeit/now/actions?workflow=CI)
[![Join the community on GitHub Discussions](https://badgen.net/badge/join%20the%20discussion/on%20github/black?icon=github)](https://github.com/zeit/now/discussions) [![Join the community on GitHub Discussions](https://badgen.net/badge/join%20the%20discussion/on%20github/black?icon=github)](https://github.com/zeit/now/discussions)
## Usage ## Usage
Get started by [Importing a Git Project](https://vercel.com/import) and use `git push` to deploy. Alternatively, you can [install Now CLI](https://vercel.com/download). Get started by [Importing a Git Project](https://vercel.com/import) and use `git push` to deploy. Alternatively, you can [install Vercel CLI](https://vercel.com/download).
## Documentation ## Documentation
@@ -17,7 +21,7 @@ For details on how to use Vercel, check out our [documentation](https://vercel.c
2. Install dependencies with `yarn install` 2. Install dependencies with `yarn install`
3. Compile the code: `yarn build` 3. Compile the code: `yarn build`
4. Link the package to the global module directory: `cd ./packages/now-cli && yarn link` 4. Link the package to the global module directory: `cd ./packages/now-cli && yarn link`
5. You can now start using `now` anywhere inside the command line 5. You can start using `vercel` anywhere inside the command line
As always, you should use `yarn test-unit` to run the tests and see if your changes have broken anything. As always, you should use `yarn test-unit` to run the tests and see if your changes have broken anything.

View File

@@ -17,9 +17,9 @@ export function withApiHandler(handler: Handler): Handler {
} }
if (req.method !== 'GET') { if (req.method !== 'GET') {
return res.status(404).json({ return res.status(405).json({
error: { error: {
code: 'not_found', code: 'method_not_allowed',
message: 'Only GET requests are supported for this endpoint.', message: 'Only GET requests are supported for this endpoint.',
}, },
}); });

View File

@@ -19,5 +19,8 @@ export default withApiHandler(async function(
req: NowRequest, req: NowRequest,
res: NowResponse res: NowResponse
) { ) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET');
res.setHeader('Access-Control-Allow-Headers', 'Authorization, Accept, Content-Type');
return res.status(200).json(frameworks); return res.status(200).json(frameworks);
}); });

View File

@@ -7,9 +7,9 @@ used an unknown or invalid dc identifier.
#### Possible Ways to Fix It #### Possible Ways to Fix It
Check your `now.json` or `--regions` flag and Check your `vercel.json` or `--regions` flag and
make sure you are using a valid string. Regions make sure you are using a valid string. Regions
and DCs have to be in *lowercase*. and DCs have to be in _lowercase_.
**Valid region identifiers**: **Valid region identifiers**:

View File

@@ -8,4 +8,4 @@ The `--token` flag was specified, but its contents are invalid.
The `--token` flag must only contain numbers (0-9) and letters from the alphabet (a-z and A-Z). This needs to be the token of the user account as which you'd like to act. The `--token` flag must only contain numbers (0-9) and letters from the alphabet (a-z and A-Z). This needs to be the token of the user account as which you'd like to act.
You can either get the token from the `./now/auth.json` file located in your user directory or [from the dashboard](https://vercel.com/account/tokens). You can either get the token from the `./vercel/auth.json` file located in your user directory or [from the dashboard](https://vercel.com/account/tokens).

View File

@@ -2,7 +2,7 @@
#### Why This Error Occurred #### Why This Error Occurred
You ran `now dev` inside a project that contains a `now.json` file with `env` or `build.env` properties that use [Now Secrets](https://vercel.com/docs/v2/build-step#environment-variables). You ran `now dev` inside a project that contains a `vercel.json` file with `env` or `build.env` properties that use [Now Secrets](https://vercel.com/docs/v2/build-step#environment-variables).
In order to use environment variables in your project locally that have values defined using the Now Secrets format (e.g. `@my-secret-value`), you will need to provide the value as an environment variable using a `.env` or `.env.build` file. In order to use environment variables in your project locally that have values defined using the Now Secrets format (e.g. `@my-secret-value`), you will need to provide the value as an environment variable using a `.env` or `.env.build` file.

View File

@@ -8,4 +8,4 @@ The `--token` flag was specified, but there's no value for it available.
In order to make it work, you need to specify a value for the `--token` flag. This needs to be the token of the user account as which you'd like to act. In order to make it work, you need to specify a value for the `--token` flag. This needs to be the token of the user account as which you'd like to act.
You can either get the token from the `./now/auth.json` file located in your user directory or [from the dashboard](https://vercel.com/account/tokens). You can either get the token from the `./vercel/auth.json` file located in your user directory or [from the dashboard](https://vercel.com/account/tokens).

View File

@@ -6,5 +6,5 @@ You're running Now CLI in a non-terminal context and there are no credentials av
#### Possible Ways to Fix It #### Possible Ways to Fix It
- Specify a value for the `--token` flag (this needs to be the token of the user account as which you'd like to act). You can either get the token from the `./now/auth.json` file located in your user directory or [from the dashboard](https://vercel.com/account/tokens). - Specify a value for the `--token` flag (this needs to be the token of the user account as which you'd like to act). You can either get the token from the `./vercel/auth.json` file located in your user directory or [from the dashboard](https://vercel.com/account/tokens).
- Ensure that both `~/now/auth.json` and `~/now/config.json` exist - Ensure that both `~/vercel/auth.json` and `~/vercel/config.json` exist

View File

@@ -0,0 +1,11 @@
# Routes Manifest Could Not Be Found
#### Why This Error Occurred
This could be caused by a failure during the build or an incorrect output directory being configured for your Next.js project.
#### Possible Ways to Fix It
Check for any build errors in the logs and ensure that the output directory setting is either not changed or is pointing to the location of the `.next` output folder (`distDir`).
If you are running `next export` you should **not** need to customize the output directory to `out` since the builder automatically detects `next export` being run and uses the output from it.

View File

@@ -7,11 +7,10 @@ setting. This isn't supported yet.
#### Possible Ways to Fix It #### Possible Ways to Fix It
Ensure your scale settings (in `now.json`, the command you're running Ensure your scale settings (in `vercel.json`, the command you're running
or from a previous deployment who's alias you're trying to overwrite) has or from a previous deployment who's alias you're trying to overwrite) has
the `min` scale setting set to `0`. You can do this by running the `min` scale setting set to `0`. You can do this by running
``` ```
now scale <deployment> 0 10 now scale <deployment> 0 10
``` ```

View File

@@ -1,10 +1,3 @@
<svg width="82" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="70" height="16" viewBox="0 0 70 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill="url(#prefix__paint0_linear)" d="M9.018 0l9.019 16H0L9.018 0z"/> <path d="M9.255.05l9.108 15.753H.148L9.255.05zM39.434 8.418c0-2.535-1.87-4.307-4.554-4.307-2.683 0-4.554 1.772-4.554 4.307 0 2.487 2.019 4.308 4.8 4.308 1.526 0 2.905-.566 3.79-1.6l-1.673-.96c-.517.517-1.28.837-2.117.837-1.23 0-2.29-.665-2.658-1.674l-.074-.172h6.966a3.76 3.76 0 00.074-.739zm-7.065-.738l.05-.148c.32-1.058 1.255-1.698 2.436-1.698 1.207 0 2.117.64 2.437 1.698l.05.148h-4.973zM65.945 8.418c0-2.535-1.871-4.307-4.554-4.307-2.683 0-4.554 1.772-4.554 4.307 0 2.487 2.018 4.308 4.8 4.308 1.526 0 2.904-.566 3.79-1.6l-1.673-.96c-.517.517-1.28.837-2.117.837-1.23 0-2.29-.665-2.659-1.674l-.073-.172h6.966a3.76 3.76 0 00.074-.739zM58.88 7.68l.05-.148c.32-1.058 1.255-1.698 2.436-1.698 1.206 0 2.117.64 2.437 1.698l.05.148H58.88zM54.13 7.015l1.673-.96c-.788-1.23-2.19-1.92-3.89-1.92-2.682 0-4.553 1.773-4.553 4.308 0 2.536 1.87 4.308 4.554 4.308 1.698 0 3.101-.69 3.89-1.92l-1.675-.96c-.443.738-1.23 1.157-2.215 1.157-1.55 0-2.585-1.034-2.585-2.585 0-1.55 1.034-2.585 2.585-2.585.96 0 1.772.419 2.215 1.157zM69.637 1.428h-1.97v11.077h1.97V1.428zM31.779 1.428h-2.265L25.182 8.91l-4.333-7.483H18.56l6.622 11.421 6.597-11.421zM45.71 6.4c.222 0 .444.025.665.074V4.382c-1.673.049-3.249.984-3.249 2.141V4.382h-1.97v8.123h1.97v-3.52c0-1.527 1.059-2.585 2.585-2.585z" fill="#000"/>
<path fill="#333" fill-rule="evenodd" d="M51.634 12.028h-6.492V2.052h6.492v1.256H46.61v3.007h4.37V7.57h-4.37v3.202h5.024v1.255zm-14.063 0h-7.235v-1.096l5.342-7.624h-5.253V2.052h7.058v1.097l-5.342 7.623h5.43v1.256zm21.88 0h6.333v-1.256h-2.423V3.308h2.423V2.052h-6.332v1.256h2.441v7.465h-2.441v1.255zm18.22 0h-1.468v-8.72h-3.36V2.052h8.225v1.256H77.67v8.72z" clip-rule="evenodd"/>
<defs>
<linearGradient id="prefix__paint0_linear" x1="28.022" x2="16.189" y1="22.991" y2="8.569" gradientUnits="userSpaceOnUse">
<stop stop-color="#fff"/>
<stop offset="1"/>
</linearGradient>
</defs>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 794 B

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,14 +1,13 @@
{ {
"npmClient": "yarn", "npmClient": "yarn",
"useWorkspaces": true, "useWorkspaces": true,
"packages": ["packages/*"], "packages": ["packages/*"],
"command": { "command": {
"publish": { "publish": {
"npmClient": "npm", "npmClient": "npm",
"allowBranch": ["master", "canary"], "allowBranch": ["master"],
"registry": "https://registry.npmjs.org/" "registry": "https://registry.npmjs.org/"
} }
}, },
"version": "independent" "version": "independent"
} }

View File

@@ -1,5 +1,5 @@
{ {
"name": "now-builders", "name": "vercel-monorepo",
"version": "0.0.0", "version": "0.0.0",
"private": true, "private": true,
"license": "MIT", "license": "MIT",
@@ -22,10 +22,12 @@
"buffer-replace": "1.0.0", "buffer-replace": "1.0.0",
"eslint": "6.2.2", "eslint": "6.2.2",
"eslint-config-prettier": "6.1.0", "eslint-config-prettier": "6.1.0",
"eslint-plugin-jest": "23.8.2",
"husky": "3.0.4", "husky": "3.0.4",
"json5": "2.1.1", "json5": "2.1.1",
"lint-staged": "9.2.5", "lint-staged": "9.2.5",
"node-fetch": "2.6.0", "node-fetch": "2.6.0",
"npm-package-arg": "6.1.0",
"prettier": "1.18.2" "prettier": "1.18.2"
}, },
"scripts": { "scripts": {
@@ -36,7 +38,7 @@
"publish-from-github": "./utils/publish.sh", "publish-from-github": "./utils/publish.sh",
"changelog": "node utils/changelog.js", "changelog": "node utils/changelog.js",
"build": "node utils/run.js build all", "build": "node utils/run.js build all",
"test-lint": "node utils/run.js test-lint", "now-build": "mkdir -p public && echo '<a href=\"https://vercel.com/import\">Import</a>' > public/output.html",
"test-unit": "node utils/run.js test-unit", "test-unit": "node utils/run.js test-unit",
"test-integration-cli": "node utils/run.js test-integration-cli", "test-integration-cli": "node utils/run.js test-integration-cli",
"test-integration-once": "node utils/run.js test-integration-once", "test-integration-once": "node utils/run.js test-integration-once",
@@ -71,6 +73,9 @@
"sourceType": "module", "sourceType": "module",
"modules": true "modules": true
}, },
"plugins": [
"jest"
],
"extends": [ "extends": [
"eslint:recommended", "eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/eslint-recommended",
@@ -89,8 +94,12 @@
"@typescript-eslint/camelcase": 0, "@typescript-eslint/camelcase": 0,
"@typescript-eslint/explicit-function-return-type": 0, "@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/no-empty-function": 0, "@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-non-null-assertion": 0,
"@typescript-eslint/no-unused-vars": 2, "@typescript-eslint/no-unused-vars": 2,
"@typescript-eslint/no-use-before-define": 0 "@typescript-eslint/no-use-before-define": 0,
"jest/no-disabled-tests": 2,
"jest/no-focused-tests": 2
}, },
"overrides": [ "overrides": [
{ {

View File

@@ -1,6 +1,6 @@
{ {
"name": "@now/frameworks", "name": "@vercel/frameworks",
"version": "0.0.13", "version": "0.0.14",
"main": "frameworks.json", "main": "frameworks.json",
"license": "UNLICENSED" "license": "UNLICENSED"
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@now/build-utils", "name": "@vercel/build-utils",
"version": "2.2.2-canary.2", "version": "2.3.0",
"license": "MIT", "license": "MIT",
"main": "./dist/index.js", "main": "./dist/index.js",
"types": "./dist/index.d.js", "types": "./dist/index.d.js",
@@ -12,8 +12,8 @@
}, },
"scripts": { "scripts": {
"build": "./build.sh", "build": "./build.sh",
"test-unit": "jest --env node --verbose --runInBand test/unit.*test.*", "test-unit": "jest --env node --verbose --runInBand --bail test/unit.*test.*",
"test-integration-once": "jest --env node --verbose --runInBand test/integration.test.js", "test-integration-once": "jest --env node --verbose --runInBand --bail test/integration.test.js",
"prepublishOnly": "./build.sh" "prepublishOnly": "./build.sh"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -1,5 +1,7 @@
import { getPlatformEnv } from './';
export default function debug(message: string, ...additional: any[]) { export default function debug(message: string, ...additional: any[]) {
if (process.env.NOW_BUILDER_DEBUG) { if (getPlatformEnv('BUILDER_DEBUG')) {
console.log(message, ...additional); console.log(message, ...additional);
} }
} }

View File

@@ -1,8 +1,9 @@
import minimatch from 'minimatch'; import minimatch from 'minimatch';
import { valid as validSemver } from 'semver'; import { valid as validSemver } from 'semver';
import { parse as parsePath, extname } from 'path'; import { parse as parsePath, extname } from 'path';
import { Route, Source } from '@now/routing-utils'; import { Route, Source } from '@vercel/routing-utils';
import { PackageJson, Builder, Config, BuilderFunctions } from './types'; import { PackageJson, Builder, Config, BuilderFunctions } from './types';
import { isOfficialRuntime } from './';
interface ErrorResponse { interface ErrorResponse {
code: string; code: string;
@@ -55,7 +56,7 @@ export function detectApiDirectory(builders: Builder[]): string | null {
function getPublicBuilder(builders: Builder[]): Builder | null { function getPublicBuilder(builders: Builder[]): Builder | null {
const builder = builders.find( const builder = builders.find(
builder => builder =>
builder.use === '@now/static' && isOfficialRuntime('static', builder.use) &&
/^.*\/\*\*\/\*$/.test(builder.src) && /^.*\/\*\*\/\*$/.test(builder.src) &&
builder.config && builder.config &&
builder.config.zeroConfig === true builder.config.zeroConfig === true
@@ -194,7 +195,8 @@ export async function detectBuilders(
!fallbackEntrypoint && !fallbackEntrypoint &&
buildCommand && buildCommand &&
!fileName.includes('/') && !fileName.includes('/') &&
fileName !== 'now.json' fileName !== 'now.json' &&
fileName !== 'vercel.json'
) { ) {
fallbackEntrypoint = fileName; fallbackEntrypoint = fileName;
} }
@@ -593,7 +595,7 @@ function checkUnusedFunctions(
} }
// Next.js can use functions only for `src/pages` or `pages` // Next.js can use functions only for `src/pages` or `pages`
if (frontendBuilder && frontendBuilder.use.startsWith('@now/next')) { if (frontendBuilder && isOfficialRuntime('next', frontendBuilder.use)) {
for (const fnKey of unusedFunctions.values()) { for (const fnKey of unusedFunctions.values()) {
if (fnKey.startsWith('pages/') || fnKey.startsWith('src/pages')) { if (fnKey.startsWith('pages/') || fnKey.startsWith('src/pages')) {
unusedFunctions.delete(fnKey); unusedFunctions.delete(fnKey);
@@ -958,7 +960,7 @@ function getRouteResult(
outputDirectory && outputDirectory &&
frontendBuilder && frontendBuilder &&
!options.featHandleMiss && !options.featHandleMiss &&
frontendBuilder.use === '@now/static' isOfficialRuntime('static', frontendBuilder.use)
) { ) {
defaultRoutes.push({ defaultRoutes.push({
src: '/(.*)', src: '/(.*)',

View File

@@ -1,4 +1,4 @@
import { Framework, FrameworkDetectionItem } from '@now/frameworks'; import { Framework, FrameworkDetectionItem } from '@vercel/frameworks';
import { DetectorFilesystem } from './detectors/filesystem'; import { DetectorFilesystem } from './detectors/filesystem';
export interface DetectFrameworkOptions { export interface DetectFrameworkOptions {

View File

@@ -23,7 +23,7 @@ interface Props {
message: string; message: string;
/** /**
* A unique error code for this particular error. * A unique error code for this particular error.
* Should start with the builder name such as `NOW_NODE_`. * Should start with the builder name such as `NODE_`.
*/ */
code: string; code: string;
/** /**

View File

@@ -54,7 +54,7 @@ export async function getSupportedNodeVersion(
engineRange + engineRange +
'".'; '".';
throw new NowBuildError({ throw new NowBuildError({
code: 'NOW_BUILD_UTILS_NODE_VERSION_INVALID', code: 'BUILD_UTILS_NODE_VERSION_INVALID',
link: link:
'https://vercel.com/docs/runtimes#official-runtimes/node-js/node-js-version', 'https://vercel.com/docs/runtimes#official-runtimes/node-js/node-js-version',
message: intro + '\n' + pleaseSet, message: intro + '\n' + pleaseSet,
@@ -72,7 +72,7 @@ export async function getSupportedNodeVersion(
engineRange + engineRange +
'".'; '".';
throw new NowBuildError({ throw new NowBuildError({
code: 'NOW_BUILD_UTILS_NODE_VERSION_DISCONTINUED', code: 'BUILD_UTILS_NODE_VERSION_DISCONTINUED',
link: link:
'https://vercel.com/docs/runtimes#official-runtimes/node-js/node-js-version', 'https://vercel.com/docs/runtimes#official-runtimes/node-js/node-js-version',
message: intro + '\n' + pleaseSet + '\n' + upstreamProvider, message: intro + '\n' + pleaseSet + '\n' + upstreamProvider,

View File

@@ -39,7 +39,7 @@ export function spawnAsync(
: 'Command'; : 'Command';
reject( reject(
new NowBuildError({ new NowBuildError({
code: `NOW_BUILD_UTILS_SPAWN_${code || signal}`, code: `BUILD_UTILS_SPAWN_${code || signal}`,
message: message:
opts.stdio === 'inherit' opts.stdio === 'inherit'
? `${cmd} exited with ${code || signal}` ? `${cmd} exited with ${code || signal}`
@@ -81,7 +81,7 @@ export function execAsync(
return reject( return reject(
new NowBuildError({ new NowBuildError({
code: `NOW_BUILD_UTILS_EXEC_${code || signal}`, code: `BUILD_UTILS_EXEC_${code || signal}`,
message: `${cmd} exited with ${code || signal}`, message: `${cmd} exited with ${code || signal}`,
}) })
); );

View File

@@ -80,3 +80,29 @@ export { readConfigFile } from './fs/read-config-file';
export * from './schemas'; export * from './schemas';
export * from './types'; export * from './types';
export * from './errors'; export * from './errors';
/**
* Helper function to support both `@vercel` and legacy `@now` official Runtimes.
*/
export const isOfficialRuntime = (desired: string, name?: string): boolean => {
if (typeof name !== 'string') {
return false;
}
return (
name === `@vercel/${desired}` ||
name === `@now/${desired}` ||
name.startsWith(`@vercel/${desired}@`) ||
name.startsWith(`@now/${desired}@`)
);
};
export const isStaticRuntime = (name?: string): boolean => {
return isOfficialRuntime('static', name);
};
/**
* Helper function to support both `VERCEL_` and legacy `NOW_` env vars.
*/
export const getPlatformEnv = (name: string): string | undefined => {
return process.env[`VERCEL_${name}`] || process.env[`NOW_${name}`];
};

View File

@@ -49,6 +49,7 @@ export interface Config {
export interface Meta { export interface Meta {
isDev?: boolean; isDev?: boolean;
devCacheDir?: string;
skipDownload?: boolean; skipDownload?: boolean;
requestPath?: string | null; requestPath?: string | null;
filesChanged?: string[]; filesChanged?: string[];
@@ -81,7 +82,7 @@ export interface AnalyzeOptions {
/** /**
* An arbitrary object passed by the user in the build definition defined * An arbitrary object passed by the user in the build definition defined
* in `now.json`. * in `vercel.json`.
*/ */
config: Config; config: Config;
} }
@@ -108,7 +109,7 @@ export interface BuildOptions {
/** /**
* An arbitrary object passed by the user in the build definition defined * An arbitrary object passed by the user in the build definition defined
* in `now.json`. * in `vercel.json`.
*/ */
config: Config; config: Config;
@@ -148,7 +149,7 @@ export interface PrepareCacheOptions {
/** /**
* An arbitrary object passed by the user in the build definition defined * An arbitrary object passed by the user in the build definition defined
* in `now.json`. * in `vercel.json`.
*/ */
config: Config; config: Config;
} }
@@ -182,27 +183,11 @@ export interface ShouldServeOptions {
/** /**
* An arbitrary object passed by the user in the build definition defined * An arbitrary object passed by the user in the build definition defined
* in `now.json`. * in `vercel.json`.
*/ */
config: Config; config: Config;
} }
export interface StartDevServerOptions {
/**
* Name of entrypoint file for this particular build job. Value
* `files[entrypoint]` is guaranteed to exist and be a valid File reference.
* `entrypoint` is always a discrete file and never a glob, since globs are
* expanded into separate builds at deployment time.
*/
entrypoint: string;
/**
* A writable temporary directory where you are encouraged to perform your
* build process. This directory will be populated with the restored cache.
*/
workPath: string;
}
export interface StartDevServerSuccess { export interface StartDevServerSuccess {
/** /**
* Port number where the dev server can be connected to, assumed to be running * Port number where the dev server can be connected to, assumed to be running
@@ -228,7 +213,7 @@ export type StartDevServerResult = StartDevServerSuccess | null;
* Source: https://gist.github.com/iainreid820/5c1cc527fe6b5b7dba41fec7fe54bf6e * Source: https://gist.github.com/iainreid820/5c1cc527fe6b5b7dba41fec7fe54bf6e
*/ */
// eslint-disable-next-line @typescript-eslint/no-namespace // eslint-disable-next-line @typescript-eslint/no-namespace
export namespace PackageJson { namespace PackageJson {
/** /**
* An author or contributor * An author or contributor
*/ */
@@ -351,24 +336,3 @@ export interface BuilderFunctions {
excludeFiles?: string; excludeFiles?: string;
}; };
} }
export interface NowRewrite {
source: string;
destination: string;
}
export interface NowRedirect {
source: string;
destination: string;
statusCode?: number;
}
export interface NowHeader {
source: string;
headers: NowHeaderKeyValue[];
}
export interface NowHeaderKeyValue {
key: string;
value: string;
}

View File

@@ -1,6 +1,6 @@
{ {
"version": 2, "version": 2,
"builds": [{ "src": "api/index.js", "use": "@now/node" }], "builds": [{ "src": "api/index.js", "use": "@vercel/node" }],
"probes": [ "probes": [
{ {
"path": "/api/index.js", "path": "/api/index.js",

View File

@@ -1,9 +1,9 @@
{ {
"version": 2, "version": 2,
"builds": [ "builds": [
{ "src": "with-npm/index.js", "use": "@now/node" }, { "src": "with-npm/index.js", "use": "@vercel/node" },
{ "src": "with-yarn/index.js", "use": "@now/node" }, { "src": "with-yarn/index.js", "use": "@vercel/node" },
{ "src": "with-yarn-and-npm/index.js", "use": "@now/node" } { "src": "with-yarn-and-npm/index.js", "use": "@vercel/node" }
], ],
"probes": [ "probes": [
{ "path": "/with-npm", "mustContain": "npm:RANDOMNESS_PLACEHOLDER" }, { "path": "/with-npm", "mustContain": "npm:RANDOMNESS_PLACEHOLDER" },

View File

@@ -3,7 +3,7 @@
"builds": [ "builds": [
{ {
"src": "index.js", "src": "index.js",
"use": "@now/node" "use": "@vercel/node"
} }
], ],
"probes": [{ "path": "/", "mustContain": "found:RANDOMNESS_PLACEHOLDER" }] "probes": [{ "path": "/", "mustContain": "found:RANDOMNESS_PLACEHOLDER" }]

View File

@@ -1,6 +1,6 @@
{ {
"version": 2, "version": 2,
"builds": [{ "src": "package.json", "use": "@now/static-build" }], "builds": [{ "src": "package.json", "use": "@vercel/static-build" }],
"build": { "env": { "NODE_ENV": "production" } }, "build": { "env": { "NODE_ENV": "production" } },
"probes": [{ "path": "/", "mustContain": "node-env:RANDOMNESS_PLACEHOLDER" }] "probes": [{ "path": "/", "mustContain": "node-env:RANDOMNESS_PLACEHOLDER" }]
} }

View File

@@ -1,6 +1,6 @@
{ {
"version": 2, "version": 2,
"builds": [{ "src": "package.json", "use": "@now/static-build" }], "builds": [{ "src": "package.json", "use": "@vercel/static-build" }],
"build": { "env": { "NODE_ENV": "custom-value:RANDOMNESS_PLACEHOLDER" } }, "build": { "env": { "NODE_ENV": "custom-value:RANDOMNESS_PLACEHOLDER" } },
"probes": [ "probes": [
{ "path": "/", "mustContain": "custom-value:RANDOMNESS_PLACEHOLDER" } { "path": "/", "mustContain": "custom-value:RANDOMNESS_PLACEHOLDER" }

View File

@@ -2,8 +2,8 @@
"version": 2, "version": 2,
"build": { "env": { "NPM_ONLY_PRODUCTION": "1" } }, "build": { "env": { "NPM_ONLY_PRODUCTION": "1" } },
"builds": [ "builds": [
{ "src": "npm/package.json", "use": "@now/static-build" }, { "src": "npm/package.json", "use": "@vercel/static-build" },
{ "src": "yarn/package.json", "use": "@now/static-build" } { "src": "yarn/package.json", "use": "@vercel/static-build" }
], ],
"probes": [ "probes": [
{ "path": "/npm", "mustContain": "npm-prod:RANDOMNESS_PLACEHOLDER" }, { "path": "/npm", "mustContain": "npm-prod:RANDOMNESS_PLACEHOLDER" },

View File

@@ -27,7 +27,7 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
} }
// eslint-disable-next-line no-loop-func // eslint-disable-next-line no-loop-func
it(`should build ${fixture}`, async () => { it(`Should build "${fixture}"`, async () => {
await expect( await expect(
testDeployment( testDeployment(
{ builderUrl, buildUtilsUrl }, { builderUrl, buildUtilsUrl },
@@ -53,7 +53,7 @@ for (const builder of buildersToTestWith) {
// don't run all foreign fixtures, just some // don't run all foreign fixtures, just some
if (['01-cowsay', '01-cache-headers', '03-env-vars'].includes(fixture)) { if (['01-cowsay', '01-cache-headers', '03-env-vars'].includes(fixture)) {
// eslint-disable-next-line no-loop-func // eslint-disable-next-line no-loop-func
it(`should build ${builder}/${fixture}`, async () => { it(`Should build "${builder}/${fixture}"`, async () => {
await expect( await expect(
testDeployment( testDeployment(
{ builderUrl, buildUtilsUrl }, { builderUrl, buildUtilsUrl },
@@ -113,15 +113,13 @@ it('Test `detectBuilders` and `detectRoutes`', async () => {
const { builders, defaultRoutes } = await detectBuilders(files, pkg); const { builders, defaultRoutes } = await detectBuilders(files, pkg);
const nowConfig = { builds: builders, routes: defaultRoutes, probes }; const nowConfig = { builds: builders, routes: defaultRoutes, probes };
await fs.writeFile( await fs.writeFile(
path.join(fixture, 'now.json'), path.join(fixture, 'now.json'),
JSON.stringify(nowConfig, null, 2) JSON.stringify(nowConfig, null, 2)
); );
const deployment = await testDeployment( const deployment = await testDeployment({ builderUrl }, fixture);
{ builderUrl, buildUtilsUrl },
fixture
);
expect(deployment).toBeDefined(); expect(deployment).toBeDefined();
}); });
@@ -199,9 +197,6 @@ it('Test `detectBuilders` with `index` files', async () => {
JSON.stringify(nowConfig, null, 2) JSON.stringify(nowConfig, null, 2)
); );
const deployment = await testDeployment( const deployment = await testDeployment({ builderUrl }, fixture);
{ builderUrl, buildUtilsUrl },
fixture
);
expect(deployment).toBeDefined(); expect(deployment).toBeDefined();
}); });

View File

@@ -1,10 +1,10 @@
import { Source, Route, Handler } from '@now/routing-utils'; import { Source, Route, Handler } from '@vercel/routing-utils';
import { detectBuilders } from '../src';
import { import {
detectBuilders,
detectOutputDirectory, detectOutputDirectory,
detectApiDirectory, detectApiDirectory,
detectApiExtensions, detectApiExtensions,
} from '../'; } from '../src';
describe('Test `detectBuilders`', () => { describe('Test `detectBuilders`', () => {
it('should never select now.json src', async () => { it('should never select now.json src', async () => {

View File

@@ -1,6 +1,6 @@
import path from 'path'; import path from 'path';
import { readFileSync } from 'fs-extra'; import { readFileSync } from 'fs-extra';
import { Framework } from '@now/frameworks'; import { Framework } from '@vercel/frameworks';
import { detectFramework, DetectorFilesystem } from '../src'; import { detectFramework, DetectorFilesystem } from '../src';
const frameworkList = JSON.parse( const frameworkList = JSON.parse(

View File

@@ -0,0 +1,40 @@
import assert from 'assert';
import { isOfficialRuntime, isStaticRuntime } from '../src';
describe('Test `isOfficialRuntime()`', () => {
it('should be correct', () => {
assert.equal(true, isOfficialRuntime('static', '@vercel/static'));
assert.equal(true, isOfficialRuntime('static', '@now/static'));
assert.equal(false, isOfficialRuntime('static', '@vercel/static-build'));
assert.equal(false, isOfficialRuntime('static', '@now/static-build'));
assert.equal(true, isOfficialRuntime('node', '@vercel/node'));
assert.equal(true, isOfficialRuntime('node', '@now/node'));
assert.equal(true, isOfficialRuntime('node', '@vercel/node@1.0.0'));
assert.equal(true, isOfficialRuntime('node', '@now/node@1.0.0'));
assert.equal(false, isOfficialRuntime('node', '@my-fork/node'));
assert.equal(false, isOfficialRuntime('node', '@now/node-server'));
assert.equal(
true,
isOfficialRuntime('static-build', '@vercel/static-build')
);
assert.equal(true, isOfficialRuntime('static-build', '@now/static-build'));
assert.equal(
true,
isOfficialRuntime('static-build', '@vercel/static-build@1.0.0')
);
assert.equal(false, isOfficialRuntime('static-build', '@vercel/static'));
assert.equal(false, isOfficialRuntime('static-build', '@now/static'));
});
});
describe('Test `isStaticRuntime()`', () => {
it('should be correct', () => {
assert.equal(true, isStaticRuntime('@vercel/static'));
assert.equal(true, isStaticRuntime('@now/static'));
assert.equal(false, isStaticRuntime('@vercel/static-build'));
assert.equal(false, isStaticRuntime('@now/static-build'));
assert.equal(false, isStaticRuntime('@now/node'));
});
});

View File

@@ -134,21 +134,21 @@ it('should throw for discontinued versions', async () => {
}); });
it('should support require by path for legacy builders', () => { it('should support require by path for legacy builders', () => {
const index = require('@now/build-utils'); const index = require('@vercel/build-utils');
const download2 = require('@now/build-utils/fs/download.js'); const download2 = require('@vercel/build-utils/fs/download.js');
const getWriteableDirectory2 = require('@now/build-utils/fs/get-writable-directory.js'); const getWriteableDirectory2 = require('@vercel/build-utils/fs/get-writable-directory.js');
const glob2 = require('@now/build-utils/fs/glob.js'); const glob2 = require('@vercel/build-utils/fs/glob.js');
const rename2 = require('@now/build-utils/fs/rename.js'); const rename2 = require('@vercel/build-utils/fs/rename.js');
const { const {
runNpmInstall: runNpmInstall2, runNpmInstall: runNpmInstall2,
} = require('@now/build-utils/fs/run-user-scripts.js'); } = require('@vercel/build-utils/fs/run-user-scripts.js');
const streamToBuffer2 = require('@now/build-utils/fs/stream-to-buffer.js'); const streamToBuffer2 = require('@vercel/build-utils/fs/stream-to-buffer.js');
const FileBlob2 = require('@now/build-utils/file-blob.js'); const FileBlob2 = require('@vercel/build-utils/file-blob.js');
const FileFsRef2 = require('@now/build-utils/file-fs-ref.js'); const FileFsRef2 = require('@vercel/build-utils/file-fs-ref.js');
const FileRef2 = require('@now/build-utils/file-ref.js'); const FileRef2 = require('@vercel/build-utils/file-ref.js');
const { Lambda: Lambda2 } = require('@now/build-utils/lambda.js'); const { Lambda: Lambda2 } = require('@vercel/build-utils/lambda.js');
expect(download2).toBe(index.download); expect(download2).toBe(index.download);
expect(getWriteableDirectory2).toBe(index.getWriteableDirectory); expect(getWriteableDirectory2).toBe(index.getWriteableDirectory);

View File

@@ -3,7 +3,6 @@ const { mkdirp, copyFile } = require('fs-extra');
const { const {
glob, glob,
debug,
download, download,
shouldServe, shouldServe,
createLambda, createLambda,
@@ -14,7 +13,7 @@ exports.analyze = ({ files, entrypoint }) => files[entrypoint].digest;
exports.version = 3; exports.version = 3;
exports.build = async ({ workPath, files, entrypoint, meta, config }) => { exports.build = async ({ workPath, files, entrypoint, meta }) => {
const outDir = await getWritableDirectory(); const outDir = await getWritableDirectory();
await download(files, workPath, meta); await download(files, workPath, meta);

View File

@@ -1,6 +1,6 @@
{ {
"name": "@now/cgi", "name": "@vercel/cgi",
"version": "1.0.4", "version": "1.0.5",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -1,22 +1,27 @@
![now](https://assets.zeit.co/image/upload/v1581518533/repositories/now-cli/v4.png) <p align="center">
<img src="https://assets.vercel.com/image/upload/v1588805858/repositories/vercel/logo.png" height="96">
<h3 align="center">Vercel</h3>
<p align="center">Develop. Preview. Ship.</p>
</p>
[![Join the community on GitHub Discussions](https://badgen.net/badge/join%20the%20discussion/on%20github/black?icon=github)](https://github.com/zeit/now/discussions) [![Join the community on GitHub Discussions](https://badgen.net/badge/join%20the%20discussion/on%20github/black?icon=github)](https://github.com/zeit/now/discussions)
## Usages ## Usages
To install the latest version of Now CLI, visit [vercel.com/download](https://vercel.com/download) or run this command: To install the latest version of Vercel CLI, visit [vercel.com/download](https://vercel.com/download) or run this command:
```sh ```sh
npm i -g now npm i -g vercel
``` ```
To quickly start a new project, run the following commands: To quickly start a new project, run the following commands:
``` ```
now init # Pick an example project vercel init # Pick an example project
cd <PROJECT> # Change directory to the new project cd <PROJECT> # Change directory to the new project
now # Deploy to the cloud vercel # Deploy to the cloud
``` ```
## Documentation ## Documentation
For details on how to use Now CLI, check out our [documentation](https://vercel.com/docs). For details on how to use Vercel CLI, check out our [documentation](https://vercel.com/docs).

View File

@@ -1,6 +1,6 @@
{ {
"name": "now", "name": "vercel",
"version": "18.0.1-canary.6", "version": "19.0.0",
"preferGlobal": true, "preferGlobal": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"description": "The command-line interface for Now", "description": "The command-line interface for Now",
@@ -19,8 +19,7 @@
"prepublishOnly": "yarn build", "prepublishOnly": "yarn build",
"coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov", "coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov",
"build": "ts-node ./scripts/build.ts", "build": "ts-node ./scripts/build.ts",
"build-dev": "ts-node ./scripts/build.ts --dev", "build-dev": "ts-node ./scripts/build.ts --dev"
"test-lint": "eslint . --ext .ts,.js --ignore-path ../../.eslintignore"
}, },
"nyc": { "nyc": {
"include": [ "include": [
@@ -42,7 +41,8 @@
"all": true "all": true
}, },
"bin": { "bin": {
"now": "./dist/index.js" "vc": "./dist/index.js",
"vercel": "./dist/index.js"
}, },
"files": [ "files": [
"dist", "dist",
@@ -64,7 +64,6 @@
"devDependencies": { "devDependencies": {
"@sentry/node": "5.5.0", "@sentry/node": "5.5.0",
"@sindresorhus/slugify": "0.11.0", "@sindresorhus/slugify": "0.11.0",
"@tootallnate/once": "1.1.2",
"@types/ansi-escapes": "3.0.0", "@types/ansi-escapes": "3.0.0",
"@types/ansi-regex": "4.0.0", "@types/ansi-regex": "4.0.0",
"@types/async-retry": "1.2.1", "@types/async-retry": "1.2.1",
@@ -108,7 +107,7 @@
"ava": "2.2.0", "ava": "2.2.0",
"bytes": "3.0.0", "bytes": "3.0.0",
"chalk": "2.4.2", "chalk": "2.4.2",
"chokidar": "2.1.6", "chokidar": "3.3.1",
"clipboardy": "2.1.0", "clipboardy": "2.1.0",
"codecov": "3.6.5", "codecov": "3.6.5",
"cpy": "7.2.0", "cpy": "7.2.0",

View File

@@ -39,14 +39,11 @@ async function createBuildersTarball() {
} }
} }
await execa( const yarn = join(dirRoot, '../../node_modules/yarn/bin/yarn.js');
'npm', await execa(process.execPath, [yarn, 'add', '--no-lockfile', ...builders], {
['install', '--save-exact', '--no-package-lock', ...builders], cwd: buildersDir,
{ stdio: 'inherit',
cwd: buildersDir, });
stdio: 'inherit',
}
);
const packer = tar.pack(buildersDir); const packer = tar.pack(buildersDir);
await pipe( await pipe(
@@ -104,13 +101,12 @@ async function main() {
// Do the initial `ncc` build // Do the initial `ncc` build
console.log(); console.log();
const src = join(dirRoot, 'src'); const src = join(dirRoot, 'src');
const ncc = join(dirRoot, 'node_modules/@zeit/ncc/dist/ncc/cli.js'); const args = ['@zeit/ncc', 'build', '--source-map'];
const args = [ncc, 'build', '--source-map'];
if (!isDev) { if (!isDev) {
args.push('--minify'); args.push('--minify');
} }
args.push(src); args.push(src);
await execa(process.execPath, args, { stdio: 'inherit' }); await execa('npx', args, { stdio: 'inherit' });
// `ncc` has some issues with `@zeit/fun`'s runtime files: // `ncc` has some issues with `@zeit/fun`'s runtime files:
// - Executable bits on the `bootstrap` files appear to be lost: // - Executable bits on the `bootstrap` files appear to be lost:

View File

@@ -1,15 +1,4 @@
#!/usr/bin/env node #!/usr/bin/env node
const fs = require('fs');
const { promisify } = require('util');
const { join, delimiter } = require('path');
const { homedir } = require('os');
const stat = promisify(fs.stat);
const unlink = promisify(fs.unlink);
function cmd(command) {
return `\`${command}\``;
}
function error(command) { function error(command) {
console.error('> Error!', command); console.error('> Error!', command);
@@ -36,51 +25,6 @@ function isGlobal() {
: Boolean(process.env.npm_config_global); : Boolean(process.env.npm_config_global);
} }
// Logic is from Now Desktop
// See: https://git.io/fj4jD
function getNowPath() {
if (process.platform === 'win32') {
const { LOCALAPPDATA, USERPROFILE, HOMEPATH } = process.env;
const home = homedir() || USERPROFILE || HOMEPATH;
let path;
if (LOCALAPPDATA) {
path = join(LOCALAPPDATA, 'now-cli', 'now.exe');
} else if (home) {
path = join(home, 'AppData', 'Local', 'now-cli', 'now.exe');
} else {
path = '';
}
return fs.existsSync(path) ? path : null;
}
const pathEnv = (process.env.PATH || '').split(delimiter);
const paths = [
join(process.env.HOME || '/', 'bin'),
'/usr/local/bin',
'/usr/bin',
];
for (const basePath of paths) {
if (!pathEnv.includes(basePath)) {
continue;
}
const nowPath = join(basePath, 'now');
if (fs.existsSync(nowPath)) {
return nowPath;
}
}
return null;
}
async function isBinary(nowPath) {
const stats = await stat(nowPath);
return !stats.isDirectory();
}
function validateNodeVersion() { function validateNodeVersion() {
let semver = '>= 0'; let semver = '>= 0';
let major = '1'; let major = '1';
@@ -113,46 +57,6 @@ async function main() {
); );
process.exit(1); process.exit(1);
} }
const nowPath = getNowPath();
if (nowPath === null) {
debug(`No now binary found`);
return;
}
debug(`Located now binary at ${nowPath}`);
try {
if ((await isBinary(nowPath)) === false) {
debug(
'Found file or directory named now but will not delete, ' +
'as it seems unrelated to Now CLI'
);
return;
}
await unlink(nowPath);
debug(`Removed ${nowPath}`);
} catch (err) {
if (process.platform !== 'win32') {
error(
`Could not remove your previous Now CLI installation.\n` +
`Please use this command to remove it: ${cmd(
`sudo rm ${nowPath}`
)}.\n` +
`Then try to install it again.`
);
} else {
error(
`Could not remove your previous Now CLI installation.\n` +
`Please remove ${cmd(nowPath)} manually and try to install it again.`
);
}
process.exit(1);
}
} }
process.on('unhandledRejection', err => { process.on('unhandledRejection', err => {

View File

@@ -7,6 +7,7 @@ import createOutput from '../../util/output';
import getArgs from '../../util/get-args'; import getArgs from '../../util/get-args';
import getSubcommand from '../../util/get-subcommand'; import getSubcommand from '../../util/get-subcommand';
import logo from '../../util/output/logo'; import logo from '../../util/output/logo';
import { getPkgName } from '../../util/pkg-name.ts';
import ls from './ls'; import ls from './ls';
import rm from './rm'; import rm from './rm';
@@ -14,7 +15,7 @@ import set from './set';
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now alias`)} [options] <command> ${chalk.bold(`${logo} ${getPkgName()} alias`)} [options] <command>
${chalk.dim('Commands:')} ${chalk.dim('Commands:')}
@@ -27,10 +28,10 @@ const help = () => {
-h, --help Output usage information -h, --help Output usage information
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
-r ${chalk.bold.underline('RULES_FILE')}, --rules=${chalk.bold.underline( -r ${chalk.bold.underline('RULES_FILE')}, --rules=${chalk.bold.underline(
'RULES_FILE' 'RULES_FILE'
)} Rules file )} Rules file
@@ -46,7 +47,7 @@ const help = () => {
${chalk.gray('')} Add a new alias to ${chalk.underline('my-api.now.sh')} ${chalk.gray('')} Add a new alias to ${chalk.underline('my-api.now.sh')}
${chalk.cyan( ${chalk.cyan(
`$ now alias set ${chalk.underline( `$ ${getPkgName()} alias set ${chalk.underline(
'api-ownv3nc9f8.now.sh' 'api-ownv3nc9f8.now.sh'
)} ${chalk.underline('my-api.now.sh')}` )} ${chalk.underline('my-api.now.sh')}`
)} )}
@@ -54,7 +55,7 @@ const help = () => {
Custom domains work as alias targets Custom domains work as alias targets
${chalk.cyan( ${chalk.cyan(
`$ now alias set ${chalk.underline( `$ ${getPkgName()} alias set ${chalk.underline(
'api-ownv3nc9f8.now.sh' 'api-ownv3nc9f8.now.sh'
)} ${chalk.underline('my-api.com')}` )} ${chalk.underline('my-api.com')}`
)} )}
@@ -67,26 +68,28 @@ const help = () => {
)} in the URLs are unneeded and ignored. )} in the URLs are unneeded and ignored.
${chalk.gray('')} Add and modify path based aliases for ${chalk.underline( ${chalk.gray('')} Add and modify path based aliases for ${chalk.underline(
'zeit.ninja' 'example.com'
)} )}
${chalk.cyan( ${chalk.cyan(
`$ now alias ${chalk.underline('zeit.ninja')} -r ${chalk.underline( `$ ${getPkgName()} alias ${chalk.underline(
'rules.json' 'example.com'
)}` )} -r ${chalk.underline('rules.json')}`
)} )}
Export effective routing rules Export effective routing rules
${chalk.cyan( ${chalk.cyan(
`$ now alias ls aliasId --json > ${chalk.underline('rules.json')}` `$ ${getPkgName()} alias ls aliasId --json > ${chalk.underline(
'rules.json'
)}`
)} )}
${chalk.gray('')} Paginate results, where ${chalk.dim( ${chalk.gray('')} Paginate results, where ${chalk.dim(
'`1584722256178`' '`1584722256178`'
)} is the time in milliseconds since the UNIX epoch. )} is the time in milliseconds since the UNIX epoch.
${chalk.cyan(`$ now alias ls --next 1584722256178`)} ${chalk.cyan(`$ ${getPkgName()} alias ls --next 1584722256178`)}
`); `);
}; };

View File

@@ -9,7 +9,7 @@ import getScope from '../../util/get-scope.ts';
import stamp from '../../util/output/stamp.ts'; import stamp from '../../util/output/stamp.ts';
import strlen from '../../util/strlen.ts'; import strlen from '../../util/strlen.ts';
import getCommandFlags from '../../util/get-command-flags'; import getCommandFlags from '../../util/get-command-flags';
import cmd from '../../util/output/cmd.ts'; import { getCommandName } from '../../util/pkg-name.ts';
export default async function ls(ctx, opts, args, output) { export default async function ls(ctx, opts, args, output) {
const { const {
@@ -55,7 +55,7 @@ export default async function ls(ctx, opts, args, output) {
if (args.length > 1) { if (args.length > 1) {
output.error( output.error(
`Invalid number of arguments. Usage: ${chalk.cyan( `Invalid number of arguments. Usage: ${chalk.cyan(
'`now alias ls [alias]`' `${getCommandName('alias ls [alias]')}`
)}` )}`
); );
return 1; return 1;
@@ -106,8 +106,8 @@ export default async function ls(ctx, opts, args, output) {
if (pagination && pagination.count === 20) { if (pagination && pagination.count === 20) {
const flags = getCommandFlags(opts, ['_', '--next']); const flags = getCommandFlags(opts, ['_', '--next']);
output.log( output.log(
`To display the next page run ${cmd( `To display the next page run ${getCommandName(
`now alias ls${flags} --next ${pagination.next}` `alias ls${flags} --next ${pagination.next}`
)}` )}`
); );
} }

View File

@@ -2,7 +2,6 @@ import chalk from 'chalk';
import ms from 'ms'; import ms from 'ms';
import table from 'text-table'; import table from 'text-table';
import Now from '../../util'; import Now from '../../util';
import cmd from '../../util/output/cmd.ts';
import Client from '../../util/client.ts'; import Client from '../../util/client.ts';
import getScope from '../../util/get-scope.ts'; import getScope from '../../util/get-scope.ts';
import removeAliasById from '../../util/alias/remove-alias-by-id'; import removeAliasById from '../../util/alias/remove-alias-by-id';
@@ -11,6 +10,7 @@ import strlen from '../../util/strlen.ts';
import promptBool from '../../util/prompt-bool'; import promptBool from '../../util/prompt-bool';
import { isValidName } from '../../util/is-valid-name'; import { isValidName } from '../../util/is-valid-name';
import findAliasByAliasOrId from '../../util/alias/find-alias-by-alias-or-id'; import findAliasByAliasOrId from '../../util/alias/find-alias-by-alias-or-id';
import { getCommandName } from '../../util/pkg-name.ts';
export default async function rm(ctx, opts, args, output) { export default async function rm(ctx, opts, args, output) {
const { const {
@@ -46,14 +46,14 @@ export default async function rm(ctx, opts, args, output) {
if (args.length !== 1) { if (args.length !== 1) {
output.error( output.error(
`Invalid number of arguments. Usage: ${chalk.cyan( `Invalid number of arguments. Usage: ${chalk.cyan(
'`now alias rm <alias>`' `${getCommandName('alias rm <alias>')}`
)}` )}`
); );
return 1; return 1;
} }
if (!aliasOrId) { if (!aliasOrId) {
output.error(`${cmd('now alias rm <alias>')} expects one argument`); output.error(`${getCommandName('alias rm <alias>')} expects one argument`);
return 1; return 1;
} }
@@ -68,7 +68,7 @@ export default async function rm(ctx, opts, args, output) {
output.error( output.error(
`Alias not found by "${aliasOrId}" under ${chalk.bold(contextName)}` `Alias not found by "${aliasOrId}" under ${chalk.bold(contextName)}`
); );
output.log(`Run ${cmd('now alias ls')} to see your aliases.`); output.log(`Run ${getCommandName('alias ls')} to see your aliases.`);
return 1; return 1;
} }

View File

@@ -7,7 +7,6 @@ import { Output } from '../../util/output';
import * as ERRORS from '../../util/errors-ts'; import * as ERRORS from '../../util/errors-ts';
import assignAlias from '../../util/alias/assign-alias'; import assignAlias from '../../util/alias/assign-alias';
import Client from '../../util/client'; import Client from '../../util/client';
import cmd from '../../util/output/cmd';
import formatDnsTable from '../../util/format-dns-table'; import formatDnsTable from '../../util/format-dns-table';
import formatNSTable from '../../util/format-ns-table'; import formatNSTable from '../../util/format-ns-table';
import getDeploymentForAlias from '../../util/alias/get-deployment-for-alias'; import getDeploymentForAlias from '../../util/alias/get-deployment-for-alias';
@@ -23,6 +22,7 @@ import handleCertError from '../../util/certs/handle-cert-error';
import isWildcardAlias from '../../util/alias/is-wildcard-alias'; import isWildcardAlias from '../../util/alias/is-wildcard-alias';
import link from '../../util/output/link'; import link from '../../util/output/link';
import { User } from '../../types'; import { User } from '../../types';
import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
@@ -77,7 +77,9 @@ export default async function set(
// If there are more than two args we have to error // If there are more than two args we have to error
if (args.length > 2) { if (args.length > 2) {
output.error( output.error(
`${cmd('now alias <deployment> <target>')} accepts at most two arguments` `${getCommandName(
`alias <deployment> <target>`
)} accepts at most two arguments`
); );
return 1; return 1;
} }
@@ -126,7 +128,7 @@ export default async function set(
output.error( output.error(
`To ship to production, optionally configure your domains (${link( `To ship to production, optionally configure your domains (${link(
'https://vercel.com/docs/v2/custom-domains' 'https://vercel.com/docs/v2/custom-domains'
)}) and run ${cmd('now --prod')}.` )}) and run ${getCommandName(`--prod`)}.`
); );
return 1; return 1;
} }
@@ -301,8 +303,8 @@ function handleSetupDomainError<T>(
)}\n\n` )}\n\n`
); );
output.print( output.print(
` Once your domain uses either the nameservers or the TXT DNS record from above, run again ${cmd( ` Once your domain uses either the nameservers or the TXT DNS record from above, run again ${getCommandName(
'now domains verify <domain>' 'domains verify <domain>'
)}.\n` )}.\n`
); );
output.print( output.print(
@@ -310,8 +312,8 @@ function handleSetupDomainError<T>(
); );
} else { } else {
output.print( output.print(
` Once your domain uses the nameservers from above, run again ${cmd( ` Once your domain uses the nameservers from above, run again ${getCommandName(
'now domains verify <domain>' 'domains verify <domain>'
)}.\n` )}.\n`
); );
} }
@@ -474,7 +476,7 @@ function handleCreateAliasError<T>(
output.log( output.log(
`Update the scale settings on ${chalk.dim( `Update the scale settings on ${chalk.dim(
error.meta.url error.meta.url
)} with \`now scale\` and try again` )} with ${getCommandName('scale')} and try again`
); );
output.log('Read more: https://err.sh/now/v2-no-min'); output.log('Read more: https://err.sh/now/v2-no-min');
return 1; return 1;
@@ -490,7 +492,7 @@ function handleCreateAliasError<T>(
output.log( output.log(
`Update the scale settings on ${chalk.dim( `Update the scale settings on ${chalk.dim(
error.meta.url error.meta.url
)} with \`now scale\` and try again` )} with ${getCommandName('scale')} and try again`
); );
return 1; return 1;
} }
@@ -510,7 +512,7 @@ function handleCreateAliasError<T>(
output.log( output.log(
`Update the scale settings on ${chalk.dim( `Update the scale settings on ${chalk.dim(
error.meta.url error.meta.url
)} with \`now scale\` and try again` )} with ${getCommandName('scale')} and try again`
); );
return 1; return 1;
} }
@@ -520,8 +522,8 @@ function handleCreateAliasError<T>(
`There is no certificate for the domain ${error.meta.domain} and it could not be created.` `There is no certificate for the domain ${error.meta.domain} and it could not be created.`
); );
output.log( output.log(
`Please generate a new certificate manually with ${cmd( `Please generate a new certificate manually with ${getCommandName(
`now certs issue ${error.meta.domain}` `certs issue ${error.meta.domain}`
)}` )}`
); );
return 1; return 1;

View File

@@ -15,10 +15,11 @@ import exit from '../../util/exit';
import Client from '../../util/client.ts'; import Client from '../../util/client.ts';
import getScope from '../../util/get-scope.ts'; import getScope from '../../util/get-scope.ts';
import createOutput from '../../util/output'; import createOutput from '../../util/output';
import { getPkgName } from '../../util/pkg-name.ts';
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now billing`)} [options] <command> ${chalk.bold(`${logo} ${getPkgName()} billing`)} [options] <command>
${chalk.dim('Options:')} ${chalk.dim('Options:')}
@@ -32,10 +33,10 @@ const help = () => {
-h, --help Output usage information -h, --help Output usage information
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
-d, --debug Debug mode [off] -d, --debug Debug mode [off]
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline( -t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
'TOKEN' 'TOKEN'
@@ -46,7 +47,7 @@ const help = () => {
${chalk.gray('')} Add a new credit card (interactively) ${chalk.gray('')} Add a new credit card (interactively)
${chalk.cyan(`$ now billing add`)} ${chalk.cyan(`$ ${getPkgName()} billing add`)}
`); `);
}; };

View File

@@ -9,6 +9,7 @@ import createCertFromFile from '../../util/certs/create-cert-from-file';
import createCertForCns from '../../util/certs/create-cert-for-cns'; import createCertForCns from '../../util/certs/create-cert-for-cns';
import { NowContext } from '../../types'; import { NowContext } from '../../types';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import { getCommandName } from '../../util/pkg-name';
interface Options { interface Options {
'--overwrite'?: boolean; '--overwrite'?: boolean;
@@ -61,7 +62,6 @@ async function add(
throw err; throw err;
} }
// $FlowFixMe
const now = new Now({ apiUrl, token, debug: debugEnabled, currentTeam }); const now = new Now({ apiUrl, token, debug: debugEnabled, currentTeam });
if (overwite) { if (overwite) {
@@ -77,7 +77,9 @@ async function add(
); );
output.print( output.print(
` ${chalk.cyan( ` ${chalk.cyan(
`now certs add --crt <domain.crt> --key <domain.key> --ca <ca.crt>` `${getCommandName(
'certs add --crt <domain.crt> --key <domain.key> --ca <ca.crt>'
)}`
)}\n` )}\n`
); );
now.close(); now.close();
@@ -89,9 +91,9 @@ async function add(
} else { } else {
output.warn( output.warn(
`${chalk.cyan( `${chalk.cyan(
'now certs add' getCommandName('certs add')
)} will be soon deprecated. Please use ${chalk.cyan( )} will be soon deprecated. Please use ${chalk.cyan(
'now certs issue <cn> <cns>' getCommandName('certs issue <cn> <cns>')
)} instead` )} instead`
); );
@@ -99,7 +101,9 @@ async function add(
output.error( output.error(
`Invalid number of arguments to create a custom certificate entry. Usage:` `Invalid number of arguments to create a custom certificate entry. Usage:`
); );
output.print(` ${chalk.cyan(`now certs add <cn>[, <cn>]`)}\n`); output.print(
` ${chalk.cyan(getCommandName('certs add <cn>[, <cn>]'))}\n`
);
now.close(); now.close();
return 1; return 1;
} }

View File

@@ -13,13 +13,14 @@ import issue from './issue';
import ls from './ls'; import ls from './ls';
import rm from './rm'; import rm from './rm';
import { NowContext } from '../../types'; import { NowContext } from '../../types';
import { getPkgName } from '../../util/pkg-name';
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now certs`)} [options] <command> ${chalk.bold(`${logo} ${getPkgName()} certs`)} [options] <command>
${chalk.yellow('NOTE:')} This command is intended for advanced use only. ${chalk.yellow('NOTE:')} This command is intended for advanced use only.
By default, Now manages your certificates automatically. By default, Vercel manages your certificates automatically.
${chalk.dim('Commands:')} ${chalk.dim('Commands:')}
@@ -32,10 +33,10 @@ const help = () => {
-h, --help Output usage information -h, --help Output usage information
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
-d, --debug Debug mode [off] -d, --debug Debug mode [off]
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline( -t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
'TOKEN' 'TOKEN'
@@ -57,17 +58,17 @@ const help = () => {
'' ''
)} Generate a certificate with the cnames "acme.com" and "www.acme.com" )} Generate a certificate with the cnames "acme.com" and "www.acme.com"
${chalk.cyan('$ now certs issue acme.com www.acme.com')} ${chalk.cyan(`$ ${getPkgName()} certs issue acme.com www.acme.com`)}
${chalk.gray('')} Remove a certificate ${chalk.gray('')} Remove a certificate
${chalk.cyan('$ now certs rm id')} ${chalk.cyan(`$ ${getPkgName()} certs rm id`)}
${chalk.gray('')} Paginate results, where ${chalk.dim( ${chalk.gray('')} Paginate results, where ${chalk.dim(
'`1584722256178`' '`1584722256178`'
)} is the time in milliseconds since the UNIX epoch. )} is the time in milliseconds since the UNIX epoch.
${chalk.cyan(`$ now certs ls --next 1584722256178`)} ${chalk.cyan(`$ ${getPkgName()} certs ls --next 1584722256178`)}
`); `);
}; };

View File

@@ -14,6 +14,7 @@ import getScope from '../../util/get-scope';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
import startCertOrder from '../../util/certs/start-cert-order'; import startCertOrder from '../../util/certs/start-cert-order';
import handleCertError from '../../util/certs/handle-cert-error'; import handleCertError from '../../util/certs/handle-cert-error';
import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--ca': string; '--ca': string;
@@ -80,7 +81,9 @@ export default async function issue(
); );
output.print( output.print(
` ${chalk.cyan( ` ${chalk.cyan(
`now certs issue --crt <domain.crt> --key <domain.key> --ca <ca.crt>` getCommandName(
'certs issue --crt <domain.crt> --key <domain.key> --ca <ca.crt>'
)
)}\n` )}\n`
); );
return 1; return 1;
@@ -107,7 +110,9 @@ export default async function issue(
output.error( output.error(
`Invalid number of arguments to create a custom certificate entry. Usage:` `Invalid number of arguments to create a custom certificate entry. Usage:`
); );
output.print(` ${chalk.cyan(`now certs issue <cn>[, <cn>]`)}\n`); output.print(
` ${chalk.cyan(getCommandName('certs issue <cn>[, <cn>]'))}\n`
);
return 1; return 1;
} }
@@ -189,7 +194,9 @@ async function runStartOrder(
output.print( output.print(
` There are no pending challenges. Finish the issuance by running: \n` ` There are no pending challenges. Finish the issuance by running: \n`
); );
output.print(` ${chalk.cyan(`now certs issue ${cns.join(' ')}`)}\n`); output.print(
` ${chalk.cyan(getCommandName(`certs issue ${cns.join(' ')}`))}\n`
);
return 0; return 0;
} }
@@ -220,7 +227,9 @@ async function runStartOrder(
output.print(`${header}\n`); output.print(`${header}\n`);
process.stdout.write(`${rows.join('\n')}\n\n`); process.stdout.write(`${rows.join('\n')}\n\n`);
output.log(`To issue the certificate once the records are added, run:`); output.log(`To issue the certificate once the records are added, run:`);
output.print(` ${chalk.cyan(`now certs issue ${cns.join(' ')}`)}\n`); output.print(
` ${chalk.cyan(getCommandName(`certs issue ${cns.join(' ')}`))}\n`
);
output.print(' Read more: https://err.sh/now/solve-challenges-manually\n'); output.print(' Read more: https://err.sh/now/solve-challenges-manually\n');
return 0; return 0;
} }

View File

@@ -3,7 +3,6 @@ import ms from 'ms';
import table from 'text-table'; import table from 'text-table';
// @ts-ignore // @ts-ignore
import Now from '../../util'; import Now from '../../util';
import cmd from '../../util/output/cmd';
import Client from '../../util/client'; import Client from '../../util/client';
import getScope from '../../util/get-scope'; import getScope from '../../util/get-scope';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
@@ -12,6 +11,7 @@ import strlen from '../../util/strlen';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import { NowContext, Cert } from '../../types'; import { NowContext, Cert } from '../../types';
import getCommandFlags from '../../util/get-command-flags'; import getCommandFlags from '../../util/get-command-flags';
import { getCommandName } from '../../util/pkg-name';
interface Options { interface Options {
'--debug'?: boolean; '--debug'?: boolean;
@@ -53,7 +53,9 @@ async function ls(
if (args.length !== 0) { if (args.length !== 0) {
output.error( output.error(
`Invalid number of arguments. Usage: ${chalk.cyan('`now certs ls`')}` `Invalid number of arguments. Usage: ${chalk.cyan(
`${getCommandName('certs ls')}`
)}`
); );
return 1; return 1;
} }
@@ -76,8 +78,8 @@ async function ls(
if (pagination && pagination.count === 20) { if (pagination && pagination.count === 20) {
const flags = getCommandFlags(opts, ['_', '--next']); const flags = getCommandFlags(opts, ['_', '--next']);
output.log( output.log(
`To display the next page run ${cmd( `To display the next page run ${getCommandName(
`now certs ls${flags} --next ${pagination.next}` `certs ls${flags} --next ${pagination.next}`
)}` )}`
); );
} }

View File

@@ -12,6 +12,7 @@ import Client from '../../util/client';
import getScope from '../../util/get-scope'; import getScope from '../../util/get-scope';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
import param from '../../util/output/param'; import param from '../../util/output/param';
import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
@@ -49,7 +50,7 @@ async function rm(
if (args.length !== 1) { if (args.length !== 1) {
output.error( output.error(
`Invalid number of arguments. Usage: ${chalk.cyan( `Invalid number of arguments. Usage: ${chalk.cyan(
'`now certs rm <id or cn>`' `${getCommandName('certs rm <id or cn>')}`
)}` )}`
); );
return 1; return 1;

View File

@@ -2,9 +2,10 @@ import chalk from 'chalk';
import logo from '../../util/output/logo'; import logo from '../../util/output/logo';
import code from '../../util/output/code'; import code from '../../util/output/code';
import note from '../../util/output/note'; import note from '../../util/output/note';
import { getPkgName } from '../../util/pkg-name.ts';
export const latestHelp = () => ` export const latestHelp = () => `
${chalk.bold(`${logo} now`)} [options] <command | path> ${chalk.bold(`${logo} ${getPkgName()}`)} [options] <command | path>
${chalk.dim('Commands:')} ${chalk.dim('Commands:')}
@@ -41,10 +42,10 @@ export const latestHelp = () => `
-V, --platform-version Set the platform version to deploy to -V, --platform-version Set the platform version to deploy to
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
-d, --debug Debug mode [off] -d, --debug Debug mode [off]
-f, --force Force a new deployment even if nothing has changed -f, --force Force a new deployment even if nothing has changed
--with-cache Retain build cache when using "--force" --with-cache Retain build cache when using "--force"
@@ -71,7 +72,7 @@ export const latestHelp = () => `
${note( ${note(
`To view the usage information for Now 1.0, run ${code( `To view the usage information for Now 1.0, run ${code(
'now help deploy-v1' `${getPkgName()} help deploy-v1`
)}` )}`
)} )}
@@ -79,21 +80,23 @@ export const latestHelp = () => `
${chalk.gray('')} Deploy the current directory ${chalk.gray('')} Deploy the current directory
${chalk.cyan('$ now')} ${chalk.cyan(`$ ${getPkgName()}`)}
${chalk.gray('')} Deploy a custom path ${chalk.gray('')} Deploy a custom path
${chalk.cyan('$ now /usr/src/project')} ${chalk.cyan(`$ ${getPkgName()} /usr/src/project`)}
${chalk.gray('')} Deploy with Environment Variables ${chalk.gray('')} Deploy with Environment Variables
${chalk.cyan('$ now -e NODE_ENV=production -e SECRET=@mysql-secret')} ${chalk.cyan(
`$ ${getPkgName()} -e NODE_ENV=production -e SECRET=@mysql-secret`
)}
${chalk.gray('')} Show the usage information for the sub command ${chalk.dim( ${chalk.gray('')} Show the usage information for the sub command ${chalk.dim(
'`list`' '`list`'
)} )}
${chalk.cyan('$ now help list')} ${chalk.cyan(`$ ${getPkgName()} help list`)}
`; `;
@@ -237,10 +240,10 @@ export const legacyHelp = () => `
-n, --name Set the project name of the deployment -n, --name Set the project name of the deployment
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
-d, --debug Debug mode [off] -d, --debug Debug mode [off]
-f, --force Force a new deployment even if nothing has changed -f, --force Force a new deployment even if nothing has changed
-t ${chalk.underline('TOKEN')}, --token=${chalk.underline( -t ${chalk.underline('TOKEN')}, --token=${chalk.underline(

View File

@@ -112,7 +112,7 @@ export default async ctx => {
} }
} }
const file = highlight('now.json'); const file = highlight('vercel.json');
const prop = code('version'); const prop = code('version');
if (localConfig) { if (localConfig) {

View File

@@ -54,6 +54,7 @@ import validatePaths, {
validateRootDirectory, validateRootDirectory,
} from '../../util/validate-paths'; } from '../../util/validate-paths';
import { readLocalConfig } from '../../util/config/files'; import { readLocalConfig } from '../../util/config/files';
import { getCommandName } from '../../util/pkg-name.ts';
const addProcessEnv = async (log, env) => { const addProcessEnv = async (log, env) => {
let val; let val;
@@ -101,9 +102,7 @@ const printDeploymentStatus = async (
if (readyState !== 'READY') { if (readyState !== 'READY') {
output.error( output.error(
`${chalk.red( `Your deployment failed. Please retry later. More: https://err.sh/now/deployment-error`
'Error!'
)} Your deployment failed. Please retry later. More: https://err.sh/now/deployment-error`
); );
return 1; return 1;
} }
@@ -123,7 +122,10 @@ const printDeploymentStatus = async (
// but fallback to the first alias in the list // but fallback to the first alias in the list
const mainAlias = const mainAlias =
aliasList.find( aliasList.find(
alias => !alias.endsWith('.now.sh') && !isWildcardAlias(alias) alias =>
!alias.endsWith('.now.sh') &&
!alias.endsWith('.vercel.app') &&
!isWildcardAlias(alias)
) || aliasList[0]; ) || aliasList[0];
isWildcard = isWildcardAlias(mainAlias); isWildcard = isWildcardAlias(mainAlias);
@@ -260,7 +262,7 @@ export default async function main(
debug: debugEnabled, debug: debugEnabled,
}); });
// retrieve `project` and `org` from .now // retrieve `project` and `org` from .vercel
const link = await getLinkedProject(output, client, path); const link = await getLinkedProject(output, client, path);
if (link.status === 'error') { if (link.status === 'error') {
@@ -302,7 +304,7 @@ export default async function main(
} }
// We use `localConfig` here to read the name // We use `localConfig` here to read the name
// even though the `now.json` file can change // even though the `vercel.json` file can change
// afterwards, this is fine since the property // afterwards, this is fine since the property
// will be deprecated and can be replaced with // will be deprecated and can be replaced with
// user input. // user input.
@@ -371,7 +373,7 @@ export default async function main(
output.print( output.print(
`${prependEmoji( `${prependEmoji(
`The ${highlight( `The ${highlight(
'now.json' 'vercel.json'
)} file should be inside of the provided root directory.`, )} file should be inside of the provided root directory.`,
emoji('warning') emoji('warning')
)}\n` )}\n`
@@ -385,7 +387,7 @@ export default async function main(
output.print( output.print(
`${prependEmoji( `${prependEmoji(
`The ${code('name')} property in ${highlight( `The ${code('name')} property in ${highlight(
'now.json' 'vercel.json'
)} is deprecated (https://zeit.ink/5F)`, )} is deprecated (https://zeit.ink/5F)`,
emoji('warning') emoji('warning')
)}\n` )}\n`
@@ -402,7 +404,7 @@ export default async function main(
if (typeof localConfig.env !== 'undefined' && !isObject(localConfig.env)) { if (typeof localConfig.env !== 'undefined' && !isObject(localConfig.env)) {
error( error(
`The ${code('env')} property in ${highlight( `The ${code('env')} property in ${highlight(
'now.json' 'vercel.json'
)} needs to be an object` )} needs to be an object`
); );
return 1; return 1;
@@ -412,7 +414,7 @@ export default async function main(
if (!isObject(localConfig.build)) { if (!isObject(localConfig.build)) {
error( error(
`The ${code('build')} property in ${highlight( `The ${code('build')} property in ${highlight(
'now.json' 'vercel.json'
)} needs to be an object` )} needs to be an object`
); );
return 1; return 1;
@@ -424,7 +426,7 @@ export default async function main(
) { ) {
error( error(
`The ${code('build.env')} property in ${highlight( `The ${code('build.env')} property in ${highlight(
'now.json' 'vercel.json'
)} needs to be an object` )} needs to be an object`
); );
return 1; return 1;
@@ -438,14 +440,14 @@ export default async function main(
parseMeta(argv['--meta']) parseMeta(argv['--meta'])
); );
// Merge dotenv config, `env` from now.json, and `--env` / `-e` arguments // Merge dotenv config, `env` from vercel.json, and `--env` / `-e` arguments
const deploymentEnv = Object.assign( const deploymentEnv = Object.assign(
{}, {},
parseEnv(localConfig.env), parseEnv(localConfig.env),
parseEnv(argv['--env']) parseEnv(argv['--env'])
); );
// Merge build env out of `build.env` from now.json, and `--build-env` args // Merge build env out of `build.env` from vercel.json, and `--build-env` args
const deploymentBuildEnv = Object.assign( const deploymentBuildEnv = Object.assign(
{}, {},
parseEnv(localConfig.build && localConfig.build.env), parseEnv(localConfig.build && localConfig.build.env),
@@ -666,8 +668,8 @@ export default async function main(
if (err instanceof BuildError) { if (err instanceof BuildError) {
output.error('Build failed'); output.error('Build failed');
output.error( output.error(
`Check your logs at https://${now.url}/_logs or run ${code( `Check your logs at https://${now.url}/_logs or run ${getCommandName(
`now logs ${now.url}`, `logs ${now.url}`,
{ {
// Backticks are interpreted as part of the URL, causing CMD+Click // Backticks are interpreted as part of the URL, causing CMD+Click
// behavior to fail in editors like VSCode. // behavior to fail in editors like VSCode.
@@ -734,8 +736,8 @@ function handleCreateDeployError(output, error) {
output.error( output.error(
`The property ${code(prop)} is not allowed in ${highlight( `The property ${code(prop)} is not allowed in ${highlight(
'now.json' 'vercel.json'
)} when using Now 2.0 please remove it.` )} please remove it.`
); );
if (prop === 'build.env' || prop === 'builds.env') { if (prop === 'build.env' || prop === 'builds.env') {
@@ -759,7 +761,7 @@ function handleCreateDeployError(output, error) {
output.error( output.error(
`The property ${code(prop)} in ${highlight( `The property ${code(prop)} in ${highlight(
'now.json' 'vercel.json'
)} can only be of type ${code(title(params.type))}.` )} can only be of type ${code(title(params.type))}.`
); );
@@ -770,7 +772,7 @@ function handleCreateDeployError(output, error) {
output.error( output.error(
`Failed to validate ${highlight( `Failed to validate ${highlight(
'now.json' 'vercel.json'
)}: ${message}\nDocumentation: ${link}` )}: ${message}\nDocumentation: ${link}`
); );
@@ -797,7 +799,9 @@ function handleCreateDeployError(output, error) {
} }
if (error instanceof BuildsRateLimited) { if (error instanceof BuildsRateLimited) {
output.error(error.message); output.error(error.message);
output.note(`Run ${code('now upgrade')} to increase your builds limit.`); output.note(
`Run ${getCommandName('upgrade')} to increase your builds limit.`
);
return 1; return 1;
} }
if ( if (

View File

@@ -1,5 +1,4 @@
import path from 'path'; import { resolve, join } from 'path';
import chalk from 'chalk';
import DevServer from '../../util/dev/server'; import DevServer from '../../util/dev/server';
import parseListen from '../../util/dev/parse-listen'; import parseListen from '../../util/dev/parse-listen';
@@ -9,7 +8,7 @@ import Client from '../../util/client';
import { getLinkedProject } from '../../util/projects/link'; import { getLinkedProject } from '../../util/projects/link';
import { getFrameworks } from '../../util/get-frameworks'; import { getFrameworks } from '../../util/get-frameworks';
import { isSettingValue } from '../../util/is-setting-value'; import { isSettingValue } from '../../util/is-setting-value';
import cmd from '../../util/output/cmd'; import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug'?: boolean; '--debug'?: boolean;
@@ -23,7 +22,7 @@ export default async function dev(
output: Output output: Output
) { ) {
const [dir = '.'] = args; const [dir = '.'] = args;
let cwd = path.resolve(dir); let cwd = resolve(dir);
const listen = parseListen(opts['--listen'] || '3000'); const listen = parseListen(opts['--listen'] || '3000');
const debug = opts['--debug'] || false; const debug = opts['--debug'] || false;
@@ -44,13 +43,9 @@ export default async function dev(
return link.exitCode; return link.exitCode;
} }
if (link.status === 'not_linked' && !process.env.__NOW_SKIP_DEV_COMMAND) { if (link.status === 'not_linked' && !process.env.__VERCEL_SKIP_DEV_CMD) {
output.print( output.error(
`${chalk.red( `Your codebase isnt linked to a project on Vercel. Run ${getCommandName()} to link it.`
'Error!'
)} Your codebase isnt linked to a project on Vercel. Run ${cmd(
'now'
)} to link it.\n`
); );
return 1; return 1;
} }
@@ -58,7 +53,8 @@ export default async function dev(
let devCommand: undefined | string; let devCommand: undefined | string;
let frameworkSlug: null | string = null; let frameworkSlug: null | string = null;
if (link.status === 'linked') { if (link.status === 'linked') {
const { project } = link; const { project, org } = link;
client.currentTeam = org.type === 'team' ? org.id : undefined;
if (project.devCommand) { if (project.devCommand) {
devCommand = project.devCommand; devCommand = project.devCommand;
@@ -76,7 +72,7 @@ export default async function dev(
} }
if (project.rootDirectory) { if (project.rootDirectory) {
cwd = path.join(cwd, project.rootDirectory); cwd = join(cwd, project.rootDirectory);
} }
} }

View File

@@ -1,6 +1,6 @@
import path from 'path'; import path from 'path';
import chalk from 'chalk'; import chalk from 'chalk';
import { PackageJson } from '@now/build-utils'; import { PackageJson } from '@vercel/build-utils';
import getArgs from '../../util/get-args'; import getArgs from '../../util/get-args';
import getSubcommand from '../../util/get-subcommand'; import getSubcommand from '../../util/get-subcommand';
@@ -13,6 +13,7 @@ import cmd from '../../util/output/cmd';
import dev from './dev'; import dev from './dev';
import readPackage from '../../util/read-package'; import readPackage from '../../util/read-package';
import readConfig from '../../util/config/read-config'; import readConfig from '../../util/config/read-config';
import { getPkgName, getCommandName } from '../../util/pkg-name';
const COMMAND_CONFIG = { const COMMAND_CONFIG = {
dev: ['dev'], dev: ['dev'],
@@ -20,9 +21,9 @@ const COMMAND_CONFIG = {
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now dev`)} [options] <dir> ${chalk.bold(`${logo} ${getPkgName()} dev`)} [options] <dir>
Starts the \`now dev\` server. Starts the \`${getPkgName()} dev\` server.
${chalk.dim('Options:')} ${chalk.dim('Options:')}
@@ -33,13 +34,13 @@ const help = () => {
${chalk.dim('Examples:')} ${chalk.dim('Examples:')}
${chalk.gray('')} Start the \`now dev\` server on port 8080 ${chalk.gray('')} Start the \`${getPkgName()} dev\` server on port 8080
${chalk.cyan('$ now dev --listen 8080')} ${chalk.cyan(`$ ${getPkgName()} dev --listen 8080`)}
${chalk.gray('')} Make the \`now dev\` server bind to localhost on port 5000 ${chalk.gray('')} Make the \`now dev\` server bind to localhost on port 5000
${chalk.cyan('$ now dev --listen 127.0.0.1:5000')} ${chalk.cyan(`$ ${getPkgName()} dev --listen 127.0.0.1:5000`)}
`); `);
}; };
@@ -77,7 +78,7 @@ export default async function main(ctx: NowContext) {
const [dir = '.'] = args; const [dir = '.'] = args;
const nowJson = await readConfig(path.join(dir, 'now.json')); const nowJson = await readConfig(dir);
// @ts-ignore: Because `nowJson` could be one of three different types // @ts-ignore: Because `nowJson` could be one of three different types
const hasBuilds = nowJson && nowJson.builds && nowJson.builds.length > 0; const hasBuilds = nowJson && nowJson.builds && nowJson.builds.length > 0;
@@ -96,11 +97,20 @@ export default async function main(ctx: NowContext) {
output.error(`More details: http://err.sh/now/now-dev-as-dev-script`); output.error(`More details: http://err.sh/now/now-dev-as-dev-script`);
return 1; return 1;
} }
if (scripts && scripts.dev && /\bvercel\b\W+\bdev\b/.test(scripts.dev)) {
output.error(
`The ${cmd('dev')} script in ${cmd(
'package.json'
)} must not contain ${cmd('vercel dev')}`
);
output.error(`More details: http://err.sh/now/now-dev-as-dev-script`);
return 1;
}
} }
} }
if (argv._.length > 2) { if (argv._.length > 2) {
output.error(`${cmd('now dev [dir]')} accepts at most one argument`); output.error(`${getCommandName(`dev [dir]`)} accepts at most one argument`);
return 1; return 1;
} }

View File

@@ -13,6 +13,7 @@ import getScope from '../../util/get-scope';
import parseAddDNSRecordArgs from '../../util/dns/parse-add-dns-record-args'; import parseAddDNSRecordArgs from '../../util/dns/parse-add-dns-record-args';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
import getDNSData from '../../util/dns/get-dns-data'; import getDNSData from '../../util/dns/get-dns-data';
import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
@@ -49,7 +50,7 @@ export default async function add(
if (!parsedParams) { if (!parsedParams) {
output.error( output.error(
`Invalid number of arguments. See: ${chalk.cyan( `Invalid number of arguments. See: ${chalk.cyan(
'`now dns --help`' `${getCommandName('dns --help')}`
)} for usage.` )} for usage.`
); );
return 1; return 1;

View File

@@ -6,6 +6,7 @@ import getScope from '../../util/get-scope';
import { DomainNotFound, InvalidDomain } from '../../util/errors-ts'; import { DomainNotFound, InvalidDomain } from '../../util/errors-ts';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
import importZonefile from '../../util/dns/import-zonefile'; import importZonefile from '../../util/dns/import-zonefile';
import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
@@ -41,7 +42,7 @@ export default async function add(
if (args.length !== 2) { if (args.length !== 2) {
output.error( output.error(
`Invalid number of arguments. Usage: ${chalk.cyan( `Invalid number of arguments. Usage: ${chalk.cyan(
'`now dns import <domain> <zonefile>`' `${getCommandName('dns import <domain> <zonefile>')}`
)}` )}`
); );
return 1; return 1;

View File

@@ -6,6 +6,7 @@ import getArgs from '../../util/get-args';
import getSubcommand from '../../util/get-subcommand'; import getSubcommand from '../../util/get-subcommand';
import handleError from '../../util/handle-error'; import handleError from '../../util/handle-error';
import logo from '../../util/output/logo'; import logo from '../../util/output/logo';
import { getPkgName } from '../../util/pkg-name';
import add from './add'; import add from './add';
import importZone from './import'; import importZone from './import';
@@ -14,7 +15,7 @@ import rm from './rm';
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now dns`)} [options] <command> ${chalk.bold(`${logo} ${getPkgName()} dns`)} [options] <command>
${chalk.dim('Commands:')} ${chalk.dim('Commands:')}
@@ -28,50 +29,64 @@ const help = () => {
-h, --help Output usage information -h, --help Output usage information
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
-d, --debug Debug mode [off] -d, --debug Debug mode [off]
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline( -t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
'TOKEN' 'TOKEN'
)} Login token )} Login token
-S, --scope Set a custom scope -S, --scope Set a custom scope
-N, --next Show next page of results
${chalk.dim('Examples:')} ${chalk.dim('Examples:')}
${chalk.gray('')} Add an A record for a subdomain ${chalk.gray('')} Add an A record for a subdomain
${chalk.cyan( ${chalk.cyan(
'$ now dns add <DOMAIN> <SUBDOMAIN> <A | AAAA | ALIAS | CNAME | TXT> <VALUE>' `$ ${getPkgName()} dns add <DOMAIN> <SUBDOMAIN> <A | AAAA | ALIAS | CNAME | TXT> <VALUE>`
)} )}
${chalk.cyan('$ now dns add zeit.rocks api A 198.51.100.100')} ${chalk.cyan(`$ ${getPkgName()} dns add zeit.rocks api A 198.51.100.100`)}
${chalk.gray('')} Add an MX record (@ as a name refers to the domain) ${chalk.gray('')} Add an MX record (@ as a name refers to the domain)
${chalk.cyan(`$ now dns add <DOMAIN> '@' MX <RECORD VALUE> <PRIORITY>`)} ${chalk.cyan(
${chalk.cyan(`$ now dns add zeit.rocks '@' MX mail.zeit.rocks 10`)} `$ ${getPkgName()} dns add <DOMAIN> '@' MX <RECORD VALUE> <PRIORITY>`
)}
${chalk.cyan(
`$ ${getPkgName()} dns add zeit.rocks '@' MX mail.zeit.rocks 10`
)}
${chalk.gray('')} Add an SRV record ${chalk.gray('')} Add an SRV record
${chalk.cyan( ${chalk.cyan(
'$ now dns add <DOMAIN> <NAME> SRV <PRIORITY> <WEIGHT> <PORT> <TARGET>' `$ ${getPkgName()} dns add <DOMAIN> <NAME> SRV <PRIORITY> <WEIGHT> <PORT> <TARGET>`
)}
${chalk.cyan(
`$ ${getPkgName()} dns add zeit.rocks '@' SRV 10 0 389 zeit.party`
)} )}
${chalk.cyan(`$ now dns add zeit.rocks '@' SRV 10 0 389 zeit.party`)}
${chalk.gray('')} Add a CAA record ${chalk.gray('')} Add a CAA record
${chalk.cyan( ${chalk.cyan(
`$ now dns add <DOMAIN> <NAME> CAA '<FLAGS> <TAG> "<VALUE>"'` `$ ${getPkgName()} dns add <DOMAIN> <NAME> CAA '<FLAGS> <TAG> "<VALUE>"'`
)}
${chalk.cyan(
`$ ${getPkgName()} dns add zeit.rocks '@' CAA '0 issue "example.com"'`
)} )}
${chalk.cyan(`$ now dns add zeit.rocks '@' CAA '0 issue "example.com"'`)}
${chalk.gray('')} Import a Zone file ${chalk.gray('')} Import a Zone file
${chalk.cyan('$ now dns import <DOMAIN> <FILE>')} ${chalk.cyan(`$ ${getPkgName()} dns import <DOMAIN> <FILE>`)}
${chalk.cyan(`$ now dns import zeit.rocks ./zonefile.txt`)} ${chalk.cyan(`$ ${getPkgName()} dns import zeit.rocks ./zonefile.txt`)}
${chalk.gray('')} Paginate results, where ${chalk.dim(
'`1584722256178`'
)} is the time in milliseconds since the UNIX epoch.
${chalk.cyan(`$ ${getPkgName()} dns ls --next 1584722256178`)}
${chalk.cyan(`$ ${getPkgName()} dns ls zeit.rocks --next 1584722256178`)}
`); `);
}; };
@@ -86,7 +101,7 @@ export default async function main(ctx: NowContext) {
let argv; let argv;
try { try {
argv = getArgs(ctx.argv.slice(2), {}); argv = getArgs(ctx.argv.slice(2), { '--next': Number, '-N': '--next' });
} catch (error) { } catch (error) {
handleError(error); handleError(error);
return 1; return 1;

View File

@@ -1,20 +1,22 @@
import chalk from 'chalk'; import chalk from 'chalk';
import ms from 'ms'; import ms from 'ms';
import plural from 'pluralize';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import { DomainNotFound } from '../../util/errors-ts'; import { DomainNotFound } from '../../util/errors-ts';
import { ThenArg, DNSRecord, NowContext } from '../../types'; import { DNSRecord, NowContext } from '../../types';
import Client from '../../util/client'; import Client from '../../util/client';
import formatTable from '../../util/format-table'; import formatTable from '../../util/format-table';
import getDNSRecords from '../../util/dns/get-dns-records'; import getDNSRecords, {
DomainRecordsItem,
} from '../../util/dns/get-dns-records';
import getDomainDNSRecords from '../../util/dns/get-domain-dns-records'; import getDomainDNSRecords from '../../util/dns/get-domain-dns-records';
import getScope from '../../util/get-scope'; import getScope from '../../util/get-scope';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
import getCommandFlags from '../../util/get-command-flags';
type DNSRecords = ThenArg<ReturnType<typeof getDNSRecords>>; import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
'--next'?: number;
}; };
export default async function ls( export default async function ls(
@@ -29,7 +31,7 @@ export default async function ls(
} = ctx; } = ctx;
const { currentTeam } = config; const { currentTeam } = config;
const { apiUrl } = ctx; const { apiUrl } = ctx;
const debug = opts['--debug']; const { '--debug': debug, '--next': nextTimestamp } = opts;
const client = new Client({ apiUrl, token, currentTeam, debug }); const client = new Client({ apiUrl, token, currentTeam, debug });
let contextName = null; let contextName = null;
@@ -50,15 +52,26 @@ export default async function ls(
if (args.length > 1) { if (args.length > 1) {
output.error( output.error(
`Invalid number of arguments. Usage: ${chalk.cyan( `Invalid number of arguments. Usage: ${chalk.cyan(
'`now dns ls [domain]`' `${getCommandName('dns ls [domain]')}`
)}` )}`
); );
return 1; return 1;
} }
if (typeof nextTimestamp !== 'undefined' && Number.isNaN(nextTimestamp)) {
output.error('Please provide a number for flag --next');
return 1;
}
if (domainName) { if (domainName) {
const records = await getDomainDNSRecords(output, client, domainName); const data = await getDomainDNSRecords(
if (records instanceof DomainNotFound) { output,
client,
domainName,
nextTimestamp,
4
);
if (data instanceof DomainNotFound) {
output.error( output.error(
`The domain ${domainName} can't be found under ${chalk.bold( `The domain ${domainName} can't be found under ${chalk.bold(
contextName contextName
@@ -67,27 +80,52 @@ export default async function ls(
return 1; return 1;
} }
const { records, pagination } = data;
output.log( output.log(
`${plural('Record', records.length, true)} found under ${chalk.bold( `${
contextName records.length > 0 ? 'Records' : 'No records'
)} ${chalk.gray(lsStamp())}` } found under ${chalk.bold(contextName)} ${chalk.gray(lsStamp())}`
); );
console.log(getDNSRecordsTable([{ domainName, records }])); console.log(getDNSRecordsTable([{ domainName, records }]));
if (pagination && pagination.count === 20) {
const flags = getCommandFlags(opts, ['_', '--next']);
output.log(
`To display the next page run ${getCommandName(
`dns ls ${domainName}${flags} --next ${pagination.next}`
)}`
);
}
return 0; return 0;
} }
const dnsRecords = await getDNSRecords(output, client, contextName); const { records: dnsRecords, pagination } = await getDNSRecords(
output,
client,
contextName,
nextTimestamp
);
const nRecords = dnsRecords.reduce((p, r) => r.records.length + p, 0); const nRecords = dnsRecords.reduce((p, r) => r.records.length + p, 0);
output.log( output.log(
`${plural('Record', nRecords, true)} found under ${chalk.bold( `${nRecords > 0 ? 'Records' : 'No records'} found under ${chalk.bold(
contextName contextName
)} ${chalk.gray(lsStamp())}` )} ${chalk.gray(lsStamp())}`
); );
console.log(getDNSRecordsTable(dnsRecords)); console.log(getDNSRecordsTable(dnsRecords));
if (pagination && pagination.count === 20) {
const flags = getCommandFlags(opts, ['_', '--next']);
output.log(
`To display the next page run ${getCommandName(
`dns ls${flags} --next ${pagination.next}`
)}`
);
}
return 0; return 0;
} }
function getDNSRecordsTable(dnsRecords: DNSRecords) { function getDNSRecordsTable(dnsRecords: DomainRecordsItem[]) {
return formatTable( return formatTable(
['', 'id', 'name', 'type', 'value', 'created'], ['', 'id', 'name', 'type', 'value', 'created'],
['l', 'r', 'l', 'l', 'l', 'l'], ['l', 'r', 'l', 'l', 'l', 'l'],
@@ -101,7 +139,7 @@ function getDNSRecordsTable(dnsRecords: DNSRecords) {
function getDNSRecordRow(record: DNSRecord) { function getDNSRecordRow(record: DNSRecord) {
const isSystemRecord = record.creator === 'system'; const isSystemRecord = record.creator === 'system';
const createdAt = `${ms( const createdAt = `${ms(
Date.now() - new Date(Number(record.created)).getTime() Date.now() - new Date(Number(record.createdAt)).getTime()
)} ago`; )} ago`;
const priority = record.mxPriority || record.priority || null; const priority = record.mxPriority || record.priority || null;
return [ return [

View File

@@ -8,6 +8,7 @@ import deleteDNSRecordById from '../../util/dns/delete-dns-record-by-id';
import getDNSRecordById from '../../util/dns/get-dns-record-by-id'; import getDNSRecordById from '../../util/dns/get-dns-record-by-id';
import getScope from '../../util/get-scope'; import getScope from '../../util/get-scope';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
@@ -19,15 +20,17 @@ export default async function rm(
args: string[], args: string[],
output: Output output: Output
) { ) {
const { authConfig: { token }, config } = ctx; const {
authConfig: { token },
config,
} = ctx;
const { currentTeam } = config; const { currentTeam } = config;
const { apiUrl } = ctx; const { apiUrl } = ctx;
const debug = opts['--debug']; const debug = opts['--debug'];
const client = new Client({ apiUrl, token, currentTeam, debug }); const client = new Client({ apiUrl, token, currentTeam, debug });
let contextName = null;
try { try {
({ contextName } = await getScope(client)); await getScope(client);
} catch (err) { } catch (err) {
if (err.code === 'NOT_AUTHORIZED' || err.code === 'TEAM_DELETED') { if (err.code === 'NOT_AUTHORIZED' || err.code === 'TEAM_DELETED') {
output.error(err.message); output.error(err.message);
@@ -40,24 +43,21 @@ export default async function rm(
const [recordId] = args; const [recordId] = args;
if (args.length !== 1) { if (args.length !== 1) {
output.error( output.error(
`Invalid number of arguments. Usage: ${chalk.cyan('`now dns rm <id>`')}` `Invalid number of arguments. Usage: ${chalk.cyan(
`${getCommandName('dns rm <id>')}`
)}`
); );
return 1; return 1;
} }
const domainRecord = await getDNSRecordById( const record = await getDNSRecordById(client, recordId);
output,
client,
contextName,
recordId
);
if (!domainRecord) { if (!record) {
output.error('DNS record not found'); output.error('DNS record not found');
return 1; return 1;
} }
const { domainName, record } = domainRecord; const { domain: domainName } = record;
const yes = await readConfirmation( const yes = await readConfirmation(
output, output,
'The following record will be removed permanently', 'The following record will be removed permanently',
@@ -91,7 +91,7 @@ function readConfirmation(
output.print( output.print(
`${table([getDeleteTableRow(domainName, record)], { `${table([getDeleteTableRow(domainName, record)], {
align: ['l', 'r', 'l'], align: ['l', 'r', 'l'],
hsep: ' '.repeat(6) hsep: ' '.repeat(6),
}).replace(/^(.*)/gm, ' $1')}\n` }).replace(/^(.*)/gm, ' $1')}\n`
); );
output.print( output.print(
@@ -112,12 +112,16 @@ function readConfirmation(
} }
function getDeleteTableRow(domainName: string, record: DNSRecord) { function getDeleteTableRow(domainName: string, record: DNSRecord) {
const recordName = `${record.name.length > 0 const recordName = `${
? `${record.name}.` record.name.length > 0 ? `${record.name}.` : ''
: ''}${domainName}`; }${domainName}`;
return [ return [
record.id, record.id,
chalk.bold(`${recordName} ${record.type} ${record.value} ${record.mxPriority || ''}`), chalk.bold(
chalk.gray(`${ms(Date.now() - new Date(Number(record.created)).getTime())} ago`) `${recordName} ${record.type} ${record.value} ${record.mxPriority || ''}`
),
chalk.gray(
`${ms(Date.now() - new Date(Number(record.createdAt)).getTime())} ago`
),
]; ];
} }

View File

@@ -12,6 +12,7 @@ import formatNSTable from '../../util/format-ns-table';
import getScope from '../../util/get-scope'; import getScope from '../../util/get-scope';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
import param from '../../util/output/param'; import param from '../../util/output/param';
import { getCommandName, getTitleName } from '../../util/pkg-name';
type Options = { type Options = {
'--cdn': boolean; '--cdn': boolean;
@@ -47,12 +48,14 @@ export default async function add(
} }
if (opts['--cdn'] !== undefined || opts['--no-cdn'] !== undefined) { if (opts['--cdn'] !== undefined || opts['--no-cdn'] !== undefined) {
output.error(`Toggling CF from Now CLI is deprecated.`); output.error(`Toggling CF from ${getTitleName()} CLI is deprecated.`);
return 1; return 1;
} }
if (args.length !== 1) { if (args.length !== 1) {
output.error(`${cmd('now domains add <domain>')} expects one argument`); output.error(
`${getCommandName('domains add <domain>')} expects one argument`
);
return 1; return 1;
} }
@@ -73,7 +76,7 @@ export default async function add(
output.error( output.error(
`You are adding '${domainName}' as a domain name containing a subdomain part '${subdomain}'\n` + `You are adding '${domainName}' as a domain name containing a subdomain part '${subdomain}'\n` +
` This feature is deprecated, please add just the root domain: ${chalk.cyan( ` This feature is deprecated, please add just the root domain: ${chalk.cyan(
`now domain add ${domain}` `${getCommandName(`domain add ${domain}`)}`
)}` )}`
); );
return 1; return 1;
@@ -139,7 +142,7 @@ export default async function add(
); );
output.print( output.print(
` If you want to force running a verification, you can run ${cmd( ` If you want to force running a verification, you can run ${cmd(
'now domains verify <domain>' `${getCommandName('domains verify <domain>')}`
)}\n` )}\n`
); );
output.print(' Read more: https://err.sh/now/domain-verification\n\n'); output.print(' Read more: https://err.sh/now/domain-verification\n\n');

View File

@@ -5,7 +5,6 @@ import { NowContext } from '../../types';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import * as ERRORS from '../../util/errors-ts'; import * as ERRORS from '../../util/errors-ts';
import Client from '../../util/client'; import Client from '../../util/client';
import cmd from '../../util/output/cmd';
import getDomainPrice from '../../util/domains/get-domain-price'; import getDomainPrice from '../../util/domains/get-domain-price';
import getDomainStatus from '../../util/domains/get-domain-status'; import getDomainStatus from '../../util/domains/get-domain-status';
import getScope from '../../util/get-scope'; import getScope from '../../util/get-scope';
@@ -13,6 +12,7 @@ import param from '../../util/output/param';
import promptBool from '../../util/input/prompt-bool'; import promptBool from '../../util/input/prompt-bool';
import purchaseDomain from '../../util/domains/purchase-domain'; import purchaseDomain from '../../util/domains/purchase-domain';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
@@ -47,7 +47,9 @@ export default async function buy(
const [domainName] = args; const [domainName] = args;
if (!domainName) { if (!domainName) {
output.error(`Missing domain name. Run ${cmd('now domains --help')}`); output.error(
`Missing domain name. Run ${getCommandName(`domains --help`)}`
);
return 1; return 1;
} }
@@ -60,7 +62,9 @@ export default async function buy(
const { domain: rootDomain, subdomain } = parsedDomain; const { domain: rootDomain, subdomain } = parsedDomain;
if (subdomain || !rootDomain) { if (subdomain || !rootDomain) {
output.error( output.error(
`Invalid domain name "${domainName}". Run ${cmd('now domains --help')}` `Invalid domain name "${domainName}". Run ${getCommandName(
`domains --help`
)}`
); );
return 1; return 1;
} }
@@ -116,8 +120,8 @@ export default async function buy(
if (buyResult instanceof ERRORS.SourceNotFound) { if (buyResult instanceof ERRORS.SourceNotFound) {
output.error( output.error(
`Could not purchase domain. Please add a payment method using ${cmd( `Could not purchase domain. Please add a payment method using ${getCommandName(
'now billing add' `billing add`
)}.` )}.`
); );
return 1; return 1;
@@ -184,8 +188,8 @@ export default async function buy(
); );
} else { } else {
output.note( output.note(
`You may now use your domain as an alias to your deployments. Run ${cmd( `You may now use your domain as an alias to your deployments. Run ${getCommandName(
'now alias --help' `alias --help`
)}` )}`
); );
} }

View File

@@ -15,10 +15,11 @@ import ls from './ls';
import rm from './rm'; import rm from './rm';
import verify from './verify'; import verify from './verify';
import move from './move'; import move from './move';
import { getPkgName } from '../../util/pkg-name';
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now domains`)} [options] <command> ${chalk.bold(`${logo} ${getPkgName()} domains`)} [options] <command>
${chalk.dim('Commands:')} ${chalk.dim('Commands:')}
@@ -28,7 +29,7 @@ const help = () => {
rm [name] Remove a domain rm [name] Remove a domain
buy [name] Buy a domain that you don't yet own buy [name] Buy a domain that you don't yet own
move [name] [destination] Move a domain to another user or team. move [name] [destination] Move a domain to another user or team.
transfer-in [name] Transfer in a domain to Zeit transfer-in [name] Transfer in a domain to Vercel
verify [name] Run a verification for a domain verify [name] Run a verification for a domain
${chalk.dim('Options:')} ${chalk.dim('Options:')}
@@ -37,10 +38,10 @@ const help = () => {
-d, --debug Debug mode [off] -d, --debug Debug mode [off]
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline( -t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
'TOKEN' 'TOKEN'
)} Login token )} Login token
@@ -51,13 +52,15 @@ const help = () => {
${chalk.gray('')} Add a domain that you already own ${chalk.gray('')} Add a domain that you already own
${chalk.cyan(`$ now domains add ${chalk.underline('domain-name.com')}`)} ${chalk.cyan(
`$ ${getPkgName()} domains add ${chalk.underline('domain-name.com')}`
)}
Make sure the domain's DNS nameservers are at least 2 of the Make sure the domain's DNS nameservers are at least 2 of the
ones listed on ${chalk.underline('https://zeit.world')}. ones listed on ${chalk.underline('https://vercel.com/edge-network')}.
${chalk.yellow('NOTE:')} Running ${chalk.dim( ${chalk.yellow('NOTE:')} Running ${chalk.dim(
'`now alias`' `${getPkgName()} alias`
)} will automatically register your domain )} will automatically register your domain
if it's configured with these nameservers (no need to ${chalk.dim( if it's configured with these nameservers (no need to ${chalk.dim(
'`domain add`' '`domain add`'
@@ -67,7 +70,7 @@ const help = () => {
'`1584722256178`' '`1584722256178`'
)} is the time in milliseconds since the UNIX epoch. )} is the time in milliseconds since the UNIX epoch.
${chalk.cyan(`$ now domains ls --next 1584722256178`)} ${chalk.cyan(`$ ${getPkgName()} domains ls --next 1584722256178`)}
`); `);
}; };

View File

@@ -3,7 +3,6 @@ import { DomainNotFound, DomainPermissionDenied } from '../../util/errors-ts';
import { NowContext } from '../../types'; import { NowContext } from '../../types';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import Client from '../../util/client'; import Client from '../../util/client';
import cmd from '../../util/output/cmd';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
import dnsTable from '../../util/format-dns-table'; import dnsTable from '../../util/format-dns-table';
import formatDate from '../../util/format-date'; import formatDate from '../../util/format-date';
@@ -11,6 +10,7 @@ import formatNSTable from '../../util/format-ns-table';
import getDomainByName from '../../util/domains/get-domain-by-name'; import getDomainByName from '../../util/domains/get-domain-by-name';
import getScope from '../../util/get-scope'; import getScope from '../../util/get-scope';
import getDomainPrice from '../../util/domains/get-domain-price'; import getDomainPrice from '../../util/domains/get-domain-price';
import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
@@ -48,14 +48,16 @@ export default async function inspect(
const inspectStamp = stamp(); const inspectStamp = stamp();
if (!domainName) { if (!domainName) {
output.error(`${cmd('now domains inspect <domain>')} expects one argument`); output.error(
`${getCommandName(`domains inspect <domain>`)} expects one argument`
);
return 1; return 1;
} }
if (args.length !== 1) { if (args.length !== 1) {
output.error( output.error(
`Invalid number of arguments. Usage: ${chalk.cyan( `Invalid number of arguments. Usage: ${chalk.cyan(
'`now domains inspect <domain>`' `${getCommandName('domains inspect <domain>')}`
)}` )}`
); );
return 1; return 1;
@@ -72,7 +74,7 @@ export default async function inspect(
output.error( output.error(
`Domain not found by "${domainName}" under ${chalk.bold(contextName)}` `Domain not found by "${domainName}" under ${chalk.bold(contextName)}`
); );
output.log(`Run ${cmd('now domains ls')} to see your domains.`); output.log(`Run ${getCommandName(`domains ls`)} to see your domains.`);
return 1; return 1;
} }
@@ -82,7 +84,7 @@ export default async function inspect(
contextName contextName
)}` )}`
); );
output.log(`Run ${cmd('now domains ls')} to see your domains.`); output.log(`Run ${getCommandName(`domains ls`)} to see your domains.`);
return 1; return 1;
} }
@@ -169,8 +171,8 @@ export default async function inspect(
` We will run a verification for you and you will receive an email upon completion.\n` ` We will run a verification for you and you will receive an email upon completion.\n`
); );
output.print( output.print(
` If you want to force running a verification, you can run ${cmd( ` If you want to force running a verification, you can run ${getCommandName(
'now domains verify <domain>' `domains verify <domain>`
)}\n` )}\n`
); );
output.print(' Read more: https://err.sh/now/domain-verification\n\n'); output.print(' Read more: https://err.sh/now/domain-verification\n\n');

View File

@@ -10,7 +10,7 @@ import strlen from '../../util/strlen';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import { Domain, NowContext } from '../../types'; import { Domain, NowContext } from '../../types';
import getCommandFlags from '../../util/get-command-flags'; import getCommandFlags from '../../util/get-command-flags';
import cmd from '../../util/output/cmd'; import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
@@ -53,7 +53,9 @@ export default async function ls(
if (args.length !== 0) { if (args.length !== 0) {
output.error( output.error(
`Invalid number of arguments. Usage: ${chalk.cyan('`now domains ls`')}` `Invalid number of arguments. Usage: ${chalk.cyan(
`${getCommandName('domains ls')}`
)}`
); );
return 1; return 1;
} }
@@ -73,8 +75,8 @@ export default async function ls(
if (pagination && pagination.count === 20) { if (pagination && pagination.count === 20) {
const flags = getCommandFlags(opts, ['_', '--next']); const flags = getCommandFlags(opts, ['_', '--next']);
output.log( output.log(
`To display the next page run ${cmd( `To display the next page run ${getCommandName(
`now domains ls${flags} --next ${pagination.next}` `domains ls${flags} --next ${pagination.next}`
)}` )}`
); );
} }

View File

@@ -5,7 +5,6 @@ import { NowContext, User, Team } from '../../types';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import * as ERRORS from '../../util/errors-ts'; import * as ERRORS from '../../util/errors-ts';
import Client from '../../util/client'; import Client from '../../util/client';
import cmd from '../../util/output/cmd';
import getScope from '../../util/get-scope'; import getScope from '../../util/get-scope';
import withSpinner from '../../util/with-spinner'; import withSpinner from '../../util/with-spinner';
import moveOutDomain from '../../util/domains/move-out-domain'; import moveOutDomain from '../../util/domains/move-out-domain';
@@ -16,6 +15,7 @@ import getDomainAliases from '../../util/alias/get-domain-aliases';
import getDomainByName from '../../util/domains/get-domain-by-name'; import getDomainByName from '../../util/domains/get-domain-by-name';
import promptBool from '../../util/input/prompt-bool'; import promptBool from '../../util/input/prompt-bool';
import getTeams from '../../util/get-teams'; import getTeams from '../../util/get-teams';
import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
@@ -53,7 +53,9 @@ export default async function move(
const { domainName, destination } = await getArgs(args); const { domainName, destination } = await getArgs(args);
if (!isRootDomain(domainName)) { if (!isRootDomain(domainName)) {
output.error( output.error(
`Invalid domain name "${domainName}". Run ${cmd('now domains --help')}` `Invalid domain name "${domainName}". Run ${getCommandName(
`domains --help`
)}`
); );
return 1; return 1;
} }
@@ -61,7 +63,7 @@ export default async function move(
const domain = await getDomainByName(client, contextName, domainName); const domain = await getDomainByName(client, contextName, domainName);
if (domain instanceof ERRORS.DomainNotFound) { if (domain instanceof ERRORS.DomainNotFound) {
output.error(`Domain not found under ${chalk.bold(contextName)}`); output.error(`Domain not found under ${chalk.bold(contextName)}`);
output.log(`Run ${cmd('now domains ls')} to see your domains.`); output.log(`Run ${getCommandName(`domains ls`)} to see your domains.`);
return 1; return 1;
} }
if (domain instanceof ERRORS.DomainPermissionDenied) { if (domain instanceof ERRORS.DomainPermissionDenied) {
@@ -100,7 +102,7 @@ export default async function move(
output.warn( output.warn(
`This domain's ${chalk.bold( `This domain's ${chalk.bold(
plural('alias', aliases.length, true) plural('alias', aliases.length, true)
)} will be removed. Run ${chalk.dim('`now alias ls`')} to list them.` )} will be removed. Run ${getCommandName(`alias ls`)} to list them.`
); );
if ( if (
!(await promptBool( !(await promptBool(
@@ -140,7 +142,7 @@ export default async function move(
} }
if (moveTokenResult instanceof ERRORS.DomainNotFound) { if (moveTokenResult instanceof ERRORS.DomainNotFound) {
output.error(`Domain not found under ${chalk.bold(contextName)}`); output.error(`Domain not found under ${chalk.bold(contextName)}`);
output.log(`Run ${cmd('now domains ls')} to see your domains.`); output.log(`Run ${getCommandName(`domains ls`)} to see your domains.`);
return 1; return 1;
} }
if (moveTokenResult instanceof ERRORS.DomainPermissionDenied) { if (moveTokenResult instanceof ERRORS.DomainPermissionDenied) {

View File

@@ -5,7 +5,6 @@ import { DomainNotFound, DomainPermissionDenied } from '../../util/errors-ts';
import { NowContext, Domain } from '../../types'; import { NowContext, Domain } from '../../types';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import Client from '../../util/client'; import Client from '../../util/client';
import cmd from '../../util/output/cmd';
import deleteCertById from '../../util/certs/delete-cert-by-id'; import deleteCertById from '../../util/certs/delete-cert-by-id';
import getDomainByName from '../../util/domains/get-domain-by-name'; import getDomainByName from '../../util/domains/get-domain-by-name';
import getScope from '../../util/get-scope'; import getScope from '../../util/get-scope';
@@ -16,6 +15,7 @@ import * as ERRORS from '../../util/errors-ts';
import param from '../../util/output/param'; import param from '../../util/output/param';
import promptBool from '../../util/input/prompt-bool'; import promptBool from '../../util/input/prompt-bool';
import setCustomSuffix from '../../util/domains/set-custom-suffix'; import setCustomSuffix from '../../util/domains/set-custom-suffix';
import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
@@ -51,14 +51,16 @@ export default async function rm(
} }
if (!domainName) { if (!domainName) {
output.error(`${cmd('now domains rm <domain>')} expects one argument`); output.error(
`${getCommandName(`domains rm <domain>`)} expects one argument`
);
return 1; return 1;
} }
if (args.length !== 1) { if (args.length !== 1) {
output.error( output.error(
`Invalid number of arguments. Usage: ${chalk.cyan( `Invalid number of arguments. Usage: ${chalk.cyan(
'`now domains rm <domain>`' `${getCommandName('domains rm <domain>')}`
)}` )}`
); );
return 1; return 1;
@@ -69,7 +71,7 @@ export default async function rm(
output.error( output.error(
`Domain not found by "${domainName}" under ${chalk.bold(contextName)}` `Domain not found by "${domainName}" under ${chalk.bold(contextName)}`
); );
output.log(`Run ${cmd('now domains ls')} to see your domains.`); output.log(`Run ${getCommandName(`domains ls`)} to see your domains.`);
return 1; return 1;
} }
@@ -79,7 +81,7 @@ export default async function rm(
contextName contextName
)}` )}`
); );
output.log(`Run ${cmd('now domains ls')} to see your domains.`); output.log(`Run ${getCommandName(`domains ls`)} to see your domains.`);
return 1; return 1;
} }
@@ -146,7 +148,7 @@ async function removeDomain(
if (removeResult instanceof ERRORS.DomainNotFound) { if (removeResult instanceof ERRORS.DomainNotFound) {
output.error(`Domain not found under ${chalk.bold(contextName)}`); output.error(`Domain not found under ${chalk.bold(contextName)}`);
output.log(`Run ${cmd('now domains ls')} to see your domains.`); output.log(`Run ${getCommandName(`domains ls`)} to see your domains.`);
return 1; return 1;
} }
@@ -204,7 +206,7 @@ async function removeDomain(
output.warn( output.warn(
`This domain's ${chalk.bold( `This domain's ${chalk.bold(
plural('alias', aliases.length, true) plural('alias', aliases.length, true)
)} will be removed. Run ${chalk.dim('`now alias ls`')} to list them.` )} will be removed. Run ${getCommandName(`alias ls`)} to list them.`
); );
} }
@@ -212,7 +214,7 @@ async function removeDomain(
output.warn( output.warn(
`This domain's ${chalk.bold( `This domain's ${chalk.bold(
plural('certificate', certs.length, true) plural('certificate', certs.length, true)
)} will be removed. Run ${chalk.dim('`now cert ls`')} to list them.` )} will be removed. Run ${getCommandName(`cert ls`)} to list them.`
); );
} }

View File

@@ -4,7 +4,6 @@ import { NowContext } from '../../types';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import * as ERRORS from '../../util/errors-ts'; import * as ERRORS from '../../util/errors-ts';
import Client from '../../util/client'; import Client from '../../util/client';
import cmd from '../../util/output/cmd';
import getScope from '../../util/get-scope'; import getScope from '../../util/get-scope';
import param from '../../util/output/param'; import param from '../../util/output/param';
import transferInDomain from '../../util/domains/transfer-in-domain'; import transferInDomain from '../../util/domains/transfer-in-domain';
@@ -15,6 +14,7 @@ import getDomainPrice from '../../util/domains/get-domain-price';
import checkTransfer from '../../util/domains/check-transfer'; import checkTransfer from '../../util/domains/check-transfer';
import promptBool from '../../util/input/prompt-bool'; import promptBool from '../../util/input/prompt-bool';
import isRootDomain from '../../util/is-root-domain'; import isRootDomain from '../../util/is-root-domain';
import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
@@ -50,14 +50,16 @@ export default async function transferIn(
const [domainName] = args; const [domainName] = args;
if (!domainName) { if (!domainName) {
output.error(`Missing domain name. Run ${cmd('now domains --help')}`); output.error(
`Missing domain name. Run ${getCommandName(`domains --help`)}`
);
return 1; return 1;
} }
if (!isRootDomain(domainName)) { if (!isRootDomain(domainName)) {
output.error( output.error(
`Invalid domain name ${param(domainName)}. Run ${cmd( `Invalid domain name ${param(domainName)}. Run ${getCommandName(
'now domains --help' `domains --help`
)}` )}`
); );
return 1; return 1;
@@ -127,8 +129,8 @@ export default async function transferIn(
if (transferInResult instanceof ERRORS.SourceNotFound) { if (transferInResult instanceof ERRORS.SourceNotFound) {
output.error( output.error(
`Could not purchase domain. Please add a payment method using ${cmd( `Could not purchase domain. Please add a payment method using ${getCommandName(
'now billing add' `billing add`
)}.` )}.`
); );
return 1; return 1;
@@ -157,6 +159,8 @@ export default async function transferIn(
` To transfer with previous DNS records, export the zone file from your previous registrar.\n` ` To transfer with previous DNS records, export the zone file from your previous registrar.\n`
); );
output.print(` Then import it to Vercel DNS by using:\n`); output.print(` Then import it to Vercel DNS by using:\n`);
output.print(` ${cmd(`now dns import ${domainName} <zonefile>`)}\n\n`); output.print(
` ${getCommandName(`dns import ${domainName} <zonefile>`)}\n\n`
);
return 0; return 0;
} }

View File

@@ -3,13 +3,13 @@ import { NowContext } from '../../types';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import * as ERRORS from '../../util/errors-ts'; import * as ERRORS from '../../util/errors-ts';
import Client from '../../util/client'; import Client from '../../util/client';
import cmd from '../../util/output/cmd';
import formatDnsTable from '../../util/format-dns-table'; import formatDnsTable from '../../util/format-dns-table';
import formatNSTable from '../../util/format-ns-table'; import formatNSTable from '../../util/format-ns-table';
import getDomainByName from '../../util/domains/get-domain-by-name'; import getDomainByName from '../../util/domains/get-domain-by-name';
import getScope from '../../util/get-scope'; import getScope from '../../util/get-scope';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
import verifyDomain from '../../util/domains/verify-domain'; import verifyDomain from '../../util/domains/verify-domain';
import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
@@ -46,14 +46,16 @@ export default async function verify(
const [domainName] = args; const [domainName] = args;
if (!domainName) { if (!domainName) {
output.error(`${cmd('now domains verify <domain>')} expects one argument`); output.error(
`${getCommandName(`domains verify <domain>`)} expects one argument`
);
return 1; return 1;
} }
if (args.length !== 1) { if (args.length !== 1) {
output.error( output.error(
`Invalid number of arguments. Usage: ${chalk.cyan( `Invalid number of arguments. Usage: ${chalk.cyan(
'`now domains verify <domain>`' `${getCommandName('domains verify <domain>')}`
)}` )}`
); );
return 1; return 1;
@@ -64,7 +66,7 @@ export default async function verify(
output.error( output.error(
`Domain not found by "${domainName}" under ${chalk.bold(contextName)}` `Domain not found by "${domainName}" under ${chalk.bold(contextName)}`
); );
output.log(`Run ${cmd('now domains ls')} to see your domains.`); output.log(`Run ${getCommandName(`domains ls`)} to see your domains.`);
return 1; return 1;
} }
@@ -74,7 +76,7 @@ export default async function verify(
contextName contextName
)}` )}`
); );
output.log(`Run ${cmd('now domains ls')} to see your domains.`); output.log(`Run ${getCommandName(`domains ls`)} to see your domains.`);
return 1; return 1;
} }
@@ -111,8 +113,8 @@ export default async function verify(
)}\n\n` )}\n\n`
); );
output.print( output.print(
` Once your domain uses either the nameservers or the TXT DNS record from above, run again ${cmd( ` Once your domain uses either the nameservers or the TXT DNS record from above, run again ${getCommandName(
'now domains verify <domain>' `domains verify <domain>`
)}.\n` )}.\n`
); );
output.print( output.print(
@@ -137,8 +139,8 @@ export default async function verify(
)} was verified using DNS TXT record. ${verifyStamp()}` )} was verified using DNS TXT record. ${verifyStamp()}`
); );
output.print( output.print(
` You can verify with nameservers too. Run ${cmd( ` You can verify with nameservers too. Run ${getCommandName(
`now domains inspect ${domain.name}` `domains inspect ${domain.name}`
)} to find out the intended set.\n` )} to find out the intended set.\n`
); );
return 0; return 0;

View File

@@ -1,10 +1,9 @@
import chalk from 'chalk'; import chalk from 'chalk';
import inquirer from 'inquirer'; import inquirer from 'inquirer';
import { NowContext, ProjectEnvTarget } from '../../types'; import { ProjectEnvTarget, Project } from '../../types';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import Client from '../../util/client'; import Client from '../../util/client';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
import { getLinkedProject } from '../../util/projects/link';
import addEnvRecord from '../../util/env/add-env-record'; import addEnvRecord from '../../util/env/add-env-record';
import getEnvVariables from '../../util/env/get-env-records'; import getEnvVariables from '../../util/env/get-env-records';
import { import {
@@ -13,160 +12,137 @@ import {
getEnvTargetChoices, getEnvTargetChoices,
} from '../../util/env/env-target'; } from '../../util/env/env-target';
import readStandardInput from '../../util/input/read-standard-input'; import readStandardInput from '../../util/input/read-standard-input';
import cmd from '../../util/output/cmd';
import param from '../../util/output/param'; import param from '../../util/output/param';
import withSpinner from '../../util/with-spinner'; import withSpinner from '../../util/with-spinner';
import { emoji, prependEmoji } from '../../util/emoji'; import { emoji, prependEmoji } from '../../util/emoji';
import { isKnownError } from '../../util/env/known-error'; import { isKnownError } from '../../util/env/known-error';
import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
}; };
export default async function add( export default async function add(
ctx: NowContext, client: Client,
project: Project,
opts: Options, opts: Options,
args: string[], args: string[],
output: Output output: Output
) { ) {
const { const stdInput = await readStandardInput();
authConfig: { token }, let [envName, envTarget] = args;
config,
} = ctx;
const { currentTeam } = config;
const { apiUrl } = ctx;
const debug = opts['--debug'];
const client = new Client({ apiUrl, token, currentTeam, debug });
const link = await getLinkedProject(output, client);
if (link.status === 'error') { if (args.length > 2) {
return link.exitCode; output.error(
} else if (link.status === 'not_linked') { `Invalid number of arguments. Usage: ${getCommandName(
output.print( `env add <name> ${getEnvTargetPlaceholder()}`
`${chalk.red( )}`
'Error!'
)} Your codebase isnt linked to a project on Vercel. Run ${cmd(
'now'
)} to link it.\n`
); );
return 1; return 1;
} else {
const { project } = link;
const stdInput = await readStandardInput();
let [envName, envTarget] = args;
if (args.length > 2) {
output.error(
`Invalid number of arguments. Usage: ${cmd(
`now env add <name> ${getEnvTargetPlaceholder()}`
)}`
);
return 1;
}
if (stdInput && (!envName || !envTarget)) {
output.error(
`Invalid number of arguments. Usage: ${cmd(
`now env add <name> <target> < <file>`
)}`
);
return 1;
}
let envTargets: ProjectEnvTarget[] = [];
if (envTarget) {
if (!isValidEnvTarget(envTarget)) {
output.error(
`The Environment ${param(
envTarget
)} is invalid. It must be one of: ${getEnvTargetPlaceholder()}.`
);
return 1;
}
envTargets.push(envTarget);
}
while (!envName) {
const { inputName } = await inquirer.prompt({
type: 'input',
name: 'inputName',
message: `Whats the name of the variable?`,
});
envName = inputName;
if (!inputName) {
output.error('Name cannot be empty');
}
}
const envs = await getEnvVariables(output, client, project.id);
const existing = new Set(
envs.filter(r => r.key === envName).map(r => r.target)
);
const choices = getEnvTargetChoices().filter(c => !existing.has(c.value));
if (choices.length === 0) {
output.error(
`The variable ${param(
envName
)} has already been added to all Environments. To remove, run ${cmd(
`now env rm ${envName}`
)}.`
);
return 1;
}
let envValue: string;
if (stdInput) {
envValue = stdInput;
} else {
const { inputValue } = await inquirer.prompt({
type: 'password',
name: 'inputValue',
message: `Whats the value of ${envName}?`,
});
envValue = inputValue || '';
}
while (envTargets.length === 0) {
const { inputTargets } = await inquirer.prompt({
name: 'inputTargets',
type: 'checkbox',
message: `Add ${envName} to which Environments (select multiple)?`,
choices,
});
envTargets = inputTargets;
if (inputTargets.length === 0) {
output.error('Please select at least one Environment');
}
}
const addStamp = stamp();
try {
await withSpinner('Saving', () =>
addEnvRecord(output, client, project.id, envName, envValue, envTargets)
);
} catch (error) {
if (isKnownError(error) && error.serverMessage) {
output.error(error.serverMessage);
return 1;
}
throw error;
}
output.print(
`${prependEmoji(
`Added Environment Variable ${chalk.bold(
envName
)} to Project ${chalk.bold(project.name)} ${chalk.gray(addStamp())}`,
emoji('success')
)}\n`
);
return 0;
} }
if (stdInput && (!envName || !envTarget)) {
output.error(
`Invalid number of arguments. Usage: ${getCommandName(
`env add <name> <target> < <file>`
)}`
);
return 1;
}
let envTargets: ProjectEnvTarget[] = [];
if (envTarget) {
if (!isValidEnvTarget(envTarget)) {
output.error(
`The Environment ${param(
envTarget
)} is invalid. It must be one of: ${getEnvTargetPlaceholder()}.`
);
return 1;
}
envTargets.push(envTarget);
}
while (!envName) {
const { inputName } = await inquirer.prompt({
type: 'input',
name: 'inputName',
message: `Whats the name of the variable?`,
});
envName = inputName;
if (!inputName) {
output.error('Name cannot be empty');
}
}
const envs = await getEnvVariables(output, client, project.id, 4);
const existing = new Set(
envs.filter(r => r.key === envName).map(r => r.target)
);
const choices = getEnvTargetChoices().filter(c => !existing.has(c.value));
if (choices.length === 0) {
output.error(
`The variable ${param(
envName
)} has already been added to all Environments. To remove, run ${getCommandName(
`env rm ${envName}`
)}.`
);
return 1;
}
let envValue: string;
if (stdInput) {
envValue = stdInput;
} else {
const { inputValue } = await inquirer.prompt({
type: 'password',
name: 'inputValue',
message: `Whats the value of ${envName}?`,
});
envValue = inputValue || '';
}
while (envTargets.length === 0) {
const { inputTargets } = await inquirer.prompt({
name: 'inputTargets',
type: 'checkbox',
message: `Add ${envName} to which Environments (select multiple)?`,
choices,
});
envTargets = inputTargets;
if (inputTargets.length === 0) {
output.error('Please select at least one Environment');
}
}
const addStamp = stamp();
try {
await withSpinner('Saving', () =>
addEnvRecord(output, client, project.id, envName, envValue, envTargets)
);
} catch (error) {
if (isKnownError(error) && error.serverMessage) {
output.error(error.serverMessage);
return 1;
}
throw error;
}
output.print(
`${prependEmoji(
`Added Environment Variable ${chalk.bold(
envName
)} to Project ${chalk.bold(project.name)} ${chalk.gray(addStamp())}`,
emoji('success')
)}\n`
);
return 0;
} }

View File

@@ -6,8 +6,11 @@ import getArgs from '../../util/get-args';
import getSubcommand from '../../util/get-subcommand'; import getSubcommand from '../../util/get-subcommand';
import getInvalidSubcommand from '../../util/get-invalid-subcommand'; import getInvalidSubcommand from '../../util/get-invalid-subcommand';
import { getEnvTargetPlaceholder } from '../../util/env/env-target'; import { getEnvTargetPlaceholder } from '../../util/env/env-target';
import { getLinkedProject } from '../../util/projects/link';
import Client from '../../util/client';
import handleError from '../../util/handle-error'; import handleError from '../../util/handle-error';
import logo from '../../util/output/logo'; import logo from '../../util/output/logo';
import { getCommandName, getPkgName } from '../../util/pkg-name';
import add from './add'; import add from './add';
import pull from './pull'; import pull from './pull';
@@ -17,7 +20,7 @@ import rm from './rm';
const help = () => { const help = () => {
const placeholder = getEnvTargetPlaceholder(); const placeholder = getEnvTargetPlaceholder();
console.log(` console.log(`
${chalk.bold(`${logo} now env`)} [options] <command> ${chalk.bold(`${logo} ${getPkgName()} env`)} [options] <command>
${chalk.dim('Commands:')} ${chalk.dim('Commands:')}
@@ -31,42 +34,51 @@ const help = () => {
-h, --help Output usage information -h, --help Output usage information
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
-d, --debug Debug mode [off] -d, --debug Debug mode [off]
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline( -t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
'TOKEN' 'TOKEN'
)} Login token )} Login token
-N, --next Show next page of results
${chalk.dim('Examples:')} ${chalk.dim('Examples:')}
${chalk.gray('')} Add a new variable to multiple Environments ${chalk.gray('')} Add a new variable to multiple Environments
${chalk.cyan('$ now env add <name>')} ${chalk.cyan(`$ ${getPkgName()} env add <name>`)}
${chalk.cyan('$ now env add API_TOKEN')} ${chalk.cyan(`$ ${getPkgName()} env add API_TOKEN`)}
${chalk.gray('')} Add a new variable for a specific Environment ${chalk.gray('')} Add a new variable for a specific Environment
${chalk.cyan(`$ now env add <name> ${placeholder}`)} ${chalk.cyan(`$ ${getPkgName()} env add <name> ${placeholder}`)}
${chalk.cyan('$ now env add DB_CONNECTION production')} ${chalk.cyan(`$ ${getPkgName()} env add DB_CONNECTION production`)}
${chalk.gray('')} Add a new Environment Variable from stdin ${chalk.gray('')} Add a new Environment Variable from stdin
${chalk.cyan(`$ cat <file> | now env add <name> ${placeholder}`)} ${chalk.cyan(
${chalk.cyan('$ cat ~/.npmrc | now env add NPM_RC preview')} `$ cat <file> | ${getPkgName()} env add <name> ${placeholder}`
${chalk.cyan('$ now env add DB_PASS production < secret.txt')} )}
${chalk.cyan(`$ cat ~/.npmrc | ${getPkgName()} env add NPM_RC preview`)}
${chalk.cyan(`$ ${getPkgName()} env add DB_PASS production < secret.txt`)}
${chalk.gray('')} Remove an variable from multiple Environments ${chalk.gray('')} Remove an variable from multiple Environments
${chalk.cyan('$ now env rm <name>')} ${chalk.cyan(`$ ${getPkgName()} env rm <name>`)}
${chalk.cyan('$ now env rm API_TOKEN')} ${chalk.cyan(`$ ${getPkgName()} env rm API_TOKEN`)}
${chalk.gray('')} Remove a variable from a specific Environment ${chalk.gray('')} Remove a variable from a specific Environment
${chalk.cyan(`$ now env rm <name> ${placeholder}`)} ${chalk.cyan(`$ ${getPkgName()} env rm <name> ${placeholder}`)}
${chalk.cyan('$ now env rm NPM_RC preview')} ${chalk.cyan(`$ ${getPkgName()} env rm NPM_RC preview`)}
${chalk.gray('')} Paginate results, where ${chalk.dim(
'`1584722256178`'
)} is the time in milliseconds since the UNIX epoch.
${chalk.cyan(`$ ${getPkgName()} env ls --next 1584722256178`)}
`); `);
}; };
@@ -84,6 +96,8 @@ export default async function main(ctx: NowContext) {
argv = getArgs(ctx.argv.slice(2), { argv = getArgs(ctx.argv.slice(2), {
'--yes': Boolean, '--yes': Boolean,
'-y': '--yes', '-y': '--yes',
'--next': Number,
'-N': '--next',
}); });
} catch (error) { } catch (error) {
handleError(error); handleError(error);
@@ -95,20 +109,40 @@ export default async function main(ctx: NowContext) {
return 2; return 2;
} }
const output = createOutput({ debug: argv['--debug'] }); const debug = argv['--debug'];
const output = createOutput({ debug });
const { subcommand, args } = getSubcommand(argv._.slice(1), COMMAND_CONFIG); const { subcommand, args } = getSubcommand(argv._.slice(1), COMMAND_CONFIG);
switch (subcommand) { const {
case 'ls': authConfig: { token },
return ls(ctx, argv, args, output); config,
case 'add': } = ctx;
return add(ctx, argv, args, output); const { currentTeam } = config;
case 'rm': const { apiUrl } = ctx;
return rm(ctx, argv, args, output); const client = new Client({ apiUrl, token, currentTeam, debug });
case 'pull': const link = await getLinkedProject(output, client);
return pull(ctx, argv, args, output); if (link.status === 'error') {
default: return link.exitCode;
output.error(getInvalidSubcommand(COMMAND_CONFIG)); } else if (link.status === 'not_linked') {
help(); output.error(
return 2; `Your codebase isnt linked to a project on Vercel. Run ${getCommandName()} to link it.`
);
return 1;
} else {
const { project, org } = link;
client.currentTeam = org.type === 'team' ? org.id : undefined;
switch (subcommand) {
case 'ls':
return ls(client, project, argv, args, output);
case 'add':
return add(client, project, argv, args, output);
case 'rm':
return rm(client, project, argv, args, output);
case 'pull':
return pull(client, project, argv, args, output);
default:
output.error(getInvalidSubcommand(COMMAND_CONFIG));
help();
return 2;
}
} }
} }

View File

@@ -1,8 +1,7 @@
import chalk from 'chalk'; import chalk from 'chalk';
import ms from 'ms'; import ms from 'ms';
import plural from 'pluralize';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import { ProjectEnvVariable, ProjectEnvTarget, NowContext } from '../../types'; import { ProjectEnvVariable, ProjectEnvTarget, Project } from '../../types';
import Client from '../../util/client'; import Client from '../../util/client';
import formatTable from '../../util/format-table'; import formatTable from '../../util/format-table';
import getEnvVariables from '../../util/env/get-env-records'; import getEnvVariables from '../../util/env/get-env-records';
@@ -10,82 +9,78 @@ import {
isValidEnvTarget, isValidEnvTarget,
getEnvTargetPlaceholder, getEnvTargetPlaceholder,
} from '../../util/env/env-target'; } from '../../util/env/env-target';
import { getLinkedProject } from '../../util/projects/link';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
import cmd from '../../util/output/cmd';
import param from '../../util/output/param'; import param from '../../util/output/param';
import getCommandFlags from '../../util/get-command-flags';
import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
'--next'?: number;
}; };
export default async function ls( export default async function ls(
ctx: NowContext, client: Client,
project: Project,
opts: Options, opts: Options,
args: string[], args: string[],
output: Output output: Output
) { ) {
const { const { '--next': nextTimestamp } = opts;
authConfig: { token },
config,
} = ctx;
const { currentTeam } = config;
const { apiUrl } = ctx;
const debug = opts['--debug'];
const client = new Client({ apiUrl, token, currentTeam, debug });
const link = await getLinkedProject(output, client);
if (link.status === 'error') { if (args.length > 1) {
return link.exitCode; output.error(
} else if (link.status === 'not_linked') { `Invalid number of arguments. Usage: ${getCommandName(
output.print( `env ls ${getEnvTargetPlaceholder()}`
`${chalk.red( )}`
'Error!'
)} Your codebase isnt linked to a project on Vercel. Run ${cmd(
'now'
)} to link it.\n`
); );
return 1; return 1;
} else {
if (args.length > 1) {
output.error(
`Invalid number of arguments. Usage: ${cmd(
`now env ls ${getEnvTargetPlaceholder()}`
)}`
);
return 1;
}
const { project } = link;
const envTarget = args[0] as ProjectEnvTarget | undefined;
if (!isValidEnvTarget(envTarget)) {
output.error(
`The Environment ${param(
envTarget
)} is invalid. It must be one of: ${getEnvTargetPlaceholder()}.`
);
return 1;
}
const lsStamp = stamp();
const records = await getEnvVariables(
output,
client,
project.id,
envTarget
);
output.log(
`${plural(
'Environment Variable',
records.length,
true
)} found in Project ${chalk.bold(project.name)} ${chalk.gray(lsStamp())}`
);
console.log(getTable(records));
return 0;
} }
const envTarget = args[0] as ProjectEnvTarget | undefined;
if (!isValidEnvTarget(envTarget)) {
output.error(
`The Environment ${param(
envTarget
)} is invalid. It must be one of: ${getEnvTargetPlaceholder()}.`
);
return 1;
}
const lsStamp = stamp();
if (typeof nextTimestamp !== 'undefined' && Number.isNaN(nextTimestamp)) {
output.error('Please provide a number for flag --next');
return 1;
}
const data = await getEnvVariables(
output,
client,
project.id,
5,
envTarget,
nextTimestamp
);
const { envs: records, pagination } = data;
output.log(
`${
records.length > 0 ? 'Environment Variables' : 'No Environment Variables'
} found in Project ${chalk.bold(project.name)} ${chalk.gray(lsStamp())}`
);
console.log(getTable(records));
if (pagination && pagination.count === 20) {
const flags = getCommandFlags(opts, ['_', '--next']);
output.log(
`To display the next page run ${getCommandName(
`env ls${flags} --next ${pagination.next}`
)}`
);
}
return 0;
} }
function getTable(records: ProjectEnvVariable[]) { function getTable(records: ProjectEnvVariable[]) {

View File

@@ -1,18 +1,17 @@
import chalk from 'chalk'; import chalk from 'chalk';
import { NowContext, ProjectEnvTarget } from '../../types'; import { ProjectEnvTarget, Project } from '../../types';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import promptBool from '../../util/prompt-bool'; import promptBool from '../../util/prompt-bool';
import Client from '../../util/client'; import Client from '../../util/client';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
import getEnvVariables from '../../util/env/get-env-records'; import getEnvVariables from '../../util/env/get-env-records';
import getDecryptedSecret from '../../util/env/get-decrypted-secret'; import getDecryptedSecret from '../../util/env/get-decrypted-secret';
import { getLinkedProject } from '../../util/projects/link';
import cmd from '../../util/output/cmd';
import param from '../../util/output/param'; import param from '../../util/output/param';
import withSpinner from '../../util/with-spinner'; import withSpinner from '../../util/with-spinner';
import { join } from 'path'; import { join } from 'path';
import { promises, existsSync } from 'fs'; import { promises, existsSync } from 'fs';
import { emoji, prependEmoji } from '../../util/emoji'; import { emoji, prependEmoji } from '../../util/emoji';
import { getCommandName } from '../../util/pkg-name';
const { writeFile } = promises; const { writeFile } = promises;
type Options = { type Options = {
@@ -21,95 +20,72 @@ type Options = {
}; };
export default async function pull( export default async function pull(
ctx: NowContext, client: Client,
project: Project,
opts: Options, opts: Options,
args: string[], args: string[],
output: Output output: Output
) { ) {
const { if (args.length > 1) {
authConfig: { token }, output.error(
config, `Invalid number of arguments. Usage: ${getCommandName(`env pull <file>`)}`
} = ctx;
const { currentTeam } = config;
const { apiUrl } = ctx;
const debug = opts['--debug'];
const client = new Client({ apiUrl, token, currentTeam, debug });
const link = await getLinkedProject(output, client);
if (link.status === 'error') {
return link.exitCode;
} else if (link.status === 'not_linked') {
output.print(
`${chalk.red(
'Error!'
)} Your codebase isnt linked to a project on Vercel. Run ${cmd(
'now'
)} to link it.\n`
); );
return 1; return 1;
} else { }
if (args.length > 1) {
output.error(
`Invalid number of arguments. Usage: ${cmd('now env pull <file>')}`
);
return 1;
}
const { project } = link; const [filename = '.env'] = args;
const [filename = '.env'] = args; const fullPath = join(process.cwd(), filename);
const fullPath = join(process.cwd(), filename); const exists = existsSync(fullPath);
const exists = existsSync(fullPath); const skipConfirmation = opts['--yes'];
const skipConfirmation = opts['--yes'];
if ( if (
exists && exists &&
!skipConfirmation && !skipConfirmation &&
!(await promptBool( !(await promptBool(
output, output,
`Found existing file ${param(filename)}. Do you want to overwrite?` `Found existing file ${param(filename)}. Do you want to overwrite?`
)) ))
) { ) {
output.log('Aborted'); output.log('Aborted');
return 0;
}
output.print(
`Downloading Development Environment Variables for Project ${chalk.bold(
project.name
)}\n`
);
const pullStamp = stamp();
const records = await withSpinner('Downloading', async () => {
const dev = ProjectEnvTarget.Development;
const envs = await getEnvVariables(output, client, project.id, dev);
const values = await Promise.all(
envs.map(env => getDecryptedSecret(output, client, env.value))
);
const results: { key: string; value: string }[] = [];
for (let i = 0; i < values.length; i++) {
results.push({ key: envs[i].key, value: values[i] });
}
return results;
});
const contents =
records
.map(({ key, value }) => `${key}="${escapeValue(value)}"`)
.join('\n') + '\n';
await writeFile(fullPath, contents, 'utf8');
output.print(
`${prependEmoji(
`${exists ? 'Updated' : 'Created'} ${chalk.bold(
filename
)} file ${chalk.gray(pullStamp())}`,
emoji('success')
)}\n`
);
return 0; return 0;
} }
output.print(
`Downloading Development Environment Variables for Project ${chalk.bold(
project.name
)}\n`
);
const pullStamp = stamp();
const records = await withSpinner('Downloading', async () => {
const dev = ProjectEnvTarget.Development;
const envs = await getEnvVariables(output, client, project.id, 4, dev);
const values = await Promise.all(
envs.map(env => getDecryptedSecret(output, client, env.value))
);
const results: { key: string; value: string }[] = [];
for (let i = 0; i < values.length; i++) {
results.push({ key: envs[i].key, value: values[i] });
}
return results;
});
const contents =
records
.map(({ key, value }) => `${key}="${escapeValue(value)}"`)
.join('\n') + '\n';
await writeFile(fullPath, contents, 'utf8');
output.print(
`${prependEmoji(
`${exists ? 'Updated' : 'Created'} ${chalk.bold(
filename
)} file ${chalk.gray(pullStamp())}`,
emoji('success')
)}\n`
);
return 0;
} }
function escapeValue(value: string) { function escapeValue(value: string) {

View File

@@ -1,9 +1,8 @@
import chalk from 'chalk'; import chalk from 'chalk';
import inquirer from 'inquirer'; import inquirer from 'inquirer';
import { NowContext, ProjectEnvTarget } from '../../types'; import { ProjectEnvTarget, Project } from '../../types';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import promptBool from '../../util/prompt-bool'; import promptBool from '../../util/prompt-bool';
import { getLinkedProject } from '../../util/projects/link';
import removeEnvRecord from '../../util/env/remove-env-record'; import removeEnvRecord from '../../util/env/remove-env-record';
import getEnvVariables from '../../util/env/get-env-records'; import getEnvVariables from '../../util/env/get-env-records';
import { import {
@@ -13,11 +12,11 @@ import {
} from '../../util/env/env-target'; } from '../../util/env/env-target';
import Client from '../../util/client'; import Client from '../../util/client';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
import cmd from '../../util/output/cmd';
import param from '../../util/output/param'; import param from '../../util/output/param';
import withSpinner from '../../util/with-spinner'; import withSpinner from '../../util/with-spinner';
import { emoji, prependEmoji } from '../../util/emoji'; import { emoji, prependEmoji } from '../../util/emoji';
import { isKnownError } from '../../util/env/known-error'; import { isKnownError } from '../../util/env/known-error';
import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
@@ -25,144 +24,119 @@ type Options = {
}; };
export default async function rm( export default async function rm(
ctx: NowContext, client: Client,
project: Project,
opts: Options, opts: Options,
args: string[], args: string[],
output: Output output: Output
) { ) {
const { if (args.length > 2) {
authConfig: { token }, output.error(
config, `Invalid number of arguments. Usage: ${getCommandName(
} = ctx; `env rm <name> ${getEnvTargetPlaceholder()}`
const { currentTeam } = config; )}`
const { apiUrl } = ctx;
const debug = opts['--debug'];
const client = new Client({ apiUrl, token, currentTeam, debug });
const link = await getLinkedProject(output, client);
if (link.status === 'error') {
return link.exitCode;
} else if (link.status === 'not_linked') {
output.print(
`${chalk.red(
'Error!'
)} Your codebase isnt linked to a project on Vercel. Run ${cmd(
'now'
)} to link it.\n`
); );
return 1; return 1;
} else { }
if (args.length > 2) {
let [envName, envTarget] = args;
let envTargets: ProjectEnvTarget[] = [];
if (envTarget) {
if (!isValidEnvTarget(envTarget)) {
output.error( output.error(
`Invalid number of arguments. Usage: ${cmd( `The Environment ${param(
`now env rm <name> ${getEnvTargetPlaceholder()}` envTarget
)}` )} is invalid. It must be one of: ${getEnvTargetPlaceholder()}.`
); );
return 1; return 1;
} }
envTargets.push(envTarget);
}
const { project } = link; while (!envName) {
let [envName, envTarget] = args; const { inputName } = await inquirer.prompt({
let envTargets: ProjectEnvTarget[] = []; type: 'input',
name: 'inputName',
message: `Whats the name of the variable?`,
});
if (envTarget) { if (!inputName) {
if (!isValidEnvTarget(envTarget)) { output.error(`Name cannot be empty`);
output.error( continue;
`The Environment ${param(
envTarget
)} is invalid. It must be one of: ${getEnvTargetPlaceholder()}.`
);
return 1;
}
envTargets.push(envTarget);
} }
while (!envName) { envName = inputName;
const { inputName } = await inquirer.prompt({ }
type: 'input',
name: 'inputName',
message: `Whats the name of the variable?`,
});
if (!inputName) { const envs = await getEnvVariables(output, client, project.id, 4);
output.error(`Name cannot be empty`); const existing = new Set(
continue; envs.filter(r => r.key === envName).map(r => r.target)
} );
envName = inputName; if (existing.size === 0) {
} output.error(`The Environment Variable ${param(envName)} was not found.\n`);
return 1;
}
const envs = await getEnvVariables(output, client, project.id); if (envTargets.length === 0) {
const existing = new Set( const choices = getEnvTargetChoices().filter(c => existing.has(c.value));
envs.filter(r => r.key === envName).map(r => r.target) if (choices.length === 0) {
);
if (existing.size === 0) {
output.error( output.error(
`The Environment Variable ${param(envName)} was not found.\n` `The Environment Variable ${param(
);
return 1;
}
if (envTargets.length === 0) {
const choices = getEnvTargetChoices().filter(c => existing.has(c.value));
if (choices.length === 0) {
output.error(
`The Environment Variable ${param(
envName
)} was found but it is not assigned to any Environments.\n`
);
return 1;
} else if (choices.length === 1) {
envTargets = [choices[0].value];
} else {
const { inputTargets } = await inquirer.prompt({
name: 'inputTargets',
type: 'checkbox',
message: `Remove ${envName} from which Environments (select multiple)?`,
choices,
});
envTargets = inputTargets;
}
}
const skipConfirmation = opts['--yes'];
if (
!skipConfirmation &&
!(await promptBool(
output,
`Removing Environment Variable ${param(
envName envName
)} from Project ${chalk.bold(project.name)}. Are you sure?` )} was found but it is not assigned to any Environments.\n`
)) );
) { return 1;
output.log('Aborted'); } else if (choices.length === 1) {
return 0; envTargets = [choices[0].value];
} } else {
const { inputTargets } = await inquirer.prompt({
const rmStamp = stamp(); name: 'inputTargets',
type: 'checkbox',
try { message: `Remove ${envName} from which Environments (select multiple)?`,
await withSpinner('Removing', async () => { choices,
for (const target of envTargets) {
await removeEnvRecord(output, client, project.id, envName, target);
}
}); });
} catch (error) { envTargets = inputTargets;
if (isKnownError(error) && error.serverMessage) {
output.error(error.serverMessage);
return 1;
}
throw error;
} }
}
output.print( const skipConfirmation = opts['--yes'];
`${prependEmoji( if (
`Removed Environment Variable ${chalk.gray(rmStamp())}`, !skipConfirmation &&
emoji('success') !(await promptBool(
)}\n` output,
); `Removing Environment Variable ${param(
envName
)} from Project ${chalk.bold(project.name)}. Are you sure?`
))
) {
output.log('Aborted');
return 0; return 0;
} }
const rmStamp = stamp();
try {
await withSpinner('Removing', async () => {
for (const target of envTargets) {
await removeEnvRecord(output, client, project.id, envName, target);
}
});
} catch (error) {
if (isKnownError(error) && error.serverMessage) {
output.error(error.serverMessage);
return 1;
}
throw error;
}
output.print(
`${prependEmoji(
`Removed Environment Variable ${chalk.gray(rmStamp())}`,
emoji('success')
)}\n`
);
return 0;
} }

View File

@@ -8,14 +8,15 @@ import createOutput from '../../util/output/create-output';
import logo from '../../util/output/logo'; import logo from '../../util/output/logo';
import error from '../../util/output/error'; import error from '../../util/output/error';
import init from './init'; import init from './init';
import { getPkgName } from '../../util/pkg-name';
const COMMAND_CONFIG = { const COMMAND_CONFIG = {
init: ['init'] init: ['init'],
}; };
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now init`)} [example] [dir] [-f | --force] ${chalk.bold(`${logo} ${getPkgName()} init`)} [example] [dir] [-f | --force]
${chalk.dim('Options:')} ${chalk.dim('Options:')}
@@ -27,19 +28,19 @@ const help = () => {
${chalk.gray('')} Choose from all available examples ${chalk.gray('')} Choose from all available examples
${chalk.cyan(`$ now init`)} ${chalk.cyan(`$ ${getPkgName()} init`)}
${chalk.gray('')} Initialize example project into a new directory ${chalk.gray('')} Initialize example project into a new directory
${chalk.cyan(`$ now init <example>`)} ${chalk.cyan(`$ ${getPkgName()} init <example>`)}
${chalk.gray('')} Initialize example project into specified directory ${chalk.gray('')} Initialize example project into specified directory
${chalk.cyan(`$ now init <example> <dir>`)} ${chalk.cyan(`$ ${getPkgName()} init <example> <dir>`)}
${chalk.gray('')} Initialize example project without checking ${chalk.gray('')} Initialize example project without checking
${chalk.cyan(`$ now init <example> --force`)} ${chalk.cyan(`$ ${getPkgName()} init <example> --force`)}
`); `);
}; };
@@ -51,7 +52,7 @@ export default async function main(ctx: NowContext) {
try { try {
argv = getArgs(ctx.argv.slice(2), { argv = getArgs(ctx.argv.slice(2), {
'--force': Boolean, '--force': Boolean,
'-f': Boolean '-f': Boolean,
}); });
args = getSubcommand(argv._.slice(1), COMMAND_CONFIG).args; args = getSubcommand(argv._.slice(1), COMMAND_CONFIG).args;
output = createOutput({ debug: argv['--debug'] }); output = createOutput({ debug: argv['--debug'] });

View File

@@ -15,6 +15,7 @@ import success from '../../util/output/success';
import info from '../../util/output/info'; import info from '../../util/output/info';
import cmd from '../../util/output/cmd'; import cmd from '../../util/output/cmd';
import didYouMean from '../../util/init/did-you-mean'; import didYouMean from '../../util/init/did-you-mean';
import { getCommandName } from '../../util/pkg-name';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
@@ -152,9 +153,11 @@ async function extractExample(
const folderRel = path.relative(process.cwd(), folder); const folderRel = path.relative(process.cwd(), folder);
const deployHint = const deployHint =
folderRel === '' folderRel === ''
? listItem(`To deploy, run ${cmd('now')}.`) ? listItem(`To deploy, run ${getCommandName()}.`)
: listItem( : listItem(
`To deploy, ${cmd(`cd ${folderRel}`)} and run ${cmd('now')}.` `To deploy, ${cmd(
`cd ${folderRel}`
)} and run ${getCommandName()}.`
); );
console.log(success(`${successLog}\n${deployHint}`)); console.log(success(`${successLog}\n${deployHint}`));
return 0; return 0;
@@ -204,8 +207,8 @@ function prepareFolder(cwd: string, folder: string, force?: boolean) {
*/ */
async function guess(exampleList: string[], name: string) { async function guess(exampleList: string[], name: string) {
const GuessError = new Error( const GuessError = new Error(
`No example found for ${chalk.bold(name)}, run ${cmd( `No example found for ${chalk.bold(name)}, run ${getCommandName(
`now init` `init`
)} to see the list of available examples.` )} to see the list of available examples.`
); );

View File

@@ -4,7 +4,6 @@ import getArgs from '../util/get-args';
import buildsList from '../util/output/builds'; import buildsList from '../util/output/builds';
import routesList from '../util/output/routes'; import routesList from '../util/output/routes';
import indent from '../util/output/indent'; import indent from '../util/output/indent';
import cmd from '../util/output/cmd.ts';
import createOutput from '../util/output'; import createOutput from '../util/output';
import Now from '../util'; import Now from '../util';
import logo from '../util/output/logo'; import logo from '../util/output/logo';
@@ -13,22 +12,23 @@ import { handleError } from '../util/error';
import strlen from '../util/strlen.ts'; import strlen from '../util/strlen.ts';
import Client from '../util/client.ts'; import Client from '../util/client.ts';
import getScope from '../util/get-scope.ts'; import getScope from '../util/get-scope.ts';
import { getPkgName, getCommandName } from '../util/pkg-name.ts';
const STATIC = 'STATIC'; const STATIC = 'STATIC';
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now inspect`)} <url> ${chalk.bold(`${logo} ${getPkgName()} inspect`)} <url>
${chalk.dim('Options:')} ${chalk.dim('Options:')}
-h, --help Output usage information -h, --help Output usage information
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline( -t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
'TOKEN' 'TOKEN'
)} Login token )} Login token
@@ -39,11 +39,11 @@ const help = () => {
${chalk.gray('')} Get information about a deployment by its unique URL ${chalk.gray('')} Get information about a deployment by its unique URL
${chalk.cyan('$ now inspect my-deployment-ji2fjij2.now.sh')} ${chalk.cyan(`$ ${getPkgName()} inspect my-deployment-ji2fjij2.now.sh`)}
${chalk.gray('-')} Get information about the deployment an alias points to ${chalk.gray('-')} Get information about the deployment an alias points to
${chalk.cyan('$ now inspect my-deployment.now.sh')} ${chalk.cyan(`$ ${getPkgName()} inspect my-deployment.now.sh`)}
`); `);
}; };
@@ -73,7 +73,7 @@ export default async function main(ctx) {
id = argv._[1]; id = argv._[1];
if (argv._.length !== 2) { if (argv._.length !== 2) {
error(`${cmd('now inspect <url>')} expects exactly one argument`); error(`${getCommandName('inspect <url>')} expects exactly one argument`);
help(); help();
return 1; return 1;
} }

View File

@@ -18,20 +18,21 @@ import toHost from '../util/to-host';
import parseMeta from '../util/parse-meta'; import parseMeta from '../util/parse-meta';
import { isValidName } from '../util/is-valid-name'; import { isValidName } from '../util/is-valid-name';
import getCommandFlags from '../util/get-command-flags'; import getCommandFlags from '../util/get-command-flags';
import { getPkgName, getCommandName } from '../util/pkg-name.ts';
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now list`)} [app] ${chalk.bold(`${logo} ${getPkgName()} list`)} [app]
${chalk.dim('Options:')} ${chalk.dim('Options:')}
-h, --help Output usage information -h, --help Output usage information
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
-d, --debug Debug mode [off] -d, --debug Debug mode [off]
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline( -t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
'TOKEN' 'TOKEN'
@@ -47,27 +48,27 @@ const help = () => {
${chalk.gray('')} List all deployments ${chalk.gray('')} List all deployments
${chalk.cyan('$ now ls')} ${chalk.cyan(`$ ${getPkgName()} ls`)}
${chalk.gray('')} List all deployments for the app ${chalk.dim('`my-app`')} ${chalk.gray('')} List all deployments for the app ${chalk.dim('`my-app`')}
${chalk.cyan('$ now ls my-app')} ${chalk.cyan(`$ ${getPkgName()} ls my-app`)}
${chalk.gray( ${chalk.gray(
'' ''
)} List all deployments and all instances for the app ${chalk.dim('`my-app`')} )} List all deployments and all instances for the app ${chalk.dim('`my-app`')}
${chalk.cyan('$ now ls my-app --all')} ${chalk.cyan(`$ ${getPkgName()} ls my-app --all`)}
${chalk.gray('')} Filter deployments by metadata ${chalk.gray('')} Filter deployments by metadata
${chalk.cyan('$ now ls -m key1=value1 -m key2=value2')} ${chalk.cyan(`$ ${getPkgName()} ls -m key1=value1 -m key2=value2`)}
${chalk.gray('')} Paginate deployments for a project, where ${chalk.dim( ${chalk.gray('')} Paginate deployments for a project, where ${chalk.dim(
'`1584722256178`' '`1584722256178`'
)} is the time in milliseconds since the UNIX epoch. )} is the time in milliseconds since the UNIX epoch.
${chalk.cyan(`$ now ls my-app --next 1584722256178`)} ${chalk.cyan(`$ ${getPkgName()} ls my-app --next 1584722256178`)}
`); `);
}; };
@@ -97,7 +98,7 @@ export default async function main(ctx) {
}); });
if (argv._.length > 2) { if (argv._.length > 2) {
error(`${cmd('now ls [app]')} accepts at most one argument`); error(`${getCommandName('ls [app]')} accepts at most one argument`);
return 1; return 1;
} }
@@ -162,12 +163,14 @@ export default async function main(ctx) {
// Some people are using entire domains as app names, so // Some people are using entire domains as app names, so
// we need to account for this here // we need to account for this here
if (app && toHost(app).endsWith('.now.sh')) { const asHost = app ? toHost(app) : '';
if (asHost.endsWith('.now.sh') || asHost.endsWith('.vercel.app')) {
note( note(
'We suggest using `now inspect <deployment>` for retrieving details about a single deployment' `We suggest using ${getCommandName(
'inspect <deployment>'
)} for retrieving details about a single deployment`
); );
const asHost = toHost(app);
const hostParts = asHost.split('-'); const hostParts = asHost.split('-');
if (hostParts < 2) { if (hostParts < 2) {
@@ -233,7 +236,7 @@ export default async function main(ctx) {
now.close(); now.close();
stopSpinner(); stopSpinner();
log(`Found matching path alias: ${chalk.cyan(item.alias)}`); log(`Found matching path alias: ${chalk.cyan(item.alias)}`);
log(`Please run ${cmd(`now alias ls ${item.alias}`)} instead`); log(`Please run ${getCommandName(`alias ls ${item.alias}`)} instead`);
return 0; return 0;
} }
@@ -283,10 +286,16 @@ export default async function main(ctx) {
// information to help the user find other deployments or instances // information to help the user find other deployments or instances
if (app == null) { if (app == null) {
log( log(
`To list more deployments for a project run ${cmd('now ls [project]')}` `To list more deployments for a project run ${cmd(
`${getCommandName('ls [project]')}`
)}`
); );
} else if (!argv['--all']) { } else if (!argv['--all']) {
log(`To list deployment instances run ${cmd('now ls --all [project]')}`); log(
`To list deployment instances run ${cmd(
`${getCommandName('ls --all [project]')}`
)}`
);
} }
print('\n'); print('\n');
@@ -339,8 +348,8 @@ export default async function main(ctx) {
if (pagination && pagination.count === 20) { if (pagination && pagination.count === 20) {
const flags = getCommandFlags(argv, ['_', '--next']); const flags = getCommandFlags(argv, ['_', '--next']);
log( log(
`To display the next page run ${cmd( `To display the next page run ${getCommandName(
`now ls${app ? ' ' + app : ''}${flags} --next ${pagination.next}` `ls${app ? ' ' + app : ''}${flags} --next ${pagination.next}`
)}` )}`
); );
} }

View File

@@ -10,45 +10,45 @@ import getArgs from '../util/get-args';
import error from '../util/output/error'; import error from '../util/output/error';
import highlight from '../util/output/highlight'; import highlight from '../util/output/highlight';
import ok from '../util/output/ok'; import ok from '../util/output/ok';
import cmd from '../util/output/cmd.ts';
import param from '../util/output/param.ts'; import param from '../util/output/param.ts';
import eraseLines from '../util/output/erase-lines'; import eraseLines from '../util/output/erase-lines';
import sleep from '../util/sleep'; import sleep from '../util/sleep';
import { handleError } from '../util/error'; import { handleError } from '../util/error';
import { writeToAuthConfigFile, writeToConfigFile } from '../util/config/files'; import { writeToAuthConfigFile, writeToConfigFile } from '../util/config/files';
import getNowDir from '../util/config/global-path'; import getGlobalPathConfig from '../util/config/global-path';
import hp from '../util/humanize-path'; import hp from '../util/humanize-path';
import logo from '../util/output/logo'; import logo from '../util/output/logo';
import exit from '../util/exit'; import exit from '../util/exit';
import createOutput from '../util/output'; import createOutput from '../util/output';
import executeLogin from '../util/login/login.ts'; import executeLogin from '../util/login/login.ts';
import { prependEmoji, emoji } from '../util/emoji'; import { prependEmoji, emoji } from '../util/emoji';
import { getCommandName, getPkgName } from '../util/pkg-name.ts';
const debug = debugFactory('now:sh:login'); const debug = debugFactory(`${getPkgName()}:login`);
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now login`)} <email> ${chalk.bold(`${logo} ${getPkgName()} login`)} <email>
${chalk.dim('Options:')} ${chalk.dim('Options:')}
-h, --help Output usage information -h, --help Output usage information
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
${chalk.dim('Examples:')} ${chalk.dim('Examples:')}
${chalk.gray('')} Log into the Now platform ${chalk.gray('')} Log into the Vercel platform
${chalk.cyan('$ now login')} ${chalk.cyan(`$ ${getPkgName()} login`)}
${chalk.gray('')} Log in using a specific email address ${chalk.gray('')} Log in using a specific email address
${chalk.cyan('$ now login john@doe.com')} ${chalk.cyan(`$ ${getPkgName()} login john@doe.com`)}
`); `);
}; };
@@ -114,8 +114,8 @@ const readEmail = async () => {
if (err.message === 'stdin lacks setRawMode support') { if (err.message === 'stdin lacks setRawMode support') {
throw new Error( throw new Error(
error( error(
`Interactive mode not supported please run ${cmd( `Interactive mode not supported please run ${getCommandName(
'now login you@domain.com' `login you@domain.com`
)}` )}`
) )
); );
@@ -248,11 +248,11 @@ const login = async ctx => {
writeToAuthConfigFile(ctx.authConfig); writeToAuthConfigFile(ctx.authConfig);
writeToConfigFile(ctx.config); writeToConfigFile(ctx.config);
output.debug(`Saved credentials in "${hp(getNowDir())}"`); output.debug(`Saved credentials in "${hp(getGlobalPathConfig())}"`);
console.log( console.log(
`${chalk.cyan('Congratulations!')} ` + `${chalk.cyan('Congratulations!')} ` +
`You are now logged in. In order to deploy something, run ${cmd('now')}.` `You are now logged in. In order to deploy something, run ${getCommandName()}.`
); );
output.print( output.print(

View File

@@ -12,26 +12,27 @@ import {
import getArgs from '../util/get-args'; import getArgs from '../util/get-args';
import { NowContext } from '../types'; import { NowContext } from '../types';
import createOutput, { Output } from '../util/output'; import createOutput, { Output } from '../util/output';
import { getPkgName } from '../util/pkg-name';
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now logout`)} ${chalk.bold(`${logo} ${getPkgName()} logout`)}
${chalk.dim('Options:')} ${chalk.dim('Options:')}
-h, --help Output usage information -h, --help Output usage information
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
${chalk.dim('Examples:')} ${chalk.dim('Examples:')}
${chalk.gray('')} Logout from the CLI: ${chalk.gray('')} Logout from the CLI:
${chalk.cyan('$ now logout')} ${chalk.cyan(`$ ${getPkgName()} logout`)}
`); `);
}; };

View File

@@ -8,20 +8,21 @@ import { maybeURL, normalizeURL } from '../util/url';
import printEvents from '../util/events'; import printEvents from '../util/events';
import Client from '../util/client.ts'; import Client from '../util/client.ts';
import getScope from '../util/get-scope.ts'; import getScope from '../util/get-scope.ts';
import { getPkgName } from '../util/pkg-name.ts';
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now logs`)} <url|deploymentId> ${chalk.bold(`${logo} ${getPkgName()} logs`)} <url|deploymentId>
${chalk.dim('Options:')} ${chalk.dim('Options:')}
-h, --help Output usage information -h, --help Output usage information
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
-d, --debug Debug mode [off] -d, --debug Debug mode [off]
-f, --follow Wait for additional data [off] -f, --follow Wait for additional data [off]
-n ${chalk.bold.underline( -n ${chalk.bold.underline(
@@ -49,7 +50,7 @@ const help = () => {
'`deploymentId`' '`deploymentId`'
)} )}
${chalk.cyan('$ now logs deploymentId')} ${chalk.cyan(`$ ${getPkgName()} logs deploymentId`)}
`); `);
}; };

View File

@@ -2,7 +2,6 @@ import chalk from 'chalk';
import table from 'text-table'; import table from 'text-table';
import mri from 'mri'; import mri from 'mri';
import ms from 'ms'; import ms from 'ms';
import plural from 'pluralize';
import strlen from '../util/strlen'; import strlen from '../util/strlen';
import { handleError, error } from '../util/error'; import { handleError, error } from '../util/error';
import exit from '../util/exit'; import exit from '../util/exit';
@@ -10,12 +9,16 @@ import Client from '../util/client.ts';
import logo from '../util/output/logo'; import logo from '../util/output/logo';
import getScope from '../util/get-scope'; import getScope from '../util/get-scope';
import createOutput from '../util/output'; import createOutput from '../util/output';
import getCommandFlags from '../util/get-command-flags';
import wait from '../util/output/wait';
import getPrefixedFlags from '../util/get-prefixed-flags';
import { getPkgName, getCommandName } from '../util/pkg-name.ts';
const e = encodeURIComponent; const e = encodeURIComponent;
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now projects`)} [options] <command> ${chalk.bold(`${logo} ${getPkgName()} projects`)} [options] <command>
${chalk.dim('Commands:')} ${chalk.dim('Commands:')}
@@ -30,12 +33,19 @@ const help = () => {
'TOKEN' 'TOKEN'
)} Login token )} Login token
-S, --scope Set a custom scope -S, --scope Set a custom scope
-N, --next Show next page of results
${chalk.dim('Examples:')} ${chalk.dim('Examples:')}
${chalk.gray('')} Add a new project ${chalk.gray('')} Add a new project
${chalk.cyan('$ now projects add my-project')} ${chalk.cyan(`$ ${getPkgName()} projects add my-project`)}
${chalk.gray('')} Paginate projects, where ${chalk.dim(
'`1584722256178`'
)} is the time in milliseconds since the UNIX epoch.
${chalk.cyan(`$ ${getPkgName()} projects ls --next 1584722256178`)}
`); `);
}; };
@@ -50,6 +60,7 @@ const main = async ctx => {
boolean: ['help'], boolean: ['help'],
alias: { alias: {
help: 'h', help: 'h',
next: 'N',
}, },
}); });
@@ -111,20 +122,33 @@ async function run({ client, contextName }) {
console.error( console.error(
error( error(
`Invalid number of arguments. Usage: ${chalk.cyan( `Invalid number of arguments. Usage: ${chalk.cyan(
'`now projects ls`' `${getCommandName('projects ls')}`
)}` )}`
) )
); );
return exit(1); return exit(1);
} }
const list = await client.fetch('/v2/projects/', { method: 'GET' }); const stopSpinner = wait(`Fetching projects in ${chalk.bold(contextName)}`);
let projectsUrl = '/v4/projects/?limit=20';
if (argv.next) {
projectsUrl += `&until=${argv.next}`;
}
const { projects: list, pagination } = await client.fetch(projectsUrl, {
method: 'GET',
});
stopSpinner();
const elapsed = ms(new Date() - start); const elapsed = ms(new Date() - start);
console.log( console.log(
`> ${plural('project', list.length, true)} found under ${chalk.bold( `> ${
contextName list.length > 0 ? 'Projects' : 'No projects'
)} ${chalk.gray(`[${elapsed}]`)}` } found under ${chalk.bold(contextName)} ${chalk.gray(`[${elapsed}]`)}`
); );
if (list.length > 0) { if (list.length > 0) {
@@ -149,6 +173,19 @@ async function run({ client, contextName }) {
if (out) { if (out) {
console.log(`\n${out}\n`); console.log(`\n${out}\n`);
} }
if (pagination && pagination.count === 20) {
const prefixedArgs = getPrefixedFlags(argv);
const flags = getCommandFlags(prefixedArgs, [
'_',
'--next',
'-N',
'-d',
'-y',
]);
const nextCmd = `projects ls${flags} --next ${pagination.next}`;
console.log(`To display the next page run ${getCommandName(nextCmd)}`);
}
} }
return; return;
} }
@@ -158,7 +195,7 @@ async function run({ client, contextName }) {
console.error( console.error(
error( error(
`Invalid number of arguments. Usage: ${chalk.cyan( `Invalid number of arguments. Usage: ${chalk.cyan(
'`now project rm <name>`' `${getCommandName('project rm <name>')}`
)}` )}`
) )
); );
@@ -200,13 +237,15 @@ async function run({ client, contextName }) {
console.error( console.error(
error( error(
`Invalid number of arguments. Usage: ${chalk.cyan( `Invalid number of arguments. Usage: ${chalk.cyan(
'`now projects add <name>`' `${getCommandName('projects add <name>')}`
)}` )}`
) )
); );
if (args.length > 1) { if (args.length > 1) {
const example = chalk.cyan(`$ now projects add "${args.join(' ')}"`); const example = chalk.cyan(
`${getCommandName(`projects add "${args.join(' ')}"`)}`
);
console.log( console.log(
`> If your project name has spaces, make sure to wrap it in quotes. Example: \n ${example} ` `> If your project name has spaces, make sure to wrap it in quotes. Example: \n ${example} `
); );

View File

@@ -7,7 +7,6 @@ import Now from '../util';
import getAliases from '../util/alias/get-aliases'; import getAliases from '../util/alias/get-aliases';
import createOutput from '../util/output'; import createOutput from '../util/output';
import logo from '../util/output/logo'; import logo from '../util/output/logo';
import cmd from '../util/output/cmd.ts';
import elapsed from '../util/output/elapsed.ts'; import elapsed from '../util/output/elapsed.ts';
import { normalizeURL } from '../util/url'; import { normalizeURL } from '../util/url';
import Client from '../util/client.ts'; import Client from '../util/client.ts';
@@ -18,20 +17,23 @@ import removeProject from '../util/projects/remove-project';
import getProjectByIdOrName from '../util/projects/get-project-by-id-or-name'; import getProjectByIdOrName from '../util/projects/get-project-by-id-or-name';
import getDeploymentByIdOrHost from '../util/deploy/get-deployment-by-id-or-host'; import getDeploymentByIdOrHost from '../util/deploy/get-deployment-by-id-or-host';
import getDeploymentsByProjectId from '../util/deploy/get-deployments-by-project-id'; import getDeploymentsByProjectId from '../util/deploy/get-deployments-by-project-id';
import { getPkgName, getCommandName } from '../util/pkg-name.ts';
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now remove`)} [...deploymentId|deploymentName] ${chalk.bold(
`${logo} ${getPkgName()} remove`
)} [...deploymentId|deploymentName]
${chalk.dim('Options:')} ${chalk.dim('Options:')}
-h, --help Output usage information -h, --help Output usage information
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
-d, --debug Debug mode [off] -d, --debug Debug mode [off]
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline( -t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
'TOKEN' 'TOKEN'
@@ -46,17 +48,17 @@ const help = () => {
'`deploymentId`' '`deploymentId`'
)} )}
${chalk.cyan('$ now rm deploymentId')} ${chalk.cyan(`$ ${getPkgName()} rm deploymentId`)}
${chalk.gray('')} Remove all deployments with name ${chalk.dim('`my-app`')} ${chalk.gray('')} Remove all deployments with name ${chalk.dim('`my-app`')}
${chalk.cyan('$ now rm my-app')} ${chalk.cyan(`$ ${getPkgName()} rm my-app`)}
${chalk.gray('')} Remove two deployments with IDs ${chalk.dim( ${chalk.gray('')} Remove two deployments with IDs ${chalk.dim(
'`eyWt6zuSdeus`' '`eyWt6zuSdeus`'
)} and ${chalk.dim('`uWHoA9RQ1d1o`')} )} and ${chalk.dim('`uWHoA9RQ1d1o`')}
${chalk.cyan('$ now rm eyWt6zuSdeus uWHoA9RQ1d1o')} ${chalk.cyan(`$ ${getPkgName()} rm eyWt6zuSdeus uWHoA9RQ1d1o`)}
`); `);
}; };
@@ -91,7 +93,7 @@ export default async function main(ctx) {
} }
if (ids.length < 1) { if (ids.length < 1) {
error(`${cmd('now rm')} expects at least one argument`); error(`${getCommandName('rm')} expects at least one argument`);
help(); help();
return 1; return 1;
} }
@@ -212,9 +214,9 @@ export default async function main(ctx) {
log( log(
`Could not find ${argv.safe ? 'unaliased' : 'any'} deployments ` + `Could not find ${argv.safe ? 'unaliased' : 'any'} deployments ` +
`or projects matching ` + `or projects matching ` +
`${ids.map(id => chalk.bold(`"${id}"`)).join(', ')}. Run ${cmd( `${ids
'now ls' .map(id => chalk.bold(`"${id}"`))
)} to list.` .join(', ')}. Run ${getCommandName('ls')} to list.`
); );
client.close(); client.close();
return 1; return 1;

View File

@@ -35,20 +35,21 @@ import {
} from '../util/errors-ts'; } from '../util/errors-ts';
import { InvalidAllForScale, InvalidRegionOrDCForScale } from '../util/errors'; import { InvalidAllForScale, InvalidRegionOrDCForScale } from '../util/errors';
import handleCertError from '../util/certs/handle-cert-error'; import handleCertError from '../util/certs/handle-cert-error';
import { getPkgName } from '../util/pkg-name.ts';
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now scale`)} <url> <dc> [min] [max] ${chalk.bold(`${logo} ${getPkgName()} scale`)} <url> <dc> [min] [max]
${chalk.dim('Options:')} ${chalk.dim('Options:')}
-h, --help Output usage information -h, --help Output usage information
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline( -t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
'TOKEN' 'TOKEN'
)} Login token )} Login token
@@ -63,25 +64,25 @@ const help = () => {
'' ''
)} Enable your deployment in all datacenters (min: 0, max: auto) )} Enable your deployment in all datacenters (min: 0, max: auto)
${chalk.cyan('$ now scale my-deployment-123.now.sh all')} ${chalk.cyan(`$ ${getPkgName()} scale my-deployment-123.now.sh all`)}
${chalk.gray( ${chalk.gray(
'-' '-'
)} Enable your deployment in the SFO datacenter (min: 0, max: auto) )} Enable your deployment in the SFO datacenter (min: 0, max: auto)
${chalk.cyan('$ now scale my-deployment-123.now.sh sfo')} ${chalk.cyan(`$ ${getPkgName()} scale my-deployment-123.now.sh sfo`)}
${chalk.gray( ${chalk.gray(
'' ''
)} Scale a deployment in all datacenters to 3 instances at all times (no sleep) )} Scale a deployment in all datacenters to 3 instances at all times (no sleep)
${chalk.cyan('$ now scale my-deployment-123.now.sh all 3')} ${chalk.cyan(`$ ${getPkgName()} scale my-deployment-123.now.sh all 3`)}
${chalk.gray( ${chalk.gray(
'' ''
)} Enable your deployment in all datacenters, with auto-scaling )} Enable your deployment in all datacenters, with auto-scaling
${chalk.cyan('$ now scale my-deployment-123.now.sh all auto')} ${chalk.cyan(`$ ${getPkgName()} scale my-deployment-123.now.sh all auto`)}
`); `);
}; };
@@ -133,9 +134,9 @@ export default async function main(ctx) {
// Fail if the user is providing an old command // Fail if the user is providing an old command
if (argv._[1] === 'ls') { if (argv._[1] === 'ls') {
output.error( output.error(
`${cmd('now scale ls')} has been deprecated. Use ${cmd( `${cmd(`${getPkgName()} scale ls`)} has been deprecated. Use ${cmd(
'now ls' 'now ls'
)} and ${cmd('now inspect <url>')}` )} and ${cmd(`${getPkgName()} inspect <url>`)}`
); );
now.close(); now.close();
return 1; return 1;
@@ -145,7 +146,7 @@ export default async function main(ctx) {
if (argv._.length < 3 || argv._.length > 5) { if (argv._.length < 3 || argv._.length > 5) {
output.error( output.error(
`${cmd( `${cmd(
'now scale <url> <dc> [min] [max]' `${getPkgName()} scale <url> <dc> [min] [max]`
)} expects at least two arguments` )} expects at least two arguments`
); );
help(); help();

View File

@@ -12,11 +12,12 @@ import getScope from '../util/get-scope.ts';
import createOutput from '../util/output'; import createOutput from '../util/output';
import confirm from '../util/input/confirm'; import confirm from '../util/input/confirm';
import getCommandFlags from '../util/get-command-flags'; import getCommandFlags from '../util/get-command-flags';
import cmd from '../util/output/cmd.ts'; import getPrefixedFlags from '../util/get-prefixed-flags';
import { getPkgName, getCommandName } from '../util/pkg-name.ts';
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now secrets`)} [options] <command> ${chalk.bold(`${logo} ${getPkgName()} secrets`)} [options] <command>
${chalk.dim('Commands:')} ${chalk.dim('Commands:')}
@@ -30,10 +31,10 @@ const help = () => {
-h, --help Output usage information -h, --help Output usage information
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
-d, --debug Debug mode [off] -d, --debug Debug mode [off]
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline( -t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
'TOKEN' 'TOKEN'
@@ -45,7 +46,7 @@ const help = () => {
${chalk.gray('')} Add a new secret ${chalk.gray('')} Add a new secret
${chalk.cyan('$ now secrets add my-secret "my value"')} ${chalk.cyan(`$ ${getPkgName()} secrets add my-secret "my value"`)}
${chalk.gray( ${chalk.gray(
'' ''
@@ -61,13 +62,13 @@ const help = () => {
'`@`' '`@`'
)} symbol) )} symbol)
${chalk.cyan(`$ now -e MY_SECRET=${chalk.bold('@my-secret')}`)} ${chalk.cyan(`$ ${getPkgName()} -e MY_SECRET=${chalk.bold('@my-secret')}`)}
${chalk.gray('')} Paginate results, where ${chalk.dim( ${chalk.gray('')} Paginate results, where ${chalk.dim(
'`1584722256178`' '`1584722256178`'
)} is the time in milliseconds since the UNIX epoch. )} is the time in milliseconds since the UNIX epoch.
${chalk.cyan(`$ now secrets ls --next 1584722256178`)} ${chalk.cyan(`$ ${getPkgName()} secrets ls --next 1584722256178`)}
`); `);
}; };
@@ -146,7 +147,9 @@ async function run({ output, token, contextName, currentTeam, ctx }) {
if (args.length > 1) { if (args.length > 1) {
console.error( console.error(
error( error(
`Invalid number of arguments. Usage: ${chalk.cyan('`now secret ls`')}` `Invalid number of arguments. Usage: ${chalk.cyan(
`${getCommandName('secret ls')}`
)}`
) )
); );
return exit(1); return exit(1);
@@ -193,8 +196,8 @@ async function run({ output, token, contextName, currentTeam, ctx }) {
'-d', '-d',
'-y', '-y',
]); ]);
const nextCmd = `now secrets ${subcommand}${flags} --next ${pagination.next}`; const nextCmd = `secrets ${subcommand}${flags} --next ${pagination.next}`;
output.log(`To display the next page run ${cmd(nextCmd)}`); output.log(`To display the next page run ${getCommandName(nextCmd)}`);
} }
return secrets.close(); return secrets.close();
} }
@@ -204,7 +207,7 @@ async function run({ output, token, contextName, currentTeam, ctx }) {
console.error( console.error(
error( error(
`Invalid number of arguments. Usage: ${chalk.cyan( `Invalid number of arguments. Usage: ${chalk.cyan(
'`now secret rm <name>`' `${getCommandName('secret rm <name>')}`
)}` )}`
) )
); );
@@ -246,7 +249,7 @@ async function run({ output, token, contextName, currentTeam, ctx }) {
console.error( console.error(
error( error(
`Invalid number of arguments. Usage: ${chalk.cyan( `Invalid number of arguments. Usage: ${chalk.cyan(
'`now secret rename <old-name> <new-name>`' `${getCommandName('secret rename <old-name> <new-name>')}`
)}` )}`
) )
); );
@@ -269,13 +272,15 @@ async function run({ output, token, contextName, currentTeam, ctx }) {
console.error( console.error(
error( error(
`Invalid number of arguments. Usage: ${chalk.cyan( `Invalid number of arguments. Usage: ${chalk.cyan(
'`now secret add <name> <value>`' `${getCommandName('secret add <name> <value>')}`
)}` )}`
) )
); );
if (args.length > 2) { if (args.length > 2) {
const example = chalk.cyan(`$ now secret add -- "${args[0]}"`); const example = chalk.cyan(
`$ ${getCommandName('secret add -- "${args[0]}"')}`
);
console.log( console.log(
`If your secret has spaces or starts with '-', make sure to terminate command options with double dash and wrap it in quotes. Example: \n ${example} ` `If your secret has spaces or starts with '-', make sure to terminate command options with double dash and wrap it in quotes. Example: \n ${example} `
); );
@@ -299,7 +304,9 @@ async function run({ output, token, contextName, currentTeam, ctx }) {
} }
if (typeof value === 'boolean') { if (typeof value === 'boolean') {
const example = chalk.cyan(`$ now secret add -- "${name}"`); const example = chalk.cyan(
`$ ${getCommandName('secret add -- "${name}"')}`
);
console.log( console.log(
`If your secret starts with '-', make sure to terminate command options with double dash and wrap it in quotes. Example: \n ${example} ` `If your secret starts with '-', make sure to terminate command options with double dash and wrap it in quotes. Example: \n ${example} `
); );
@@ -349,28 +356,3 @@ async function readConfirmation(output, secret, contextName) {
return confirm(`${chalk.bold.red('Are you sure?')}`, false); return confirm(`${chalk.bold.red('Are you sure?')}`, false);
} }
/**
* This function adds a prefix `-` or `--` to the flags
* passed from the command line, because the package `mri`
* used to extract the args removes them for some reason.
*/
function getPrefixedFlags(args) {
const prefixedArgs = {};
for (const arg in args) {
if (arg === '_') {
prefixedArgs[arg] = argv[arg];
} else {
let prefix = '-';
// Full form flags need two dashes, whereas one letter
// flags need only one.
if (arg.length > 1) {
prefix = '--';
}
prefixedArgs[`${prefix}${arg}`] = argv[arg];
}
}
return prefixedArgs;
}

View File

@@ -9,10 +9,11 @@ import list from './teams/list';
import add from './teams/add'; import add from './teams/add';
import change from './teams/switch'; import change from './teams/switch';
import invite from './teams/invite'; import invite from './teams/invite';
import { getPkgName } from '../util/pkg-name.ts';
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now teams`)} [options] <command> ${chalk.bold(`${logo} ${getPkgName()} teams`)} [options] <command>
${chalk.dim('Commands:')} ${chalk.dim('Commands:')}
@@ -26,17 +27,18 @@ const help = () => {
-h, --help Output usage information -h, --help Output usage information
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
-d, --debug Debug mode [off] -d, --debug Debug mode [off]
-N, --next Show next page of results
${chalk.dim('Examples:')} ${chalk.dim('Examples:')}
${chalk.gray('')} Switch to a team ${chalk.gray('')} Switch to a team
${chalk.cyan(`$ now switch <slug>`)} ${chalk.cyan(`$ ${getPkgName()} switch <slug>`)}
${chalk.gray( ${chalk.gray(
'' ''
@@ -49,7 +51,13 @@ const help = () => {
${chalk.gray('')} Invite new members (interactively) ${chalk.gray('')} Invite new members (interactively)
${chalk.cyan(`$ now teams invite`)} ${chalk.cyan(`$ ${getPkgName()} teams invite`)}
${chalk.gray('')} Paginate results, where ${chalk.dim(
'`1584722256178`'
)} is the time in milliseconds since the UNIX epoch.
${chalk.cyan(`$ ${getPkgName()} teams ls --next 1584722256178`)}
`); `);
}; };
@@ -64,8 +72,9 @@ const main = async ctx => {
alias: { alias: {
help: 'h', help: 'h',
debug: 'd', debug: 'd',
switch: 'change' switch: 'change',
} next: 'N',
},
}); });
debug = argv.debug; debug = argv.debug;
@@ -86,7 +95,10 @@ const main = async ctx => {
await exit(0); await exit(0);
} }
const { authConfig: { token }, config } = ctx; const {
authConfig: { token },
config,
} = ctx;
return run({ token, config }); return run({ token, config });
}; };
@@ -113,7 +125,8 @@ async function run({ token, config }) {
teams, teams,
config, config,
apiUrl, apiUrl,
token token,
argv,
}); });
break; break;
} }
@@ -124,7 +137,7 @@ async function run({ token, config }) {
config, config,
apiUrl, apiUrl,
token, token,
debug debug,
}); });
break; break;
} }
@@ -140,7 +153,7 @@ async function run({ token, config }) {
args, args,
config, config,
apiUrl, apiUrl,
token token,
}); });
break; break;
} }

View File

@@ -7,11 +7,11 @@ import rightPad from '../../util/output/right-pad';
import eraseLines from '../../util/output/erase-lines'; import eraseLines from '../../util/output/erase-lines';
import chars from '../../util/output/chars'; import chars from '../../util/output/chars';
import success from '../../util/output/success'; import success from '../../util/output/success';
import cmd from '../../util/output/cmd.ts';
import note from '../../util/output/note'; import note from '../../util/output/note';
import textInput from '../../util/input/text'; import textInput from '../../util/input/text';
import invite from './invite'; import invite from './invite';
import { writeToConfigFile } from '../../util/config/files'; import { writeToConfigFile } from '../../util/config/files';
import { getPkgName, getCommandName } from '../../util/pkg-name.ts';
const validateSlugKeypress = (data, value) => const validateSlugKeypress = (data, value) =>
// TODO: the `value` here should contain the current value + the keypress // TODO: the `value` here should contain the current value + the keypress
@@ -26,8 +26,8 @@ const validateNameKeypress = (data, value) =>
const gracefulExit = () => { const gracefulExit = () => {
console.log(); // Blank line console.log(); // Blank line
note( note(
`Your team is now active for all ${cmd('now')} commands!\n Run ${cmd( `Your team is now active for all ${getPkgName()} commands!\n Run ${getCommandName(
'now switch' `switch`
)} to change it in the future.` )} to change it in the future.`
); );
return 0; return 0;
@@ -151,8 +151,8 @@ export default async function({ apiUrl, token, teams, config }) {
apiUrl, apiUrl,
config, config,
introMsg: 'Invite your teammates! When done, press enter on an empty field', introMsg: 'Invite your teammates! When done, press enter on an empty field',
noopMsg: `You can invite teammates later by running ${cmd( noopMsg: `You can invite teammates later by running ${getCommandName(
'now teams invite' `teams invite`
)}`, )}`,
}); });

View File

@@ -14,6 +14,7 @@ import eraseLines from '../../util/output/erase-lines';
import success from '../../util/output/success'; import success from '../../util/output/success';
import getUser from '../../util/get-user.ts'; import getUser from '../../util/get-user.ts';
import Client from '../../util/client.ts'; import Client from '../../util/client.ts';
import { getCommandName } from '../../util/pkg-name.ts';
const validateEmail = data => regexEmail.test(data.trim()) || data.length === 0; const validateEmail = data => regexEmail.test(data.trim()) || data.length === 0;
@@ -96,9 +97,9 @@ export default async function({
// We specifically need a team scope here // We specifically need a team scope here
let err = `You can't run this command under ${param( let err = `You can't run this command under ${param(
user.username || user.email user.username || user.email
)}.\nPlease select a team scope using ${cmd('now switch')} or use ${cmd( )}.\nPlease select a team scope using ${getCommandName(
'--scope' `switch`
)}`; )} or use ${cmd('--scope')}`;
return fatalError(err); return fatalError(err);
} }

View File

@@ -8,12 +8,28 @@ import info from '../../util/output/info';
import error from '../../util/output/error'; import error from '../../util/output/error';
import chars from '../../util/output/chars'; import chars from '../../util/output/chars';
import table from '../../util/output/table'; import table from '../../util/output/table';
import createOutput from '../../util/output';
import getUser from '../../util/get-user.ts'; import getUser from '../../util/get-user.ts';
import Client from '../../util/client.ts'; import Client from '../../util/client.ts';
import getPrefixedFlags from '../../util/get-prefixed-flags';
import { getPkgName } from '../../util/pkg-name.ts';
import getCommandFlags from '../../util/get-command-flags';
import cmd from '../../util/output/cmd.ts';
export default async function({ teams, config, apiUrl, token, argv }) {
const { next } = argv;
const output = createOutput({ debug: argv['--debug'] });
if (typeof next !== 'undefined' && !Number.isInteger(next)) {
output.error('Please provide a number for flag --next');
return 1;
}
export default async function({ teams, config, apiUrl, token }) {
const stopSpinner = wait('Fetching teams'); const stopSpinner = wait('Fetching teams');
const list = (await teams.ls()).teams; const { teams: list, pagination } = await teams.ls({
next,
apiVersion: 2,
});
let { currentTeam } = config; let { currentTeam } = config;
const accountIsCurrent = !currentTeam; const accountIsCurrent = !currentTeam;
@@ -78,4 +94,14 @@ export default async function({ teams, config, apiUrl, token }) {
teamList.map(team => [team.current, team.value, team.name]), teamList.map(team => [team.current, team.value, team.name]),
[1, 5] [1, 5]
); );
if (pagination && pagination.count === 20) {
const prefixedArgs = getPrefixedFlags(argv);
const flags = getCommandFlags(prefixedArgs, ['_', '--next', '-N', '-d']);
const nextCmd = `${getPkgName()} teams ls${flags} --next ${
pagination.next
}`;
console.log(); // empty line
output.log(`To display the next page run ${cmd(nextCmd)}`);
}
} }

View File

@@ -7,10 +7,11 @@ import getArgs from '../util/get-args';
import { NowContext } from '../types'; import { NowContext } from '../types';
import createOutput from '../util/output'; import createOutput from '../util/output';
import getUpdateCommand from '../util/get-update-command'; import getUpdateCommand from '../util/get-update-command';
import { getPkgName, getTitleName } from '../util/pkg-name';
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now update`)} [options] ${chalk.bold(`${logo} ${getPkgName()} update`)} [options]
${chalk.dim('Options:')} ${chalk.dim('Options:')}
@@ -26,9 +27,9 @@ const help = () => {
${chalk.dim('Examples:')} ${chalk.dim('Examples:')}
${chalk.gray('')} Update Now CLI to the latest "canary" version ${chalk.gray('')} Update ${getTitleName()} CLI to the latest "canary" version
${chalk.cyan(`$ now update --channel=canary`)} ${chalk.cyan(`$ ${getPkgName()} update --channel=canary`)}
`); `);
}; };
@@ -42,7 +43,7 @@ export default async function main(ctx: NowContext): Promise<number> {
'--release': String, '--release': String,
'-V': '--release', '-V': '--release',
'--yes': Boolean, '--yes': Boolean,
'-y': '--yes' '-y': '--yes',
}); });
} catch (err) { } catch (err) {
handleError(err); handleError(err);
@@ -56,6 +57,10 @@ export default async function main(ctx: NowContext): Promise<number> {
const debugEnabled = argv['--debug']; const debugEnabled = argv['--debug'];
const output = createOutput({ debug: debugEnabled }); const output = createOutput({ debug: debugEnabled });
output.log(`Please run ${cmd(await getUpdateCommand())} to update Now CLI`); output.log(
`Please run ${cmd(
await getUpdateCommand()
)} to update ${getTitleName()} CLI`
);
return 0; return 0;
} }

View File

@@ -5,20 +5,21 @@ import { handleError } from '../util/error';
import Client from '../util/client.ts'; import Client from '../util/client.ts';
import getScope from '../util/get-scope.ts'; import getScope from '../util/get-scope.ts';
import createOutput from '../util/output'; import createOutput from '../util/output';
import { getPkgName } from '../util/pkg-name.ts';
const help = () => { const help = () => {
console.log(` console.log(`
${chalk.bold(`${logo} now whoami`)} ${chalk.bold(`${logo} ${getPkgName()} whoami`)}
${chalk.dim('Options:')} ${chalk.dim('Options:')}
-h, --help Output usage information -h, --help Output usage information
-A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline( -A ${chalk.bold.underline('FILE')}, --local-config=${chalk.bold.underline(
'FILE' 'FILE'
)} Path to the local ${'`now.json`'} file )} Path to the local ${'`vercel.json`'} file
-Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline( -Q ${chalk.bold.underline('DIR')}, --global-config=${chalk.bold.underline(
'DIR' 'DIR'
)} Path to the global ${'`.now`'} directory )} Path to the global ${'`.vercel`'} directory
-d, --debug Debug mode [off] -d, --debug Debug mode [off]
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline( -t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
'TOKEN' 'TOKEN'
@@ -28,7 +29,7 @@ const help = () => {
${chalk.gray('')} Shows the username of the currently logged in user ${chalk.gray('')} Shows the username of the currently logged in user
${chalk.cyan('$ now whoami')} ${chalk.cyan(`$ ${getPkgName()} whoami`)}
`); `);
}; };

View File

@@ -24,7 +24,7 @@ import checkForUpdate from 'update-check';
import ms from 'ms'; import ms from 'ms';
import { URL } from 'url'; import { URL } from 'url';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import getNowDir from './util/config/global-path'; import getGlobalPathConfig from './util/config/global-path';
import { import {
getDefaultConfig, getDefaultConfig,
getDefaultAuthConfig, getDefaultAuthConfig,
@@ -48,11 +48,11 @@ import { NowError } from './util/now-error';
import { SENTRY_DSN } from './util/constants.ts'; import { SENTRY_DSN } from './util/constants.ts';
import getUpdateCommand from './util/get-update-command'; import getUpdateCommand from './util/get-update-command';
import { metrics, shouldCollectMetrics } from './util/metrics.ts'; import { metrics, shouldCollectMetrics } from './util/metrics.ts';
import { getLinkedOrg } from './util/projects/link'; import { getCommandName, getTitleName } from './util/pkg-name.ts';
const NOW_DIR = getNowDir(); const VERCEL_DIR = getGlobalPathConfig();
const NOW_CONFIG_PATH = configFiles.getConfigFilePath(); const VERCEL_CONFIG_PATH = configFiles.getConfigFilePath();
const NOW_AUTH_CONFIG_PATH = configFiles.getAuthConfigFilePath(); const VERCEL_AUTH_CONFIG_PATH = configFiles.getAuthConfigFilePath();
const GLOBAL_COMMANDS = new Set(['help']); const GLOBAL_COMMANDS = new Set(['help']);
@@ -63,7 +63,7 @@ sourceMap.install();
// Configure the error reporting system // Configure the error reporting system
Sentry.init({ Sentry.init({
dsn: SENTRY_DSN, dsn: SENTRY_DSN,
release: `now-cli@${pkg.version}`, release: `vercel-cli@${pkg.version}`,
environment: pkg.version.includes('canary') ? 'canary' : 'stable', environment: pkg.version.includes('canary') ? 'canary' : 'stable',
}); });
@@ -122,8 +122,8 @@ const main = async argv_ => {
} }
// the second argument to the command can be a path // the second argument to the command can be a path
// (as in: `now path/`) or a subcommand / provider // (as in: `vercel path/`) or a subcommand / provider
// (as in: `now ls`) // (as in: `vercel ls`)
const targetOrSubcommand = argv._[2]; const targetOrSubcommand = argv._[2];
let update = null; let update = null;
@@ -149,9 +149,9 @@ const main = async argv_ => {
console.log( console.log(
info( info(
`${chalk.bgRed('UPDATE AVAILABLE')} ` + `${chalk.bgRed('UPDATE AVAILABLE')} ` +
`Run ${cmd(await getUpdateCommand())} to install Now CLI ${ `Run ${cmd(
update.latest await getUpdateCommand()
}` )} to install ${getTitleName()} CLI ${update.latest}`
) )
); );
@@ -164,7 +164,7 @@ const main = async argv_ => {
output.print( output.print(
`${chalk.grey( `${chalk.grey(
`Now CLI ${pkg.version}${ `${getTitleName()} CLI ${pkg.version}${
targetOrSubcommand === 'dev' ? ' dev (beta)' : '' targetOrSubcommand === 'dev' ? ' dev (beta)' : ''
}${ }${
pkg.version.includes('canary') || targetOrSubcommand === 'dev' pkg.version.includes('canary') || targetOrSubcommand === 'dev'
@@ -177,7 +177,7 @@ const main = async argv_ => {
// we want to handle version or help directly only // we want to handle version or help directly only
if (!targetOrSubcommand) { if (!targetOrSubcommand) {
if (argv['--version']) { if (argv['--version']) {
console.log(require('../package').version); console.log(pkg.version);
return 0; return 0;
} }
} }
@@ -185,12 +185,12 @@ const main = async argv_ => {
let nowDirExists; let nowDirExists;
try { try {
nowDirExists = existsSync(NOW_DIR); nowDirExists = existsSync(VERCEL_DIR);
} catch (err) { } catch (err) {
console.error( console.error(
error( error(
`${'An unexpected error occurred while trying to find the ' + `${'An unexpected error occurred while trying to find the ' +
'now global directory: '}${err.message}` 'global directory: '}${err.message}`
) )
); );
@@ -199,12 +199,12 @@ const main = async argv_ => {
if (!nowDirExists) { if (!nowDirExists) {
try { try {
await mkdirp(NOW_DIR); await mkdirp(VERCEL_DIR);
} catch (err) { } catch (err) {
console.error( console.error(
error( error(
`${'An unexpected error occurred while trying to create the ' + `${'An unexpected error occurred while trying to create the ' +
`now global directory "${hp(NOW_DIR)}" `}${err.message}` `global directory "${hp(VERCEL_DIR)}" `}${err.message}`
) )
); );
} }
@@ -214,12 +214,12 @@ const main = async argv_ => {
let configExists; let configExists;
try { try {
configExists = existsSync(NOW_CONFIG_PATH); configExists = existsSync(VERCEL_CONFIG_PATH);
} catch (err) { } catch (err) {
console.error( console.error(
error( error(
`${'An unexpected error occurred while trying to find the ' + `${'An unexpected error occurred while trying to find the ' +
`now config file "${hp(NOW_CONFIG_PATH)}" `}${err.message}` `config file "${hp(VERCEL_CONFIG_PATH)}" `}${err.message}`
) )
); );
@@ -235,14 +235,14 @@ const main = async argv_ => {
console.error( console.error(
error( error(
`${'An unexpected error occurred while trying to read the ' + `${'An unexpected error occurred while trying to read the ' +
`now config in "${hp(NOW_CONFIG_PATH)}" `}${err.message}` `config in "${hp(VERCEL_CONFIG_PATH)}" `}${err.message}`
) )
); );
return 1; return 1;
} }
// This is from when Now CLI supported // This is from when Vercel CLI supported
// multiple providers. In that case, we really // multiple providers. In that case, we really
// need to migrate. // need to migrate.
if ( if (
@@ -267,7 +267,7 @@ const main = async argv_ => {
console.error( console.error(
error( error(
`${'An unexpected error occurred while trying to write the ' + `${'An unexpected error occurred while trying to write the ' +
`default now config to "${hp(NOW_CONFIG_PATH)}" `}${err.message}` `default config to "${hp(VERCEL_CONFIG_PATH)}" `}${err.message}`
) )
); );
@@ -278,12 +278,12 @@ const main = async argv_ => {
let authConfigExists; let authConfigExists;
try { try {
authConfigExists = existsSync(NOW_AUTH_CONFIG_PATH); authConfigExists = existsSync(VERCEL_AUTH_CONFIG_PATH);
} catch (err) { } catch (err) {
console.error( console.error(
error( error(
`${'An unexpected error occurred while trying to find the ' + `${'An unexpected error occurred while trying to find the ' +
`now auth file "${hp(NOW_AUTH_CONFIG_PATH)}" `}${err.message}` `auth file "${hp(VERCEL_AUTH_CONFIG_PATH)}" `}${err.message}`
) )
); );
@@ -301,14 +301,14 @@ const main = async argv_ => {
console.error( console.error(
error( error(
`${'An unexpected error occurred while trying to read the ' + `${'An unexpected error occurred while trying to read the ' +
`now auth config in "${hp(NOW_AUTH_CONFIG_PATH)}" `}${err.message}` `auth config in "${hp(VERCEL_AUTH_CONFIG_PATH)}" `}${err.message}`
) )
); );
return 1; return 1;
} }
// This is from when Now CLI supported // This is from when Vercel CLI supported
// multiple providers. In that case, we really // multiple providers. In that case, we really
// need to migrate. // need to migrate.
if (authConfig.credentials) { if (authConfig.credentials) {
@@ -321,8 +321,10 @@ const main = async argv_ => {
) { ) {
console.error( console.error(
error( error(
`The content of "${hp(NOW_AUTH_CONFIG_PATH)}" is invalid. ` + `The content of "${hp(VERCEL_AUTH_CONFIG_PATH)}" is invalid. ` +
'No `token` property found inside. Run `now login` to authorize.' `No \`token\` property found inside. Run ${getCommandName(
'login'
)} to authorize.`
) )
); );
return 1; return 1;
@@ -339,7 +341,7 @@ const main = async argv_ => {
console.error( console.error(
error( error(
`${'An unexpected error occurred while trying to write the ' + `${'An unexpected error occurred while trying to write the ' +
`default now config to "${hp(NOW_AUTH_CONFIG_PATH)}" `}${ `default config to "${hp(VERCEL_AUTH_CONFIG_PATH)}" `}${
err.message err.message
}` }`
) )
@@ -350,7 +352,7 @@ const main = async argv_ => {
// Let the user know we migrated the config // Let the user know we migrated the config
if (migrated) { if (migrated) {
const directory = param(hp(NOW_DIR)); const directory = param(hp(VERCEL_DIR));
debug( debug(
`The credentials and configuration within the ${directory} directory were upgraded` `The credentials and configuration within the ${directory} directory were upgraded`
); );
@@ -464,7 +466,7 @@ const main = async argv_ => {
error({ error({
message: message:
'No existing credentials found. Please run ' + 'No existing credentials found. Please run ' +
`${param('now login')} or pass ${param('--token')}`, `${getCommandName('login')} or pass ${param('--token')}`,
slug: 'no-credentials-found', slug: 'no-credentials-found',
}) })
); );
@@ -541,22 +543,6 @@ const main = async argv_ => {
const targetCommand = commands.get(subcommand); const targetCommand = commands.get(subcommand);
if (
!['login', 'logout'].includes(targetCommand) &&
(process.env.NOW_ORG_ID || !scope)
) {
const client = new Client({ apiUrl, token });
const link = await getLinkedOrg(client, output);
if (link.status === 'error') {
return link.exitCode;
}
if (link.status === 'linked') {
scope = link.org.slug;
}
}
if ( if (
typeof scope === 'string' && typeof scope === 'string' &&
targetCommand !== 'login' && targetCommand !== 'login' &&

View File

@@ -187,6 +187,9 @@ export type DNSRecord = {
value: string; value: string;
created: number; created: number;
updated: number; updated: number;
createdAt: number;
updatedAt: number;
domain: string;
}; };
type SRVRecordData = { type SRVRecordData = {

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