Compare commits

..

508 Commits

Author SHA1 Message Date
Steven
0b54093ca2 Publish
- @now/go@0.5.7
 - @now/node@0.12.3
 - @now/python@0.2.13
 - @now/routing-utils@1.2.1
 - @now/rust@0.2.10
 - @now/static-build@0.9.3
2019-08-01 16:10:17 -07:00
Steven
8c7371e093 Revert "[now-build-utils][now-static-build] Fix spawn options fo… (#867)
This reverts commit cf640a619e35c8cebaf6655799f273ba11bbd6e6.
2019-08-01 16:06:00 -07:00
Matthew Sweeney
e59c0f59f5 [now-static-build] Add sapper Optimization and Test (#865)
* add sapper optimization and test

* remove test dir

* remove test scripts
2019-08-01 15:28:16 -07:00
Steven
21b115a788 Update CODEOWNERS (#866) 2019-08-01 15:28:07 -07:00
Connor Davis
c5df4f7f9e [now-routing-utils] Make Now Routing Utils a Public Library (#860)
* Make Now Routing Utils a Public Library

* Suggestions

* Cleanup

* Update lockfile

* Add to dist to eslint ignore

* v1.2.0-canary.0

* v1.2.0-canary.1

* v1.2.1-canary.0

* Use optional dep instead of peer dep
2019-08-01 15:28:02 -07:00
Igor Klopov
2429451115 [now-rust] install rust in npm install of the builder (#863) 2019-08-01 15:27:45 -07:00
Andy
21789cdbf1 [now-build-utils][now-static-build] Fix spawn options for windows (#864)
* [now-build-utils][now-static-build] Fix spawn options for windows

* Fix type

* Fix types
2019-08-01 15:27:39 -07:00
Igor Klopov
f74ed2aff1 [now-go] install golang in npm install step (#859)
* [now-go] install golang in npm install step

* update

* move logic into now-install script

* remove unneeded items from gitignore

* now-postinstall
2019-08-01 15:27:28 -07:00
Steven
2f83e6375a [now-node] Bump node-file-trace to 0.2.6 (#861) 2019-08-01 15:27:23 -07:00
Kai Richard König
99a7b8f1f7 [now-python] Use pipfile2req to convert pipfile to requirements.txt (#857)
* Use a more robust library to convert pipfile - closes #841

* Renaming for clarity

* Suppress warnings since we know it will be invoked manually

Co-Authored-By: Steven <steven@ceriously.com>

* Apply the flag while installing not while generating the requirements.

Co-Authored-By: Steven <steven@ceriously.com>
2019-08-01 15:27:17 -07:00
Steven
3fa7b80bde Publish
- @now/build-utils@0.9.6
 - @now/next@0.5.8
 - @now/node@0.12.2
2019-07-31 08:30:21 -04:00
Steven
d012e73166 [now-node] Bump node-file-trace to 0.2.5 (#852) 2019-07-31 08:29:09 -04:00
Andy
d6c46da37f [now-build-utils] Remove @now/nuxt from default builders (#850) 2019-07-31 08:29:04 -04:00
Andy
1508932ad6 [now-static-build] Allow setting the tag for zero-config builders (#842)
* [now-static-build] Allow to set the `tag` for zero-config builders

This reverts commit 32b6f1d6a9047920d6cc40385de711022f77c4d4.

* Remove unsupported builders

* Fix setting the tag
2019-07-31 08:28:58 -04:00
Steven
873b099f53 [now-node] Bump node-file-trace to 0.2.4 (#849) 2019-07-31 08:28:52 -04:00
Steven
6546d3b67d [now-build-utils] Fix require file path for legacy builders (#846)
* [now-build-utils] Fix require file path

* Add more tests
2019-07-31 08:28:46 -04:00
Steven
34ad4ac33a [now-next] Fix dev-server bundle output (#847)
* [now-next] Fix dev-server bundle

* [now-next] Fix bundle output dev-server
2019-07-31 08:28:39 -04:00
Steven
01d0b017af Publish
- @now/build-utils@0.9.5
 - @now/next@0.5.7
 - @now/node@0.12.1
 - @now/static-build@0.9.2
2019-07-30 07:38:20 -04:00
Steven
db88ad4b32 [master] Clean up package.json to match canary 2019-07-30 07:28:41 -04:00
Andy Bitz
4b846c3c88 Revert "[now-static-build] Allow to set the tag for zero-config builders"
This reverts commit d74d5141e4cb2c4e1e8a50bd66cad8d36f57e734.
2019-07-30 07:24:49 -04:00
Andy Bitz
2731435e3b [now-static-build] Allow to set the tag for zero-config builders 2019-07-30 07:24:43 -04:00
Steven
f18e1a6bd4 [now-static-build] Use ncc before publishing to npm (#839) 2019-07-30 07:24:31 -04:00
Steven
167d7bedec [now-next] Use ncc before publishing to npm (#832)
* [now-next] Change bridge build step

* Remove dependency on @now/node-bridge

* Test: print deploymentUrl

* Rename build script

* Use ncc before publishing

* Move deps to devDependencies
2019-07-30 07:24:11 -04:00
Sophearak Tha
cd0b1d61d1 [now-build-utils] Add debug() function (#831)
* Add `debug()` function

* Apply suggestions from code review

Co-Authored-By: Steven <steven@ceriously.com>

* Update packages/now-build-utils/src/debug.ts

Co-Authored-By: Steven <steven@ceriously.com>

* Apply suggestions from code review

Co-Authored-By: Steven <steven@ceriously.com>
2019-07-30 07:21:44 -04:00
Steven
86dc3708d2 [now-node] Fix 18-nested-tsconfig tests (#830)
* [now-node] Fix nested-tsconfig tests

* Remove unnecessary test
2019-07-30 07:21:19 -04:00
paulogdm
1e79eae029 Update _error.js route to return 404 status (#828) 2019-07-30 07:21:07 -04:00
paulogdm
d0c954210a Update types.ts (#829) 2019-07-30 07:20:55 -04:00
Steven
67c3481779 [now-build-utils] Use ncc before publishing to npm (#820)
* [now-build-utils] Use ncc before publish to npm

* Test all foreign fixtures

* Revert tests, but keep now-next
2019-07-30 07:20:42 -04:00
Steven
67473afd5b [now-node] Bump node-file-trace to 0.2.3 (#819)
* Silence vscode error

* Bump node-file-trace to 0.2.3

* Add test for mixed modules
2019-07-30 07:20:19 -04:00
Steven
3d52610acf [now-node] Fix symlink regression (#813) 2019-07-30 07:20:07 -04:00
Steven
729ba010c4 [now-node] Change TS default to esModuleInterop=true (#789)
* [now-node] Default to esModuleInterop=true

* Add test fixture 19-default-import-ts

* Change back to match ts-node
2019-07-30 07:19:51 -04:00
Steven
a470e563dc [now-node] Add logs with time for each step (#786)
* [now-node] Add logs with time for each step

* Fix typo
2019-07-30 07:19:33 -04:00
ywg-jean
15f674b8b7 [now-node] Yarn workspaces/transpilation followup (#782)
* tests transpilation of yarn workspaces

up until @now/node@0.7.4-canary.28 this used to work out of the box

* tests that typescript workspaces are properly compiled

* update node-file-trace, symlink handling

* update node-file-trace, use index.ts in package.json main

* remove logging!

* adds test with ts files in a subdir

* Updates typescript example to avoid node internal special casing

The initial example ended up passing even with a flawed implementation
because it unknowingly relied on a special case within node module's
resulotion engine which automaticaly resolves index files
within a module if they are located in the same directory as the
module's `package.json`

* upgrade to node-file-trace 0.2.2

* cleanup manual debugging leftovers

* fix yarn lock for node-file-trace 0.2.2

* more cleanup of manual tests

I offer my apologies about this mess
2019-07-30 07:19:15 -04:00
Andy Bitz
1e4e6b68e0 Publish
- @now/build-utils@0.9.4
2019-07-24 22:27:49 +02:00
Andy
2332100cff [now-build-utils] Do not use canary for zero config (#821) 2019-07-24 22:27:34 +02:00
Steven
9cb6f500b0 Publish
- @now/build-utils@0.9.3
 - @now/next@0.5.6
2019-07-23 14:45:11 -04:00
Joe Haddad
79a2bfde35 [now-next] Add immutable header to Next.js static assets (#810)
* Add immutable header to Next.js static assets

* Verify builder injects immutable header

* Use incorrect type

* Add missing field

* Add missing else clause
2019-07-23 14:43:29 -04:00
Luis Fernando Alvarez D
86a659e5c5 Normalize slash for nested paths (#788)
* Fixed slash issue in nested folders for Windows

* Added a test for dynamic routes in dev
2019-07-23 14:43:18 -04:00
Andy Bitz
0f00110db7 Publish
- @now/static-build@0.9.1
2019-07-22 20:51:23 +02:00
Andy
03ca6975ed [now-static-build] Use dev command in zero config when there is no (#808)
command
2019-07-22 20:50:25 +02:00
Andy
001813c529 [now-static-build] Adjust error message (#807) 2019-07-22 20:50:16 +02:00
Leo Lamprecht
570ef4824b Publish
- @now/static-build@0.9.0
2019-07-22 18:12:18 +00:00
Leo Lamprecht
ae9a43a0bd [now-static-build] Optimized Docusarus 2.0 (#809)
* Optimized Docusarus 2.0

* Better name for framework

* Added Docusaurus 1.0 test
2019-07-22 18:11:40 +00:00
Andy Bitz
ffaa5eaa17 Publish
- @now/build-utils@0.9.2
2019-07-21 20:31:50 +02:00
Andy
7f41a23a43 [now-build-utils] Improve builder detection (#803)
* [now-build-utils] Improve builder detection

* Changed message

* Change type

* Allow standalone public

* Removed unused interface

* Adjust test

* Adjust test
2019-07-21 20:31:21 +02:00
Leo Lamprecht
e80a1a5340 Publish
- @now/static-build@0.8.0
2019-07-20 13:46:54 +00:00
Leo Lamprecht
7eadaf889a Added zero config support for Ember (#801)
* Added zero config support for Ember

* Renamed dir

* Renamed dir

* Removed useless tests

* Trigger production build

* Fixed ember example
2019-07-20 13:38:07 +00:00
Andy Bitz
0823cc1005 Publish
- @now/static-build@0.7.5
2019-07-19 22:26:01 +02:00
Andy
11be2bf349 [now-static-build] Improve error message for the output directory for zero config (#795)
* [now-static-build] Improve error message for the output directory for zero config

* Add link
2019-07-19 22:24:58 +02:00
Andy Bitz
e8f31aebeb Publish
- @now/build-utils@0.9.1
2019-07-19 15:55:07 +02:00
Andy
162d27a38f [now-build-utils] Display link for missing build script warning (#792)
* [now-build-utils] Display link for missing `build` script warning

* Add link
2019-07-19 15:54:52 +02:00
Andy
355c007dbb [now-build-utils] Add nuxt builder detection (#798)
* [now-build-utils] Add nuxt builder detection

* Add tests

* Fix version
2019-07-19 15:54:47 +02:00
Andy Bitz
f946463cab Publish
- @now/static-build@0.7.4
2019-07-19 12:44:25 +02:00
Andy
a1e768ecc1 [now-static-build] Replace dist with public as output directory (#793)
* [now-static-build] Replace `dist` with `public` as output directory

* Fix test

* Revert "Fix test"

This reverts commit 351c84c7bea1313742c165f753e7481fc7c3c0fa.

* Revert "[now-static-build] Replace `dist` with `public` as output directory"

This reverts commit daedfac17729645d9b409d7df3da6b0fb5d3b56a.

* Apply only to zero config

* Fix path
2019-07-19 12:43:51 +02:00
Andy Bitz
539f9135dd Publish
- @now/build-utils@0.9.0
2019-07-19 00:35:45 +02:00
Andy
abd3d84d4c [now-build-utils] Improve static builds detection (#787)
* [now-build-utils] Improve static builds detection

* Don't deconstruct

* Allow null for package.json
2019-07-19 00:29:47 +02:00
Steven
0274893d31 Publish
- @now/bash@1.0.3
2019-07-18 10:32:09 -04:00
Steven
0ec767e0d0 Enhance readme publish steps (#783) 2019-07-18 10:19:34 -04:00
Steven
e6296fa06b Ignore yarn.lock changes on publish (#784) 2019-07-18 10:19:26 -04:00
Igor Klopov
35def42263 [now-bash] Respect meta.isDev flag (#778)
* switch from SRC to DIST, pass 'meta' to 'download'

* mkdir true directory of entrypoint

* lint fixes

* added a test

* Delete yarn-error.log
2019-07-18 10:19:18 -04:00
Steven
08641ab804 Publish
- @now/bash@1.0.2
 - @now/build-utils@0.8.9
 - @now/go@0.5.6
 - @now/next@0.5.5
 - @now/node-bridge@1.2.3
 - @now/node@0.12.0
 - @now/php@0.5.7
 - @now/python@0.2.12
 - @now/ruby@0.1.3
 - @now/rust@0.2.9
 - @now/static-build@0.7.3
2019-07-18 07:25:24 -04:00
Steven
e7f87ceba7 [now-node] Fix order devDependencies (master only) 2019-07-17 17:21:44 -04:00
Steven
e9632699e1 Regenerate yarn.lock and pin dependencies (#780)
* Regenerate yarn.lock

* Fix typings for bridge and helpers

* Remove top level dependencies and pin version

* Add missing @types/multistream

* Add @types/node

* Add @types/node

* Fix child.stdout null check

* Add global types

* Move types to root, generate lock file

* Remove unused tests inside the integration tests
2019-07-17 17:18:02 -04:00
Steven
a9427bbe76 [now-node] Use ncc before publishing to npm (#755)
* [now-node] Use ncc before publishing

* Copy entire bridge source file

* Remove node-bridge dependency

* add typescript to build

* ensure typescript reference is not analyzed

* remove duplicate build

* typescript as a compiler

* Revert "typescript as a compiler"

This reverts commit f51178e641b09ea6aff0dc98185c86e8d27de2cc.

* exclude langs

* fixup mkdir

* fixup mv command

* fixup typescript reference

* Change require to use bridge

* Remove copy step for bridge defs

* Change back to require

* Copy bridge again

* Remove dependency on @now/node-bridge
2019-07-17 13:30:42 -04:00
ywg-jean
cd700b01cc [now-node] Yarn workspaces transpilation & typescript dependenci… (#765)
* tests transpilation of yarn workspaces

up until @now/node@0.7.4-canary.28 this used to work out of the box

* tests that typescript workspaces are properly compiled

* update node-file-trace, symlink handling

* update node-file-trace, use index.ts in package.json main

* remove logging!
2019-07-17 13:30:30 -04:00
Guy Bedford
12244133f8 Use typescript esnext target (#756) 2019-07-17 13:30:17 -04:00
Steven
55acea648c Revert "[now-node-bridge] Increase timeout to 10 minutes" (#768)
This reverts commit 1658a84795b1dbd3ae240b2443476fdcf3af38f7.
2019-07-17 13:30:01 -04:00
Steven
48a6b77fed [now-node-bridge] Increase timeout to 10 minutes (#766) 2019-07-17 13:29:54 -04:00
dependabot[bot]
b0e20c043c Bump lodash from 4.17.11 to 4.17.14 in /test/integration/now-nod… (#761)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.14.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.14)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-17 13:29:38 -04:00
Sophearak Tha
88ceaf12d0 Improve support for zero-config in now dev (#764) 2019-07-17 13:29:16 -04:00
Guy Bedford
0f94a523a6 [now-node] Fix .tsx resolution (#760)
* tsx resolution test

* .tsx support

* add logging, extension rewrite fix

* remove logging
2019-07-17 13:28:47 -04:00
Steven
0b3a01d07b [now-node] Bump @zeit/node-file-trace to 0.1.7 (#759)
* adds failing test to prevent future regression with yarn workspaces

* [now-node] Bump  @zeit/node-file-trace to 0.1.7
2019-07-17 13:28:34 -04:00
Nathan Rajlich
c03d9479e1 [now-static-build] Use yarn when invoking now-dev script (#747)
`yarn` used to be used, but was switched over to `npm` in #636.

The problem with `npm` is that when the `ignoreScripts` config option
is enabled in the user's `.npmrc` file, then `npm run …` does not get
invoked. This makes sense for `npm i`, but doesn't really make sense if
you're explicitly _trying_ to run a package script via `npm run`, and in
fact breaks `now dev`.

`yarn` has a similar option to ignore scripts, however it has the more
understandable behavior that when you do `yarn run` then the script is
actually run.

There isn't a concern about if the user does not have `yarn` installed
since `now dev` bundles its own copy of yarn and uses that version.
2019-07-17 13:28:09 -04:00
JJ Kasper
8d987243c6 Remove extra pre-fixing for dynamic routes (#751) 2019-07-17 13:27:45 -04:00
JJ Kasper
23d877de75 [now-next] Add subdir prefix to "src" for dynamic routes (#745)
* Update dynamic routes to have prefix in src
and not in dest for dev

* Make sure prefix isn't inside of capture
group for dynamic routes

* Prevent double slashes in src regexp

* Make sure leading slash is outside capture group

* Move up removing of leading slash from capture group

Fixes #729.
2019-07-17 13:27:26 -04:00
Guy Bedford
8855813697 [now-node] Support symlink outputs (#728)
* support symlink outputs

* create symlink in build file

* ensure build script idempotency

* Add isSymbolicLink and fix test
2019-07-17 13:26:53 -04:00
Sophearak Tha
5ca59332ed Remove maxLambdaSize config from all builders (#741)
* remove maxLambdaSize config

* remove maxLambdaSize config from `now-bash`, `now-php` and from tests
2019-07-17 13:26:30 -04:00
Luc
860a678b74 Update node-file-trace to 0.1.6 (#748) 2019-07-17 13:26:13 -04:00
Steven
ecb3fd25da [now-lambda] Remove package source code (#744)
* [now-lambda] Remove package source code

* Rename variable
2019-07-17 13:25:18 -04:00
Steven
5cb95bd226 [now-node] Add support for AWS Lambda API usage (#742)
* Add support for direct AWS usage

* Add test case using callback
2019-07-17 13:24:00 -04:00
Guy Bedford
47bc8c04ad update to node-file-trace@0.1.5 (#735) 2019-07-17 13:20:53 -04:00
Steven
2879041a65 Remove deprecated builders (#733)
* Remove deprecated builders

* Update comment so that tests  run
2019-07-17 13:20:35 -04:00
Steven
2e7e403725 [now-node] Add puppeteer / lighthouse tests (#731)
* [now-node] Add puppeteer tests

* Rename puppeteer tests

* Fix tests
2019-07-17 13:18:21 -04:00
Steven
30eede64ec [now-node] Add integration test for sharp (#730)
* [now-node] Add integration test for `sharp`

* Add monkey image in test
2019-07-17 13:18:05 -04:00
Guy Bedford
70f3d6f7de Nested tsconfig.json lookup support (#726)
* lookup nested tsconfig.json for each ts compilation

* [now-node] Nested tsconfig.json

* fixes
2019-07-17 13:17:25 -04:00
Guy Bedford
e1f7191f67 [now-node] Use node-file-trace approach as ncc alternative (#712)
* WIP: filter approach

* typing fixes

* reinclude ncc for helpers build

* include node-file-trace

* get integration tests working

* add node-file-trace to files

* fixup nested package.json files

* add node-file-trace dependencies

* add trace logging

* fixup inputFiles glob

* Revert "add node-file-trace dependencies"

This reverts commit ef0d3f60c9ec9ee78047a3f85f836fab21655bee.

* use external @zeit/node-file-trace

* inputFiles logging

* add missing Promise.all

* remove node-file-trace in files, ncc as devDependency

* disable typescript tests

* feedback from @styfle

* babel support

* add babel commonjs transform

* sourcemaps support

* fix faulty build config

* separate babel compilation file

* typescript attempt

* reenable typescript tests

* typescript support

* fixup typescript source maps

* remove Babel error wrapper

* set typescript errors to logging

* mode support

* formatting

* add back prepareCache

* fixup binary emission

* support typescript compiler fallback

* remove logging

* update yarn lock

* Update packages/now-node/test/fixtures/12-stack-trace-esm/index.js

Co-Authored-By: Steven <steven@ceriously.com>

* formatting

* guard log statements

* update probe line number for eslint ignore line

* fixup default config handling
2019-07-17 13:16:22 -04:00
Steven
a8f4b67aa2 [now-node-server] Remove package source code (#721)
* [now-node-server] Remove package

* Update comment so tests run
2019-07-17 13:15:54 -04:00
Simon Willison
d64a53cbb1 [now-python] Support ASGI functions as well as classes (#711)
* [now-python] Support ASGI functions as well as classes

Refs #710

* Fixed incorrect indentation
2019-07-17 13:12:08 -04:00
Andy Bitz
4300882d12 Publish
- @now/build-utils@0.8.8
2019-07-16 19:30:24 +02:00
Andy
0711e094f3 [now-build-utils] Fix file order (#772)
* [now-build-utils] Fix file order

* Use localeCompare
2019-07-16 19:30:08 +02:00
Andy Bitz
4ec1883262 Publish
- @now/build-utils@0.8.7
2019-07-16 17:25:37 +02:00
Andy
cb53db4157 [now-build-utils] Ignore more default routes and builds (#771)
* [now-build-utils] Ignore more default routes

* Don't export

* Update packages/now-build-utils/src/detect-builder.ts

Co-Authored-By: Steven <steven@ceriously.com>

* Update packages/now-build-utils/src/detect-builder.ts

Co-Authored-By: Steven <steven@ceriously.com>
2019-07-16 17:25:15 +02:00
Andy Bitz
49aea85638 Publish
- @now/build-utils@0.8.6
 - @now/static-build@0.7.2
2019-07-16 11:43:43 +02:00
Andy
3971b5a8cf [now-static-build] Remove default routes for now dev (#769)
* [now-static-build] Remove default routes for now dev

* Update packages/now-static-build/src/index.ts

Co-Authored-By: Leo Lamprecht <mindrun@icloud.com>
2019-07-16 11:41:41 +02:00
Igor Klopov
958946d01a Publish
- @now/build-utils@0.8.5
2019-07-13 22:01:47 +03:00
Igor Klopov
f3d284476f remove mutex because it is not reentrant and hangs on sub-invocation (#758) 2019-07-13 22:00:17 +03:00
Andy Bitz
6076b12067 Publish
- @now/build-utils@0.8.4
 - @now/static-build@0.7.1
2019-07-12 06:35:38 +02:00
Andy
5c7eba6049 [now-static-build] Fix warning and framework support (#750)
* [now-static-build] Fix template string

* [now-static-build] Handle different dist dir for Angular

* Fix type issue

* Fix hexo test

* Log more

* Change hexo test

* Adjust Hexo test

* Removed extra logging

* Continue with prev test

* Use @now/node@canary

* Fix tests

* Increase timeout

* Increase timeout

* Add framework

* Reset timeout for now-build-utils

* Increase timeout

* Adjust test
2019-07-12 06:34:03 +02:00
Andy Bitz
3ed99a5b25 Publish
- @now/next@0.5.4
2019-07-10 23:43:45 +02:00
Andy
f8b08926f2 [now-next] Create a serverless config by creating a new config (#688)
* [now-next] Create a serverless config by creating a new config

* Adjust config for promises

* Add tests and fixes

* Fix the tests

* Always create the config for non-dev mode

* Removed unused version

* Handle promises

* Adjust test

* Removed semver check

* Removed import

* Try tests

* Update tests

* Log results

* Add more logging

* More logging

* Fixed typo and removed logging
2019-07-10 23:43:03 +02:00
Andy Bitz
354e80b3e3 Publish
- @now/build-utils@0.8.3
2019-07-10 17:47:53 +02:00
Andy Bitz
0cfb4a8466 Revert "Remove deprecated builders (#733)"
This reverts commit 6766e9a099.
2019-07-10 17:44:31 +02:00
Andy Bitz
8facd2845f Revert "[now-node-server] Remove package source code (#721)"
This reverts commit d327426c93.
2019-07-10 17:44:28 +02:00
Andy Bitz
9dae464fa6 Revert "Publish"
This reverts commit 6ff4b25d79.
2019-07-10 17:43:42 +02:00
Andy Bitz
6ff4b25d79 Publish
- @now/build-utils@0.8.3
 - @now/node@0.11.2
2019-07-10 17:39:49 +02:00
Steven
6766e9a099 Remove deprecated builders (#733)
* Remove deprecated builders

* Update comment so that tests  run
2019-07-10 17:38:59 +02:00
Steven
d327426c93 [now-node-server] Remove package source code (#721)
* [now-node-server] Remove package

* Update comment so tests run
2019-07-10 17:36:07 +02:00
Andy Bitz
47f73c856f Revert "Remove deprecated builders (#733)"
This reverts commit 9d15c35623.
2019-07-10 17:34:33 +02:00
Andy Bitz
9fdd247773 Revert "[now-node-server] Remove package source code (#721)"
This reverts commit a55ce5da8f.
2019-07-10 17:34:31 +02:00
Andy Bitz
fe59cabf15 Revert "Publish"
This reverts commit da37a9bc06.
2019-07-10 15:30:00 +02:00
Andy Bitz
da37a9bc06 Publish
- @now/build-utils@0.8.3
 - @now/node@0.11.2
2019-07-10 15:19:34 +02:00
Andy
bad779be1f Use --pure-lockfile on build (#738)
* Use --pure-lockfile on build

* Add --pure-lockfile to publish
2019-07-10 15:17:31 +02:00
Andy Bitz
5eb5deb8eb Revert "Publish"
This reverts commit f9afee7dba.
2019-07-10 15:09:42 +02:00
Andy Bitz
f9afee7dba Publish
- @now/build-utils@0.8.3
 - @now/node@0.11.2
2019-07-10 14:28:37 +02:00
Andy
547e9ed684 Add --pure-lockfile option (#737) 2019-07-10 14:26:31 +02:00
Andy Bitz
68d2927cbf Revert "Publish"
This reverts commit ca7f716432.
2019-07-10 14:16:22 +02:00
Andy Bitz
ca7f716432 Publish
- @now/build-utils@0.8.3
 - @now/node@0.11.2
2019-07-10 14:02:12 +02:00
Steven
9d15c35623 Remove deprecated builders (#733)
* Remove deprecated builders

* Update comment so that tests  run
2019-07-10 13:51:37 +02:00
Steven
a55ce5da8f [now-node-server] Remove package source code (#721)
* [now-node-server] Remove package

* Update comment so tests run
2019-07-10 13:49:40 +02:00
Connor Davis
f0a06b797e Update CODEOWNERS 2019-07-10 13:46:33 +02:00
Andy
0a77f43832 [now-build-utils] Add warnings and simpler routes (#734)
* [now-build-utils] Add warnings

* Make routes regexes simpler

* Adjust tests

* Adjust tests

* Fix tests

* Remove now-build script check
2019-07-10 13:46:13 +02:00
Andy Bitz
4ce0d31688 Publish
- @now/bash@1.0.1
 - @now/go@0.5.5
 - @now/python@0.2.11
2019-07-09 01:09:23 +02:00
Andy
280802615f [now-bash][now-go][now-python] Support zero config (#723)
* [now-bash][now-go][now-python] Support zero config

* Remove default config
2019-07-09 01:01:27 +02:00
Andy Bitz
c7db281065 Publish
- @now/build-utils@0.8.2
2019-07-08 17:14:04 +02:00
Andy
ca00739041 [now-build-utils] Fix default routes on windows and adjust error message (#720)
* [now-build-utils] Fix default routes on windows and adjust error message

* Remove extra condition
2019-07-08 17:13:29 +02:00
Andy Bitz
11f8b17599 Publish
- @now/build-utils@0.8.1
2019-07-08 12:40:23 +02:00
Andy Bitz
970ab7d5c5 Revert "Fixed yarn.lock (#717)"
This reverts commit 5bfbd63e13.
2019-07-08 12:39:19 +02:00
Andy Bitz
71c082dccd Revert "Publish"
This reverts commit 76a185eb90.
2019-07-08 12:34:31 +02:00
Andy Bitz
76a185eb90 Publish
- @now/build-utils@0.8.1
2019-07-08 12:23:30 +02:00
Andy
8c0f3d107d [now-build-utils] Ignore dot and underscore prefix for api directory (#718)
* [now-build-utils] Add support for `_` and `.` prefixes in `api/`

 * Remove log statement

* Ignore dot and underscore prefix for api directory

* Set one builder per file if there are files to ignore

* Always return all builds with their exact match
2019-07-08 12:22:40 +02:00
Leo Lamprecht
5bfbd63e13 Fixed yarn.lock (#717)
This reverts commit d83b09ffbd.
2019-07-07 16:00:20 +00:00
Leo Lamprecht
f7bc3b3490 Publish
- @now/bash@1.0.0
 - @now/build-utils@0.8.0
 - @now/go@0.5.4
 - @now/html-minifier@1.1.4
 - @now/md@0.5.5
 - @now/mdx-deck@0.5.5
 - @now/next@0.5.3
 - @now/node-server@0.8.2
 - @now/node@0.11.1
 - @now/optipng@0.6.4
 - @now/php@0.5.6
 - @now/python@0.2.10
 - @now/ruby@0.1.2
 - @now/rust@0.2.8
 - @now/static-build@0.7.0
2019-07-07 15:54:56 +00:00
Leo Lamprecht
d83b09ffbd Revert "Fixed yarn.lock (#717)"
This reverts commit 0c120f6202.
2019-07-07 15:53:06 +00:00
Leo Lamprecht
0c120f6202 Fixed yarn.lock (#717) 2019-07-07 14:54:41 +00:00
Leo Lamprecht
48a01415f8 Complete cleanup (#716) 2019-07-07 16:48:28 +02:00
Leo Lamprecht
9198b72382 Revert "Bumps ncc to 0.20.x (#641)"
This reverts commit cd45dce724405968e9e6f58ae4fad983c5d35f20.
2019-07-07 14:28:26 +00:00
Andy
79048b83de [now-build-utils] Add methods to detect builders and routes from files and package.json (#705)
* [now-build-utils] Add methods to detect builders and routes from files
and package.json

* Update packages/now-build-utils/src/detect-routes.ts

Co-Authored-By: Steven <steven@ceriously.com>

* Update packages/now-build-utils/src/detect-routes.ts

Co-Authored-By: Steven <steven@ceriously.com>

* Update packages/now-build-utils/src/detect-routes.ts

Co-Authored-By: Steven <steven@ceriously.com>

* Added tests for new functions

* Adjusted tests

* Tests

* Tests

* Fix routes detection

* Fix routes and tests

* Update concatArrayOfText
2019-07-07 13:30:53 +00:00
Leo Lamprecht
f798e2cf19 [now-static-build] Optimize more frameworks out of the box (#704)
* Added Preact CLI

* Added Hexo

* Added Aurelia

* Correctly check for projects

* Added Gridsome

* Added UmiJS

* Added Polymer

* Added Polymer tests

* Better umi test

* Correctly test for 404

* Make Polymer tests work perfectly

* Removed aurelia

* Removed tests from preact

* Removed aurelia from the framework list

* Removed broken probe from hexo
2019-07-07 13:30:48 +00:00
Steven
be5057a738 [now-static-build] Add support for Node 10 in shell scripts (#708) 2019-07-07 13:30:44 +00:00
Steven
059d44fde7 [now-build-utils] Add shell script args / opts (#707)
* [now-build-utils] Add shell script args / opts

* Remove dead code
2019-07-07 13:30:40 +00:00
Igor Klopov
11ad481546 [now-build-utils] Add option to skip download + yarn mutex (#700)
* dontDownload in Meta

* yarn --mutex network

* dontDownload -> skipDownload
2019-07-07 13:30:34 +00:00
Luc
4061ed2eb7 [now-node] Make types.d.ts the main types export (#706) 2019-07-07 13:30:30 +00:00
dependabot[bot]
b54c79e619 Bump fstream from 1.0.11 to 1.0.12 (#702)
Bumps [fstream](https://github.com/npm/fstream) from 1.0.11 to 1.0.12.
- [Release notes](https://github.com/npm/fstream/releases)
- [Commits](https://github.com/npm/fstream/compare/v1.0.11...v1.0.12)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-07 13:30:24 +00:00
Luc
2203ae1a20 [now-node] Reduce risks of conflict with entrypoint's name (#626)
* helper -> ___help3rs , bridge -> ___bridg3

* launcher -> ___launch3r

* use const to configure filenames

* revert yarn.lock

* add `now` in file names

Co-Authored-By: Steven <steven@ceriously.com>

* add test to prevent regression

* remove 3 in filenames

* rename fixtures folder

* Apply suggestions from code review

Co-Authored-By: Steven <steven@ceriously.com>

* fix errors
2019-07-07 13:30:16 +00:00
Steven
5e58c1738b Add lucleray to codeowners (#695) 2019-07-07 13:30:12 +00:00
Luc
290577ddfb [now-node] Benchmark helpers (#613)
* add bench

* remove yarn.lock

* refactor and extract launcher logic

* add entrypoints to bench

* Update packages/now-node/src/launcher.ts

Co-Authored-By: Steven <steven@ceriously.com>
2019-07-07 13:30:08 +00:00
Steven
a5e651403e [now-node] Add support for server.listen() (#691)
* [now-node] Add support for listener

* Fix listener

* Add hapi-async test

* Add timeout for listening

* Add additional case for invalid export

* Increase timeout to 5 seconds
2019-07-07 13:30:03 +00:00
ywg-jean
df2769717b Bumps ncc to 0.20.x (#641)
* bumps ncc to 0.20.0

* upgrades to ncc@0.20.2

this includes the fixes for https://github.com/zeit/ncc/issues/434

* defines filterAssetBase when calling ncc

This prevents assets from being evicted by ncc's filtering.

* scopes includeFiles under the package root

it was previously scoped under the directory of the input file currently
being processed.
This should fix #522 along with fixing the 09-include-files tests for
now-node

* Bump to ncc 0.20.3

* Bump ncc-watcher to 1.1.0
2019-07-07 13:29:57 +00:00
Tim Craft
880ef77b7b [now-ruby] Use BUNDLE_JOBS=4 for parallel Ruby gem downloads (#689) 2019-07-07 13:29:23 +00:00
Tim Craft
af2616c283 [now-ruby] Use ruby 2.5.5 (#690) 2019-07-07 13:29:19 +00:00
Steven
4300f4d797 Add homepage to all packages (#685) 2019-07-07 13:29:13 +00:00
Nathan Rajlich
4921e541af [now-node] Use the local version of node when running via now dev (#683)
This is a companion to https://github.com/zeit/now-cli/pull/2480.
2019-07-07 13:29:07 +00:00
Leo Lamprecht
6ce00eda8c [now-static-build] Optimize static frameworks (#696)
* Optimize frameworks in @now/static-build

* Make it shorter

* Disable build.sh for zero config

* Adjust error message according to zero config prop

* Renamed wrong fixtures

* Added Gatsby fixture

* Ignore static-build fixtures when linting

* Fix test

* Support Svelte

* Added Create React app and Svelte defaults

* Added comma

* Merge routes properly

* Removed test file

* Polished test

* Fixed types

* Added type

* Added correct type

* Added default routes for Svelte

* Extended route type

* Temporarily removed check

* Revert "Temporarily removed check"

This reverts commit bb5e2843eca60753228d499efbb6dd4aa1c28c5b.

* Enable routes

* Added package.json type

* Added Framework type

* Added Route type

* Increase size

* Export Route type

* Added Vue

* Fix test

* Fixed all tests

* Added Angular app

* Removed garbage

* Ignore ts stuff

* Added type

* Added type for function

* Made it async

* Require minimum node version

* Push pretter polishment

* Add support for node version

* Make minNodeVersion optional

* Make node version silent

* Added optional type

* Log everything

* Fixed tests

* Changed version

* Pushed Node.js version update

* Update packages/now-build-utils/src/fs/node-version.ts

Co-Authored-By: Andy <AndyBitz@users.noreply.github.com>

* Cleaner syntax

* Silence more messages

* Hide more text

* Update packages/now-build-utils/src/fs/run-user-scripts.ts

Co-Authored-By: Steven <steven@ceriously.com>

* Update packages/now-build-utils/src/fs/run-user-scripts.ts

Co-Authored-By: Steven <steven@ceriously.com>
2019-07-07 13:27:38 +00:00
Andy Bitz
060e952f6c Publish
- @now/build-utils@0.7.4
2019-07-04 22:58:06 +02:00
Andy Bitz
1639127b24 Publish
- @now/next@0.5.2
2019-07-01 18:45:01 +02:00
Joe Haddad
ebbb62eaea [now-next] Reorder process overrides (#682)
* Reorder process overrides

* Remove next.config.js to test the feature

* Correct src

* Fix more broken code

* Fix tests
2019-07-01 18:44:43 +02:00
Andy Bitz
66954e84fe Publish
- @now/bash@0.3.0
 - @now/build-utils@0.7.3
 - @now/node@0.11.0
 - @now/ruby@0.1.1
2019-07-01 13:10:01 +02:00
Andy
15a21bb28c [now-bash] Add import config prop (#681)
* [now-bash] Add imports config prop

* Fixed type

* Rename to import
2019-07-01 13:08:18 +02:00
Nathan Rajlich
96ca1e1d8c [now-node] Watch consumed assets when running in now dev (#612)
Watch assets that `ncc` reports as part of the compiled bundle.

For example, "pug" template files:

```js
app.set("views", path.join(__dirname, "../../", "/views/"));
```
2019-07-01 13:07:47 +02:00
Luc
587cb52191 [now-node] Add support for server instance exports (#657)
* check for listen method on export

* revert setting helpers on __proto__

* fix launcher

* add missing semicolon

* fix missing bridge parameter

* add server test fixture

* move express test fixtures to servers

* add missing entrypoints in fixtures

* temporary fix before we update node-bridge

* refactor express test fixture

* add fixtures for hapi, fastify, koa

* fix now.json in servers fixtures

* remove fastify as it is not yet supported

* remove fs-extra as a dependency
2019-07-01 13:07:38 +02:00
Luc
95422ffd46 [now-node] Make helpers 100% match expressjs API (#678)
* remove Stream support

* text/plain -> text/html

* add etags

* bring test suite from expressjs

* add TODO comment

* remove body for 204 and 304

* do not send body when req.method is HEAD

* fix tests

* lazy load etag

* add type safeguards

* avoid type casting
2019-07-01 13:07:33 +02:00
Steven
391a883799 [docs] Add codeowners for ruby (#676) 2019-07-01 13:07:26 +02:00
Steven
43d6960df4 [now-ruby] Move typescript to devDependency (#675) 2019-07-01 13:07:06 +02:00
Andy Bitz
5c128003d8 Publish
- @now/build-utils@0.7.2
 - @now/static-build@0.6.2
2019-06-30 00:30:37 +02:00
Andy
2f8fd1b14b [now-static-build] Default to now-dev when zeroConfig is false (#679)
* [now-static-build] Default to `now-dev` when `zeroConfig` is false

* Adjust tests

* Fix build

* Return nowCmd

* Adjusted type

* Changed type

* Removed type

* Cast type

* [now-build-utils] Export config
2019-06-30 00:30:00 +02:00
Andy Bitz
625553c146 Publish
- @now/build-utils@0.7.1
2019-06-29 23:12:38 +02:00
Andy
3b0ce7bad3 [now-builds-util] Add zeroConfig to config type (#680) 2019-06-29 23:11:41 +02:00
Andy Bitz
489ec1dfa5 Publish
- @now/go@0.5.3
 - @now/next@0.5.1
 - @now/node-bridge@1.2.2
 - @now/node-server@0.8.1
 - @now/node@0.10.1
 - @now/python@0.2.9
 - @now/static-build@0.6.1
2019-06-28 18:32:41 +02:00
Steven
d3f92d7143 [now-static-build] Add missing random to test (#674) 2019-06-28 18:28:38 +02:00
Andy
3072b044ef [now-static-build] Use build and dev command if there is no… (#673)
* [now-static-build] Use `build` and `dev` command if there is no `now-` version

* Fix default dev command

* Get correct command

* Added type

* Add getCommands and replace now-dev occurrences

* Linting

* Added test for build

* Adjusted test

* Adjusted message

* Adjusted tests
2019-06-28 18:28:30 +02:00
Steven
3b4968657f [now-static-build] Improve msg when missing script (#672)
* [now-static-build] Improve msg when missing script

* Add 07-nonzero-sh test fixture

* Use uppercase

* Print bash script name
2019-06-28 18:28:24 +02:00
Steven
cafae4c800 [now-static-build] Use typescript (#671)
* [now-static-build] Use typescript

* Add tsconfig and add missing types

* Move to /src folder

* Fix type error

* Remove accidental commit of tsconfig.json
2019-06-28 18:28:17 +02:00
Luc
64952d24f1 [now-node] Fix res.send() and res.json() helpers (#669)
* fix res.send/res.json discrepancies with express

* add tests and refactor

* throw error on res.json(undefined)

* re-add streams

* do not console.warn

* move hello to fixtures-helpers folder

* be more explicit about accepted types

* setDefaultCT -> setContentType

* improve error messages

* make `fixtures-helpers/hello` appear in the code

* refactor setContentType

* set correct `content-length` header

* use PassThrough stream to remove fixture

* remove `.only` in test
2019-06-28 18:28:10 +02:00
Luc
72758b6e0d [tests] Improve git diff in jest config and refactor (#663)
* improve git diff in jest config

* refactor jest.config.js

* try with empty testMatch

* Revert "try with empty testMatch"

This reverts commit ec69a03cc7953a8e6e2d7b2f3ba2bb08d2fcbfa5.

* Update jest.config.js

Co-Authored-By: Steven <steven@ceriously.com>

* trim branch name

* move trim up

* add empty files to test behaviour

* Remove empty files
2019-06-28 18:28:03 +02:00
JJ Kasper
4f80bc74d5 Update now-next for new dynamic syntax (#660) 2019-06-28 18:27:55 +02:00
Sophearak Tha
a6e62ed61c [now-go] Ignore vendor folder when looking for go.mod (#593)
* Ignore `vendor` folder when looking for `go.mod`

* add warning message

* Apply suggestions from code review

Co-Authored-By: Steven <steven@ceriously.com>
2019-06-28 18:27:46 +02:00
Luc
d8eecd6172 Revert "Only run github action on 'release' event (#662)" (#665)
This reverts commit 5ff2c37147eb203f5199ffe4d4aa9480e3ebaa85.
2019-06-28 18:27:37 +02:00
Luc
0e70608511 Only run github action on 'release' event (#662)
* only run github action on 'release' event

* only run master build on 'release' event
2019-06-28 18:27:25 +02:00
Luc
da0de150df add --exact to lerna version (#664) 2019-06-28 18:27:19 +02:00
Luc
a58c35fb9e [now-node-bridge] Use a callback on server.listen() method rather than server.on('listening') (#661)
* rely on the listen method rather than events

* add empty files to trigger tests suites

* improve types

* remove empty files
2019-06-28 18:27:11 +02:00
Nathan Cahill
fe88a69ab7 [now-python] Add Python ASGI support (#654)
* add python asgi support

* Update packages/now-python/test/fixtures/11-asgi/index.py

Co-Authored-By: Steven <steven@ceriously.com>

* Update packages/now-python/test/fixtures/11-asgi/now.json

Co-Authored-By: Steven <steven@ceriously.com>

* Update packages/now-python/test/fixtures/11-asgi/now.json

Co-Authored-By: Steven <steven@ceriously.com>

* add raw_path
2019-06-28 18:27:02 +02:00
Steven
9767682006 Publish
- @now/build-utils@0.7.0
 - @now/go@0.5.2
 - @now/next@0.5.0
 - @now/node-bridge@1.2.1
 - @now/node-server@0.8.0
 - @now/node@0.10.0
 - @now/optipng@0.6.3
 - @now/python@0.2.8
 - @now/ruby@0.1.0
 - @now/rust@0.2.7
 - @now/static-build@0.6.0
2019-06-24 17:02:17 -04:00
Steven
3285b31721 Revert "[now-node] Fix express not overriding helpers properties" (#659)
This reverts commit 7a7d8a55fbbe4f8ee89ce50a3c62816fc95f28f5.
2019-06-24 17:00:18 -04:00
Steven
70353c7fc0 [now-build-utils] Fail if engines is invalid (#658)
* [now-build-utils] Fail if engines does not match

* Add test to throw when invalid semver

* Apply suggestions from leo

Co-Authored-By: Leo Lamprecht <mindrun@icloud.com>

* Fix ts error

* Print range so its clear what to add to engines
2019-06-24 15:50:48 -04:00
Nathan Cahill
f85cf99325 support local pipfile (#652) 2019-06-24 15:50:37 -04:00
Luc
8b14a46d04 Add git diff to publishing steps in readme (#646)
* add `git diff canary` to publishing to stable

* Improve readme
2019-06-24 15:50:32 -04:00
Steven
383cbfd82f [now-build-utils] Remove enginesMatch export (#650)
* [now-build-utils] Remove `enginesMatch` export

* Remove unused import
2019-06-24 15:50:23 -04:00
Steven
81e268a3c9 Add support for node 10 in all builders (#649)
* Add support for node 10 in all builders

* Fix meta undefined
2019-06-24 15:50:16 -04:00
Steven
ac8b33213b [now-build-utils] Enhance node version selection (#648)
* [now-build-utils] Enhance node version selection

* Fix test
2019-06-24 15:50:10 -04:00
piousdeer
de12e7b8c8 [now-static-build] Use cross-spawn and npm for now dev (#639)
* [now-static-build] Use `cross-spawn` and npm

* [now-static-build] Add `cross-spawn` dependency
2019-06-24 15:50:04 -04:00
ywg-jean
b9346603f0 Proposes a contributing guideline (#644)
* proposes a contributing guideline

the guideline outlines the process to open a pull request on this
repository and offers guidance on interpreting test errors.

* Wording improvement

As per @styfle suggestion

Co-Authored-By: Steven <steven@ceriously.com>

* Reword reference to code of conduct

As per @styfle's suggestion.

Co-Authored-By: Steven <steven@ceriously.com>

* fix local developement section title

Co-Authored-By: Steven <steven@ceriously.com>

* Improves project description wording

Co-Authored-By: Steven <steven@ceriously.com>

* Proper setup instructions

The ones provided initially were incomplete (might explain why I had some issues :) )

Co-Authored-By: Steven <steven@ceriously.com>

* updates description of tests

Co-Authored-By: Steven <steven@ceriously.com>

* Improve explanation of integration tests

Co-Authored-By: Steven <steven@ceriously.com>

* Update ncc bug qualification section

Co-Authored-By: Steven <steven@ceriously.com>

* fixes typo

Co-Authored-By: Steven <steven@ceriously.com>

* clarifies when and why to run ncc manually

Co-Authored-By: Steven <steven@ceriously.com>

* clarifies how to access to test deployements and associated logs

Co-Authored-By: Steven <steven@ceriously.com>
2019-06-24 15:50:00 -04:00
Luc
0b793dfc35 [now-node] Fix express not overriding helpers properties (#638)
* add breaking test

* fix test

* fix tests (bis)

* be explicit about @ts-ignore

* be more specific in test name
2019-06-24 15:49:52 -04:00
Steven
9dd672c383 [now-node] Change PATH to use node10 (#637)
* [now-node] Change PATH to use node10

* Fallback to node8
2019-06-24 15:49:46 -04:00
Steven
1b743aeea8 [now-ruby] Fix ruby publish step (#642) 2019-06-24 15:49:41 -04:00
Steven
d4af4b9f5c Run prettier (#635) 2019-06-24 15:49:35 -04:00
Steven
b734ca3e01 [now-build-utils] Add spawnOpts param to runNpmInstall() (#634) 2019-06-24 15:49:27 -04:00
Luc
f81d753104 [now-go] Fix failing build when go.mod exists in a subfolder (#633)
* add test

* fix test

* fix 14-go-mod-sub test fixtures

* add index.go to make fixtures correct
2019-06-24 15:49:21 -04:00
Steven
db31b9a207 [tests] Bump typescript to 3.5.2 (#631) 2019-06-24 15:49:07 -04:00
Nathan Cahill
b80b5182e6 [now-ruby] Add @now/ruby Builder (#454)
* add @now/ruby

* changes from feedback

* remove mm

* increase timeout

Co-Authored-By: Steven <steven@ceriously.com>

* address changes

* fix linting errors

* support arrays in includeFiles

* undo type change
2019-06-24 15:48:56 -04:00
Steven
268a7c2b81 [now-node] Enable node10.x runtime (#630) 2019-06-24 15:48:48 -04:00
Sophearak Tha
667a16c996 [now-go] add support for nested packages (#623)
* add support for nested packages

* properly clone array
2019-06-24 15:48:20 -04:00
Steven
7b851f81c0 Publish
- @now/build-utils@0.6.0
2019-06-17 14:25:30 -04:00
Steven
80fbbcd194 [now-build-utils] Add enginesMatch export (#618)
* Add engineSatisifies for node

* Rename to enginesMatch

* Add test for node10

* Minor refactor

* Add tests for engines, uses semver.intersect()

* Revert @now/node, new PR later
2019-06-17 14:22:22 -04:00
luc
3108332043 Publish
- @now/build-utils@0.5.8
 - @now/md@0.5.4
 - @now/next@0.4.2
 - @now/node-bridge@1.2.0
 - @now/node-server@0.7.5
 - @now/node@0.9.0
 - @now/python@0.2.7
 - @now/static-build@0.5.9
2019-06-17 18:19:38 +02:00
Steven
7509c82c32 [tests] Fix yarn.lock (#628) 2019-06-17 16:40:33 +02:00
Steven
c4f5a5b48d [now-node] Remove layers (#617) 2019-06-17 16:05:31 +02:00
Luc
05314da810 [now-node] Fix faulty behavior when request's body is empty and content-type is application/json (#615)
* add test for empty body and `application/json`

* fix test
2019-06-17 16:01:16 +02:00
Steven
5f1cf714c1 [tests] Run against all commits in the branch (#611) 2019-06-17 16:01:09 +02:00
Steven
2623e2e799 [now-node] Bump layer versions (#610) 2019-06-17 16:01:00 +02:00
Steven
bac1da09d4 [now-build-utils] Add types for Layers (#604)
* [now-build-utils] Add PrepareLayersOptions

* [now-build-utils] Add types for layers

* Add layer types to lambda

* Add any values to a layer function

* Change props to optional

* Update layers per call

* Add missing getFiles function

* Fix types

* Improve error message

* Change createLambda() api

* Remove node-gyp hack

* [now-layer-node] Add bootstrap

* Add fallback to empty object

* Add config.useLayers

* Remove config, change to layers check

* Fix typo

* Add deprecation message
2019-06-17 16:00:47 +02:00
Luc
5b57f1a3ac [now-node] Improve @now/node helpers (#609)
* lazy load everything 

* do not read charset in content-type to set encoding

* add tests

* add tests for express compat

* add test for `res.status().send()`

* update after PR comments
2019-06-17 16:00:39 +02:00
Nathan Rajlich
2e95dd5329 [now-md] Fix shouldServe() logic (#608)
* [now-md] Fix `shouldServe()` logic

Since this builder is not a 1-1 mapping of the input -> output names,
the default `shouldServe()` function needs to be augmented such that
the `.html` requestPath is "considered like" a `.md` file.

* Remove "ends with .html" optimization

It breaks index files, i.e. `GET /`
2019-06-17 16:00:30 +02:00
Joe Haddad
215f6367d6 [now-next] Humanize message about now-build (#607)
Some users read this message as a warning that required action (the captain caps lock WARNING didn't help).

Users should never need to define a `now-build` script unless they grow out of running `next build`.
2019-06-17 16:00:24 +02:00
Joe Haddad
e8cd348a79 [now-next] Fix erroneous .next folder message (#606)
We now store the `.next/cache` folder so we need to check for the `static` folder to know if the user uploaded something they should've excluded.
2019-06-17 16:00:17 +02:00
Luc
168f373641 [now-node] Assign type for req.headers.cookie (#603) 2019-06-17 16:00:00 +02:00
Luc
8c3174be29 [now-node] Move @types/node to dependencies (#602)
* move @types/node to dependencies

* fix types
2019-06-17 15:59:44 +02:00
Luc
898de78b63 [now-node] Make helpers opt-out instead of opt-in (#601)
* set helpers to true by default

* update tests
2019-06-17 15:58:00 +02:00
Luc
26e33c1c4b Pin now-node-bridge dependencies in now-next and now-node-server (#600)
* pin dependencies in now-next

* pin dependencies in now-node-server

* regenerate yarn.lock
2019-06-17 15:57:33 +02:00
Luc
c2f95de3ec [now-node] Helpers compatibility with express, micro, etc (#594)
* copy bridge into now-node

* pass body buffer to listener

* only send addon when helpers are added

* ship bridge.js to deployment

* remove raw-body deps

* fix not waiting for server `listening` event

* add test for express compat

* add test for micro compat

* update now-node-bridge

* remove unnecessary yarn.lock

* fix wrong replacement in launcher.ts

* fix listener not defined

* fix unit tests

* add "test" for exports

* add console.log

* add test in node-bridge

* log error before throwing

* revert now-node-bridge to canary state

* remove unused code

* refactor consumeProxyRequests -> consumeEvent

* remove ts-jest

* update tests

* do not transform body to string if not necessary

* fix tests

* remove jest from deps in now-node

* x-bridge-reqid -> x-now-bridge-request-id

* add test for consumeEvent

* do not expose request id header to the client

* pin node-bridge version

* update node-bridge deps to 1.2.0-canary.1

* update yarn.lock

* add await for user's listener

* refactor

* pass async function to `Server`
2019-06-17 15:56:09 +02:00
Luc
6a7de860db [now-node-bridge] Make normalized events consumable by server (#598)
* add `consumeProxyRequest` to bridge

* refactor

* fix tests

* Update packages/now-node-bridge/test/bridge.test.js

Co-Authored-By: Leo Lamprecht <mindrun@icloud.com>

* Update packages/now-node-bridge/src/bridge.ts

Co-Authored-By: Leo Lamprecht <mindrun@icloud.com>
2019-06-17 15:28:05 +02:00
Steven
acb8cadafe [now-static-build] Should fail build when distDir is empty (#597) 2019-06-17 15:27:58 +02:00
Kai Richard König
1a8df7080d [now-python] Do not append query string to path (#580)
* Do not append query string to path - fixes \#545

* Avoid creating multiple parsed urls

* Fix missing whitespace

* Fix handler

* Remove unused imports
2019-06-17 15:27:50 +02:00
JJ Kasper
5a92826eb0 [now-next] Update appending .html to exported routes (#592) 2019-06-17 15:27:24 +02:00
Steven
e083aa3750 Publish
- @now/node@0.8.1
2019-06-08 14:56:27 -04:00
Steven
941f675657 [now-node] Change helpers to opt-in (#591)
* [now-node] Change helpers to opt-in

* Fix tests

* Fix tests
2019-06-08 14:55:56 -04:00
Steven
6fad726abb Publish
- @now/build-utils@0.5.7
 - @now/node@0.8.0
2019-06-08 10:38:13 -04:00
Luc
dd22051d6b [now-node] Add tests for types exports (#590)
* helpers.test.js -> helpers.test.ts

* import NowRequest and NowResponse in test

* fix addHelpers return type

* add comments
2019-06-08 10:36:05 -04:00
Luc
7e86cb403f [now-node] Add Express-like API (#577)
* first iteration of express-like api for @now/node

* fix error when config is undefined

* add integration test for helpers

* add `res.status()` to helpers integration test

* fix error caused by config values being strings

* add helpers opt-out integration test

* add `helpers.js` to deployed files

* add boolean and number to config values types

* update config.helpers to work with boolean

* add unit tests

* fix type error in config type

* add unit test for req.body

* ignore errors not generated in helpers

* Update packages/now-node/test/fixtures/15-helpers/no-helpers/index.js

Co-Authored-By: Steven <steven@ceriously.com>

* update config type

* use ternary instead of filtering with `Boolean`

* add probe in 15-helpers

* add probe for ts function

* ncc `helpers.js`

* fix Config type

* fix @now/rust type issue

* add comment in build.sh

* test that content-type header is correctly added

* add missing tsconfig.json in fixtures

* add `body` to fix `Invalid JSON` errors

* Revert "add `body` to fix `Invalid JSON` errors"

This reverts commit 9b2ff55409501140f0d7411d121fc3a4dfd34ccc.

* make `helpers` false by default

* add method POST to probe for helpers

* Revert "make `helpers` false by default"

This reverts commit d029a432a0bf2463e1613e6cfd76929ce6e45073.

* replace POST requests by GET in probes

* remove unnecessary comments

* destructure in parseQuery

* keep @now/rust unchanged

* Request -> NowRequest and Response -> NowResponse

* improve config types

* add NowListener type

* export NowRequest and NowResponse

* generate `.d.ts` files

* add types to helpers/ts fixtures

* Update packages/now-build-utils/src/types.ts

Co-Authored-By: Steven <steven@ceriously.com>

* Update packages/now-node/build.sh

Co-Authored-By: Steven <steven@ceriously.com>
2019-06-08 10:35:45 -04:00
Nathan Rajlich
d19d557738 [now-node] Add watch array for Builder v2 API (#582)
* [now-node] Add `watch` array

For `now dev`

* Use ncc-watcher from npm registry

* Update `yarn.lock`

* Fix integration tests

* Apply @styfle's suggestions

* Update `@zeit/ncc-watcher` to v1.0.3
2019-06-08 10:35:23 -04:00
Steven
e4281f698c Publish
- @now/rust@0.2.6
2019-06-07 12:56:50 -04:00
Steven
86ff681c6d Use prettier on .json files (#588) 2019-06-07 12:56:21 -04:00
Steven
ba97a7cf19 [now-rust] Move ts files into /src (#585) 2019-06-07 12:56:14 -04:00
Luc
0a94397700 [now-rust] config.includeFiles can be string[] (#584) 2019-06-07 12:56:04 -04:00
Luc
5c8e2f2ccc Fix content-type: application/json header being added even if body is undefined (#583) 2019-06-07 12:55:47 -04:00
Steven
35d56a34cb Publish
- @now/python@0.2.6
2019-06-06 17:19:25 -04:00
Steven
9dfd37e135 Update publish instructions in the README (#579)
* Update README.md

* Fix typo

* Add prettier to markdown files

* Fix table

* Another cherry pick
2019-06-06 16:58:57 -04:00
Steven
6f815f2645 Fix python (#581)
This change never made it to master
2019-06-06 16:58:28 -04:00
Steven
e186f89cfd Publish
- @now/build-utils@0.5.6
 - @now/go@0.5.1
 - @now/lambda@0.5.4
 - @now/layer-node@0.0.2
 - @now/layer-npm@0.0.2
 - @now/layer-yarn@0.0.2
 - @now/next@0.4.1
 - @now/node-bridge@1.1.4
 - @now/node-server@0.7.4
 - @now/node@0.7.4
 - @now/optipng@0.6.2
 - @now/php-bridge@0.5.3
 - @now/php@0.5.5
 - @now/python@0.2.5
 - @now/rust@0.2.5
 - @now/static-build@0.5.8
 - @now/wordpress@0.5.3
2019-06-06 15:15:47 -04:00
Steven
50cade8bba [now-layer] Add entrypoint to BuildLayerResult (#578)
* [now-layer] Add meta to BuildLayerResult

* Fix tests

* Fix test for expect entrypoint

* Return entrypoint

* Remove meta

* Remove meta

* Remove npmVerison meta check from layer-node
2019-06-06 15:13:06 -04:00
dependabot[bot]
13866e61f6 Bump js-yaml from 3.12.0 to 3.13.1 (#576)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.12.0 to 3.13.1.
- [Release notes](https://github.com/nodeca/js-yaml/releases)
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.12.0...3.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2019-06-06 17:49:33 +00:00
Joe Haddad
b72f902271 [now-next] Route 404 to custom Next.js error page (#569) 2019-06-06 17:49:28 +00:00
JJ Kasper
159cfe99dd Revert "Fix missing slash from prepending entryDirectory (#573)" (#575)
This reverts commit 36ac7605762639968a52d66a1bcb6d3cab68da3f.
2019-06-06 17:49:24 +00:00
JJ Kasper
1d9a96d104 Fix missing slash from prepending entryDirectory (#573)
* Fix missing slash for staticRoute

* Add util for prepending entryDirectory correctly

* Apply suggestions from code review

Co-Authored-By: Connor Davis <mail@connordav.is>

* Don't add export route for dynamic pages

* Fix type error from review commit

* Don't use scopeToEntry on lambdas
2019-06-06 17:49:20 +00:00
JJ Kasper
245f846d3e [now-next] Make sure .html is appended to dynamic auto exported routes (#572) 2019-06-06 17:49:14 +00:00
JJ Kasper
c5ef7f3f35 [now-next] Add generating of dynamic routes for auto exported pages (#570) 2019-06-06 17:49:10 +00:00
Steven
ccba15a5aa [now-next] Add timer to codeowners (#571) 2019-06-06 17:49:06 +00:00
dependabot[bot]
f49aefa8e4 Bump handlebars from 4.0.12 to 4.1.2 (#568)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.0.12 to 4.1.2.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.0.12...v4.1.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-06-06 17:48:57 +00:00
Sophearak Tha
d6b36df4ce [now-go] Fix subdirectory parse fail (#565) 2019-06-06 17:48:52 +00:00
JJ Kasper
3e4dd10a79 [now-next] Re-add generating of dynamic routes (#559)
* Re-add generating of dynamic routes

* Run prettier

* Update to use startsWith
2019-06-06 17:48:47 +00:00
Connor Davis
73956706bd Prettier everything (#563)
* Prettier everything

* md files should use spaces too

* Move prettier config to package.json

* Retry tests
2019-06-06 17:48:40 +00:00
Steven
bd8da5360d Add layers for npm and yarn (#558)
* Add `now-layer-npm`

* Change version to 0.0.1-canary.0

* Add now-layer-yarn

* Update version

* Add now-metadata.json

* Read package.json to detect npm version

* Fix tests for windows zip
2019-06-06 17:48:27 +00:00
Steven
6d5a2a4438 [now-layer-node] Add node runtime layer (#552)
* [now-node-runtime] Add node runtime layer

* Add now-node-runtime to eslintignore

* Add test

* Rename variables, add comment

* Remove createGunzip()

* Add .yarnrc

* Rename to `now-layer-node`

* Pin dependencies

* Remove npm and npx from the layer

* Ignore uncessary files for node installer

* Use single glob string
2019-06-06 17:48:18 +00:00
Timothy
c88dc78e33 Fix static-build local development docs link (#556) 2019-06-06 17:48:10 +00:00
Steven
63ac11e9f7 [now-python] Publish from dist directory (#550)
* [now-python] Publish from dist directory

* Fix path to `now_init.py`

* Add now-init.py to npm publish

* Fix typo
2019-06-06 17:48:02 +00:00
Steven
1840632729 [tests] Fix duplicate GH Actions (#551)
* [tests] Fix duplicate GH Actions

* Fix typo

* Use linear to avoid cancelled checks
2019-06-06 17:46:48 +00:00
Steven
00d8eb0f65 [now-python] Improve error message (#548)
* [now-python] Improve error message

* Check if BaseHTTPRequestHandler

* Add a test for uppercase Handler
2019-06-06 17:46:43 +00:00
Steven
3db58ac373 [now-python] Disable pip upgrade notice (#547) 2019-06-06 17:46:39 +00:00
Steven
92a1720eea [tests] Only publish to npm from master/canary branch (#546)
* Change circleci workflow to build-and-test

* Add branch filter

* Separate into two workflows

* Move both workflows into single file

* Rename to main.workflow
2019-06-06 17:46:34 +00:00
Sophearak Tha
9abbfbe3f3 [now-go] Add support for go.mod in different entrypoint directory (#540)
* Add support for `go.mod` in different `entrypoint` directory

* Add tests cover Go Modules

* Workaround solution to make `now dev` support `go.mod` in different folder than `entrypoint`

* Ensure to backup `go.mod` and `go.sum` only in isDev

* Update packages/now-go/index.ts

* Update packages/now-go/index.ts

* Update watcher to work for different local packages under the same `go.mod`

* Improve code readability
2019-06-06 17:46:30 +00:00
Joe Haddad
11ef8aa816 [now-next] Define Next.js generated routes (#536)
* Match static files before checking dynamic routes

* Add Next.js lambda matching

* Apply suggestions from code review

Co-Authored-By: Connor Davis <mail@connordav.is>

* Correct index logic

* Add builder support for handle filesystem

* Check html rewrites first
2019-06-06 17:46:24 +00:00
Mike Engel
3a122ea950 [now-rust] Install rust with rustup & convert now-rust to typescript (#533)
* fix: Don't try and install rust and openssl during development

* feat: Convert now-rust to typescript

* Fix some typescript errors

* feat: Fix types for now-rust

* fix: Fix typo in type name

* fix: Small cleanups and tweaks from the PR review

* fix: Increase test timeout duration

- Add built JS files from now-build-utils to the eslintignore file

* fix: Compile to dist directory and don't lint now-rust

* fix: Only ignore linting for now-rust's dist dir
2019-06-06 17:46:20 +00:00
Steven
737e50630a Enable tests for all (#544)
* Enable circleci tests for all

* Update readme to mention GH Actions

* Move variable to the top
2019-06-06 17:46:11 +00:00
Lukáš Huvar
fb27b7b9be Fix servless error page fixes#234 (#541) 2019-06-06 17:46:00 +00:00
Steven
d1a4aecd2f Use GitHub Actions for publishing to npm (#539)
* Use GitHub Actions for publishing to npm

* Move publish from CircleCI to GH Actions

* Add npm install

* Fix names

* Use yarn instead of npm

* Fix typo

* Remove publish from circleci

* Fix typo

* Add check for NPM_TOKEN

* Add tag filter

* Remove tag filter
2019-06-06 17:45:55 +00:00
Steven
5ef7014ed8 Update codeowners for python & rust (#538) 2019-06-06 17:45:43 +00:00
Sophearak Tha
0ff2c9950e Show error when using package main with go.mod #528 (#537) 2019-06-06 17:45:31 +00:00
Steven
ddcdcdf3e2 Merge branch 'canary' into master 2019-05-27 17:21:55 -04:00
Mike Engel
bfc99f19d2 [now-rust] Don't try and install rust and openssl during development (#532) 2019-05-27 16:32:09 -04:00
Steven
de2c08cfe8 Publish
- @now/build-utils@0.5.6-canary.0
2019-05-25 14:24:52 -04:00
Steven
9679f07124 [build-utils] add --unsafe-perm to npm install, so that postinstall runs (#530) 2019-05-25 14:24:01 -04:00
Steven
6ce24d6a4e Switch branch during publish (#529) 2019-05-24 17:28:29 -04:00
Steven
e3e029f5f6 Update README.md 2019-05-24 13:37:35 -04:00
Steven
89172a6e89 Publish
- @now/go@0.5.0
 - @now/next@0.4.0
 - @now/node-bridge@1.1.3
 - @now/node-server@0.7.3
 - @now/node@0.7.3
 - @now/python@0.2.4
 - @now/static-build@0.5.7
2019-05-24 12:29:57 -04:00
Steven
e8f1dbaa46 Empty commit to satisfy lerna 2019-05-24 12:27:37 -04:00
Sophearak Tha
16b5b6fdf3 Publish
- @now/python@0.2.4-canary.2
2019-05-24 20:59:19 +07:00
Sophearak Tha
3bab29ff76 Add custom path and proper check (#527)
* Add custom path and proper check

* Change route tests to use another name
2019-05-24 20:55:28 +07:00
Sophearak Tha
d675d2e668 Use unquote() for http handler (#525)
* Use unquote() for http handler

* Add tests for url params http handler
2019-05-24 20:27:44 +07:00
Joe Haddad
2dda88e676 Publish
- @now/next@0.3.4-canary.4
2019-05-23 15:32:28 -07:00
Joe Haddad
5a0090eb1f [now-next] Ensure route begins with a slash (#524)
* Ensure route begins with a slash

* Simplift

* Apply suggestions from code review

Co-Authored-By: Connor Davis <mail@connordav.is>

* Adjust spacing
2019-05-23 15:31:13 -07:00
Sophearak Tha
d438b4ec4e Publish
- @now/go@0.4.8-canary.1
 - @now/python@0.2.4-canary.1
2019-05-23 20:34:53 +07:00
Sophearak Tha
f8810fd7e6 [now-python] Make sure to pass decode url params (#496)
* Make sure to pass decode url params

* Add tests cover default and custom routes behaviour on url param

* Removed `unquote` since `urlparse` already return expected value

* Using unquote in both PATH_INFO and QUERY_STRING

* Better code structure now_init.py

* Better test
2019-05-23 09:27:44 -04:00
Sophearak Tha
a642cfea96 [now-go] Add option to use private Git for go get (#513)
* Add option to use private Git

* Update packages/now-go/index.ts

Co-Authored-By: Steven <steven@ceriously.com>

* Fix import error

* Using `GIT_CREDENTIALS` over multiple env vars

* Ignore initialize Git credentials in `meta.isDev`
2019-05-23 11:39:36 +07:00
Joe Haddad
2daa20a9f2 Publish
- @now/next@0.3.4-canary.3
2019-05-22 18:36:15 -07:00
JJ Kasper
4d5c0c40f0 [now-next] Update to use routes for static pages (#521) 2019-05-22 20:25:10 -05:00
Joe Haddad
29051681df Publish
- @now/next@0.3.4-canary.2
2019-05-22 16:18:59 -07:00
JJ Kasper
96d5e81538 [now-next] Handle statically exported pages (#520)
* Add support for auto exported pages

* Add entryDirectory to staticPages mapping

* Map to FsFileRef instead of path
2019-05-22 16:14:24 -07:00
Steven
9ba9dd6949 Publish
- @now/go@0.4.8-canary.0
 - @now/next@0.3.4-canary.1
 - @now/node-bridge@1.1.3-canary.0
 - @now/node-server@0.7.3-canary.0
 - @now/node@0.7.3-canary.0
 - @now/python@0.2.4-canary.0
2019-05-22 15:11:27 -04:00
Steven
b362d57270 [now-node-bridge] Disable callbackWaitsForEmptyEventLoop (#505)
* [now-node] Disable callbackWaitsForEmptyEventLoop

* Fix unit tests
2019-05-22 15:06:02 -04:00
Nathan Rajlich
4ff95e1718 Publish
- @now/go@0.4.7
 - @now/python@0.2.3
2019-05-20 12:40:51 -07:00
Sophearak Tha
ef02bedd4d Publish
- @now/python@0.2.3-canary.0
2019-05-20 23:54:04 +07:00
Sophearak Tha
ed68a09c3e Make sure cwd user clean by using cwd/.now (#516) 2019-05-20 23:53:03 +07:00
Leo Lamprecht
ac7ae5fc5d Run only tests for packages that changed (#515) 2019-05-20 18:10:42 +02:00
Sophearak Tha
9727b1f020 Publish
- @now/go@0.4.7-canary.1
2019-05-20 21:30:41 +07:00
Sophearak Tha
2dc454f15f [now-go] Give user descriptive error message when Go Modules not available (#514)
* Give user descriptive error message when Go Modules not available

* Include go1.11 onward
2019-05-20 21:29:36 +07:00
Sophearak Tha
4463af5c7a Publish
- @now/go@0.4.7-canary.0
 - @now/next@0.3.4-canary.0
2019-05-20 18:56:19 +07:00
Sophearak Tha
c00fb37cf6 [now-go] Use meta in download() (#495)
* Use meta in `download()`

* better handling cwd

* Ignore .now in during parsing entrypoint

* Make re-built faster
2019-05-20 18:52:50 +07:00
Marcel Haupenthal
4deb426f9c [now-go] Ignore folders in analyze.go (#503)(#504) (#506)
* [now-go] Ignore folders in `analyze.go` (#503)(#504)

This commit adds some changes to the way the AST for the source is
built.

The `analyze.go` program now ignores every `vendor`, `.git` and
`testdata` folder. This improves performance, since `vendor` and `.git`
are usually large folders (#504).

By ignoring `testdata`, we mimick the behaviour of `go build` and avoid
failing the parsing because of invalid Go code inside of `testdata` (#503)

* [now-go] Don't ignore `.git` in analyze (#506)

If the user wants to ignore `.git`, he should put it into `.nowignore`
2019-05-17 13:02:20 +07:00
Nathan Rajlich
008b04413a Publish
- @now/next@0.3.3
2019-05-16 11:49:42 -07:00
Nathan Rajlich
f177ba46e9 Publish
- @now/next@0.3.3-canary.0
 - @now/static-build@0.5.7-canary.0
2019-05-16 10:46:18 -07:00
Nathan Rajlich
c030fce589 [now-next] Default NODE_ENV to "development" for dev server (#493) 2019-05-15 18:46:26 -07:00
Nathan Rajlich
50a5150bb5 Publish
- @now/static-build@0.5.6
2019-05-14 10:40:21 -07:00
Nathan Rajlich
0578ccf47e Publish
- @now/static-build@0.5.6-canary.1
2019-05-13 15:58:26 -07:00
Nathan Rajlich
e32cd36ded [now-static-build] Remove srcBase from the proxy pass destination (#499)
The `srcBase` (directory where the entrypoint is located) should not be
in the `dest` proxy pass URL.

Consider an entrypoint like `www/package.json`. The development server
will be running within the `www` directory. A request for `GET
/static/foo.js` comes in, so we want to proxy pass to
`http://localhost:12345/static/foo.js` rather than
`http://localhost:12345/www/static/foo.js` which would lead to a 404.
2019-05-13 15:58:01 -07:00
Nathan Rajlich
6ac0ab121c Publish
- @now/static-build@0.5.6-canary.0
2019-05-13 13:12:35 -07:00
Nathan Rajlich
05db2e6a73 [now-static-build] Add err.sh link when dev server detection fails (#498)
* [now-static-build] Add `err.sh` link when dev server detection fails

The error message alone doesn't explain how to fix it, so adding this
`err.sh` link to guide the user to instructions on how to fix it.

For example: https://github.com/zeit/now-cli/issues/2339

* Shorter title

* should -> must
2019-05-13 13:11:03 -07:00
Nathan Rajlich
0b89d30d6c Publish
- @now/build-utils@0.5.5
 - @now/cgi@0.1.4
 - @now/go@0.4.6
 - @now/mdx-deck@0.5.4
 - @now/next@0.3.2
 - @now/node-server@0.7.2
 - @now/node@0.7.2
 - @now/php@0.5.4
 - @now/python@0.2.2
 - @now/rust@0.2.4
2019-05-11 08:13:57 -07:00
Tim Neutkens
8a021c9417 [now-next] Add support for /api routes (#494) 2019-05-11 16:18:23 +02:00
Nathan Rajlich
f218771382 Publish
- @now/cgi@0.1.4-canary.0
 - @now/go@0.4.6-canary.0
 - @now/mdx-deck@0.5.4-canary.0
 - @now/node-server@0.7.2-canary.1
 - @now/node@0.7.2-canary.2
 - @now/php@0.5.4-canary.0
 - @now/python@0.2.2-canary.0
 - @now/rust@0.2.4-canary.1
2019-05-10 19:19:15 -07:00
Nathan Rajlich
17309291ed [now-node-server] Pass meta to download() function (#489) 2019-05-10 19:18:31 -07:00
Nathan Rajlich
86300577ae [now-rust] Pass meta to download() function 2019-05-10 17:14:22 -07:00
Nathan Rajlich
f9594e0d61 [now-python] Pass meta to download() function (#491) 2019-05-11 01:13:48 +02:00
Nathan Rajlich
20fd4b2e12 [now-php] Download files to workPath and pass meta (#490)
It's not clear to me why we were installing to `userfiles` directory,
so let me know if this breaks something.
2019-05-11 01:13:14 +02:00
Nathan Rajlich
718e4d0e0c [now-mdx-deck] Pass meta to download() function (#488) 2019-05-11 01:12:46 +02:00
Nathan Rajlich
dc3584cd08 [now-cgi] Download files to workPath and pass meta (#487) 2019-05-11 01:12:12 +02:00
Nathan Rajlich
b41788b241 Update yarn.lock 2019-05-10 13:17:05 -07:00
Nathan Rajlich
af9a2f9792 [now-node-server] Update @zeit/ncc to v0.18.5 2019-05-10 13:17:05 -07:00
Nathan Rajlich
f8b8e760de [now-node] Update @zeit/ncc to v0.18.5 2019-05-10 13:17:05 -07:00
Sophearak Tha
93d6ec8024 [now-go] Only use valid exported function with net/http interface (#477)
* Only use valid exported function with `net/http` interface

* Improve log, show link to docs if we coudn't parsed the entrypoint
2019-05-10 21:13:44 +07:00
Nathan Rajlich
7ed6b84056 Remove packages/now-rust/now-rust-0.2.3.tgz (#480)
It appears to have been accidentally committed in
bd2d05344e.
2019-05-08 14:50:57 -07:00
Nathan Rajlich
31da488365 Publish
- @now/build-utils@0.5.5-canary.1
 - @now/next@0.3.2-canary.1
 - @now/node@0.7.2-canary.1
2019-05-08 12:22:17 -07:00
Nathan Rajlich
8eaf05f782 Add initial CODEOWNERS file (#479)
* Add initial `CODEOWNERS` file

* Add `@now/go` to `CODEOWNERS` file
2019-05-08 12:07:32 -07:00
Nathan Rajlich
9311e90f27 [now-next] Fix failing unit test when isDev: true (#478) 2019-05-08 12:00:35 -07:00
Steven
c0de970de2 Add coverage to .gitignore (#473)
* Add coverage to `.gitignore`

* Add .tgz to `.gitignore`

* *.tgz
2019-05-07 17:57:09 -07:00
Nathan Rajlich
465ac2093d [now-node] Pass in the meta object to download() (#475)
Depends on https://github.com/zeit/now-builders/pull/474.
2019-05-07 17:56:39 -07:00
Nathan Rajlich
19ab0e8698 [now-build-utils] Make download() a no-op in now dev (#474)
This will be necessary for the update in `now dev` to have the builder
`workPath` be equal to the `cwd` source directory of the dev server.

Otherwise, unnecessary file modifications are made (copying the source
file to itself) and file corruption often occurs.
2019-05-07 17:56:16 -07:00
Steven
02fa98e5e3 Publish
- @now/build-utils@0.5.5-canary.0
 - @now/next@0.3.2-canary.0
 - @now/node-server@0.7.2-canary.0
 - @now/node@0.7.2-canary.0
 - @now/rust@0.2.4-canary.0
2019-05-07 17:08:55 -04:00
Steven
4aef9d48b0 [now-node] Bump ncc to 0.18.3 (#472) 2019-05-07 15:40:14 -04:00
Luis Fernando Alvarez D
bd2d05344e [now-next] Add public files to the output (#468) 2019-05-07 14:06:05 -05:00
Steven
edc7696623 Add newline to .gitignore 2019-05-07 09:28:59 -04:00
Steven
e2f91094bc Publish
- @now/bash@0.2.3
 - @now/build-utils@0.5.4
 - @now/cgi@0.1.3
 - @now/go@0.4.5
 - @now/html-minifier@1.1.3
 - @now/lambda@0.5.3
 - @now/md@0.5.3
 - @now/mdx-deck@0.5.3
 - @now/next@0.3.1
 - @now/node-bridge@1.1.2
 - @now/node-server@0.7.1
 - @now/node@0.7.1
 - @now/optipng@0.6.1
 - @now/php-bridge@0.5.2
 - @now/php@0.5.3
 - @now/python@0.2.1
 - @now/rust@0.2.3
 - @now/static-build@0.5.5
 - @now/wordpress@0.5.2
2019-05-07 07:09:50 -04:00
Steven
38dba57378 Bump stable version 2019-05-07 07:00:57 -04:00
Nathan Rajlich
be6a6ba1d7 Publish
- @now/build-utils@0.5.2-canary.2
 - @now/next@0.2.1-canary.1
2019-05-06 17:07:12 -07:00
Nathan Rajlich
31fb5d9ec8 [now-next] Sync runtime env vars in dev server after app.prepare() (#467)
* [now-next] Sync runtime env vars in dev server after `app.prepare()`

* Update packages/now-next/src/index.ts

Co-Authored-By: TooTallNate <n@n8.io>

* Update packages/now-next/src/index.ts

Co-Authored-By: TooTallNate <n@n8.io>

* Add `syncEnvVars()` helper function for common logic
2019-05-06 16:43:20 -07:00
Joe Haddad
6c8f946a48 [now-build-utils] Remove mutable option and add sha+ephemeral scheme (#466)
Co-Authored-By: Steven <steven@ceriously.com>

* Add an ephemeral option for files

* Use array destructuring

Co-Authored-By: Timer <joe.haddad@zeit.co>

* Remove mutable option

* Remove code all together

* Introduce `sha+ephemeral` handling

* http => https

* Elaborate more on the cloudfront url

* Update comment a bit more

* Add comment explaining other url
2019-05-06 19:12:39 -04:00
Steven
d59e1b9789 Publish
- @now/build-utils@0.5.2-canary.1
 - @now/go@0.4.3-canary.1
2019-05-06 08:47:35 -04:00
Steven
2852d3fbc3 [now-build-utils] Add yarn --ignore-engines during install (#463) 2019-05-05 22:57:37 -04:00
Sophearak Tha
d0292eb751 Improve go checking in user dev machine (#460) 2019-05-06 09:11:24 +07:00
Steven
17bbf69346 Publish
- @now/node-server@0.6.1-canary.2
 - @now/python@0.1.1-canary.2
2019-05-03 19:48:26 -04:00
Steven
4fb4229c90 Remove python/pip installer (#459)
* Remove python/pip installer

* Add back PYTHONUSERBASE env var
2019-05-03 19:46:47 -04:00
Steven
03b7586b50 [now-node-server] Fix unit tests 2019-05-03 14:09:45 -04:00
Mickaël Allonneau
a1427866ca [now-node-server] 'config.includeFiles' accepts a string (#442)
* 1st try (fails)

* 2nd try (fails)

* 3rd try (fails)

* 4th try (fail)
2019-05-03 13:54:33 -04:00
Nathan Rajlich
5f787b8146 Publish
- @now/bash@0.2.1-canary.0
 - @now/cgi@0.1.1-canary.0
 - @now/html-minifier@1.1.1-canary.0
 - @now/lambda@0.5.1-canary.0
 - @now/md@0.5.1-canary.0
 - @now/node-server@0.6.1-canary.1
 - @now/node@0.6.1-canary.2
 - @now/optipng@0.5.1-canary.0
 - @now/php@0.5.1-canary.0
 - @now/python@0.1.1-canary.1
 - @now/rust@0.2.1-canary.0
2019-05-02 15:21:06 -07:00
Nathan Rajlich
b03405a665 Add default shouldServe() to appropriate builders (#456)
This adds the default `shouldServe()` implementation to the following
builders:

 * `@now/bash`
 * `@now/cgi`
 * `@now/html-minifier`
 * `@now/lambda`
 * `@now/md`
 * `@now/node-server`
 * `@now/node`
 * `@now/optipng`
 * `@now/php`
 * `@now/python`
 * `@now/rust`

The default implementation may be used for these builders because
they map 1-1 with their entrypoint file -> output file/lambda.
2019-05-02 15:09:58 -07:00
Steven
4393dad15a Publish
- @now/node@0.6.1-canary.1
 - @now/static-build@0.5.3-canary.1
2019-05-02 16:07:38 -04:00
Marios Antonoudiou
b4d604b2e9 [now-static-build] Fix @now/static-build nested build (#452) 2019-05-02 15:15:40 -04:00
Mickaël Allonneau
5fb6e5c0ba [now-node] 'config.includeFiles' accepts a string (#441) 2019-05-02 14:26:35 -04:00
Steven
9d7dd3a713 Publish
- @now/python@0.1.1-canary.0
2019-05-02 11:32:59 -04:00
Steven
4f867b320d [now-python] Upgrade build env to python3.6 (#450)
* [now-python] Upgarde build env to python3.6

* Add support for isDev
2019-05-02 11:00:39 -04:00
Nathan Rajlich
c153690104 Publish
- @now/build-utils@0.5.2-canary.0
 - @now/go@0.4.3-canary.0
 - @now/next@0.2.1-canary.0
 - @now/static-build@0.5.3-canary.0
2019-05-01 23:34:18 -07:00
Nathan Rajlich
8c1b96edf7 [now-build-utils] Use cross-spawn for Windows support (#449) 2019-05-01 23:26:20 -07:00
Carlos Alexandro Becker
15c83a69f7 [now-go] Add support for config.includeFiles (#447) 2019-05-01 17:39:53 -04:00
Steven
0986de85ee [now-static-build] Warn when now-dev script is missing (#443)
* Warn when now-dev script is missing

* Add link to local dev docs

* Update packages/now-static-build/index.js

Co-Authored-By: styfle <steven@ceriously.com>

* Fix url
2019-05-01 17:32:50 -04:00
Leo Lamprecht
94c5d83ccc Copy the entire process environment to child (#448)
* Copy the entire process environment to child

* Removed lockfile

* Removed useless code

* Add comment
2019-05-01 22:26:35 +02:00
Steven
ff49b9d32d Publish
- @now/node-server@0.6.1-canary.0
 - @now/node@0.6.1-canary.0
2019-05-01 14:20:43 -04:00
Steven
ec5290dab1 [node-node] Bump ncc to 0.18.2 (#446) 2019-05-01 12:19:43 -04:00
Steven
4f758ec84e Create CODE_OF_CONDUCT.md (#444) 2019-05-01 09:04:34 -04:00
Steven
7951be156a Publish
- @now/build-utils@0.5.1
 - @now/go@0.4.2
 - @now/static-build@0.5.2
2019-04-30 10:33:52 -04:00
Nathan Rajlich
1bafc1d7b7 Publish
- @now/go@0.4.1
2019-04-29 18:03:38 -07:00
Sophearak Tha
1493101325 [now-go] Improve speed for now dev (#438)
* Improve speed for build() `@now/go` `now dev`

* Remove duplicate line

* Improve code flow

* Improve logging information

* no need to download Go if it available
2019-04-29 18:01:09 -07:00
Nathan Rajlich
824b044a96 Publish
- @now/static-build@0.5.1
2019-04-29 14:57:30 -07:00
Nathan Rajlich
0978be4c3d Publish
- @now/static-build@0.5.1-canary.0
2019-04-29 14:00:45 -07:00
Nathan Rajlich
dc832aa6c3 Regenerate yarn.lock file 2019-04-29 14:00:26 -07:00
Nathan Rajlich
8df77fe4fa [now-build-utils] Wait for the dev server to print the URL with correct port number (#439)
This is an alternative approach to detecting when the dev server is
ready to receive HTTP traffic, also bumps the timeout to 5 minutes.
2019-04-29 13:58:44 -07:00
Sophearak Tha
ff413b45fa Publish
- @now/go@0.4.1-canary.3
2019-04-29 16:46:58 +07:00
Sophearak Tha
e7befb5dc1 Make install @now/go faster (#435) 2019-04-29 16:46:08 +07:00
Steven
b898f82771 [now-go] Use optimized build flags (#428)
* Add optimized build output

* Add `config.ldsflags`
2019-04-29 09:41:50 +07:00
Leo Lamprecht
e6b22cb0df Publish
- @now/go@0.4.1-canary.2
2019-04-28 19:54:24 +00:00
Sophearak Tha
cbfe4a133d Using full path for checking against entrypoint (#433) 2019-04-29 00:44:31 +07:00
Sophearak Tha
823b78c626 Publish
- @now/go@0.4.1-canary.1
2019-04-28 21:22:30 +07:00
Sophearak Tha
03e1255043 Improve rebuild speed for now dev (#432) 2019-04-28 20:56:07 +07:00
Steven
3373cbca4e Publish
- @now/build-utils@0.5.1-canary.0
 - @now/go@0.4.1-canary.0
2019-04-25 17:11:31 -04:00
Sophearak Tha
4fba4b5f67 [now-go] Migrated to TypeScript and support Builder v2 API (#412)
* Migrated `@now/go` to TypeScript

* Add support for Builder v2 API

* Add now-go to .eslintignore

* Update go bin path

* Update packages/now-go/.gitignore

Co-Authored-By: sophearak <t.sophearak@gmail.com>

* Update packages/now-go/go-helpers.ts

Co-Authored-By: sophearak <t.sophearak@gmail.com>

* Update packages/now-go/go-helpers.ts

Co-Authored-By: sophearak <t.sophearak@gmail.com>

* Using American English for consistency

Co-Authored-By: sophearak <t.sophearak@gmail.com>

* Rename analyse.go to analyze.go

* Update packages/now-go/go-helpers.ts

Co-Authored-By: sophearak <t.sophearak@gmail.com>

* Remove `mkdirp-promise` from now-go

* Ensure `watch` directory-aware given `entrypoint` in subdirectory

* Support export struct type declaration

* Improve log

* Add type to `analyzed`

* Update packages/now-go/index.ts

Co-Authored-By: sophearak <t.sophearak@gmail.com>

* Migrate test fixtures from `add/now-go-tests`
2019-04-25 17:07:56 -04:00
Steven
9fcf6da3c1 Add comment to fsPath about absolute path (#427) 2019-04-25 11:27:36 -04:00
Steven
d8a5da6a3e Publish
- @now/bash@0.2.0
 - @now/build-utils@0.5.0
 - @now/cgi@0.1.0
 - @now/go@0.4.0
 - @now/html-minifier@1.1.0
 - @now/lambda@0.5.0
 - @now/md@0.5.0
 - @now/mdx-deck@0.5.0
 - @now/next@0.2.0
 - @now/node-bridge@1.1.0
 - @now/node-server@0.6.0
 - @now/node@0.6.0
 - @now/optipng@0.5.0
 - @now/php-bridge@0.5.0
 - @now/php@0.5.0
 - @now/python@0.1.0
 - @now/rust@0.2.0
 - @now/static-build@0.5.0
 - @now/wordpress@0.5.0
2019-04-25 09:19:19 -04:00
Leo Lamprecht
48f7b72bb2 Added missing workPath type property (#426) 2019-04-25 15:05:41 +02:00
Nathan Rajlich
8e2d5de446 [now-static-build] Add now-dev package.json script (#418)
* [static-build] Add `now-dev` package.json script

This will cause `now dev` to run the `now-dev` script as defined in the
`package.json` file.

`now dev` sets the `$PORT` env variable for use in the `now-dev` script,
which is expected to launch a file watching server (for example `hugo
dev`) on the specified `$PORT`. `now dev` wait for this port to be bound
before returning the `build()` function with the generated assets.

The `watch` array is just "watch everything in the
`path.dirname(entrypoint)`" so any file changed within that directory
will trigger a "re-sync" of the source files that `now dev` is working
with, which the user spawned static build watcher should pick up on and
return the updated assets.

* Use `routes` instead of globbing the output dir

Proxy passing to the development server is a cleaner approach, since it
removes the race condition about the builder not having knowledge of
when a dev watcher server rebuilds, so it's not possible to know how
long to wait to return outputs upon another call to `build()`.

* Make `watch` be an array

Co-Authored-By: TooTallNate <n@n8.io>

* Fix `promise-timeout` require()

* Inherit from `process.env` for `yarn run`

Otherwise ENOENT happens because there is no `PATH` env var set

* Only validate dist dir in production builds

* Fix `routes` and `watch` output

* Remove dev logging, add better timeout error message

* Populate `routes` upon rebuild

* Pass `meta` to the `download()` function

* Revert version change in `package.json`

* Save devport sooner
2019-04-25 08:41:38 -04:00
Steven
2b3efb06be Revert "[now-node] Add initial Builder v2 API (#424)" (#425)
This reverts commit dc3f112d4f.
2019-04-24 22:16:37 -04:00
Connor Davis
13e57bf68f [now/next] Set env variable directly 2019-04-24 16:57:00 -05:00
Nathan Rajlich
dc3f112d4f [now-node] Add initial Builder v2 API (#424)
This is a less complete version of #400, since it's still a WIP.
2019-04-24 14:46:02 -07:00
Connor Davis
da1c423033 Publish
- @now/next@0.2.0-canary.45
2019-04-24 14:57:51 -05:00
Connor Davis
5e1d58f0e8 Set target env variable (#423) 2019-04-25 04:16:08 +09:00
Leo Lamprecht
8940f7fa33 Publish
- @now/next@0.2.0-canary.44
2019-04-24 17:24:39 +00:00
Leo Lamprecht
0aeecd81d3 Pass meta to download() of @now/next (#422) 2019-04-24 19:23:57 +02:00
Joe Haddad
bd4cb3d2a0 Publish
- @now/next@0.2.0-canary.43
2019-04-24 10:50:02 -04:00
Joe Haddad
b3d14f536d Increase heap size for Next.js builds (#419)
* Increase heap size for Next.js builds

* Save some memory for the system
2019-04-24 23:10:27 +09:00
Leo Lamprecht
445d4d84cb Publish
- @now/build-utils@0.4.41-canary.8
 - @now/next@0.2.0-canary.42
2019-04-24 11:06:31 +00:00
Leo Lamprecht
30d4ec8cbd Make download() dedupe (#416)
* Make `download()` dedupe

* Made it work

* Fixed unused var
2019-04-24 13:05:31 +02:00
Nathan Rajlich
51355c263c [now-build-utils] Allow build options for runPackageJsonScript() (#417)
To allow, for example, setting `env` variable.
2019-04-24 10:23:46 +08:00
Steven
ec6d695f24 Add builder v2 tests to @now/next (#415)
* Add builder v2 tests to @now/next

* Add builder v2 tests

* wip

* Return childProcesses for tests
2019-04-23 18:41:26 -04:00
Leo Lamprecht
da910dc097 Publish
- @now/next@0.2.0-canary.41
2019-04-23 19:33:38 +00:00
Leo Lamprecht
00cb55f953 Make @now/next dev work on macOS (#414)
* Make `@now/next` dev work on macOS

* Fixed resolving

* Correctly use cwd

* Removed useless code
2019-04-23 21:32:56 +02:00
Leo Lamprecht
54ee557187 Publish
- @now/next@0.2.0-canary.40
 - @now/node-server@0.5.4-canary.5
 - @now/node@0.5.4-canary.6
2019-04-23 12:01:05 +00:00
Leo Lamprecht
e9a49f658b Develop Next.js app inside workPath (#410)
* Develop Next.js app inside workPath

* Made file watching work

* Define routes the first time

* Added index handling

* Fixed indexing

* Fixed indexing again

* Removed useless code

* Start server in child process
2019-04-23 13:58:50 +02:00
Steven
f3484bc7c9 [now-node] Bump ncc to 0.18.1 (#411)
* [now-node] Bump ncc to 0.18.1

* Fix unit test
2019-04-22 18:20:53 -04:00
Leo Lamprecht
f76d200fd2 Renamed property that has changed its name (#409)
* Define that initial build is needed

* Removed useless code
2019-04-21 20:30:02 +02:00
Leo Lamprecht
24ba90bfeb Wait for Next.js dev server to run before continuing (#408)
* Wait for server better

* Fixed version
2019-04-21 18:48:21 +02:00
Olli Vanhoja
9f0fdada18 Log HTTP status just after fetch returns in deploymentPost() (#406) 2019-04-20 21:40:38 +03:00
Leo Lamprecht
a987c4b298 Publish
- @now/build-utils@0.4.41-canary.7
 - @now/next@0.2.0-canary.39
 - @now/optipng@0.4.9-canary.1
2019-04-20 00:17:07 +00:00
Leo Lamprecht
a746adda93 Only match absolute paths in Next.js builder (#405) 2019-04-20 02:16:20 +02:00
Mark
6a00f02137 @now/optipng using typescript (#397)
Migration `@now/optipng` to typescript

Co-Authored-By: MAPESO <markdrew53@gmail.com>
2019-04-19 19:08:25 -04:00
Leo Lamprecht
65558f8197 Publish
- @now/build-utils@0.4.41-canary.6
 - @now/next@0.2.0-canary.38
2019-04-19 21:58:05 +00:00
Leo Lamprecht
a8bf77091f Made now-next invoke next dev (#398)
* Made `now-next` invoke `next dev`

* Even cleaner

* Fixed some types

* Fixed dirs

* Start server if initial build

* Added remaining types

* Added missing type

* Made property optional

* Fixed types

* Expose that the Builder is continuous

* Added more details

* Removed useless code

* Made it work

* Removed useless crap

* Added new version

* Synced up

* Refined logging

* Fixed routes

* Correctly parse request paths

* Fixed routes

* Fixed GET parameter issues
2019-04-19 23:54:47 +02:00
Steven
ee179b9b52 Add fetchTokenWithRetry for bad json response (#403)
This is a quick fix for our token problem by attempting to retry the fetch.

> FetchError: invalid json response body at NOW_TOKEN_FACTORY_URL reason: Unexpected token A in JSON at position 0

The root cause is in the token factory because it throws `Confirmation incomplete` but that will be harder to track down and fix.
2019-04-19 12:59:22 -04:00
Nathan Rajlich
b480b07cce [now-build-utils] Add meta object type definition for build() (#399)
* [now-build-utils] Add `meta` object type definition for `build()`

* Add `meta.requestPath`
2019-04-18 19:30:01 -07:00
Steven
fc8452abfd Publish
- @now/next@0.2.0-canary.1
 - @now/node-server@0.5.4-canary.4
 - @now/node@0.5.4-canary.5
2019-04-18 09:12:32 -04:00
Steven
48b6d0ebfc [now-node] Enable source maps so errors show proper stack trace (#391)
This will increase the lambda size a little bit but it will make for a much better user experience when debugging uncaught errors.

I also added a test so we don't regress.
2019-04-17 17:53:49 -04:00
Connor Davis
a3d6cea3c6 Migrate @now/next to Builders v2 + TS (#379) 2019-04-16 17:24:26 -05:00
Steven
8a61b1b513 Publish
- @now/build-utils@0.4.41-canary.5
 - @now/next@0.1.3-canary.15
 - @now/node@0.5.4-canary.4
2019-04-16 10:53:49 -04:00
Sophearak Tha
50e648d28a [@now/node] Make sure includeFiles have proper path inside lambda (#387)
Fixes #381 

Demo(public): https://now-node-fs.sophearak.now.sh/
2019-04-16 09:41:04 -04:00
Amio
52994bfe26 [build-utils] add default shouldServe and type ShouldServeOptions (#382)
Added the `ShouldServeParam` type declaration and default implementation for `shouldServe` for builder maker to import.
2019-04-16 19:51:51 +08:00
Connor Davis
1339f17585 Update index.js 2019-04-16 03:30:33 -05:00
Nathan Rajlich
9dd12cf1a7 Publish
- @now/build-utils@0.4.41-canary.4
2019-04-15 18:18:37 -07:00
Nathan Rajlich
6dab09f38e [now-build-utils] Create zip files with symlinks properly (#388)
After #359, creating zip files with symlinks would be corrupted because
the "target" of the symlink was actually the file contents.

This commit fixes the zip file construction logic to handle symlinks by
placing the target of the symlink as the "contents" of the file in the
zip. The unit test relies on GNU `unzip` and checks that it creates the
symlink from the produced zip file as expected.
2019-04-15 12:32:28 -07:00
Amio
c79d7be591 Mute stdio for runNpmInstall by default (#338)
Output logs if error occurs
2019-04-16 00:13:51 +08:00
Joe Haddad
9af3425d6d Publish
- @now/build-utils@0.4.41-canary.3
 - @now/next@0.1.3-canary.14
 - @now/node-bridge@1.0.2-canary.2
 - @now/node-server@0.5.4-canary.3
 - @now/node@0.5.4-canary.3
 - @now/php@0.4.17-canary.1
 - @now/python@0.1.0-canary.2
2019-04-15 08:31:34 +09:00
Igor Klopov
0700c16504 now/node: fix 07-content-length (#392) 2019-04-14 18:55:42 -04:00
Joe Haddad
4e55d9f709 Add a mutable flag to FileRef (#389)
* Add an immutable flag to FileRef

* `immutable` => `mutable`

* Add missing `assert` statement
2019-04-15 07:13:05 +09:00
Joe Haddad
945eb24bdc [now-next] Cache the new Next.js cache location (#386) 2019-04-11 16:10:45 -05:00
Connor Davis
c884102401 [now/next] cache everything in node_modules 2019-04-11 13:42:20 -05:00
Pete Nykänen
36e79efd7f Fix typo in Python builder (#383)
Simple typo fix
2019-04-11 11:29:20 -04:00
Steven
21ee0f3707 Publish
- @now/php@0.4.17-canary.0
2019-04-10 17:48:45 -04:00
Ties
ea5d3b8e80 [@now/php] Added includeFiles config (#326)
This is a retry of https://github.com/zeit/now-builders/pull/37, where the git history is a mess.
2019-04-10 17:44:18 -04:00
Connor Davis
301e0f216b Publish 2019-04-10 16:23:55 -05:00
Sophearak Tha
7a6fbd8c3d [now/python] Add django test (#378)
This PR added 08-django test.
2019-04-10 11:28:02 -04:00
Joe Haddad
77e7a0f502 [now-next] Cache Flying Shuttle directory (#380) 2019-04-09 22:53:41 -05:00
Nathan Rajlich
6bc42bbce9 Publish
- @now/build-utils@0.4.41-canary.2
2019-04-09 18:14:11 -07:00
Nathan Rajlich
de88969c46 [now-build-utils] Set the mode when creating the file, not afterwards (#375)
* [now-build-utils] Set the `mode` when creating the file, not afterwards

This is the more proper fix for #373.

* Use `parseInt()`

For some reason, `@types/node` allows string for `chmod()`
but not for `createWriteStream()`.

* Use a bitmask

See:

 - https://github.com/nodejs/node-v0.x-archive/issues/3045
 - https://www.martin-brennan.com/nodejs-file-permissions-fstat/
2019-04-09 11:17:23 -07:00
Igor Klopov
e86cd38787 Publish
- @now/node@0.5.4-canary.2
 - @now/node-server@0.5.4-canary.2
2019-04-09 20:41:20 +03:00
Igor Klopov
dc1badc931 [now-node] Move @zeit/ncc to npm dependencies (#370)
* now/node: move ncc to deps of package.json

* use require(ncc) instead of import (temporarily)

* do the same for now/node-server
2019-04-09 09:43:18 -07:00
Igor Klopov
ed3c176f5c Publish
- @now/node@0.5.4-canary.1
 - @now/node-server@0.5.4-canary.1
2019-04-09 18:09:37 +03:00
Igor Klopov
749ee5264c Publish
- @now/node-bridge@1.0.2-canary.1
2019-04-09 17:40:56 +03:00
Igor Klopov
9808ea1d8f Publish
- @now/build-utils@0.4.41-canary.1
2019-04-09 12:54:17 +03:00
Nathan Rajlich
a77e7109c7 [now-node-bridge] Exit the Node.js process upon unhandledRejection (#372)
If the `http.Server` handler function throws an error asynchronously,
then it ends up being an unhandled rejection which doesn't kill the node
process which causes the HTTP request to hang indefinitely. So print the
error here and force the process to exit so that the lambda invocation
returns an Unhandled error quickly.
2019-04-09 11:40:08 +03:00
Connor Davis
3b87c7ca83 Fix subscribe pattern 2019-04-08 21:43:28 -05:00
Connor Davis
1887df779a Handle static files in now dev (#369) 2019-04-08 21:41:34 -05:00
Steven
daccd0d8fc Publish
- @now/bash@0.1.5-canary.1
 - @now/build-utils@0.4.41-canary.0
 - @now/go@0.3.1-canary.3
 - @now/mdx-deck@0.4.19-canary.2
 - @now/next@0.1.3-canary.9
 - @now/node-bridge@1.0.2-canary.0
 - @now/node-server@0.5.4-canary.0
 - @now/node@0.5.4-canary.0
 - @now/python@0.1.0-canary.1
 - @now/rust@0.1.2-canary.2
 - @now/static-build@0.4.19-canary.2
2019-04-08 13:33:47 -04:00
Steven
fc9bbd2578 [now-static-build] fix link to docs (#368)
Fix link to documentation in static builder when the `dist` directory is not created.

I also changed the `build-utils` to use top-level imports like our docs specify.
2019-04-08 13:17:47 -04:00
Steven
f23f6ca643 Publish
- @now/python@0.1.0-canary.0
2019-04-08 09:30:06 -04:00
Sophearak Tha
c8d90fbcd1 [now/python] Update python tests (#367)
## What included?
- update python version to 3.6 in tests
- add `content-type` test
2019-04-08 08:45:51 -04:00
Nathan Rajlich
f4247da49a Publish
- @now/build-utils@0.4.40
2019-04-07 21:03:58 -07:00
Nathan Rajlich
9d781403ef [now-build-utils] Add support for symlinks to download() (#359)
* [now-build-utils] Add support for symlinks to `download()`

`now dev` is using this function to extract the `prepareCache()`
results, but upon extraction symlinks are lost and turned into
regular files, which breaks relative requires in Node.js modules.

This commit properly creates the symlinks from the files passed to
the `download()` function so that this problem no longer happens.

* Refactor `glob()` to return symlinks properly and add unit test

* Ensure the symlink target dir exists
2019-04-07 19:27:13 -07:00
Amio
ca188cf8e2 [now-built-utils] Add type declaration for glob (#360) 2019-04-07 19:17:06 -07:00
Connor Davis
207d895c0c Fix version check (#366) 2019-04-07 20:56:39 -05:00
Mike Engel
685821976d [now-rust] Make @now-rust's includeFiles match @now/node-server (#362)
This updates the `includeFiles` implementation to match how `now-node-server` does it, which is an array of globs rather than a single glob. To avoid making a new major version, this is done in a backwards compatible way to support existing projects using the current single glob API.

Added extra files to ensure that all would be included/processed even though the test just tests for one of them.

cc/ @styfle
2019-04-07 19:56:37 -04:00
Steven
fef5638cb9 [now-python] convert python builder to use typescript (#351)
* Add typescript to now-python

* Fix path

* Add gitignore

* Fix type errors

* Fix lint

* Move files back to root, add npmignore

* Final fixes
2019-04-07 11:13:02 -04:00
Nathan Rajlich
073ed247ad Update prepareCache() functions to use existing workPath (#356)
Considering that `prepareCache()` is executed directly after `build()`
is run, it seems that deleting the previous `workPath` and re-installing
the dependencies is just extra work, and it would be better to create
a cache from the `workPath` artifacts that `build()` just created.

From the perspective of `now dev`, this is ideal because:

 1. The `workPath` shouldn't be deleted since static file assets are
    served from the `workPath`, so `prepareCache()` deleting this
    directory is problematic.
 2. Creating the cache quickly becomes an important goal, because it
    reflects how quickly a developer can iterate on a file, and we don't
    want them waiting for `yarn` to finish installing dependencies all
    the time in order to see the change in their project.
2019-04-06 15:58:16 -07:00
Connor Davis
f071788ce6 [now/next] canary is updated 2019-04-05 18:18:11 -05:00
Igor Klopov
16f24bc3c8 [now-build-utils] decrease sema to fix deployments stuck at 'downloading' (#353)
[now-build-utils] decrease sema to fix deployments stuck at 'downloading'
2019-04-05 17:47:26 -04:00
Connor Davis
97fe3d489d [now-next] Strip Carat from version (#350)
* Strip Carat from version

* Get from next package.json

* Fix require

* Use resolveFrom

* Correctly fetch Next.js version

* Update index.js

* Update package.json
2019-04-05 02:12:27 -04:00
Joe Haddad
522d3a530c [now-next] Bump required version of Next.js (#352) 2019-04-05 01:49:19 -04:00
Steven
bafb49c464 Publish
- @now/python@0.0.42-canary.2
2019-04-04 15:21:34 -04:00
Sophearak Tha
7d5bd91e23 [@now/python] migrate @now/python-wsgi to @now/python` (#339)
* migrate `@now/python-wsgi to `@now/python`

* Refactor to use build-utils main

* Update install flag `--upgrade` in the right order.

Co-Authored-By: sophearak <t.sophearak@gmail.com>

* using `cwd` in instead in `execa`

* add 01-cowsay test with `pip` and `pipenv`

* add 01-wsgi test

* Fix typo

* Add test script for now-python

* Add now_init.py to support dynamic imports

* Remove redundant files, no more config.wsgi

* replace all occurrences __NOW_HANDLER_FILENAME

* update tests for `@now/python`
2019-04-04 10:08:20 -04:00
Connor Davis
213614881c Delete .next if it exists (#347) 2019-04-03 23:20:15 -05:00
Nathan Rajlich
a225a4f855 Publish
- @now/build-utils@0.4.39
2019-04-03 17:23:18 -07:00
Connor Davis
ed2fd1dd29 Merge branch 'master' of github.com:zeit/now-builders 2019-04-03 19:00:21 -05:00
Connor Davis
bd33528fc7 Publish 2019-04-03 19:00:02 -05:00
Connor Davis
16969803f8 @now/next hotfixes for now dev optimizations (#345) 2019-04-03 18:58:13 -05:00
Nathan Rajlich
03cc4c0b01 Publish
- @now/build-utils@0.4.39-canary.0
2019-04-03 16:00:21 -07:00
Nathan Rajlich
0b9699da75 [now-build-utils] Remove yarn/npm cache clean after install (#346)
`cache clean` was being invoked for legacy purposes back when we were
dealing with Lambda's 500mb runtime filesystem limit. Now that builds
are not running on lambda, this can be removed. It also makes `now dev`
building unnecessarily slow.
2019-04-03 15:55:39 -07:00
Connor Davis
6737011a63 Publish 2019-04-03 14:55:32 -05:00
Joe Haddad
6d2b0e014c Make @now/next compatible with now dev (#340) 2019-04-03 14:53:22 -05:00
Sigurd Spieckermann
409359bfec Python WSGI builder without server (#95)
This PR adds a builder for Python WSGI web apps. It is heavily based on [`serverless-wsgi`](https://github.com/logandk/serverless-wsgi) and [`requests-wsgi-adapter`](https://github.com/seanbrant/requests-wsgi-adapter), uses [`Werkzeug`](https://github.com/pallets/werkzeug), and works without running an additional web server.

I've tested it manually with a simple Flask app that contains endpoints with `GET` and `POST` methods, nested paths, and JSON and binary response bodies.

Curiously, the `event` parameter in the `now_handler` function does not appear to have the expected structure of AWS Lambda functions. For instance, `event['isBase64Encoded']` does not exist. Instead, this information is encoded in `json.loads(event['body'])['encoding']`. The returned `dict` also expects `encoding='base64'` for a binary response body instead of `isBase64Encoded=True`. I've also noticed that no AWS request headers are included. I assume Now is responsible for these differences to plain AWS Lambda functions.

I'd appreciate code review and feedback to get robust official Python WSGI support into Now as soon as possible.
2019-04-02 10:35:32 -04:00
Steven
2151812596 Publish
- @now/node@0.5.3
 - @now/node-server@0.5.3
2019-04-01 15:38:49 -04:00
Steven
22860be6d0 Publish
- @now/node@0.5.3-canary.1
- @now/node-server@0.5.3-canary.1
2019-04-01 15:27:36 -04:00
Steven
78c3cbd7b4 [now-node] Bump ncc to 0.17.3 (#337)
* [now-node] Bump ncc to 0.17.3
2019-04-01 15:22:31 -04:00
Nathan Rajlich
a458a55e99 Publish
- @now/build-utils@0.4.38
2019-04-01 07:39:09 -07:00
Sophearak Tha
911d85be39 [now-go] fix subdirectory build fail for @now/go (#309)
* fix subdirectory build fail for `@now/go`

* using sep over platform specific forward slash

* Update packages/now-go/index.js

Co-Authored-By: sophearak <t.sophearak@gmail.com>

* Update packages/now-go/index.js

Co-Authored-By: sophearak <t.sophearak@gmail.com>

* add 01-cowsay with subdirectory test case
2019-04-01 13:36:04 +07:00
Nathan Rajlich
98b5a4b0e9 Publish
- @now/node@0.5.2
 - @now/node-server@0.5.2
2019-03-31 15:01:28 -07:00
Nathan Rajlich
5f80e451b8 Update @now/node-bridge to v1.0.1 stable for @now/node and @now/node-server 2019-03-31 15:00:39 -07:00
Nathan Rajlich
0288f2d1a3 Publish
- @now/node-bridge@1.0.1
2019-03-31 14:47:13 -07:00
Sophearak Tha
e39a5eca04 Add Codecov report (#327)
* Add Codecov

* Using flag for coverage instead

* Revert "Using flag for coverage instead"

This reverts commit 9e14c8c8299267b2ff0431d822391e0538839ae7.

* Update codecov

* Add circle ci test coverage step

* try run jest without `node --expose-gc`

* Revert "try run jest without `node --expose-gc`"

This reverts commit 39fbd7995375ac62529d2d55519abc877b526071.

* run jest --coverage without `node --expose-gc`

* run jest with --runInBand flag

* Run tests and coverage at the same time
2019-03-29 09:11:14 -04:00
Steven
d4493f7d39 Fix rate limit for tests (#330)
This will generate a new token for every 10 API call so we stop getting rate limited.
2019-03-28 15:36:24 -04:00
Nathan Rajlich
145e5a10c2 [now-next] Set NODE_ENV to development in now dev (#325) 2019-03-26 12:52:50 -07:00
Nathan Rajlich
bd2d289252 [now-node] Set NODE_ENV to development in now dev (#324) 2019-03-26 12:52:26 -07:00
Nathan Rajlich
a673e5f752 [now-node-server] Set NODE_ENV to development in now dev (#323) 2019-03-26 12:52:04 -07:00
Nathan Rajlich
b2dc31a6b4 Revert "[now-node] Set NODE_ENV to development in now dev"
This reverts commit 62a308bed7.

Accidentally commited to `master` branch
2019-03-26 11:41:31 -07:00
Nathan Rajlich
62a308bed7 [now-node] Set NODE_ENV to development in now dev 2019-03-26 11:39:49 -07:00
Nathan Rajlich
ac08bfd26f [now-bash] Improvements for error handling (#318)
* Add shellcheck ignore comments to dynamic imports

* Add shebang to `runtime.sh`

So that vim applies proper syntax highlighting when bash-specific
features like `<<<` are used.

* Send error responses with `errorMessage` property

So that `now dev` can display the error message properly.
2019-03-26 10:51:59 -07:00
Mike Engel
d7f1371799 [now-rust] Allow extra static files on the lambda fs config.includeFiles (#300)
This add the ability to include other files into the filesystem of the lambda. This works by providing an `includeFiles` option in the builder config, and then moving those into the lambda when it's created. The `includeFiles` option is a glob matcher relative to the entrypoint.

**Note:** This is the first example I know of that allows a user to add more files to the filesystem through the official now builders. This API is something I came up with, and may not be the best or what y'all are thinking.

## Why?
This is helpful for my specific case, where I need extra binaries on the system when the lambda executes (`wget` and `now`). This could also be useful to include large files to parse, or other things one wouldn't want to include in the rust binary itself due to file size, memory allocation, whatever.

## Example
**Local file structure**
```
now_lambda/
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── static
    ├── now
    └── wget
```

**Now config**
```json
{
  "version": 2,
  "name": "now-lambda",
  "builds": [
    {
      "src": "Cargo.toml",
      "use": "@now/rust",
      "config": { "includeFiles": "static/*", "maxLambdaSize": "50mb" }
    }
  ]
}
```

**Lambda file structure**
```
/var/task/
├── bootstrap
└── static
    ├── now
    └── wget
```

## Testing
You can use `https://mike-now-rust-5shu849in.now.sh` as the builder's `"use"` key to test it out. It's a hosted tarball of this PR with a little extra debugging thrown in.
2019-03-26 11:19:25 -04:00
Nathan Rajlich
c97ad02aca [now-node] Enable TypeScript strict mode (#321) 2019-03-25 19:15:08 -07:00
Nathan Rajlich
c0460b734d Publish
- @now/node-server@0.5.2-canary.4
 - @now/node@0.5.2-canary.6
2019-03-25 19:03:21 -07:00
Steven
3b0ed55b57 [now-node] Bump ncc to 0.17.0 (#317)
* Bump ncc to 0.17.0

* Bump ncc to 0.17.0
2019-03-25 18:59:50 -07:00
Nathan Rajlich
402153f076 Publish
- @now/build-utils@0.4.38-canary.1
2019-03-25 18:22:30 -07:00
Nathan Rajlich
6ec823e292 [now-built-utils] Use constants for the type field (#320)
This is important for TypeScript usage with the combined `File` type
declaration. It helps the compiler understand the proper type in
consuming code via `if` checks to avoid casting.
2019-03-25 18:18:38 -07:00
Nathan Rajlich
a9af9ebb5a [now-build-utils] Pin "end-of-stream" dependency to v1.4.1 (#319)
All of the other deps are pinned versions, so this is for consistency.
2019-03-25 17:45:11 -07:00
Nathan Rajlich
ce88a64693 Publish
- @now/build-utils@0.4.38-canary.0
 - @now/python@0.0.42-canary.1
2019-03-22 17:31:09 -07:00
Nathan Rajlich
490cd8363e [now-python] Use workDir provided by builder (#294)
* [now-python] Use `workDir` provided by builder

Instead of generating another temp directory.

* [now-python] Add `--upgrade` flag to `pip install`

This is mainly for `now dev`.
2019-03-22 17:27:27 -07:00
Nathan Rajlich
71d1651797 Publish
- @now/build-utils@0.4.37
2019-03-22 15:56:18 -07:00
Nathan Rajlich
0da7197c3e Publish
- @now/build-utils@0.4.37-canary.3
 - @now/go@0.3.1-canary.2
 - @now/html-minifier@1.0.8-canary.1
 - @now/md@0.4.10-canary.2
 - @now/next@0.1.3-canary.2
 - @now/node-bridge@1.0.1-canary.1
 - @now/node-server@0.5.2-canary.3
 - @now/node@0.5.2-canary.5
 - @now/rust@0.1.2-canary.1
2019-03-22 14:44:44 -07:00
Nathan Rajlich
950a4e98e9 [now-node-server] Print a more helpful message when a module is missing (#313)
Similar to #312, but for `@now/node-server`.
2019-03-22 14:32:46 -07:00
Nathan Rajlich
8258ede23f [now-node] Print a more helpful message when a module is missing (#312) 2019-03-22 14:32:17 -07:00
Steven
77f84fe2aa Enhance TS declarations (#311)
This adds a few new exports to `@now/build-utils` with proper documentation 😄 

- AnalyzeOptions
- BuildOptions
- PrepareCacheOptions

I also updated TS is `now-node` and `now-node-bridge`.

### Screenshot

Here's an example of what the docs look like with TS Intellisense 📖 

![image](https://user-images.githubusercontent.com/229881/54851181-80825380-4cbf-11e9-9703-2ca75e8cdf47.png)
2019-03-22 17:31:43 -04:00
Igor Klopov
5c4b946864 Publish
- @now/build-utils@0.4.37-canary.2
2019-03-22 19:41:23 +03:00
Steven
dfc51ad97f Add tracing priority to tests (#310) 2019-03-22 10:09:45 -04:00
Steven
d32afc8332 [now-build-utils] Add typescript (#305)
* Add typescript to build utils

* Move file to file.ts

* Move to src directory

* Cast to readable

* Cast to stats

* Ignore js files

* Remove includes

* Run Linting after Building in CircleCI

* Move now-next tsconfig, add build script

* Fix default exports

* Attemp to fix default exports

* Change api to use index

* Add types to package.json

* Add missing fs

* Add shims

* Add missing end-of-stream dep

* Fix shims

* Ignore TS when linting

* Removed the unused top-level typescript
2019-03-21 18:23:05 -04:00
Sophearak Tha
9d1263ccc2 [now-go] better way to init go.mod (#304) 2019-03-21 09:33:24 +07:00
Matias Larsson
7bf2cfb3dc Remove collapseInlineTagWhitespace option (#281)
`collapseInlineTagWhitespace` removes white space between inline elements so `<p>Text with <a href="https://zeit.co/now">a link</a> is hard to read.</p>` renders as `Text witha linkis hard to read.`.

See example at https://runkit.com/5c8a1c7a0f950f0012252fbb/5c8a1c7a0f950f0012252fbc
2019-03-20 16:06:02 -04:00
Sophearak Tha
9b37460c4f [now-node] Add config.includeFiles (#277)
* add `includeFiles` support in `@now/node`

Co-Authored-By: sophearak <t.sophearak@gmail.com>
2019-03-20 14:07:06 -04:00
Sophearak Tha
b7f8b37ca6 [now-node-server] Add config.includeFiles (#302)
The main idea behind this is we want user be able to specific files in that should be include in the `handler` which later can be use in runtime.

For the most case, `ncc` be able to detect relevant files included in the `handler`. But the case that `ncc` not able to resolve, this option come in handy.

PR #277 does the same thing, but for `@now/node`.
2019-03-20 11:48:50 -04:00
Antonio Nuno Monteiro
13aa1b2d1c Publish now_lambda 0.1.3 (#287) 2019-03-20 10:56:12 -04:00
Nathan Rajlich
92437c075e [now-md] Remove console.log() call of Markdown file result (#303)
Not sure why this was here, but it's pretty noisey in the logs,
especially when executing this builder via `now dev`.
2019-03-20 09:09:16 -04:00
Steven
331c263587 Publish
- @now/bash@0.1.5-canary.0
 - @now/node-server@0.5.2-canary.2
 - @now/node@0.5.2-canary.4
 - @now/python@0.0.42-canary.0
2019-03-17 22:10:56 -04:00
Steven
7d4f6f636b [now-node] Bump ncc to 0.16.1 (#298)
[now-node] Bump `@zeit/ncc` to version 0.16.1 which includes fixes for webpack asset loader
2019-03-17 21:40:58 -04:00
Nathan Rajlich
5e90ef8e34 Publish
- @now/bash@0.1.4
 - @now/python@0.0.41
2019-03-17 17:01:43 -07:00
Nathan Rajlich
4885d680a7 Publish
- @now/next@0.1.3-canary.1
 - @now/python@0.0.41-canary.5
2019-03-17 13:58:36 -07:00
Nathan Rajlich
97cbe0b894 [now-python] Bind HTTP server to an ephemeral port (#296)
* [now-python] Bind HTTP server to an ephemeral port

Similar to #224, but for Python.

* Bind to port 0
2019-03-17 13:57:06 -07:00
Connor Davis
301eea90ee Add Terser Cache to Now Cache (#268)
* Add terser cache to Now cache

* Thought I removed this line

* Update to cache next dir

* Change to next-minifier
2019-03-17 14:28:51 -04:00
Nathan Rajlich
ea4f9dd930 Regenerate yarn.lock file 2019-03-16 21:00:31 -07:00
1053 changed files with 128478 additions and 8420 deletions

View File

@@ -20,23 +20,17 @@ jobs:
- run:
name: Bootstrapping
command: yarn bootstrap
- run:
name: Linting
command: yarn lint
- run:
name: Building
command: ./.circleci/build.sh
- run:
name: Tests
command: yarn test
name: Linting
command: yarn lint
- run:
name: Potentially save npm token
command: "([[ ! -z $NPM_TOKEN ]] && echo \"//registry.npmjs.org/:_authToken=$NPM_TOKEN\" >> ~/.npmrc) || echo \"Did not write npm token\""
- run:
name: Potentially publish releases to npm
command: ./.circleci/publish.sh
name: Tests and Coverage
command: yarn test-coverage
workflows:
version: 2
build-and-deploy:
build-and-test:
jobs:
- build

View File

@@ -1,6 +1,13 @@
#!/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
@@ -21,4 +28,7 @@ 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

43
.editorconfig Normal file
View File

@@ -0,0 +1,43 @@
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[{*.json,*.json.example,*.gyp,*.yml,*.yaml,*.workflow}]
indent_style = space
indent_size = 2
[{*.py,*.asm}]
indent_style = space
[*.py]
indent_size = 4
[*.asm]
indent_size = 8
[*.md]
trim_trailing_whitespace = false
indent_style = space
indent_size = 2
# Ideal settings - some plugins might support these
[*.js,*.jsx,*.ts,*.tsx]
quote_type = single
indent_style = space
indent_size = 2
[{*.c,*.cc,*.h,*.hh,*.cpp,*.hpp,*.m,*.mm,*.mpp,*.java,*.go,*.rs,*.php,*.ng,*.d,*.cs,*.swift}]
indent_style = tab
indent_size = 4
tab_width = 4
[{*.c,*.cc,*.h,*.hh,*.cpp,*.hpp,*.m,*.mm,*.mpp,*.js,*.java,*.go,*.rs,*.php,*.ng,*.jsx,*.ts,*.tsx,*.d,*.cs,*.swift}]
curly_bracket_next_line = false
spaces_around_operators = true
spaces_around_brackets = outside
# close enough to 1TB
indent_brace_style = K&R

View File

@@ -2,3 +2,17 @@
/node_modules/*
/**/node_modules/*
/packages/now-go/go/*
/packages/now-build-utils/dist/*
/packages/now-build-utils/src/*.js
/packages/now-build-utils/src/fs/*.js
/packages/now-node/dist/*
/packages/now-next/dist/*
/packages/now-node-bridge/*
/packages/now-python/dist/*
/packages/now-optipng/dist/*
/packages/now-go/*
/packages/now-rust/dist/*
/packages/now-ruby/dist/*
/packages/now-static-build/dist/*
/packages/now-static-build/test/fixtures/**
/packages/now-routing-utils/dist/*

View File

@@ -8,7 +8,7 @@
},
"overrides": [
{
"files": ["test/**"],
"files": ["**/test/**"],
"rules": {
"import/no-extraneous-dependencies": 0
},

14
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1,14 @@
# Documentation
# https://help.github.com/en/articles/about-code-owners
* @styfle
/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-rust @styfle @mike-engel @anmonteiro
/packages/now-ruby @styfle @coetry @nathancahill
/packages/now-static-build @styfle @AndyBitz
/packages/now-routing-utils @dav-is

76
.github/main.workflow vendored Normal file
View File

@@ -0,0 +1,76 @@
workflow "Canary publish" {
on = "push"
resolves = ["3. Canary yarn run publish"]
}
action "0. Canary filter" {
uses = "actions/bin/filter@3c0b4f0e63ea54ea5df2914b4fabf383368cd0da"
args = "branch canary"
}
action "0. Canary PR not deleted" {
uses = "actions/bin/filter@3c0b4f0e63ea54ea5df2914b4fabf383368cd0da"
needs = ["0. Canary filter"]
args = "not deleted"
}
action "1. Canary yarn install" {
uses = "actions/npm@59b64a598378f31e49cb76f27d6f3312b582f680"
needs = ["0. Canary PR not deleted"]
runs = "yarn"
args = "--pure-lockfile install"
}
action "2. Canary yarn run build" {
uses = "actions/npm@59b64a598378f31e49cb76f27d6f3312b582f680"
needs = ["1. Canary yarn install"]
runs = "yarn"
args = "--pure-lockfile run build"
}
action "3. Canary yarn run publish" {
uses = "actions/npm@59b64a598378f31e49cb76f27d6f3312b582f680"
needs = ["2. Canary yarn run build"]
runs = "yarn"
args = "--pure-lockfile run publish-from-github"
secrets = ["NPM_TOKEN"]
}
workflow "Master publish" {
on = "push"
resolves = ["3. Master yarn run publish"]
}
action "0. Master filter" {
uses = "actions/bin/filter@3c0b4f0e63ea54ea5df2914b4fabf383368cd0da"
args = "branch master"
}
action "0. Master PR not deleted" {
uses = "actions/bin/filter@3c0b4f0e63ea54ea5df2914b4fabf383368cd0da"
needs = ["0. Master filter"]
args = "not deleted"
}
action "1. Master yarn install" {
uses = "actions/npm@59b64a598378f31e49cb76f27d6f3312b582f680"
needs = ["0. Master PR not deleted"]
runs = "yarn"
args = "--pure-lockfile install"
}
action "2. Master yarn run build" {
uses = "actions/npm@59b64a598378f31e49cb76f27d6f3312b582f680"
needs = ["1. Master yarn install"]
runs = "yarn"
args = "--pure-lockfile run build"
}
action "3. Master yarn run publish" {
uses = "actions/npm@59b64a598378f31e49cb76f27d6f3312b582f680"
needs = ["2. Master yarn run build"]
runs = "yarn"
args = "--pure-lockfile run publish-from-github"
secrets = ["NPM_TOKEN"]
}

4
.gitignore vendored
View File

@@ -1,4 +1,6 @@
node_modules
tmp
target/
.next
.next
coverage
*.tgz

View File

@@ -1,3 +0,0 @@
{
"singleQuote": true
}

74
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,74 @@
## 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/

85
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,85 @@
# Contributing
When contributing to this repository, please first discuss the change you wish to make via issue 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-builders
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/ncc integration
Some of the builders use `@zeit/ncc` to bundle files before deployment. If you suspect an error with the bundling mechanism, you can run the `ncc` CLI with a couple modifications to the test.
For example if an error occurred in `now-node/test/fixtures/08-assets`
```
cd packages/now-node/test/fixtures/08-assets
yarn install
echo 'require("http").createServer(module.exports).listen(3000)' >> index.js
npx @zeit/ncc@0.20.1 build index.js --source-map
node dist
```
This will compile the test with the specific version of `ncc` and run the resulting file. If it fails here, then there is likely a bug in `ncc` and not the Builder.

View File

@@ -1,27 +1,61 @@
# now-builders
This is the full list of official Builders provided by the ZEIT team.
This is a monorepo containing the [Official Builders](https://zeit.co/docs/v2/deployments/builders/overview) provided by the ZEIT team.
More details here: https://zeit.co/docs/v2/deployments/builders/overview/
## Channels
There are two Channels:
| Channel | Git Branch | npm dist-tag | use example |
| ------- | ------------------------------------------------------------- | ------------ | ------------------ |
| Canary | [canary](https://github.com/zeit/now-builders/commits/canary) | `@canary` | `@now/node@canary` |
| Stable | [master](https://github.com/zeit/now-builders/commits/master) | `@latest` | `@now/node@latest` |
All PRs should be 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.
### Publishing to npm
Run the following command to publish modified builders to npm:
For the stable channel use:
```
yarn publish-stable
```
For the canary channel use:
For the Canary Channel, publish the modified Builders to npm with the following:
```
yarn publish-canary
```
CircleCI will take care of publishing the updated packages to npm from there.
For the Stable Channel, you must do the following:
If for some reason CircleCI fails to publish the npm package, you may do so
- Cherry pick each commit from canary to master
- 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
include the `--tag canary` parameter if you are publishing a canary release!
use `npm publish --tag canary` if you are publishing a canary release!
### Contributing
See the [Contribution guidelines for this project](CONTRIBUTING.md), it also contains guidance on interpreting tests failures.

View File

@@ -29,12 +29,11 @@ Serverless:
- 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:
1. Serverless Next.js requires Next.js 8 or later, to upgrade you can install the `latest` version:
```
npm install next --save
@@ -46,7 +45,7 @@ npm install next --save
{
"scripts": {
"now-build": "next build"
},
}
}
```
@@ -54,9 +53,9 @@ npm install next --save
```js
module.exports = {
target: 'serverless'
target: 'serverless',
// Other options are still valid
}
};
```
4. Optionally make sure the `"src"` in `"builds"` points to your application `package.json`
@@ -70,4 +69,4 @@ module.exports = {
### Useful Links
- [Serverless target implementation](https://github.com/zeit/now-builders/pull/150)
- [Serverless target implementation](https://github.com/zeit/now-builders/pull/150)

View File

@@ -20,7 +20,7 @@ npm install next --save
{
"scripts": {
"now-build": "next build"
},
}
}
```
@@ -28,9 +28,9 @@ npm install next --save
```js
module.exports = {
target: 'serverless'
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`

View File

@@ -0,0 +1,38 @@
# `@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,4 +1,38 @@
const { execSync } = require('child_process');
const { relative } = require('path');
const branch = execSync('git branch | grep "*" | cut -d " " -f2')
.toString()
.trim();
console.log(`Running tests on branch "${branch}"`);
const gitPath = branch === 'master' ? 'HEAD~1' : 'origin/canary...HEAD';
const diff = execSync(`git diff ${gitPath} --name-only`).toString();
const changed = diff
.split('\n')
.filter(item => Boolean(item) && item.includes('packages/'))
.map(item => relative('packages', item).split('/')[0]);
const matches = Array.from(new Set(changed));
if (matches.length === 0) {
matches.push('now-node');
console.log(`No packages changed, defaulting to ${matches[0]}`);
} else {
console.log('The following packages have changed:');
console.log(matches.join('\n'));
}
const testMatch = matches.map(
item => `**/${item}/**/?(*.)+(spec|test).[jt]s?(x)`,
);
module.exports = {
testEnvironment: 'node',
collectCoverageFrom: ['packages/**/*.{js,jsx}', '!**/node_modules/**'],
testMatch,
collectCoverageFrom: [
'packages/(!test)/**/*.{js,jsx}',
'!**/node_modules/**',
'!**/test/**',
],
};

View File

@@ -1,9 +1,7 @@
{
"npmClient": "yarn",
"useWorkspaces": true,
"packages": [
"packages/*"
],
"packages": ["packages/*"],
"command": {
"publish": {
"npmClient": "npm",

View File

@@ -12,10 +12,14 @@
"scripts": {
"lerna": "lerna",
"bootstrap": "lerna bootstrap",
"publish-stable": "lerna version",
"publish-canary": "lerna version prerelease --preid canary",
"lint": "tsc && eslint .",
"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": "./.circleci/build.sh",
"lint": "eslint .",
"codecov": "codecov",
"test": "jest --runInBand --verbose",
"test-coverage": "jest --runInBand --verbose --coverage --globals \"{\\\"coverage\\\":true}\" && codecov",
"lint-staged": "lint-staged"
},
"pre-commit": "lint-staged",
@@ -24,26 +28,39 @@
"prettier --write",
"eslint --fix",
"git add"
],
"*.ts": [
"prettier --write",
"git add"
],
"*.json": [
"prettier --write",
"git add"
],
"*.md": [
"prettier --write",
"git add"
]
},
"devDependencies": {
"@types/fs-extra": "^5.0.4",
"@types/glob": "^7.1.1",
"@types/multistream": "^2.1.1",
"@types/node": "^10.12.8",
"@types/node": "*",
"@zeit/ncc": "0.20.4",
"async-retry": "1.2.3",
"buffer-replace": "^1.0.0",
"eslint": "^5.9.0",
"eslint-config-airbnb-base": "^13.1.0",
"eslint-config-prettier": "^3.1.0",
"eslint-plugin-import": "^2.14.0",
"buffer-replace": "1.0.0",
"codecov": "3.2.0",
"eslint": "5.9.0",
"eslint-config-airbnb-base": "13.1.0",
"eslint-config-prettier": "3.3.0",
"eslint-plugin-import": "2.14.0",
"fs-extra": "^7.0.1",
"glob": "^7.1.3",
"jest": "^23.6.0",
"lint-staged": "^8.0.4",
"node-fetch": "^2.3.0",
"pre-commit": "^1.2.2",
"prettier": "^1.15.2",
"typescript": "^3.1.6"
"jest": "24.7.1",
"lint-staged": "8.1.0",
"node-fetch": "2.6.0",
"pre-commit": "1.2.2",
"prettier": "1.17.1"
},
"prettier": {
"singleQuote": true,
"trailingComma": "es5"
}
}

View File

@@ -7,7 +7,9 @@ export IMPORT_CACHE="$LAMBDA_TASK_ROOT/.import-cache"
export PATH="$IMPORT_CACHE/bin:$PATH"
# Load `import` and runtime
# shellcheck disable=SC1090
. "$(which import)"
# shellcheck disable=SC1090
. "$IMPORT_CACHE/runtime.sh"
# Load user code and process events in a loop forever

View File

@@ -11,12 +11,12 @@ curl -sfLS https://import.pw > "$IMPORT_BIN"
chmod +x "$IMPORT_BIN"
# For now only the entrypoint file is copied into the lambda
mkdir -p "$(dirname "$ENTRYPOINT")"
cp "$SRC/$ENTRYPOINT" "$ENTRYPOINT"
mkdir -p "$(dirname "$DIST/$ENTRYPOINT")"
cp "$ENTRYPOINT" "$DIST/$ENTRYPOINT"
# Copy in the runtime
cp "$BUILDER/runtime.sh" "$IMPORT_CACHE"
cp "$BUILDER/bootstrap" .
cp "$BUILDER/bootstrap" "$DIST"
# Load `import`
. "$(which import)"
@@ -24,7 +24,7 @@ cp "$BUILDER/bootstrap" .
# Cache runtime and user dependencies
echo "Caching imports in \"$ENTRYPOINT\"…"
. "$IMPORT_CACHE/runtime.sh"
. "$ENTRYPOINT"
. "$DIST/$ENTRYPOINT"
echo "Done caching imports"
# Run user build script

View File

@@ -1,35 +1,55 @@
const execa = require('execa');
const { join } = require('path');
const snakeCase = require('snake-case');
const glob = require('@now/build-utils/fs/glob'); // eslint-disable-line import/no-extraneous-dependencies
const download = require('@now/build-utils/fs/download'); // eslint-disable-line import/no-extraneous-dependencies
const { createLambda } = require('@now/build-utils/lambda'); // eslint-disable-line import/no-extraneous-dependencies
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory'); // eslint-disable-line import/no-extraneous-dependencies
const {
glob,
download,
createLambda,
shouldServe,
} = require('@now/build-utils'); // eslint-disable-line import/no-extraneous-dependencies
exports.config = {
maxLambdaSize: '10mb',
};
// From this list: https://import.pw/importpw/import/docs/config.md
const allowedConfigImports = new Set([
'CACHE',
'CURL_OPTS',
'DEBUG',
'RELOAD',
'SERVER',
]);
exports.analyze = ({ files, entrypoint }) => files[entrypoint].digest;
exports.build = async ({
workPath, files, entrypoint, config,
workPath, files, entrypoint, meta, config,
}) => {
const srcDir = await getWritableDirectory();
console.log('downloading files...');
await download(files, srcDir);
await download(files, workPath, meta);
const distPath = join(workPath, 'dist');
const configEnv = Object.keys(config).reduce((o, v) => {
o[`IMPORT_${snakeCase(v).toUpperCase()}`] = config[v]; // eslint-disable-line no-param-reassign
const name = snakeCase(v).toUpperCase();
if (allowedConfigImports.has(name)) {
o[`IMPORT_${name}`] = config[v]; // eslint-disable-line no-param-reassign
}
return o;
}, {});
const IMPORT_CACHE = `${workPath}/.import-cache`;
if (config && config.import) {
Object.keys(config.import).forEach((key) => {
const name = snakeCase(key).toUpperCase();
// eslint-disable-next-line no-param-reassign
configEnv[`IMPORT_${name}`] = config.import[key];
});
}
const IMPORT_CACHE = `${distPath}/.import-cache`;
const env = Object.assign({}, process.env, configEnv, {
PATH: `${IMPORT_CACHE}/bin:${process.env.PATH}`,
IMPORT_CACHE,
SRC: srcDir,
DIST: distPath,
BUILDER: __dirname,
ENTRYPOINT: entrypoint,
});
@@ -43,7 +63,7 @@ exports.build = async ({
});
const lambda = await createLambda({
files: await glob('**', workPath),
files: await glob('**', distPath),
handler: entrypoint, // not actually used in `bootstrap`
runtime: 'provided',
environment: Object.assign({}, configEnv, {
@@ -55,3 +75,5 @@ exports.build = async ({
[entrypoint]: lambda,
};
};
exports.shouldServe = shouldServe;

View File

@@ -1,10 +1,11 @@
{
"name": "@now/bash",
"version": "0.1.4-canary.0",
"version": "1.0.3",
"description": "Now 2.0 builder for HTTP endpoints written in Bash",
"main": "index.js",
"author": "Nathan Rajlich <nate@zeit.co>",
"license": "MIT",
"homepage": "https://zeit.co/docs/v2/deployments/official-builders/bash-now-bash",
"repository": {
"type": "git",
"url": "https://github.com/zeit/now-builders.git",
@@ -20,5 +21,8 @@
"dependencies": {
"execa": "^1.0.0",
"snake-case": "^2.1.0"
},
"scripts": {
"test": "jest"
}
}

View File

@@ -1,3 +1,4 @@
#!/bin/bash
import "static-binaries@1.0.0"
static_binaries jq
@@ -13,12 +14,14 @@ _lambda_runtime_api() {
_lambda_runtime_init() {
# Initialize user code
# shellcheck disable=SC1090
. "$SCRIPT_FILENAME" || {
local exit_code="$?"
local error
error='{"exitCode":'"$exit_code"'}'
local error_message="Initialization failed for '$SCRIPT_FILENAME' (exit code $exit_code)"
echo "$error_message" >&2
local error='{"errorMessage":"'"$error_message"'"}'
_lambda_runtime_api "init/error" -X POST -d "$error"
exit "$EXIT_CODE"
exit "$exit_code"
}
# Process events
@@ -45,9 +48,6 @@ _lambda_runtime_next() {
local body
body="$(mktemp)"
local exit_code=0
REQUEST="$event"
# Stdin of the `handler` function is the HTTP request body.
# Need to use a fifo here instead of bash <() because Lambda
# errors with "/dev/fd/63 not found" for some reason :/
@@ -56,6 +56,7 @@ _lambda_runtime_next() {
mkfifo "$stdin"
_lambda_runtime_body < "$event" > "$stdin" &
local exit_code=0
handler "$event" < "$stdin" > "$body" || exit_code="$?"
rm -f "$event" "$stdin"
@@ -69,8 +70,9 @@ _lambda_runtime_next() {
| _lambda_runtime_api "invocation/$request_id/response" -X POST -d @- > /dev/null
rm -f "$body" "$_HEADERS"
else
echo "\`handler\` function return code: $exit_code"
_lambda_runtime_api "invocation/$request_id/error" -X POST -d @- > /dev/null <<< '{"exitCode":'"$exit_code"'}'
local error_message="Invocation failed for 'handler' function in '$SCRIPT_FILENAME' (exit code $exit_code)"
echo "$error_message" >&2
_lambda_runtime_api "invocation/$request_id/error" -X POST -d '{"errorMessage":"'"$error_message"'"}' > /dev/null
fi
}
@@ -100,7 +102,10 @@ http_response_header() {
local value="$2"
local tmp
tmp="$(mktemp)"
jq --arg name "$name" --arg value "$value" '.[$name] = $value' < "$_HEADERS" > "$tmp"
jq \
--arg name "$name" \
--arg value "$value" \
'.[$name] = $value' < "$_HEADERS" > "$tmp"
mv -f "$tmp" "$_HEADERS"
}

View File

@@ -0,0 +1,3 @@
handler() {
echo "cow:RANDOMNESS_PLACEHOLDER"
}

View File

@@ -1,8 +1,8 @@
{
"version": 2,
"builds": [
{ "src": "index.md", "use": "@now/md" },
{ "src": "subdirectory/index.md", "use": "@now/md" }
{ "src": "index.sh", "use": "@now/bash" },
{ "src": "subdirectory/index.sh", "use": "@now/bash" }
],
"probes": [
{ "path": "/", "mustContain": "cow:RANDOMNESS_PLACEHOLDER" },

View File

@@ -0,0 +1,3 @@
handler() {
echo "yoda:RANDOMNESS_PLACEHOLDER"
}

View File

@@ -1,146 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
cross-spawn@^6.0.0:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
dependencies:
nice-try "^1.0.4"
path-key "^2.0.1"
semver "^5.5.0"
shebang-command "^1.2.0"
which "^1.2.9"
end-of-stream@^1.1.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==
dependencies:
once "^1.4.0"
execa@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
dependencies:
cross-spawn "^6.0.0"
get-stream "^4.0.0"
is-stream "^1.1.0"
npm-run-path "^2.0.0"
p-finally "^1.0.0"
signal-exit "^3.0.0"
strip-eof "^1.0.0"
get-stream@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
dependencies:
pump "^3.0.0"
is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
lower-case@^1.1.1:
version "1.1.4"
resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw=
nice-try@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
no-case@^2.2.0:
version "2.3.2"
resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==
dependencies:
lower-case "^1.1.1"
npm-run-path@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
dependencies:
path-key "^2.0.0"
once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies:
wrappy "1"
p-finally@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
path-key@^2.0.0, path-key@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
pump@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
dependencies:
end-of-stream "^1.1.0"
once "^1.3.1"
semver@^5.5.0:
version "5.6.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
dependencies:
shebang-regex "^1.0.0"
shebang-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
signal-exit@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
snake-case@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-2.1.0.tgz#41bdb1b73f30ec66a04d4e2cad1b76387d4d6d9f"
integrity sha1-Qb2xtz8w7GagTU4srRt2OH1NbZ8=
dependencies:
no-case "^2.2.0"
strip-eof@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
which@^1.2.9:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
dependencies:
isexe "^2.0.0"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=

3
packages/now-build-utils/.gitignore vendored Normal file
View File

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

View File

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

View File

@@ -0,0 +1,6 @@
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,33 +1 @@
const assert = require('assert');
const intoStream = require('into-stream');
class FileBlob {
constructor({ mode = 0o100644, data }) {
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 }) {
assert(typeof mode === 'number');
assert(typeof stream.pipe === 'function'); // is-stream
const chunks = [];
await new Promise((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() {
return intoStream(this.data);
}
}
module.exports = FileBlob;
module.exports = require('./dist/index').FileBlob;

View File

@@ -1,100 +1 @@
const assert = require('assert');
const fs = require('fs-extra');
const multiStream = require('multistream');
const path = require('path');
const Sema = require('async-sema');
/** @typedef {{[filePath: string]: FileFsRef}} FsFiles */
const semaToPreventEMFILE = new Sema(30);
/**
* @constructor
* @argument {Object} options
* @argument {number} [options.mode=0o100644]
* @argument {string} options.fsPath
*/
class FileFsRef {
constructor({ mode = 0o100644, fsPath }) {
assert(typeof mode === 'number');
assert(typeof fsPath === 'string');
/** @type {string} */
this.type = 'FileFsRef';
/** @type {number} */
this.mode = mode;
/** @type {string} */
this.fsPath = fsPath;
}
/**
* Creates a `FileFsRef` with the correct `mode` from the file system.
*
* @argument {Object} options
* @argument {string} options.fsPath
* @returns {Promise<FileFsRef>}
*/
static async fromFsPath({ fsPath }) {
const { mode } = await fs.lstat(fsPath);
return new FileFsRef({ mode, fsPath });
}
/**
* @argument {Object} options
* @argument {number} [options.mode=0o100644]
* @argument {NodeJS.ReadableStream} options.stream
* @argument {string} options.fsPath
* @returns {Promise<FileFsRef>}
*/
static async fromStream({ mode = 0o100644, stream, fsPath }) {
assert(typeof mode === 'number');
assert(typeof stream.pipe === 'function'); // is-stream
assert(typeof fsPath === 'string');
await fs.mkdirp(path.dirname(fsPath));
await new Promise((resolve, reject) => {
const dest = fs.createWriteStream(fsPath);
stream.pipe(dest);
stream.on('error', reject);
dest.on('finish', resolve);
dest.on('error', reject);
});
await fs.chmod(fsPath, mode.toString(8).slice(-3));
return new FileFsRef({ mode, fsPath });
}
/**
* @returns {Promise<NodeJS.ReadableStream>}
*/
async toStreamAsync() {
await semaToPreventEMFILE.acquire();
const release = () => semaToPreventEMFILE.release();
const stream = fs.createReadStream(this.fsPath);
stream.on('close', release);
stream.on('error', release);
return stream;
}
/**
* @returns {NodeJS.ReadableStream}
*/
toStream() {
let flag;
// 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);
});
});
}
}
module.exports = FileFsRef;
module.exports = require('./dist/index').FileFsRef;

View File

@@ -1,96 +1 @@
const assert = require('assert');
const fetch = require('node-fetch');
const multiStream = require('multistream');
const retry = require('async-retry');
const Sema = require('async-sema');
/** @typedef {{[filePath: string]: FileRef}} Files */
const semaToDownloadFromS3 = new Sema(10);
class BailableError extends Error {
constructor(...args) {
super(...args);
/** @type {boolean} */
this.bail = false;
}
}
/**
* @constructor
* @argument {Object} options
* @argument {number} [options.mode=0o100644]
* @argument {string} options.digest
*/
class FileRef {
constructor({ mode = 0o100644, digest }) {
assert(typeof mode === 'number');
assert(typeof digest === 'string');
/** @type {string} */
this.type = 'FileRef';
/** @type {number} */
this.mode = mode;
/** @type {string} */
this.digest = digest;
}
/**
* @returns {Promise<NodeJS.ReadableStream>}
*/
async toStreamAsync() {
let url;
// sha:24be087eef9fac01d61b30a725c1a10d7b45a256
const digestParts = this.digest.split(':');
if (digestParts[0] === 'sha') {
// url = `https://s3.amazonaws.com/now-files/${digestParts[1]}`;
url = `https://dmmcy0pwk6bqi.cloudfront.net/${digestParts[1]}`;
}
assert(url);
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();
}
}
/**
* @returns {NodeJS.ReadableStream}
*/
toStream() {
let flag;
// 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);
});
});
}
}
module.exports = FileRef;
module.exports = require('./dist/index').FileRef;

View File

@@ -1,38 +1 @@
const path = require('path');
const FileFsRef = require('../file-fs-ref.js');
/** @typedef {import('../file-ref')} FileRef */
/** @typedef {import('../file-fs-ref')} FileFsRef */
/** @typedef {{[filePath: string]: FileRef|FileFsRef}} Files */
/** @typedef {{[filePath: string]: FileFsRef}|{}} DownloadedFiles */
/**
* @param {FileRef|FileFsRef} file
* @param {string} fsPath
* @returns {Promise<FileFsRef>}
*/
async function downloadFile(file, fsPath) {
const { mode } = file;
const stream = file.toStream();
return FileFsRef.fromStream({ mode, stream, fsPath });
}
/**
* Download files to disk
* @argument {Files} files
* @argument {string} basePath
* @returns {Promise<DownloadedFiles>}
*/
module.exports = async function download(files, basePath) {
const files2 = {};
await Promise.all(
Object.keys(files).map(async (name) => {
const file = files[name];
const fsPath = path.join(basePath, name);
files2[name] = await downloadFile(file, fsPath);
}),
);
return files2;
};
module.exports = require('../dist/index').download;

View File

@@ -1,10 +1 @@
const { join } = require('path');
const { tmpdir } = require('os');
const { mkdirp } = require('fs-extra');
module.exports = async function getWritableDirectory() {
const name = Math.floor(Math.random() * 0x7fffffff).toString(16);
const directory = join(tmpdir(), name);
await mkdirp(directory);
return directory;
};
module.exports = require('../dist/index').getWriteableDirectory;

View File

@@ -1,67 +1 @@
const assert = require('assert');
const path = require('path');
const vanillaGlob = require('glob');
const FileFsRef = require('../file-fs-ref.js');
/** @typedef {import('fs').Stats} Stats */
/** @typedef {import('glob').IOptions} GlobOptions */
/** @typedef {import('../file-fs-ref').FsFiles|{}} GlobFiles */
/**
* @argument {string} pattern
* @argument {GlobOptions|string} opts
* @argument {string} [mountpoint]
* @returns {Promise<GlobFiles>}
*/
module.exports = function glob(pattern, opts = {}, mountpoint) {
return new Promise((resolve, reject) => {
/** @type {GlobOptions} */
let options;
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})`);
}
options.statCache = {};
options.stat = true;
options.dot = true;
// eslint-disable-next-line consistent-return
vanillaGlob(pattern, options, (error, files) => {
if (error) return reject(error);
resolve(
files.reduce((files2, relativePath) => {
const fsPath = path.join(options.cwd, relativePath);
/** @type {Stats|any} */
const stat = options.statCache[fsPath];
assert(
stat,
`statCache does not contain value for ${relativePath} (resolved to ${fsPath})`,
);
if (stat && stat.isFile()) {
let finalPath = relativePath;
if (mountpoint) finalPath = path.join(mountpoint, finalPath);
return {
...files2,
[finalPath]: new FileFsRef({ mode: stat.mode, fsPath }),
};
}
return files2;
}, {}),
);
});
});
};
module.exports = require('../dist/index').glob;

View File

@@ -1,25 +1 @@
/** @typedef { import('@now/build-utils/file-ref') } FileRef */
/** @typedef { import('@now/build-utils/file-fs-ref') } FileFsRef */
/** @typedef {{[filePath: string]: FileRef|FileFsRef}} Files */
/**
* @callback delegate
* @argument {string} name
* @returns {string}
*/
/**
* Rename files using delegate function
* @argument {Files} files
* @argument {delegate} delegate
* @returns {Files}
*/
module.exports = function rename(files, delegate) {
return Object.keys(files).reduce(
(newFiles, name) => ({
...newFiles,
[delegate(name)]: files[name],
}),
{},
);
};
module.exports = require('../dist/index').rename;

View File

@@ -1,119 +1 @@
const assert = require('assert');
const fs = require('fs-extra');
const path = require('path');
const { spawn } = require('child_process');
function spawnAsync(command, args, cwd, opts = {}) {
return new Promise((resolve, reject) => {
const child = spawn(command, args, { stdio: 'inherit', cwd, ...opts });
child.on('error', reject);
child.on('close', (code, signal) => (code !== 0
? reject(new Error(`Exited with ${code || signal}`))
: resolve()));
});
}
async function chmodPlusX(fsPath) {
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);
}
async function runShellScript(fsPath) {
assert(path.isAbsolute(fsPath));
const destPath = path.dirname(fsPath);
await chmodPlusX(fsPath);
await spawnAsync(`./${path.basename(fsPath)}`, [], destPath);
return true;
}
async function scanParentDirs(destPath, scriptName) {
assert(path.isAbsolute(destPath));
let hasScript = false;
let hasPackageLockJson = false;
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.exists(packageJsonPath)) {
// eslint-disable-next-line no-await-in-loop
const packageJson = JSON.parse(await fs.readFile(packageJsonPath));
hasScript = Boolean(
packageJson.scripts && scriptName && packageJson.scripts[scriptName],
);
// eslint-disable-next-line no-await-in-loop
hasPackageLockJson = await fs.exists(
path.join(currentDestPath, 'package-lock.json'),
);
break;
}
const newDestPath = path.dirname(currentDestPath);
if (currentDestPath === newDestPath) break;
currentDestPath = newDestPath;
}
return { hasScript, hasPackageLockJson };
}
async function installDependencies(destPath, args = []) {
assert(path.isAbsolute(destPath));
let commandArgs = args;
console.log(`installing to ${destPath}`);
const { hasPackageLockJson } = await scanParentDirs(destPath);
const opts = {
env: {
...process.env,
// This is a little hack to force `node-gyp` to build for the
// Node.js version that `@now/node` and `@now/node-server` use
npm_config_target: '8.10.0',
},
};
if (hasPackageLockJson) {
commandArgs = args.filter(a => a !== '--prefer-offline');
await spawnAsync('npm', ['install'].concat(commandArgs), destPath, opts);
await spawnAsync('npm', ['cache', 'clean', '--force'], destPath, opts);
} else {
await spawnAsync(
'yarn',
['--cwd', destPath].concat(commandArgs),
destPath,
opts,
);
await spawnAsync('yarn', ['cache', 'clean'], destPath, opts);
}
}
async function runPackageJsonScript(destPath, scriptName) {
assert(path.isAbsolute(destPath));
const { hasScript, hasPackageLockJson } = await scanParentDirs(
destPath,
scriptName,
);
if (!hasScript) return false;
if (hasPackageLockJson) {
console.log(`running "npm run ${scriptName}"`);
await spawnAsync('npm', ['run', scriptName], destPath);
} else {
console.log(`running "yarn run ${scriptName}"`);
await spawnAsync('yarn', ['--cwd', destPath, 'run', scriptName], destPath);
}
return true;
}
module.exports = {
runShellScript,
installDependencies,
runNpmInstall: installDependencies,
runPackageJsonScript,
};
module.exports = require('../dist/index');

View File

@@ -1,4 +1 @@
const fastStreamToBuffer = require('fast-stream-to-buffer');
const { promisify } = require('util');
module.exports = promisify(fastStreamToBuffer);
module.exports = require('../dist/index').streamToBuffer;

View File

@@ -1,60 +1 @@
const assert = require('assert');
const Sema = require('async-sema');
const { ZipFile } = require('yazl');
const streamToBuffer = require('./fs/stream-to-buffer.js');
class Lambda {
constructor({
zipBuffer, handler, runtime, environment,
}) {
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);
async function createLambda({
files, handler, runtime, environment = {},
}) {
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 zipFile = new ZipFile();
const zipBuffer = await new Promise((resolve, reject) => {
Object.keys(files)
.sort()
.forEach((name) => {
const file = files[name];
const stream = file.toStream();
stream.on('error', reject);
zipFile.addReadStream(stream, name, { mode: file.mode, mtime });
});
zipFile.end();
streamToBuffer(zipFile.outputStream).then(resolve).catch(reject);
});
return new Lambda({
zipBuffer,
handler,
runtime,
environment,
});
} finally {
sema.release();
}
}
module.exports = {
Lambda,
createLambda,
};
module.exports = require('./dist/index');

View File

@@ -1,25 +1,43 @@
{
"name": "@now/build-utils",
"version": "0.4.37-canary.1",
"version": "0.9.6",
"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-builders.git",
"directory": "packages/now-build-utils"
},
"dependencies": {
"scripts": {
"build": "./build.sh",
"test": "./build.sh && jest",
"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",
"fast-stream-to-buffer": "1.0.0",
"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": "4.0.0",
"memory-fs": "0.4.1",
"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"
},
"scripts": {
"test": "jest"
}
}

View File

@@ -0,0 +1,7 @@
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

@@ -0,0 +1,169 @@
import { PackageJson, Builder, Config } from './types';
import minimatch from 'minimatch';
interface ErrorResponse {
code: string;
message: string;
}
interface Options {
tag?: 'canary' | 'latest';
}
const src: string = 'package.json';
const config: Config = { zeroConfig: true };
// Static builders are special cased in `@now/static-build`
const BUILDERS = new Map<string, Builder>([
['next', { src, use: '@now/next', config }],
]);
const API_BUILDERS: Builder[] = [
{ 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 },
];
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',
};
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 BUILDERS) {
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 the file does not match any builder we also
// don't want to create a route e.g. `package.json`
if (API_BUILDERS.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 = API_BUILDERS.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((builder: Builder) => {
// @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

@@ -0,0 +1,262 @@
import { Route, Builder } from './types';
import { parse as parsePath } from 'path';
import { ignoreApiFilter, sortFiles } from './detect-builders';
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: number = 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 } = parsePath(segment);
return fileName;
}
return segment;
}
);
const src = `^/${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));
}
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

@@ -0,0 +1,46 @@
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

@@ -0,0 +1,97 @@
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

@@ -0,0 +1,95 @@
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;
}
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;
constructor({ mode = 0o100644, digest }: FileRefOptions) {
assert(typeof mode === 'number');
assert(typeof digest === 'string');
this.type = 'FileRef';
this.mode = mode;
this.digest = digest;
}
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
// `https://now-files.s3.amazonaws.com/${digestHash}`
url = `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

@@ -0,0 +1,75 @@
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

@@ -0,0 +1,10 @@
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

@@ -0,0 +1,70 @@
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

@@ -0,0 +1,53 @@
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

@@ -0,0 +1,12 @@
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

@@ -0,0 +1,190 @@
import assert from 'assert';
import fs from 'fs-extra';
import path from 'path';
import spawn from 'cross-spawn';
import { SpawnOptions } from 'child_process';
import { deprecate } from 'util';
import { Meta, PackageJson, NodeVersion } 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
): Promise<NodeVersion> {
const { packageJson } = await scanParentDirs(destPath, true);
const range =
(packageJson && packageJson.engines && packageJson.engines.node) ||
minNodeVersion;
return getSupportedNodeVersion(range, typeof minNodeVersion !== 'undefined');
}
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
) {
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

@@ -0,0 +1,28 @@
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

@@ -0,0 +1,47 @@
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

@@ -0,0 +1,107 @@
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

@@ -0,0 +1,27 @@
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

@@ -0,0 +1,216 @@
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,9 +1,10 @@
{
"version": 2,
"builds": [
{ "src": "api/index.js", "use": "@now/node" }
],
"builds": [{ "src": "api/index.js", "use": "@now/node" }],
"probes": [
{ "path": "/api/index.js", "mustContain": "cross-cow:RANDOMNESS_PLACEHOLDER" }
{
"path": "/api/index.js",
"mustContain": "cross-cow:RANDOMNESS_PLACEHOLDER"
}
]
}

View File

@@ -0,0 +1,9 @@
const scheduler = require('@google-cloud/scheduler');
module.exports = (_, res) => {
if (scheduler) {
res.end('found:RANDOMNESS_PLACEHOLDER');
} else {
res.end('nope:RANDOMNESS_PLACEHOLDER');
}
};

View File

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

View File

@@ -0,0 +1,8 @@
{
"name": "15-yarn-ignore-engines",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"@google-cloud/scheduler": "0.3.0"
}
}

View File

@@ -0,0 +1 @@
contents

View File

@@ -0,0 +1 @@
./a.txt

View File

@@ -1,12 +1,23 @@
/* global beforeAll, expect, it, jest */
const fs = require('fs');
const path = require('path');
const fs = require('fs-extra');
// eslint-disable-next-line import/no-extraneous-dependencies
const execa = require('execa');
const assert = require('assert');
const { glob, download } = require('../');
const { createZip } = require('../dist/lambda');
const {
getSupportedNodeVersion,
defaultSelection,
} = require('../dist/fs/node-version');
const {
packAndDeploy,
testDeployment,
} = require('../../../test/lib/deployment/test-deployment.js');
const { detectBuilders, detectRoutes } = require('../dist');
jest.setTimeout(4 * 60 * 1000);
const builderUrl = '@canary';
let buildUtilsUrl;
@@ -17,6 +28,124 @@ beforeAll(async () => {
console.log('buildUtilsUrl', buildUtilsUrl);
});
// unit tests
it('should re-create symlinks properly', async () => {
const files = await glob('**', path.join(__dirname, 'symlinks'));
assert.equal(Object.keys(files).length, 2);
const outDir = path.join(__dirname, 'symlinks-out');
await fs.remove(outDir);
const files2 = await download(files, outDir);
assert.equal(Object.keys(files2).length, 2);
const [linkStat, aStat] = await Promise.all([
fs.lstat(path.join(outDir, 'link.txt')),
fs.lstat(path.join(outDir, 'a.txt')),
]);
assert(linkStat.isSymbolicLink());
assert(aStat.isFile());
});
it('should create zip files with symlinks properly', async () => {
const files = await glob('**', path.join(__dirname, 'symlinks'));
assert.equal(Object.keys(files).length, 2);
const outFile = path.join(__dirname, 'symlinks.zip');
await fs.remove(outFile);
const outDir = path.join(__dirname, 'symlinks-out');
await fs.remove(outDir);
await fs.mkdirp(outDir);
await fs.writeFile(outFile, await createZip(files));
await execa('unzip', [outFile], { cwd: outDir });
const [linkStat, aStat] = await Promise.all([
fs.lstat(path.join(outDir, 'link.txt')),
fs.lstat(path.join(outDir, 'a.txt')),
]);
assert(linkStat.isSymbolicLink());
assert(aStat.isFile());
});
it('should only match supported node versions', () => {
expect(getSupportedNodeVersion('10.x')).resolves.toHaveProperty('major', 10);
expect(getSupportedNodeVersion('8.10.x')).resolves.toHaveProperty('major', 8);
expect(getSupportedNodeVersion('8.11.x')).rejects.toThrow();
expect(getSupportedNodeVersion('6.x')).rejects.toThrow();
expect(getSupportedNodeVersion('999.x')).rejects.toThrow();
expect(getSupportedNodeVersion('foo')).rejects.toThrow();
expect(getSupportedNodeVersion('')).resolves.toBe(defaultSelection);
expect(getSupportedNodeVersion(null)).resolves.toBe(defaultSelection);
expect(getSupportedNodeVersion(undefined)).resolves.toBe(defaultSelection);
});
it('should match all semver ranges', () => {
// See https://docs.npmjs.com/files/package.json#engines
expect(getSupportedNodeVersion('10.0.0')).resolves.toHaveProperty(
'major',
10,
);
expect(getSupportedNodeVersion('10.x')).resolves.toHaveProperty('major', 10);
expect(getSupportedNodeVersion('>=10')).resolves.toHaveProperty('major', 10);
expect(getSupportedNodeVersion('>=10.3.0')).resolves.toHaveProperty(
'major',
10,
);
expect(getSupportedNodeVersion('8.5.0 - 10.5.0')).resolves.toHaveProperty(
'major',
10,
);
expect(getSupportedNodeVersion('>=9.0.0')).resolves.toHaveProperty(
'major',
10,
);
expect(getSupportedNodeVersion('>=9.5.0 <=10.5.0')).resolves.toHaveProperty(
'major',
10,
);
expect(getSupportedNodeVersion('~10.5.0')).resolves.toHaveProperty(
'major',
10,
);
expect(getSupportedNodeVersion('^10.5.0')).resolves.toHaveProperty(
'major',
10,
);
});
it('should support require by path for legacy builders', () => {
const index = require('@now/build-utils');
const download2 = require('@now/build-utils/fs/download.js');
const getWriteableDirectory2 = require('@now/build-utils/fs/get-writable-directory.js');
const glob2 = require('@now/build-utils/fs/glob.js');
const rename2 = require('@now/build-utils/fs/rename.js');
const {
runNpmInstall: runNpmInstall2,
} = require('@now/build-utils/fs/run-user-scripts.js');
const streamToBuffer2 = require('@now/build-utils/fs/stream-to-buffer.js');
const FileBlob2 = require('@now/build-utils/file-blob.js');
const FileFsRef2 = require('@now/build-utils/file-fs-ref.js');
const FileRef2 = require('@now/build-utils/file-ref.js');
const { Lambda: Lambda2 } = require('@now/build-utils/lambda.js');
expect(download2).toBe(index.download);
expect(getWriteableDirectory2).toBe(index.getWriteableDirectory);
expect(glob2).toBe(index.glob);
expect(rename2).toBe(index.rename);
expect(runNpmInstall2).toBe(index.runNpmInstall);
expect(streamToBuffer2).toBe(index.streamToBuffer);
expect(FileBlob2).toBe(index.FileBlob);
expect(FileFsRef2).toBe(index.FileFsRef);
expect(FileRef2).toBe(index.FileRef);
expect(Lambda2).toBe(index.Lambda);
});
// own fixtures
const fixturesPath = path.resolve(__dirname, 'fixtures');
@@ -36,7 +165,7 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
// few foreign tests
const buildersToTestWith = ['now-node-server', 'now-static-build'];
const buildersToTestWith = ['now-next', 'now-node', 'now-static-build'];
// eslint-disable-next-line no-restricted-syntax
for (const builder of buildersToTestWith) {
@@ -48,7 +177,7 @@ for (const builder of buildersToTestWith) {
// eslint-disable-next-line no-restricted-syntax
for (const fixture of fs.readdirSync(fixturesPath2)) {
// don't run all foreign fixtures, just some
if (['01-cowsay', '03-env-vars'].includes(fixture)) {
if (['01-cowsay', '01-cache-headers', '03-env-vars'].includes(fixture)) {
// eslint-disable-next-line no-loop-func
it(`should build ${builder}/${fixture}`, async () => {
await expect(
@@ -61,3 +190,330 @@ for (const builder of buildersToTestWith) {
}
}
}
it('Test `detectBuilders`', async () => {
{
// package.json + no build
const pkg = { dependencies: { next: '9.0.0' } };
const files = ['package.json', 'pages/index.js', 'public/index.html'];
const { builders, errors } = await detectBuilders(files, pkg);
expect(builders).toBe(null);
expect(errors.length).toBe(1);
}
{
// package.json + no build + next
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
};
const files = ['package.json', 'pages/index.js'];
const { builders, errors } = await detectBuilders(files, pkg);
expect(builders[0].use).toBe('@now/next');
expect(errors).toBe(null);
}
{
// package.json + no build + next
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
};
const files = ['package.json', 'pages/index.js'];
const { builders, errors } = await detectBuilders(files, pkg);
expect(builders[0].use).toBe('@now/next');
expect(errors).toBe(null);
}
{
// package.json + no build
const pkg = {};
const files = ['package.json'];
const { builders, errors } = await detectBuilders(files, pkg);
expect(builders).toBe(null);
expect(errors.length).toBe(1);
}
{
// static file
const files = ['index.html'];
const { builders, errors } = await detectBuilders(files);
expect(builders).toBe(null);
expect(errors).toBe(null);
}
{
// no package.json + public
const files = ['api/users.js', 'public/index.html'];
const { builders, errors } = await detectBuilders(files);
expect(builders[1].use).toBe('@now/static');
expect(errors).toBe(null);
}
{
// no package.json + no build + raw static + api
const files = ['api/users.js', 'index.html'];
const { builders, errors } = await detectBuilders(files);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].src).toBe('api/users.js');
expect(builders[1].use).toBe('@now/static');
expect(builders[1].src).toBe('index.html');
expect(builders.length).toBe(2);
expect(errors).toBe(null);
}
{
// package.json + no build + root + api
const files = ['index.html', 'api/[endpoint].js', 'static/image.png'];
const { builders, errors } = await detectBuilders(files);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].src).toBe('api/[endpoint].js');
expect(builders[1].use).toBe('@now/static');
expect(builders[1].src).toBe('index.html');
expect(builders[2].use).toBe('@now/static');
expect(builders[2].src).toBe('static/image.png');
expect(builders.length).toBe(3);
expect(errors).toBe(null);
}
{
// api + ignore files
const files = [
'api/_utils/handler.js',
'api/[endpoint]/.helper.js',
'api/[endpoint]/[id].js',
];
const { builders } = await detectBuilders(files);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].src).toBe('api/[endpoint]/[id].js');
expect(builders.length).toBe(1);
}
{
// api + next + public
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
};
const files = ['package.json', 'api/endpoint.js', 'public/index.html'];
const { builders } = await detectBuilders(files, pkg);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].src).toBe('api/endpoint.js');
expect(builders[1].use).toBe('@now/next');
expect(builders[1].src).toBe('package.json');
expect(builders.length).toBe(2);
}
{
// api + next + raw static
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
};
const files = ['package.json', 'api/endpoint.js', 'index.html'];
const { builders } = await detectBuilders(files, pkg);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].src).toBe('api/endpoint.js');
expect(builders[1].use).toBe('@now/next');
expect(builders[1].src).toBe('package.json');
expect(builders.length).toBe(2);
}
{
// api + raw static
const files = ['api/endpoint.js', 'index.html', 'favicon.ico'];
const { builders } = await detectBuilders(files);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].src).toBe('api/endpoint.js');
expect(builders[1].use).toBe('@now/static');
expect(builders[1].src).toBe('favicon.ico');
expect(builders[2].use).toBe('@now/static');
expect(builders[2].src).toBe('index.html');
expect(builders.length).toBe(3);
}
{
// api + public
const files = [
'api/endpoint.js',
'public/index.html',
'public/favicon.ico',
'README.md',
];
const { builders } = await detectBuilders(files);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].src).toBe('api/endpoint.js');
expect(builders[1].use).toBe('@now/static');
expect(builders[1].src).toBe('public/**/*');
expect(builders.length).toBe(2);
}
{
// just public
const files = ['public/index.html', 'public/favicon.ico', 'README.md'];
const { builders } = await detectBuilders(files);
expect(builders[0].src).toBe('public/**/*');
expect(builders.length).toBe(1);
}
{
// next + public
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
};
const files = ['package.json', 'public/index.html', 'README.md'];
const { builders } = await detectBuilders(files, pkg);
expect(builders[0].use).toBe('@now/next');
expect(builders[0].src).toBe('package.json');
expect(builders.length).toBe(1);
}
{
// nuxt
const pkg = {
scripts: { build: 'nuxt build' },
dependencies: { nuxt: '2.8.1' },
};
const files = ['package.json', 'pages/index.js'];
const { builders } = await detectBuilders(files, pkg);
expect(builders[0].use).toBe('@now/static-build');
expect(builders[0].src).toBe('package.json');
expect(builders.length).toBe(1);
}
{
// package.json with no build + api
const pkg = { dependencies: { next: '9.0.0' } };
const files = ['package.json', 'api/[endpoint].js'];
const { builders } = await detectBuilders(files, pkg);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].src).toBe('api/[endpoint].js');
expect(builders.length).toBe(1);
}
{
// package.json with no build + public directory
const pkg = { dependencies: { next: '9.0.0' } };
const files = ['package.json', 'public/index.html'];
const { builders, errors } = await detectBuilders(files, pkg);
expect(builders).toBe(null);
expect(errors.length).toBe(1);
}
{
// no package.json + api
const files = ['api/[endpoint].js', 'api/[endpoint]/[id].js'];
const { builders } = await detectBuilders(files);
expect(builders.length).toBe(2);
}
{
// no package.json + no api
const files = ['index.html'];
const { builders, errors } = await detectBuilders(files);
expect(builders).toBe(null);
expect(errors).toBe(null);
}
{
// package.json + api + canary
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
};
const files = [
'pages/index.js',
'api/[endpoint].js',
'api/[endpoint]/[id].js',
];
const { builders } = await detectBuilders(files, pkg, { tag: 'canary' });
expect(builders[0].use).toBe('@now/node@canary');
expect(builders[1].use).toBe('@now/node@canary');
expect(builders[2].use).toBe('@now/next@canary');
expect(builders.length).toBe(3);
}
});
it('Test `detectRoutes`', async () => {
{
const files = ['api/user.go', 'api/team.js', 'api/package.json'];
const { builders } = await detectBuilders(files);
const { defaultRoutes } = await detectRoutes(files, builders);
expect(defaultRoutes.length).toBe(2);
expect(defaultRoutes[0].dest).toBe('/api/team.js');
expect(defaultRoutes[1].dest).toBe('/api/user.go');
}
{
const files = ['api/user.go', 'api/user.js'];
const { builders } = await detectBuilders(files);
const { error } = await detectRoutes(files, builders);
expect(error.code).toBe('conflicting_file_path');
}
{
const files = ['api/[user].go', 'api/[team]/[id].js'];
const { builders } = await detectBuilders(files);
const { error } = await detectRoutes(files, builders);
expect(error.code).toBe('conflicting_file_path');
}
{
const files = ['api/[team]/[team].js'];
const { builders } = await detectBuilders(files);
const { error } = await detectRoutes(files, builders);
expect(error.code).toBe('conflicting_path_segment');
}
{
const files = ['api/[endpoint].js', 'api/[endpoint]/[id].js'];
const { builders } = await detectBuilders(files);
const { defaultRoutes } = await detectRoutes(files, builders);
expect(defaultRoutes.length).toBe(2);
}
{
const files = [
'public/index.html',
'api/[endpoint].js',
'api/[endpoint]/[id].js',
];
const { builders } = await detectBuilders(files);
const { defaultRoutes } = await detectRoutes(files, builders);
expect(defaultRoutes[2].src).toBe('/(.*)');
expect(defaultRoutes[2].dest).toBe('/public/$1');
expect(defaultRoutes.length).toBe(3);
}
{
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
};
const files = ['public/index.html', 'api/[endpoint].js'];
const { builders } = await detectBuilders(files, pkg);
const { defaultRoutes } = await detectRoutes(files, builders);
expect(defaultRoutes.length).toBe(1);
}
});

View File

@@ -0,0 +1,20 @@
{
"compilerOptions": {
"declaration": true,
"esModuleInterop": true,
"lib": ["esnext"],
"module": "commonjs",
"moduleResolution": "node",
"noEmitOnError": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"outDir": "./dist",
"types": ["node"],
"strict": true,
"target": "esnext"
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}

View File

@@ -5,15 +5,17 @@ const glob = require('@now/build-utils/fs/glob'); // eslint-disable-line import/
const download = require('@now/build-utils/fs/download'); // eslint-disable-line import/no-extraneous-dependencies
const { createLambda } = require('@now/build-utils/lambda'); // eslint-disable-line import/no-extraneous-dependencies
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory'); // eslint-disable-line import/no-extraneous-dependencies
const { shouldServe } = require('@now/build-utils'); // eslint-disable-line import/no-extraneous-dependencies
exports.analyze = ({ files, entrypoint }) => files[entrypoint].digest;
exports.build = async ({ files, entrypoint }) => {
exports.build = async ({
workPath, files, entrypoint, meta,
}) => {
console.log('downloading files...');
const srcDir = await getWritableDirectory();
const outDir = await getWritableDirectory();
await download(files, srcDir);
await download(files, workPath, meta);
const handlerPath = path.join(__dirname, 'handler');
await copyFile(handlerPath, path.join(outDir, 'handler'));
@@ -23,7 +25,7 @@ exports.build = async ({ files, entrypoint }) => {
// For now only the entrypoint file is copied into the lambda
await copyFile(
path.join(srcDir, entrypoint),
path.join(workPath, entrypoint),
path.join(outDir, entrypoint),
);
@@ -40,3 +42,5 @@ exports.build = async ({ files, entrypoint }) => {
[entrypoint]: lambda,
};
};
exports.shouldServe = shouldServe;

View File

@@ -1,6 +1,6 @@
{
"name": "@now/cgi",
"version": "0.0.16-canary.0",
"version": "0.1.4",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -1,5 +1,5 @@
node_modules
*.log
/?.js
/go
/get-exported-function-name
/analyze
*.js

View File

@@ -0,0 +1,5 @@
*.ts
test
tsconfig.json
package-lock.json
yarn.lock

View File

@@ -1,129 +0,0 @@
const tar = require('tar');
const execa = require('execa');
const fetch = require('node-fetch');
const { mkdirp } = require('fs-extra');
const { dirname, join } = require('path');
const debug = require('debug')('@now/go:go-helpers');
const archMap = new Map([['x64', 'amd64'], ['x86', '386']]);
const platformMap = new Map([['win32', 'windows']]);
// Location where the `go` binary will be installed after `postinstall`
const GO_DIR = join(__dirname, 'go');
const GO_BIN = join(GO_DIR, 'bin/go');
const getPlatform = p => platformMap.get(p) || p;
const getArch = a => archMap.get(a) || a;
const getGoUrl = (version, platform, arch) => {
const goArch = getArch(arch);
const goPlatform = getPlatform(platform);
const ext = platform === 'win32' ? 'zip' : 'tar.gz';
return `https://dl.google.com/go/go${version}.${goPlatform}-${goArch}.${ext}`;
};
async function getExportedFunctionName(filePath) {
debug('Detecting handler name for %o', filePath);
const bin = join(__dirname, 'get-exported-function-name');
const args = [filePath];
const name = await execa.stdout(bin, args);
debug('Detected exported name %o', name);
return name;
}
// Creates a `$GOPATH` directory tree, as per `go help gopath` instructions.
// Without this, `go` won't recognize the `$GOPATH`.
function createGoPathTree(goPath, platform, arch) {
const tuple = `${getPlatform(platform)}_${getArch(arch)}`;
debug('Creating GOPATH directory structure for %o (%s)', goPath, tuple);
return Promise.all([
mkdirp(join(goPath, 'bin')),
mkdirp(join(goPath, 'pkg', tuple)),
]);
}
async function get({ src } = {}) {
const args = ['get'];
if (src) {
debug('Fetching `go` dependencies for file %o', src);
args.push(src);
} else {
debug('Fetching `go` dependencies for cwd %o', this.cwd);
}
await this(...args);
}
async function build({ src, dest }) {
debug('Building `go` binary %o -> %o', src, dest);
let sources;
if (Array.isArray(src)) {
sources = src;
} else {
sources = [src];
}
await this('build', '-o', dest, ...sources);
}
async function createGo(
goPath,
platform = process.platform,
arch = process.arch,
opts = {},
goMod = false,
) {
const env = {
...process.env,
PATH: `${dirname(GO_BIN)}:${process.env.PATH}`,
GOPATH: goPath,
...opts.env,
};
if (goMod) {
env.GO111MODULE = 'on';
}
function go(...args) {
debug('Exec %o', `go ${args.join(' ')}`);
return execa('go', args, { stdio: 'inherit', ...opts, env });
}
go.cwd = opts.cwd || process.cwd();
go.get = get;
go.build = build;
go.goPath = goPath;
await createGoPathTree(goPath, platform, arch);
return go;
}
async function downloadGo(
dir = GO_DIR,
version = '1.12',
platform = process.platform,
arch = process.arch,
) {
debug('Installing `go` v%s to %o for %s %s', version, dir, platform, arch);
const url = getGoUrl(version, platform, arch);
debug('Downloading `go` URL: %o', url);
const res = await fetch(url);
if (!res.ok) {
throw new Error(`Failed to download: ${url} (${res.status})`);
}
// TODO: use a zip extractor when `ext === "zip"`
await mkdirp(dir);
await new Promise((resolve, reject) => {
res.body
.on('error', reject)
.pipe(tar.extract({ cwd: dir, strip: 1 }))
.on('error', reject)
.on('finish', resolve);
});
return createGo(dir, platform, arch);
}
module.exports = {
createGo,
downloadGo,
getExportedFunctionName,
};

View File

@@ -0,0 +1,170 @@
import tar from 'tar';
import execa from 'execa';
import fetch from 'node-fetch';
import { mkdirp, pathExists } from 'fs-extra';
import { dirname, join } from 'path';
import { homedir } from 'os';
import Debug from 'debug';
const debug = Debug('@now/go:go-helpers');
const archMap = new Map([['x64', 'amd64'], ['x86', '386']]);
const platformMap = new Map([['win32', 'windows']]);
// Location where the `go` binary will be installed after `postinstall`
const GO_DIR = join(__dirname, 'go');
const GO_BIN = join(GO_DIR, 'bin/go');
const getPlatform = (p: string) => platformMap.get(p) || p;
const getArch = (a: string) => archMap.get(a) || a;
const getGoUrl = (version: string, platform: string, arch: string) => {
const goArch = getArch(arch);
const goPlatform = getPlatform(platform);
const ext = platform === 'win32' ? 'zip' : 'tar.gz';
return `https://dl.google.com/go/go${version}.${goPlatform}-${goArch}.${ext}`;
};
export async function getAnalyzedEntrypoint(filePath: string, modulePath = '') {
debug('Analyzing entrypoint %o', filePath);
const bin = join(__dirname, 'analyze');
const isAnalyzeExist = await pathExists(bin);
if (!isAnalyzeExist) {
const src = join(__dirname, 'util', 'analyze.go');
const dest = join(__dirname, 'analyze');
const go = await downloadGo();
await go.build(src, dest);
}
const args = [`-modpath=${modulePath}`, filePath];
const analyzed = await execa.stdout(bin, args);
debug('Analyzed entrypoint %o', analyzed);
return analyzed;
}
// Creates a `$GOPATH` directory tree, as per `go help gopath` instructions.
// Without this, `go` won't recognize the `$GOPATH`.
function createGoPathTree(goPath: string, platform: string, arch: string) {
const tuple = `${getPlatform(platform)}_${getArch(arch)}`;
debug('Creating GOPATH directory structure for %o (%s)', goPath, tuple);
return Promise.all([
mkdirp(join(goPath, 'bin')),
mkdirp(join(goPath, 'pkg', tuple)),
]);
}
class GoWrapper {
private env: { [key: string]: string };
private opts: execa.Options;
constructor(env: { [key: string]: string }, opts: execa.Options = {}) {
if (!opts.cwd) {
opts.cwd = process.cwd();
}
this.env = env;
this.opts = opts;
}
private execute(...args: string[]) {
const { opts, env } = this;
debug('Exec %o', `go ${args.join(' ')}`);
return execa('go', args, { stdio: 'inherit', ...opts, env });
}
mod() {
return this.execute('mod', 'tidy');
}
get(src?: string) {
const args = ['get'];
if (src) {
debug('Fetching `go` dependencies for file %o', src);
args.push(src);
} else {
debug('Fetching `go` dependencies for cwd %o', this.opts.cwd);
}
return this.execute(...args);
}
build(src: string | string[], dest: string, ldsflags = '-s -w') {
debug('Building optimized `go` binary %o -> %o', src, dest);
const sources = Array.isArray(src) ? src : [src];
return this.execute('build', '-ldflags', ldsflags, '-o', dest, ...sources);
}
}
export async function createGo(
goPath: string,
platform = process.platform,
arch = process.arch,
opts: execa.Options = {},
goMod = false
) {
const path = `${dirname(GO_BIN)}:${process.env.PATH}`;
const env: { [key: string]: string } = {
...process.env,
PATH: path,
GOPATH: goPath,
...opts.env,
};
if (goMod) {
env.GO111MODULE = 'on';
}
await createGoPathTree(goPath, platform, arch);
return new GoWrapper(env, opts);
}
export async function downloadGo(
dir = GO_DIR,
version = '1.12',
platform = process.platform,
arch = process.arch
) {
// Check default `Go` in user machine
const isUserGo = await pathExists(join(homedir(), 'go'));
// If we found GOPATH in ENV, or default `Go` path exists
// asssume that user have `Go` installed
if (isUserGo || process.env.GOPATH !== undefined) {
const { stdout } = await execa('go', ['version']);
if (parseInt(stdout.split('.')[1]) >= 11) {
return createGo(dir, platform, arch);
}
throw new Error(
`Your current ${stdout} doesn't support Go Modules. Please update.`
);
} else {
// Check `Go` bin in builder CWD
const isGoExist = await pathExists(join(dir, 'bin'));
if (!isGoExist) {
debug(
'Installing `go` v%s to %o for %s %s',
version,
dir,
platform,
arch
);
const url = getGoUrl(version, platform, arch);
debug('Downloading `go` URL: %o', url);
console.log('Downloading Go ...');
const res = await fetch(url);
if (!res.ok) {
throw new Error(`Failed to download: ${url} (${res.status})`);
}
// TODO: use a zip extractor when `ext === "zip"`
await mkdirp(dir);
await new Promise((resolve, reject) => {
res.body
.on('error', reject)
.pipe(tar.extract({ cwd: dir, strip: 1 }))
.on('error', reject)
.on('finish', resolve);
});
}
return createGo(dir, platform, arch);
}
}

View File

@@ -1,198 +0,0 @@
const { join, dirname } = require('path');
const {
readFile, writeFile, pathExists, move,
} = require('fs-extra');
const glob = require('@now/build-utils/fs/glob.js'); // eslint-disable-line import/no-extraneous-dependencies
const download = require('@now/build-utils/fs/download.js'); // eslint-disable-line import/no-extraneous-dependencies
const { createLambda } = require('@now/build-utils/lambda.js'); // eslint-disable-line import/no-extraneous-dependencies
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory.js'); // eslint-disable-line import/no-extraneous-dependencies
const { createGo, getExportedFunctionName } = require('./go-helpers');
const config = {
maxLambdaSize: '10mb',
};
async function build({ files, entrypoint }) {
console.log('Downloading user files...');
const [goPath, outDir] = await Promise.all([
getWritableDirectory(),
getWritableDirectory(),
]);
const srcPath = join(goPath, 'src', 'lambda');
const downloadedFiles = await download(files, srcPath);
console.log(`Parsing AST for "${entrypoint}"`);
let parseFunctionName;
try {
parseFunctionName = await getExportedFunctionName(
downloadedFiles[entrypoint].fsPath,
);
} catch (err) {
console.log(`Failed to parse AST for "${entrypoint}"`);
throw err;
}
if (!parseFunctionName) {
const err = new Error(
`Could not find an exported function in "${entrypoint}"`,
);
console.log(err.message);
throw err;
}
const handlerFunctionName = parseFunctionName.split(',')[0];
console.log(
`Found exported function "${handlerFunctionName}" in "${entrypoint}"`,
);
// we need `main.go` in the same dir as the entrypoint,
// otherwise `go build` will refuse to build
const entrypointDirname = dirname(downloadedFiles[entrypoint].fsPath);
// check if package name other than main
const packageName = parseFunctionName.split(',')[1];
const isGoModExist = await pathExists(`${entrypointDirname}/go.mod`);
if (packageName !== 'main') {
const go = await createGo(
goPath,
process.platform,
process.arch,
{
cwd: entrypointDirname,
},
true,
);
if (!isGoModExist) {
try {
go('mod', 'init', packageName);
} catch (err) {
console.log(`failed to \`go mod init ${packageName}\``);
throw err;
}
}
const mainModGoFileName = 'main__mod__.go';
const modMainGoContents = await readFile(
join(__dirname, mainModGoFileName),
'utf8',
);
let goPackageName = `${packageName}/${packageName}`;
const goFuncName = `${packageName}.${handlerFunctionName}`;
if (isGoModExist) {
const goModContents = await readFile(
`${entrypointDirname}/go.mod`,
'utf8',
);
goPackageName = `${
goModContents.split('\n')[0].split(' ')[1]
}/${packageName}`;
}
const mainModGoContents = modMainGoContents
.replace('__NOW_HANDLER_PACKAGE_NAME', goPackageName)
.replace('__NOW_HANDLER_FUNC_NAME', goFuncName);
// write main__mod__.go
await writeFile(
join(entrypointDirname, mainModGoFileName),
mainModGoContents,
);
// move user go file to folder
try {
await move(
downloadedFiles[entrypoint].fsPath,
`${join(entrypointDirname, packageName, entrypoint)}`,
);
} catch (err) {
console.log('failed to move entry to package folder');
throw err;
}
console.log('tidy go.mod file');
try {
// ensure go.mod up-to-date
await go('mod', 'tidy');
} catch (err) {
console.log('failed to `go mod tidy`');
throw err;
}
console.log('Running `go build`...');
const destPath = join(outDir, 'handler');
try {
const src = [join(entrypointDirname, mainModGoFileName)];
await go.build({ src, dest: destPath });
} catch (err) {
console.log('failed to `go build`');
throw err;
}
} else {
const go = await createGo(
goPath,
process.platform,
process.arch,
{
cwd: entrypointDirname,
},
false,
);
const origianlMainGoContents = await readFile(
join(__dirname, 'main.go'),
'utf8',
);
const mainGoContents = origianlMainGoContents.replace(
'__NOW_HANDLER_FUNC_NAME',
handlerFunctionName,
);
// in order to allow the user to have `main.go`,
// we need our `main.go` to be called something else
const mainGoFileName = 'main__now__go__.go';
// Go doesn't like to build files in different directories,
// so now we place `main.go` together with the user code
await writeFile(join(entrypointDirname, mainGoFileName), mainGoContents);
// `go get` will look at `*.go` (note we set `cwd`), parse the `import`s
// and download any packages that aren't part of the stdlib
try {
await go.get();
} catch (err) {
console.log('failed to `go get`');
throw err;
}
console.log('Running `go build`...');
const destPath = join(outDir, 'handler');
try {
const src = [
join(entrypointDirname, mainGoFileName),
downloadedFiles[entrypoint].fsPath,
];
await go.build({ src, dest: destPath });
} catch (err) {
console.log('failed to `go build`');
throw err;
}
}
const lambda = await createLambda({
files: await glob('**', outDir),
handler: 'handler',
runtime: 'go1.x',
environment: {},
});
return {
[entrypoint]: lambda,
};
}
module.exports = { config, build };

427
packages/now-go/index.ts Normal file
View File

@@ -0,0 +1,427 @@
import { join, sep, dirname, basename } from 'path';
import { readFile, writeFile, pathExists, move } from 'fs-extra';
import { homedir } from 'os';
import execa from 'execa';
import {
glob,
download,
createLambda,
getWriteableDirectory,
BuildOptions,
shouldServe,
Files,
} from '@now/build-utils';
import { createGo, getAnalyzedEntrypoint } from './go-helpers';
interface Analyzed {
found?: boolean;
packageName: string;
functionName: string;
watch: string[];
}
interface BuildParamsMeta {
isDev: boolean | undefined;
}
interface BuildParamsType extends BuildOptions {
files: Files;
entrypoint: string;
workPath: string;
meta: BuildParamsMeta;
}
// Initialize private git repo for Go Modules
async function initPrivateGit(credentials: string) {
await execa('git', [
'config',
'--global',
'credential.helper',
`store --file ${join(homedir(), '.git-credentials')}`,
]);
await writeFile(join(homedir(), '.git-credentials'), credentials);
}
export const version = 2;
export async function build({
files,
entrypoint,
config,
workPath,
meta = {} as BuildParamsMeta,
}: BuildParamsType) {
if (process.env.GIT_CREDENTIALS && !meta.isDev) {
console.log('Initialize Git credentials...');
await initPrivateGit(process.env.GIT_CREDENTIALS);
}
if (process.env.GO111MODULE) {
console.log(`\nManually assigning 'GO111MODULE' is not recommended.
By default:
- 'GO111MODULE=on' If entrypoint package name is not 'main'
- 'GO111MODULE=off' If entrypoint package name is 'main'
We highly recommend you leverage Go Modules in your project.
Learn more: https://github.com/golang/go/wiki/Modules
`);
}
console.log('Downloading user files...');
const entrypointArr = entrypoint.split(sep);
let [goPath, outDir] = await Promise.all([
getWriteableDirectory(),
getWriteableDirectory(),
]);
const srcPath = join(goPath, 'src', 'lambda');
let downloadedFiles;
if (meta.isDev) {
downloadedFiles = await download(files, workPath, meta);
} else {
downloadedFiles = await download(files, srcPath);
}
console.log(`Parsing AST for "${entrypoint}"`);
let analyzed: string;
try {
let goModAbsPathDir = '';
for (const file of Object.keys(downloadedFiles)) {
if (file === 'go.mod') {
goModAbsPathDir = dirname(downloadedFiles[file].fsPath);
}
}
analyzed = await getAnalyzedEntrypoint(
downloadedFiles[entrypoint].fsPath,
goModAbsPathDir
);
} catch (err) {
console.log(`Failed to parse AST for "${entrypoint}"`);
throw err;
}
if (!analyzed) {
const err = new Error(
`Could not find an exported function in "${entrypoint}"
Learn more: https://zeit.co/docs/v2/deployments/official-builders/go-now-go/#entrypoint
`
);
console.log(err.message);
throw err;
}
const parsedAnalyzed = JSON.parse(analyzed) as Analyzed;
if (meta.isDev) {
let base = null;
if (config && config.zeroConfig) {
base = workPath;
} else {
base = dirname(downloadedFiles['now.json'].fsPath);
}
const destNow = join(
base,
'.now',
'cache',
basename(entrypoint, '.go'),
'src',
'lambda'
);
// this will ensure Go rebuilt fast
goPath = join(base, '.now', 'cache', basename(entrypoint, '.go'));
await download(downloadedFiles, destNow);
downloadedFiles = await glob('**', destNow);
}
// find `go.mod` in downloadedFiles
const entrypointDirname = dirname(downloadedFiles[entrypoint].fsPath);
let isGoModExist = false;
let goModPath = '';
let isGoModInRootDir = false;
for (const file of Object.keys(downloadedFiles)) {
const fileDirname = dirname(downloadedFiles[file].fsPath);
if (file === 'go.mod') {
isGoModExist = true;
isGoModInRootDir = true;
goModPath = fileDirname;
} else if (file.endsWith('go.mod') && !file.endsWith('vendor')) {
if (entrypointDirname === fileDirname) {
isGoModExist = true;
goModPath = fileDirname;
break;
}
}
}
const input = entrypointDirname;
var includedFiles: Files = {};
if (config && config.includeFiles) {
for (const pattern of config.includeFiles) {
const files = await glob(pattern, input);
for (const assetName of Object.keys(files)) {
includedFiles[assetName] = files[assetName];
}
}
}
const handlerFunctionName = parsedAnalyzed.functionName;
console.log(
`Found exported function "${handlerFunctionName}" in "${entrypoint}"`
);
if (!isGoModExist && 'vendor' in downloadedFiles) {
throw new Error('`go.mod` is required to use a `vendor` directory.');
}
// check if package name other than main
// using `go.mod` way building the handler
const packageName = parsedAnalyzed.packageName;
if (isGoModExist && packageName === 'main') {
throw new Error('Please change `package main` to `package handler`');
}
if (packageName !== 'main') {
const go = await createGo(
goPath,
process.platform,
process.arch,
{
cwd: entrypointDirname,
},
true
);
if (!isGoModExist) {
try {
const defaultGoModContent = `module ${packageName}`;
await writeFile(join(entrypointDirname, 'go.mod'), defaultGoModContent);
} catch (err) {
console.log(`failed to create default go.mod for ${packageName}`);
throw err;
}
}
const mainModGoFileName = 'main__mod__.go';
const modMainGoContents = await readFile(
join(__dirname, mainModGoFileName),
'utf8'
);
let goPackageName = `${packageName}/${packageName}`;
const goFuncName = `${packageName}.${handlerFunctionName}`;
if (isGoModExist) {
const goModContents = await readFile(join(goModPath, 'go.mod'), 'utf8');
const usrModName = goModContents.split('\n')[0].split(' ')[1];
if (entrypointArr.length > 1 && isGoModInRootDir) {
let cleanPackagePath = [...entrypointArr];
cleanPackagePath.pop();
goPackageName = `${usrModName}/${cleanPackagePath.join('/')}`;
} else {
goPackageName = `${usrModName}/${packageName}`;
}
}
const mainModGoContents = modMainGoContents
.replace('__NOW_HANDLER_PACKAGE_NAME', goPackageName)
.replace('__NOW_HANDLER_FUNC_NAME', goFuncName);
if (meta.isDev && isGoModExist && isGoModInRootDir) {
await writeFile(
join(dirname(downloadedFiles['go.mod'].fsPath), mainModGoFileName),
mainModGoContents
);
} else if (isGoModExist && isGoModInRootDir) {
await writeFile(join(srcPath, mainModGoFileName), mainModGoContents);
} else if (isGoModExist && !isGoModInRootDir) {
// using `go.mod` path to write main__mod__.go
await writeFile(join(goModPath, mainModGoFileName), mainModGoContents);
} else {
// using `entrypointDirname` to write main__mod__.go
await writeFile(
join(entrypointDirname, mainModGoFileName),
mainModGoContents
);
}
// move user go file to folder
try {
// default path
let finalDestination = join(entrypointDirname, packageName, entrypoint);
let forceMove = false;
if (meta.isDev) {
forceMove = true;
}
// if `entrypoint` include folder, only use filename
if (entrypointArr.length > 1) {
finalDestination = join(
entrypointDirname,
packageName,
entrypointArr[entrypointArr.length - 1]
);
}
if (
dirname(downloadedFiles[entrypoint].fsPath) === goModPath ||
!isGoModExist
) {
await move(downloadedFiles[entrypoint].fsPath, finalDestination, {
overwrite: forceMove,
});
}
} catch (err) {
console.log('failed to move entry to package folder');
throw err;
}
let baseGoModPath = '';
if (meta.isDev && isGoModExist && isGoModInRootDir) {
baseGoModPath = dirname(downloadedFiles['go.mod'].fsPath);
} else if (isGoModExist && isGoModInRootDir) {
baseGoModPath = srcPath;
} else if (isGoModExist && !isGoModInRootDir) {
baseGoModPath = goModPath;
} else {
baseGoModPath = entrypointDirname;
}
if (meta.isDev) {
const isGoModBk = await pathExists(join(baseGoModPath, 'go.mod.bk'));
if (isGoModBk) {
await move(
join(baseGoModPath, 'go.mod.bk'),
join(baseGoModPath, 'go.mod'),
{ overwrite: true }
);
await move(
join(baseGoModPath, 'go.sum.bk'),
join(baseGoModPath, 'go.sum'),
{ overwrite: true }
);
}
}
console.log('Tidy `go.mod` file...');
try {
// ensure go.mod up-to-date
await go.mod();
} catch (err) {
console.log('failed to `go mod tidy`');
throw err;
}
console.log('Running `go build`...');
const destPath = join(outDir, 'handler');
try {
let src = [join(baseGoModPath, mainModGoFileName)];
await go.build(src, destPath, config.ldsflags);
} catch (err) {
console.log('failed to `go build`');
throw err;
}
if (meta.isDev) {
// caching for `now dev`
await move(
join(baseGoModPath, 'go.mod'),
join(baseGoModPath, 'go.mod.bk'),
{ overwrite: true }
);
await move(
join(baseGoModPath, 'go.sum'),
join(baseGoModPath, 'go.sum.bk'),
{ overwrite: true }
);
}
} else {
// legacy mode
// we need `main.go` in the same dir as the entrypoint,
// otherwise `go build` will refuse to build
const go = await createGo(
goPath,
process.platform,
process.arch,
{
cwd: entrypointDirname,
},
false
);
const origianlMainGoContents = await readFile(
join(__dirname, 'main.go'),
'utf8'
);
const mainGoContents = origianlMainGoContents.replace(
'__NOW_HANDLER_FUNC_NAME',
handlerFunctionName
);
// in order to allow the user to have `main.go`,
// we need our `main.go` to be called something else
const mainGoFileName = 'main__now__go__.go';
// Go doesn't like to build files in different directories,
// so now we place `main.go` together with the user code
await writeFile(join(entrypointDirname, mainGoFileName), mainGoContents);
// `go get` will look at `*.go` (note we set `cwd`), parse the `import`s
// and download any packages that aren't part of the stdlib
console.log('Running `go get`...');
try {
await go.get();
} catch (err) {
console.log('failed to `go get`');
throw err;
}
console.log('Running `go build`...');
const destPath = join(outDir, 'handler');
try {
const src = [
join(entrypointDirname, mainGoFileName),
downloadedFiles[entrypoint].fsPath,
];
await go.build(src, destPath);
} catch (err) {
console.log('failed to `go build`');
throw err;
}
}
const lambda = await createLambda({
files: { ...(await glob('**', outDir)), ...includedFiles },
handler: 'handler',
runtime: 'go1.x',
environment: {},
});
const output = {
[entrypoint]: lambda,
};
let watch = parsedAnalyzed.watch;
let watchSub: string[] = [];
// if `entrypoint` located in subdirectory
// we will need to concat it with return watch array
if (entrypointArr.length > 1) {
entrypointArr.pop();
watchSub = parsedAnalyzed.watch.map(file => join(...entrypointArr, file));
}
return {
output,
watch: watch.concat(watchSub),
};
}
export { shouldServe };

View File

@@ -0,0 +1,6 @@
import { downloadGo } from './go-helpers';
downloadGo().catch(err => {
console.error(err);
process.exit(1);
});

View File

@@ -1,14 +1,18 @@
{
"name": "@now/go",
"version": "0.3.1-canary.1",
"version": "0.5.7",
"license": "MIT",
"homepage": "https://zeit.co/docs/v2/deployments/official-builders/go-now-go",
"repository": {
"type": "git",
"url": "https://github.com/zeit/now-builders.git",
"directory": "packages/now-go"
},
"scripts": {
"postinstall": "node ./util/install"
"build": "tsc",
"test": "tsc && jest",
"prepublish": "tsc",
"now-postinstall": "node install.js"
},
"files": [
"*.js",
@@ -20,8 +24,15 @@
"debug": "^4.1.1",
"execa": "^1.0.0",
"fs-extra": "^7.0.0",
"mkdirp-promise": "5.0.1",
"node-fetch": "^2.2.1",
"tar": "4.4.6"
},
"devDependencies": {
"@types/debug": "^4.1.3",
"@types/execa": "^0.9.0",
"@types/fs-extra": "^5.0.5",
"@types/node-fetch": "^2.3.0",
"@types/tar": "^4.0.0",
"typescript": "3.5.2"
}
}

View File

@@ -0,0 +1,13 @@
package cowsay
import (
"fmt"
"net/http"
say "github.com/dhruvbird/go-cowsay"
)
// Handler function
func Handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, say.Format("cow:RANDOMNESS_PLACEHOLDER"))
}

View File

@@ -0,0 +1,11 @@
{
"version": 2,
"builds": [
{ "src": "index.go", "use": "@now/go" },
{ "src": "subdirectory/index.go", "use": "@now/go" }
],
"probes": [
{ "path": "/", "mustContain": "cow:RANDOMNESS_PLACEHOLDER" },
{ "path": "/subdirectory", "mustContain": "subcow:RANDOMNESS_PLACEHOLDER" }
]
}

View File

@@ -0,0 +1,13 @@
package subcow
import (
"fmt"
"net/http"
say "github.com/dhruvbird/go-cowsay"
)
// Handler function
func Handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, say.Format("subcow:RANDOMNESS_PLACEHOLDER"))
}

View File

@@ -0,0 +1 @@
module build-env

View File

@@ -0,0 +1,17 @@
package buildenv
import (
"fmt"
"net/http"
"os"
)
// Handler function
func Handler(w http.ResponseWriter, r *http.Request) {
rdm := os.Getenv("RANDOMNESS_BUILD_ENV")
if rdm == "" {
fmt.Println("No build env received")
}
fmt.Fprintf(w, rdm+":build-env")
}

View File

@@ -0,0 +1 @@
module env

View File

@@ -0,0 +1,17 @@
package env
import (
"fmt"
"net/http"
"os"
)
// Handler function
func Handler(w http.ResponseWriter, r *http.Request) {
rdm := os.Getenv("RANDOMNESS_ENV")
if rdm == "" {
fmt.Println("No env received")
}
fmt.Fprintf(w, rdm)
}

View File

@@ -0,0 +1,18 @@
{
"version": 2,
"builds": [
{
"src": "env/index.go",
"use": "@now/go"
}
],
"env": {
"RANDOMNESS_ENV": "RANDOMNESS_PLACEHOLDER"
},
"probes": [
{
"path": "/env",
"mustContain": "RANDOMNESS_PLACEHOLDER"
}
]
}

View File

@@ -0,0 +1,11 @@
package function
import (
"fmt"
"net/http"
)
// Handler function
func Handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "RANDOMNESS_PLACEHOLDER")
}

View File

@@ -0,0 +1,4 @@
{
"version": 2,
"builds": [{ "src": "index.go", "use": "@now/go" }]
}

View File

@@ -0,0 +1,7 @@
{
"version": 2,
"builds": [{ "src": "*.go", "use": "@now/go" }],
"env": {
"RANDOMNESS_ENV_VAR": "RANDOMNESS_PLACEHOLDER"
}
}

View File

@@ -0,0 +1,16 @@
package function
import (
"net/http"
"os"
"strconv"
)
// HandlerTest1 function
func HandlerTest1(w http.ResponseWriter, r *http.Request) {
rdm := os.Getenv("RANDOMNESS_ENV_VAR")
w.WriteHeader(401)
w.Header().Set("content-length", strconv.Itoa(len(rdm+":content-length")))
w.Write([]byte(rdm + ":content-length"))
}

View File

@@ -0,0 +1,12 @@
package function
import (
"net/http"
)
// HandlerTest2 function
func HandlerTest2(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Length", "2")
w.WriteHeader(401)
w.Write([]byte(""))
}

View File

@@ -0,0 +1,13 @@
package function
import (
"net/http"
"os"
)
// HandlerTest3 function
func HandlerTest3(w http.ResponseWriter, r *http.Request) {
rev := os.Getenv("RANDOMNESS_ENV_VAR")
w.WriteHeader(401)
w.Write([]byte(rev + ":content-length"))
}

View File

@@ -0,0 +1,16 @@
package cowsay
import (
"fmt"
"io/ioutil"
"net/http"
)
// Handler function
func Handler(w http.ResponseWriter, r *http.Request) {
bts, err := ioutil.ReadFile("templates/foo.txt")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
fmt.Fprintf(w, string(bts))
}

View File

@@ -0,0 +1,18 @@
{
"version": 2,
"builds": [
{
"src": "index.go",
"use": "@now/go",
"config": {
"includeFiles": ["templates/**"]
}
}
],
"probes": [
{
"path": "/",
"mustContain": "foobar from file"
}
]
}

View File

@@ -0,0 +1 @@
foobar from file

View File

@@ -0,0 +1,22 @@
package function
import (
"fmt"
"net/http"
)
// Person struct
type Person struct {
name string
age int
}
// NewPerson struct method
func NewPerson(name string, age int) *Person {
return &Person{name: name, age: age}
}
// H func
func H(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "RANDOMNESS_PLACEHOLDER")
}

View File

@@ -0,0 +1,5 @@
{
"version": 2,
"builds": [{ "src": "index.go", "use": "@now/go" }],
"probes": [{ "path": "/", "mustContain": "RANDOMNESS_PLACEHOLDER" }]
}

View File

@@ -0,0 +1,3 @@
module go-mod
go 1.12

View File

@@ -0,0 +1,11 @@
package handler
import (
"fmt"
"net/http"
)
// Handler func
func Handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "RANDOMNESS_PLACEHOLDER")
}

View File

@@ -0,0 +1,5 @@
{
"version": 2,
"builds": [{ "src": "index.go", "use": "@now/go" }],
"probes": [{ "path": "/", "mustContain": "RANDOMNESS_PLACEHOLDER" }]
}

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