Compare commits

..

180 Commits

Author SHA1 Message Date
Leo Lamprecht
5e1b099285 12.0.0-canary.84 2018-09-11 18:34:26 +02:00
Matheus Fernandes
87b1f5a5fb Added new iad1 data center (#1575) 2018-09-11 18:34:08 +02:00
Leo Lamprecht
ae8cbdce0a 12.0.0-canary.83 2018-09-10 19:09:42 +02:00
Cygnusfear
95de48c03f Changed error to log to avoid breaking automatic deployments (#1572)
throwing an error re-opened this issue:
https://github.com/zeit/now-cli/issues/1044

breaks automation when no deployments are found or deployment name is changed
2018-09-10 19:09:36 +02:00
Nathan Rajlich
5ea4fd9a5e Add now whoami to --help (#1573) 2018-09-10 19:06:19 +02:00
Leo Lamprecht
1f3d9e7e0f 12.0.0-canary.82 2018-09-06 21:00:04 +02:00
Jaga Santagostino
05e4528b1c Add changelog link when new version is available (#1530)
* add changelog link if new version is available

* Linked directly
2018-09-06 20:59:24 +02:00
Jarmo Isotalo
40789776bc Prefer URL over deployment ID as the ID not shown in now ls (#1554) 2018-09-06 20:59:19 +02:00
Zeke Sikelianos
75759edd26 Use consistent wording in usage (#1541) 2018-09-06 20:39:53 +02:00
Nathan Rajlich
2a5dc1dba6 Update @zeit/dockerignore to v0.0.3 (#1560)
* Update `@zeit/dockerignore` to v0.0.2

To fix https://github.com/zeit/now-cli/issues/1441.

* Update `@zeit/dockerignore` to v0.0.3
2018-09-06 20:39:09 +02:00
Javi Velasco
0cbf50b7ff 12.0.0-canary.81 2018-09-05 18:00:07 +02:00
Javi Velasco
a3f5b805bb Restructure certs command (#1567)
* Restructure add command

* Remove cert start and finish

* Rename certs add to issue

* Better errors and add cant-solve-challenge

* Show err.sh for dns configuration errors generating certs

* Add err.sh to solve challenges manually

* Add deprecation message to certs add

* Improve grammar

* Minor fixes
2018-09-05 17:58:22 +02:00
Javi Velasco
c337877501 12.0.0-canary.80 2018-09-02 23:24:48 +02:00
Javi Velasco
a6e9dd850a Allow to generate certs solving challenges manually (#1566)
* Move getDomainNameservers function

* Don't show an error as unexpected if there is a code in the error payload

* Add start and finish cert order functions

* Integrate add wildcard cert for external domains

* Use a different endpoint to get a cert by id

* Add new command to download a certificate

* If there are no pending challenges, try to generate the cert right away

* Remove cert download

* Move DNS table options to an object

* Bugfix: cancel spinner message when finish order fails

* Restore add to work only with cert add

* Refactor obtaining cns

* Add start and finish order commands
2018-09-02 23:24:04 +02:00
Leo Lamprecht
a14d4057de 12.0.0-canary.79 2018-09-01 12:18:06 +02:00
Olli Vanhoja
210240ce66 Fix scaling v1 deployments to all DCs (#1556)
```
> Error! An unexpected error occurred in scale: Error: This region (gru1) only accepts Serverless Docker Deployments (400)
```

This is happening because `now-cli` is validating DC names and
expanding "all" locally. However not all DCs have same features but
the client can't be aware of that. Instead of making the client
aware of the differing capabilities of the available DCs we should
pass "all" as a special DC selector, and let the backend handle
scaling properly.
2018-08-28 18:51:52 -07:00
timothyis
d21f7fe75c 12.0.0-canary.78 2018-08-25 15:52:37 +01:00
Timothy
54805cd2a0 Add gru1 (#1545)
* Add gru1

* Add gru to errors

* Hard code sfo,bru scale

* Add --regions argument

* Push with console.log

* Scale to `bru`

* Scale down in bru only
2018-08-25 15:52:16 +01:00
Javi Velasco
c7da2e732a 12.0.0-canary.77 2018-08-24 02:41:01 +02:00
Javi Velasco
4b4beaa892 Pass domain to verify insted of alias when verifying on alias (#1548) 2018-08-24 02:40:35 +02:00
Javi Velasco
e13596acae 12.0.0-canary.76 2018-08-20 20:10:08 +02:00
Javi Velasco
8eb065181f Return scaling validation errors on alias (#1538)
* Return scaling errors on alias

* Join pattern match error in one expression
2018-08-20 19:52:29 +02:00
Javi Velasco
1d97219fef 12.0.0-canary.75 2018-08-20 05:13:55 +02:00
Javi Velasco
d312f94825 Fix updating scale (#1536) 2018-08-20 04:46:55 +02:00
Javi Velasco
478a6f7369 12.0.0-canary.74 2018-08-19 18:22:22 +02:00
Javi Velasco
e309123296 Try to verify against domain name instead of alias (#1534) 2018-08-19 18:21:46 +02:00
Leo Lamprecht
777646cb0e 12.0.0-canary.73 2018-08-13 19:23:27 +02:00
Arunoda Susiripala
39e23f7144 Remove @zeit/schemas (#1507)
We no longer use it inside this repository.
2018-08-13 18:52:58 +02:00
Leo Lamprecht
b68b5c0ea3 12.0.0-canary.72 2018-08-09 12:23:10 +02:00
Sean
46dfeb8ca9 Less cryptic invalid alias message (#1506)
* Less cryptic invalid alias message

* URL -> hostname
2018-08-09 12:23:05 +02:00
Leo Lamprecht
6771ad43af Point Spectrum badge to correct location (#1516) 2018-08-09 12:21:35 +02:00
Luciano Pellacani Franca
1881b9c6cb fixing typo (#1509) 2018-08-07 20:26:05 +01:00
Pranay Prakash
dae6b7a980 12.0.0-canary.71 2018-08-04 03:08:37 +00:00
Pranay Prakash
aed6209f6a Bugfixes and improvements for deployment READY status detection (#1501)
* Have returnify use generators and reinstantiate them upon error

* check for status not_ready instead of 412

* poll every 5s instead of 1s for ready state notification

* poll every 2s for scale verification
2018-08-03 19:31:23 -07:00
Leo Lamprecht
b44a590aa0 12.0.0-canary.70 2018-08-03 08:16:35 +02:00
Olli Vanhoja
936b5fc983 Show selected session affinity when inspecting a deployment (#1489) 2018-08-03 08:12:43 +02:00
yairhaimo
473d6617f2 Include correct help command in now domains (#1492) 2018-08-03 08:11:29 +02:00
Leo Lamprecht
fcf50b5aeb 12.0.0-canary.69 2018-08-02 10:55:58 +02:00
Pranay Prakash
a3835d2e8a Retry 412 errors (#1494)
* retry on 412

* add comment for returnify and exit when the iterator ends
2018-08-02 10:55:02 +02:00
Pranay Prakash
d89481966e poll every 5s (#1496) 2018-08-01 22:56:19 -07:00
Leo Lamprecht
3148ce0f31 12.0.0-canary.68 2018-08-02 07:29:37 +02:00
Leo Lamprecht
f65363856a Better error message for rate limiting deployments (#1495)
* Better error message for rate limiting deployments

* Fixed typo

* Show time until reset

* Removed logging
2018-08-02 07:28:31 +02:00
Leo Lamprecht
e205b57352 12.0.0-canary.67 2018-08-01 13:49:54 +02:00
Aria Malkani
f44a1dbf21 Checks if it is an npm deployment before getting the aliased name (#1490)
* checks it is a npm deployment before reading package.json

* checks if you have a config.type first

* checks if you have a config.type first

* fixed logic for config.type
2018-08-01 13:49:27 +02:00
Leo Lamprecht
b7fe2f606c 12.0.0-canary.66 2018-07-31 10:27:36 +02:00
Leo Lamprecht
6e81c1795c Bumped configuration schemas to the latest version (#1488) 2018-07-31 10:27:22 +02:00
Leo Lamprecht
141d8e4467 12.0.0-canary.65 2018-07-30 13:35:55 +02:00
Robin Millette
edbfeab75f Updated link about authentication file (#1483)
* Fix link to config help

* Update get-default-auth-cfg.js
2018-07-30 13:35:34 +02:00
Robin Millette
e48ea10ebb Updated link about global configuration file (#1482)
* Fix link to config help

* Update get-default-cfg.js
2018-07-30 13:34:52 +02:00
Leo Lamprecht
8565af5526 12.0.0-canary.64 2018-07-30 13:23:30 +02:00
Leo Lamprecht
511d3bae8f Added schema for static header configuration (#1486)
* Added schema for static header configuration

* Bumped yet again
2018-07-30 13:23:07 +02:00
Pranay Prakash
8df233fef1 12.0.0-canary.63 2018-07-29 22:07:06 +00:00
Pranay Prakash
4b97410cc0 Don't downscale previous slot deployment on alias (#1485)
* don't downscale

* use /now/v4/deployments/:id
2018-07-29 15:05:34 -07:00
Leo Lamprecht
aadf8097d1 12.0.0-canary.62 2018-07-24 23:48:57 +02:00
Leo Lamprecht
40d8b74b1b Fixed now billing and use new API (#1477)
* Use correct source when listing

* Use correct source when buying domains

* Replaced the rest too

* Make adding work nicely

* Make listing work for all scopes

* Don't require address

* Bumped lockfile

* Removed more useless code

* Renamed file

* Fixed weird zlib error

* Fixed output

* Added some tests
2018-07-24 23:48:00 +02:00
Leo Lamprecht
8c4d42891c 12.0.0-canary.61 2018-07-22 01:54:51 +02:00
Leo Lamprecht
3672374d23 Fixed integration tests (#1476) 2018-07-22 01:54:05 +02:00
Leo Lamprecht
9ff9d3f174 12.0.0-canary.60 2018-07-19 19:54:19 +02:00
Nathan Rajlich
86540fa7fd Add --build-env to now deploy command (#1459)
* Add `--build-env` to `now deploy` command

Build env vars are only visible during build-time, compared to
regular env vars which are only exposed during runtime.

This also removes the client-side validation of the deployment
schema, because it makes it difficult to keep the client and server
in sync, especially as new features are added. Instead `now-cli`
should be responsible for knowing how to render the server's error
message in an informative and future-proof way so that we can
update the server and even older clients would show the validation
error properly.

* Remove `only` dependency

* Add `--build-env` CLI flag integration test
2018-07-19 19:53:52 +02:00
Pranay Prakash
1538c80a7d 12.0.0-canary.59 2018-07-18 23:29:18 +00:00
Pranay Prakash
0225fcfe51 Improvements to the CLI to handle slot specific flows (#1475)
* Handle scale slots error

* generate and send a requestID when verifying instantiation

* Don't compy incompatible scale settings

* deprecate BinaryDeployment

* add err.sh link

* swap cuid for uuid
2018-07-18 16:26:07 -07:00
Leo Lamprecht
57f3861de6 12.0.0-canary.58 2018-07-17 09:50:26 +02:00
Arunoda Susiripala
04c365a251 Add more integration tests (#1466)
* Add more integration tests related to static builds and env
Here we are adding a few more integration tests for static builds and for using env vars in the build step.

* Add build-env related test case.
2018-07-17 09:47:21 +02:00
Nathan Rajlich
7dfe4690ce 12.0.0-canary.57 2018-07-17 00:10:17 -07:00
Nathan Rajlich
92bcf1b7c9 Remove shallow deployment verification (#1474)
Remove shallow deployment verification
2018-07-17 00:08:55 -07:00
Igor Klopov
8a15d5c65a retry createDeploy if files are missing. addresses #1463 (#1465) 2018-07-13 18:26:12 +03:00
Leo Lamprecht
f64374225d 12.0.0-canary.56 2018-07-11 15:37:44 +02:00
Javi Velasco
7537eac6a7 Control can't solve challenge errors (#1458) 2018-07-11 15:37:22 +02:00
Leo Lamprecht
e2880d2434 12.0.0-canary.55 2018-07-10 19:28:01 +02:00
Javi Velasco
8296de16ef Check domain after adding (#1455)
* Check domain info after adding it

* Add message spiner to show while adding a domain
2018-07-10 19:27:42 +02:00
Leo Lamprecht
5cff5e9dfd 12.0.0-canary.54 2018-07-10 12:16:13 +02:00
Javi Velasco
cb07a748c2 Refactor DNS and update domains with CDN improvements (#1438)
* Do not allow adding domains with subdomains

* Do not ask for confirmation when the domain exists

* Improve message when the domain is under a different account

* Fix flow errors

* Revamp domains add command

* Remove setting dns records when setting up the domain

* Refactor DNS commands

* Hide fields in system dns records and show creator

* Better formatting for dns ls

* Remove exhaustive check of dns record type

* Remove domain ids from responses in domain commands

* Change all `domains` API references to use `v3`

* Update to domains API v3

* Remove NeedUpgrade error and use CDNNeedsUpgrade where it proceeds

* Update copies when adding domains

* Remove extra blank line

* Fix flow errors
2018-07-10 12:13:45 +02:00
Nathan Rajlich
c7b985bdc6 Remove legacy atlas logic (#1451)
* Remove legacy `atlas` logic

No longer used for anything.

* Remove another `atlas`
2018-07-10 11:43:00 +02:00
Javi Velasco
bf32ca0e4a Dont try to generate always wildcard certs when aliasing (#1445)
* Change params order in createAlias

* Make setupDomain return domainInfo

* Do not try to get a wildcard cert for alias when domain is external

* Update setup-domain.js
2018-07-10 11:42:37 +02:00
Javi Velasco
a4e52de0e3 Add retryAfter info to rate limit errors (#1442) 2018-07-10 11:41:28 +02:00
Nathan Rajlich
e43e9b11a0 Wait for static builds to be ready and show logs (#1452)
Implicitly sets the `noVerify` option since there is nothing to verify.
2018-07-10 01:11:10 -07:00
Javi Velasco
847b9e97c4 12.0.0-canary.53 2018-07-09 13:05:01 +02:00
Javi Velasco
baad689286 Fix typo when checking NS during setup domain (#1450) 2018-07-09 12:53:11 +02:00
Arunoda Susiripala
5e7afc4385 12.0.0-canary.52 2018-07-09 09:40:37 +05:30
Matheus Fernandes
d724b7a631 Revert "Upgrade to webpack 4 and latest Babel" (#1448)
* Revert "12.0.0-canary.51"

This reverts commit 5e17fe5ad6.

* Revert "Update `@zeit/schemas` to v1.6.0"

This reverts commit b216adadc0.

* Revert "Upload the Dockerfile if it's a static deployment. (#1437)"

This reverts commit 5078c95667.

* Revert "Upgrade to webpack 4 and latest Babel (#1436)"

This reverts commit 7612d77647.
2018-07-08 20:48:55 -07:00
Nathan Rajlich
5e17fe5ad6 12.0.0-canary.51 2018-07-05 17:52:14 -07:00
Nathan Rajlich
b216adadc0 Update @zeit/schemas to v1.6.0 2018-07-05 17:39:38 -07:00
Arunoda Susiripala
5078c95667 Upload the Dockerfile if it's a static deployment. (#1437)
* Upload the Dockerfile if it's a static deployment.
This allows us to build the Dockerfile and upload static assets

* Allow to upload package.json as well for static deployments.
2018-07-05 22:32:19 +05:30
Javi Velasco
7612d77647 Upgrade to webpack 4 and latest Babel (#1436)
* Upgrade to webpack 4 and last latest

* Fix building commands

* Do not call yarn build when yarn link

* Use resolved paths in webpack config
2018-07-04 17:51:16 +01:00
Leo Lamprecht
0d76041c10 12.0.0-canary.50 2018-07-03 21:20:17 +02:00
Javi Velasco
59be596d24 Allow to deploy and alias when non essential APIs are down (#1435)
* Try to purchase a domain only when there is no other choice

* Allow eventsStream to fail during deployment

* Allow to verify instantiation without events API
2018-07-03 12:18:54 -07:00
Leo Lamprecht
63e51a3c98 12.0.0-canary.49 2018-07-02 11:31:15 +02:00
Leo Lamprecht
7f3128b3e5 Fixed the tests (#1430)
* Fixed the tests

* Wrapped up
2018-07-02 11:30:44 +02:00
Leo Lamprecht
c235813ae7 12.0.0-canary.48 2018-06-22 21:50:33 +02:00
Javi Velasco
3ee18e7051 Small fixes (#1418)
* Remove FlowFixMe in deploy command

* Show success message when creating a cert for alias based on response cns
2018-06-21 23:04:40 -07:00
Leo Lamprecht
14fc5d8796 12.0.0-canary.47 2018-06-21 12:53:44 +02:00
Leo Lamprecht
9fb0077385 Improved error message for schema validation (#1416)
* Bumped schema

* Improved error message for schema validation
2018-06-21 12:53:12 +02:00
Javi Velasco
2e9c7265b6 12.0.0-canary.46 2018-06-19 17:13:48 +02:00
Javi Velasco
d9e77b784a Allow to enable and disable CDN for domains and refactor domains (#1413)
* Move domains command to its own folder

* Refactor domains commands

* Add cdn to domain ls

* Add function to patch domains

* Support toggling cdnEnabled

* Better messages

* Add new cdn options to help command in domains
2018-06-19 17:12:55 +02:00
Javi Velasco
b5b296ad7f 12.0.0-canary.45 2018-06-15 17:35:53 +02:00
Javi Velasco
acdfde5aa2 Deeply nested wildcard certs (#1407)
* Better error when we can't verify a domain during alias

* Remove preferDNS option from CLI and allow wildcard certs for deeply nested
2018-06-15 12:04:10 +02:00
Pranay Prakash
0eddfbd28c Improve the progress bar during upload (#1406)
* use push instead of read

* don't auto-clear

* single progress bar that hangs till last chink

* print symmary beofre link

* print smmary faster

* print more discreet timestamps

* fix tests

* fix flow error
2018-06-13 23:21:39 -04:00
Javi Velasco
037f0610bc 12.0.0-canary.44 2018-06-13 15:39:27 +02:00
Javi Velasco
dd45f8f2ab Request normal cert for deeply nested alias (#1404)
* Request normal cert for deeply nested alias

* When is a deeply nested domain request a normal cert
2018-06-13 15:38:47 +02:00
Leo Lamprecht
d454c84f61 12.0.0-canary.43 2018-06-11 10:40:32 +02:00
Felix Yan
a4c98e07a5 Fix a typo in unique-strings.js (#1400) 2018-06-08 12:20:57 -07:00
Igor Klopov
85715630bd test-integration: test deployment logs output (#1398) 2018-06-08 04:31:36 -07:00
Nathan Rajlich
45d8d4a84f 12.0.0-canary.42 2018-06-07 14:48:16 -07:00
Nathan Rajlich
690882c97a Fix shallow verify (#1397) 2018-06-07 14:45:27 -07:00
Leo Lamprecht
e03836e4a1 12.0.0-canary.41 2018-06-07 11:00:32 +02:00
Leo Lamprecht
d4ec54135a Updated configuration schema (#1394) 2018-06-07 10:59:51 +02:00
Javi Velasco
b29785d851 Ensure there is scale rules before trying to apply (#1389) 2018-06-07 10:52:24 +02:00
Javi Velasco
148870d706 Fixed unexpected error while aliasing (#1387) 2018-06-07 10:50:49 +02:00
Nathan Rajlich
ed1f7e335d Add shallow deployment verification (#1367)
* Add shallow deployment verification

* Add Flow type for `now.retry()`

* Add 3 fetch retries to shallow verify

* Use generics

* Collapse

* Fix

* Add `X-Now-Shallow` verification
2018-06-06 13:08:19 -07:00
Matheus Fernandes
eaf4695194 12.0.0-canary.40 2018-06-01 15:59:43 -07:00
Igor Klopov
c312d42302 reuse getSafeAlias function for all callers of findAliasByAliasOrId (#1385) 2018-06-02 01:27:47 +03:00
Leo Lamprecht
a8a2a6c066 12.0.0-canary.39 2018-05-29 20:07:19 +02:00
Leo Lamprecht
8b3512cb07 Bumped configuration schemas to the latest version (#1379) 2018-05-29 20:06:57 +02:00
Leo Lamprecht
945facdd2c 12.0.0-canary.38 2018-05-29 18:36:15 +02:00
Javi Velasco
8676ed4cff Support for Custom Deployment Suffix (#1378)
* Allow to fallback to passed body parsing a response error

* Extract domain purchase from setup-domain

* Move getCertRequestSettings

* Add create method to Now interface

* Extract print dns table and zeit world table functions

* Add support to generate certificates during deploy

* Point to v5 in deploy endpoint

* Add feedback messages when creating a cert during deployment

* Remove hardcoded references to now.sh

* Dont bump create endpoint version

* Support empty reponses in fetch
2018-05-29 07:58:24 -07:00
Leo Lamprecht
e4d4afa840 12.0.0-canary.37 2018-05-28 13:16:13 +02:00
Leo Lamprecht
81cf286ea4 Bumped configuration schemas to the latest version (#1374) 2018-05-28 13:15:58 +02:00
Leo Lamprecht
e834625728 12.0.0-canary.36 2018-05-28 09:07:30 +02:00
Pranay Prakash
a7c22eb08c add @zeit/dockerignore (#1373) 2018-05-26 09:51:56 -07:00
Leo Lamprecht
837c358371 12.0.0-canary.35 2018-05-25 20:58:30 +02:00
Leo Lamprecht
9743db27e7 Updated configuration schemas to the latest version (#1372) 2018-05-25 11:54:27 -07:00
Tim Neutkens
ce725143e6 12.0.0-canary.34 2018-05-22 17:32:26 +02:00
Tim Neutkens
677805c33a Make sure subdomain is correctly typed / checked (#1364)
Fixes an error introduced in #1344 when running `now alias` on a naked domain like `example.com`.
2018-05-22 17:31:25 +02:00
Pranay Prakash
3d3f1fe39b Make the progress bar for uploads consider bytes, not number of files (#1335)
* use got and propogate uploadProgress

* Accept comma separated cns (#1336)

* use got and propogate uploadProgress

* hook into stream.read

* revert `got` stuff

* remove stray whitespace
2018-05-21 16:40:24 -07:00
Pranay Prakash
123c68ad2b fix clipboard arg parsing (#1358) 2018-05-21 16:39:40 -07:00
Timothy
86861c58af Fix error message via #1350 (#1361) 2018-05-21 16:39:22 -07:00
Pranay Prakash
d4ddb6b3f9 Strip quotes from Dockerfile labels (#1351)
* Strip quotes from Dockerfile labels

* remove console.log

* add test

* issue normal cert for nested subdomain (#1344)

* Prefer HTTP challenge for regular certs

* 12.0.0-canary.31

* Update non-existing team test

* 12.0.0-canary.32

* Bumped `update-check` to the latest version (#1354)

* 12.0.0-canary.33

* Strip quotes from Dockerfile labels

* remove console.log

* add test
2018-05-21 16:39:06 -07:00
Leo Lamprecht
0fc7de40d4 12.0.0-canary.33 2018-05-18 14:06:57 +02:00
Leo Lamprecht
3cb4a9c8dd Bumped update-check to the latest version (#1354) 2018-05-18 14:06:18 +02:00
Javi Velasco
d681289457 12.0.0-canary.32 2018-05-18 03:24:28 +02:00
Javi Velasco
bc1c3c3f5b Update non-existing team test 2018-05-18 03:24:08 +02:00
Javi Velasco
5ae4287c0f 12.0.0-canary.31 2018-05-18 03:02:00 +02:00
Javi Velasco
cde9f56886 Prefer HTTP challenge for regular certs 2018-05-18 03:01:26 +02:00
Pranay Prakash
2b6b006bbd issue normal cert for nested subdomain (#1344) 2018-05-18 02:32:12 +02:00
Leo Lamprecht
54e1bcafc0 12.0.0-canary.30 2018-05-16 21:28:21 +02:00
Leo Lamprecht
7e98d0a22b Store config on platform & load schema from package (#1349)
* Load schema from package

* Send config to deployment endpoint

* Upgraded @zeit/schemas to the latest version

* Removed type for now

* Added config correctly
2018-05-16 21:26:41 +02:00
Tim Neutkens
c27b4a6aaf 12.0.0-canary.29 2018-05-16 18:08:53 +02:00
Javi Velasco
8f17ffd817 Fix table import (#1348) 2018-05-16 18:07:58 +02:00
Leo Lamprecht
0a7d688d32 12.0.0-canary.28 2018-05-15 21:58:07 +02:00
Leo Lamprecht
8cb2fe1284 Account for npm being down (#1346)
* Corrected license file name

* Corrected readme name

* Added editorconfig

* Account for npm being down

* Print full error

* Only show full error while debugging
2018-05-15 21:57:40 +02:00
Leo Lamprecht
e6e375232e 12.0.0-canary.27 2018-05-15 10:07:03 +02:00
Guillermo Rauch
08c4ab8a0c Updated error message about verification timeout 2018-05-15 10:06:37 +02:00
Leo Lamprecht
f86647fc26 12.0.0-canary.26 2018-05-15 10:01:29 +02:00
Javi Velasco
f310f6a86f Accept comma separated cns (#1336) 2018-05-08 21:36:53 +02:00
Javi Velasco
58c6acd265 12.0.0-canary.25 2018-04-27 22:02:10 -07:00
Igor Klopov
c7d97e3866 ignore keep-alive packets for now logs -f (#1331) 2018-04-27 21:45:47 -07:00
Javi Velasco
0890144c61 12.0.0-canary.24 2018-04-26 11:13:14 -07:00
Javi Velasco
69a7d91b57 Safe deployment polling and other minor fixes (#1330)
* Initialize polling function from args

* Remove rule of having a mandatory dest field in path alias rules

* Wait 5 seconds after getting the deployment ready

* Ignore errors coming from events stream
2018-04-26 11:07:15 -07:00
Javi Velasco
a9016c88f6 Refactor scale and remove old alias and scale (#1321)
* Migrate to arg@2.0.0

* Refactor scale command

* Move alias.js to alias/index.js

* Move alias set to its own file

* Move alias ls to its own file

* Move alias rm to its own file

* Remove old alias and scale files

* Update alias integration test

* Fix scaling to 0

* Read scale params from now.json on deploy
2018-04-24 19:16:25 -07:00
Igor Klopov
e8990742cf handle keep-alive event in inspect command (#1326) 2018-04-22 20:16:02 -07:00
Javi Velasco
f51400a3a1 12.0.0-canary.23 2018-04-18 11:27:15 -07:00
Javi Velasco
e763ee5301 Handle ENOENT error when deploying unexistent path (#1320)
* Handle ENOENT error when deploying unexistent path

* Show success on dedupped deployments
2018-04-18 11:26:47 -07:00
Javi Velasco
fd978699e8 Migrate to arg@2.0.0 (#1316) 2018-04-17 19:28:45 -07:00
Javi Velasco
bbd9585829 Fix double ambiguous deploy prompt (#1318) 2018-04-17 19:20:27 -07:00
Javi Velasco
54cf1ebb31 12.0.0-canary.22 2018-04-17 18:07:07 -07:00
Javi Velasco
6fc77c6cfa Fix 0 min scale (#1317) 2018-04-17 18:05:04 -07:00
Javi Velasco
f8372e3bb9 12.0.0-canary.21 2018-04-17 10:49:33 -07:00
Naoyuki Kanezawa
6728be7b1a improve image upload (#1293) 2018-04-17 10:37:17 -07:00
Javi Velasco
65e1a1e731 Fix number of instances verification (#1315) 2018-04-17 10:32:32 -07:00
Javi Velasco
cd9478e853 12.0.0-canary.20 2018-04-16 17:46:47 -07:00
Javi Velasco
b9364ed4fc Improve instance verification for deploy (#1313)
* Refactor verify instances for deploy

* Don't rely on return

* Use new verify instances in alias

* Use new verify instances in alias
2018-04-16 17:45:19 -07:00
Leo Lamprecht
2715e8e9d8 12.0.0-canary.19 2018-04-13 23:23:44 -07:00
Javi Velasco
f987c93cf0 Replace combine-async-generators (#1305)
* Replace combine-asyng-generators

* Ignore empty objects from events stream

* Update type for alias event
2018-04-13 21:55:06 -07:00
Javi Velasco
5c254a7151 Print response in docker test (#1304)
* Print response when failing in docker test file

* Add line

* Parse response text as JSON, print if it fails
2018-04-13 19:49:18 -07:00
Leo Lamprecht
f253e29f33 12.0.0-canary.18 2018-04-13 19:05:49 -07:00
Leo Lamprecht
f37fa13eab Added missing dependencies (#1303) 2018-04-13 19:00:17 -07:00
Javi Velasco
64765b393a Refactor deploy events printing (#1302)
* Move deploy command to its own directory

* Do not show success on downscale message

* Move getDeploymentByIdOrHost to /util/deploy

* Remove unneeded parameter in getAppName

* Better types for copyToClipboard

* Update to babel 7

* Add generator utility functions

* Add function to get deployment events

* Finish  getDeploymentEvents after getting one state-change event

* Refactor deploy events and reduce verification timeout

* Reduce verification timeout for scale and alias

* Use output.log for success message in scale

* Fix integration tests
2018-04-13 18:33:27 -07:00
Leo Lamprecht
54c84b4ce0 12.0.0-canary.17 2018-04-11 12:23:06 -07:00
Javi Velasco
146bcba794 Remove old certs command (#1295) 2018-04-11 12:22:49 -07:00
Leo Lamprecht
d3dd1b731d 12.0.0-canary.16 2018-04-11 11:43:12 -07:00
Javi Velasco
d608ee7390 Remove old alias command (#1294) 2018-04-11 11:42:38 -07:00
Leo Lamprecht
4e2e0950c7 12.0.0-canary.15 2018-04-10 17:53:51 -07:00
Leo Lamprecht
ddc7e97ab6 Fixed typo in release instructions 2018-04-10 17:53:27 -07:00
Leo Lamprecht
a21759ee42 Resolved conflicts 2018-04-10 17:53:02 -07:00
Leo Lamprecht
cc4beb94cf Merge branch 'master' into canary 2018-04-10 17:47:11 -07:00
Leo Lamprecht
0bfafa9311 12.0.0-canary.14 2018-04-10 16:38:48 -07:00
Leo Lamprecht
4eefc34629 Moved documentation for releasing out 2018-04-10 16:26:44 -07:00
Leo Lamprecht
4d3f882dc0 Make clear how a release works exactly 2018-04-10 16:08:39 -07:00
Leo Lamprecht
3a802fbb70 Improved intro and contribution section 2018-04-10 16:07:31 -07:00
Leo Lamprecht
6f00b03d24 Made sure the integration tests work as expected 2018-04-10 15:46:41 -07:00
2447 changed files with 21963 additions and 301560 deletions

View File

@@ -1,135 +1,72 @@
version: 2
jobs:
install:
docker:
- image: circleci/node:10
- image: circleci/node:9.10.0
working_directory: ~/repo
environment:
GOPATH: $HOME/go
steps:
- checkout
- restore_cache:
keys:
- v1-dependencies-{{ checksum "yarn.lock" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- run:
name: Updating apt packages
command: sudo apt-get update
- run:
name: Installing the latest version of Go
command: sudo apt-get install golang-go
- v1-dependencies-{{ checksum "yarn.lock" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- run:
name: Installing Dependencies
command: yarn install --check-files --frozen-lockfile
command: yarn
- save_cache:
paths:
- node_modules
- packages/gatsby-plugin-now/node_modules
- packages/now-build-utils/node_modules
- packages/now-cgi/node_modules
- packages/now-cli/node_modules
- packages/now-client/node_modules
- packages/now-go/node_modules
- packages/now-next/node_modules
- packages/now-node/node_modules
- packages/now-node-bridge/node_modules
- packages/now-python/node_modules
- packages/now-routing-utils/node_modules
- packages/now-ruby/node_modules
- packages/now-static-build/node_modules
key: v1-dependencies-{{ checksum "yarn.lock" }}
- persist_to_workspace:
root: .
paths:
- node_modules
- packages/gatsby-plugin-now/node_modules
- packages/now-build-utils/node_modules
- packages/now-cgi/node_modules
- packages/now-cli/node_modules
- packages/now-client/node_modules
- packages/now-go/node_modules
- packages/now-next/node_modules
- packages/now-node/node_modules
- packages/now-node-bridge/node_modules
- packages/now-python/node_modules
- packages/now-routing-utils/node_modules
- packages/now-ruby/node_modules
- packages/now-static-build/node_modules
build:
docker:
- image: circleci/node:10
- image: circleci/node:9.10.0
working_directory: ~/repo
steps:
- checkout
- run:
name: Installing apt dependencies
command: sudo apt install -y rsync
- attach_workspace:
at: .
- run:
name: Building
command: yarn build
name: Compiling Binaries
command: yarn run pack
- store_artifacts:
path: packages/now-cli/dist
path: packed
- persist_to_workspace:
root: .
paths:
- packages/gatsby-plugin-now/test/fixtures
- packages/now-build-utils/dist
- packages/now-cgi/dist
- packages/now-cli/dist
- packages/now-cli/assets
- packages/now-client/dist
- packages/now-go/dist
- packages/now-next/dist
- packages/now-node/dist
- packages/now-node/test/fixtures/15-helpers/ts/types.d.ts
- packages/now-node/test/fixtures/11-symlinks/symlink
- packages/now-node-bridge/index.js
- packages/now-node-bridge/bridge.js
- packages/now-python/dist
- packages/now-routing-utils/dist
- packages/now-ruby/dist
- packages/now-static-build/dist
- packages/now-static-build/test/fixtures/10a-gatsby-redirects/plugins
- packed
test-lint:
docker:
- image: circleci/node:10
- image: circleci/node:9.10.0
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Compiling `now dev` HTML error templates
command: node packages/now-cli/scripts/compile-templates.js
- run:
name: Linting Code
command: yarn test-lint
# test-unit:
# docker:
# - image: circleci/node:10
# working_directory: ~/repo
# steps:
# - checkout
# - attach_workspace:
# at: .
# - run:
# name: Compiling `now dev` HTML error templates
# command: node packages/now-cli/scripts/compile-templates.js
# - run:
# name: Running Unit Tests
# command: yarn test-unit --clean false
# - persist_to_workspace:
# root: .
# paths:
# - packages/now-cli/.nyc_output
test-unit:
docker:
- image: circleci/node:9.10.0
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Running Unit Tests
command: yarn test-unit
test-integration-macos-node-8:
test-integration:
macos:
xcode: '9.2.0'
working_directory: ~/repo
@@ -137,259 +74,59 @@ jobs:
- checkout
- attach_workspace:
at: .
- run:
name: Update Node.js
command: curl -sfLS install-node.now.sh/8.11 | sh -s -- --yes
- run:
name: Output version
command: node --version
- run:
name: Running Integration Tests
command: yarn test-integration --clean false
command: yarn test-integration
test-integration-macos-node-10:
macos:
xcode: '10.0.0'
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Running Integration Tests
command: yarn test-integration --clean false
test-integration-macos-node-12:
macos:
xcode: '10.3.0'
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Running Integration Tests
command: yarn test-integration --clean false
test-integration-linux-node-8:
compress:
docker:
- image: circleci/node:8
- image: circleci/node:9.10.0
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Running Integration Tests
command: yarn test-integration --clean false
name: Compressing Binaries
command: yarn gzip
- persist_to_workspace:
root: .
paths:
- packed
test-integration-linux-node-10:
upload:
docker:
- image: circleci/node:10
- image: circleci/golang:1.10
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- restore_cache:
keys:
- v1-pkg-cache
- run:
name: Output version
command: node --version
name: Installing Uploader
command: go get github.com/aktau/github-release
- run:
name: Running Integration Tests
command: yarn test-integration --clean false
test-integration-linux-node-12:
docker:
- image: circleci/node:12
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Running Integration Tests
command: yarn test-integration --clean false
test-integration-macos-now-dev-node-8:
macos:
xcode: '9.2.0'
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Update Node.js
command: curl -sfLS install-node.now.sh/8.11 | sh -s -- --yes
- run:
name: Output version
command: node --version
- run:
name: Downloading Hugo
command: 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:
name: Running Integration Tests for `now dev`
command: yarn test-integration-now-dev --clean false
test-integration-macos-now-dev-node-10:
macos:
xcode: '10.0.0'
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Downloading Hugo
command: 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:
name: Running Integration Tests for `now dev`
command: yarn test-integration-now-dev --clean false
test-integration-macos-now-dev-node-12:
macos:
xcode: '10.3.0'
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Downloading Hugo
command: 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:
name: Running Integration Tests for `now dev`
command: yarn test-integration-now-dev --clean false
test-integration-linux-now-dev-node-8:
docker:
- image: circleci/node:8
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Downloading Hugo
command: curl -L -O https://github.com/gohugoio/hugo/releases/download/v0.55.6/hugo_0.55.6_Linux-64bit.tar.gz && tar -xzf hugo_0.55.6_Linux-64bit.tar.gz && mv ./hugo packages/now-cli/test/dev/fixtures/08-hugo/
- run:
name: Running Integration Tests for `now dev`
command: yarn test-integration-now-dev --clean false
test-integration-linux-now-dev-node-10:
docker:
- image: circleci/node:10
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Downloading Hugo
command: curl -L -O https://github.com/gohugoio/hugo/releases/download/v0.55.6/hugo_0.55.6_Linux-64bit.tar.gz && tar -xzf hugo_0.55.6_Linux-64bit.tar.gz && mv ./hugo packages/now-cli/test/dev/fixtures/08-hugo/
- run:
name: Running Integration Tests for `now dev`
command: yarn test-integration-now-dev --clean false
test-integration-linux-now-dev-node-12:
docker:
- image: circleci/node:12
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Downloading Hugo
command: curl -L -O https://github.com/gohugoio/hugo/releases/download/v0.55.6/hugo_0.55.6_Linux-64bit.tar.gz && tar -xzf hugo_0.55.6_Linux-64bit.tar.gz && mv ./hugo packages/now-cli/test/dev/fixtures/08-hugo/
- run:
name: Running Integration Tests for `now dev`
command: yarn test-integration-now-dev --clean false
test-integration-once:
docker:
- image: circleci/node:10
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Output version
command: node --version
- run:
name: Running Integration Tests Once
command: yarn test-integration-once --clean false
coverage:
docker:
- image: circleci/node:10
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Compiling `now dev` HTML error templates
command: node packages/now-cli/scripts/compile-templates.js
- run:
name: Run unit tests
command: yarn workspace now run test-unit
- run:
name: Run coverage report
command: yarn workspace now run coverage
source-maps:
docker:
- image: circleci/node:10
working_directory: ~/repo
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Installing Sentry CLI
command: npm install -g @sentry/cli
- run:
name: Creating a New Sentry Release
command: sentry-cli releases new now-cli@`git describe --tags`
- run:
name: Upload Sourcemap Files
command: sentry-cli releases files now-cli@`git describe --tags` upload-sourcemaps ./dist
- run:
name: Finalize Sentry Release
command: sentry-cli releases finalize now-cli@`git describe --tags`
name: Uploading Binaries
command:
>-
for file in ./packed/*.gz;
do
github-release upload -R -t `git describe --tags` -n ${file##*/} -f $file
done
- save_cache:
key: v1-pkg-cache
paths:
- "/go/pkg"
publish-stable:
docker:
- image: circleci/node:10
- image: circleci/node:9.10.0
working_directory: ~/repo
steps:
- checkout
@@ -404,7 +141,7 @@ jobs:
publish-canary:
docker:
- image: circleci/node:10
- image: circleci/node:9.10.0
working_directory: ~/repo
steps:
- checkout
@@ -437,123 +174,43 @@ workflows:
filters:
tags:
only: /.*/
# - test-unit:
# requires:
# - build
# filters:
# tags:
# only: /.*/
- test-integration-macos-node-8:
- test-unit:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-macos-node-10:
- test-integration:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-macos-node-12:
- compress:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-linux-node-8:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-linux-node-10:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-linux-node-12:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-macos-now-dev-node-8:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-macos-now-dev-node-10:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-macos-now-dev-node-12:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-linux-now-dev-node-8:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-linux-now-dev-node-10:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-linux-now-dev-node-12:
requires:
- build
filters:
tags:
only: /.*/
- test-integration-once:
requires:
- build
filters:
tags:
only: /.*/
- coverage:
requires:
#- test-unit
- test-integration-macos-node-8
- test-integration-macos-node-10
- test-integration-macos-node-12
- test-integration-linux-node-8
- test-integration-linux-node-10
- test-integration-linux-node-12
- test-integration-macos-now-dev-node-8
- test-integration-macos-now-dev-node-10
- test-integration-macos-now-dev-node-12
- test-integration-linux-now-dev-node-8
- test-integration-linux-now-dev-node-10
- test-integration-linux-now-dev-node-12
- test-integration-once
- test-lint
- test-integration
- test-unit
filters:
tags:
only: /.*/
branches:
ignore: /.*/
- upload:
requires:
- compress
filters:
tags:
only: /.*/
- publish-canary:
requires:
- coverage
- upload
filters:
tags:
only: /^.*canary.*($|\b)/
branches:
ignore: /.*/
- publish-stable:
requires:
- coverage
- upload
filters:
tags:
only: /^(\d+\.)?(\d+\.)?(\*|\d+)$/
branches:
ignore: /.*/

View File

@@ -1,34 +0,0 @@
#!/bin/bash
set -euo pipefail
if [ -z "$NPM_TOKEN" ]; then
echo "NPM_TOKEN not found. Did you forget to assign the GitHub Action secret?"
exit 1
fi
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
if [ ! -e ~/.npmrc ]; then
echo "~/.npmrc file does not exist, skipping publish"
exit 0
fi
npm_tag=""
tag="$(git describe --tags --exact-match 2> /dev/null || :)"
if [ -z "$tag" ]; then
echo "Not a tagged commit, skipping publish"
exit 0
fi
if [[ "$tag" =~ -canary ]]; then
echo "Publishing canary release"
npm_tag="--npm-tag canary"
else
echo "Publishing stable release"
fi
# Sometimes this is a false alarm and blocks publish
git checkout yarn.lock
yarn run lerna publish from-git $npm_tag --yes

View File

@@ -1,32 +0,0 @@
node_modules
dist
# gatsby-plugin-now
packages/gatsby-plugin-now/test/fixtures
# now-cli
packages/now-cli/@types
packages/now-cli/download
packages/now-cli/dist
packages/now-cli/test/fixtures
packages/now-cli/test/dev/fixtures
packages/now-cli/bin
packages/now-cli/link
packages/now-cli/src/util/dev/templates/*.ts
# now-client
packages/now-client/tests/fixtures
packages/now-client/lib
# now-next
packages/now-next/test/fixtures
# now-node
packages/now-node/src/bridge.ts
packages/now-node/test/fixtures
# now-node-bridge
packages/now-node-bridge/bridge.*
# now-static-build
packages/now-static-build/test/fixtures

View File

@@ -1,64 +0,0 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"modules": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
"prettier/@typescript-eslint"
],
"env": {
"node": true,
"jest": true,
"es6": true
},
"rules": {
"require-atomic-updates": 0,
"@typescript-eslint/ban-ts-ignore": 0,
"@typescript-eslint/camelcase": 0,
"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/no-use-before-define": 0
},
"overrides": [
{
"files": ["**/*.js"],
"rules": {
"@typescript-eslint/no-var-requires": "off"
}
},
{
"files": ["packages/now-cli/**/*"],
"rules": {
"lines-between-class-members": 0,
"no-async-promise-executor": 0,
"no-control-regex": 0,
"no-empty": 0,
"prefer-const": 0,
"prefer-destructuring": 0,
"@typescript-eslint/ban-types": 0,
"@typescript-eslint/consistent-type-assertions": 0,
"@typescript-eslint/member-delimiter-style": 0,
"@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-inferrable-types": 0,
"@typescript-eslint/no-var-requires": 0
}
},
{
"files": ["packages/now-client/**/*"],
"rules": {
"prefer-const": 0,
"require-atomic-updates": 0,
"@typescript-eslint/ban-ts-ignore": 0,
"@typescript-eslint/no-explicit-any": 0
}
}
]
}

2
.flowconfig Normal file
View File

@@ -0,0 +1,2 @@
[ignore]
.*/node_modules/.*/\(test\).*\.json$

3
.gitattributes vendored
View File

@@ -1,3 +0,0 @@
# Ignore test fixtures in GitHub Languages
# See https://github.com/github/linguist#vendored-code
packages/*/test/* linguist-vendored

18
.github/CODEOWNERS vendored
View File

@@ -1,18 +0,0 @@
# Documentation
# https://help.github.com/en/articles/about-code-owners
* @tootallnate @leo
/packages/now-cli/src/commands/dev/ @tootallnate @leo @styfle @AndyBitz
/packages/now-cli/src/util/dev/ @tootallnate @leo @styfle @AndyBitz
/packages/now-cli/src/commands/domains/ @javivelasco @mglagola @anatrajkovska
/packages/now-cli/src/commands/certs/ @javivelasco @mglagola @anatrajkovska
/packages/now-client @leo @rdev
/packages/now-build-utils @styfle @AndyBitz
/packages/now-node @styfle @tootallnate @lucleray
/packages/now-node-bridge @styfle @tootallnate @lucleray
/packages/now-next @Timer
/packages/now-go @styfle @sophearak
/packages/now-python @styfle @sophearak
/packages/now-ruby @styfle @coetry @nathancahill
/packages/now-static-build @styfle @AndyBitz
/packages/now-routing-utils @dav-is

View File

@@ -1,33 +0,0 @@
name: Publish
on:
push:
branches:
- master
- canary
tags:
- '!*'
jobs:
publish:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10.x]
steps:
- uses: actions/checkout@v1
- name: Checkout
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Install
run: yarn install --check-files --frozen-lockfile
- name: Build
run: yarn build
- name: Publish
run: yarn publish-from-github
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

22
.gitignore vendored
View File

@@ -1,20 +1,12 @@
# dependencies
node_modules
package-lock.json
# build output
dist
packed
test/fixtures/integration
# logs
npm-debug.log
yarn-error.log
.nyc_output
coverage
*.swp
*.bak
*.tgz
packages/now-cli/.builders
packages/now-cli/assets
packages/now-cli/src/util/dev/templates/*.ts
packages/now-cli/test/**/yarn.lock
!packages/now-cli/test/dev/**/yarn.lock
packages/now-cli/test/**/node_modules
packages/now-cli/test/dev/fixtures/08-hugo/hugo
packages/now-cli/test/dev/fixtures/**/dist
packages/now-cli/test/dev/fixtures/**/public
packages/now-cli/test/fixtures/integration

View File

@@ -1,16 +0,0 @@
version = 1
[merge]
automerge_label = "automerge"
blacklist_title_regex = "^WIP.*"
blacklist_labels = ["work in progress"]
method = "squash"
delete_branch_on_merge = true
block_on_reviews_requested = false
notify_on_conflict = true
optimistic_updates = true
[merge.message]
title = "pull_request_title"
include_pr_number = true
body_type = "markdown"

View File

@@ -1,4 +0,0 @@
{
"singleQuote": true,
"trailingComma": "es5"
}

View File

@@ -1 +1 @@
save-prefix ""
save-prefix ""

View File

@@ -1,74 +0,0 @@
## Code of Conduct
### Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
### Our Standards
Examples of behavior that contributes to creating a positive environment
include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or
advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic
address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
### Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
### Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
### Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at [abuse@zeit.co](mailto:abuse@zeit.co). All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
### Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@@ -1,96 +0,0 @@
# Contributing
When contributing to this repository, please first discuss the change you wish to make via [GitHub Issue](https://github.com/zeit/now/issues/new) or [Spectrum](https://spectrum.chat/zeit) with the owners of this repository before submitting a Pull Request.
Please read our [code of conduct](CODE_OF_CONDUCT.md) and follow it in all your interactions with the project.
## Local development
This project is configured in a monorepo pattern where one repo contains multiple npm packages. Dependencies are installed and managed with `yarn`, not `npm` CLI.
To get started, execute the following:
```
git clone https://github.com/zeit/now
yarn install
yarn bootstrap
yarn build
yarn lint
yarn test
```
Make sure all the tests pass before making changes.
## Verifying your change
Once you are done with your changes (we even suggest doing it along the way ), make sure all the test still run by running
```
yarn build && yarn test
```
from the root of the project.
If any test fails, make sure to fix it along with your changes. See [Interpreting test errors](#Interpreting-test-errors) for more information about how the tests are executed, especially the integration tests.
## Pull Request Process
Once you are confident that your changes work properly, open a pull request on the main repository.
The pull request will be reviewed by the maintainers and the tests will be checked by our continuous integration platform.
## Interpreting test errors
There are 2 kinds of tests in this repository Unit tests and Integration tests.
Unit tests are run locally with `jest` and execute quickly because they are testing the smallest units of code.
### Integration tests
Integration tests create deployments to your ZEIT account using the `test` project name. After each test is deployed, the `probes` key is used to check if the response is the expected value. If the value doesn't match, you'll see a message explaining the difference. If the deployment failed to build, you'll see a more generic message like the following:
```
[Error: Fetched page https://test-8ashcdlew.now.sh/root.js does not contain hello Root!. Instead it contains An error occurred with this application.
NO_STATUS_CODE_FRO Response headers:
cache-control=s-maxage=0
connection=close
content-type=text/plain; charset=utf-8
date=Wed, 19 Jun 2019 18:01:37 GMT
server=now
strict-transport-security=max-age=63072000
transfer-encoding=chunked
x-now-id=iad1:hgtzj-1560967297876-44ae12559f95
x-now-trace=iad1]
```
In such cases you can visit the URL of the failed deployment and append `/_logs` so see the build error. In the case above, that would be https://test-8ashcdlew.now.sh/_logs
The logs of this deployment will contain the actual error which may help you to understand what went wrong.
### @zeit/node-file-trace
Some of the Builders use `@zeit/node-file-trace` to tree-shake files before deployment. If you suspect an error with this tree-shaking mechanism, you can create the following script in your project:
```js
const trace = require('@zeit/node-file-trace');
trace(['path/to/entrypoint.js'], {
ts: true,
mixedModules: true,
})
.then(o => console.log(o.fileList))
.then(e => console.error(e));
```
When you run this script, you'll see all imported files. If anything file is missing, the bug is in [@zeit/node-file-trace](https://github.com/zeit/node-file-trace) and not the Builder.
## Deploy a Builder with existing project
Sometimes you want to test changes to a Builder against an existing project, maybe with `now dev` or an actual deployment. You can avoid publishing every Builder change to npm by uploading the Builder as a tarball.
1. Change directory to the desired Builder `cd ./packages/now-node`
2. Run `yarn build` to compile typescript and other build steps
3. Run `npm pack` to create a tarball file
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
6. Run `now` or `now dev` to deploy with the experimental Builder

View File

@@ -1,447 +0,0 @@
# Builders Developer Reference
The following page is a reference for how to create a Builder using the available Builder's API.
A Builder is an npm module that exposes a `build` function and optionally an `analyze` function and `prepareCache` function.
Official Builders are published to [npmjs.com](https://npmjs.com) as a package and referenced in the `use` property of the `now.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 Builder.
See the [Builders Documentation](https://zeit.co/docs/v2/advanced/builders) to view example usage.
## Builder Exports
### `version`
A **required** exported constant that decides which version of the Builder API to use.
The latest and suggested version is `2`.
### `analyze`
An **optional** exported function that returns a unique fingerprint used for the purpose of [build de-duplication](https://zeit.co/docs/v2/advanced/concepts/immutability#deduplication-algorithm). If the `analyze` function is not supplied, a random fingerprint is assigned to each build.
```js
export analyze({
files: Files,
entrypoint: String,
workPath: String,
config: Object
}) : String fingerprint
```
If you are using TypeScript, you should use the following types:
```ts
import { AnalyzeOptions } from '@now/build-utils'
export analyze(options: AnalyzeOptions) {
return 'fingerprint goes here'
}
```
### `build`
A **required** exported function that returns a [Files](#files) data structure that contains the Build outputs, which can be a [Static File](#file) or a [Serverless Function](#serverless-function).
What's a Serverless Function? Read about [Serverless Function concepts](https://zeit.co/docs/v2/deployments/concepts/lambdas) to learn more.
```js
build({
files: Files,
entrypoint: String,
workPath: String,
config: Object,
meta?: {
isDev?: Boolean,
requestPath?: String,
filesChanged?: Array<String>,
filesRemoved?: Array<String>
}
}) : {
watch: Array<String>,
output: Files output,
routes: Object
}
```
If you are using TypeScript, you should use the following types:
```ts
import { BuildOptions } from '@now/build-utils'
export build(options: BuildOptions) {
// Build the code here
return {
output: {
'path-to-file': File,
'path-to-lambda': Lambda
},
watch: [],
routes: {}
}
}
```
### `prepareCache`
An **optional** exported function that is equivalent to [`build`](#build), but it executes the instructions necessary to prepare a cache for the next run.
```js
prepareCache({
files: Files,
entrypoint: String,
workPath: String,
cachePath: String,
config: Object
}) : Files cacheOutput
```
If you are using TypeScript, you can import the types for each of these functions by using the following:
```ts
import { PrepareCacheOptions } from '@now/build-utils'
export prepareCache(options: PrepareCacheOptions) {
return { 'path-to-file': File }
}
```
### `shouldServe`
An **optional** exported function that is only used by `now dev` in [Now CLI](https:///download) and indicates whether a [Builder](https://zeit.co/docs/v2/advanced/builders) wants to be responsible for building a certain request path.
```js
shouldServe({
entrypoint: String,
files: Files,
config: Object,
requestPath: String,
workPath: String
}) : Boolean
```
If you are using TypeScript, you can import the types for each of these functions by using the following:
```ts
import { ShouldServeOptions } from '@now/build-utils'
export shouldServe(options: ShouldServeOptions) {
return Boolean
}
```
If this method is not defined, Now CLI will default to [this function](https://github.com/zeit/now/blob/52994bfe26c5f4f179bdb49783ee57ce19334631/packages/now-build-utils/src/should-serve.ts).
### Builder Options
The exported functions [`analyze`](#analyze), [`build`](#build), and [`prepareCache`](#preparecache) receive one argument with the following properties.
**Properties:**
- `files`: All source files of the project as a [Files](#files) data structure.
- `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).
- `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`.
## Example: html-minifier
Let's walk through what it takes to create a simple builder that takes in a HTML source file and yields a minified HTML static file as its build output.
While this is a very simple builder, the approach demonstrated here can be used to return anything: one or more static files and/or one or more lambdas.
## Setting up the module
### Defining the analyze step
The `analyze` hook is optional. Its goal is to give the developer a tool to avoid wasting time _re-computing a build_ that has already occurred.
The return value of `analyze` is a _fingerprint_: a simple string that uniquely identifies the build process.
If `analyze` is not specified, its behavior is to use as the fingerprint the combined checksums of **all the files in the same directory level as the entrypoint**. This is a default that errs on making sure that we re-execute builds when files _other than the entrypoint_ (like dependencies, manifest files, etc) have changed.
For our `html-minify` example, we know that HTML files don't have dependencies. Therefore, our analyze step can just return the `digest` of the entrypoint.
Our `index.js` file looks as follows:
```js
exports.analyze = function({ files, entrypoint }) {
return files[entrypoint].digest
}
```
This means that we will only re-minify and re-create the build output _only if the file contents (and therefore its digest) change._
### Defining the build step
Your module will need some utilities to manipulate the data structures we pass you, create new ones and alter the filesystem.
To that end, we expose our API as part of a `@now/build-utils` package. This package is always loaded on your behalf, so make sure it's only included as `peerDependencies` in your `package.json`.
Builders can include dependencies of their liking:
```js
const htmlMinifier = require('html-minifier')
exports.version = 2
exports.analyze = ({ files, entrypoint }) => files[entrypoint].digest
exports.build = async ({ files, entrypoint, config }) => {
const stream = files[entrypoint].toStream()
const options = Object.assign({}, config || {})
const { data } = await FileBlob.fromStream({ stream })
const content = data.toString()
const minified = htmlMinifier(content, options)
const result = new FileBlob({ data: minified })
return {
output: {
[entrypoint]: result
},
watch: [],
routes: {}
}
}
```
### Defining a `prepareCache` step
If our builder had performed work that could be re-used in the next build invocation, we could define a `prepareCache` step.
In this case, there are not intermediate artifacts that we can cache, and our `analyze` step already takes care of caching the full output based on the fingerprint of the input.
## Technical Details
### Execution Context
A [Serverless Function](https://zeit.co/docs/v2/advanced/concepts/lambdas) is created where the builder logic is executed. The lambda is run using the Node.js 8 runtime. A brand new sandbox is created for each deployment, for security reasons. The sandbox is cleaned up between executions to ensure no lingering temporary files are shared from build to build.
All the APIs you export ([`analyze`](#analyze), [`build`](#build) and [`prepareCache`](#preparecache)) are not guaranteed to be run in the same process, but the filesystem we expose (e.g.: `workPath` and the results of calling [`getWriteableDirectory`](#getWriteableDirectory) ) is retained.
If you need to share state between those steps, use the filesystem.
### Directory and Cache Lifecycle
When a new build is created, we pre-populate the `workPath` supplied to `analyze` with the results of the `prepareCache` step of the previous build.
The `analyze` step can modify that directory, and it will not be re-created when it's supplied to `build` and `prepareCache`.
To learn how the cache key is computed and invalidated, refer to the [overview](https://zeit.co/docs/v2/advanced/builders#technical-details).
### Accessing Environment and Secrets
The env and secrets specified by the user as `build.env` are passed to the builder process. This means you can access user env via `process.env` in Node.js.
### Utilities as peerDependencies
When you publish your builder to npm, make sure to not specify `@now/build-utils` (as seen below in the API definitions) as a dependency, but rather as part of `peerDependencies`.
## Types
### `Files`
```ts
import { File } from '@now/build-utils'
type Files = { [filePath: string]: File }
```
This is an abstract type that is implemented as a plain [JavaScript Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object). It's helpful to think of it as a virtual filesystem representation.
When used as an input, the `Files` object will only contain `FileRefs`. When `Files` is an output, it may consist of `Lambda` (Serverless Functions) types as well as `FileRefs`.
An example of a valid output `Files` object is:
```json
{
"index.html": FileRef,
"api/index.js": Lambda
}
```
### `File`
This is an abstract type that can be imported if you are using TypeScript.
```ts
import { File } from '@now/build-utils'
```
Valid `File` types include:
- [`FileRef`](#fileref)
- [`FileFsRef`](#filefsref)
- [`FileBlob`](#fileblob)
### `FileRef`
```ts
import { FileRef } from '@now/build-utils'
```
This is a [JavaScript class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) that represents an abstract file instance stored in our platform, based on the file identifier string (its checksum). When a `Files` object is passed as an input to `analyze` or `build`, all its values will be instances of `FileRef`.
**Properties:**
- `mode : Number` file mode
- `digest : String` a checksum that represents the file
**Methods:**
- `toStream() : Stream` creates a [Stream](https://nodejs.org/api/stream.html) of the file body
### `FileFsRef`
```ts
import { FileFsRef } from '@now/build-utils'
```
This is a [JavaScript class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) that represents an abstract instance of a file present in the filesystem that the build process is executing in.
**Properties:**
- `mode : Number` file mode
- `fsPath : String` the absolute path of the file in file system
**Methods:**
- `static async fromStream({ mode : Number, stream : Stream, fsPath : String }) : FileFsRef` creates an instance of a [FileFsRef](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) from `Stream`, placing file at `fsPath` with `mode`
- `toStream() : Stream` creates a [Stream](https://nodejs.org/api/stream.html) of the file body
### `FileBlob`
```ts
import { FileBlob } from '@now/build-utils'
```
This is a [JavaScript class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) that represents an abstract instance of a file present in memory.
**Properties:**
- `mode : Number` file mode
- `data : String | Buffer` the body of the file
**Methods:**
- `static async fromStream({ mode : Number, stream : Stream }) :FileBlob` creates an instance of a [FileBlob](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) from [`Stream`](https://nodejs.org/api/stream.html) with `mode`
- `toStream() : Stream` creates a [Stream](https://nodejs.org/api/stream.html) of the file body
### `Lambda`
```ts
import { Lambda } from '@now/build-utils'
```
This is a [JavaScript class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes), called a Serverless Function, that can be created by supplying `files`, `handler`, `runtime`, and `environment` as an object to the [`createLambda`](#createlambda) helper. The instances of this class should not be created directly. Instead use a call to [`createLambda`](#createlambda).
**Properties:**
- `files : Files` the internal filesystem of the lambda
- `handler : String` path to handler file and (optionally) a function name it exports
- `runtime : LambdaRuntime` the name of the lambda runtime
- `environment : Object` key-value map of handler-related (aside of those passed by user) environment variables
### `LambdaRuntime`
This is an abstract enumeration type that is implemented by one of the following possible `String` values:
- `nodejs10.x`
- `nodejs8.10`
- `go1.x`
- `java-1.8.0-openjdk`
- `python3.6`
- `python2.7`
- `dotnetcore2.1`
- `dotnetcore2.0`
- `dotnetcore1.0`
## JavaScript API
The following is exposed by `@now/build-utils` to simplify the process of writing Builders, manipulating the file system, using the above types, etc.
### `createLambda`
Signature: `createLambda(Object spec) : Lambda`
```ts
import { createLambda } from '@now/build-utils'
```
Constructor for the [`Lambda`](#lambda) type.
```js
const { createLambda, FileBlob } = require('@now/build-utils')
await createLambda({
runtime: 'nodejs8.10',
handler: 'index.main',
files: {
'index.js': new FileBlob({ data: 'exports.main = () => {}' })
}
})
```
### `download`
Signature: `download() : Files`
```ts
import { download } from '@now/build-utils'
```
This utility allows you to download the contents of a [`Files`](#files) data structure, therefore creating the filesystem represented in it.
Since `Files` is an abstract way of representing files, you can think of `download` as a way of making that virtual filesystem _real_.
If the **optional** `meta` property is passed (the argument for [build](#build)), only the files that have changed are downloaded. This is decided using `filesRemoved` and `filesChanged` inside that object.
```js
await download(files, workPath, meta)
```
### `glob`
Signature: `glob() : Files`
```ts
import { glob } from '@now/build-utils'
```
This utility allows you to _scan_ the filesystem and return a [`Files`](#files) representation of the matched glob search string. It can be thought of as the reverse of [`download`](#download).
The following trivial example downloads everything to the filesystem, only to return it back (therefore just re-creating the passed-in [`Files`](#files)):
```js
const { glob, download } = require('@now/build-utils')
exports.build = ({ files, workPath }) => {
await download(files, workPath)
return glob('**', workPath)
}
```
### `getWriteableDirectory`
Signature: `getWriteableDirectory() : String`
```ts
import { getWriteableDirectory } from '@now/build-utils'
```
In some occasions, you might want to write to a temporary directory.
### `rename`
Signature: `rename(Files) : Files`
```ts
import { rename } from '@now/build-utils'
```
Renames the keys of the [`Files`](#files) object, which represent the paths. For example, to remove the `*.go` suffix you can use:
```js
const rename = require('@now/build-utils')
const originalFiles = { 'one.go': fileFsRef1, 'two.go': fileFsRef2 }
const renamedFiles = rename(originalFiles, path => path.replace(/\.go$/, '')
```

View File

@@ -1,40 +0,0 @@
# Publishing to npm
Always publish to the Canary Channel as soon as a PR is merged into the `canary` branch.
```
yarn publish-canary
```
Publish the Stable Channel weekly.
- Cherry pick each commit from `canary` to `master` branch
- Verify that you are _in-sync_ with canary (with the exception of the `version` line in `package.json`)
- Deploy the modified Builders
```
# View differences excluding "Publish" commits
git checkout canary && git pull
git log --pretty=format:"$ad- %s [%an]" | grep -v Publish > ~/Desktop/canary.txt
git checkout master && git pull
git log --pretty=format:"$ad- %s [%an]" | grep -v Publish > ~/Desktop/master.txt
diff ~/Desktop/canary.txt ~/Desktop/master.txt
# Cherry pick all PRs from canary into master ...
git cherry-pick <PR501_COMMIT_SHA>
git cherry-pick <PR502_COMMIT_SHA>
git cherry-pick <PR503_COMMIT_SHA>
git cherry-pick <PR504_COMMIT_SHA>
# Verify the only difference is "version" in package.json
git diff origin/canary
# Ship it
yarn publish-stable
```
After running this publish step, GitHub Actions will take care of publishing the modified Builder packages to npm.
If for some reason GitHub Actions fails to publish the npm package, you may do so
manually by running `npm publish` from the package directory. Make sure to
use `npm publish --tag canary` if you are publishing a canary release!

View File

@@ -1,26 +1,18 @@
![now](https://assets.zeit.co/image/upload/v1542240976/repositories/now-cli/now-cli-repo-banner-v3.png)
![now](https://github.com/zeit/art/blob/a7867d60f54a41127023a8740a221921df309d24/now-cli/repo-banner.png?raw=true)
[![Build Status](https://circleci.com/gh/zeit/now.svg?&style=shield)](https://circleci.com/gh/zeit/workflows/now)
[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/zeit)
[![Build Status](https://circleci.com/gh/zeit/now-cli.svg?&style=shield)](https://circleci.com/gh/zeit/workflows/now-cli) [![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/zeit)
**Note**: The [canary](https://github.com/zeit/now/tree/canary) branch is under heavy development the stable release branch is [master](https://github.com/zeit/now/tree/master).
**Note**: The [canary](https://github.com/zeit/now-cli/tree/canary) branch is under heavy development the stable release branch is [master](https://github.com/zeit/now-cli/tree/master).
## Usage
To install the latest version of Now CLI, visit [zeit.co/download](https://zeit.co/download) or run this command:
To install the latest version of Now CLI, run this command:
```
npm i -g now
npm install -g now
```
To quickly start a new project, run the following commands:
```
now init # Pick an example project to clone
cd <PROJECT> # Change directory to the newly created project
now dev # Run locally during development
now # Deploy to the cloud
```
There are also [other installation methods](https://zeit.co/download) available.
## Documentation
@@ -29,13 +21,11 @@ For details on how to use Now CLI, check out our [documentation](https://zeit.co
## Caught a Bug?
1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device
2. Install dependencies with `yarn install`
3. Compile the code: `yarn build`
4. Link the package to the global module directory: `yarn link`
5. You can now start using `now` anywhere inside the command line
2. Link the package to the global module directory: `yarn run link` (not `yarn link`)
3. You can now start using `now` from 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 can use `yarn test` to run the tests and see if your changes have broken anything.
## How to Create a Release
If you have write access to this repository, you can read more about how to publish a release [here](https://github.com/zeit/now/wiki/Creating-a-Release).
If you have write access to this repository, you can read more about how to publish a release [here](https://github.com/zeit/zeit/blob/master/guides/now-cli-release.md).

View File

@@ -1,25 +0,0 @@
# Versioning
Builders are released to two different channels.
## Channels
| Channel | Git Branch | npm dist-tag | use example |
| ------- | ------------------------------------------------------------- | ------------ | ------------------ |
| Canary | [canary](https://github.com/zeit/now/commits/canary) | `@canary` | `@now/node@canary` |
| Stable | [master](https://github.com/zeit/now/commits/master) | `@latest` | `@now/node@latest` |
All PRs are submitted to the `canary` branch. Once a PR is merged into the `canary` branch, it should be published to npm immediately using the Canary Channel.
## Version Selection
Since Builders are published to [npmjs.com](https://npmjs.com), this makes versioning works the same for Builders as it does for any npm package. The `use` statement in [now.json](https://zeit.co/docs/v2/advanced/configuration#builds) has a similar syntax to `npm install`.
The following are valid examples [@now/node](https://www.npmjs.com/package/@now/node?activeTab=versions):
- `@now/node`
- `@now/node@0.7.3`
- `@now/node@canary`
- `@now/node@0.7.2-canary.2`
We always recommend using the latest version by leaving off the dist-tag suffix, `@now/node` for example.

16
download/install.js Normal file
View File

@@ -0,0 +1,16 @@
/* eslint-disable no-var */
// Native
var path = require('path')
var fs = require('fs')
var dist = path.join(__dirname, 'dist')
var src = path.join(__dirname, 'src')
// Don't install when developing locally
if (fs.existsSync(src)) {
// eslint-disable-next-line unicorn/no-process-exit
process.exit(0)
}
require(path.join(dist, 'download.js'))

10
download/src/chmod.js Normal file
View File

@@ -0,0 +1,10 @@
// Native
import fs from 'fs'
export default function (file) {
const s = fs.statSync(file)
const newMode = s.mode | 64 | 8 | 1
if (s.mode === newMode) return
const base8 = newMode.toString(8).slice(-3)
fs.chmodSync(file, base8)
}

191
download/src/index.js Normal file
View File

@@ -0,0 +1,191 @@
/* eslint-disable unicorn/no-process-exit */
// Native
import fs from 'fs'
import path from 'path'
import { spawnSync } from 'child_process'
import zlib from 'zlib'
// Packages
import onDeath from 'death'
import fetch from 'node-fetch'
import retry from 'async-retry'
import which from 'which-promise'
import readPkg from 'read-pkg'
// Utilities
import plusxSync from './chmod'
import {
disableProgress,
enableProgress,
info,
showProgress,
warn
} from './log'
fetch.Promise = Promise
global.Promise = Promise
let { platform } = process
if (detectAlpine()) platform = 'alpine'
const packageDir = path.join(__dirname, '..', '..')
const packageJSON = readPkg.sync(packageDir)
const now = path.join(__dirname, 'now')
const targetWin32 = path.join(__dirname, 'now.exe')
const target = platform === 'win32' ? targetWin32 : now
const partial = target + '.partial'
const backup = target + '.' + packageJSON.version + '.backup'
const platformToName = {
alpine: 'now-alpine',
darwin: 'now-macos',
linux: 'now-linux',
win32: 'now-win.exe'
}
function detectAlpine () {
if (platform !== 'linux') return false
// https://github.com/sass/node-sass/issues/1589#issuecomment-265292579
const ldd = spawnSync('ldd', [ process.execPath ]).stdout.toString()
return /\bmusl\b/.test(ldd)
}
async function download() {
try {
fs.writeFileSync(
now,
'#!/usr/bin/env node\n' +
'console.log("Please wait until the \'now\' installation completes!")\n'
)
} catch (err) {
if (err.code === 'EACCES') {
warn(
'Please try installing Now CLI again with the `--unsafe-perm` option.'
)
info('Example: `npm i -g --unsafe-perm now`')
process.exit()
}
throw err
}
onDeath(() => {
fs.writeFileSync(
now,
'#!/usr/bin/env node\n' +
'console.log("The \'now\' installation did not complete successfully.")\n' +
'console.log("Please run \'npm i -g now\' to reinstall!")\n'
)
process.exit()
})
info('For the source code, check out: https://github.com/zeit/now-cli')
// Print an empty line
console.log('')
await retry(async () => {
enableProgress('Downloading Now CLI ' + packageJSON.version)
showProgress(0)
try {
const name = platformToName[platform]
const url = `https://github.com/zeit/now-cli/releases/download/${packageJSON.version}/${name}.gz`
const resp = await fetch(url, { compress: false })
if (resp.status !== 200) {
throw new Error(resp.statusText + ' ' + url)
}
const size = resp.headers.get('content-length')
const ws = fs.createWriteStream(partial)
await new Promise((resolve, reject) => {
let bytesRead = 0
resp.body
.on('error', reject)
.on('data', chunk => {
bytesRead += chunk.length
if (size) {
showProgress(100 * bytesRead / size)
}
})
const gunzip = zlib.createGunzip()
gunzip
.on('error', reject)
resp.body.pipe(gunzip).pipe(ws)
ws
.on('error', reject)
.on('close', () => {
showProgress(100)
resolve()
})
})
} finally {
disableProgress()
}
}, {
retries: 500,
onRetry: (err) => console.error(err)
})
fs.renameSync(partial, target)
fs.writeFileSync(backup, fs.readFileSync(target))
}
function modifyGitBashFile (content) {
return (
'#!/bin/sh\n' +
'basedir=$(dirname "$(echo "$0" | sed -e \'s,\\\\,/,g\')")\n' +
'\n' +
'case `uname` in\n' +
' *CYGWIN*) basedir=`cygpath -w "$basedir"`;;\n' +
'esac\n' +
'\n' +
content.replace(
'download/dist/now"', 'download/dist/now.exe"'));
}
async function main() {
if (fs.existsSync(backup)) {
fs.writeFileSync(target, fs.readFileSync(backup))
} else {
await download()
}
if (platform === 'win32') {
try {
fs.writeFileSync(now, '')
// Workaround for https://github.com/npm/cmd-shim/pull/25
const globalPath = path.dirname(await which('npm'))
let gitBashFile = path.join(globalPath, 'now')
if (!fs.existsSync(gitBashFile)) {
gitBashFile = path.join(process.env.APPDATA, 'npm/now');
}
fs.writeFileSync(
gitBashFile, modifyGitBashFile(fs.readFileSync(gitBashFile, 'utf8'))
)
} catch (err) {
if (err.code !== 'ENOENT') {
// Not a problem. only git cmd will not work
console.error(err)
}
}
} else {
plusxSync(now)
}
}
main().catch(err => {
console.error(err)
process.exit(2)
})

43
download/src/log.js Normal file
View File

@@ -0,0 +1,43 @@
// Packages
import assert from 'assert'
import chalk from 'chalk'
import Progress from 'progress'
let bar
export function enableProgress(text) {
assert(!bar)
bar = new Progress(`> ${text} [:bar] :percent`, {
stream: process.stdout,
width: 20,
complete: '=',
incomplete: ' ',
total: 100
})
}
export function info(text) {
console.log(`> ${text}`)
}
export function warn(text) {
console.log(chalk.red('> Warning!'), text)
}
export function showProgress(percentage) {
assert(bar)
bar.update(percentage / 100)
}
export function disableProgress() {
assert(bar)
// It is auto-completed once it updates to 100
// otherwise it outputs a blank line
if (!bar.complete) {
bar.terminate()
}
bar = undefined
}

View File

@@ -0,0 +1,34 @@
// Native
const path = require('path')
module.exports = {
target: 'node',
node: {
__dirname: false,
__filename: false,
process: false
},
entry: [
'./src/index.js'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'download.js'
},
module: {
loaders: [ {
test: /.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
plugins: [
'@babel/transform-async-to-generator',
'@babel/transform-runtime'
],
presets: [
'@babel/preset-env'
]
}
} ]
}
}

View File

@@ -14,7 +14,7 @@ it could be that:
- The domain was acquired recently, and it might not be ready for use yet.
- Required DNS records have not propagated yet.
When running into this, ensure that your nameservers are configured correctly. Also, if you bought the domain recently or have made changes, please be patient,
When running into this, ensure that your nameservers have configuration is correct. Also, if you bought the domain recently or have made changes, please be patient,
it might take a while for these to be ready.
If your domain is _not_ pointing to ZEIT World DNS and youre getting this

View File

@@ -1,21 +0,0 @@
# Domain Verification
#### Why This Error Occurred
The domain you supplied cannot be verified using either the intended set of nameservers of the given verification TXT record.
#### Possible Ways to Fix It
Apply the intended set of nameservers to your domain or add the given TXT verification record through your domain provider.
You can retrieve both the intended nameservers and TXT verification record for the domain you wish to verify by running `now domains inspect <domain>`.
When you have added either verification method to your domain, you can run `now domains verify <domain>` again to complete verification for your domain.
ZEIT will also automatically check periodically that your domain has been verified and automatically mark it as such if we detect either verification method on the domain.
If you would not like to verify your domain, you can remove it from your account using `now domains rm <domain>`.
#### Resources
- [ZEIT Domains Documentation](https://zeit.co/docs/v2/domains-and-aliases/adding-a-domain/)
- [Zero-Downtime Domain Migration Guide](https://zeit.co/docs/v2/domains-and-aliases/zero-downtime-domain-migration/)

View File

@@ -14,4 +14,4 @@ now -e VARIABLE_NAME=@secret-name
In addition, ensure that the secret (`@secret-name` in the example above) exists in the current scope (the team or user account that you're using).
You can run `now switch` or `--scope` to switch to a different team or user.
You can run `now switch` or `--team` to switch to a different team or user.

View File

@@ -1,26 +0,0 @@
# Missing Environment Variables While Developing
#### 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://zeit.co/docs/v2/deployments/environment-variables-and-secrets).
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.
We require this to ensure your app works as you intend it to, in the Now Dev environment, and to provide you with a way to mirror or separate private environment variables within your applications, for example when connecting to a database.
Read below for how to address this error.
#### Possible Ways to Fix It
The error message will list environment variables that are required and which file they are required to be included in (either `.env` or `.env.build`).
If the file does not exist yet, please create the file that the error message mentions and insert the missing environment variable into it.
For example, if the error message shows that the environment variable `TEST` is missing from `.env`, then the `.env` file should look like this:
```
TEST=value
```
In the above example, `TEST` represents the name of the environment variable and `value` its value.
For more information on Environment Variables in development, [see the documentation](https://zeit.co/docs/v2/development/environment-variables/).

View File

@@ -1,11 +0,0 @@
# Missing Scope Value
#### Why This Error Occurred
The `--scope` flag was specified, but there's no value for it available.
#### Possible Ways to Fix It
In order to make it work, you need to specify a value for the `--scope` flag. This needs to be the slug or ID of the team as which you'd like to act or the username or ID of a user you'd like to act as.
As an example, if your team URL is `https://zeit.co/teams/zeit`, you would set `--scope` to `zeit`.

View File

@@ -0,0 +1,11 @@
# Missing Team Value
#### Why This Error Occurred
The `--team` flag was specified, but there's no value for it available.
#### Possible Ways to Fix It
In order to make it work, you need to specify a value for the `--team` flag. This needs to be the slug of the team as which you'd like to act.
As an example, if your team URL is `https://zeit.co/teams/zeit`, the slug of the team is `zeit`.

View File

@@ -8,4 +8,4 @@ In turn, they would have to take the value of the `--token` flag into considerat
#### Possible Ways to Fix It
Specify a value for the `--scope` flag. This needs to be the slug or ID of the team as which you'd like to act (as an example, if your team URL is `https://zeit.co/teams/zeit`, the value can be `zeit`) or the username or ID of a user you'd like to act as.
Specify a value for the `--team` flag. This needs to be the slug of the team as which you'd like to act. As an example, if your team URL is `https://zeit.co/teams/zeit`, the slug is `zeit`.

View File

@@ -1,9 +0,0 @@
# `now dev` as `dev` script
#### Why This Error Occurred
The `package.json` file of the used project invokes `now dev` as `dev` script. This would cause `now dev` to recursively invoke itself.
#### Possible Ways to Fix It
Adjust the `dev` script inside the `package.json` file to match what your framework uses to begin development mode, e.g. `next` for Next.js or `gatsby develop` for Gatsby.

View File

@@ -1,72 +0,0 @@
# `@now/next` Legacy Mode
#### Why This Warning Occurred
`@now/next` has two modes: `legacy` and `serverless`. You will always want to use the `serverless` mode. `legacy` is to provide backwards compatibility with previous `@now/next` versions.
The differences:
Legacy:
- Minimal lambda size of `2.2Mb` (approximately)
- Forces `next@v7.0.2-canary.49` and `next-server@v7.0.2-canary.49`
- Forces all `dependencies` to be `devDependencies`
- Loads `next.config.js` on bootup, breaking sometimes when users didn't use `phases` to load files
- Used `next-server` which is the full Next.js server with routing etc.
- Runs `npm install`
- Runs `npm run now-build`
- Runs `npm install --production` after build
Serverless:
- Minimal lambda size of `49Kb` (approximately)
- Uses Next.js build targets (`target: 'serverless'`) in `next.config.js`. [documentation](https://github.com/zeit/next.js#summary)
- Does not make changes to your application dependencies
- Does not load `next.config.js` ([as per the serverless target documentation](https://github.com/zeit/next.js#summary))
- Runs `npm install`
- Runs `npm run now-build`
- Does not run `npm install --production` as the output from the build is all that's needed to bundle lambdas.
- No runtime dependencies, meaning smaller lambda functions
- Optimized for fast [cold start](https://zeit.co/blog/serverless-ssr#cold-start)
#### Possible Ways to Fix It
In order to create the smallest possible lambdas Next.js has to be configured to build for the `serverless` target.
1. Serverless Next.js requires Next.js 8 or later, to upgrade you can install the `latest` version:
```
npm install next --save
```
2. Add the `now-build` script to your `package.json`
```json
{
"scripts": {
"now-build": "next build"
}
}
```
3. Add `target: 'serverless'` to `next.config.js`
```js
module.exports = {
target: 'serverless',
// Other options are still valid
};
```
4. Optionally make sure the `"src"` in `"builds"` points to your application `package.json`
```js
{
"version": 2,
"builds": [{ "src": "package.json", "use": "@now/next" }]
}
```
### Useful Links
- [Serverless target implementation](https://github.com/zeit/now-builders/pull/150)

View File

@@ -1,45 +0,0 @@
# `@now/next` No Serverless Pages Built
#### Why This Error Occurred
This error occurs when you have your application is not configured for Serverless Next.js build output.
#### Possible Ways to Fix It
In order to create the smallest possible lambdas Next.js has to be configured to build for the `serverless` target.
1. Serverless Next.js requires Next.js 8 or later, to upgrade you can install the `latest` version:
```
npm install next --save
```
2. Add the `now-build` script to your `package.json`
```json
{
"scripts": {
"now-build": "next build"
}
}
```
3. Add `target: 'serverless'` to `next.config.js`
```js
module.exports = {
target: 'serverless',
// Other options
};
```
4. Remove `distDir` from `next.config.js` as `@now/next` can't parse this file and expects your build output at `/.next`
5. Optionally make sure the `"src"` in `"builds"` points to your application `package.json`
```js
{
"version": 2,
"builds": [{ "src": "package.json", "use": "@now/next" }]
}
```

View File

@@ -1,38 +0,0 @@
# `@now/static-build` Failed to detect a server running
#### Why This Warning Occurred
When running `now dev`, the `@now/static-build` builder proxies relevant HTTP
requests to the server that is created by the `now-dev` script in the
`package.json` file.
In order for `now dev` to know which port the server is running on, the builder
is provided a `$PORT` environment variable that the server _must_ bind to. The
error "Failed to detect a server running on port" is printed if the builder fails
to detect a server listening on that specific port within five minutes.
#### Possible Ways to Fix It
Please ensure that your `now-dev` script binds the spawned development server on
the provided `$PORT` that the builder expects the server to bind to.
For example, if you are using Gatsby, your `now-dev` script must use the `-p`
(port) option to bind to the `$PORT` specified from the builder:
```
{
...
"scripts": {
...
"now-dev": "gatsby develop -p $PORT"
}
}
```
Consult your static builder program's `--help` or documentation to figure out what
the command line flag to bind to a specific port is (in many cases, it is one of:
`-p` / `-P` / `--port`).
### Useful Links
- [`@now/static-build` Local Development Documentation](https://zeit.co/docs/v2/deployments/official-builders/static-build-now-static-build#local-development)

View File

@@ -1,10 +0,0 @@
# Scope Not Accessible
#### Why This Error Occurred
You specified the `--scope` flag and specified the ID or slug of a team that you're not a part of or a user whose account you don't own. This problem could also occur if your user credentials aren't valid anymore.
#### Possible Ways to Fix It
- Make sure commands like `now ls` work just fine. This will ensure that your user credentials are valid. If it's not working correctly, please log in again using `now login`.
- Ensure that the scope you specified using `--scope` shows up in the output of `now switch`. If it doesn't, you're either not part of the team (if you specified a team) or you logged into the wrong user account.

View File

@@ -1,11 +0,0 @@
# Scope Not Existent
#### Why This Error Occurred
You specified the `--scope` flag and specified the ID or slug of a team that does not exist or that you're not a part of. Similarly you might have specified the ID or username of user whose account you don't own.
#### Possible Ways to Fix It
If you're sure the specified team exists, please make sure that you're a part of it (ask an owner of the team to invite you). If you specified the identifier of a user, make sure you are actually the owner of this account.
Otherwise, either create a team with the specified slug or ensure that the identifier is correct if you're sure that the scope exists.

View File

@@ -0,0 +1,10 @@
# Team Not Accessible
#### Why This Error Occurred
You specified the `--team` flag and specified the slug of a team that you're not a part of. This problem could also occur if your user credentials aren't valid anymore.
#### Possible Ways to Fix It
- Make sure commands like `now ls` work just fine. This will ensure that your user credentials are valid. If it's not working correctly, please log in again using `now login`.
- Ensure that the team you specified using `--team` shows up in the output of `now switch`. If it doesn't, you're not part of it. In that case, please ask an owner of the team to invite you.

View File

@@ -0,0 +1,11 @@
# Team Not Existent
#### Why This Error Occurred
You specified the `--team` flag and specified the slug of a team that does not exist or that you're not a part of.
#### Possible Ways to Fix It
If you're sure the team exists, please make sure that you're a part of it (ask an owner of the team to invite you). After that, the command will work.
Otherwise, either create a team with the specified slug or ensure that the slug is correct if you're sure that the team exists.

View File

@@ -6,7 +6,7 @@ After the deployment build completed and the deployment state was set to `READY`
instances failed to initialize properly.
The CLI attempted to verify that the scale settings of your instances matched,
but it couldn't do so within the allotted time (defaults to 2 minutes).
but it couldn't do so within the alloted time (defaults to 2 minutes).
#### Possible Ways to Fix It

View File

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

11
link/link.js Executable file
View File

@@ -0,0 +1,11 @@
#!/usr/bin/env node
try {
// eslint-disable-next-line import/no-unassigned-import
require('../dist/now.js')
} catch (err) {
if (err.code === 'ENOENT' && err.syscall === 'uv_cwd') {
console.error(`Current path doesn't exist!`)
process.exit(1)
}
}

9
link/package.json Normal file
View File

@@ -0,0 +1,9 @@
{
"name": "now",
"license": "Apache-2.0",
"description": "The command line interface for Now",
"repository": "zeit/now-cli",
"bin": {
"now": "link.js"
}
}

View File

@@ -1,60 +1,187 @@
{
"name": "now-builders",
"version": "0.0.0",
"private": true,
"license": "MIT",
"workspaces": {
"packages": [
"packages/*"
],
"nohoist": [
"**/@types/**"
]
},
"dependencies": {
"lerna": "3.16.4"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "2.0.0",
"@typescript-eslint/parser": "2.0.0",
"@zeit/ncc": "0.20.4",
"async-retry": "1.2.3",
"buffer-replace": "1.0.0",
"eslint": "6.2.2",
"eslint-config-prettier": "6.1.0",
"husky": "3.0.4",
"lint-staged": "9.2.5",
"node-fetch": "2.6.0",
"prettier": "1.18.2"
},
"name": "now",
"version": "12.0.0-canary.84",
"license": "Apache-2.0",
"description": "The command-line interface for Now",
"repository": "zeit/now-cli",
"scripts": {
"lerna": "lerna",
"bootstrap": "lerna bootstrap",
"publish-stable": "git checkout master && git pull && lerna version --exact",
"publish-canary": "git checkout canary && git pull && lerna version prerelease --preid canary --exact",
"publish-from-github": "./.circleci/publish.sh",
"build": "node run.js build all",
"test-lint": "node run.js test-lint",
"test-unit": "node run.js test-unit",
"test-integration": "node run.js test-integration",
"test-integration-once": "node run.js test-integration-once",
"test-integration-now-dev": "node run.js test-integration-now-dev",
"lint": "eslint . --ext .ts,.js"
"test": "yarn test-lint",
"test-unit": "ava test/unit.js --fail-fast",
"test-integration": "ava test/integration.js --serial --fail-fast",
"test-lint": "eslint .",
"prepublishOnly": "yarn build-download && cp /dev/null download/dist/now",
"dev": "webpack -w",
"precommit": "lint-staged",
"postinstall": "node download/install.js",
"gzip": "ls packed/now* | xargs gzip",
"bundle": "pkg dist/now.js -c package.json -o packed/now --options no-warnings",
"pack": "rm -rf packed && webpack && yarn bundle",
"build-download": "webpack --context download --config download/webpack.config.js",
"link": "webpack && cd link && npm link",
"build": "webpack"
},
"lint-staged": {
"*.{js,ts}": [
"prettier --write",
"eslint",
"git add"
],
"*.{json,md}": [
"prettier --write",
"*.js": [
"yarn test-lint",
"prettier --write --single-quote --no-semi",
"git add"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
"bin": {
"now": "download/dist/now"
},
"files": [
"download/dist",
"download/install.js"
],
"pkg": {
"scripts": [
"dist/*.js"
],
"targets": [
"node9-alpine-x64",
"node9-linux-x64",
"node9-macos-x64",
"node9-win-x64"
]
},
"eslintIgnore": [
"download",
"dist",
"test/fixtures"
],
"eslintConfig": {
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
"parser": "babel-eslint",
"extends": [
"eslint:recommended",
"plugin:flowtype/recommended"
],
"plugins": [
"flowtype"
],
"env": {
"es6": true,
"node": true
},
"rules": {
"func-names": 0,
"no-console": 0,
"no-shadow": 0,
"no-extra-semi": 0,
"no-empty": 0
}
},
"babel": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
}
]
],
"plugins": [
"@babel/plugin-transform-flow-comments",
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-proposal-async-generator-functions"
]
},
"devDependencies": {
"@babel/core": "7.0.0-beta.44",
"@babel/plugin-proposal-async-generator-functions": "7.0.0-beta.44",
"@babel/plugin-proposal-object-rest-spread": "7.0.0-beta.44",
"@babel/plugin-transform-flow-comments": "7.0.0-beta.44",
"@babel/plugin-transform-runtime": "7.0.0-beta.44",
"@babel/preset-env": "7.0.0-beta.44",
"@babel/runtime": "7.0.0-beta.44",
"@zeit/dockerignore": "0.0.3",
"@zeit/source-map-support": "0.6.2",
"ajv": "6.4.0",
"alpha-sort": "2.0.1",
"ansi-escapes": "3.0.0",
"ansi-regex": "3.0.0",
"archiver": "2.0.3",
"arg": "2.0.0",
"arr-flatten": "1.1.0",
"async-retry": "1.1.3",
"async-sema": "1.2.0",
"ava": "0.25.0",
"aws-sdk": "2.124.0",
"babel-eslint": "8.2.2",
"babel-loader": "8.0.0-beta.2",
"bytes": "3.0.0",
"chalk": "2.3.1",
"child-process-promise": "2.2.1",
"clipboardy": "1.1.4",
"convert-stream": "1.0.2",
"copy-webpack-plugin": "4.0.1",
"credit-card": "3.0.1",
"death": "1.1.0",
"debug": "3.1.0",
"deployment-type": "1.0.1",
"docker-file-parser": "1.0.2",
"dotenv": "4.0.0",
"download": "6.2.5",
"email-prompt": "0.3.2",
"email-validator": "1.1.1",
"epipebomb": "1.0.0",
"es7-sleep": "1.0.0",
"eslint": "4.7.2",
"eslint-plugin-flowtype": "2.46.1",
"execa": "0.9.0",
"fetch-h2": "0.2.5",
"flow-babel-webpack-plugin": "1.1.1",
"fs-extra": "4.0.2",
"glob": "7.1.2",
"ignore": "3.3.5",
"ini": "1.3.4",
"inquirer": "3.3.0",
"is-url": "1.2.2",
"jsonlines": "0.1.1",
"lint-staged": "4.2.3",
"load-json-file": "3.0.0",
"lodash.range": "3.2.0",
"micro": "9.1.2",
"mkdirp-promise": "5.0.1",
"mri": "1.1.0",
"ms": "2.0.0",
"node-fetch": "1.7.3",
"opn": "5.1.0",
"ora": "1.3.0",
"pipe-streams-to-promise": "0.2.0",
"pkg": "4.3.0",
"pluralize": "7.0.0",
"pre-commit": "1.2.2",
"prettier": "1.7.2",
"printf": "0.2.5",
"progress": "2.0.0",
"psl": "1.1.20",
"qr-image": "3.2.0",
"read-pkg": "2.0.0",
"semver": "5.5.0",
"shebang-loader": "0.0.1",
"single-line-log": "1.1.2",
"sinon": "4.4.2",
"strip-ansi": "4.0.0",
"stripe": "5.1.0",
"supports-color": "5.2.0",
"tar-fs": "1.15.3",
"test-listen": "1.1.0",
"text-table": "0.2.0",
"then-sleep": "1.0.1",
"through2": "2.0.3",
"tmp-promise": "1.0.3",
"uid-promise": "1.0.0",
"update-check": "1.5.0",
"webpack": "3.6.0",
"webpack-node-externals": "1.6.0",
"which-promise": "1.0.0",
"write-json-file": "2.2.0"
}
}

View File

@@ -1,6 +0,0 @@
#!/bin/bash
set -euo pipefail
# build fixtures for tests
yarn --cwd test/fixtures install
yarn --cwd test/fixtures run build

View File

@@ -1,33 +0,0 @@
const path = require('path');
const writeFile = require('util').promisify(require('fs').writeFile);
const REDIRECT_FILE_NAME = '__now_routes_g4t5bY.json';
exports.onPostBuild = async ({ store }) => {
const { redirects, program } = store.getState();
if (!redirects.length === 0) {
return;
}
const routes = [{ handle: 'filesystem' }];
for (const redirect of redirects) {
const route = {
src: redirect.fromPath,
status: redirect.statusCode || (redirect.isPermanent ? 301 : 302),
headers: { Location: redirect.toPath }
};
if (redirect.force) {
routes.unshift(route);
} else {
routes.push(route);
}
}
await writeFile(
path.join(program.directory, 'public', REDIRECT_FILE_NAME),
JSON.stringify(routes)
);
};

View File

@@ -1 +0,0 @@
// noop

View File

@@ -1,32 +0,0 @@
{
"name": "gatsby-plugin-now",
"version": "1.2.1",
"main": "index.js",
"license": "MIT",
"homepage": "https://github.com/zeit/now/tree/canary/packages/gatsby-plugin-now",
"repository": {
"type": "git",
"url": "https://github.com/zeit/now.git",
"directory": "packages/gatsby-plugin-now"
},
"scripts": {
"build": "./build.sh",
"test-integration-once": "jest --verbose"
},
"files": [
"index.js",
"gatsby-node.js"
],
"peerDependencies": {
"gatsby": ">=2.0.0"
},
"devDependencies": {
"jest": "24.9.0"
},
"jest": {
"testPathIgnorePatterns": [
"/node_modules/",
"<rootDir>/test/fixtures/"
]
}
}

View File

@@ -1,24 +0,0 @@
# gatsby-plugin-now
This plugin generates [Now Routes](https://zeit.co/docs/v2/advanced/routes) for [redirects](https://www.gatsbyjs.org/docs/actions/#createRedirect) you configured for to your Gatsby project.
### Usage
1. Install the plugin:
```
npm install gatsby-plugin-now --save-dev
```
2. Add it to the configuration file:
```
// gatsby-config.js
module.exports = {
plugins: [
'gatsby-plugin-now'
]
}
```
3. [Deploy your project to ZEIT Now](https://www.gatsbyjs.org/docs/deploying-to-zeit-now/)

View File

@@ -1,86 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`test generated now routes 1`] = `
Array [
Object {
"headers": Object {
"Location": "/",
},
"src": "/my-special-redirect",
"status": 302,
},
Object {
"handle": "filesystem",
},
Object {
"headers": Object {
"Location": "/page-2",
},
"src": "/page2",
"status": 301,
},
Object {
"headers": Object {
"Location": "/page-2/",
},
"src": "/page2/",
"status": 301,
},
Object {
"headers": Object {
"Location": "/",
},
"src": "/orange",
"status": 302,
},
Object {
"headers": Object {
"Location": "/",
},
"src": "/grape",
"status": 302,
},
Object {
"headers": Object {
"Location": "/page-2/",
},
"src": "/blue",
"status": 302,
},
Object {
"headers": Object {
"Location": "/page-2/",
},
"src": "/randirect",
"status": 302,
},
Object {
"headers": Object {
"Location": "/",
},
"src": "/juice",
"status": 302,
},
Object {
"headers": Object {
"Location": "/",
},
"src": "/soda",
"status": 302,
},
Object {
"headers": Object {
"Location": "/page-2/",
},
"src": "/donut",
"status": 302,
},
Object {
"headers": Object {
"Location": "/page-2/",
},
"src": "/randorect",
"status": 302,
},
]
`;

View File

@@ -1,4 +0,0 @@
public
node_modules
.cache
yarn.lock

View File

@@ -1,3 +0,0 @@
module.exports = {
plugins: [{ resolve: require.resolve('../../') }]
};

View File

@@ -1,105 +0,0 @@
'use strict';
// Implement the Gatsby API “createPages”. This is called once the
// data layer is bootstrapped to let plugins create pages from data.
exports.createPages = ({ actions }) => {
// need createRedirect action in actions collection
// to make the redirection magic happen.
// https://www.gatsbyjs.org/docs/bound-action-creators/
const { createRedirect } = actions;
// Lets set up some string consts to use thoroughout the following.
// MDN > JavaScript reference > Statements and declarations
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
// Maybe we usually redirect to page 2, with trailing slash.
const page2Path = `/page-2/`;
// But sometimes to homepage.
const homePath = `/`;
// One-off redirect, note trailing slash missing on fromPath and
// toPath here.
createRedirect({
fromPath: `/page2`,
isPermanent: true,
redirectInBrowser: true,
toPath: `/page-2`
});
// Another one-off redirect, note trailing slash on toPath here.
// This time we want trailing slash on toPath so we use
// page2Path. Need to handle trailing-slashed and non-trailing-
// slashed fromPaths separately, Gatsby serves page components
// at either version by default, but we need to explicitly redirect
// both versions independently, more on page components:
// Docs > Building with Components
// https://www.gatsbyjs.org/docs/building-with-components/
// and handling trailing slashes:
// Docs > Creating and modifying pages > Removing trailing slashes
// https://www.gatsbyjs.org/docs/creating-and-modifying-pages/#removing-trailing-slashes
createRedirect({
fromPath: `/page2/`,
isPermanent: true,
redirectInBrowser: true,
toPath: page2Path
});
// One approach to handle several redirects at once is to create an
// array of from/to path pairs.
let redirectBatch1 = [
{ f: `/orange`, t: `/` },
// We could use homePath and page2Path directly here.
{ f: `/grape`, t: homePath },
{ f: `/blue`, t: page2Path },
// or leave to empty and swap for page2Path later on.
{ f: `/randirect`, t: `` }
];
// Then we can loop through the array of object literals to create
// each redirect. A for loop would do the trick
for (var { f: f, t: t } of redirectBatch1) {
// Here we swap any empty toPath values for trusty page 2 via
// page2Path.
if (t === ``) {
t = page2Path;
}
createRedirect({
fromPath: f,
redirectInBrowser: true,
toPath: t
});
// Uncomment next line to see loop in action during build
// console.log('\nRedirecting:\n' + f + '\nTo:\n' + t + '\n');
// or check .cache/redirects.json post-compile.
}
// A more modern approach might use forEach rather than for...of
// Compare
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration#for...of_statement
// and
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
let redirectBatch2 = [
{ f: `/juice`, t: `/` },
{ f: `/soda`, t: `/` },
{ f: `/donut`, t: page2Path },
{ f: `/randorect`, t: `` }
];
redirectBatch2.forEach(({ f, t }) => {
if (t === ``) {
t = page2Path;
}
createRedirect({
fromPath: f,
redirectInBrowser: true,
toPath: t
});
// Uncomment next line to see forEach in action during build
// console.log('\nRedirecting:\n' + f + '\nTo:\n' + t + '\n');
});
createRedirect({
fromPath: '/my-special-redirect',
toPath: homePath,
force: true
});
};

View File

@@ -1,11 +0,0 @@
{
"name": "fixtures",
"dependencies": {
"gatsby": "2.14.0",
"react": "16.9.0",
"react-dom": "16.9.0"
},
"scripts": {
"build": "gatsby build"
}
}

View File

@@ -1,9 +0,0 @@
import React from 'react';
const IndexPage = () => (
<div>
<h1>Hi people</h1>
</div>
);
export default IndexPage;

View File

@@ -1,5 +0,0 @@
test('test generated now routes', async () => {
const nowRoutes = require('./fixtures/public/__now_routes_g4t5bY.json');
expect(nowRoutes).toMatchSnapshot();
});

View File

@@ -1,3 +0,0 @@
dist
test/symlinks-out
test/symlinks.zip

View File

@@ -1,3 +0,0 @@
/src
/test
tmp

View File

@@ -1,6 +0,0 @@
tsc
rm dist/index.js
ncc build src/index.ts -o dist/main
mv dist/main/index.js dist/index.js
rm -rf dist/main

View File

@@ -1 +0,0 @@
module.exports = require('./dist/index').FileBlob;

View File

@@ -1 +0,0 @@
module.exports = require('./dist/index').FileFsRef;

View File

@@ -1 +0,0 @@
module.exports = require('./dist/index').FileRef;

View File

@@ -1 +0,0 @@
module.exports = require('../dist/index').download;

View File

@@ -1 +0,0 @@
module.exports = require('../dist/index').getWriteableDirectory;

View File

@@ -1 +0,0 @@
module.exports = require('../dist/index').glob;

View File

@@ -1 +0,0 @@
module.exports = require('../dist/index').rename;

View File

@@ -1 +0,0 @@
module.exports = require('../dist/index');

View File

@@ -1 +0,0 @@
module.exports = require('../dist/index').streamToBuffer;

View File

@@ -1 +0,0 @@
module.exports = require('./dist/index');

View File

@@ -1,43 +0,0 @@
{
"name": "@now/build-utils",
"version": "0.10.0",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",
"homepage": "https://zeit.co/docs/v2/deployments/builders/developer-guide",
"repository": {
"type": "git",
"url": "https://github.com/zeit/now.git",
"directory": "packages/now-build-utils"
},
"scripts": {
"build": "./build.sh",
"test-integration-once": "jest --env node --verbose --runInBand",
"prepublishOnly": "./build.sh"
},
"devDependencies": {
"@types/async-retry": "^1.2.1",
"@types/cross-spawn": "6.0.0",
"@types/end-of-stream": "^1.4.0",
"@types/fs-extra": "^5.0.5",
"@types/glob": "^7.1.1",
"@types/multistream": "2.1.1",
"@types/node-fetch": "^2.1.6",
"@types/semver": "6.0.0",
"@types/yazl": "^2.4.1",
"async-retry": "1.2.3",
"async-sema": "2.1.4",
"cross-spawn": "6.0.5",
"end-of-stream": "1.4.1",
"execa": "^1.0.0",
"fs-extra": "7.0.0",
"glob": "7.1.3",
"into-stream": "5.0.0",
"minimatch": "3.0.4",
"multistream": "2.1.1",
"node-fetch": "2.2.0",
"semver": "6.1.1",
"typescript": "3.5.2",
"yazl": "2.4.3"
}
}

View File

@@ -1,7 +0,0 @@
export default function debug(message: string, ...additional: any[]) {
if (process.env.NOW_BUILDER_DEBUG) {
console.log(message, ...additional);
} else if (process.env.NOW_BUILDER_ANNOTATE) {
console.log(`[now-builder-debug] ${message}`, ...additional);
}
}

View File

@@ -1,182 +0,0 @@
import { PackageJson, Builder, Config } from './types';
import minimatch from 'minimatch';
interface ErrorResponse {
code: string;
message: string;
}
interface Options {
tag?: 'canary' | 'latest' | string;
}
const src = 'package.json';
const config: Config = { zeroConfig: true };
const MISSING_BUILD_SCRIPT_ERROR: ErrorResponse = {
code: 'missing_build_script',
message:
'Your `package.json` file is missing a `build` property inside the `script` property.' +
'\nMore details: https://zeit.co/docs/v2/advanced/platform/frequently-asked-questions#missing-build-script'
};
// Static builders are special cased in `@now/static-build`
function getBuilders(): Map<string, Builder> {
return new Map<string, Builder>([
['next', { src, use: '@now/next', config }]
]);
}
// Must be a function to ensure that the returned
// object won't be a reference
function getApiBuilders(): Builder[] {
return [
{ src: 'api/**/*.js', use: '@now/node', config },
{ src: 'api/**/*.ts', use: '@now/node', config },
{ src: 'api/**/*.go', use: '@now/go', config },
{ src: 'api/**/*.py', use: '@now/python', config },
{ src: 'api/**/*.rb', use: '@now/ruby', config }
];
}
function hasPublicDirectory(files: string[]) {
return files.some(name => name.startsWith('public/'));
}
function hasBuildScript(pkg: PackageJson | undefined) {
const { scripts = {} } = pkg || {};
return Boolean(scripts && scripts['build']);
}
async function detectBuilder(pkg: PackageJson): Promise<Builder> {
for (const [dependency, builder] of getBuilders()) {
const deps = Object.assign({}, pkg.dependencies, pkg.devDependencies);
// Return the builder when a dependency matches
if (deps[dependency]) {
return builder;
}
}
// By default we'll choose the `static-build` builder
return { src, use: '@now/static-build', config };
}
// Files that match a specific pattern will get ignored
export function ignoreApiFilter(file: string) {
if (file.includes('/.')) {
return false;
}
if (file.includes('/_')) {
return false;
}
if (file.endsWith('.d.ts')) {
return false;
}
// If the file does not match any builder we also
// don't want to create a route e.g. `package.json`
if (getApiBuilders().every(({ src }) => !minimatch(file, src))) {
return false;
}
return true;
}
// We need to sort the file paths by alphabet to make
// sure the routes stay in the same order e.g. for deduping
export function sortFiles(fileA: string, fileB: string) {
return fileA.localeCompare(fileB);
}
async function detectApiBuilders(files: string[]): Promise<Builder[]> {
const builds = files
.sort(sortFiles)
.filter(ignoreApiFilter)
.map(file => {
const result = getApiBuilders().find(({ src }): boolean =>
minimatch(file, src)
);
return result ? { ...result, src: file } : null;
});
const finishedBuilds = builds.filter(Boolean);
return finishedBuilds as Builder[];
}
// When zero config is used we can call this function
// to determine what builders to use
export async function detectBuilders(
files: string[],
pkg?: PackageJson | undefined | null,
options?: Options
): Promise<{
builders: Builder[] | null;
errors: ErrorResponse[] | null;
}> {
const errors: ErrorResponse[] = [];
// Detect all builders for the `api` directory before anything else
let builders = await detectApiBuilders(files);
if (pkg && hasBuildScript(pkg)) {
builders.push(await detectBuilder(pkg));
} else {
if (pkg && builders.length === 0) {
// We only show this error when there are no api builders
// since the dependencies of the pkg could be used for those
errors.push(MISSING_BUILD_SCRIPT_ERROR);
return { errors, builders: null };
}
// We allow a `public` directory
// when there are no build steps
if (hasPublicDirectory(files)) {
builders.push({
use: '@now/static',
src: 'public/**/*',
config
});
} else if (builders.length > 0) {
// We can't use pattern matching, since `!(api)` and `!(api)/**/*`
// won't give the correct results
builders.push(
...files
.filter(name => !name.startsWith('api/'))
.filter(name => !(name === 'package.json'))
.map(name => ({
use: '@now/static',
src: name,
config
}))
);
}
}
// Change the tag for the builders
if (builders && builders.length) {
const tag = options && options.tag;
if (tag) {
builders = builders.map((originBuilder: Builder) => {
// Copy builder to make sure it is not a reference
const builder = { ...originBuilder };
// @now/static has no canary builder
if (builder.use !== '@now/static') {
builder.use = `${builder.use}@${tag}`;
}
return builder;
});
}
}
return {
builders: builders.length ? builders : null,
errors: errors.length ? errors : null
};
}

View File

@@ -1,295 +0,0 @@
import { Route, Builder } from './types';
import { parse as parsePath } from 'path';
import { ignoreApiFilter, sortFiles } from './detect-builders';
function escapeName(name: string) {
const special = '[]^$.|?*+()'.split('');
for (const char of special) {
name = name.replace(new RegExp(`\\${char}`, 'g'), `\\${char}`);
}
return name;
}
function joinPath(...segments: string[]) {
const joinedPath = segments.join('/');
return joinedPath.replace(/\/{2,}/g, '/');
}
function concatArrayOfText(texts: string[]): string {
if (texts.length <= 2) {
return texts.join(' and ');
}
const last = texts.pop();
return `${texts.join(', ')}, and ${last}`;
}
// Takes a filename or foldername, strips the extension
// gets the part between the "[]" brackets.
// It will return `null` if there are no brackets
// and therefore no segment.
function getSegmentName(segment: string): string | null {
const { name } = parsePath(segment);
if (name.startsWith('[') && name.endsWith(']')) {
return name.slice(1, -1);
}
return null;
}
function createRouteFromPath(filePath: string): Route {
const parts = filePath.split('/');
let counter = 1;
const query: string[] = [];
const srcParts = parts.map((segment, index): string => {
const name = getSegmentName(segment);
const isLast = index === parts.length - 1;
if (name !== null) {
// We can't use `URLSearchParams` because `$` would get escaped
query.push(`${name}=$${counter++}`);
return `([^\\/]+)`;
} else if (isLast) {
const { name: fileName, ext } = parsePath(segment);
const isIndex = fileName === 'index';
const prefix = isIndex ? '\\/' : '';
const names = [
prefix,
prefix + escapeName(fileName),
prefix + escapeName(fileName) + escapeName(ext)
].filter(Boolean);
// Either filename with extension, filename without extension
// or nothing when the filename is `index`
return `(${names.join('|')})${isIndex ? '?' : ''}`;
}
return segment;
});
const { name: fileName } = parsePath(filePath);
const isIndex = fileName === 'index';
const src = isIndex
? `^/${srcParts.slice(0, -1).join('/')}${srcParts.slice(-1)[0]}$`
: `^/${srcParts.join('/')}$`;
const dest = `/${filePath}${query.length ? '?' : ''}${query.join('&')}`;
return { src, dest };
}
// Check if the path partially matches and has the same
// name for the path segment at the same position
function partiallyMatches(pathA: string, pathB: string): boolean {
const partsA = pathA.split('/');
const partsB = pathB.split('/');
const long = partsA.length > partsB.length ? partsA : partsB;
const short = long === partsA ? partsB : partsA;
let index = 0;
for (const segmentShort of short) {
const segmentLong = long[index];
const nameLong = getSegmentName(segmentLong);
const nameShort = getSegmentName(segmentShort);
// If there are no segments or the paths differ we
// return as they are not matching
if (segmentShort !== segmentLong && (!nameLong || !nameShort)) {
return false;
}
if (nameLong !== nameShort) {
return true;
}
index += 1;
}
return false;
}
// Counts how often a path occurres when all placeholders
// got resolved, so we can check if they have conflicts
function pathOccurrences(filePath: string, files: string[]): string[] {
const getAbsolutePath = (unresolvedPath: string): string => {
const { dir, name } = parsePath(unresolvedPath);
const parts = joinPath(dir, name).split('/');
return parts.map(part => part.replace(/\[.*\]/, '1')).join('/');
};
const currentAbsolutePath = getAbsolutePath(filePath);
return files.reduce((prev: string[], file: string): string[] => {
const absolutePath = getAbsolutePath(file);
if (absolutePath === currentAbsolutePath) {
prev.push(file);
} else if (partiallyMatches(filePath, file)) {
prev.push(file);
}
return prev;
}, []);
}
// Checks if a placeholder with the same name is used
// multiple times inside the same path
function getConflictingSegment(filePath: string): string | null {
const segments = new Set<string>();
for (const segment of filePath.split('/')) {
const name = getSegmentName(segment);
if (name !== null && segments.has(name)) {
return name;
}
if (name) {
segments.add(name);
}
}
return null;
}
function sortFilesBySegmentCount(fileA: string, fileB: string): number {
const lengthA = fileA.split('/').length;
const lengthB = fileB.split('/').length;
if (lengthA > lengthB) {
return -1;
}
if (lengthA < lengthB) {
return 1;
}
// Paths that have the same segment length but
// less placeholders are preferred
const countSegments = (prev: number, segment: string) =>
getSegmentName(segment) ? prev + 1 : 0;
const segmentLengthA = fileA.split('/').reduce(countSegments, 0);
const segmentLengthB = fileB.split('/').reduce(countSegments, 0);
if (segmentLengthA > segmentLengthB) {
return 1;
}
if (segmentLengthA < segmentLengthB) {
return -1;
}
return 0;
}
interface RoutesResult {
defaultRoutes: Route[] | null;
error: { [key: string]: string } | null;
}
async function detectApiRoutes(files: string[]): Promise<RoutesResult> {
if (!files || files.length === 0) {
return { defaultRoutes: null, error: null };
}
// The deepest routes need to be
// the first ones to get handled
const sortedFiles = files
.filter(ignoreApiFilter)
.sort(sortFiles)
.sort(sortFilesBySegmentCount);
const defaultRoutes: Route[] = [];
for (const file of sortedFiles) {
// We only consider every file in the api directory
// as we will strip extensions as well as resolving "[segments]"
if (!file.startsWith('api/')) {
continue;
}
const conflictingSegment = getConflictingSegment(file);
if (conflictingSegment) {
return {
defaultRoutes: null,
error: {
code: 'conflicting_path_segment',
message:
`The segment "${conflictingSegment}" occurres more than ` +
`one time in your path "${file}". Please make sure that ` +
`every segment in a path is unique`
}
};
}
const occurrences = pathOccurrences(file, sortedFiles).filter(
name => name !== file
);
if (occurrences.length > 0) {
const messagePaths = concatArrayOfText(
occurrences.map(name => `"${name}"`)
);
return {
defaultRoutes: null,
error: {
code: 'conflicting_file_path',
message:
`Two or more files have conflicting paths or names. ` +
`Please make sure path segments and filenames, without their extension, are unique. ` +
`The path "${file}" has conflicts with ${messagePaths}`
}
};
}
defaultRoutes.push(createRouteFromPath(file));
}
// 404 Route to disable directory listing
if (defaultRoutes.length) {
defaultRoutes.push({
status: 404,
src: '/api(\\/.*)?$'
});
}
return { defaultRoutes, error: null };
}
function hasPublicBuilder(builders: Builder[]): boolean {
return builders.some(
builder =>
builder.use === '@now/static' &&
builder.src === 'public/**/*' &&
builder.config &&
builder.config.zeroConfig === true
);
}
export async function detectRoutes(
files: string[],
builders: Builder[]
): Promise<RoutesResult> {
const routesResult = await detectApiRoutes(files);
if (routesResult.defaultRoutes && hasPublicBuilder(builders)) {
routesResult.defaultRoutes.push({
src: '/(.*)',
dest: '/public/$1'
});
}
return routesResult;
}

View File

@@ -1,46 +0,0 @@
import assert from 'assert';
import intoStream from 'into-stream';
import { File } from './types';
interface FileBlobOptions {
mode?: number;
data: string | Buffer;
}
interface FromStreamOptions {
mode?: number;
stream: NodeJS.ReadableStream;
}
export default class FileBlob implements File {
public type: 'FileBlob';
public mode: number;
public data: string | Buffer;
constructor({ mode = 0o100644, data }: FileBlobOptions) {
assert(typeof mode === 'number');
assert(typeof data === 'string' || Buffer.isBuffer(data));
this.type = 'FileBlob';
this.mode = mode;
this.data = data;
}
static async fromStream({ mode = 0o100644, stream }: FromStreamOptions) {
assert(typeof mode === 'number');
assert(typeof stream.pipe === 'function'); // is-stream
const chunks: Buffer[] = [];
await new Promise<void>((resolve, reject) => {
stream.on('data', chunk => chunks.push(Buffer.from(chunk)));
stream.on('error', error => reject(error));
stream.on('end', () => resolve());
});
const data = Buffer.concat(chunks);
return new FileBlob({ mode, data });
}
toStream(): NodeJS.ReadableStream {
return intoStream(this.data);
}
}

View File

@@ -1,97 +0,0 @@
import assert from 'assert';
import fs from 'fs-extra';
import multiStream from 'multistream';
import path from 'path';
import Sema from 'async-sema';
import { File } from './types';
const semaToPreventEMFILE = new Sema(20);
interface FileFsRefOptions {
mode?: number;
fsPath: string;
}
interface FromStreamOptions {
mode: number;
stream: NodeJS.ReadableStream;
fsPath: string;
}
class FileFsRef implements File {
public type: 'FileFsRef';
public mode: number;
public fsPath: string;
constructor({ mode = 0o100644, fsPath }: FileFsRefOptions) {
assert(typeof mode === 'number');
assert(typeof fsPath === 'string');
this.type = 'FileFsRef';
this.mode = mode;
this.fsPath = fsPath;
}
static async fromFsPath({
mode,
fsPath,
}: FileFsRefOptions): Promise<FileFsRef> {
let m = mode;
if (!m) {
const stat = await fs.lstat(fsPath);
m = stat.mode;
}
return new FileFsRef({ mode: m, fsPath });
}
static async fromStream({
mode = 0o100644,
stream,
fsPath,
}: FromStreamOptions): Promise<FileFsRef> {
assert(typeof mode === 'number');
assert(typeof stream.pipe === 'function'); // is-stream
assert(typeof fsPath === 'string');
await fs.mkdirp(path.dirname(fsPath));
await new Promise<void>((resolve, reject) => {
const dest = fs.createWriteStream(fsPath, {
mode: mode & 0o777,
});
stream.pipe(dest);
stream.on('error', reject);
dest.on('finish', resolve);
dest.on('error', reject);
});
return new FileFsRef({ mode, fsPath });
}
async toStreamAsync(): Promise<NodeJS.ReadableStream> {
await semaToPreventEMFILE.acquire();
const release = () => semaToPreventEMFILE.release();
const stream = fs.createReadStream(this.fsPath);
stream.on('close', release);
stream.on('error', release);
return stream;
}
toStream(): NodeJS.ReadableStream {
let flag = false;
// eslint-disable-next-line consistent-return
return multiStream(cb => {
if (flag) return cb(null, null);
flag = true;
this.toStreamAsync()
.then(stream => {
cb(null, stream);
})
.catch(error => {
cb(error, null);
});
});
}
}
export = FileFsRef;

View File

@@ -1,100 +0,0 @@
import assert from 'assert';
import fetch from 'node-fetch';
import multiStream from 'multistream';
import retry from 'async-retry';
import Sema from 'async-sema';
import { File } from './types';
interface FileRefOptions {
mode?: number;
digest: string;
mutable?: boolean;
}
const semaToDownloadFromS3 = new Sema(5);
class BailableError extends Error {
public bail: boolean;
constructor(...args: string[]) {
super(...args);
this.bail = false;
}
}
export default class FileRef implements File {
public type: 'FileRef';
public mode: number;
public digest: string;
private mutable: boolean;
constructor({ mode = 0o100644, digest, mutable = false }: FileRefOptions) {
assert(typeof mode === 'number');
assert(typeof digest === 'string');
this.type = 'FileRef';
this.mode = mode;
this.digest = digest;
this.mutable = mutable;
}
async toStreamAsync(): Promise<NodeJS.ReadableStream> {
let url = '';
// sha:24be087eef9fac01d61b30a725c1a10d7b45a256
const [digestType, digestHash] = this.digest.split(':');
if (digestType === 'sha') {
// This CloudFront URL edge caches the `now-files` S3 bucket to prevent
// overloading it. Mutable files cannot be cached.
// `https://now-files.s3.amazonaws.com/${digestHash}`
url = this.mutable
? `https://now-files.s3.amazonaws.com/${digestHash}`
: `https://dmmcy0pwk6bqi.cloudfront.net/${digestHash}`;
} else if (digestType === 'sha+ephemeral') {
// This URL is currently only used for cache files that constantly
// change. We shouldn't cache it on CloudFront because it'd always be a
// MISS.
url = `https://now-ephemeral-files.s3.amazonaws.com/${digestHash}`;
} else {
throw new Error('Expected digest to be sha');
}
await semaToDownloadFromS3.acquire();
// console.time(`downloading ${url}`);
try {
return await retry(
async () => {
const resp = await fetch(url);
if (!resp.ok) {
const error = new BailableError(
`download: ${resp.status} ${resp.statusText} for ${url}`
);
if (resp.status === 403) error.bail = true;
throw error;
}
return resp.body;
},
{ factor: 1, retries: 3 }
);
} finally {
// console.timeEnd(`downloading ${url}`);
semaToDownloadFromS3.release();
}
}
toStream(): NodeJS.ReadableStream {
let flag = false;
// eslint-disable-next-line consistent-return
return multiStream(cb => {
if (flag) return cb(null, null);
flag = true;
this.toStreamAsync()
.then(stream => {
cb(null, stream);
})
.catch(error => {
cb(error, null);
});
});
}
}

View File

@@ -1,75 +0,0 @@
import path from 'path';
import FileFsRef from '../file-fs-ref';
import { File, Files, Meta } from '../types';
import { remove, mkdirp, readlink, symlink } from 'fs-extra';
export interface DownloadedFiles {
[filePath: string]: FileFsRef;
}
const S_IFMT = 61440; /* 0170000 type of file */
const S_IFLNK = 40960; /* 0120000 symbolic link */
export function isSymbolicLink(mode: number): boolean {
return (mode & S_IFMT) === S_IFLNK;
}
async function downloadFile(file: File, fsPath: string): Promise<FileFsRef> {
const { mode } = file;
if (mode && isSymbolicLink(mode) && file.type === 'FileFsRef') {
const [target] = await Promise.all([
readlink((file as FileFsRef).fsPath),
mkdirp(path.dirname(fsPath)),
]);
await symlink(target, fsPath);
return FileFsRef.fromFsPath({ mode, fsPath });
} else {
const stream = file.toStream();
return FileFsRef.fromStream({ mode, stream, fsPath });
}
}
async function removeFile(basePath: string, fileMatched: string) {
const file = path.join(basePath, fileMatched);
await remove(file);
}
export default async function download(
files: Files,
basePath: string,
meta?: Meta
): Promise<DownloadedFiles> {
const { isDev = false, skipDownload = false, filesChanged = null, filesRemoved = null } =
meta || {};
if (isDev || skipDownload) {
// In `now dev`, the `download()` function is a no-op because
// the `basePath` matches the `cwd` of the dev server, so the
// source files are already available.
return files as DownloadedFiles;
}
const files2: DownloadedFiles = {};
await Promise.all(
Object.keys(files).map(async name => {
// If the file does not exist anymore, remove it.
if (Array.isArray(filesRemoved) && filesRemoved.includes(name)) {
await removeFile(basePath, name);
return;
}
// If a file didn't change, do not re-download it.
if (Array.isArray(filesChanged) && !filesChanged.includes(name)) {
return;
}
const file = files[name];
const fsPath = path.join(basePath, name);
files2[name] = await downloadFile(file, fsPath);
})
);
return files2;
}

View File

@@ -1,10 +0,0 @@
import { join } from 'path';
import { tmpdir } from 'os';
import { mkdirp } from 'fs-extra';
export default async function getWritableDirectory() {
const name = Math.floor(Math.random() * 0x7fffffff).toString(16);
const directory = join(tmpdir(), name);
await mkdirp(directory);
return directory;
}

View File

@@ -1,70 +0,0 @@
import path from 'path';
import assert from 'assert';
import vanillaGlob_ from 'glob';
import { promisify } from 'util';
import { lstat, Stats } from 'fs-extra';
import FileFsRef from '../file-fs-ref';
type GlobOptions = vanillaGlob_.IOptions;
interface FsFiles {
[filePath: string]: FileFsRef;
}
const vanillaGlob = promisify(vanillaGlob_);
export default async function glob(
pattern: string,
opts: GlobOptions | string,
mountpoint?: string
): Promise<FsFiles> {
let options: GlobOptions;
if (typeof opts === 'string') {
options = { cwd: opts };
} else {
options = opts;
}
if (!options.cwd) {
throw new Error(
'Second argument (basePath) must be specified for names of resulting files'
);
}
if (!path.isAbsolute(options.cwd)) {
throw new Error(`basePath/cwd must be an absolute path (${options.cwd})`);
}
const results: FsFiles = {};
options.symlinks = {};
options.statCache = {};
options.stat = true;
options.dot = true;
const files = await vanillaGlob(pattern, options);
for (const relativePath of files) {
const fsPath = path.join(options.cwd!, relativePath).replace(/\\/g, '/');
let stat: Stats = options.statCache![fsPath] as Stats;
assert(
stat,
`statCache does not contain value for ${relativePath} (resolved to ${fsPath})`
);
if (stat.isFile()) {
const isSymlink = options.symlinks![fsPath];
if (isSymlink) {
stat = await lstat(fsPath);
}
let finalPath = relativePath;
if (mountpoint) {
finalPath = path.join(mountpoint, finalPath);
}
results[finalPath] = new FileFsRef({ mode: stat.mode, fsPath });
}
}
return results;
}

View File

@@ -1,53 +0,0 @@
import { intersects } from 'semver';
import { NodeVersion } from '../types';
const supportedOptions: NodeVersion[] = [
{ major: 10, range: '10.x', runtime: 'nodejs10.x' },
{ major: 8, range: '8.10.x', runtime: 'nodejs8.10' },
];
// This version should match Fargate's default in the PATH
// Today that is Node 8
export const defaultSelection = supportedOptions.find(
o => o.major === 8
) as NodeVersion;
export async function getSupportedNodeVersion(
engineRange?: string,
silent?: boolean
): Promise<NodeVersion> {
let selection = defaultSelection;
if (!engineRange) {
if (!silent) {
console.log(
'missing `engines` in `package.json`, using default range: ' +
selection.range
);
}
} else {
const found = supportedOptions.some(o => {
// the array is already in order so return the first
// match which will be the newest version of node
selection = o;
return intersects(o.range, engineRange);
});
if (found) {
if (!silent) {
console.log(
'Found `engines` in `package.json`, selecting range: ' +
selection.range
);
}
} else {
if (!silent) {
throw new Error(
'found `engines` in `package.json` with an unsupported node range: ' +
engineRange +
'\nplease use `10.x` or `8.10.x` instead'
);
}
}
}
return selection;
}

View File

@@ -1,12 +0,0 @@
import { Files } from '../types';
type Delegate = (name: string) => string;
export default function rename(files: Files, delegate: Delegate): Files {
return Object.keys(files).reduce(
(newFiles, name) => ({
...newFiles,
[delegate(name)]: files[name],
}),
{}
);
}

View File

@@ -1,207 +0,0 @@
import assert from 'assert';
import fs from 'fs-extra';
import path from 'path';
import debug from '../debug';
import spawn from 'cross-spawn';
import { SpawnOptions } from 'child_process';
import { deprecate } from 'util';
import { Meta, PackageJson, NodeVersion, Config } from '../types';
import { getSupportedNodeVersion } from './node-version';
function spawnAsync(
command: string,
args: string[],
cwd: string,
opts: SpawnOptions = {}
) {
return new Promise<void>((resolve, reject) => {
const stderrLogs: Buffer[] = [];
opts = { stdio: 'inherit', cwd, ...opts };
const child = spawn(command, args, opts);
if (opts.stdio === 'pipe' && child.stderr) {
child.stderr.on('data', data => stderrLogs.push(data));
}
child.on('error', reject);
child.on('close', (code, signal) => {
if (code === 0) {
return resolve();
}
const errorLogs = stderrLogs.map(line => line.toString()).join('');
if (opts.stdio !== 'inherit') {
reject(new Error(`Exited with ${code || signal}\n${errorLogs}`));
} else {
reject(new Error(`Exited with ${code || signal}`));
}
});
});
}
async function chmodPlusX(fsPath: string) {
const s = await fs.stat(fsPath);
const newMode = s.mode | 64 | 8 | 1; // eslint-disable-line no-bitwise
if (s.mode === newMode) return;
const base8 = newMode.toString(8).slice(-3);
await fs.chmod(fsPath, base8);
}
export async function runShellScript(
fsPath: string,
args: string[] = [],
spawnOpts?: SpawnOptions
) {
assert(path.isAbsolute(fsPath));
const destPath = path.dirname(fsPath);
await chmodPlusX(fsPath);
await spawnAsync(`./${path.basename(fsPath)}`, args, destPath, spawnOpts);
return true;
}
export function getSpawnOptions(
meta: Meta,
nodeVersion: NodeVersion
): SpawnOptions {
const opts = {
env: { ...process.env },
};
if (!meta.isDev) {
opts.env.PATH = `/node${nodeVersion.major}/bin:${opts.env.PATH}`;
}
return opts;
}
export async function getNodeVersion(
destPath: string,
minNodeVersion?: string,
config?: Config
): Promise<NodeVersion> {
const { packageJson } = await scanParentDirs(destPath, true);
let range: string | undefined;
let silent = false;
if (packageJson && packageJson.engines && packageJson.engines.node) {
range = packageJson.engines.node;
} else if (minNodeVersion) {
range = minNodeVersion;
silent = true;
} else if (config && config.zeroConfig) {
// Use latest node version zero config detected
range = '10.x';
silent = true;
}
return getSupportedNodeVersion(range, silent);
}
async function scanParentDirs(destPath: string, readPackageJson = false) {
assert(path.isAbsolute(destPath));
let hasPackageLockJson = false;
let packageJson: PackageJson | undefined;
let currentDestPath = destPath;
// eslint-disable-next-line no-constant-condition
while (true) {
const packageJsonPath = path.join(currentDestPath, 'package.json');
// eslint-disable-next-line no-await-in-loop
if (await fs.pathExists(packageJsonPath)) {
// eslint-disable-next-line no-await-in-loop
if (readPackageJson) {
packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
}
// eslint-disable-next-line no-await-in-loop
hasPackageLockJson = await fs.pathExists(
path.join(currentDestPath, 'package-lock.json')
);
break;
}
const newDestPath = path.dirname(currentDestPath);
if (currentDestPath === newDestPath) break;
currentDestPath = newDestPath;
}
return { hasPackageLockJson, packageJson };
}
export async function runNpmInstall(
destPath: string,
args: string[] = [],
spawnOpts?: SpawnOptions,
meta?: Meta
) {
if (meta && meta.isDev) {
debug('Skipping dependency installation because dev mode is enabled');
return;
}
assert(path.isAbsolute(destPath));
let commandArgs = args;
console.log(`installing to ${destPath}`);
const { hasPackageLockJson } = await scanParentDirs(destPath);
const opts = spawnOpts || { env: process.env };
if (hasPackageLockJson) {
commandArgs = args.filter(a => a !== '--prefer-offline');
await spawnAsync(
'npm',
commandArgs.concat(['install', '--unsafe-perm']),
destPath,
opts
);
} else {
await spawnAsync(
'yarn',
commandArgs.concat(['--ignore-engines', '--cwd', destPath]),
destPath,
opts
);
}
}
export async function runPackageJsonScript(
destPath: string,
scriptName: string,
opts?: SpawnOptions
) {
assert(path.isAbsolute(destPath));
const { packageJson, hasPackageLockJson } = await scanParentDirs(
destPath,
true
);
const hasScript = Boolean(
packageJson &&
packageJson.scripts &&
scriptName &&
packageJson.scripts[scriptName]
);
if (!hasScript) return false;
if (hasPackageLockJson) {
console.log(`running "npm run ${scriptName}"`);
await spawnAsync('npm', ['run', scriptName], destPath, opts);
} else {
console.log(`running "yarn run ${scriptName}"`);
await spawnAsync(
'yarn',
['--cwd', destPath, 'run', scriptName],
destPath,
opts
);
}
return true;
}
/**
* @deprecate installDependencies() is deprecated.
* Please use runNpmInstall() instead.
*/
export const installDependencies = deprecate(
runNpmInstall,
'installDependencies() is deprecated. Please use runNpmInstall() instead.'
);

View File

@@ -1,28 +0,0 @@
import eos from 'end-of-stream';
export default function streamToBuffer(
stream: NodeJS.ReadableStream
): Promise<Buffer> {
return new Promise<Buffer>((resolve, reject) => {
const buffers: Buffer[] = [];
stream.on('data', buffers.push.bind(buffers));
eos(stream, err => {
if (err) {
reject(err);
return;
}
switch (buffers.length) {
case 0:
resolve(Buffer.allocUnsafe(0));
break;
case 1:
resolve(buffers[0]);
break;
default:
resolve(Buffer.concat(buffers));
}
});
});
}

View File

@@ -1,47 +0,0 @@
import FileBlob from './file-blob';
import FileFsRef from './file-fs-ref';
import FileRef from './file-ref';
import { Lambda, createLambda } from './lambda';
import download, { DownloadedFiles } from './fs/download';
import getWriteableDirectory from './fs/get-writable-directory';
import glob from './fs/glob';
import rename from './fs/rename';
import {
installDependencies,
runPackageJsonScript,
runNpmInstall,
runShellScript,
getNodeVersion,
getSpawnOptions,
} from './fs/run-user-scripts';
import streamToBuffer from './fs/stream-to-buffer';
import shouldServe from './should-serve';
import { detectBuilders } from './detect-builders';
import { detectRoutes } from './detect-routes';
import debug from './debug';
export {
FileBlob,
FileFsRef,
FileRef,
Lambda,
createLambda,
download,
DownloadedFiles,
getWriteableDirectory,
glob,
rename,
installDependencies,
runPackageJsonScript,
runNpmInstall,
runShellScript,
getNodeVersion,
getSpawnOptions,
streamToBuffer,
shouldServe,
detectBuilders,
detectRoutes,
debug,
};
export * from './types';

View File

@@ -1,107 +0,0 @@
import assert from 'assert';
import Sema from 'async-sema';
import { ZipFile } from 'yazl';
import { readlink } from 'fs-extra';
import { Files } from './types';
import FileFsRef from './file-fs-ref';
import { isSymbolicLink } from './fs/download';
import streamToBuffer from './fs/stream-to-buffer';
interface Environment {
[key: string]: string;
}
interface LambdaOptions {
zipBuffer: Buffer;
handler: string;
runtime: string;
environment: Environment;
}
interface CreateLambdaOptions {
files: Files;
handler: string;
runtime: string;
environment?: Environment;
}
export class Lambda {
public type: 'Lambda';
public zipBuffer: Buffer;
public handler: string;
public runtime: string;
public environment: Environment;
constructor({ zipBuffer, handler, runtime, environment }: LambdaOptions) {
this.type = 'Lambda';
this.zipBuffer = zipBuffer;
this.handler = handler;
this.runtime = runtime;
this.environment = environment;
}
}
const sema = new Sema(10);
const mtime = new Date(1540000000000);
export async function createLambda({
files,
handler,
runtime,
environment = {},
}: CreateLambdaOptions): Promise<Lambda> {
assert(typeof files === 'object', '"files" must be an object');
assert(typeof handler === 'string', '"handler" is not a string');
assert(typeof runtime === 'string', '"runtime" is not a string');
assert(typeof environment === 'object', '"environment" is not an object');
await sema.acquire();
try {
const zipBuffer = await createZip(files);
return new Lambda({
zipBuffer,
handler,
runtime,
environment,
});
} finally {
sema.release();
}
}
export async function createZip(files: Files): Promise<Buffer> {
const names = Object.keys(files).sort();
const symlinkTargets = new Map<string, string>();
for (const name of names) {
const file = files[name];
if (file.mode && isSymbolicLink(file.mode) && file.type === 'FileFsRef') {
const symlinkTarget = await readlink((file as FileFsRef).fsPath);
symlinkTargets.set(name, symlinkTarget);
}
}
const zipFile = new ZipFile();
const zipBuffer = await new Promise<Buffer>((resolve, reject) => {
for (const name of names) {
const file = files[name];
const opts = { mode: file.mode, mtime };
const symlinkTarget = symlinkTargets.get(name);
if (typeof symlinkTarget === 'string') {
zipFile.addBuffer(Buffer.from(symlinkTarget, 'utf8'), name, opts);
} else {
const stream = file.toStream() as import('stream').Readable;
stream.on('error', reject);
zipFile.addReadStream(stream, name, opts);
}
}
zipFile.end();
streamToBuffer(zipFile.outputStream)
.then(resolve)
.catch(reject);
});
return zipBuffer;
}

View File

@@ -1,27 +0,0 @@
import { parse } from 'path';
import { ShouldServeOptions } from './types';
import FileFsRef from './file-fs-ref';
export default function shouldServe({
entrypoint,
files,
requestPath,
}: ShouldServeOptions): boolean {
requestPath = requestPath.replace(/\/$/, ''); // sanitize trailing '/'
entrypoint = entrypoint.replace(/\\/, '/'); // windows compatibility
if (entrypoint === requestPath && hasProp(files, entrypoint)) {
return true;
}
const { dir, name } = parse(entrypoint);
if (name === 'index' && dir === requestPath && hasProp(files, entrypoint)) {
return true;
}
return false;
}
function hasProp(obj: { [path: string]: FileFsRef }, key: string): boolean {
return Object.hasOwnProperty.call(obj, key);
}

View File

@@ -1,216 +0,0 @@
import FileRef from './file-ref';
import FileFsRef from './file-fs-ref';
export interface File {
type: string;
mode: number;
toStream: () => NodeJS.ReadableStream;
/**
* The absolute path to the file in the filesystem
*/
fsPath?: string;
}
export interface Files {
[filePath: string]: File;
}
export interface Route {
src?: string;
dest?: string;
handle?: string;
type?: string;
headers?: {
[key: string]: string;
};
continue?: boolean;
status?: number;
}
export interface Config {
[key: string]:
| string
| string[]
| boolean
| number
| { [key: string]: string }
| undefined;
maxLambdaSize?: string;
includeFiles?: string | string[];
bundle?: boolean;
ldsflags?: string;
helpers?: boolean;
rust?: string;
debug?: boolean;
zeroConfig?: boolean;
import?: { [key: string]: string };
}
export interface Meta {
isDev?: boolean;
skipDownload?: boolean;
requestPath?: string;
filesChanged?: string[];
filesRemoved?: string[];
}
export interface AnalyzeOptions {
/**
* All source files of the project
*/
files: {
[filePath: string]: FileRef;
};
/**
* 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;
/**
* An arbitrary object passed by the user in the build definition defined
* in `now.json`.
*/
config: Config;
}
export interface BuildOptions {
/**
* All source files of the project
*/
files: Files;
/**
* 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;
/**
* An arbitrary object passed by the user in the build definition defined
* in `now.json`.
*/
config: Config;
/**
* Metadata related to the invoker of the builder, used by `now dev`.
* Builders may use the properties on this object to change behavior based
* on the build environment.
*/
meta?: Meta;
}
export interface PrepareCacheOptions {
/**
* All source files of the project
*/
files: Files;
/**
* 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.
*/
workPath: string;
/**
* A writable temporary directory where you can build a cache to use for
* the next run.
*/
cachePath: string;
/**
* An arbitrary object passed by the user in the build definition defined
* in `now.json`.
*/
config: Config;
}
export interface ShouldServeOptions {
/**
* A path string from a request.
*/
requestPath: string;
/**
* 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;
/**
* All source files of the project
*/
files: {
[path: string]: FileFsRef;
};
/**
* A writable temporary directory where you are encouraged to perform your
* build process. This directory will be populated with the restored cache.
*/
workPath: string;
/**
* An arbitrary object passed by the user in the build definition defined
* in `now.json`.
*/
config: Config;
}
export interface PackageJson {
name?: string;
version?: string;
engines?: {
[key: string]: string;
node: string;
npm: string;
};
scripts?: {
[key: string]: string;
};
dependencies?: {
[key: string]: string;
};
devDependencies?: {
[key: string]: string;
};
}
export interface NodeVersion {
major: number;
range: string;
runtime: string;
}
export interface Builder {
use: string;
src: string;
config?: Config;
}

View File

@@ -1 +0,0 @@
now.json

View File

@@ -1,3 +0,0 @@
module.exports = (req, res) => {
res.end(req.query.endpoint);
};

View File

@@ -1,3 +0,0 @@
module.exports = (req, res) => {
res.end(`${req.query.endpoint}/${req.query.id}`);
};

View File

@@ -1,5 +0,0 @@
{
"scripts": {
"build": "mkdir -p public && echo 'hello from index.txt' > public/index.txt"
}
}

View File

@@ -1 +0,0 @@
now.json

View File

@@ -1,3 +0,0 @@
module.exports = (req, res) => {
res.end('hello from api/date.js');
};

View File

@@ -1,3 +0,0 @@
module.exports = (req, res) => {
res.end('hello from api/date/index.js');
};

View File

@@ -1,3 +0,0 @@
module.exports = (req, res) => {
res.end('hello from api/index.js');
};

View File

@@ -1,5 +0,0 @@
{
"scripts": {
"build": "mkdir -p public && echo 'hello from index.txt' > public/index.txt"
}
}

View File

@@ -1,5 +0,0 @@
const cowsay = require('cowsay').say;
module.exports = (req, resp) => {
resp.end(cowsay({ text: 'cross-cow:RANDOMNESS_PLACEHOLDER' }));
};

View File

@@ -1,5 +0,0 @@
{
"dependencies": {
"lib": "../lib"
}
}

View File

@@ -1,7 +0,0 @@
{
"name": "lib",
"version": "0.0.1",
"dependencies": {
"cowsay": "*"
}
}

View File

@@ -1,10 +0,0 @@
{
"version": 2,
"builds": [{ "src": "api/index.js", "use": "@now/node" }],
"probes": [
{
"path": "/api/index.js",
"mustContain": "cross-cow:RANDOMNESS_PLACEHOLDER"
}
]
}

View File

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

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