Showing preview only (672K chars total). Download the full file or copy to clipboard to get everything.
Repository: apex/up
Branch: master
Commit: 66dbf6d5e836
Files: 230
Total size: 618.2 KB
Directory structure:
gitextract_3gd4es3i/
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE.md
│ └── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .goreleaser.yml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── History.md
├── LICENSE
├── Makefile
├── Readme.md
├── cmd/
│ ├── up/
│ │ └── main.go
│ └── up-proxy/
│ └── main.go
├── config/
│ ├── backoff.go
│ ├── backoff_test.go
│ ├── config.go
│ ├── config_test.go
│ ├── cors.go
│ ├── dns.go
│ ├── dns_test.go
│ ├── doc.go
│ ├── duration.go
│ ├── duration_test.go
│ ├── environment.go
│ ├── errorpages.go
│ ├── errorpages_test.go
│ ├── hooks.go
│ ├── hooks_test.go
│ ├── lambda.go
│ ├── lambda_test.go
│ ├── logs.go
│ ├── relay.go
│ ├── runtimes.go
│ ├── stages.go
│ ├── stages_test.go
│ ├── static.go
│ └── static_test.go
├── docs/
│ ├── 00-introduction.md
│ ├── 01-installation.md
│ ├── 02-aws-credentials.md
│ ├── 03-getting-started.md
│ ├── 04-configuration.md
│ ├── 05-runtimes.md
│ ├── 06-commands.md
│ ├── 07-guides.md
│ ├── 08-troubleshooting.md
│ ├── 09-faq.md
│ └── 10-links.md
├── go.mod
├── go.sum
├── handler/
│ ├── handler.go
│ ├── handler_test.go
│ └── testdata/
│ ├── node/
│ │ ├── app.js
│ │ └── up.json
│ ├── node-pkg/
│ │ ├── app.js
│ │ ├── package.json
│ │ └── up.json
│ ├── node-pkg-start/
│ │ ├── index.js
│ │ ├── package.json
│ │ └── up.json
│ ├── spa/
│ │ ├── app.js
│ │ ├── css/
│ │ │ ├── bar.css
│ │ │ └── foo.css
│ │ ├── index.html
│ │ └── up.json
│ ├── static/
│ │ ├── index.html
│ │ ├── style.css
│ │ └── up.json
│ ├── static-redirects/
│ │ ├── help/
│ │ │ └── ping/
│ │ │ └── alerts/
│ │ │ └── index.html
│ │ ├── index.html
│ │ └── up.json
│ └── static-rewrites/
│ ├── help/
│ │ └── ping/
│ │ └── alerts.html
│ ├── index.html
│ └── up.json
├── http/
│ ├── cors/
│ │ ├── cors.go
│ │ └── cors_test.go
│ ├── errorpages/
│ │ ├── errorpages.go
│ │ ├── errorpages_test.go
│ │ └── testdata/
│ │ ├── defaults/
│ │ │ ├── index.html
│ │ │ └── up.json
│ │ └── templates/
│ │ ├── 404.html
│ │ ├── 5xx.html
│ │ ├── index.html
│ │ └── up.json
│ ├── gzip/
│ │ ├── gzip.go
│ │ └── gzip_test.go
│ ├── headers/
│ │ ├── headers.go
│ │ ├── headers_test.go
│ │ └── testdata/
│ │ ├── _headers
│ │ ├── index.html
│ │ ├── style.css
│ │ └── up.json
│ ├── inject/
│ │ ├── inject.go
│ │ ├── inject_test.go
│ │ └── testdata/
│ │ ├── 404.html
│ │ ├── index.html
│ │ ├── style.css
│ │ └── up.json
│ ├── logs/
│ │ ├── logs.go
│ │ ├── logs_test.go
│ │ └── testdata/
│ │ ├── index.html
│ │ └── up.json
│ ├── poweredby/
│ │ ├── poweredby.go
│ │ ├── poweredby_test.go
│ │ └── testdata/
│ │ ├── index.html
│ │ └── up.json
│ ├── redirects/
│ │ ├── redirects.go
│ │ └── redirects_test.go
│ ├── relay/
│ │ ├── relay.go
│ │ ├── relay_test.go
│ │ └── testdata/
│ │ ├── basic/
│ │ │ ├── app.js
│ │ │ └── up.json
│ │ └── node/
│ │ ├── package.json
│ │ ├── server.js
│ │ └── up.json
│ ├── robots/
│ │ ├── robots.go
│ │ ├── robots_test.go
│ │ └── testdata/
│ │ ├── index.html
│ │ └── up.json
│ └── static/
│ ├── static.go
│ ├── static_test.go
│ └── testdata/
│ ├── dynamic/
│ │ ├── app.js
│ │ ├── public/
│ │ │ └── css/
│ │ │ └── style.css
│ │ └── up.json
│ └── static/
│ ├── index.html
│ ├── style.css
│ └── up.json
├── install.sh
├── internal/
│ ├── account/
│ │ ├── account.go
│ │ └── cards.go
│ ├── cli/
│ │ ├── app/
│ │ │ └── app.go
│ │ ├── build/
│ │ │ └── build.go
│ │ ├── config/
│ │ │ └── config.go
│ │ ├── deploy/
│ │ │ └── deploy.go
│ │ ├── disable-stats/
│ │ │ └── disable-stats.go
│ │ ├── docs/
│ │ │ └── docs.go
│ │ ├── domains/
│ │ │ └── domains.go
│ │ ├── logs/
│ │ │ └── logs.go
│ │ ├── metrics/
│ │ │ └── metrics.go
│ │ ├── prune/
│ │ │ └── prune.go
│ │ ├── root/
│ │ │ └── root.go
│ │ ├── run/
│ │ │ └── run.go
│ │ ├── stack/
│ │ │ └── stack.go
│ │ ├── start/
│ │ │ └── start.go
│ │ ├── team/
│ │ │ └── team.go
│ │ ├── upgrade/
│ │ │ └── upgrade.go
│ │ ├── url/
│ │ │ └── url.go
│ │ └── version/
│ │ └── version.go
│ ├── colors/
│ │ └── colors.go
│ ├── errorpage/
│ │ ├── errorpage.go
│ │ ├── errorpage_test.go
│ │ ├── template.go
│ │ └── testdata/
│ │ ├── 200.html
│ │ ├── 404.html
│ │ ├── 4xx.html
│ │ ├── 500.html
│ │ ├── error.html
│ │ ├── other.html
│ │ └── somedir/
│ │ └── test.html
│ ├── header/
│ │ ├── header.go
│ │ └── header_test.go
│ ├── inject/
│ │ ├── inject.go
│ │ └── inject_test.go
│ ├── logs/
│ │ ├── logs.go
│ │ ├── parser/
│ │ │ ├── ast/
│ │ │ │ └── ast.go
│ │ │ ├── grammar.peg
│ │ │ ├── grammar.peg.go
│ │ │ ├── parser.go
│ │ │ └── parser_test.go
│ │ ├── text/
│ │ │ ├── text.go
│ │ │ └── text_test.go
│ │ └── writer/
│ │ ├── writer.go
│ │ └── writer_test.go
│ ├── metrics/
│ │ └── metrics.go
│ ├── progressreader/
│ │ └── progressreader.go
│ ├── proxy/
│ │ ├── bin/
│ │ │ └── bin.go
│ │ ├── event.go
│ │ ├── event_test.go
│ │ ├── lambda.go
│ │ ├── request.go
│ │ ├── request_test.go
│ │ ├── response.go
│ │ └── response_test.go
│ ├── redirect/
│ │ ├── redirect.go
│ │ └── redirect_test.go
│ ├── setup/
│ │ └── setup.go
│ ├── shim/
│ │ ├── index.js
│ │ └── shim.go
│ ├── signal/
│ │ └── signal.go
│ ├── stats/
│ │ └── stats.go
│ ├── userconfig/
│ │ ├── userconfig.go
│ │ └── userconfig_test.go
│ ├── util/
│ │ ├── util.go
│ │ └── util_test.go
│ ├── validate/
│ │ └── validate.go
│ └── zip/
│ ├── testdata/
│ │ ├── .file
│ │ ├── .upignore
│ │ ├── Readme.md
│ │ ├── bar.js
│ │ ├── foo.js
│ │ └── index.js
│ ├── zip.go
│ └── zip_test.go
├── platform/
│ ├── aws/
│ │ ├── cost/
│ │ │ ├── cost.go
│ │ │ ├── cost_test.go
│ │ │ └── domains.go
│ │ ├── domains/
│ │ │ └── domains.go
│ │ ├── logs/
│ │ │ └── logs.go
│ │ ├── regions/
│ │ │ ├── regions.go
│ │ │ └── regions_test.go
│ │ └── runtime/
│ │ └── runtime.go
│ ├── event/
│ │ └── event.go
│ └── lambda/
│ ├── lambda.go
│ ├── lambda_test.go
│ ├── metrics.go
│ ├── prune.go
│ ├── reporter/
│ │ └── reporter.go
│ └── stack/
│ ├── resources/
│ │ ├── resources.go
│ │ └── resources_test.go
│ ├── stack.go
│ ├── stack_test.go
│ ├── status.go
│ └── status_test.go
├── platform.go
├── reporter/
│ ├── discard/
│ │ └── discard.go
│ ├── plain/
│ │ └── plain.go
│ ├── reporter.go
│ └── text/
│ └── text.go
└── up.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
internal/proxy/bin/bin_assets.go filter=lfs diff=lfs merge=lfs -text
================================================
FILE: .github/FUNDING.yml
================================================
github: tj
================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
## Prerequisites
* [ ] I am running the latest version. (`up upgrade`)
* [ ] I searched to see if the issue already exists.
* [ ] I inspected the verbose debug output with the `-v, --verbose` flag.
* [ ] Are you an Up Pro subscriber?
## Description
Describe the bug or feature.
## Steps to Reproduce
Describe the steps required to reproduce the issue if applicable.
## Slack
Join us on Slack https://chat.apex.sh/
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
Open an issue and discuss changes before spending time on them, unless the change is trivial or an issue already exists.
Use "VERB some thing here. Closes #n" to close the relevant issue, where VERB is one of:
- add
- remove
- change
- refactor
If the change is documentation related prefix with "docs: ", as these are filtered from the changelog.
docs: add ~/.aws/config
Run `dep ensure` if you introduce any new `import`'s so they're included in the ./vendor dir.
================================================
FILE: .gitignore
================================================
.envrc
node_modules/
.shards/
lib
vendor/
testing
up-proxy
!cmd/up-proxy
dist
.idea
.vscode
.DS_Store
internal/proxy/bin/bin_assets.go
internal/shim/bindata.go
================================================
FILE: .goreleaser.yml
================================================
build:
main: cmd/up/main.go
binary: up
goos:
- darwin
- linux
- windows
- freebsd
- netbsd
- openbsd
goarch:
- amd64
- 386
ignore:
- goos: darwin
goarch: 386
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^refactor'
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant 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 tj@apex.sh. The project team will review and investigate all complaints, and will respond in a way that it deems 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/
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
Before contributing to Up you'll need a few things:
- Install [Golang 1.11](https://golang.org/dl/) for that Go thing if you don't have it
The following are optional:
- Install [pointlander/peg](https://github.com/pointlander/peg) if you're working on the log grammar
- Install [shuLhan/go-bindata](https://github.com/shuLhan/go-bindata) if you need to bake `up-proxy` into `up`
## Setup
Grab Up:
```
$ go get github.com/apex/up
```
Change into the project:
```
$ cd $GOPATH/src/github.com/apex/up
```
## Testing
```
$ make test
```
## Layout
Although Up is not provided as a library it is structured as if it was, for organizational purposes. The project layout is loosely:
- *.go – Primary API
- [reporter](reporter) – Event based CLI reporting
- [platform](platform) – Platform specifics (AWS Lambda, Azure, Google, etc)
- [internal](internal) – Internal utilities and lower level tooling
- [http](http) – HTTP middleware for up-proxy
- [handler](handler) – HTTP middleware aggregate, effectively the entire proxy
- [docs](docs) – Documentation used to generate the static site
- [config](config) – Configuration structures and validation for `up.json`
- [cmd](cmd) – Commands, where `up` is the CLI and `up-proxy` is serving requests in production
Note that this is just a first pass, and the code / layout will be refactored. View [Godoc](http://godoc.org/github.com/apex/up) for more details of the internals.
## Proxy
One oddity is that the `up-proxy` is baked into `up`. Yes there's a binary within the binary :) – this is so `up` can inject the proxy before deploying your function to Lambda.
The proxy accepts AWS Lambda events from API Gateway, translates them to HTTP, and sends a request to your application, then translates it back to an event that API Gateway understands.
Reverse proxy features such as URL rewriting, gzip compression, script injection, error pages and others are also provided in `up-proxy`.
## Roadmap
Up uses GitHub issue tracking and milestones for its loose roadmap. I highly recommend installing Zenhub (https://www.zenhub.com/) as well, however I primarily organize by milestones and labels for now.
## Releases
Notes for myself:
- Run `make clean build` if necessary to re-build the proxy
- Run `git changelog`
- Run `git release`
- Run `make release`
- Re-build documentation
- Notes about any backwards compat issues, migration, IAM policy changes
- Adjust schemastore JSON schema if necessary
================================================
FILE: History.md
================================================
v1.7.1 / 2021-09-27
===================
* fix Lambda state issue by waiting for an Active state. Closes #833
v1.7.0-pro / 2020-10-07
=======================
* add support for tagging resources
v1.7.0 / 2020-10-07
===================
* add `lambda.timeout` back, defaulting to 60s. Closes #814
* change LICENSE, commercial use requires a subscription
v1.6.2 / 2020-09-23
===================
* Rebuild to decrease the binary filesize bloat
v1.6.2-pro / 2020-09-23
=======================
* Rebuild to decrease the binary filesize bloat
v1.6.1-pro / 2020-09-23
=======================
* Rebuild the proxy to include X-Up-Timeout
v1.6.0-pro / 2020-09-23
=======================
* Rebase
v1.6.0 / 2020-09-23
===================
* add support for X-Up-Timeout header field. Closes #815
* change id field to request_id
v1.5.2 / 2020-06-08
===================
* add Hong Kong region. Closes #804
* fix `up stack` panic due to missing res.DistributionDomainName. Closes #809
v1.5.1-pro / 2019-12-17
=======================
* Rebase
v1.5.1 / 2019-12-17
===================
* fix overriding of `lambda.runtime`
v1.5.0-pro / 2019-11-21
=======================
* Rebase
v1.5.0 / 2019-11-21
===================
* change error_pages to be disabled by default, use `enable: true` to add them
* fix stack delete behavior to not attempt to delete configured lambda roles. (Closes #787) (#788)
v1.4.1-pro / 2019-10-23
=======================
* fix: add blacklisting of up-env.json so it cannot be .upignored
v1.4.0-pro / 2019-10-23
=======================
* change warming functions to nodejs10.x, existing ones will be fine, as AWS doesn't
actually stop these functions, they just discontinue updating/creation
* Rebase
v1.4.0 / 2019-10-23
===================
* refactor nodejs shim to work on node8 or node10
* change default runtime to nodejs10.x (potentially breaking change, depends on your application). Closes #784
v1.3.0-pro / 2019-05-30
=======================
* add wrapping of env var logs with `logs.disable` check
v1.3.0 / 2019-05-30
===================
* add ./vendor to excluded directories by default
* refactor: regenerate parser with updated peg
* remove discount message, it didn't work
v1.2.0 / 2019-04-20
===================
* add 60% coupon
v1.2.0-pro / 2019-04-05
=======================
* add regional DNS with latency-based routing
* add `--region` flag for every command to override region id
v1.1.3-pro / 2019-04-02
=======================
* Rebase
v1.1.3 / 2019-04-02
===================
* update tj/aws dependency for duplicate logs fix
v1.1.2-pro / 2019-03-29
=======================
* Rebase
v1.1.2 / 2019-03-29
===================
* fix: update tj/aws dependency for ThrottlingException logs exception
v1.1.1-pro / 2019-03-23
=======================
* update warming function to nodejs8.10 to prevent EOL warning from AWS
v1.1.0-pro / 2019-03-04
===================
* add file based environment variables, removing the size restrictions
v1.0.0-pro / 2019-02-26
===================
* add regional endpoint support
v0.9.1-pro / 2019-01-21
=======================
* add sorting of env vars. Closes #750
v0.9.0-pro / 2018-12-13
=======================
* add Lambda layer support. Closes #743
v0.8.1-pro / 2018-12-11
=======================
* improve `up env export` performance, no longer linear time
* fix `up deploys` error when the stage is not deployed. Closes #716
* Rebase
v0.8.1 / 2018-12-11
===================
* update tj/aws for bug preventing all logs from being returned. Closes #733
* add deploy --no-build flag for skipping build hooks. Closes #730
* Release v0.8.0-pro
v0.8.0-pro / 2018-12-06
=======================
* improve `up env export` performance, no longer linear time
* fix `up deploys` error when the stage is not deployed. Closes #716
v0.8.0 / 2018-12-04
===================
* add endpoint URL to the deployment output
* add deploy stage to the deployment output
* add msg about Up Pro
* remove "not info" log example. Closes #724
* fix typo in deploy example. Closes #718
* fix: use crystallang/crystal for Crystal builds (#713)
v0.7.8-pro / 2018-09-24
=======================
* add `up env export` command for exposing env vars to shell scripts
v0.7.7-pro / 2018-09-17
=======================
* Rebase
v0.7.7 / 2018-09-17
===================
* update go-update dependency for copy regression
v0.7.5-pro / 2018-09-17
=======================
* Rebase
v0.7.5 / 2018-09-17
===================
* update go-update dependency for rename() to copy replacement
v0.7.4-pro / 2018-09-16
=======================
* add baked in env vars from SSM, env vars are no longer loaded at runtime. Closes #547
v0.7.4 / 2018-09-16
===================
* add request id to proxy errors
* fix missing lambda configurations costs. (#703)
* fix order relay errors so timeouts are returned first (leads to better error messages)
v0.7.3-pro / 2018-08-08
=======================
* Rebase
v0.7.3 / 2018-08-08
===================
* fix crash recovery in lambda, bug was introduced in v0.7.0
* update cors middleware for security when using allow-origin * and allow-credentials
v0.7.2-pro / 2018-07-23
=======================
* Rebase
v0.7.2 / 2018-07-23
===================
* add vpc stage override support. Closes #689
v0.7.1-pro / 2018-07-12
=======================
* Rebase
v0.7.1 / 2018-07-12
===================
* fix initial IAM role creation waiting due to error response change
v0.7.0-pro / 2018-07-11
=======================
* Rebase
v0.7.0 / 2018-07-11
===================
* add in-flight request timeouts.
* remove retries
* refactor crash recovery to be more robust
v0.6.8-pro / 2018-06-07
=======================
* Rebase
v0.6.8 / 2018-06-07
===================
* fix multiple set-cookie API Gateway limitation for real (previous had a bug)
v0.6.7-pro / 2018-06-07
=======================
* fix s3 acceleration update with existing S3 buckets
* Rebase
v0.6.7 / 2018-06-07
===================
* add striping of @owner/repo@ portion of Lerna tags. Closes #670
* fix multiple set-cookies API Gateway limitation with casing hack
* fix deployment with empty Git repo
* update AWS SDK versions for assuming roles. (#668)
v0.6.6-pro / 2018-05-24
=======================
* Rebase
v0.6.6 / 2018-05-24
===================
* add vpc support. Closes #281
* fix Crystal build on Linux: PWD => pwd (#664)
v0.6.5-pro / 2018-05-16
=======================
* Rebase
v0.6.5 / 2018-05-16
===================
* add hidden disable stats command (#659)
* add X-Context header field. Closes #657
* fix CORS header fields from being clobbered by error pages. Closes #661
v0.6.4-pro / 2018-05-09
=======================
* add deployment size to `up deploys` output
* add asterisk to denote current version in `up deploys` due to rollbacks
* Rebase
v0.6.4 / 2018-05-09
===================
* add support for customizing the Lambda function IAM role policy. Closes #539
* add support for specifying dns zone, and disabling it. Closes #536
* add support for updating the role policy upon deploy
* change default prune retention to 30 versions
v0.6.3-pro / 2018-05-02
=======================
* add deployment size to `up deploys` output
* add asterisk to denote current version in `up deploys` due to rollbacks
* Rebase
v0.6.3 / 2018-05-02
===================
* add `--stage` flag to `up build`
* add `--stage` flag to `up run`
* change logs, metrics, and url commands to use `-s` flag for stage. Closes #371 (BREAKING)
v0.6.2-pro / 2018-04-25
=======================
* Rebase
v0.6.2 / 2018-04-25
===================
* add up prune `--stage` flag. Closes #647
* add `up` to ignore whitelist by default
* remove retries on 5xx. Closes #485
* fix login bug preventing `--email` from overriding the active team email
v0.6.1-pro / 2018-04-16
=======================
* Rebase
v0.6.1 / 2018-04-16
===================
* add guard against `up stack plan` before `up`
* add `prune` command to remove old releases from S3. Closes #322
v0.6.0-pro / 2018-04-10
=======================
* Rebase
v0.6.0 / 2018-04-10
===================
* add annual plan subscription option
v0.5.17-pro / 2018-04-09
========================
* Rebase
v0.5.14 / 2018-04-09
====================
* add start command --stage flag. Closes #639
* fix scenario where JSON logs have invalid .level values
* refactor: add note about running `up upgrade` after subscribing
v0.5.16-pro / 2018-04-07
========================
* Rebase
v0.5.13 / 2018-04-07
====================
* fix "Error: fetching git commit: " error when Git is missing from the system
v0.5.15-pro / 2018-04-03
========================
* Rebase
v0.5.12 / 2018-04-03
====================
* add support for defining `lambda.runtime`
* add robots middleware (#627)
* change default runtime to nodejs 8.10
* refactor: remove redundant wrapping of "deploying" message
v0.5.11 / 2018-03-19
====================
* fix: update tj/go for Git signer fix
v0.5.12-pro / 2018-03-19
========================
* Rebase
v0.5.10 / 2018-03-19
====================
* fix: update tj/go for Git subject fix
v0.5.11-pro / 2018-03-16
========================
* refactor: add mapping of Alarm and Subscription for `up stack plan` output
* refactor: add .duration to Deploys track call
* Rebase
v0.5.9 / 2018-03-16
===================
* add support for serving static files with dynamic applications. Closes #174
v0.5.10-pro / 2018-03-15
===================
* add nicer `up rollback` failure message when version does not exist
* add git sha and tag support to `up rollback`
* add `up deploys` for listing deployments and versions
* fix log filter relational and equality operators with strings
v0.5.8 / 2018-03-15
===================
* fix log filter relational and equality operators with strings
v0.5.7 / 2018-03-15
===================
* add git versioning, used for Pro rollbacks and deployment changelog. Closes #100
v0.5.9-pro / 2018-03-09
=======================
* add stage overrides for lambda warming. Closes #615
v0.5.8-pro / 2018-03-05
=======================
* Rebase
v0.5.6 / 2018-03-05
===================
* add support for upgrading in-place up(1). Closes #607
* add CI specific upgrade to avoid progress bar
* fix: remove IsNotFound error check, masks the real issue
v0.5.7-pro / 2018-03-03
=======================
* Rebase
v0.5.5 / 2018-03-03
===================
* fix: improve idempotency of stack deletion
* docs: add sns to policy (necesary for Pro's alerting)
v0.5.6-pro / 2018-03-02
=======================
* add support for `=` delimited env vars ("FOO=bar")
* add support for passing multiple env vars to `up env set`
* add support for overriding envs for `up start` (`$ URL=xxx up start`)
v0.5.5-pro / 2018-03-01
=======================
* Rebase
v0.5.4 / 2018-03-01
===================
* add default `up start` command for Go and Crystal. Closes #581
* add log stage field to all logs, not just request-level
* add owner to `up team` output
* fix `up metrics` output, should be stage-specific, not global
* refactor: add humanized error when the stack (app) does not exist
* refactor: add stage name to beginning of log line instead of as a field
* refactor: add os/arch to debug logs to aid in support
* refactor: add alias upserts when updating (merged from pro)
* refactor: remove a redundant "deploying" error wrap
* refactor: tweak some error messages
* refactor: change perms of up.json to 0644. Closes #601
v0.5.4-pro / 2018-02-23
=======================
* Rebase
v0.5.3 / 2018-02-23
===================
* fix log flushing, make it synchronous. Closes #545
* docs: add changelog link
* docs: add mention of BINDIR
v0.5.3-pro / 2018-02-22
=======================
* add 1s sleep to /_ping endpoint for improved warming concurrency accuracy
* add `up env get` command for fetching a value
* Rebase
v0.5.2 / 2018-02-22
===================
* remove unsetting of `AWS_*` vars for now, reverts #590 fix
v0.5.1 / 2018-02-22
===================
* add function version to `up stack` output
* change `up team ci` to output base64 encoded config
* change UP_CONFIG to attempt base64-decode when not JSON (#594)
* fix proxy.command overrides. Closes #597
* fix .profile precedence. Closes #590
v0.5.2-pro / 2018-02-12
=======================
* add active warming support
* Rebase
v0.5.1-pro / 2018-02-08
=======================
* add `up env` --decrypt flag for emergencies when you need to list
v0.5.0-pro / 2018-02-08
=======================
* add nicer env var logging with masking
* add custom stage support to `up env`
* add message for `up env` when no vars are defined
* fix rollbacks using -previous aliases
* Rebase
v0.5.0 / 2018-02-08
===================
* add custom stage support. Closes #326
* add customer feedback option when unsubscribing
* add `up team card change` command for updating the CC
* remove sourcing of .gitignore. Closes #557
* remove development as a remote stage (now local only). Closes #563
* refactor: add separator to make log message more obvious
* refactor: add hiding of cursor when verifying email
* refactor retry labels below s3 uploads (improves performance)
* refactor: add nicer output when using `up url -c`
v0.4.12-pro / 2018-02-01
========================
* Rebase
v0.4.12 / 2018-02-01
====================
* add -o, --open to `up start` for opening in the browser
* add `logs.{stdout,stderr}` for configuring log levels. Closes #565
* add `-c, --command` flag to `up start`. Closes #564
* fix panic when .domain is missing from a stage, as it is now optional. Closes #567
* docs: add example .upignore for static sites
* docs: fix team members rm example. Closes #562
* docs: add "Unable to associate certificate error" to troubleshooting
* docs: add gin example
v0.4.11-pro / 2018-01-29
========================
* Rebase
v0.4.11 / 2018-01-29
====================
* add development config overrides to `up start`
* add the ability to override .proxy.command at the stage level
* docs: mention that the WHOIS contact emails are used
* docs: fix link for acm validation
* docs: tweak
* docs: add guide for hot reloading
* docs: remove old "Local Environment Variables" guide section
* docs: add gin example for dev command
v0.4.10-pro / 2018-01-25
========================
* Rebase
v0.4.10 / 2018-01-25
====================
* refactor to use a single account/region level S3 bucket, not per-project. Closes #550
* fix base64 encoded json when params are provided
v0.4.9-pro / 2018-01-24
=======================
* Rebase
v0.4.9 / 2018-01-24
===================
* revert tj/go-update, causing permission issues
v0.4.8-pro / 2018-01-24
=======================
* fix validating after overrides
v0.4.8 / 2018-01-24
===================
* update tj/go-update for copy instead of rename. Closes #329
* update api client for RemoveMember() json body change
* docs: add missing ssm to policy
* docs: add note about 404s
v0.4.7-pro / 2018-01-19
=======================
* add rollback support
* fix upgrade deduplication due to version having -pro suffix
v0.4.7 / 2018-01-19
===================
* add optimization of ACM certificate creation. Closes #452
* add `development` Lambda alias. Closes #542
* add start of stage overrides for config. Closes #314
* add support for upgrading to a specific version of Up. Closes #387
* update go-cli-analytics for disabled segment cli logging
* refactor handler.New() to accept an http.Handler
* refactor logging configuration, delegate isatty check etc
* refactor: move internal logs to tj/aws
* refactor platform integration quickly
v0.4.6-pro / 2018-01-03
=======================
* add rollback support
v0.4.5-pro / 2018-01-03
=======================
* add s3 acceleration
* fix a log call in runtime
v0.4.6 / 2018-01-03
===================
* add support for Clojure with Leiningen (#522)
* add coupon price adjustment to `up team` output. Closes #516
* add support for overriding NODE_ENV. Closes #505
* add error for multiple regions, until the feature is complete
* add Paris region
* change `error_pages` to be enabled by default for text/html requests
* refactor `handler.New()` to accept config
* refactor signal handling
* refactor: update api client
* refactor: remove unnecessary code (#517)
* refactor login and provide a non-error when you are already signed in
* fix s3 buckets, should be scoped to region
* fix output flickering before build output
* fix: add a ! in front of build.gradle for forced inclusion (#518)
v0.4.4-pro / 2017-12-22
=======================
* Rebase
v0.4.5 / 2017-12-22
===================
* add new subscribe workflow
* add team CRUD and rename `up account` to `up team`. Re #410
* refactor: replace `kingpin.CmdClause` with `kingpin.Cmd`
* refactor: use `time.Since` for time difference (#509)
* refactor: add "ci" to stats so we can see how often CI is used
* refactor: simplify start of plain reporter (#508)
* refactor: a typo fix in http/relay (#507)
* refactor: drop unnecessary `fmt.Sprintf` in reporter/text (#506)
* refactor: simplify personal team check (#500)
v0.4.3-pro / 2017-12-19
=======================
* Rebase
v0.4.4 / 2017-12-19
===================
* fix `up stack status` scenario before a domain is mapped
* refactor: config, simplify unmarshal json of dns. Closes #497
v0.4.2-pro / 2017-12-19
=======================
* Rebase
v0.4.3 / 2017-12-19
===================
* refactor: shorten s3 bucket name
v0.4.1-pro / 2017-12-19
=======================
* remove 0.0.0 hack for pro upgrade
* Rebase
v0.4.2 / 2017-12-19
===================
* change to disallow uppercase characters in .name. Closes #498
* refactor: add humanized string for the current version
* refactor: add config/backoff.go
v0.4.1 / 2017-12-18
===================
* fix upgrades to pro when version matches
v0.4.0-pro / 2017-12-18
=======================
* add slack `gif` option
* add slack alert support
* add initialization of env vars for builds. Closes #458
* add initialization of env vars for deployments. Closes #458
* add initialization of env vars for `up start`. Closes #458
* add `{alerts,actions}_count` to Deploy track
* change missing default to `notBreaching`
* refactor: add title casing to `up env` output
v0.4.0 / 2017-12-18
===================
* add unquoted string literals for log queries
* add log string sans-quote literal. Closes #461
* add log message field equality short-hand. Closes #372
* add CI=true check for plain text output. Re #422
* add --format=plain for CI. Closes #422
* add setup workflow for creating up.json and doing the initial deploy. Closes #482, #386
* add `NODE_ENV` population by default
* add env vars to `up start`
* add s3 deployments. Closes #272
* add cloudfront endpoint to `up stack` output. Closes #459
* change logs to purple (match everything else)
* change how expanded log mode looks
* remove `--region` flag
* fix upgrade messages for OSS -> Pro
* fix clearing state in text reporter
v0.3.0-pro / 2017-12-03
=======================
* add sms alerting support
v0.2.0-pro / 2017-12-03
=======================
* add hosted email alerting for nicer formatting
* change alert default `period` to 1m
v0.1.11-pro / 2017-11-30
========================
* add support for listing secrets without last modified user name
* fix secrets listing when user ARN is not present. Closes #433
* refactor alerting into new resources sub-pkg
* Rebase
v0.3.8 / 2017-11-30
===================
* add {pre,post}{build,deploy} hooks
* add flushing of logs after [re]start. See #359
* add "w" for week to `ParseDuration()`
* refactor: fix Map for now
* refactor: use effective domain for CFN id
* refactor: add test for existing zone and apex domain
* refactor: add test for existing zone
* refactor: add test coverage for CFN resources
* fix hosted zones for sub-domains. Closes #447
* fix `.type` precedence when runtime files are detected. Closes #436
v0.3.7 / 2017-11-24
===================
* add date formatting for older logs
* remove project init from `up account login`
* fix timestamps for lambda plain text logs
v0.1.10-pro / 2017-11-23
========================
* add support for listing secrets without last modified user name
* fix secrets listing when user ARN is not present. Closes #433
* Rebase
v0.3.6 / 2017-11-22
===================
* fix subscription without coupon
v0.1.9-pro / 2017-11-21
=======================
* Rebase
v0.3.5 / 2017-11-21
===================
* add `stage` field to all log contexts (fixes log filtering against `production`)
* fix DNS record logical id collision. Closes #420
* refactor `up stack` output
v0.1.8-pro / 2017-11-20
=======================
* add TreatMissingData as ignore by default
v0.1.7-pro / 2017-11-20
=======================
* fix email alerting
v0.1.6-pro / 2017-11-20
=======================
* add initial alerting support
v0.1.5-pro / 2017-11-20
=======================
* fix "development" env support for `up env`
* Rebase
v0.3.4 / 2017-11-20
===================
* add `up accounts ci` and --copy to help with setting up UP_CONFIG for CI
* fix domain verification for ssl certificates. Closes #425
* update tj/kingpin for arg output formatting fix
v0.1.4-pro / 2017-11-18
=======================
* Rebase
v0.3.3 / 2017-11-18
===================
* fix zip paths on Windows. Closes #418
v0.1.3-pro / 2017-11-18
=======================
* Rebase
v0.3.2 / 2017-11-18
===================
* add support for UP_CONFIG from environment
* add `up docs` command back for opening documentation in the browser
* change logs `--since` default to 1 day
* fix intermittent metrics failure. Closes #414
v0.3.1 / 2017-11-15
===================
* add `up account` and sub-commands
* add extended duration parsing for `--since` flags. Closes #401
* add log expansion. Closes #399
* add Content-Length request header
* add request logs
* add pom.xml and build.grade to whitelist which cannot be ignored
* change metrics `--since` default to 1 month
* refactor: remove .size defaulting of 0
* refactor progress bar with diffing, making it more responsive
* fix missing logs when json does not take the shape of a log. Closes #411
v0.1.2-pro / 2017-11-15
=======================
* fix missing logs when json does not take the shape of a log. Closes #411
v0.1.0-pro / 2017-11-15
=======================
* add `env` command
v0.3.0 / 2017-10-19
===================
* add listing of NS records in `up stack` output
* add changelog exclusion of docs: for goreleaser
* add nicer domain registration form
* update tj/survey for color changes
* update dependencies
* refactor: add more properties to deploy track
* refactor: tweak cert email output
* refactor: exclude Makefile from todo target (#382)
* refactor: add stack to ResourceType mapping
* refactor reporting for aws types
* fix install.deps target
* fix case where improper cert is created due to second-level domain (.co.uk). Closes #350
* fix hosted zone regression introduced by e8a33a3
* fix permission issues for static file serving. Closes #385
* docs: add domains command
* docs: move policy behind a details element for collapsing
* docs: tweak for domain changes
v0.2.10 / 2017-10-13
====================
* add flushing of proxy logs after response. Closes #370
* add periodic flushing of proxy logs for `up start`. Closes #369
* add internal text handler to `up start`
v0.2.9 / 2017-10-10
===================
* fix: disable relay keep alive conns, they interact poorly with suspension (#365)
v0.2.8 / 2017-10-09
===================
* fix missing body regression
v0.2.7 / 2017-10-09
===================
* update go-apex dep
* update lambda shim with concurrency support
* fix: implement proxy GetBody to allow for re-reading request bodies. Closes #363
* remove .lambda.timeout, replace with .proxy.timeout
v0.2.6 / 2017-09-29
===================
* add `proxy.retry` option defaulting to `true`
* add UP_STAGE to `up start`
* add stage `.path` basepath support
* fix install script for Yosemite. Closes #345
v0.2.5 / 2017-09-20
===================
* add more relay logs
* docs: refactor
* add .proxy.timeout for requests and retries. Closes #335
* refactor: remove a duplicate test
* add retrying of 5xx errors for idempotent requests. Closes #214
* docs: change chown to bin only. Closes #337
* docs: add deletion info
* docs: add more stage info
* docs: add guide for full app
* docs: add note about CF provisioning
* docs: add stage section
* docs: refactor dns section
* docs: remove references to `certs`
* docs: remove "coming soon"
* docs: tweak faq
* docs: add vendor mention
* update Bowery/prompt dep and fix spacing
* fix 404 checksum not found (#331)
* docs: add missing package comments
* docs: add missing package comments
* docs: add note about omitting proxy bin changes
v0.2.4 / 2017-09-15
===================
* add custom domain support
* add Up version to the -v debug output
* add support for JSON log lines, captured and translated to the internal format
* add support for indented log lines to be captured as a single message
* add sub-process cleanup and grace period. Closes #311
* add `ssm:GetParametersByPath` to the function policy
* add UP_STAGE env var. Closes #200
* change default `proxy.listen_timeout` to 15
* fix gzip handling when previously compressed. Closes #328
* fix ignoring of .pypath
v0.2.3 / 2017-09-05
===================
* fix rewrite content-type. Closes #304
v0.2.2 / 2017-09-05
===================
* add logging of log query for debugging
* add stage shorthands to log grammar. Closes #286
* add bytes / duration units to logging grammar. Closes #283
* add humanization of .size field in logs. Closes #252
* add support for checking domain availability and registration. Closes #159
* add support for multiple hook commands with arrays. Closes #127
* add forced inclusion of ./server
* add eu-west-2 to the regions list. Closes #280
* fix ignoring of node_modules dotfiles (removed .bin by accident etc)
* fix stage validation, move before building zip
* fix support for other authentication schemes. Closes #287
* fix dns record .ttl default
* rename .proxy.timeout to .proxy.listen_timeout (BREAKING)
* remove `docs` command
* remove omission of stage from logs
v0.2.1 / 2017-08-25
===================
* fix missing param in Infof log call, outputting `MISSING`
v0.2.0 / 2017-08-25
===================
* add hiding of cursor for stack delete and apply
* add support for configuring proxy timeout (#273)
* add cost to metrics output. Closes #204
* add: ignore dotfiles by default
* add nicer formatting for numeric metrics
* add build command. Closes #257
* add validation of stage name to `url` and `deploy`. Closes #261
* remove .npmignore support. Closes #270
v0.1.12 / 2017-08-23
=====================
* add some basic formatting to `up stack plan`
* rename `up stack show` to `up stack status`
* fix hard-coded versions for stack updates
v0.1.11 / 2017-08-22
====================
* add support for regions defined in `~/.aws/config`
* add `up stack plan` and `up stack apply` support. Closes #115
* add environment variables to hooks when performing builds etc
* fix support for implicit `app.js` when `package.json` is present without a `start` script defined
v0.1.10 / 2017-08-15
====================
* add default of ./server back for when source is omitted (main.go for example)
* add `**` .upignore support
* add forced inclusion of Up's required files
* add support for omitting `node_modules` when using Browserify or Webpack
* update go-archive for gitignore parity improvements
v0.1.9 / 2017-08-14
===================
* add -modtime 0
* add smaller progress bar for initial stack
* revert "add error when a dir does not look like a valid project. Closes #197"
* caused an issue if you ignore *.go for example, not robust enough
v0.1.8 / 2017-08-14
===================
* add error when a dir does not look like a valid project. Closes #197
* add convenience make targets `install` and `install.deps`
* add note about AWS_PROFILE in getting started. Closes #230
* add python projects with a requirements.txt
* add install.sh
* fix greedy default error page, add option to explicitly enable. Closes #233
* fix exec bit on windows. Closes #225
* fix python overriding of custom command
* remove default of ./server
* remove "-api" suffix from IAM role (breaking change)
* refactor NewLogs() to properly delegate the error instead of panic
v0.1.7 / 2017-08-12
===================
* add size of code/zip before attempting deploy. Closes #222
* add better description for --force
* change default timeout to 15s from 5s
* change default memory from 128 to 512 (Node.js require() is slow)
* fix relay timeout (lack of an error)
================================================
FILE: LICENSE
================================================
The MIT License
Copyright (c) 2020 TJ Holowaychuk tj@tjholowaychuk.com
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: Makefile
================================================
GO ?= go
# Build all files.
build:
@echo "==> Building"
@$(GO) generate ./...
.PHONY: build
# Install from source.
install:
@echo "==> Installing up ${GOPATH}/bin/up"
@$(GO) install ./...
.PHONY: install
# Run all tests.
test: internal/proxy/bin/bin_assets.go
@$(GO) test -timeout 2m ./... && echo "\n==>\033[32m Ok\033[m\n"
.PHONY: test
# Run all tests in CI.
test.ci: internal/proxy/bin/bin_assets.go
@$(GO) test -v -timeout 5m ./... && echo "\n==>\033[32m Ok\033[m\n"
.PHONY: test.ci
internal/proxy/bin/bin_assets.go:
@$(GO) generate ./...
# Show source statistics.
cloc:
@cloc -exclude-dir=vendor,node_modules .
.PHONY: cloc
# Release binaries to GitHub.
release: build
@echo "==> Releasing"
@goreleaser -p 1 --rm-dist --config .goreleaser.yml
@echo "==> Complete"
.PHONY: release
# Show to-do items per file.
todo:
@rg TODO:
.PHONY: todo
# Show size of imports.
size:
@curl -sL https://gist.githubusercontent.com/tj/04e0965e23da00ca33f101e5b2ed4ed4/raw/9aa16698b2bc606cf911219ea540972edef05c4b/gistfile1.txt | bash
.PHONY: size
# Clean.
clean:
@rm -fr \
dist \
internal/proxy/bin/bin_assets.go \
internal/shim/bindata.go
.PHONY: clean
================================================
FILE: Readme.md
================================================

Up deploys infinitely scalable serverless apps, APIs, and static websites in seconds, so you can get back to working on what makes your product unique.
With Up there's no need to worry about managing or scaling machines, paying for idle servers, worrying about logging infrastructure or alerting. Just deploy your app with `$ up` and you're done!
Use the free OSS version, or subscribe to [Up Pro](#pro-features) for a small monthly fee for unlimited use within your company, there is no additional cost per team-member or application. Deploy dozens or even hundreds of applications for pennies thanks to AWS Lambda's cost effective nature.
## About
Up focuses on deploying "vanilla" HTTP servers so there's nothing new to learn, just develop with your favorite existing frameworks such as Express, Koa, Django, Golang net/http or others.
Up currently supports Node.js, Golang, Python, Java, Crystal, Clojure and static sites out of the box. Up is platform-agnostic, supporting AWS Lambda and API Gateway as the first targets. You can think of Up as self-hosted Heroku style user experience for a fraction of the price, with the security, isolation, flexibility, and scalability of AWS.
Check out the [documentation](https://up.docs.apex.sh/) for more instructions and links, or try one of the [examples](https://github.com/apex/up-examples), or chat with us in [Slack](https://chat.apex.sh/).

## OSS Features
Features of the free open-source edition.

## Pro Features
Up Pro provides additional features for production-ready applications such as encrypted environment variables, error alerting, unlimited team members, unlimited applications, priority [email support](mailto:support@apex.sh), and global deployments for **$19.99/mo USD**. Visit [Subscribing to Up Pro](https://apex.sh/docs/up/guides/#subscribing_to_up_pro) to get started.

[](https://apex.sh/docs/up/guides/#subscribing_to_up_pro)
## Quick Start
Install Up:
```
$ curl -sf https://up.apex.sh/install | sh
```
Create an `app.js` file:
```js
require('http').createServer((req, res) => {
res.end('Hello World\n')
}).listen(process.env.PORT)
```
Deploy the app:
```
$ up
```
Open it in the browser, or copy the url to your clipboard:
```
$ up url -o
$ up url -c
```
<a href="https://apex.sh"><img src="http://tjholowaychuk.com:6000/svg/sponsor"></a>
================================================
FILE: cmd/up/main.go
================================================
package main
import (
"errors"
"os"
"runtime"
"github.com/stripe/stripe-go"
"github.com/tj/go/env"
"github.com/tj/go/term"
// commands
_ "github.com/apex/up/internal/cli/build"
_ "github.com/apex/up/internal/cli/config"
_ "github.com/apex/up/internal/cli/deploy"
_ "github.com/apex/up/internal/cli/disable-stats"
_ "github.com/apex/up/internal/cli/docs"
_ "github.com/apex/up/internal/cli/domains"
_ "github.com/apex/up/internal/cli/logs"
_ "github.com/apex/up/internal/cli/metrics"
_ "github.com/apex/up/internal/cli/prune"
_ "github.com/apex/up/internal/cli/run"
_ "github.com/apex/up/internal/cli/stack"
_ "github.com/apex/up/internal/cli/start"
_ "github.com/apex/up/internal/cli/team"
_ "github.com/apex/up/internal/cli/upgrade"
_ "github.com/apex/up/internal/cli/url"
_ "github.com/apex/up/internal/cli/version"
"github.com/apex/up/internal/cli/app"
"github.com/apex/up/internal/signal"
"github.com/apex/up/internal/stats"
"github.com/apex/up/internal/util"
)
var version = "master"
func main() {
signal.Add(reset)
stripe.Key = env.GetDefault("STRIPE_KEY", "pk_live_23pGrHcZ2QpfX525XYmiyzmx")
stripe.LogLevel = 0
err := run()
if err == nil {
return
}
term.ShowCursor()
switch {
case util.IsNoCredentials(err):
util.Fatal(errors.New("Cannot find credentials, visit https://apex.sh/docs/up/credentials/ for help."))
default:
util.Fatal(err)
}
}
// run the cli.
func run() error {
stats.SetProperties(map[string]interface{}{
"os": runtime.GOOS,
"arch": runtime.GOARCH,
"version": version,
"ci": os.Getenv("CI") == "true" || os.Getenv("CI") == "1",
})
return app.Run(version)
}
// reset cursor.
func reset() error {
term.ShowCursor()
println()
return nil
}
================================================
FILE: cmd/up-proxy/main.go
================================================
package main
import (
"os"
"time"
"github.com/apex/go-apex"
"github.com/apex/log"
"github.com/apex/log/handlers/json"
"github.com/apex/up"
"github.com/apex/up/handler"
"github.com/apex/up/internal/logs"
"github.com/apex/up/internal/proxy"
"github.com/apex/up/internal/util"
"github.com/apex/up/platform/aws/runtime"
)
func main() {
start := time.Now()
stage := os.Getenv("UP_STAGE")
// setup logging
log.SetHandler(json.Default)
if s := os.Getenv("LOG_LEVEL"); s != "" {
log.SetLevelFromString(s)
}
log.Log = log.WithFields(logs.Fields())
log.Info("initializing")
// read config
c, err := up.ReadConfig("up.json")
if err != nil {
log.Fatalf("error reading config: %s", err)
}
ctx := log.WithFields(log.Fields{
"name": c.Name,
"type": c.Type,
})
// init project
p := runtime.New(c)
// init runtime
if err := p.Init(stage); err != nil {
ctx.Fatalf("error initializing: %s", err)
}
// overrides
if err := c.Override(stage); err != nil {
ctx.Fatalf("error overriding: %s", err)
}
// create handler
h, err := handler.FromConfig(c)
if err != nil {
ctx.Fatalf("error creating handler: %s", err)
}
// init handler
h, err = handler.New(c, h)
if err != nil {
ctx.Fatalf("error initializing handler: %s", err)
}
// serve
log.WithField("duration", util.MillisecondsSince(start)).Info("initialized")
apex.Handle(proxy.NewHandler(h))
}
================================================
FILE: config/backoff.go
================================================
package config
import (
"time"
"github.com/tj/backoff"
)
// Backoff config.
type Backoff struct {
// Min time in milliseconds.
Min int `json:"min"`
// Max time in milliseconds.
Max int `json:"max"`
// Factor applied for every attempt.
Factor float64 `json:"factor"`
// Attempts performed before failing.
Attempts int `json:"attempts"`
// Jitter is applied when true.
Jitter bool `json:"jitter"`
}
// Default implementation.
func (b *Backoff) Default() error {
if b.Min == 0 {
b.Min = 100
}
if b.Max == 0 {
b.Max = 500
}
if b.Factor == 0 {
b.Factor = 2
}
if b.Attempts == 0 {
b.Attempts = 3
}
return nil
}
// Backoff returns the backoff from config.
func (b *Backoff) Backoff() *backoff.Backoff {
return &backoff.Backoff{
Min: time.Duration(b.Min) * time.Millisecond,
Max: time.Duration(b.Max) * time.Millisecond,
Factor: b.Factor,
Jitter: b.Jitter,
}
}
================================================
FILE: config/backoff_test.go
================================================
package config
import (
"testing"
"time"
"github.com/tj/assert"
)
func TestBackoff_Default(t *testing.T) {
a := &Backoff{}
assert.NoError(t, a.Default(), "default")
b := &Backoff{
Min: 100,
Max: 500,
Factor: 2,
Attempts: 3,
}
assert.Equal(t, b, a)
}
func TestBackoff_Backoff(t *testing.T) {
a := &Backoff{}
assert.NoError(t, a.Default(), "default")
b := a.Backoff()
assert.Equal(t, time.Millisecond*100, b.Min)
assert.Equal(t, time.Millisecond*500, b.Max)
}
================================================
FILE: config/config.go
================================================
package config
import (
"encoding/json"
"io/ioutil"
"os"
"github.com/apex/log"
"github.com/pkg/errors"
"github.com/apex/up/internal/header"
"github.com/apex/up/internal/inject"
"github.com/apex/up/internal/redirect"
"github.com/apex/up/internal/validate"
"github.com/apex/up/platform/aws/regions"
"github.com/aws/aws-sdk-go/aws/session"
)
// defaulter is the interface that provides config defaulting.
type defaulter interface {
Default() error
}
// validator is the interface that provides config validation.
type validator interface {
Validate() error
}
// Config for the project.
type Config struct {
Name string `json:"name"`
Description string `json:"description"`
Type string `json:"type"`
Headers header.Rules `json:"headers"`
Redirects redirect.Rules `json:"redirects"`
Hooks Hooks `json:"hooks"`
Environment Environment `json:"environment"`
Regions []string `json:"regions"`
Profile string `json:"profile"`
Inject inject.Rules `json:"inject"`
Lambda Lambda `json:"lambda"`
CORS *CORS `json:"cors"`
ErrorPages ErrorPages `json:"error_pages"`
Proxy Relay `json:"proxy"`
Static Static `json:"static"`
Logs Logs `json:"logs"`
Stages Stages `json:"stages"`
DNS DNS `json:"dns"`
}
// Validate implementation.
func (c *Config) Validate() error {
if err := validate.RequiredString(c.Name); err != nil {
return errors.Wrap(err, ".name")
}
if err := validate.Name(c.Name); err != nil {
return errors.Wrapf(err, ".name %q", c.Name)
}
if err := validate.List(c.Type, []string{"static", "server"}); err != nil {
return errors.Wrap(err, ".type")
}
if err := validate.Lists(c.Regions, regions.IDs); err != nil {
return errors.Wrap(err, ".regions")
}
if err := c.DNS.Validate(); err != nil {
return errors.Wrap(err, ".dns")
}
if err := c.Static.Validate(); err != nil {
return errors.Wrap(err, ".static")
}
if err := c.Inject.Validate(); err != nil {
return errors.Wrap(err, ".inject")
}
if err := c.Lambda.Validate(); err != nil {
return errors.Wrap(err, ".lambda")
}
if err := c.Proxy.Validate(); err != nil {
return errors.Wrap(err, ".proxy")
}
if err := c.Stages.Validate(); err != nil {
return errors.Wrap(err, ".stages")
}
if len(c.Regions) > 1 {
return errors.New("multiple regions is not yet supported, see https://github.com/apex/up/issues/134")
}
return nil
}
// Default implementation.
func (c *Config) Default() error {
if c.Stages == nil {
c.Stages = make(Stages)
}
// we default stages here before others simply to
// initialize the default stages such as "development"
// allowing runtime inference to default values.
if err := c.Stages.Default(); err != nil {
return errors.Wrap(err, ".stages")
}
// TODO: hack, move to the instantiation of aws clients
if c.Profile != "" {
setProfile(c.Profile)
}
// default type to server
if c.Type == "" {
c.Type = "server"
}
// runtime defaults
if c.Type != "static" {
runtime := inferRuntime()
log.WithField("type", runtime).Debug("inferred runtime")
if err := runtimeConfig(runtime, c); err != nil {
return errors.Wrap(err, "runtime")
}
}
// default .regions
if err := c.defaultRegions(); err != nil {
return errors.Wrap(err, ".region")
}
// region globbing
c.Regions = regions.Match(c.Regions)
// default .proxy
if err := c.Proxy.Default(); err != nil {
return errors.Wrap(err, ".proxy")
}
// default .lambda
if err := c.Lambda.Default(); err != nil {
return errors.Wrap(err, ".lambda")
}
// default .dns
if err := c.DNS.Default(); err != nil {
return errors.Wrap(err, ".dns")
}
// default .logs
if err := c.Logs.Default(); err != nil {
return errors.Wrap(err, ".logs")
}
// default .inject
if err := c.Inject.Default(); err != nil {
return errors.Wrap(err, ".inject")
}
// default .error_pages
if err := c.ErrorPages.Default(); err != nil {
return errors.Wrap(err, ".error_pages")
}
// default .stages
if err := c.Stages.Default(); err != nil {
return errors.Wrap(err, ".stages")
}
return nil
}
// Override with stage config if present, and re-validate.
func (c *Config) Override(stage string) error {
s := c.Stages.GetByName(stage)
if s == nil {
return nil
}
s.Override(c)
return c.Validate()
}
// defaultRegions checks AWS_REGION and falls back on us-west-2.
func (c *Config) defaultRegions() error {
if len(c.Regions) != 0 {
log.Debugf("%d regions from config", len(c.Regions))
return nil
}
s, err := session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
})
if err != nil {
return errors.Wrap(err, "creating session")
}
if r := *s.Config.Region; r != "" {
log.Debugf("region from aws shared config %q", r)
c.Regions = append(c.Regions, r)
return nil
}
r := "us-west-2"
log.Debugf("region defaulted to %q", r)
c.Regions = append(c.Regions, r)
return nil
}
// ParseConfig returns config from JSON bytes.
func ParseConfig(b []byte) (*Config, error) {
c := &Config{}
if err := json.Unmarshal(b, c); err != nil {
return nil, errors.Wrap(err, "parsing json")
}
if err := c.Default(); err != nil {
return nil, errors.Wrap(err, "defaulting")
}
if err := c.Validate(); err != nil {
return nil, errors.Wrap(err, "validating")
}
return c, nil
}
// ParseConfigString returns config from JSON string.
func ParseConfigString(s string) (*Config, error) {
return ParseConfig([]byte(s))
}
// MustParseConfigString returns config from JSON string.
func MustParseConfigString(s string) *Config {
c, err := ParseConfigString(s)
if err != nil {
panic(err)
}
return c
}
// ReadConfig reads the configuration from `path`.
func ReadConfig(path string) (*Config, error) {
b, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return ParseConfig(b)
}
// setProfile sets the AWS_PROFILE.
func setProfile(name string) {
os.Setenv("AWS_PROFILE", name)
}
================================================
FILE: config/config_test.go
================================================
package config
import (
"io/ioutil"
"os"
"testing"
"github.com/tj/assert"
)
func TestConfig_Name(t *testing.T) {
t.Run("valid", func(t *testing.T) {
c := Config{
Name: "my-app123",
}
assert.NoError(t, c.Default(), "default")
assert.NoError(t, c.Validate(), "validate")
})
t.Run("invalid", func(t *testing.T) {
c := Config{
Name: "my app",
}
assert.NoError(t, c.Default(), "default")
assert.EqualError(t, c.Validate(), `.name "my app": must contain only lowercase alphanumeric characters and '-'`)
})
t.Run("invalid", func(t *testing.T) {
c := Config{
Name: "MYAPP",
}
assert.NoError(t, c.Default(), "default")
assert.EqualError(t, c.Validate(), `.name "MYAPP": must contain only lowercase alphanumeric characters and '-'`)
})
}
func TestConfig_Type(t *testing.T) {
t.Run("default", func(t *testing.T) {
c := Config{
Name: "api",
}
assert.NoError(t, c.Default(), "default")
assert.NoError(t, c.Validate(), "validate")
assert.Equal(t, "server", c.Type)
})
t.Run("valid", func(t *testing.T) {
c := Config{
Name: "api",
Type: "server",
}
assert.NoError(t, c.Default(), "default")
assert.NoError(t, c.Validate(), "validate")
})
t.Run("invalid", func(t *testing.T) {
c := Config{
Name: "api",
Type: "something",
}
assert.NoError(t, c.Default(), "default")
assert.EqualError(t, c.Validate(), `.type: "something" is invalid, must be one of:
• static
• server`)
})
}
func TestConfig_Regions(t *testing.T) {
t.Skip()
t.Run("valid multiple", func(t *testing.T) {
c := Config{
Name: "api",
Type: "server",
Regions: []string{"us-west-2", "us-east-1"},
}
assert.NoError(t, c.Default(), "default")
assert.NoError(t, c.Validate(), "validate")
})
t.Run("valid multiple", func(t *testing.T) {
c := Config{
Name: "api",
Type: "server",
Regions: []string{"us-west-2", "us-east-1"},
}
assert.NoError(t, c.Default(), "default")
assert.NoError(t, c.Validate(), "validate")
})
t.Run("valid globbing", func(t *testing.T) {
c := Config{
Name: "api",
Type: "server",
Regions: []string{"us-*", "us-east-1", "ca-central-*"},
}
assert.NoError(t, c.Default(), "default")
assert.NoError(t, c.Validate(), "validate")
assert.Equal(t, []string{"us-east-2", "us-east-1", "us-west-1", "us-west-2", "us-east-1", "ca-central-1"}, c.Regions)
})
t.Run("invalid globbing", func(t *testing.T) {
c := Config{
Name: "api",
Type: "server",
Regions: []string{"uss-*"},
}
assert.NoError(t, c.Default(), "default")
assert.EqualError(t, c.Validate(), `.regions: "uss-*" is invalid, must be one of:
• us-east-2
• us-east-1
• us-west-1
• us-west-2
• ap-south-1
• ap-northeast-2
• ap-southeast-1
• ap-southeast-2
• ap-northeast-1
• ca-central-1
• eu-central-1
• eu-west-1
• eu-west-2
• eu-west-3
• sa-east-1`)
})
t.Run("invalid", func(t *testing.T) {
c := Config{
Name: "api",
Type: "server",
Regions: []string{"us-west-1", "us-west-9"},
}
assert.NoError(t, c.Default(), "default")
assert.EqualError(t, c.Validate(), `.regions: "us-west-9" is invalid, must be one of:
• us-east-2
• us-east-1
• us-west-1
• us-west-2
• ap-south-1
• ap-northeast-2
• ap-southeast-1
• ap-southeast-2
• ap-northeast-1
• ca-central-1
• eu-central-1
• eu-west-1
• eu-west-2
• eu-west-3
• sa-east-1`)
})
}
func TestConfig_defaultRegions(t *testing.T) {
t.Run("regions from config", func(t *testing.T) {
regions := []string{"us-east-1"}
c := Config{
Name: "api",
Type: "server",
Regions: regions,
}
assert.NoError(t, c.Default(), "default")
assert.NoError(t, c.defaultRegions(), "defaultRegions")
assert.Equal(t, 1, len(c.Regions), "regions should have length 2")
assert.Equal(t, regions, c.Regions, "should read regions from config")
assert.NoError(t, c.Validate(), "validate")
})
t.Run("regions from AWS_REGION", func(t *testing.T) {
region := "sa-east-1"
os.Setenv("AWS_REGION", region)
defer os.Setenv("AWS_REGION", "")
c := Config{
Name: "api",
Type: "server",
}
assert.NoError(t, c.Default(), "default")
assert.NoError(t, c.defaultRegions(), "defaultRegions")
assert.Equal(t, 1, len(c.Regions), "regions should have length 1")
assert.Equal(t, region, c.Regions[0], "should read regions from AWS_REGION")
assert.NoError(t, c.Default(), "default")
assert.NoError(t, c.Validate(), "validate")
})
t.Run("regions from AWS_DEFAULT_REGION", func(t *testing.T) {
region := "sa-east-1"
os.Setenv("AWS_DEFAULT_REGION", region)
defer os.Setenv("AWS_DEFAULT_REGION", "")
c := Config{
Name: "api",
Type: "server",
}
assert.NoError(t, c.Default(), "default")
assert.NoError(t, c.defaultRegions(), "defaultRegions")
assert.Equal(t, 1, len(c.Regions), "regions should have length 1")
assert.Equal(t, region, c.Regions[0], "should read regions from AWS_DEFAULT_REGION")
assert.NoError(t, c.Validate(), "validate")
})
t.Run("regions from shared config with default profile", func(t *testing.T) {
content := `
[default]
region = sa-east-1
output = json
[profile another-profile]
region = ap-southeast-2
output = json`
tmpfile, err := ioutil.TempFile("", "config")
assert.NoError(t, err)
defer os.Remove(tmpfile.Name())
_, err = tmpfile.WriteString(content)
assert.NoError(t, err)
os.Setenv("AWS_CONFIG_FILE", tmpfile.Name())
defer os.Setenv("AWS_CONFIG_FILE", "")
c := Config{
Name: "api",
Type: "server",
}
assert.NoError(t, c.Default(), "default")
assert.NoError(t, c.defaultRegions(), "defaultRegions")
assert.Equal(t, 1, len(c.Regions), "regions should have length 1")
assert.Equal(t, "sa-east-1", c.Regions[0], "should read regions from shared config with default profile")
assert.NoError(t, c.Validate(), "validate")
})
t.Run("regions from shared config with AWS_PROFILE profile", func(t *testing.T) {
content := `
[default]
region = sa-east-1
output = json
[profile another-profile]
region = ap-southeast-2
output = json`
tmpfile, err := ioutil.TempFile("", "config")
assert.NoError(t, err)
defer os.Remove(tmpfile.Name())
_, err = tmpfile.WriteString(content)
assert.NoError(t, err)
os.Setenv("AWS_CONFIG_FILE", tmpfile.Name())
defer os.Setenv("AWS_CONFIG_FILE", "")
os.Setenv("AWS_PROFILE", "another-profile")
defer os.Setenv("AWS_PROFILE", "")
c := Config{
Name: "api",
Type: "server",
}
assert.NoError(t, c.Default(), "default")
assert.NoError(t, c.defaultRegions(), "defaultRegions")
assert.Equal(t, 1, len(c.Regions), "regions should have length 1")
assert.Equal(t, "ap-southeast-2", c.Regions[0], "should read regions from shared config with AWS_PROFILE profile")
assert.NoError(t, c.Validate(), "validate")
})
t.Run("default region must be us-west-2", func(t *testing.T) {
// Make sure we aren't reading AWS config file
os.Setenv("AWS_CONFIG_FILE", "does-not-exist")
c := Config{
Name: "api",
Type: "server",
}
assert.NoError(t, c.Default(), "default")
assert.NoError(t, c.defaultRegions(), "defaultRegions")
assert.Equal(t, 1, len(c.Regions), "regions should have length 1")
assert.Equal(t, "us-west-2", c.Regions[0], "default region must be us-west-2")
assert.NoError(t, c.Validate(), "validate")
})
}
================================================
FILE: config/cors.go
================================================
package config
// CORS configuration.
type CORS struct {
// AllowedOrigins is a list of origins a cross-domain request can be executed from.
// If the special "*" value is present in the list, all origins will be allowed.
// An origin may contain a wildcard (*) to replace 0 or more characters
// (i.e.: http://*.domain.com). Usage of wildcards implies a small performance penalty.
// Only one wildcard can be used per origin.
// Default value is ["*"]
AllowedOrigins []string `json:"allowed_origins"`
// AllowedMethods is a list of methods the client is allowed to use with
// cross-domain requests. Default value is simple methods (GET and POST)
AllowedMethods []string `json:"allowed_methods"`
// AllowedHeaders is list of non simple headers the client is allowed to use with
// cross-domain requests.
// If the special "*" value is present in the list, all headers will be allowed.
// Default value is [] but "Origin" is always appended to the list.
AllowedHeaders []string `json:"allowed_headers"`
// ExposedHeaders indicates which headers are safe to expose to the API of a CORS
// API specification
ExposedHeaders []string `json:"exposed_headers"`
// AllowCredentials indicates whether the request can include user credentials like
// cookies, HTTP authentication or client side SSL certificates.
AllowCredentials bool `json:"allow_credentials"`
// MaxAge indicates how long (in seconds) the results of a preflight request
// can be cached.
MaxAge int `json:"max_age"`
// Debugging flag adds additional output to debug server side CORS issues
Debug bool `json:"debug"`
}
================================================
FILE: config/dns.go
================================================
package config
import (
"encoding/json"
"github.com/apex/up/internal/validate"
"github.com/pkg/errors"
)
// recordTypes is a list of valid record types.
var recordTypes = []string{
"ALIAS",
"A",
"AAAA",
"CNAME",
"MX",
"NAPTR",
"NS",
"PTR",
"SOA",
"SPF",
"SRV",
"TXT",
}
// DNS config.
type DNS struct {
Zones []*Zone `json:"zones"`
}
// UnmarshalJSON implementation.
func (d *DNS) UnmarshalJSON(b []byte) error {
var zones map[string][]*Record
if err := json.Unmarshal(b, &zones); err != nil {
return err
}
for name, records := range zones {
zone := &Zone{Name: name, Records: records}
d.Zones = append(d.Zones, zone)
}
return nil
}
// Default implementation.
func (d *DNS) Default() error {
for _, z := range d.Zones {
if err := z.Default(); err != nil {
return errors.Wrapf(err, "zone %s", z.Name)
}
}
return nil
}
// Validate implementation.
func (d *DNS) Validate() error {
for _, z := range d.Zones {
if err := z.Validate(); err != nil {
return errors.Wrapf(err, "zone %s", z.Name)
}
}
return nil
}
// Zone is a DNS zone.
type Zone struct {
Name string `json:"name"`
Records []*Record `json:"records"`
}
// Default implementation.
func (z *Zone) Default() error {
for i, r := range z.Records {
if err := r.Default(); err != nil {
return errors.Wrapf(err, "record %d", i)
}
}
return nil
}
// Validate implementation.
func (z *Zone) Validate() error {
for i, r := range z.Records {
if err := r.Validate(); err != nil {
return errors.Wrapf(err, "record %d", i)
}
}
return nil
}
// Record is a DNS record.
type Record struct {
Name string `json:"name"`
Type string `json:"type"`
TTL int `json:"ttl"`
Value []string `json:"value"`
}
// Validate implementation.
func (r *Record) Validate() error {
if err := validate.List(r.Type, recordTypes); err != nil {
return errors.Wrap(err, ".type")
}
if err := validate.RequiredString(r.Name); err != nil {
return errors.Wrap(err, ".name")
}
if err := validate.RequiredStrings(r.Value); err != nil {
return errors.Wrap(err, ".value")
}
if err := validate.MinStrings(r.Value, 1); err != nil {
return errors.Wrap(err, ".value")
}
return nil
}
// Default implementation.
func (r *Record) Default() error {
if r.TTL == 0 {
r.TTL = 300
}
return nil
}
================================================
FILE: config/dns_test.go
================================================
package config
import (
"encoding/json"
"log"
"os"
"sort"
"testing"
"github.com/tj/assert"
)
func ExampleDNS() {
s := `{
"something.sh": [
{
"name": "something.com",
"type": "A",
"ttl": 60,
"value": ["35.161.83.243"]
},
{
"name": "blog.something.com",
"type": "CNAME",
"ttl": 60,
"value": ["34.209.172.67"]
},
{
"name": "api.something.com",
"type": "A",
"value": ["54.187.185.18"]
}
]
}`
var c DNS
if err := json.Unmarshal([]byte(s), &c); err != nil {
log.Fatalf("error unmarshaling: %s", err)
}
sort.Slice(c.Zones[0].Records, func(i int, j int) bool {
a := c.Zones[0].Records[i]
b := c.Zones[0].Records[j]
return a.Name > b.Name
})
if err := c.Validate(); err != nil {
log.Fatalf("error validating: %s", err)
}
if err := c.Default(); err != nil {
log.Fatalf("error defaulting: %s", err)
}
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
enc.Encode(c)
// Output:
// {
// "zones": [
// {
// "name": "something.sh",
// "records": [
// {
// "name": "something.com",
// "type": "A",
// "ttl": 60,
// "value": [
// "35.161.83.243"
// ]
// },
// {
// "name": "blog.something.com",
// "type": "CNAME",
// "ttl": 60,
// "value": [
// "34.209.172.67"
// ]
// },
// {
// "name": "api.something.com",
// "type": "A",
// "ttl": 300,
// "value": [
// "54.187.185.18"
// ]
// }
// ]
// }
// ]
// }
}
func TestDNS_Validate(t *testing.T) {
t.Run("invalid", func(t *testing.T) {
c := &DNS{
Zones: []*Zone{
{
Name: "apex.sh",
Records: []*Record{
{
Name: "blog.apex.sh",
Type: "CNAME",
},
},
},
},
}
assert.EqualError(t, c.Validate(), `zone apex.sh: record 0: .value: must have at least 1 value`)
})
}
func TestRecord_Type(t *testing.T) {
t.Run("valid", func(t *testing.T) {
c := &Record{
Name: "blog.apex.sh",
Type: "A",
Value: []string{"1.1.1.1"},
}
assert.NoError(t, c.Validate(), "validate")
})
t.Run("invalid", func(t *testing.T) {
c := &Record{
Name: "blog.apex.sh",
Type: "AAA",
}
assert.EqualError(t, c.Validate(), `.type: "AAA" is invalid, must be one of:
• ALIAS
• A
• AAAA
• CNAME
• MX
• NAPTR
• NS
• PTR
• SOA
• SPF
• SRV
• TXT`)
})
}
func TestRecord_TTL(t *testing.T) {
c := &Record{Type: "A"}
assert.NoError(t, c.Default(), "default")
assert.Equal(t, 300, c.TTL)
}
func TestRecord_Value(t *testing.T) {
t.Run("empty", func(t *testing.T) {
c := &Record{
Name: "blog.apex.sh",
Type: "A",
}
assert.EqualError(t, c.Validate(), `.value: must have at least 1 value`)
})
t.Run("invalid", func(t *testing.T) {
c := &Record{
Name: "blog.apex.sh",
Type: "A",
Value: []string{"1.1.1.1", ""},
}
assert.EqualError(t, c.Validate(), `.value: at index 1: is required`)
})
}
================================================
FILE: config/doc.go
================================================
// Package config provides configuration structures,
// validation, and defaulting for up.json config.
package config
================================================
FILE: config/duration.go
================================================
package config
import (
"bytes"
"strconv"
"time"
)
// Duration may be specified as numerical seconds or
// as a duration string such as "1.5m".
type Duration time.Duration
// Seconds returns the duration in seconds.
func (d *Duration) Seconds() float64 {
return float64(time.Duration(*d) / time.Second)
}
// UnmarshalJSON implementation.
func (d *Duration) UnmarshalJSON(b []byte) error {
if i, err := strconv.ParseInt(string(b), 10, 64); err == nil {
*d = Duration(time.Second * time.Duration(i))
return nil
}
v, err := time.ParseDuration(string(bytes.Trim(b, `"`)))
if err != nil {
return err
}
*d = Duration(v)
return nil
}
// MarshalJSON implement.
func (d *Duration) MarshalJSON() ([]byte, error) {
return []byte(strconv.Itoa(int(d.Seconds()))), nil
}
================================================
FILE: config/duration_test.go
================================================
package config
import (
"encoding/json"
"testing"
"time"
"github.com/tj/assert"
)
func TestDuration_UnmarshalJSON(t *testing.T) {
t.Run("numeric seconds", func(t *testing.T) {
s := `{
"timeout": 5
}`
var c struct {
Timeout Duration
}
err := json.Unmarshal([]byte(s), &c)
assert.NoError(t, err, "unmarshal")
assert.Equal(t, Duration(5*time.Second), c.Timeout)
})
t.Run("string duration", func(t *testing.T) {
s := `{
"timeout": "1.5m"
}`
var c struct {
Timeout Duration
}
err := json.Unmarshal([]byte(s), &c)
assert.NoError(t, err, "unmarshal")
assert.Equal(t, Duration(90*time.Second), c.Timeout)
})
}
================================================
FILE: config/environment.go
================================================
package config
// Environment variables.
type Environment map[string]string
================================================
FILE: config/errorpages.go
================================================
package config
// ErrorPages configuration.
type ErrorPages struct {
// Enable error pages.
Enable bool `json:"enable"`
// Dir containing error pages.
Dir string `json:"dir"`
// Variables are passed to the template for use.
Variables map[string]interface{} `json:"variables"`
}
// Default implementation.
func (e *ErrorPages) Default() error {
if e.Dir == "" {
e.Dir = "."
}
return nil
}
================================================
FILE: config/errorpages_test.go
================================================
package config
import (
"testing"
"github.com/tj/assert"
)
func TestErrorPages(t *testing.T) {
c := &ErrorPages{}
assert.NoError(t, c.Default(), "default")
assert.Equal(t, ".", c.Dir, "dir")
}
================================================
FILE: config/hooks.go
================================================
package config
import (
"encoding/json"
"errors"
)
// Hook is one or more commands.
type Hook []string
// Hooks for the project.
type Hooks struct {
Build Hook `json:"build"`
Clean Hook `json:"clean"`
PreBuild Hook `json:"prebuild"`
PostBuild Hook `json:"postbuild"`
PreDeploy Hook `json:"predeploy"`
PostDeploy Hook `json:"postdeploy"`
}
// Override config.
func (h *Hooks) Override(c *Config) {
if v := h.Build; v != nil {
c.Hooks.Build = v
}
if v := h.Clean; v != nil {
c.Hooks.Clean = v
}
if v := h.PreBuild; v != nil {
c.Hooks.PreBuild = v
}
if v := h.PostBuild; v != nil {
c.Hooks.PostBuild = v
}
if v := h.PreDeploy; v != nil {
c.Hooks.PreDeploy = v
}
if v := h.PostDeploy; v != nil {
c.Hooks.PostDeploy = v
}
}
// Get returns the hook by name or nil.
func (h *Hooks) Get(s string) Hook {
switch s {
case "build":
return h.Build
case "clean":
return h.Clean
case "prebuild":
return h.PreBuild
case "postbuild":
return h.PostBuild
case "predeploy":
return h.PreDeploy
case "postdeploy":
return h.PostDeploy
default:
return nil
}
}
// UnmarshalJSON implementation.
func (h *Hook) UnmarshalJSON(b []byte) error {
switch b[0] {
case '"':
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
*h = append(*h, s)
return nil
case '[':
return json.Unmarshal(b, (*[]string)(h))
default:
return errors.New("hook must be a string or array of strings")
}
}
// IsEmpty returns true if the hook is empty.
func (h *Hook) IsEmpty() bool {
return h == nil || len(*h) == 0
}
================================================
FILE: config/hooks_test.go
================================================
package config
import (
"encoding/json"
"testing"
"github.com/tj/assert"
)
func TestHook(t *testing.T) {
t.Run("missing", func(t *testing.T) {
s := []byte(`{}`)
var c struct {
Build Hook
}
err := json.Unmarshal(s, &c)
assert.NoError(t, err, "unmarshal")
assert.Equal(t, Hook(nil), c.Build)
})
t.Run("invalid type", func(t *testing.T) {
s := []byte(`
{
"build": 5
}
`)
var c struct {
Build Hook
}
err := json.Unmarshal(s, &c)
assert.EqualError(t, err, `hook must be a string or array of strings`)
})
t.Run("string", func(t *testing.T) {
s := []byte(`
{
"build": "go build main.go"
}
`)
var c struct {
Build Hook
}
err := json.Unmarshal(s, &c)
assert.NoError(t, err, "unmarshal")
assert.Equal(t, Hook{"go build main.go"}, c.Build)
})
t.Run("array", func(t *testing.T) {
s := []byte(`
{
"build": [
"go build main.go",
"browserify src/index.js > app.js"
]
}
`)
var c struct {
Build Hook
}
err := json.Unmarshal(s, &c)
assert.NoError(t, err, "unmarshal")
assert.Equal(t, Hook{
"go build main.go",
"browserify src/index.js > app.js",
}, c.Build)
})
}
================================================
FILE: config/lambda.go
================================================
package config
// defaultRuntime is the default runtime.
var defaultRuntime = "nodejs10.x"
// defaultPolicy is the default function role policy.
var defaultPolicy = IAMPolicyStatement{
"Effect": "Allow",
"Resource": "*",
"Action": []string{
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"ssm:GetParametersByPath",
"ec2:CreateNetworkInterface",
"ec2:DescribeNetworkInterfaces",
"ec2:DeleteNetworkInterface",
},
}
// IAMPolicyStatement configuration.
type IAMPolicyStatement map[string]interface{}
// VPC configuration.
type VPC struct {
Subnets []string `json:"subnets"`
SecurityGroups []string `json:"security_groups"`
}
// Lambda configuration.
type Lambda struct {
// Memory of the function.
Memory int `json:"memory"`
// Timeout of the function.
Timeout int `json:"timeout"`
// Role of the function.
Role string `json:"role"`
// Runtime of the function.
Runtime string `json:"runtime"`
// Policy of the function role.
Policy []IAMPolicyStatement `json:"policy"`
// VPC configuration.
VPC *VPC `json:"vpc"`
}
// Default implementation.
func (l *Lambda) Default() error {
if l.Timeout == 0 {
l.Timeout = 60
}
if l.Memory == 0 {
l.Memory = 512
}
if l.Runtime == "" {
l.Runtime = defaultRuntime
}
l.Policy = append(l.Policy, defaultPolicy)
return nil
}
// Validate implementation.
func (l *Lambda) Validate() error {
return nil
}
// Override config.
func (l *Lambda) Override(c *Config) {
if l.Memory != 0 {
c.Lambda.Memory = l.Memory
}
if l.Timeout != 0 {
c.Lambda.Timeout = l.Timeout
}
if l.Role != "" {
c.Lambda.Role = l.Role
}
if l.VPC != nil {
c.Lambda.VPC = l.VPC
}
if l.Runtime != "" {
c.Lambda.Runtime = l.Runtime
}
}
================================================
FILE: config/lambda_test.go
================================================
package config
import (
"testing"
"github.com/tj/assert"
)
func TestLambda(t *testing.T) {
c := &Lambda{}
assert.NoError(t, c.Default(), "default")
assert.Equal(t, 60, c.Timeout, "timeout")
assert.Equal(t, 512, c.Memory, "timeout")
}
func TestLambda_Policy(t *testing.T) {
t.Run("defaults", func(t *testing.T) {
c := &Lambda{}
assert.NoError(t, c.Default(), "default")
assert.Len(t, c.Policy, 1)
assert.Equal(t, defaultPolicy, c.Policy[0])
})
t.Run("specified", func(t *testing.T) {
c := &Lambda{
Policy: []IAMPolicyStatement{
{
"Effect": "Allow",
"Resource": "*",
"Action": []string{
"s3:List*",
"s3:Get*",
},
},
},
}
assert.NoError(t, c.Default(), "default")
assert.Len(t, c.Policy, 2)
assert.Equal(t, defaultPolicy, c.Policy[1])
})
}
================================================
FILE: config/logs.go
================================================
package config
// Logs configuration.
type Logs struct {
// Disable json log output.
Disable bool `json:"disable"`
// Stdout default log level.
Stdout string `json:"stdout"`
// Stderr default log level.
Stderr string `json:"stderr"`
}
// Default implementation.
func (l *Logs) Default() error {
if l.Stdout == "" {
l.Stdout = "info"
}
if l.Stderr == "" {
l.Stderr = "error"
}
return nil
}
================================================
FILE: config/relay.go
================================================
package config
import (
"github.com/pkg/errors"
)
// Relay config.
type Relay struct {
// Command run to start your server.
Command string `json:"command"`
// Timeout in seconds to wait for a response.
Timeout int `json:"timeout"`
// ListenTimeout in seconds when waiting for the app to bind to PORT.
ListenTimeout int `json:"listen_timeout"`
}
// Default implementation.
func (r *Relay) Default() error {
if r.Command == "" {
r.Command = "./server"
}
if r.Timeout == 0 {
r.Timeout = 15
}
if r.ListenTimeout == 0 {
r.ListenTimeout = 15
}
return nil
}
// Validate will try to perform sanity checks for this Relay configuration.
func (r *Relay) Validate() error {
if r.Command == "" {
err := errors.New("should not be empty")
return errors.Wrap(err, ".command")
}
if r.ListenTimeout <= 0 {
err := errors.New("should be greater than 0")
return errors.Wrap(err, ".listen_timeout")
}
if r.ListenTimeout > 25 {
err := errors.New("should be <= 25")
return errors.Wrap(err, ".listen_timeout")
}
if r.Timeout > 25 {
err := errors.New("should be <= 25")
return errors.Wrap(err, ".timeout")
}
return nil
}
// Override config.
func (r *Relay) Override(c *Config) {
if r.Command != "" {
c.Proxy.Command = r.Command
}
}
================================================
FILE: config/runtimes.go
================================================
package config
import (
"os"
"github.com/apex/up/internal/util"
"github.com/pkg/errors"
)
// Runtime is an app runtime.
type Runtime string
// Runtimes available.
const (
RuntimeUnknown Runtime = "unknown"
RuntimeGo = "go"
RuntimeNode = "node"
RuntimeClojure = "clojure"
RuntimeCrystal = "crystal"
RuntimePython = "python"
RuntimeStatic = "static"
RuntimeJavaMaven = "java maven"
RuntimeJavaGradle = "java gradle"
)
// inferRuntime returns the runtime based on files present in the CWD.
func inferRuntime() Runtime {
switch {
case util.Exists("main.go"):
return RuntimeGo
case util.Exists("main.cr"):
return RuntimeCrystal
case util.Exists("package.json"):
return RuntimeNode
case util.Exists("app.js"):
return RuntimeNode
case util.Exists("project.clj"):
return RuntimeClojure
case util.Exists("pom.xml"):
return RuntimeJavaMaven
case util.Exists("build.gradle"):
return RuntimeJavaGradle
case util.Exists("app.py"):
return RuntimePython
case util.Exists("index.html"):
return RuntimeStatic
default:
return RuntimeUnknown
}
}
// runtimeConfig performs config inferences based on what Up thinks the runtime is.
func runtimeConfig(runtime Runtime, c *Config) error {
switch runtime {
case RuntimeGo:
golang(c)
case RuntimeClojure:
clojureLein(c)
case RuntimeJavaMaven:
javaMaven(c)
case RuntimeJavaGradle:
javaGradle(c)
case RuntimeCrystal:
crystal(c)
case RuntimePython:
python(c)
case RuntimeStatic:
c.Type = "static"
case RuntimeNode:
if err := nodejs(c); err != nil {
return err
}
}
return nil
}
// golang config.
func golang(c *Config) {
if c.Hooks.Build.IsEmpty() {
c.Hooks.Build = Hook{`GOOS=linux GOARCH=amd64 go build -o server *.go`}
}
if c.Hooks.Clean.IsEmpty() {
c.Hooks.Clean = Hook{`rm server`}
}
if s := c.Stages.GetByName("development"); s != nil {
if s.Proxy.Command == "" {
s.Proxy.Command = "go run *.go"
}
}
}
// java gradle config.
func javaGradle(c *Config) {
if c.Proxy.Command == "" {
c.Proxy.Command = "java -jar server.jar"
}
if c.Hooks.Build.IsEmpty() {
// assumes build results in a shaded jar named server.jar
if util.Exists("gradlew") {
c.Hooks.Build = Hook{`./gradlew clean build && cp build/libs/server.jar .`}
} else {
c.Hooks.Build = Hook{`gradle clean build && cp build/libs/server.jar .`}
}
}
if c.Hooks.Clean.IsEmpty() {
c.Hooks.Clean = Hook{`rm server.jar && gradle clean`}
}
}
// java maven config.
func javaMaven(c *Config) {
if c.Proxy.Command == "" {
c.Proxy.Command = "java -jar server.jar"
}
if c.Hooks.Build.IsEmpty() {
// assumes package results in a shaded jar named server.jar
if util.Exists("mvnw") {
c.Hooks.Build = Hook{`./mvnw clean package && cp target/server.jar .`}
} else {
c.Hooks.Build = Hook{`mvn clean package && cp target/server.jar .`}
}
}
if c.Hooks.Clean.IsEmpty() {
c.Hooks.Clean = Hook{`rm server.jar && mvn clean`}
}
}
// clojure lein config.
func clojureLein(c *Config) {
if c.Proxy.Command == "" {
c.Proxy.Command = "java -jar server.jar"
}
if c.Hooks.Build.IsEmpty() {
// assumes package results in a shaded jar named server.jar
c.Hooks.Build = Hook{`lein uberjar && cp target/*-standalone.jar server.jar`}
}
if c.Hooks.Clean.IsEmpty() {
c.Hooks.Clean = Hook{`lein clean && rm server.jar`}
}
}
// crystal config.
func crystal(c *Config) {
if c.Hooks.Build.IsEmpty() {
c.Hooks.Build = Hook{`docker run --rm -v $(pwd):/src -w /src crystallang/crystal crystal build -o server main.cr --release --static`}
}
if c.Hooks.Clean.IsEmpty() {
c.Hooks.Clean = Hook{`rm server`}
}
if s := c.Stages.GetByName("development"); s != nil {
if s.Proxy.Command == "" {
s.Proxy.Command = "crystal run main.cr"
}
}
}
// nodejs config.
func nodejs(c *Config) error {
var pkg struct {
Scripts struct {
Start string `json:"start"`
Build string `json:"build"`
} `json:"scripts"`
}
// read package.json
if err := util.ReadFileJSON("package.json", &pkg); err != nil && !os.IsNotExist(errors.Cause(err)) {
return err
}
// use "start" script unless explicitly defined in up.json
if c.Proxy.Command == "" {
if s := pkg.Scripts.Start; s == "" {
c.Proxy.Command = `node app.js`
} else {
c.Proxy.Command = s
}
}
// use "build" script unless explicitly defined in up.json
if c.Hooks.Build.IsEmpty() {
c.Hooks.Build = Hook{pkg.Scripts.Build}
}
return nil
}
// python config.
func python(c *Config) {
if c.Proxy.Command == "" {
c.Proxy.Command = "python app.py"
}
// Only add build & clean hooks if a requirements.txt exists
if !util.Exists("requirements.txt") {
return
}
// Set PYTHONPATH env
if c.Environment == nil {
c.Environment = Environment{}
}
c.Environment["PYTHONPATH"] = ".pypath/"
// Copy libraries into .pypath/
if c.Hooks.Build.IsEmpty() {
c.Hooks.Build = Hook{`mkdir -p .pypath/ && pip install -r requirements.txt -t .pypath/`}
}
// Clean .pypath/
if c.Hooks.Clean.IsEmpty() {
c.Hooks.Clean = Hook{`rm -r .pypath/`}
}
}
================================================
FILE: config/stages.go
================================================
package config
import (
"sort"
"github.com/apex/up/internal/validate"
"github.com/pkg/errors"
)
// defaultStages is a list of default stage names.
var defaultStages = []string{
"development",
"staging",
"production",
}
// Stage config.
type Stage struct {
Domain string `json:"domain"`
Zone interface{} `json:"zone"`
Path string `json:"path"`
Cert string `json:"cert"`
Name string `json:"-"`
StageOverrides
}
// IsLocal returns true if the stage represents a local environment.
func (s *Stage) IsLocal() bool {
return s.Name == "development"
}
// IsRemote returns true if the stage represents a remote environment.
func (s *Stage) IsRemote() bool {
return !s.IsLocal()
}
// Validate implementation.
func (s *Stage) Validate() error {
if err := validate.Stage(s.Name); err != nil {
return errors.Wrap(err, ".name")
}
switch s.Zone.(type) {
case bool, string:
return nil
default:
return errors.Errorf(".zone is an invalid type, must be string or boolean")
}
}
// Default implementation.
func (s *Stage) Default() error {
if s.Zone == nil {
s.Zone = true
}
return nil
}
// StageOverrides config.
type StageOverrides struct {
Hooks Hooks `json:"hooks"`
Lambda Lambda `json:"lambda"`
Proxy Relay `json:"proxy"`
}
// Override config.
func (s *StageOverrides) Override(c *Config) {
s.Hooks.Override(c)
s.Lambda.Override(c)
s.Proxy.Override(c)
}
// Stages config.
type Stages map[string]*Stage
// Default implementation.
func (s Stages) Default() error {
// defaults
for _, name := range defaultStages {
if _, ok := s[name]; !ok {
s[name] = &Stage{}
}
}
// assign names
for name, s := range s {
s.Name = name
}
// defaults
for _, s := range s {
if err := s.Default(); err != nil {
return errors.Wrapf(err, "stage %q", s.Name)
}
}
return nil
}
// Validate implementation.
func (s Stages) Validate() error {
for _, s := range s {
if err := s.Validate(); err != nil {
return errors.Wrapf(err, "stage %q", s.Name)
}
}
return nil
}
// List returns configured stages.
func (s Stages) List() (v []*Stage) {
for _, s := range s {
v = append(v, s)
}
return
}
// Domains returns configured domains.
func (s Stages) Domains() (v []string) {
for _, s := range s.List() {
if s.Domain != "" {
v = append(v, s.Domain)
}
}
return
}
// Names returns configured stage names.
func (s Stages) Names() (v []string) {
for _, s := range s.List() {
v = append(v, s.Name)
}
sort.Strings(v)
return
}
// RemoteNames returns configured remote stage names.
func (s Stages) RemoteNames() (v []string) {
for _, s := range s.List() {
if s.IsRemote() {
v = append(v, s.Name)
}
}
sort.Strings(v)
return
}
// GetByDomain returns the stage by domain or nil.
func (s Stages) GetByDomain(domain string) *Stage {
for _, s := range s.List() {
if s.Domain == domain {
return s
}
}
return nil
}
// GetByName returns the stage by name or nil.
func (s Stages) GetByName(name string) *Stage {
for _, s := range s.List() {
if s.Name == name {
return s
}
}
return nil
}
================================================
FILE: config/stages_test.go
================================================
package config
import (
"testing"
"github.com/tj/assert"
)
func TestStage_Override(t *testing.T) {
c, err := ParseConfigString(`{
"name": "app",
"regions": ["us-west-2"],
"lambda": {
"memory": 128
},
"hooks": {
"build": "parcel index.html -o build",
"clean": "rm -fr build"
},
"proxy": {
"command": "node app.js"
},
"stages": {
"production": {
"lambda": {
"memory": 1024
},
"hooks": {
"build": "parcel index.html -o build --production"
}
},
"staging": {
"proxy": {
"command": "node app.js --foo=bar"
}
}
}
}`)
assert.NoError(t, err, "parse")
assert.NoError(t, c.Default(), "default")
assert.NoError(t, c.Validate(), "validate")
assert.NoError(t, c.Override("production"), "override")
assert.Equal(t, 1024, c.Lambda.Memory)
assert.Equal(t, Hook{`parcel index.html -o build --production`}, c.Hooks.Build)
assert.Equal(t, `node app.js`, c.Proxy.Command)
assert.NoError(t, c.Override("staging"), "override")
assert.Equal(t, `node app.js --foo=bar`, c.Proxy.Command)
}
func TestStages_Default(t *testing.T) {
t.Run("no custom stages", func(t *testing.T) {
s := Stages{}
assert.NoError(t, s.Default(), "default")
assert.NoError(t, s.Validate(), "validate")
assert.Len(t, s, 3)
assert.Equal(t, "staging", s["staging"].Name)
assert.Equal(t, "production", s["production"].Name)
})
t.Run("custom stages", func(t *testing.T) {
s := Stages{
"beta": &Stage{},
}
assert.NoError(t, s.Default(), "default")
assert.NoError(t, s.Validate(), "validate")
assert.Len(t, s, 4)
assert.Equal(t, "beta", s["beta"].Name)
assert.Equal(t, true, s["beta"].Zone)
})
}
func TestStages_Validate(t *testing.T) {
t.Run("no stages", func(t *testing.T) {
s := Stages{}
assert.NoError(t, s.Validate(), "validate")
})
t.Run("some stages", func(t *testing.T) {
s := Stages{
"staging": &Stage{
Domain: "gh-polls-stage.com",
},
"production": &Stage{
Domain: "gh-polls.com",
},
}
assert.NoError(t, s.Default(), "default")
assert.NoError(t, s.Validate(), "validate")
assert.Equal(t, "staging", s["staging"].Name)
assert.Equal(t, "production", s["production"].Name)
})
t.Run("valid zone boolean", func(t *testing.T) {
s := Stages{
"production": &Stage{
Domain: "gh-polls.com",
Zone: false,
},
}
assert.NoError(t, s.Default(), "default")
assert.NoError(t, s.Validate(), "validate")
})
t.Run("valid zone string", func(t *testing.T) {
s := Stages{
"production": &Stage{
Domain: "api.gh-polls.com",
Zone: "api.gh-polls.com",
},
}
assert.NoError(t, s.Default(), "default")
assert.NoError(t, s.Validate(), "validate")
})
t.Run("invalid zone type", func(t *testing.T) {
s := Stages{
"production": &Stage{
Domain: "api.gh-polls.com",
Zone: 123,
},
}
assert.NoError(t, s.Default(), "default")
assert.EqualError(t, s.Validate(), `stage "production": .zone is an invalid type, must be string or boolean`)
})
}
func TestStages_List(t *testing.T) {
stage := &Stage{
Domain: "gh-polls-stage.com",
}
prod := &Stage{
Domain: "gh-polls.com",
}
s := Stages{
"staging": stage,
"production": prod,
}
list := []*Stage{
stage,
prod,
}
stages := s.List()
assert.Equal(t, list, stages)
}
func TestStages_GetByDomain(t *testing.T) {
stage := &Stage{
Domain: "gh-polls-stage.com",
}
prod := &Stage{
Domain: "gh-polls.com",
}
s := Stages{
"staging": stage,
"production": prod,
}
assert.Equal(t, prod, s.GetByDomain("gh-polls.com"))
}
================================================
FILE: config/static.go
================================================
package config
import (
"os"
"github.com/pkg/errors"
)
// Static configuration.
type Static struct {
// Dir containing static files.
Dir string `json:"dir"`
// Prefix is an optional URL prefix for serving static files.
Prefix string `json:"prefix"`
}
// Validate implementation.
func (s *Static) Validate() error {
info, err := os.Stat(s.Dir)
if os.IsNotExist(err) {
return nil
}
if err != nil {
return errors.Wrap(err, ".dir")
}
if !info.IsDir() {
return errors.Errorf(".dir %s is not a directory", s.Dir)
}
return nil
}
================================================
FILE: config/static_test.go
================================================
package config
import (
"os"
"testing"
"github.com/tj/assert"
)
func TestStatic(t *testing.T) {
cwd, _ := os.Getwd()
table := []struct {
Static
valid bool
}{
{Static{Dir: cwd}, true},
{Static{Dir: cwd + "/static_test.go"}, false},
}
for _, row := range table {
if row.valid {
assert.NoError(t, row.Validate())
} else {
assert.Error(t, row.Validate())
}
}
}
================================================
FILE: docs/00-introduction.md
================================================
---
title: Introduction
slug: introduction
---
Up deploys infinitely scalable serverless apps, APIs, and static websites in seconds, so you can get back to working on what makes your product unique.
Up focuses on deploying "vanilla" HTTP servers so there's nothing new to learn, just develop with your favorite existing frameworks such as Express, Koa, Django, Golang net/http or others.
Up currently supports Node.js, Golang, Python, Java, Crystal, and static sites out of the box. Up is platform-agnostic, supporting AWS Lambda and API Gateway as the first targets — you can think of Up as self-hosted Heroku style user experience for a fraction of the price, with the security, flexibility, and scalability of AWS — just `$ up` and you're done!
================================================
FILE: docs/01-installation.md
================================================
---
title: Installation
slug: setup
---
Up is distributed in a binary form and can be installed manually via the [tarball releases](https://github.com/apex/up/releases) or one of the options below. The quickest way to get `up` is to run the following command:
```
$ curl -sf https://up.apex.sh/install | sh
```
By default Up is installed to `/usr/local/bin`, to specify a directory use `BINDIR`, this can be useful in CI where you may not have access to `/usr/local/bin`. Here's an example installing to the current directory:
```
$ curl -sf https://up.apex.sh/install | BINDIR=. sh
```
Verify installation with:
```
$ up version
```
Later when you want to update `up` to the latest version use the following command:
```
$ up upgrade
```
If you hit permission issues, you may need to run the following, as `up` is installed to `/usr/local/bin/up` by default.
```
$ sudo chown -R $(whoami) /usr/local/bin/
```
================================================
FILE: docs/02-aws-credentials.md
================================================
---
title: AWS Credentials
slug: credentials
---
Before using Up you need to first provide your AWS account credentials so that Up is allowed to create resources on your behalf.
## AWS credential profiles
Most AWS tools support the `~/.aws/credentials` file for storing credentials, allowing you to specify `AWS_PROFILE` environment variable so Up knows which one to reference. To read more on configuring these files view [Configuring the AWS CLI](http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html).
Here's an example of `~/.aws/credentials`, where `export AWS_PROFILE=myaccount` would activate these settings.
```
[myaccount]
aws_access_key_id = xxxxxxxx
aws_secret_access_key = xxxxxxxxxxxxxxxxxxxxxxxx
```
### Best practices
You may store the profile name in the `up.json` file itself as shown in the following snippet:
```json
{
"name": "appname-api",
"profile": "myaccount"
}
```
This is ideal as it ensures you will not accidentally deploy to a different AWS account.
## IAM policy for Up CLI
Below is a policy for [AWS Identity and Access Management](https://aws.amazon.com/iam/) which provides Up access to manage your resources. Note that the policy may change as features are added to Up, so you may have to adjust the policy.
If you're using Up for a production application it's highly recommended to configure an IAM role and user(s) for your team, restricting the access to the account and its resources.
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"acm:*",
"cloudformation:Create*",
"cloudformation:Delete*",
"cloudformation:Describe*",
"cloudformation:ExecuteChangeSet",
"cloudformation:Update*",
"cloudfront:*",
"cloudwatch:*",
"ec2:*",
"ecs:*",
"events:*",
"iam:AttachRolePolicy",
"iam:CreatePolicy",
"iam:CreateRole",
"iam:DeleteRole",
"iam:DeleteRolePolicy",
"iam:GetRole",
"iam:PassRole",
"iam:PutRolePolicy",
"lambda:AddPermission",
"lambda:Create*",
"lambda:Delete*",
"lambda:Get*",
"lambda:InvokeFunction",
"lambda:List*",
"lambda:RemovePermission",
"lambda:Update*",
"logs:Create*",
"logs:Describe*",
"logs:FilterLogEvents",
"logs:Put*",
"logs:Test*",
"route53:*",
"route53domains:*",
"s3:*",
"ssm:*",
"sns:*"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "apigateway:*",
"Resource": "arn:aws:apigateway:*::/*"
}
]
}
```
================================================
FILE: docs/03-getting-started.md
================================================
---
title: Getting Started
slug: getting-started
---
The simplest Up application is a single file for the application itself, with zero dependencies, and an `up.json` file which requires only a `name`.
If the directory does not contain an `up.json` file, the first execution of `up` will prompt you to create it, or you can manually create an `up.json` with some preferences:
```json
{
"name": "appname-api",
"profile": "companyname",
"regions": ["us-west-2"]
}
```
Up runs "vanilla" HTTP servers listening on the `PORT` environment variable, which is passed to your program by Up. For example create a new directory with the following `app.js` file:
```js
const http = require('http')
const { PORT = 3000 } = process.env
http.createServer((req, res) => {
res.end('Hello World from Node.js\n')
}).listen(PORT)
```
Deploy it to the staging environment:
```
$ up
```
Open up the URL in your browser:
```
$ up url --open
```
Or test with curl:
```
$ curl `up url`
```
That's it! You've deployed a basic Up application. To view further help for commands use:
```
$ up help
$ up help COMMAND
$ up help COMMAND SUBCOMMAND
```
If you're not a Node.js developer here are some examples in additional languages.
For Python create `app.py`:
```python
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
import os
class myHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
self.wfile.write("Hello World from Python\n")
return
server = HTTPServer(('', int(os.environ['PORT'])), myHandler)
server.serve_forever()
```
For Golang create `main.go`:
```go
package main
import (
"os"
"fmt"
"log"
"net/http"
)
func main() {
addr := ":"+os.Getenv("PORT")
http.HandleFunc("/", hello)
log.Fatal(http.ListenAndServe(addr, nil))
}
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello World from Go")
}
```
Finally for Crystal create `main.cr`:
```ruby
require "http/server"
port = ENV["PORT"].to_i
server = HTTP::Server.new(port) do |ctx|
ctx.response.content_type = "text/plain"
ctx.response.print "Hello world from Crystal"
end
server.listen
```
================================================
FILE: docs/04-configuration.md
================================================
---
title: Configuration
slug: configuration
---
Configuration for your app lives in the `up.json` within your project's directory. This section details each of the options available.
## Name
The name of the application, which is used to name resources such as the Lambda function or API Gateway.
```json
{
"name": "api"
}
```
## Profile
The `profile` property is equivalent to setting `AWS_PROFILE` for referencing AWS credentials in the `~/.aws` directory. Use of this property is preferred as it prevents accidents with environment variables.
```json
{
"profile": "someapp"
}
```
## Regions
You may specify a target region for deployments using the `regions` array. By default "us-west-2" is used unless the `AWS_REGION` environment variable is defined.
Note: Currently only a single region is supported, however you can deploy to many regions one at a time for global deploys, see https://medium.com/@tjholowaychuk/global-serverless-apps-with-aws-lambda-api-gateway-4642ef1f221d for details.
A single region:
```json
{
"regions": ["us-west-2"]
}
```
Currently Lambda supports the following regions:
- **us-east-2** – US East (Ohio)
- **us-east-1** – US East (N. Virginia)
- **us-west-1** – US West (N. California)
- **us-west-2** – US West (Oregon)
- **ap-northeast-2** – Asia Pacific (Seoul)
- **ap-south-1** – Asia Pacific (Mumbai)
- **ap-southeast-1** – Asia Pacific (Singapore)
- **ap-southeast-2** – Asia Pacific (Sydney)
- **ap-northeast-1** – Asia Pacific (Tokyo)
- **ca-central-1** – Canada (Central)
- **eu-central-1** – EU (Frankfurt)
- **eu-west-1** – EU (Ireland)
- **eu-west-2** – EU (London)
- **eu-west-3** – EU (Paris)
- **eu-north-1** – EU (Stockholm)
- **sa-east-1** – South America (São Paulo)
## Lambda settings
The following Lambda-specific settings are available:
- `role` – IAM role ARN, defaulting to the one Up creates for you
- `memory` – Function memory in mb (Default `512`, Min `128`, Max `3008`)
- `policy` – IAM function policy statement(s)
- `runtime` — Lambda function runtime. (Default `nodejs10.x`)
- `vpc` - VPC subnets and security groups
For example:
```json
{
"name": "api",
"lambda": {
"memory": 512,
"runtime": "nodejs8.10",
"vpc": {
"subnets": [
"subnet-aaaaaaa",
"subnet-bbbbbbb",
"subnet-ccccccc",
],
"security_groups": [
"sg-xxxxxxx"
]
}
}
}
```
The Lambda `memory` setting also scales the CPU, if your app is slow, or for cases such as larger Node applications with many `require()`s you may need to increase this value. View the [Lambda Pricing](https://aws.amazon.com/lambda/pricing/) page for more information regarding the `memory` setting.
Using Up Pro in a VPC requires access to the that the AWS SSM Parameter Store API for environment variables, otherwise the app may appear to "hang" and timeout when loading secrets. Removing VPC configuration must currently be done in the AWS console.
Note: Changes to Lambda configuration do not require a `up stack apply`, just deploy and these changes are picked up!
### IAM policy
Up uses IAM policies to grant access to resources within your AWS account such as DynamoDB or S3.
To add additional permissions add one or more IAM policy statements to the `policy` array, in the following example we permit DynamoDB item reading, updating, and deleting.
```json
{
"name": "myapp",
"lambda": {
"memory": 1024,
"policy": [
{
"Effect": "Allow",
"Resource": "*",
"Action": [
"dynamodb:Get*",
"dynamodb:List*",
"dynamodb:PutItem",
"dynamodb:DeleteItem"
]
}
]
}
}
```
Deploy to update the IAM function role permissions.
## Hook scripts
Up provides "hooks" which are commands invoked at certain points within the deployment workflow for automating builds, linting and so on. The following hooks are available:
- `prebuild` – Run before building
- `build` – Run before building. Overrides inferred build command(s)
- `postbuild` – Run after building
- `predeploy` – Run before deploying
- `postdeploy` – Run after deploying
- `clean` – Run after a deploy to clean up artifacts. Overrides inferred clean command(s)
Here's an example using Browserify to bundle a Node application. Use the `-v` verbose log flag to see how long each hook takes.
```json
{
"name": "app",
"hooks": {
"build": "browserify --node app.js > server.js",
"clean": "rm server.js"
}
}
```
Up performs runtime inference to discover what kind of application you're using, and does its best to provide helpful defaults – see the [Runtimes](#runtimes) section.
Multiple commands are provided by using arrays, and are run in separate shells:
```json
{
"name": "app",
"hooks": {
"build": [
"mkdir -p build",
"cp -fr static build",
"browserify --node index.js > build/client.js"
],
"clean": "rm -fr build"
}
}
```
To get a better idea of when hooks run, and how long the command(s) take, you may want to deploy with `-v` for verbose debug logs.
## Static file serving
Up ships with a robust static file server, to enable it specify the app `type` as `"static"`.
```json
{
"type": "static"
}
```
By default the current directory (`.`) is served, however you can change this using the `dir` setting. The following configuration restricts only serving of files in `./public/*`, any attempts to read files from outside of this root directory will fail.
```json
{
"name": "app",
"type": "static",
"static": {
"dir": "public"
}
}
```
Note that `static.dir` only tells Up which directory to serve – it does not exclude other files from the deployment – see [Ignoring Files](#ignoring_files). For example you may want an `.upignore` containing:
```
*
!public/**
```
Note: Files are currently served from AWS Lambda as well, so there is a 6MB restriction on the file size.
### Dynamic applications
If your project is not strictly static, for example a Node.js web app, you may omit `type` and add static file serving simply by defining `static` as shown below. With this setup Up will serve the file if it exists, before passing control to your application.
```json
{
"name": "app",
"static": {
"dir": "public"
}
}
```
By default there is no prefix, so `GET /index.css` will resolve to `./public/index.css`, however, you may specify a prefix such as "/static/" for `GET /static/index.css` to ensure static files never conflict with your app's routes:
```json
{
"name": "app",
"static": {
"dir": "public",
"prefix": "/static/"
}
}
```
Note: Static file serving for dynamic apps does not automatically resolve `index.html` files. The presence of a file is checked before passing control to your application.
## Environment variables
The `environment` object may be used for plain-text environment variables. Note that these are not encrypted, and are stored in up.json which is typically committed to GIT, so do not store secrets here.
```json
{
"name": "api",
"environment": {
"API_FEATURE_FOO": "1",
"API_FEATURE_BAR": "0"
}
}
```
These become available to you via `process.env.API_FEATURES_FOO`, `os.Getenv("API_FEATURES_FOO")` or similar in your language of choice.
The following environment variables are provided by Up:
- `PORT` – port number such as "3000"
- `UP_STAGE` – stage name such as "staging" or "production"
## Header injection
The `headers` object allows you to map HTTP header fields to paths. The most specific pattern takes precedence.
Here's an example of two header fields specified for `/*` and `/*.css`:
```json
{
"name": "app",
"type": "static",
"headers": {
"/*": {
"X-Something": "I am applied to everything"
},
"/*.css": {
"X-Something-Else": "I am applied to styles"
}
}
}
```
Requesting `GET /` will match the first pattern, injecting `X-Something`:
```
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 200
Content-Type: text/html; charset=utf-8
Last-Modified: Fri, 21 Jul 2017 20:42:51 GMT
X-Powered-By: up
X-Something: I am applied to everything
Date: Mon, 31 Jul 2017 20:49:33 GMT
```
Requesting `GET /style.css` will match the second, more specific pattern, injecting `X-Something-Else`:
```json
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 50
Content-Type: text/css; charset=utf-8
Last-Modified: Fri, 21 Jul 2017 20:42:51 GMT
X-Powered-By: up
X-Something-Else: I am applied to styles
Date: Mon, 31 Jul 2017 20:49:35 GMT
```
## Error pages
When enabled Up will serve a minimalistic error page for requests accepting `text/html`. The following settings are available:
- `enable` — enable the error page feature
- `dir` — the directory where the error pages are located
- `variables` — vars available to the pages
The default template's `color` and optionally provide a `support_email` to allow customers to contact your support team, for example:
```json
{
"name": "site",
"type": "static",
"error_pages": {
"enable": true,
"variables": {
"support_email": "support@apex.sh",
"color": "#228ae6"
}
}
}
```
If you'd like to provide custom templates you may create one or more of the following files. The most specific file takes precedence.
- `error.html` – Matches any 4xx or 5xx
- `5xx.html` – Matches any 5xx error
- `4xx.html` – Matches any 4xx error
- `CODE.html` – Matches a specific code such as 404.html
Variables specified via `variables`, as well as `.StatusText` and `.StatusCode` may be used in the template.
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{.StatusText}} - {{.StatusCode}}</title>
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<h1>{{.StatusText}}</h1>
{{with .Variables.support_email}}
<span class="message">Please try your request again or <a href="mailto:{{.}}">contact support</a>.</span>
{{else}}
<span class="message">Please try your request again or contact support.</span>
{{end}}
</body>
</html>
```
## Script injection
Scripts, styles, and other tags may be injected to HTML pages before the closing `</head>` tag or closing `</body>` tag.
In the following example the `<link rel="/style.css">` is injected to the head, as well as the inlining the `scripts/config.js` file. A `<script src="/app.js"></script>` is then injected into the body.
```json
{
"name": "site",
"type": "static",
"inject": {
"head": [
{
"type": "style",
"value": "/style.css"
},
{
"type": "inline script",
"file": "scripts/config.js"
}
],
"body": [
{
"type": "script",
"value": "/app.js"
}
]
}
}
```
Currently you may specify the following types:
- `literal` – A literal string
- `comment` – An html comment
- `style` – A style `href`
- `script` – A script `src`
- `inline style` – An inline style
- `inline script` – An inline script
- `google analytics` – Google Analytics snippet with API key
- `segment` – Segment snippet with API key
All of these require a `value`, which sets the `src`, `href`, or inline content. Optionally you can populate `value` via a `file` path to a local file on disk, this is typically more convenient for inline scripts or styles. For example:
- `{ "type": "literal", "value": "<meta name=...>" }`
- `{ "type": "comment", "value": "Just a boring comment" }`
- `{ "type": "script", "value": "/feedback.js" }`
- `{ "type": "style", "value": "/feedback.css" }`
- `{ "type": "inline script", "file": "/feedback.js" }`
- `{ "type": "inline style", "file": "/feedback.css" }`
- `{ "type": "script", "value": "var config = {};" }`
- `{ "type": "google analytics", "value": "API_KEY" }`
- `{ "type": "segment", "value": "API_KEY" }`
## Redirects and rewrites
Up supports redirects and URL rewriting via the `redirects` object, which maps path patterns to a new location. If `status` is omitted (or 200) then it is a rewrite, otherwise it is a redirect.
```json
{
"name": "app",
"type": "static",
"redirects": {
"/blog": {
"location": "https://blog.apex.sh/",
"status": 301
},
"/docs/:section/guides/:guide": {
"location": "/help/:section/:guide",
"status": 302
},
"/store/*": {
"location": "/shop/:splat"
}
}
}
```
In the previous example `/blog` will redirect to a different site, while `/docs/ping/guides/alerting` will redirect to `/help/ping/alerting`. Finally `/store/ferrets` and nested paths such as `/store/ferrets/tobi` will redirect to `/shop/ferrets/tobi` and so on.
A common use-case for rewrites is for SPAs or Single Page Apps, where you want to serve the `index.html` file regardless of the path. The other common requirement for SPAs is that you of course can serve scripts and styles, so by default if a file is found, it will not be rewritten to `location`.
```json
{
"name": "app",
"type": "static",
"redirects": {
"/*": {
"location": "/",
"status": 200
}
}
}
```
If you wish to force the rewrite regardless of a file existing, set `force` to `true` as shown here:
```json
{
"name": "app",
"type": "static",
"redirects": {
"/*": {
"location": "/",
"status": 200,
"force": true
}
}
}
```
More specific target paths take precedence over those which are less specific, for example `/blog` will win over and `/*`.
## Cross-Origin Resource Sharing
CORS is a mechanism which allows requests originating from a different host to make requests to your API. Several options are available to restrict this access, if the defaults are appropriate simply enable it as shown below.
```json
{
"cors": {
"enable": true
}
}
```
Suppose you have `https://api.myapp.com`, you may want to customize `cors` to permit access only from `https://myapp.com` so that other sites cannot call your API directly.
```json
{
"cors": {
"allowed_origins": ["https://myapp.com"],
"allowed_methods": ["HEAD", "GET", "POST", "PUT", "PATCH", "DELETE"],
"allowed_headers": ["*"],
"allow_credentials": true
}
}
```
- `allowed_origins` – A list of origins a cross-domain request can be executed from. Use `*` to allow any origin, or a wildcard such as `http://*.domain.com` (Default: `["*"]`)
- `allowed_methods` – A list of methods the client is allowed to use with cross-domain requests. (Default: `["HEAD", "GET", "POST"]`)
- `allowed_headers` – A list of headers the client is allowed to use with cross-domain requests. If the special `*` value is present in the list, all headers will be allowed. (Default: `["Origin", "Accept", "Content-Type", "X-Requested-With"]`)
- `exposed_headers` – A list of headers which are safe to expose to the API of a CORS response.
- `max_age` – A number indicating how long (in seconds) the results of a preflight request can be cached.
- `allow_credentials` – A boolean indicating whether the request can include user credentials such as cookies, HTTP authentication or client side SSL certificates. (Default: `true`)
- `debug` - A boolean which will output debug logs (Default: `false`)
Here's an example performing a GraphQL query with `fetch()`, note that `Accept` is set to accept only JSON:
```js
const body = JSON.stringify({
query: `query {
pet(id: 2) {
name
}
}`
})
const res = await fetch('https://myapp.com', {
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
method: 'POST',
body
})
```
Note: You do not need to run `up stack plan` for CORS settings, simply redeploy the stage.
## Reverse proxy
Up acts as a reverse proxy in front of your server, this is how CORS, redirection, script injection and other middleware style features are provided.
The following settings are available:
- `command` – Command run through the shell to start your server (Default `./server`)
- When `package.json` is detected `npm start` is used
- When `app.js` is detected `node app.js` is used
- `timeout` – Timeout in seconds per request (Default `15`, Max `25`)
- `listen_timeout` – Timeout in seconds Up will wait for your app to boot and listen on `PORT` (Default `15`, Max `25`)
```json
{
"proxy": {
"command": "node app.js",
"timeout": 10,
"listen_timeout": 5
}
}
```
Lambda's function timeout is implied from the `.proxy.timeout` setting.
### Crash recovery
Another benefit of using Up as a reverse proxy is performing crash recovery. Up will attempt to restart your application if the process crashes to continue serving subsequent requests.
## DNS zones & records
Up allows you to configure DNS zones and records. One or more zones may be provided as keys in the `dns` object ("myapp.com" here), with a number of records defined within it.
```json
{
"name": "gh-polls",
"dns": {
"gh-polls.com": [
{
"name": "app.gh-polls.com",
"type": "CNAME",
"value": ["gh-polls.netlify.com"]
}
]
}
}
```
The record `type` must be one of:
- A
- AAAA
- CNAME
- MX
- NAPTR
- NS
- PTR
- SOA
- SPF
- SRV
- TXT
## Stages
Up supports the concept of "stages" for configuration, such as mapping of custom domains, or tuneing the size of Lambda function to use.
By default the following stages are defined:
- `development` — local development environment
- `staging` — remote environment for staging new features or releases
- `production` — remote environment for production
To create a new stage, first add it to your configuration, in this case we'll call it "beta":
```json
{
"name": "app",
"lambda": {
"memory": 128
},
"stages": {
"beta": {
}
}
}
```
Now you'll need to plan your stack changes, which will set up a new API Gateway and permissions:
```
$ up stack plan
Add api deployment
id: ApiDeploymentBeta
Add lambda permission
id: ApiLambdaPermissionBeta
```
Apply those changes:
```
$ up stack apply
```
Now you can deploy to your new stage by passing the name `beta` and open the end-point in the browser:
```
$ up beta
$ up url -o beta
```
To delete a stage, simply remove it from the `up.json` configuration and run `up stack plan` again, and `up stack apply` after reviewing the changes.
You may of course assign a custom domain to these stages as well, let's take a look at that next!
## Stages & custom domains
By defining a stage and its `domain`, Up knows it will need to create a free SSL certificate—`gh-polls.com` in the following example—setup the DNS records, and map the domain to API Gateway. SSL certificates are managed via [AWS ACM](https://aws.amazon.com/certificate-manager/) which automatically renew for you, there's no additional work or cost associated with them.
```json
{
"stages": {
"production": {
"domain": "gh-polls.com"
}
}
}
```
Here's another example mapping each stage to a domain, note that the domains do not need to be related, you could use `stage-gh-polls.com` for example.
```json
{
"stages": {
"production": {
"domain": "gh-polls.com"
},
"staging": {
"domain": "stage.gh-polls.com"
}
}
}
```
You may also provide an optional base path, for example to prefix your API with `/v1`. Note that currently your application will still receive "/v1" in its request path, for example Node's `req.url` will be "/v1/users" instead of "/users".
```json
{
"stages": {
"production": {
"domain": "api.gh-polls.com",
"path": "/v1"
}
}
}
```
Plan the changes via `up stack plan` and `up stack apply` to perform the changes. You may [purchase domains](#guides.development_to_production_workflow.purchasing_a_domain) from the command-line, or map custom domains from other registrars. Up uses Route53 to purchase domains using your AWS account credit card. See `up help domains`.
Note: CloudFront can take up to ~40 minutes to distribute this configuration the first time, so grab a coffee while these changes are applied. Also note that ACM certificates are always created in the Virginia (us-east-1) region due to how API Gateway interoperates with CloudFront.
### DNS zones
By default when you specify a stage `domain` — such as "api.example.com" — a DNS zone is created in Route53 for the top level domain "example.com", and an ALIAS record "api.example.com" is added to this zone.
If you're using external DNS and wish to omit the zone entirely you can disable it with the `zone` property:
```json
{
"stages": {
"production": {
"domain": "gh-polls.com",
"zone": false
}
}
}
```
You may also explicitly specify the zone by providing a string. In the following example an "api.gh-polls.com" zone will be created, instead of putting the record in "gh-polls.com".
```json
{
"stages": {
"production": {
"domain": "api.gh-polls.com",
"zone": "api.gh-polls.com"
}
}
}
```
## Stage overrides
Up allows some configuration properties to be overridden at the stage level. The following example illustrates how you can tune lambda memory and hooks per-stage.
```json
{
"name": "app",
"hooks": {
"build": "parcel index.html --no-minify -o build",
"clean": "rm -fr build"
},
"stages": {
"production": {
"hooks": {
"build": "parcel index.html -o build"
},
"lambda": {
"memory": 1024
}
}
}
}
```
Currently the following properties may be specified at the stage level:
- `hooks`
- `lambda`
- `proxy.command`
For example you may want to override `proxy.command` for development, which is the env `up start` uses. In the following example [gin](https://github.com/codegangsta/gin) is used for hot reloading of Go programs:
```json
{
"name": "app",
"stages": {
"development": {
"proxy": {
"command": "gin --port $PORT"
}
}
}
}
```
## Logs
By default Up treats stdout as `info` level logs, and stderr as `error` level. If your logger uses stderr, such as Node's `debug()` module and you'd like to change this behaviour you may override these levels:
```json
{
"name": "app",
"environment": {
"DEBUG": "myapp"
},
"logs": {
"stdout": "info",
"stderr": "info"
}
}
```
You can disable Up's logs entirely by using the "disable" option:
```json
{
"logs": {
"disable": true
}
}
```
## Ignoring files
Up supports gitignore style pattern matching for omitting files from deployment via the `.upignore` file.
An example `.upignore` to omit markdown and `.go` source files might look like this:
```
*.md
*.go
```
### Negation
By default dotfiles are ignored, if you wish to include them, you may use `!` to negate a pattern in `.upignore`:
```
!.myfile
```
Another use-case for negation is to ignore everything and explicitly include a number of files instead, to be more specific:
```
*
!app.js
!package.json
!node_modules/**
!src/**
```
### Inspecting
To get a better idea of which files are being filtered or added, use `up -v` when deploying, and you may also find it useful to `grep` in some cases:
```
$ up -v 2>&1 | grep filtered
DEBU filtered .babelrc – 25
DEBU filtered .git – 408
DEBU filtered .gitignore – 13
DEBU filtered node_modules/ansi-regex/readme.md – 1749
DEBU filtered node_modules/ansi-styles/readme.md – 1448
DEBU filtered node_modules/binary-extensions/readme.md – 751
DEBU filtered node_modules/chalk/readme.md – 6136
```
You may also wish to use `up build --size` to view the largest files within the zip.
### Pattern matching
Note that patterns are matched much like `.gitignore`, so if you have the following `.upignore` contents even `node_modules/debug/src/index.js` will be ignored since it contains `src`.
```
src
```
You can be more specific with a leading `./`:
```
./src
```
Files can be matched recursively using `**`, for example ignoring everything except the files in `dist`:
```
*
!dist/**
```
================================================
FILE: docs/05-runtimes.md
================================================
---
title: Runtimes
slug: runtimes
---
Up supports a number of interpreted languages, and virtually any language which can be compiled to a binary such as Golang. Up does its best to provide idiomatic and useful out-of-the-box experiences tailored to each language. Currently first-class support is provided for:
- Golang
- Node.js
- Crystal
- Static sites
## Node.js
When a `package.json` file is detected, Node.js is the assumed runtime. By default `nodejs10.x` is used, see [Lambda Settings](https://apex.sh/docs/up/configuration/#lambda_settings) for details.
The `build` hook becomes:
```
$ npm run build
```
The server run by the proxy becomes:
```
$ npm start
```
## Golang
When a `main.go` file is detected, Golang is the assumed runtime.
The `build` hook becomes:
```
$ GOOS=linux GOARCH=amd64 go build -o server *.go
```
The `clean` hook becomes:
```
$ rm server
```
## Crystal
When a `main.cr` file is detected, Crystal is the assumed runtime. Note that this runtime requires Docker to be installed.
The `build` hook becomes:
```
$ docker run --rm -v $(pwd):/src -w /src crystallang/crystal crystal build -o server main.cr --release --static
```
The `clean` hook becomes:
```
$ rm server
```
## Static
When an `index.html` file is detected the project is assumed to be static.
================================================
FILE: docs/06-commands.md
================================================
---
title: Commands
slug: commands
---
Up provides the `up` command-line program, used to deploy the app, and manage associated resources such as domains and SSL certificates, as well as operational tasks like viewing logs.
To view details for a command at any time use `up help`, `up help <command>`, for example `up help team members add`.
```
Usage:
up [<flags>] <command> [<args> ...]
Flags:
-h, --help Output usage information.
-C, --chdir="." Change working directory.
-v, --verbose Enable verbose log output.
--format="text" Output formatter.
--version Show application version.
Commands:
help Show help for a command.
build Build zip file.
config Show configuration after defaults and validation.
deploy Deploy the project.
docs Open documentation website in the browser.
domains ls List purchased domains.
domains check Check availability of a domain.
domains buy Purchase a domain.
env ls List variables.
env add Add a variable.
env rm Remove a variable.
logs Show log output.
metrics Show project metrics.
rollback Rollback to a previous deployment.
prune Prune old S3 deployments of a stage.
run Run a hook.
stack plan Plan configuration changes.
stack apply Apply configuration changes.
stack delete Delete configured resources.
stack status Show status of resources.
start Start development server.
team status Status of your account.
team switch Switch active team.
team login Sign in to your account.
team logout Sign out of your account.
team members add Add invites a team member.
team members rm Remove a member or invite.
team members ls List team members and invites.
team subscribe Subscribe to the Pro plan.
team unsubscribe Unsubscribe from the Pro plan.
team card change Change the default card.
team ci Credentials for CI.
team add Add a new team.
upgrade Install the latest or specified version of Up.
url Show, open, or copy a stage endpoint.
version Show version.
Examples:
Deploy the project to the staging environment.
$ up
Deploy the project to the production stage.
$ up deploy production
Show the staging endpoint url.
$ up url
Tail project logs.
$ up logs -f
Show error or fatal level logs.
$ up logs 'error or fatal'
Run build command manually.
$ up run build
Show help and examples for a command.
$ up help team
Show help and examples for a sub-command.
$ up help team members
```
## Deploy
Deploy the project, by default to the "staging" stage. Note that running `up` and `up deploy` are identical, as it is the default command.
```
Usage:
up deploy [<stage>]
Flags:
-h, --help Output usage information.
-C, --chdir="." Change working directory.
-v, --verbose Enable verbose log output.
--format="text" Output formatter.
--version Show application version.
Args:
[<stage>] Target stage name.
```
### Examples
Deploy the project to the staging stage.
```
$ up
```
Deploy the project to the staging stage, this is the same as running `up` without arguments.
```
$ up deploy
```
Deploy the project to the production stage.
```
$ up deploy production
```
Note that since `deploy` is the default command the following is also valid:
```
$ up production
```
## Config
Validate and output configuration with defaults applied.
```
$ up config
```
```json
{
"name": "app",
"description": "",
"type": "server",
"headers": null,
"redirects": null,
"hooks": {
"build": "GOOS=linux GOARCH=amd64 go build -o server *.go",
"clean": "rm server"
},
"environment": null,
"regions": [
"us-west-2"
],
"inject": null,
"lambda": {
"role": "arn:aws:iam::ACCOUNT:role/lambda_function",
"memory": 128,
"timeout": 5
},
"cors": null,
"error_pages": {
"dir": ".",
"variables": null
},
"proxy": {
"command": "./server",
"backoff": {
"min": 100,
"max": 500,
"factor": 2,
"attempts": 3,
"jitter": false
}
},
"static": {
"dir": "."
},
"logs": {
"disable": false
},
"dns": {
"zones": null
}
}
...
```
## Logs
Show or tail log output with optional query for filtering. When viewing or tailing logs, you are viewing them from _all_ stages, see the examples below to filter on a stage name.
```
Usage:
up logs [<flags>] [<query>]
Flags:
-h, --help Output usage information.
-C, --chdir="." Change working directory.
-v, --verbose Enable verbose log output.
--format="text" Output formatter.
--version Show application version.
-f, --follow Follow or tail the live logs.
-S, --since="1d" Show logs since duration (30s, 5m, 2h, 1h30m, 3d, 1M).
-e, --expand Show expanded logs.
Args:
[<query>] Query pattern for filtering logs.
```
### Expanded output
Use the `-e` or `--expand` flag to expand log fields:
```
$ up -e 'path = "/static/*"'
1:36:34pm INFO request
id: 8ff53267-c33a-11e7-9685-15d48d102ae9
ip: 70.66.179.182
method: GET
path: /static/3.jpg
stage: production
version: 5
1:36:34pm INFO response
duration: 1ms
id: 8ff53267-c33a-11e7-9685-15d48d102ae9
ip: 70.66.179.182
method: GET
path: /static/3.jpg
size: 0 B
stage: production
status: 304
version: 5
1:36:34pm INFO request
id: 8ff4bd57-c33a-11e7-bf4b-4f0d97c427c5
ip: 70.66.179.182
method: GET
path: /static/1.png
stage: production
version: 5
```
### JSON output
When stdout is not a terminal Up will output the logs as JSON, which can be useful for further processing with tools such as [jq](https://stedolan.github.io/jq/).
In this contrived example the last 5 hours of production errors are piped to `jq` to produce a CSV of HTTP methods to IP address.
```
$ up logs -s 5h 'production error' | jq -r '.|[.fields.method,.fields.ip]|@csv'
```
Yielding:
```
"GET","207.194.34.24"
"GET","207.194.34.24"
"GET","207.194.34.24"
```
### Examples
Show logs from the past day.
```
$ up logs
```
Show logs from the past 45 minutes.
```
$ up -S 45m logs
```
Show logs from the past 12 hours.
```
$ up -S 12h logs
```
Show live log output.
```
$ up logs -f
```
Show live logs from production only.
```
$ up logs -f production
```
Show live error logs from production only.
```
$ up logs -f 'production error'
```
Show error logs, which include 5xx responses.
```
$ up logs error
```
Show error and warning logs, which include 4xx and 5xx responses.
```
$ up logs 'warn or error'
```
Show logs with a specific message.
```
$ up logs 'message = "user login" method = "GET"'
```
Show logs with a specific message with implicit `=`:
```
$ up logs '"user login" method = "GET"'
```
Show responses with latency above 15ms.
```
$ up logs 'duration > 15'
```
Show 4xx and 5xx responses in production
```
$ up logs 'production (warn or error)'
```
Show production 5xx responses with a POST, PUT, or DELETE method.
```
$ up logs 'production error method in ("POST", "PUT", "DELETE")
```
Show 200 responses with latency above 1500ms.
```
$ up logs 'status = 200 duration > 1.5s'
```
Show responses with bodies larger than 100kb.
```
$ up logs 'size > 100kb'
```
Show 4xx and 5xx responses.
```
$ up logs 'status >= 400'
```
Show emails containing @apex.sh.
```
$ up logs 'user.email contains "@apex.sh"'
```
Show emails ending with @apex.sh.
```
$ up logs 'user.email = "*@apex.sh"'
```
Show emails starting with tj@.
```
$ up logs 'user.email = "tj@*"'
```
Show logs with a more complex query.
```
$ up logs 'method in ("POST", "PUT") ip = "207.*" status = 200 duration >= 50'
```
## URL
Show, open, or copy a stage endpoint.
```
Usage:
up url [<flags>]
Flags:
-h, --help Output usage information.
-C, --chdir="." Change working directory.
-v, --verbose Enable verbose log output.
--format="text" Output formatter.
--version Show application version.
-s, --stage="staging" Target stage name.
-o, --open Open endpoint in the browser.
-c, --copy Copy endpoint to the clipboard.
```
### Examples
Show the staging endpoint.
```
$ up url
```
Open the staging endpoint in the browser.
```
$ up url --open
```
Copy the staging endpoint to the clipboard.
```
$ up url --copy
```
Show the production endpoint.
```
$ up url -s production
```
Open the production endpoint in the browser.
```
$ up url -o -s production
```
Copy the production endpoint to the clipboard.
```
$ up url -c -s production
```
## Metrics
Show project metrics and estimated cost breakdown for requests, invocation count and the time spent for Lambda invocations.
```
Usage:
up metrics [<flags>]
Flags:
-h, --help Output usage information.
-C, --chdir="." Change working directory.
-v, --verbose Enable verbose log output.
--format="text" Output formatter.
--version Show application version.
-s, --stage="staging" Target stage name.
-S, --since="1M" Show metrics since duration (30s, 5m, 2h, 1h30m, 3d, 1M).
```
For example:
```
$ up metrics -s production -S 15d
Requests: 13,653 ($0.01)
Duration min: 0ms
Duration avg: 48ms
Duration max: 15329ms
Duration sum: 3m6.611s ($0.00)
Errors 4xx: 1,203
Errors 5xx: 2
Invocations: 12,787 ($0.00)
Errors: 0
Throttles: 0
```
## Start
Start development server. The development server runs the same proxy that is used in production for serving, so you can test a static site or application locally with the same feature-set.
See [Stage Overrides](https://up.docs.apex.sh/#configuration.stage_overrides) for an example of overriding the proxy command per-stage, especially useful in development.
Up Pro supports environment variables, and these will be loaded with `up start`, and variables mapped to the "development" stage will take precedence. For example:
```
$ up env set NAME Tobi
$ up start # app has NAME available as Tobi
$ up env set NAME Loki -s development
$ up start # app has NAME available Loki
```
The `UP_STAGE` and `NODE_ENV` environment variables will be set to "development" automatically.
```
Usage:
up start [<flags>]
Flags:
-h, --help Output usage information.
-C, --chdir="." Change working directory.
-v, --verbose Enable verbose log output.
--format="text" Output formatter.
--version Show application version.
-c, --command=COMMAND Proxy command override
-o, --open Open endpoint in the browser.
--address=":3000" Address for server.
```
### Examples
Start development server on port 3000.
```
$ up start
```
Start development server on port 5000.
```
$ up start --address :5000
```
Override proxy command. Note that the server created must listen on `PORT`, which is why `--port $PORT` is required for the [gin](https://github.com/codegangsta/gin) example.
```
$ up start -c 'go run main.go'
$ up start -c 'gin --port $PORT'
$ up start -c 'node --some-flag app.js'
$ up start -c 'parcel'
```
## Domains
Manage domain names, and purchase them from AWS Route53 as the registrar.
```
Usage:
up domains <command> [<args> ...]
Flags:
-h, --help Output usage information.
-C, --chdir="." Change working directory.
-v, --verbose Enable verbose log output.
--version Show application version.
Subcommands:
domains list List purchased domains.
domains check Check availability of a domain.
domains buy Purchase a domain.
```
### Examples
List purchased domains.
```
$ up domains
```
Check availability of a domain.
```
$ up domains check example.com
```
Purchase a domain (with interactive form).
```
$ up domains buy
```
## Stack
Stack resource management. The stack is essentially all of the resources powering your app, which is configured by Up on the first deploy.
At any time if you'd like to delete the application simply run `$ up stack delete`. To view the status and potential errors use `$ up stack`.
```
Usage:
up stack <command> [<args> ...]
Flags:
-h, --help Output usage information.
-C, --chdir="." Change working directory.
-v, --verbose Enable verbose log output.
--version Show application version.
Subcommands:
stack plan Plan configuration changes.
stack apply Apply configuration changes.
stack delete Delete configured resources.
stack status Show status of resources.
```
### Examples
Show status of the stack resources and nameservers.
```
$ up stack
```
Show resource changes.
```
$ up stack plan
```
Apply resource changes.
```
$ up stack apply
```
Delete the stack resources.
```
$ up stack delete
```
## Build
Build zip file, typically only helpful for inspecting its contents. If you're interested in seeing what files are causing bloat, use the `--size` flag to list files by size descending.
```
Usage:
up build [<flags>]
Flags:
-h, --help Output usage information.
-C, --chdir="." Change working directory.
-v, --verbose Enable verbose log output.
--format="text" Output formatter.
--version Show application version.
-s, --stage="staging" Target stage name.
--size Show zip contents size information.
```
### Examples
Build archive and save to ./out.zip
```
$ up build
```
Build archive and output to file via stdout.
```
$ up build > /tmp/out.zip
```
Build archive list files by size.
```
$ up build --size
```
Build archive and list size without creating out.zip.
```
$ up build --size > /dev/null
```
## Team
Manage team members, plans, and billing.
```
Usage:
up team <command> [<args> ...]
Flags:
-h, --help Output usage information.
-C, --chdir="." Change working directory.
-v, --verbose Enable verbose log output.
--format="text" Output formatter.
--version Show application version.
Subcommands:
team status Status of your account.
team switch Switch active team.
team login Sign in to your account.
team logout Sign out of your account.
team members add Add invites a team member.
team members rm Remove a member or invite.
team members ls List team members and invites.
team subscribe Subscribe to the Pro plan.
team unsubscribe Unsubscribe from the Pro plan.
team card change Change the default card.
team ci Credentials for CI.
team add Add a new team.
```
### Examples
Show active team and subscription status.
```
$ up team
```
Switch teams interactively.
```
$ up team switch
```
Sign in or create account with interactive prompt.
```
$ up team login
```
Sign in to a team.
```
$ up team login --email tj@example.com --team apex-software
```
Add a new team and automatically switch to the team.
```
$ up team add "Apex Software"
```
Subscribe to the Pro plan.
```
$ up team subscribe
```
Invite a team member to your active team.
```
$ up team members add asya@example.com
```
## Upgrade
Install the latest or specified version of Up. The OSS and Pro versions have independent semver, as bugfixes and features for one may not be relevant to the other.
If you're an Up Pro subscriber, `up upgrade` will _always_ install Up Pro, even when `--target` is specified, there is no need to specify that you want the Pro version.
```
Usage:
up upgrade [<flags>]
Flags:
-h, --help Output usage information.
-C, --chdir="." Change working directory.
-v, --verbose Enable verbose log output.
--format="text" Output formatter.
--version Show application version.
-t, --target=TARGET Target version for upgrade.
```
### Examples
Upgrade to the latest version available.
```
$ up upgrade
```
Upgrade to the specified version.
```
$ up upgrade -t 0.4.4
```
## Prune
Prune old S3 deployments of a stage.
```
Usage:
up prune [<flags>]
Flags:
-h, --help Output usage information.
-C, --chdir="." Change working directory.
-v, --verbose Enable verbose log output.
--format="text" Output formatter.
--version Show application version.
-s, --stage="staging" Target stage name.
-r, --retain=30 Number of versions to retain.
```
### Examples
Prune and retain the most recent 30 staging versions.
```
$ up prune
```
Prune and retain the most recent 30 production versions.
```
$ up prune -s production
```
Prune and retain the most recent 15 production versions.
```
$ up prune -s production -r 15
```
================================================
FILE: docs/07-guides.md
================================================
---
title: Guides
slug: guides
---
## Subscribing to Up Pro
Up Pro provides additional features which are not available in the open-source version, such as encrypted environment variables, alerting support and more.
First sign into the platform with the following command – you'll receive an email for confirmation.
```
$ up team login
email: tj@apex.sh
⠋ verify: Check your email for a confirmation link
```
Click the link in your email and you're signed in! If you're using Up Pro with one or more organizations, you should create a team to manage team members and subscriptions independently. If you plan on using Up Pro for personal use you may skip this step.
```
$ up team add "My Company"
```
Next you'll need to subscribe! You'll be asked for an optional coupon, credit card information – which never touches our servers, only Stripe via HTTPS – and finally a subscription confirmation.
```
$ up team subscribe
```
Now you and your team members may upgrade to the latest version of Up Pro, instead of the open-source distribution:
```
$ up upgrade
```
To view the status of your account at any time run the following:
```
$ up team
team: apex
subscription: Up Pro
amount: $10.00/mo USD
created: December 22, 2017
```
To switch to another team run the following and select the active team.
```
$ up team switch
❯ apex
tj@apex.sh
```
## Inviting team members
To invite members use the following command:
```
$ up team members add tobi@apex.sh
$ up team members add loki@apex.sh
$ up team members add jane@apex.sh
```
At any time you can view invites and members:
```
$ up team members
team: apex
Members
• tj@apex.sh
• tobi@apex.sh
• loki@apex.sh
Invites
• jane@apex.sh
```
Your team members will receive an email with installation instructions, where they run the following to sign in – with your team id of course.
```
$ up team login --email tobi@apex.sh --team apex
```
## Development to production workflow
This section guides you through taking a small application from development, to production, complete with purchasing and mapping a custom domain.
### Deploying
First create `app.js` in an empty directory with the following Node.js app. Note that it must listen on __PORT__ which is passed by Up.
```js
const http = require('http')
const { PORT = 3000 } = process.env
http.createServer((req, res) => {
res.end('Hello World\n')
}).listen(PORT)
```
Next you should give your application a name and start configuring. The `profile` name should correspond with the name in `~/.aws/credentials` so that Up knows which AWS account to deploy to, and which credentials to use.
```json
{
"name": "up-example",
"profile": "up-tobi"
}
```
Run `up` to deploy the application.
```
$ up
build: 5 files, 3.9 MB (358ms)
deploy: complete (14.376s)
stack: complete (1m12.086s)
```
Test with `curl` to ensure everything is working:
```
$ curl `up url`
Hello World
```
### Purchasing a domain
Domains can be mapped from existing services, or purchased directly from AWS via Route53. First check if the domain you'd like is available:
```
$ up domains check up.com
Domain up.com is unavailable
Suggestions:
theupwards.com $12.00 USD
upwardonline.com $12.00 USD
myupwards.com $12.00 USD
theastir.com $12.00 USD
astironline.com $12.00 USD
myastir.com $12.00 USD
myupward.net $11.00 USD
cleanup.tv $32.00 USD
myup.tv $32.00 USD
itup.tv $32.00 USD
newup.tv $32.00 USD
thedown.net $11.00 USD
theupward.net $11.00 USD
upwardsonline.net $11.00 USD
```
Oh no up.com is taken! Try another:
```
$ up domains check up-example.com
Domain up-example.com is available for $12.00 USD
```
Purchase it with the following command and fill out the details required by the registrar:
```
$ up domains buy
Domain: up-example.com
First name: TJ
Last name: Holowaychuk
Email: tj@apex.sh
Phone: +1.2501007000
Country code: CA
City: Victoria
State or province: BC
Zip code: X9X 9X9
Address: Some address here
```
It can take a few minutes for AWS to finalize the purchase after which you should receive an email. Then you'll see it in the `up domains` output along with the automatic renewal time.
```
$ up domains
gh-polls.com renews Aug 28 17:17:58
up-example.com renews Sep 19 19:40:50
```
By default domains purchased with Up have privacy protection enabled, hiding your contact information from [WHOIS](https://en.wikipedia.org/wiki/WHOIS).
### Deploying to Stages
Before deploying to the staging and production stages, first tweak the application a little to include the `UP_STAGE` environment variable:
```js
const http = require('http')
const { PORT = 3000, UP_STAGE } = process.env
http.createServer((req, res) => {
res.end('Hello World from ' + UP_STAGE)
}).listen(PORT)
```
Now deploy to staging and production. Note that `up` is an alias of `up deploy staging`.
```
$ up
$ up deploy production
```
Open both in the browser:
```
$ up url -o
$ up url -s production -o
```
You should see "Hello World from production" and "Hello World from staging".
### Mapping custom domains to stages
Now that you have an application deployed, you probably want a fancy custom domain for it right? You can map these using the `stages` and `domain` properties.
Here we let Up know that we want `up-example.com` for production and `stage.up-example.com` for staging.
```json
{
"name": "up-example",
"profile": "up-tobi",
"stages": {
"staging": {
"domain": "stage.up-example.com"
},
"production": {
"domain": "up-example.com"
}
}
}
```
Note that you could map staging to a domain like `staging-myapp.com`, it does not have to be a sub-domain of your production domain.
Now when you run `up stack plan` to preview changes to your resources, it will prompt you to verify the Let's Encrypt certificate emails that AWS sends.
```
$ up stack plan
domains: Check your email for certificate approval
⠧ confirm: up-example.com
```
AWS requires email verification to prove you own the domain. AWS sends an email to the 3 contact addresses listed in WHOIS when you registered the domain, and to the following 5 common system addresses for your domain:
- administrator@your_domain_name
- hostmaster@your_domain_name
- postmaster@your_domain_name
- webmaster@your_domain_name
- admin@your_domain_name
See [Validate Domain Ownership](https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-validate-email.html) for more information.
After clicking "I Approve" in one of the emails, the output will resume and you'll see some new resources Up will be creating.
```
Add AWS::ApiGateway::DomainName
id: ApiDomainDevelopment
Add AWS::ApiGateway::BasePathMapping
id: ApiDomainDevelopmentPathMapping
Add AWS::ApiGateway::DomainName
id: ApiDomainProduction
Add AWS::ApiGateway::BasePathMapping
id: ApiDomainProductionPathMapping
Add AWS::Route53::RecordSet
id: DnsZoneDevUpExampleComRecordDevUpExampleCom
Add AWS::Route53::RecordSet
id: DnsZoneUpExampleComRecordUpExampleCom
```
If you're curious, now that Up knows you want to map the domain(s), it will create:
- Registers ACM free SSL certificate(s) for your domain(s)
- CloudFront distribution for the API Gateway
- API Gateway stage mapping
- Route53 DNS zone and record(s) mapping to the CloudFront distribution
Now apply these changes:
```
$ up stack apply
```
After the changes have been applied, it can take roughly 10-40 minutes for CloudFront to distribute the configuration and SSL certificate globally, so until then our up-example.com domain won't work.
Once available https://up-example.com will always point to production via `up deploy production`, and https://stage.up-example.com/ will point to the latest deployment via `up`.
### Mapping domains from external registrars
If you purchased a domain via `up domains buy` you can skip this step, however if you used an external registrar such as Godaddy you will need to delegate to AWS for DNS management.
To do this you'll need to sign in to your registrar's site, and configure the nameservers. To figure out what values to use for the nameservers, run `up stack`, which outputs the NS records for the apex (top-level) domains of your application.
```
$ up stack
Staging
domain: stage.up-example.com
endpoint: d2od0udp1p8bru.cloudfront.net
Production
domain: up-example.com
endpoint: d72wsqljqg5cy.cloudfront.net
nameservers:
• ns-1495.awsdns-58.org
• ns-103.awsdns-12.com
• ns-1670.awsdns-16.co.uk
• ns-659.awsdns-18.net
```
Save those four values in your registrar's interface, and you should be good to go! Note that altering DNS records can take some time to propagate.
### Mapping with third-party DNS
If you manage DNS with a third-party such as Cloudflare, and wish to use Up only for deployment you will need to manually edit or add DNS records.
For example if your top-level domain `sloths.com` is managed by Cloudflare and you'd like point `api.sloths.com` to your app, you should first add it to your `up.json`:
```json
{
"name": "sloths"
"stages": {
"production": {
"domain": "api.sloths.com"
}
}
}
```
Next you will need to `up stack plan` and `up stack apply`, this will set up a CloudFront end-point for the application. To view the endpoint information, run `up stack`:
```
$ up stack
Production
domain: api.sloths.com
endpoint: d72wsqljqg5cy.cloudfront.net
```
In your DNS provider – Cloudflare in this example – you should create a `CNAME` record pointing to the production `endpoint`. Make sure that the `domain` you use matches the domain in Cloudflare.
### Stack changes
The "stack" is all of the resources associated with your app. You plan changes via `up stack plan` and perform them with `up stack apply`.
Suppose you wanted to map the "staging" stage, you would first add it to `up.json`:
```json
{
"name": "up-example",
"profile": "up-tobi",
"stages": {
"staging": {
"domain": "stage.up-example.com"
},
"production": {
"domain": "up-example.com"
}
}
}
```
Then run:
```
$ up stack plan
```
Review the output, it should be all "Add"s in this case, then apply:
```
$ up stack apply
```
### Deleting the application
After you're done messing around, you may want to remove all the resources and the app itself. To do so simply run:
```
$ up stack delete
```
## Deploying applications from continuous integration
Up makes it easy to deploy your applications from CI, thanks to its Go binaries you can install Up in seconds in any CI provider such as Travis, Circle, Semaphore among others.
### Environment variables
The first step is to set up environment variables so that you have access to your AWS account. You can get these values from `cat ~/.aws/credentials`:
- `AWS_ACCESS_KEY_ID` – AWS access key
- `AWS_SECRET_ACCESS_KEY` – AWS secret key
If using running Up Pro you'll need your Up credentials in order to access Up Pro via the `up upgrade` command. To obtain this run `up team ci` or `up team ci --copy` to copy it directly to your clipboard, then paste this as the env var's value.
- `UP_CONFIG` – Up configuration as base64-encoded JSON
If you run into "403 Forbidden" errors this is due to GitHub's low rate limit for unauthenticated users, consider creating a [Personal Access Token](https://github.com/settings/tokens) and adding the following variable to your CI:
- `GITHUB_TOKEN` — Github personal access token
### Commands
You may install Up in the current working directory, and deploy to production with the following commands, omitting the `up upgrade` if you are not an Up Pro subscriber.
```
$ curl -sf https://up.apex.sh/install | BINDIR=. sh
$ ./up upgrade
$ ./up production
```
Or if you prefer installing globally within `PATH`:
```
$ sudo chown -R $(whoami) /usr/local/bin
$ curl -sf https://up.apex.sh/install | sh
$ up upgrade
$ up production
```
## Mastering logging
This section describes how you can log from your application in a way that Up will recognize. In the future Up will support forwarding your logs to services such as Loggly, Papertrail or ELK.
### Plain text
The first option is plain-text logs to stdout or stderr. Currently writes to stderr are considered ERROR-level logs, and stdout becomes INFO.
Writing plain-text logs is simple, for example with Node.js:
```js
console.log('User signed in')
console.error('Failed to sign in: %s', err)
```
Would be collected as:
```
INFO: User signed in
ERROR: Failed to sign in: something broke
```
### JSON structured logs
The second option is structured logging with JSON events, which is preferred as it allows you to query against specific fields and treat logs like events.
JSON logs require a `level` and `message` field:
```js
console.log(`{ "level": "info", "message": "User login" }`)
```
Would be collected as:
```
INFO: User login
```
The `message` field should typically contain no dynamic content, such as user names or emails, these can be provided as fields:
```js
console.log(`{ "level": "info", "message": "User login", "fields": { "name": "Tobi", "email": "tobi@apex.sh" } }`)
```
Would be collected as:
```
INFO: User login name=Tobi email=tobi@apex.sh
```
Allowing you to perform queries such as:
```
$ up logs 'message = "User login" name = "Tobi"'
```
Or:
```
$ up logs 'name = "Tobi" or email = "tobi@*"'
```
Here's a simple JavaScript logger for reference. All you need to do is output some JSON to stdout and Up will handle the rest!
```js
function log(level, message, fields = {}) {
const entry = { level, message, fields }
console.log(JSON.stringify(entry))
}
```
For example, with the Go [apex/log](https://github.com/apex/log) package you'd use the `json` handler, which outputs this format.
## Log query language
Up supports a comprehensive query language, allowing you to perform complex filters against structured data, supporting operators, equality, substring tests and so on. This section details the options available when querying.
### AND operator
The `and` operator is implied, and entirely optional to specify, since this is the common case.
Suppose you have the following example query to show only production errors from a the specified IP address.
```
production error ip = "207.194.32.30"
```
The parser will inject `and`, effectively compiling to:
```
production and error and ip = "207.194.38.50"
```
### Or operator
There is of course also an `or` operator, for example showing warnings or errors.
```
production (warn or error)
```
These may of course be nested as you require:
```
(production or staging) (warn or error) method = "GET"
```
### Equality operators
The `=` and `!=` equality operators allow you to filter on the contents of a field.
Here `=` is used to show only GET requests:
```
method = "GET"
```
Or for example `!=` may be used to show anything except GET:
```
method != "GET"
```
### Relational operators
The `>`, `>=`, `<`, and `<=` relational operators are useful for comparing numeric values, for example response status codes:
```
status >= 200 status < 300
```
### Stages
Currently all development, staging, and production logs are all stored in the same location, however you may filter to find exactly what you need.
The keywords `production`, `staging`, and `development` expand to:
```
stage = "production"
```
For example, filtering on slow production responses:
```
production duration >= 1s
```
Is the same as:
```
stage = "production" duration >= 1s
```
### Severity levels
Up provides request level logging with severity levels applied automatically. For example, a 5xx response is an ERROR level, while 4xx is a WARN, and 3xx or 2xx are the INFO level.
This means that instead of using the following for showing production errors:
```
production status >= 500
```
You may use:
```
production error
```
### In Operator
The `in` operator checks for the presence of a field within the set provided. For example, showing only POST, PUT and PATCH requests:
```
method in ("POST", "PUT", "PATCH")
```
### Units
The log grammar supports units for bytes and durations. For example, showing responses larger than 56kb:
```
size > 56kb
```
Or showing responses longer than 1500ms:
```
duration > 1.5s
```
Byte units are:
- `b` bytes (`123b` or `123` are equivalent)
- `kb` bytes (`5kb`, `128kb`)
- `mb` bytes (`5mb`, `15.5mb`)
Duration units are:
- `ms` milliseconds (`100ms` or `100` are equivalent)
- `s` seconds (`1.5s`, `5s`)
### Substring matches
When filtering on strings, such as the log message, you may use the `*` character for substring matches.
For example if you want to show logs with a remote ip prefix of `207.`:
```
ip = "207.*"
```
Or a message containing the word "login":
```
message = "*login*"
```
There is also a special keyword for this case:
```
message contains "login"
```
## Hot reloading in development
The `up start` command uses your `proxy.command` by default, which may be inferred based on your application type, such as `node app.js` for Node.js or `./server` for Golang.
You may alter this command for `up start` with the development environment. For example with Golang you may want `go run main.go`, or hot reloading with [gin](https://github.com/codegangsta/gin) as shown here:
```json
{
"name": "app",
"stages": {
"development": {
"proxy": {
"command": "gin --port $PORT"
}
}
}
}
```
Note that the server must always listen on `PORT` which is provided by `up start`.
## Accessing lambda context
Traditional AWS Lambda functions provided a context object which contains runtime information such as API Gateway user identity. This information is exposed as JSON in the `X-Context` header field in Up as shown here:
```js
const http = require('http')
const { PORT } = process.env
const app = http.createServer((req, res) => {
const ctx = JSON.parse(req.headers['x-context'])
res.end(JSON.stringify(ctx, null, 2))
})
console.log('Starting app on %s', PORT)
app.listen(PORT)
```
Output will be similar to the following. Visit the [AWS Documentation](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html) for details.
```json
{
"apiId": "g4yn392afg",
"resourceId": "ez0z8areob",
"requestId": "d8314ef1-5543-11e8-a925-21fa0dd01c37",
"accountId": "337344593553",
"stage": "staging",
"identity": {
"apiKey": "",
"accountId": "",
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36",
"sourceIp": "64.110.31.100",
"accessKey": "",
"caller": "",
"user": "",
"userARN": "",
"cognitoIdentityId": "",
"cognitoIdentityPoolId": "",
"cognitoAuthenticationType": "",
"cognitoAuthenticationProvider": ""
},
"authorizer": null
}
```
================================================
FILE: docs/08-troubleshooting.md
================================================
---
title: Troubleshooting
menu: Help
slug: troubleshooting
---
This section contains self-help troubleshooting information. If you're running into an issue you can't resolve, try the [Slack](https://chat.apex.sh/) chat, or [submit an issue](https://github.com/apex/up).
<details>
<summary>I didn't receive a sign-in or certificate confirmation email</summary>
<p>AWS email delivery can be slow sometimes. Please give it 30-60s. Otherwise, be sure to check your spam folder.</p>
</details>
<details>
<summary>My application times out or seems slow</summary>
<p>Lambda `memory` scales CPU alongside RAM, so if your application is slow to initialize or serve responses, you may want to try `1024` or above. See [Lambda Pricing](https://aws.amazon.com/lambda/pricing/) for options.</p>
<p>Ensure that all of your dependencies are deployed. You may use `up -v` to view what is added or filtered from the deployment or `up build --size` to output the contents of the zip.</p>
</details>
<details>
<summary>I'm seeing 404 Not Found responses</summary>
<p>By default, Up ignores files which are found in `.upignore`. Use the verbose flag such as `up -v` to see if files have been filtered or `up build --size` to see a list of files within the zip sorted by size. See [Ignoring Files](#configuration.ignoring_files) for more information.</p>
</details>
<details>
<summary>My deployment seems stuck</summary>
<p>The first deploy also creates resources associated with your project and can take roughly 1-2 minutes. AWS provides limited granularity into the creation progress of these resources, so the progress bar may appear "stuck".</p>
</details>
<details>
<summary>How do I sign into my team?</summary>
<p>Run `up team login` if you aren't signed in, then run `up team login --team my-team-id` to sign into any teams you're an owner or member of.</p>
</details>
<details>
<summary>Unable to associate certificate error</summary>
<p>If you receive a `Unable to associate certificate` error it is because you have not verified the SSL certificate. Certs for CloudFront when creating a custom domain MUST be in us-east-1, so if you need to manually resend verification emails visit [ACM in US East 1](https://console.aws.amazon.com/acm/home?region=us-east-1).</p>
</details>
<details>
<summary>I'm seeing 403 Forbidden errors in CI</summary>
<p>If you run into "403 Forbidden" errors this is due to GitHub's low rate limit for unauthenticated users, consider creating a [Personal Access Token](https://github.com/settings/tokens) and adding `GITHUB_TOKEN` to your CI.</p>
</details>
================================================
FILE: docs/09-faq.md
================================================
---
title: Questions
menu: FAQ
slug: faq
---
<details>
<summary>Is this a hosted service?</summary>
<p>There are currently no plans for a hosted version. Up lets you deploy applications to your own AWS account for isolation, security, and longevity — don't worry about a startup going out of business.</p>
</details>
<details>
<summary>How much does Up Pro cost?</summary>
<p>Up's subscription fee is currently $20/mo USD. When subscribed, your team has access to Up Pro updates until the subscription is cancelled. When cancelled, you receive access until the end of your billing period.</p>
<p>For the subscription, you get unlimited access within your organization; there is no additional fee per team member or "seat". You can deploy any number of applications as you wish.</p>
<p>Note that AWS charges for use of its resources. However, most small to medium applications will fit within the AWS free tier.</p>
</details>
<details>
<summary>What platforms does Up support?</summary>
<p>Currently AWS via API Gateway and Lambda are supported, this is the focus until Up is nearing feature completion, after which additional providers such as GCP and Azure will be added.</p>
</details>
<details>
<summary>How is this different than other serverless frameworks?</summary>
<p>Most of the AWS Lambda based tools are function-oriented, while Up abstracts this away entirely. Up does not use framework "shims", the servers that you run using Up are regular HTTP servers and require no code changes for Lambda compatibility.</p>
<p>Up keeps your apps and APIs portable, makes testing them locally easier, and prevents vendor lock-in. The Lambda support for Up is simply an implementation detail, you are not coupled to API Gateway or Lambda. Up uses the API Gateway proxy mode to send all requests (regardless of path or method) to your application.</p>
<p>If you're looking to manage function-level event processing pipelines, Apex or Serverless are likely better candidates, however if you're creating applications, apis, micro services, or websites, Up is built for you.</p>
</details>
<details>
<summary>Why run HTTP servers in Lambda?</summary>
<p>You might be thinking this defeats the purpose of Lambda, however most people just want to use the tools they know and love. Up lets you be productive developing locally as you normally would, Lambda for hosting is only an implementation detail.</p>
<p>With Up you can use any Python, Node, Go, or Java framework you'd normally use to develop, and deploy with a single command, while maintaining the cost effectiveness, self-healing, and scaling capabilities of Lambda.</p>
</details>
<details>
<summary>How much does it cost to run an application?</summary>
<p>AWS API Gateway provides 1 million free requests per month, so there's a good chance you won't have to pay anything at all. Beyond that view the <a href="https://aws.amazon.com/api-gateway/pricing/">AWS Pricing</a> for more information.</p>
</details>
<details>
<summary>How well does it scale?</summary>
<p>Up scales to fit your traffic on-demand, you don't have to do anything beyond deploying your code. There's no restriction on the number of concurrent instances, apps, custom domains and so on.</p>
</details>
<details>
<summary>How much latency does Up's reverse proxy introduce?</summary>
<p>With a 512mb Lambda function Up introduces an average of around 500µs (microseconds) per request.</p>
</details>
<details>
<summary>Can I remove the /staging and /production paths?</summary>
<p>Up uses AWS API Gateway, which imposes the stage base paths. Currently there is no way to remove them, however when you use
custom domains these paths are not present.</p>
</details>
<details>
<summary>Do the servers stay active while idle?</summary>
<p>This depends on the platform, and with Lambda being the initial platform provided the current answer is no, the server(s) are frozen when inactive and are otherwise "stateless".</p>
<p>Typically relying on background work in-process is an anti-pattern as it does not scale. Lambda functions combined with CloudWatch scheduled events for example are a good way to handle this kind of work, if you're looking for a scalable alternative.</p>
</details>
<details>
<summary>What databases can I use?</summary>
<p>You're not limited to databases from any given platform, such as AWS Provided that the database host provides authentication, you can use anything. See the <a href="https://github.com/apex/up/wiki#databases">Wiki</a> for a list of managed & serverless database solutions.</p>
</details>
<details>
<summary>Why is Up licensed as GPLv3?</summary>
<p>Up is licensed in such a way that myself as an independent developer can continue to improve the product and provide support. Commercial customers receive access to a premium version of Up with additional features, priority support for bugfixes, and of course knowing that the project will stick around! Up saves your team countless hours maintaining infrastructure and custom tooling, so you can get back to what makes your company and products unique.</p>
</details>
<details>
<summary>Can I donate?</summary>
<p>Yes you can! Head over to the <a href="https://opencollective.com/apex-up">OpenCollective</a> page. Any donations are greatly appreciated and help me focus more on Up's implementation, documentation, and examples. If you're using the free OSS version for personal or commercial use please consider giving back, even a few bucks buys a coffee :).</p>
</details>
================================================
FILE: docs/10-links.md
================================================
---
title: Links
slug: links
---
Links to helpful resources such as the Up community, changelog, examples, articles, videos and more.
- [Changelog](https://github.com/apex/up/blob/master/History.md) for changes
- [GitHub repository](https://github.com/apex/up)
- [GitHub Actions](https://github.com/apex/actions) for continuous deployment
- [@tjholowaychuk](https://twitter.com/tjholowaychuk) on Twitter for updates
- [Example applications](https://github.com/apex/up-examples) for Up in various languages
- [Slack](https://chat.apex.sh/) to chat with apex(1) and up(1) community members
- [Blog](https://blog.apex.sh/) to follow release posts, tips and tricks
- [YouTube](https://www.youtube.com/watch?v=1wnSNj-jmo4&index=1&list=PLbFkWVvnVLnRP-E87Tqe6nYVjOk6461o0) for the Apex Up video playlist
- [Wiki](https://github.com/apex/up/wiki) for article listings, database suggestions, and sample apps
- [Serverless Calculator](http://serverlesscalc.com/) for helping estimate costs for your use-case
================================================
FILE: go.mod
================================================
module github.com/apex/up
require (
github.com/NYTimes/gziphandler v0.0.0-20170916004738-97ae7fbaf816
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 // indirect
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 // indirect
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 // indirect
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc // indirect
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect
github.com/apex/go-apex v1.0.0
github.com/apex/log v1.3.0
github.com/armon/go-radix v1.0.0 // indirect
github.com/atotto/clipboard v0.1.2 // indirect
github.com/aws/aws-sdk-go v1.31.9
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2 // indirect
github.com/buger/goterm v0.0.0-20181115115552-c206103e1f37 // indirect
github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c // indirect
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect
github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9
github.com/denormal/go-gitignore v0.0.0-20170315120618-40de3d33f668 // indirect
github.com/dsnet/compress v0.0.0-20171208185109-cc9eb1d7ad76 // indirect
github.com/dustin/go-humanize v0.0.0-20171012181109-77ed807830b4
github.com/facebookgo/freeport v0.0.0-20150612182905-d4adf43b75b9
github.com/fanyang01/radix v0.0.0-20160415095728-e1747dd9eeac
github.com/fatih/color v1.7.0 // indirect
github.com/golang/sync v0.0.0-20170927054112-8e0aa688b654
github.com/google/go-github v14.0.0+incompatible // indirect
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 // indirect
github.com/gosuri/uilive v0.0.0-20170323041506-ac356e6e42cd // indirect
github.com/gosuri/uiprogress v0.0.0-20170224063937-d0567a9d84a1 // indirect
github.com/hashicorp/go-uuid v0.0.0-20160717022140-64130c7a86d7 // indirect
github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 // indirect
github.com/jehiah/go-strftime v0.0.0-20151206194810-2efbe75097a5 // indirect
github.com/klauspost/compress v1.2.1 // indirect
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5 // indirect
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6 // indirect
github.com/klauspost/pgzip v0.0.0-20170402124221-0bf5dcad4ada // indirect
github.com/mattn/go-isatty v0.0.9 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/mitchellh/go-homedir v0.0.0-20161203194507-b8bc1bf76747
github.com/pascaldekloe/name v0.0.0-20170812100307-81013e77fe79
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4
github.com/pkg/errors v0.9.1
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rs/cors v0.0.0-20180726230524-02026070ea74
github.com/segmentio/analytics-go v0.0.0-20160426181448-2d840d861c32 // indirect
github.com/segmentio/backo-go v0.0.0-20160424052352-204274ad699c // indirect
github.com/segmentio/go-snakecase v1.0.0
github.com/sergi/go-diff v1.0.0 // indirect
github.com/stripe/stripe-go v28.5.0+incompatible
github.com/timewasted/go-accept-headers v0.0.0-20130320203746-c78f304b1b09
github.com/tj/assert v0.0.1
github.com/tj/aws v0.1.4
github.com/tj/backoff v1.0.0
github.com/tj/go v1.8.6
github.com/tj/go-archive v1.0.2
github.com/tj/go-cli-analytics v1.0.0
github.com/tj/go-headers v0.0.0-20170630155323-711a635412ca
github.com/tj/go-progress v0.0.0-20171031175334-333acdb6fe9f
github.com/tj/go-spin v1.1.0
github.com/tj/go-update v2.2.4+incompatible
github.com/tj/kingpin v2.5.0+incompatible
github.com/tj/survey v2.0.6+incompatible
github.com/ulikunitz/xz v0.5.4 // indirect
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
golang.org/x/net v0.0.0-20200202094626-16171245cfb2
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f // indirect
gopkg.in/yaml.v3 v3.0.0-20200602174320-3e3e88ca92fa // indirect
)
go 1.13
================================================
FILE: go.sum
================================================
github.com/NYTimes/gziphandler v0.0.0-20170916004738-97ae7fbaf816 h1:wBaYm5ra+p6jEKkg9G3tCimdOwp/dcCPSfkePrWoc6w=
github.com/NYTimes/gziphandler v0.0.0-20170916004738-97ae7fbaf816/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo=
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/apex/go-apex v1.0.0 h1:Em8+vo4WXEQp7GfNDTr35HRnE5sFYcRpkTODpVjU39A=
github.com/apex/go-apex v1.0.0/go.mod h1:Hy8WsL4dnQc/bYBxElRQ7xHXLNBAqz0BVxUhHiGwKLA=
github.com/apex/log v1.1.0 h1:J5rld6WVFi6NxA6m8GJ1LJqu3+GiTFIt3mYv27gdQWI=
github.com/apex/log v1.1.0/go.mod h1:yA770aXIDQrhVOIGurT/pVdfCpSq1GQV/auzMN5fzvY=
github.com/apex/log v1.3.0 h1:1fyfbPvUwD10nMoh3hY6MXzvZShJQn9/ck7ATgAt5pA=
github.com/apex/log v1.3.0/go.mod h1:jd8Vpsr46WAe3EZSQ/IUMs2qQD/GOycT5rPWCO1yGcs=
github.com/apex/logs v0.0.4/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE=
github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys=
github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/atotto/clipboard v0.0.0-20160219034421-bb272b845f11 h1:Gmm0NreNeu4FgEzX1Ht6ceAf5/wOBG+Gi625BEy9d40=
github.com/atotto/clipboard v0.0.0-20160219034421-bb272b845f11/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/atotto/clipboard v0.1.2 h1:YZCtFu5Ie8qX2VmVTBnrqLSiU9XOWwqNRmdT3gIQzbY=
github.com/atotto/clipboard v0.1.2/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aws/aws-sdk-go v1.19.1 h1:8kOP0/XGJwXIFlYoD1DAtA39cAjc15Iv/QiDMKitD9U=
github.com/aws/aws-sdk-go v1.19.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.31.9 h1:n+b34ydVfgC30j0Qm69yaapmjejQPW2BoDBX7Uy/tLI=
github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo=
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2 h1:1B/+1BcRhOMG1KH/YhNIU8OppSWk5d/NGyfRla88CuY=
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
github.com/buger/goterm v0.0.0-20170918171949-d443b9114f9c h1:p1/ndMSoqqRp8tN/HJuqYNt1IlBzDbug0JYTJAktrtg=
github.com/buger/goterm v0.0.0-20170918171949-d443b9114f9c/go.mod h1:u9UyCz2eTrSGy6fbupqJ54eY5c4IC8gREQ1053dK12U=
github.com/buger/goterm v0.0.0-20181115115552-c206103e1f37 h1:uxxtrnACqI9zK4ENDMf0WpXfUsHP5V8liuq5QdgDISU=
github.com/buger/goterm v0.0.0-20181115115552-c206103e1f37/go.mod h1:u9UyCz2eTrSGy6fbupqJ54eY5c4IC8gREQ1053dK12U=
github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c h1:aprLqMn7gSPT+vdDSl+/E6NLEuArwD/J7IWd8bJt5lQ=
github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c/go.mod h1:Ie6SubJv/NTO9Q0UBH0QCl3Ve50lu9hjbi5YJUw03TE=
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9 h1:74lLNRzvsdIlkTgfDSMuaPjBr4cf6k7pwQQANm/yLKU=
github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4=
github.com/denormal/go-gitignore v0.0.0-20170315120618-40de3d33f668 h1:JJc1wCJD+mjauA6uWGKHgwwpoqnuHsFRCVnGDQuyAbI=
github.com/denormal/go-gitignore v0.0.0-20170315120618-40de3d33f668/go.mod h1:C/+sI4IFnEpCn6VQ3GIPEp+FrQnQw+YQP3+n+GdGq7o=
github.com/dsnet/compress v0.0.0-20171208185109-cc9eb1d7ad76 h1:eX+pdPPlD279OWgdx7f6KqIRSONuK7egk+jDx7OM3Ac=
github.com/dsnet/compress v0.0.0-20171208185109-cc9eb1d7ad76/go.mod h1:KjxHHirfLaw19iGT70HvVjHQsL1vq1SRQB4yOsAfy2s=
github.com/dustin/go-humanize v0.0.0-20171012181109-77ed807830b4 h1:I4YDfvHXPYd8OWal9f4CgxbqNH2Bbcqk6wuLTy+ieww=
github.com/dustin/go-humanize v0.0.0-20171012181109-77ed807830b4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/facebookgo/freeport v0.0.0-20150612182905-d4adf43b75b9 h1:wWke/RUCl7VRjQhwPlR/v0glZXNYzBHdNUzf/Am2Nmg=
github.com/facebookgo/freeport v0.0.0-20150612182905-d4adf43b75b9/go.mod h1:uPmAp6Sws4L7+Q/OokbWDAK1ibXYhB3PXFP1kol5hPg=
github.com/fanyang01/radix v0.0.0-20160415095728-e1747dd9eeac h1:fYRW78xH/NepMB5++0kO74kXra7McyBQKsnWlRZyhaQ=
github.com/fanyang01/radix v0.0.0-20160415095728-e1747dd9eeac/go.mod h1:PSQWLj5d94M4cGhTeXFExqzf4B98d1Zlxtwf5wL1Vmc=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/sync v0.0.0-20170927054112-8e0aa688b654 h1:bzR1is7uS8E5I4vAF7Qu2TaSDoYqneMomTnAuesaMHw=
github.com/golang/sync v0.0.0-20170927054112-8e0aa688b654/go.mod h1:YCHYtYb9c8Q7XgYVYjmJBPtFPKx5QvOcPxHZWjldabE=
github.com/google/go-github v14.0.0+incompatible h1:IH7XxuaXbLVh4iwPks5+jmKZXElyvAf+5K1108Ku8fU=
github.com/google/go-github v14.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0=
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gosuri/uilive v0.0.0-20170323041506-ac356e6e42cd h1:1e+0Z+T4t1mKL5xxvxXh5FkjuiToQGKreCobLu7lR3Y=
github.com/gosuri/uilive v0.0.0-20170323041506-ac356e6e42cd/go.mod h1:qkLSc0A5EXSP6B04TrN4oQoxqFI7A8XvoXSlJi8cwk8=
github.com/gosuri/uiprogress v0.0.0-20170224063937-d0567a9d84a1 h1:4iPLwzjiWGBQnYdtKbg/JNlGlEEvklrrMdjypdA1LKQ=
github.com/gosuri/uiprogress v0.0.0-20170224063937-d0567a9d84a1/go.mod h1:C1RTYn4Sc7iEyf6j8ft5dyoZ4212h8G1ol9QQluh5+0=
github.com/hashicorp/go-uuid v0.0.0-20160717022140-64130c7a86d7 h1:w8czuEDeFZo7CdZ2APLO24tTbjzO4cNXTfCkBdtU+wg=
github.com/hashicorp/go-uuid v0.0.0-20160717022140-64130c7a86d7/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 h1:WgfvpuKg42WVLkxNwzfFraXkTXPK36bMqXvMFN67clI=
github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214/go.mod h1:kj6hFWqfwSjFjLnYW5PK1DoxZ4O0uapwHRmd9jhln4E=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jehiah/go-strftime v0.0.0-20151206194810-2efbe75097a5 h1:E1bpycfzgfdJWK32+GOJDYVrep2fbX6cN6tYiXd+CGY=
github.com/jehiah/go-strftime v0.0.0-20151206194810-2efbe75097a5/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
github.com/klauspost/compress v1.2.1 h1:z1Ra6IKoPtIeVA8GV0SCQhuo6T4EBjlL9VwonZ8NYBo=
github.com/klauspost/compress v1.2.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5 h1:2U0HzY8BJ8hVwDKIzp7y4voR9CX/nvcfymLmg2UiOio=
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6 h1:KAZ1BW2TCmT6PRihDPpocIy1QTtsAsrx6TneU/4+CMg=
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=
github.com/klauspost/pgzip v0.0.0-20170402124221-0bf5dcad4ada h1:ZHhgRyr+9LYwfuWChpSTCCe/07V26LEElTKUXj+2fAg=
github.com/klauspost/pgzip v0.0.0-20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mitchellh/go-homedir v0.0.0-20161203194507-b8bc1bf76747 h1:eQox4Rh4ewJF+mqYPxCkmBAirRnPaHEB26UkNuPyjlk=
github.com/mitchellh/go-homedir v0.0.0-20161203194507-b8bc1bf76747/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pascaldekloe/name v0.0.0-20170812100307-81013e77fe79 h1:01H24QTjrY56mVV6Ms4bbkT+z36nC+c133Cvxe391vQ=
github.com/pascaldekloe/name v0.0.0-20170812100307-81013e77fe79/go.mod h1:eD5JxqMiuNYyFNmyY9rkJ/slN8y59oEu4Ei7F8OoKWQ=
github.com/pkg/browser v0.0.0-20170505125900-c90ca0c84f15 h1:mrI+6Ae64Wjt+uahGe5we/sPS1sXjvfT3YjtawAVgps=
github.com/pkg/browser v0.0.0-20170505125900-c90ca0c84f15/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 h1:49lOXmGaUpV9Fz3gd7TFZY106KVlPVa5jcYD1gaQf98=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rs/cors v0.0.0-20180726230524-02026070ea74 h1:2UqoDqa4MGBAM2/DsHlZEvzpubV5s4jcMi8tXkLtSvE=
github.com/rs/cors v0.0.0-20180726230524-02026070ea74/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/segmentio/analytics-go v0.0.0-20160426181448-2d840d861c32 h1:+0sDBHuIsUlerfNGmggprc/aCAFQ5ZvPReQOHHTVZUs=
github.com/segmentio/analytics-go v0.0.0-20160426181448-2d840d861c32/go.mod h1:C7CYBtQWk4vRk2RyLu0qOcbHJ18E3F1HV2C/8JvKN48=
github.com/segmentio/backo-go v0.0.0-20160424052352-204274ad699c h1:rsRTAcCR5CeNLkvgBVSjQoDGRRt6kggsE6XYBqCv2KQ=
github.com/segmentio/backo-go v0.0.0-20160424052352-204274ad699c/go.mod h1:kJ9mm9YmoWSkk+oQ+5Cj8DEoRCX2JT6As4kEtIIOp1M=
github.com/segmentio/go-snakecase v1.0.0 h1:FSeHpP0sBL3O+MCpxvQZrS5a51WAki6gposZuwVE9L4=
github.com/segmentio/go-snakecase v1.0.0/go.mod h1:jk1miR5MS7Na32PZUykG89Arm+1BUSYhuGR6b7+hJto=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.1.4 h1:ToftOQTytwshuOSj6bDSolVUa3GINfJP/fg3OkkOzQQ=
github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho=
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stripe/stripe-go v28.5.0+incompatible h1:YBJrol3D+WNmmpRIfot0bT/3FGWF8to9306nTRmpZD8=
github.com/stripe/stripe-go v28.5.0+incompatible/go.mod h1:A1dQZmO/QypXmsL0T8axYZkSN/uA/T/A64pfKdBAMiY=
github.com/stripe/stripe-go v70.15.0+incompatible h1:hNML7M1zx8RgtepEMlxyu/FpVPrP7KZm1gPFQquJQvM=
github.com/stripe/stripe-go v70.15.0+incompatible/go.mod h1:A1dQZmO/QypXmsL0T8axYZkSN/uA/T/A64pfKdBAMiY=
github.com/timewasted/go-accept-headers v0.0.0-20130320203746-c78f304b1b09 h1:QVxbx5l/0pzciWYOynixQMtUhPYC3YKD6EcUlOsgGqw=
github.com/timewasted/go-accept-headers v0.0.0-20130320203746-c78f304b1b09/go.mod h1:Uy/Rnv5WKuOO+PuDhuYLEpUiiKIZtss3z519uk67aF0=
github.com/tj/assert v0.0.0-20170216210512-748ebc778a69 h1:yjFMw2bnmM1YJSZn/aHiJ2yYZSBVL4oB8TC/+Y2pvIg=
github.com/tj/assert v0.0.0-20170216210512-748ebc778a69/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
github.com/tj/assert v0.0.1 h1:T7ozLNagrCCKl3wc+a706ztUCn/D6WHCJtkyvqYG+kQ=
github.com/tj/assert v0.0.1/go.mod h1:lsg+GHQ0XplTcWKGxFLf/XPcPxWO8x2ut5jminoR2rA=
github.com/tj/aws v0.1.4 h1:DZJArmjug0N7EvQxSs8W3gIDz1UzF8PeEE2MbTPhA80=
github.com/tj/aws v0.1.4/go.mod h1:kG2Lk+22zcwmIKGMfSCcKDrqbVklm6AqVwQ/3BwbFec=
github.com/tj/backoff v1.0.0 h1:Zi5jr//0f/ZtFXzXA2sx4pd/n3KTMK6b3xO2D1y50I4=
github.com/tj/backoff v1.0.0/go.mod h1:opbA1vtO/vdNR4wI5izntg38viykxrVNMku6WVSWU/k=
github.com/tj/go v1.8.5 h1:QbRCjQp1v308lsdHe+x/XYJ2U+WdSxY9tWiduvOFsPU=
github.com/tj/go v1.8.5/go.mod h1:iDIwBG1ZkyeGIOBZLZQfpIztHr5m0gG+YGXrKaUC4yE=
github.com/tj/go v1.8.6 h1:HZ+XV+wB4vqN5y5VLoZqYUuUJTBF+2kblBru7aUa44E=
github.com/tj/go v1.8.6/go.mod h1:iDIwBG1ZkyeGIOBZLZQfpIztHr5m0gG+YGXrKaUC4yE=
github.com/tj/go v1.8.7 h1:a7M1Xo+QKmlUHEzZj2LX0LHqkh7/LpOa6Or8luBvY/c=
github.com/tj/go v1.8.7/go.mod h1:88DQADQo0c0fHmWNcr88pIGUHlV5du8aGtON+S1jr5A=
github.com/tj/go-archive v1.0.2 h1:qrtC9BD1rrxuaUAD3sgzaqkt98YeGelE2aJAwZlFL24=
github.com/tj/go-archive v1.0.2/go.mod h1:qqEdZXPGCYTFmpsGAGlTxUIv5fWK8NBEdvzU7NV3fJo=
github.com/tj/go-cli-analytics v1.0.0 h1:aOf/mTKoyMSy8VnvLOTNPDwImjxT7mNC7ivmpTmRtdg=
github.com/tj/go-cli-analytics v1.0.0/go.mod h1:Iwh92wE6jdgYylSZpfFmEoDtB812G235Nq/FtBYmv3E=
github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0=
github.com/tj/go-headers v0.0.0-20170630155323-711a635412ca h1:xcArqZ1PrVz/YH9AnEd8vCuEVY4vGKqeC6zFNzS56Mg=
github.com/tj/go-headers v0.0.0-20170630155323-711a635412ca/go.mod h1:TplXCeOi+Y4CQVdB8KFG4+EtmxgxQaauYO/h3cASuZA=
github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao=
github.com/tj/go-progress v0.0.0-20171031175334-333acdb6fe9f h1:adrNJejn+15T3PPv/M2scCcFcc9WzCZYdLw25nLl76Y=
github.com/tj/go-progress v0.0.0-20171031175334-333acdb6fe9f/go.mod h1:abH8hpo1+c7MbAa0ZCKvvGOgowFNgaoRQEcY0vsRTh4=
github.com/tj/go-spin v1.1.0 h1:lhdWZsvImxvZ3q1C5OIB7d72DuOwP4O2NdBg9PyzNds=
github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=
github.com/tj/go-update v2.2.4+incompatible h1:7Rkw5ZyRSFb3QyEWM7sHCy9rCy1/r66elkOyGlfnZFc=
github.com/tj/go-update v2.2.4+incompatible/go.mod h1:waFwwyiAhGey2e+dNoYQ/iLhIcFqhCW7zL/+vDU1WLo=
github.com/tj/kingpin v2.5.0+incompatible h1:nZWdCABGeebLFX5Ha/rYqxgEQpSXYWh5N9Dx2sGR0Bs=
github.com/tj/kingpin v2.5.0+incompatible/go.mod h1:/babRmtQneL+pp+Yi24s2gukswokaKCR4gfjGbnjHBk=
github.com/tj/survey v2.0.6+incompatible h1:tVgc1+kmYX9R0CEoHaTczapjdc4GaJla0VAB7O+w1So=
github.com/tj/survey v2.0.6+incompatible/go.mod h1:vLPzQYAOKWgXqr5jV9luQXJuoXKHOg0ltn5FEw1Nz0c=
github.com/ulikunitz/xz v0.5.4 h1:zATC2OoZ8H1TZll3FpbX+ikwmadbO699PE06cIkm9oU=
github.com/ulikunitz/xz v0.5.4/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g=
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20171027103834-c73622c77280 h1:TFSo8RGq2v9crRl/RW0EH71y1kdSjqeCxljzuDsD+oA=
golang.org/x/net v0.0.0-20171027103834-c73622c77280/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20171031081856-95c657629925 h1:nCH33NboKIsT4HoXBsXTWX8ul303HxWgkc5s2Ezwacg=
golang.org/x/sys v0.0.0-20171031081856-95c657629925/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20171102192421-88f656faf3f3 h1:TtrmcC9vFAjk6IwmXFdqQovdiZxrqQycAYaeCHauPKU=
golang.org/x/text v0.0.0-20171102192421-88f656faf3f3/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7
gitextract_3gd4es3i/ ├── .gitattributes ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE.md │ └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .goreleaser.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── History.md ├── LICENSE ├── Makefile ├── Readme.md ├── cmd/ │ ├── up/ │ │ └── main.go │ └── up-proxy/ │ └── main.go ├── config/ │ ├── backoff.go │ ├── backoff_test.go │ ├── config.go │ ├── config_test.go │ ├── cors.go │ ├── dns.go │ ├── dns_test.go │ ├── doc.go │ ├── duration.go │ ├── duration_test.go │ ├── environment.go │ ├── errorpages.go │ ├── errorpages_test.go │ ├── hooks.go │ ├── hooks_test.go │ ├── lambda.go │ ├── lambda_test.go │ ├── logs.go │ ├── relay.go │ ├── runtimes.go │ ├── stages.go │ ├── stages_test.go │ ├── static.go │ └── static_test.go ├── docs/ │ ├── 00-introduction.md │ ├── 01-installation.md │ ├── 02-aws-credentials.md │ ├── 03-getting-started.md │ ├── 04-configuration.md │ ├── 05-runtimes.md │ ├── 06-commands.md │ ├── 07-guides.md │ ├── 08-troubleshooting.md │ ├── 09-faq.md │ └── 10-links.md ├── go.mod ├── go.sum ├── handler/ │ ├── handler.go │ ├── handler_test.go │ └── testdata/ │ ├── node/ │ │ ├── app.js │ │ └── up.json │ ├── node-pkg/ │ │ ├── app.js │ │ ├── package.json │ │ └── up.json │ ├── node-pkg-start/ │ │ ├── index.js │ │ ├── package.json │ │ └── up.json │ ├── spa/ │ │ ├── app.js │ │ ├── css/ │ │ │ ├── bar.css │ │ │ └── foo.css │ │ ├── index.html │ │ └── up.json │ ├── static/ │ │ ├── index.html │ │ ├── style.css │ │ └── up.json │ ├── static-redirects/ │ │ ├── help/ │ │ │ └── ping/ │ │ │ └── alerts/ │ │ │ └── index.html │ │ ├── index.html │ │ └── up.json │ └── static-rewrites/ │ ├── help/ │ │ └── ping/ │ │ └── alerts.html │ ├── index.html │ └── up.json ├── http/ │ ├── cors/ │ │ ├── cors.go │ │ └── cors_test.go │ ├── errorpages/ │ │ ├── errorpages.go │ │ ├── errorpages_test.go │ │ └── testdata/ │ │ ├── defaults/ │ │ │ ├── index.html │ │ │ └── up.json │ │ └── templates/ │ │ ├── 404.html │ │ ├── 5xx.html │ │ ├── index.html │ │ └── up.json │ ├── gzip/ │ │ ├── gzip.go │ │ └── gzip_test.go │ ├── headers/ │ │ ├── headers.go │ │ ├── headers_test.go │ │ └── testdata/ │ │ ├── _headers │ │ ├── index.html │ │ ├── style.css │ │ └── up.json │ ├── inject/ │ │ ├── inject.go │ │ ├── inject_test.go │ │ └── testdata/ │ │ ├── 404.html │ │ ├── index.html │ │ ├── style.css │ │ └── up.json │ ├── logs/ │ │ ├── logs.go │ │ ├── logs_test.go │ │ └── testdata/ │ │ ├── index.html │ │ └── up.json │ ├── poweredby/ │ │ ├── poweredby.go │ │ ├── poweredby_test.go │ │ └── testdata/ │ │ ├── index.html │ │ └── up.json │ ├── redirects/ │ │ ├── redirects.go │ │ └── redirects_test.go │ ├── relay/ │ │ ├── relay.go │ │ ├── relay_test.go │ │ └── testdata/ │ │ ├── basic/ │ │ │ ├── app.js │ │ │ └── up.json │ │ └── node/ │ │ ├── package.json │ │ ├── server.js │ │ └── up.json │ ├── robots/ │ │ ├── robots.go │ │ ├── robots_test.go │ │ └── testdata/ │ │ ├── index.html │ │ └── up.json │ └── static/ │ ├── static.go │ ├── static_test.go │ └── testdata/ │ ├── dynamic/ │ │ ├── app.js │ │ ├── public/ │ │ │ └── css/ │ │ │ └── style.css │ │ └── up.json │ └── static/ │ ├── index.html │ ├── style.css │ └── up.json ├── install.sh ├── internal/ │ ├── account/ │ │ ├── account.go │ │ └── cards.go │ ├── cli/ │ │ ├── app/ │ │ │ └── app.go │ │ ├── build/ │ │ │ └── build.go │ │ ├── config/ │ │ │ └── config.go │ │ ├── deploy/ │ │ │ └── deploy.go │ │ ├── disable-stats/ │ │ │ └── disable-stats.go │ │ ├── docs/ │ │ │ └── docs.go │ │ ├── domains/ │ │ │ └── domains.go │ │ ├── logs/ │ │ │ └── logs.go │ │ ├── metrics/ │ │ │ └── metrics.go │ │ ├── prune/ │ │ │ └── prune.go │ │ ├── root/ │ │ │ └── root.go │ │ ├── run/ │ │ │ └── run.go │ │ ├── stack/ │ │ │ └── stack.go │ │ ├── start/ │ │ │ └── start.go │ │ ├── team/ │ │ │ └── team.go │ │ ├── upgrade/ │ │ │ └── upgrade.go │ │ ├── url/ │ │ │ └── url.go │ │ └── version/ │ │ └── version.go │ ├── colors/ │ │ └── colors.go │ ├── errorpage/ │ │ ├── errorpage.go │ │ ├── errorpage_test.go │ │ ├── template.go │ │ └── testdata/ │ │ ├── 200.html │ │ ├── 404.html │ │ ├── 4xx.html │ │ ├── 500.html │ │ ├── error.html │ │ ├── other.html │ │ └── somedir/ │ │ └── test.html │ ├── header/ │ │ ├── header.go │ │ └── header_test.go │ ├── inject/ │ │ ├── inject.go │ │ └── inject_test.go │ ├── logs/ │ │ ├── logs.go │ │ ├── parser/ │ │ │ ├── ast/ │ │ │ │ └── ast.go │ │ │ ├── grammar.peg │ │ │ ├── grammar.peg.go │ │ │ ├── parser.go │ │ │ └── parser_test.go │ │ ├── text/ │ │ │ ├── text.go │ │ │ └── text_test.go │ │ └── writer/ │ │ ├── writer.go │ │ └── writer_test.go │ ├── metrics/ │ │ └── metrics.go │ ├── progressreader/ │ │ └── progressreader.go │ ├── proxy/ │ │ ├── bin/ │ │ │ └── bin.go │ │ ├── event.go │ │ ├── event_test.go │ │ ├── lambda.go │ │ ├── request.go │ │ ├── request_test.go │ │ ├── response.go │ │ └── response_test.go │ ├── redirect/ │ │ ├── redirect.go │ │ └── redirect_test.go │ ├── setup/ │ │ └── setup.go │ ├── shim/ │ │ ├── index.js │ │ └── shim.go │ ├── signal/ │ │ └── signal.go │ ├── stats/ │ │ └── stats.go │ ├── userconfig/ │ │ ├── userconfig.go │ │ └── userconfig_test.go │ ├── util/ │ │ ├── util.go │ │ └── util_test.go │ ├── validate/ │ │ └── validate.go │ └── zip/ │ ├── testdata/ │ │ ├── .file │ │ ├── .upignore │ │ ├── Readme.md │ │ ├── bar.js │ │ ├── foo.js │ │ └── index.js │ ├── zip.go │ └── zip_test.go ├── platform/ │ ├── aws/ │ │ ├── cost/ │ │ │ ├── cost.go │ │ │ ├── cost_test.go │ │ │ └── domains.go │ │ ├── domains/ │ │ │ └── domains.go │ │ ├── logs/ │ │ │ └── logs.go │ │ ├── regions/ │ │ │ ├── regions.go │ │ │ └── regions_test.go │ │ └── runtime/ │ │ └── runtime.go │ ├── event/ │ │ └── event.go │ └── lambda/ │ ├── lambda.go │ ├── lambda_test.go │ ├── metrics.go │ ├── prune.go │ ├── reporter/ │ │ └── reporter.go │ └── stack/ │ ├── resources/ │ │ ├── resources.go │ │ └── resources_test.go │ ├── stack.go │ ├── stack_test.go │ ├── status.go │ └── status_test.go ├── platform.go ├── reporter/ │ ├── discard/ │ │ └── discard.go │ ├── plain/ │ │ └── plain.go │ ├── reporter.go │ └── text/ │ └── text.go └── up.go
SYMBOL INDEX (968 symbols across 132 files)
FILE: cmd/up-proxy/main.go
function main (line 19) | func main() {
FILE: cmd/up/main.go
function main (line 38) | func main() {
function run (line 60) | func run() error {
function reset (line 72) | func reset() error {
FILE: config/backoff.go
type Backoff (line 10) | type Backoff struct
method Default (line 28) | func (b *Backoff) Default() error {
method Backoff (line 49) | func (b *Backoff) Backoff() *backoff.Backoff {
FILE: config/backoff_test.go
function TestBackoff_Default (line 10) | func TestBackoff_Default(t *testing.T) {
function TestBackoff_Backoff (line 24) | func TestBackoff_Backoff(t *testing.T) {
FILE: config/config.go
type defaulter (line 20) | type defaulter interface
type validator (line 25) | type validator interface
type Config (line 30) | type Config struct
method Validate (line 52) | func (c *Config) Validate() error {
method Default (line 101) | func (c *Config) Default() error {
method Override (line 180) | func (c *Config) Override(stage string) error {
method defaultRegions (line 192) | func (c *Config) defaultRegions() error {
function ParseConfig (line 219) | func ParseConfig(b []byte) (*Config, error) {
function ParseConfigString (line 238) | func ParseConfigString(s string) (*Config, error) {
function MustParseConfigString (line 243) | func MustParseConfigString(s string) *Config {
function ReadConfig (line 253) | func ReadConfig(path string) (*Config, error) {
function setProfile (line 263) | func setProfile(name string) {
FILE: config/config_test.go
function TestConfig_Name (line 11) | func TestConfig_Name(t *testing.T) {
function TestConfig_Type (line 40) | func TestConfig_Type(t *testing.T) {
function TestConfig_Regions (line 75) | func TestConfig_Regions(t *testing.T) {
function TestConfig_defaultRegions (line 169) | func TestConfig_defaultRegions(t *testing.T) {
FILE: config/cors.go
type CORS (line 4) | type CORS struct
FILE: config/dns.go
type DNS (line 27) | type DNS struct
method UnmarshalJSON (line 32) | func (d *DNS) UnmarshalJSON(b []byte) error {
method Default (line 48) | func (d *DNS) Default() error {
method Validate (line 59) | func (d *DNS) Validate() error {
type Zone (line 70) | type Zone struct
method Default (line 76) | func (z *Zone) Default() error {
method Validate (line 87) | func (z *Zone) Validate() error {
type Record (line 98) | type Record struct
method Validate (line 106) | func (r *Record) Validate() error {
method Default (line 127) | func (r *Record) Default() error {
FILE: config/dns_test.go
function ExampleDNS (line 13) | func ExampleDNS() {
function TestDNS_Validate (line 95) | func TestDNS_Validate(t *testing.T) {
function TestRecord_Type (line 115) | func TestRecord_Type(t *testing.T) {
function TestRecord_TTL (line 149) | func TestRecord_TTL(t *testing.T) {
function TestRecord_Value (line 155) | func TestRecord_Value(t *testing.T) {
FILE: config/duration.go
type Duration (line 11) | type Duration
method Seconds (line 14) | func (d *Duration) Seconds() float64 {
method UnmarshalJSON (line 19) | func (d *Duration) UnmarshalJSON(b []byte) error {
method MarshalJSON (line 35) | func (d *Duration) MarshalJSON() ([]byte, error) {
FILE: config/duration_test.go
function TestDuration_UnmarshalJSON (line 11) | func TestDuration_UnmarshalJSON(t *testing.T) {
FILE: config/environment.go
type Environment (line 4) | type Environment
FILE: config/errorpages.go
type ErrorPages (line 4) | type ErrorPages struct
method Default (line 16) | func (e *ErrorPages) Default() error {
FILE: config/errorpages_test.go
function TestErrorPages (line 9) | func TestErrorPages(t *testing.T) {
FILE: config/hooks.go
type Hook (line 9) | type Hook
method UnmarshalJSON (line 69) | func (h *Hook) UnmarshalJSON(b []byte) error {
method IsEmpty (line 86) | func (h *Hook) IsEmpty() bool {
type Hooks (line 12) | type Hooks struct
method Override (line 22) | func (h *Hooks) Override(c *Config) {
method Get (line 49) | func (h *Hooks) Get(s string) Hook {
FILE: config/hooks_test.go
function TestHook (line 10) | func TestHook(t *testing.T) {
FILE: config/lambda.go
type IAMPolicyStatement (line 22) | type IAMPolicyStatement
type VPC (line 25) | type VPC struct
type Lambda (line 31) | type Lambda struct
method Default (line 52) | func (l *Lambda) Default() error {
method Validate (line 71) | func (l *Lambda) Validate() error {
method Override (line 76) | func (l *Lambda) Override(c *Config) {
FILE: config/lambda_test.go
function TestLambda (line 9) | func TestLambda(t *testing.T) {
function TestLambda_Policy (line 16) | func TestLambda_Policy(t *testing.T) {
FILE: config/logs.go
type Logs (line 4) | type Logs struct
method Default (line 16) | func (l *Logs) Default() error {
FILE: config/relay.go
type Relay (line 8) | type Relay struct
method Default (line 20) | func (r *Relay) Default() error {
method Validate (line 37) | func (r *Relay) Validate() error {
method Override (line 62) | func (r *Relay) Override(c *Config) {
FILE: config/runtimes.go
type Runtime (line 11) | type Runtime
constant RuntimeUnknown (line 15) | RuntimeUnknown Runtime = "unknown"
constant RuntimeGo (line 16) | RuntimeGo = "go"
constant RuntimeNode (line 17) | RuntimeNode = "node"
constant RuntimeClojure (line 18) | RuntimeClojure = "clojure"
constant RuntimeCrystal (line 19) | RuntimeCrystal = "crystal"
constant RuntimePython (line 20) | RuntimePython = "python"
constant RuntimeStatic (line 21) | RuntimeStatic = "static"
constant RuntimeJavaMaven (line 22) | RuntimeJavaMaven = "java maven"
constant RuntimeJavaGradle (line 23) | RuntimeJavaGradle = "java gradle"
function inferRuntime (line 27) | func inferRuntime() Runtime {
function runtimeConfig (line 53) | func runtimeConfig(runtime Runtime, c *Config) error {
function golang (line 78) | func golang(c *Config) {
function javaGradle (line 95) | func javaGradle(c *Config) {
function javaMaven (line 115) | func javaMaven(c *Config) {
function clojureLein (line 135) | func clojureLein(c *Config) {
function crystal (line 151) | func crystal(c *Config) {
function nodejs (line 168) | func nodejs(c *Config) error {
function python (line 199) | func python(c *Config) {
FILE: config/stages.go
type Stage (line 18) | type Stage struct
method IsLocal (line 28) | func (s *Stage) IsLocal() bool {
method IsRemote (line 33) | func (s *Stage) IsRemote() bool {
method Validate (line 38) | func (s *Stage) Validate() error {
method Default (line 52) | func (s *Stage) Default() error {
type StageOverrides (line 61) | type StageOverrides struct
method Override (line 68) | func (s *StageOverrides) Override(c *Config) {
type Stages (line 75) | type Stages
method Default (line 78) | func (s Stages) Default() error {
method Validate (line 102) | func (s Stages) Validate() error {
method List (line 112) | func (s Stages) List() (v []*Stage) {
method Domains (line 121) | func (s Stages) Domains() (v []string) {
method Names (line 132) | func (s Stages) Names() (v []string) {
method RemoteNames (line 142) | func (s Stages) RemoteNames() (v []string) {
method GetByDomain (line 154) | func (s Stages) GetByDomain(domain string) *Stage {
method GetByName (line 165) | func (s Stages) GetByName(name string) *Stage {
FILE: config/stages_test.go
function TestStage_Override (line 9) | func TestStage_Override(t *testing.T) {
function TestStages_Default (line 53) | func TestStages_Default(t *testing.T) {
function TestStages_Validate (line 79) | func TestStages_Validate(t *testing.T) {
function TestStages_List (line 138) | func TestStages_List(t *testing.T) {
function TestStages_GetByDomain (line 161) | func TestStages_GetByDomain(t *testing.T) {
FILE: config/static.go
type Static (line 10) | type Static struct
method Validate (line 19) | func (s *Static) Validate() error {
FILE: config/static_test.go
function TestStatic (line 10) | func TestStatic(t *testing.T) {
FILE: handler/handler.go
function FromConfig (line 26) | func FromConfig(c *up.Config) (http.Handler, error) {
function New (line 38) | func New(c *up.Config, h http.Handler) (http.Handler, error) {
FILE: handler/handler_test.go
function newHandler (line 13) | func newHandler(t testing.TB, c *up.Config) http.Handler {
function TestNode (line 23) | func TestNode(t *testing.T) {
function TestStatic (line 51) | func TestStatic(t *testing.T) {
function TestNodeWithPackage (line 80) | func TestNodeWithPackage(t *testing.T) {
function TestNodeWithPackageStart (line 97) | func TestNodeWithPackageStart(t *testing.T) {
function TestHandler_conditionalGet (line 114) | func TestHandler_conditionalGet(t *testing.T) {
function TestHandler_rewrite (line 132) | func TestHandler_rewrite(t *testing.T) {
function TestHandler_redirect (line 149) | func TestHandler_redirect(t *testing.T) {
function TestHandler_spa (line 166) | func TestHandler_spa(t *testing.T) {
FILE: http/cors/cors.go
function New (line 14) | func New(c *up.Config, next http.Handler) http.Handler {
function options (line 23) | func options(c *config.CORS) cors.Options {
FILE: http/cors/cors_test.go
function TestCORS_disabled (line 17) | func TestCORS_disabled(t *testing.T) {
function TestCORS_defaults (line 43) | func TestCORS_defaults(t *testing.T) {
function TestCORS_options (line 95) | func TestCORS_options(t *testing.T) {
FILE: http/errorpages/errorpages.go
type response (line 23) | type response struct
method WriteHeader (line 32) | func (r *response) WriteHeader(code int) {
method Write (line 72) | func (r *response) Write(b []byte) (int, error) {
function New (line 86) | func New(c *up.Config, next http.Handler) (http.Handler, error) {
FILE: http/errorpages/errorpages_test.go
function TestErrors_templates (line 48) | func TestErrors_templates(t *testing.T) {
function TestErrors_dir (line 64) | func TestErrors_dir(t *testing.T) {
function TestErrors_defaults (line 79) | func TestErrors_defaults(t *testing.T) {
function TestErrors_disabled (line 101) | func TestErrors_disabled(t *testing.T) {
function test (line 138) | func test(t *testing.T, c *up.Config) {
function nonError (line 173) | func nonError(h http.Handler) func(t *testing.T) {
function acceptsHTML (line 187) | func acceptsHTML(h http.Handler) func(t *testing.T) {
function acceptsText (line 205) | func acceptsText(h http.Handler) func(t *testing.T) {
function doesNotAcceptHTML (line 223) | func doesNotAcceptHTML(h http.Handler) func(t *testing.T) {
FILE: http/gzip/gzip.go
function New (line 13) | func New(c *up.Config, next http.Handler) http.Handler {
FILE: http/gzip/gzip_test.go
function TestGzip (line 22) | func TestGzip(t *testing.T) {
FILE: http/headers/headers.go
function New (line 23) | func New(c *up.Config, next http.Handler) (http.Handler, error) {
function readFromFile (line 51) | func readFromFile(path string) (header.Rules, error) {
FILE: http/headers/headers_test.go
function TestHeaders (line 15) | func TestHeaders(t *testing.T) {
FILE: http/inject/inject.go
type response (line 16) | type response struct
method Write (line 26) | func (r *response) Write(b []byte) (int, error) {
method WriteHeader (line 36) | func (r *response) WriteHeader(code int) {
method end (line 45) | func (r *response) end() {
function New (line 60) | func New(c *up.Config, next http.Handler) (http.Handler, error) {
FILE: http/inject/inject_test.go
function TestInject (line 19) | func TestInject(t *testing.T) {
FILE: http/logs/logs.go
type response (line 22) | type response struct
method Write (line 30) | func (r *response) Write(b []byte) (int, error) {
method WriteHeader (line 37) | func (r *response) WriteHeader(code int) {
function New (line 43) | func New(c *up.Config, next http.Handler) (http.Handler, error) {
function logContext (line 64) | func logContext(r *http.Request) log.Interface {
function logRequest (line 75) | func logRequest(ctx log.Interface, r *http.Request) {
function logResponse (line 87) | func logResponse(ctx log.Interface, res *response, r *http.Request) {
FILE: http/logs/logs_test.go
function TestLogs (line 16) | func TestLogs(t *testing.T) {
FILE: http/poweredby/poweredby.go
function New (line 9) | func New(name string, next http.Handler) http.Handler {
FILE: http/poweredby/poweredby_test.go
function TestPoweredby (line 14) | func TestPoweredby(t *testing.T) {
FILE: http/redirects/redirects.go
type rewrite (line 21) | type rewrite struct
method WriteHeader (line 28) | func (r *rewrite) WriteHeader(code int) {
method Write (line 40) | func (r *rewrite) Write(b []byte) (int, error) {
function New (line 54) | func New(c *up.Config, next http.Handler) (http.Handler, error) {
FILE: http/redirects/redirects_test.go
function TestRedirects (line 17) | func TestRedirects(t *testing.T) {
function test (line 88) | func test(t *testing.T, h http.Handler) {
FILE: http/relay/relay.go
type Proxy (line 33) | type Proxy struct
method Start (line 93) | func (p *Proxy) Start() error {
method Restart (line 114) | func (p *Proxy) Restart() error {
method RoundTrip (line 136) | func (p *Proxy) RoundTrip(r *http.Request) (*http.Response, error) {
method environment (line 174) | func (p *Proxy) environment() []string {
method startServer (line 182) | func (p *Proxy) startServer() error {
method command (line 207) | func (p *Proxy) command(s string, env []string) *exec.Cmd {
function New (line 65) | func New(c *up.Config) (http.Handler, error) {
function newTransport (line 216) | func newTransport(timeout time.Duration) *http.Transport {
function env (line 229) | func env(name string, val interface{}) string {
FILE: http/relay/relay_test.go
function skipCI (line 18) | func skipCI(t testing.TB) {
function TestRelay (line 24) | func TestRelay(t *testing.T) {
function assertString (line 173) | func assertString(t testing.TB, want, got string) {
FILE: http/robots/robots.go
function New (line 12) | func New(c *up.Config, next http.Handler) http.Handler {
FILE: http/robots/robots_test.go
function TestRobots (line 15) | func TestRobots(t *testing.T) {
FILE: http/static/static.go
function New (line 14) | func New(c *up.Config) http.Handler {
function NewDynamic (line 19) | func NewDynamic(c *up.Config, next http.Handler) http.Handler {
function normalizePrefix (line 59) | func normalizePrefix(s string) string {
FILE: http/static/static_test.go
function TestStatic_defaults (line 15) | func TestStatic_defaults(t *testing.T) {
function TestStatic_dir (line 25) | func TestStatic_dir(t *testing.T) {
function test (line 39) | func test(t *testing.T, c *up.Config) {
function TestStatic_dynamic (line 86) | func TestStatic_dynamic(t *testing.T) {
function TestStatic_dynamicPrefix (line 124) | func TestStatic_dynamicPrefix(t *testing.T) {
function TestNormalizePrefix (line 172) | func TestNormalizePrefix(t *testing.T) {
FILE: internal/account/account.go
type Error (line 18) | type Error struct
method Error (line 24) | func (e *Error) Error() string {
type Card (line 29) | type Card struct
type CouponDuration (line 36) | type CouponDuration
constant Forever (line 40) | Forever CouponDuration = "forever"
constant Once (line 41) | Once = "once"
constant Repeating (line 42) | Repeating = "repeating"
type Coupon (line 46) | type Coupon struct
method Discount (line 55) | func (c *Coupon) Discount(n int) int {
method Description (line 64) | func (c *Coupon) Description() (s string) {
type Discount (line 84) | type Discount struct
type Plan (line 89) | type Plan struct
type User (line 104) | type User struct
type Team (line 110) | type Team struct
type Client (line 123) | type Client struct
method GetCoupon (line 135) | func (c *Client) GetCoupon(id string) (coupon *Coupon, err error) {
method AddCard (line 148) | func (c *Client) AddCard(token, cardToken string) error {
method GetTeam (line 165) | func (c *Client) GetTeam(token string) (*Team, error) {
method GetCards (line 177) | func (c *Client) GetCards(token string) (cards []Card, err error) {
method GetPlans (line 189) | func (c *Client) GetPlans(token string) (plans []Plan, err error) {
method RemoveCard (line 201) | func (c *Client) RemoveCard(token, id string) error {
method AddPlan (line 212) | func (c *Client) AddPlan(token, product, interval, coupon string) error {
method AddTeam (line 233) | func (c *Client) AddTeam(token, id, name string) error {
method AddInvite (line 252) | func (c *Client) AddInvite(token, email string) error {
method RemoveMember (line 269) | func (c *Client) RemoveMember(token, email string) error {
method RemovePlan (line 286) | func (c *Client) RemovePlan(token, product string) error {
method AddFeedback (line 298) | func (c *Client) AddFeedback(token, message string) error {
method Login (line 315) | func (c *Client) Login(email, team string) (code string, err error) {
method LoginWithToken (line 349) | func (c *Client) LoginWithToken(token, email, team string) (code strin...
method GetAccessToken (line 374) | func (c *Client) GetAccessToken(email, team, code string) (key string,...
method PollAccessToken (line 400) | func (c *Client) PollAccessToken(ctx context.Context, email, team, cod...
method requestJSON (line 433) | func (c *Client) requestJSON(token, method, path string, v interface{}...
method request (line 443) | func (c *Client) request(token, method, path string, body io.Reader) (...
function New (line 128) | func New(url string) *Client {
FILE: internal/account/cards.go
function PromptForCard (line 63) | func PromptForCard() (card stripe.CardParams, err error) {
FILE: internal/cli/app/app.go
function Run (line 13) | func Run(version string) error {
FILE: internal/cli/build/build.go
function init (line 22) | func init() {
FILE: internal/cli/config/config.go
function init (line 13) | func init() {
FILE: internal/cli/deploy/deploy.go
function init (line 20) | func init() {
function deploy (line 34) | func deploy(stage string, build bool) error {
function isMissingConfig (line 123) | func isMissingConfig(err error) bool {
function getCommit (line 130) | func getCommit() (git.Commit, error) {
function isIgnorable (line 144) | func isIgnorable(err error) bool {
FILE: internal/cli/disable-stats/disable-stats.go
function init (line 11) | func init() {
FILE: internal/cli/docs/docs.go
function init (line 13) | func init() {
FILE: internal/cli/domains/domains.go
function init (line 24) | func init() {
function buy (line 87) | func buy(cmd *kingpin.Cmd) {
function check (line 119) | func check(cmd *kingpin.Cmd) {
function list (line 166) | func list(cmd *kingpin.Cmd) {
function validateEmail (line 197) | func validateEmail(v interface{}) error {
function validateCountryCode (line 217) | func validateCountryCode(v interface{}) error {
function validatePhoneNumber (line 232) | func validatePhoneNumber(v interface{}) error {
FILE: internal/cli/logs/logs.go
function init (line 18) | func init() {
FILE: internal/cli/metrics/metrics.go
function init (line 14) | func init() {
FILE: internal/cli/prune/prune.go
function init (line 11) | func init() {
FILE: internal/cli/root/root.go
function init (line 29) | func init() {
FILE: internal/cli/run/run.go
function init (line 11) | func init() {
FILE: internal/cli/stack/stack.go
function init (line 15) | func init() {
function plan (line 30) | func plan(cmd *kingpin.Cmd) {
function apply (line 58) | func apply(cmd *kingpin.Cmd) {
function delete (line 80) | func delete(cmd *kingpin.Cmd) {
function status (line 128) | func status(cmd *kingpin.Cmd) {
FILE: internal/cli/start/start.go
function init (line 20) | func init() {
FILE: internal/cli/team/team.go
function init (line 52) | func init() {
function add (line 76) | func add(cmd *kingpin.Cmd) {
function copy (line 141) | func copy(cmd *kingpin.Cmd) {
function status (line 175) | func status(cmd *kingpin.Cmd) {
function switchTeam (line 236) | func switchTeam(cmd *kingpin.Cmd) {
function login (line 280) | func login(cmd *kingpin.Cmd) {
function logout (line 391) | func logout(cmd *kingpin.Cmd) {
function subscribe (line 409) | func subscribe(cmd *kingpin.Cmd) {
function unsubscribe (line 525) | func unsubscribe(cmd *kingpin.Cmd) {
function members (line 578) | func members(cmd *kingpin.Cmd) {
function addMember (line 586) | func addMember(cmd *kingpin.Cmd) {
function removeMember (line 613) | func removeMember(cmd *kingpin.Cmd) {
function listMembers (line 640) | func listMembers(cmd *kingpin.Cmd) {
function card (line 681) | func card(cmd *kingpin.Cmd) {
function changeCard (line 687) | func changeCard(cmd *kingpin.Cmd) {
function prompt (line 727) | func prompt(name string, s *string) error {
function feedback (line 733) | func feedback() (string, error) {
function currency (line 743) | func currency(n int) string {
function keys (line 748) | func keys(m map[string]string) (v []string) {
FILE: internal/cli/upgrade/upgrade.go
function init (line 29) | func init() {
function getLatestOrSpecified (line 134) | func getLatestOrSpecified(s update.Store, version string) (*update.Relea...
function getLatest (line 143) | func getLatest(s update.Store) (*update.Release, error) {
function versionName (line 162) | func versionName(s string) string {
FILE: internal/cli/url/url.go
function init (line 17) | func init() {
FILE: internal/cli/version/version.go
function init (line 12) | func init() {
FILE: internal/colors/colors.go
type Func (line 9) | type Func
function Gray (line 12) | func Gray(s string) string {
function Blue (line 17) | func Blue(s string) string {
function Cyan (line 22) | func Cyan(s string) string {
function Green (line 27) | func Green(s string) string {
function Red (line 32) | func Red(s string) string {
function Yellow (line 37) | func Yellow(s string) string {
function Purple (line 42) | func Purple(s string) string {
function Bool (line 47) | func Bool(ok bool) Func {
FILE: internal/errorpage/errorpage.go
type Page (line 18) | type Page struct
method Match (line 26) | func (p *Page) Match(code int) bool {
method Specificity (line 42) | func (p *Page) Specificity() int {
method Render (line 56) | func (p *Page) Render(data interface{}) (string, error) {
type Pages (line 68) | type Pages
method Match (line 71) | func (p Pages) Match(code int) *Page {
function Load (line 82) | func Load(dir string) (pages Pages, err error) {
function Sort (line 127) | func Sort(pages Pages) {
function isErrorPage (line 136) | func isErrorPage(path string) bool {
function isRange (line 156) | func isRange(name string) bool {
function stripExt (line 161) | func stripExt(path string) string {
FILE: internal/errorpage/errorpage_test.go
function load (line 11) | func load(t testing.TB, dir string) Pages {
function TestPages_precedence (line 18) | func TestPages_precedence(t *testing.T) {
FILE: internal/header/header.go
type Fields (line 9) | type Fields
type Rules (line 12) | type Rules
type Matcher (line 15) | type Matcher struct
method Lookup (line 20) | func (m *Matcher) Lookup(path string) Fields {
function Compile (line 30) | func Compile(rules Rules) (*Matcher, error) {
function Merge (line 42) | func Merge(a, b Rules) Rules {
FILE: internal/header/header_test.go
function TestMatcher_Lookup (line 9) | func TestMatcher_Lookup(t *testing.T) {
function TestMerge (line 37) | func TestMerge(t *testing.T) {
FILE: internal/inject/inject.go
type Rules (line 37) | type Rules
method Default (line 40) | func (r Rules) Default() error {
method Validate (line 53) | func (r Rules) Validate() error {
method Apply (line 70) | func (r Rules) Apply(html string) string {
type Rule (line 88) | type Rule struct
method Apply (line 103) | func (r *Rule) Apply(html string) string {
method Default (line 127) | func (r *Rule) Default() error {
method Validate (line 142) | func (r *Rule) Validate() error {
method defaultFile (line 155) | func (r *Rule) defaultFile(path string) error {
function Head (line 166) | func Head(html, s string) string {
function Body (line 171) | func Body(html, s string) string {
function Script (line 176) | func Script(src string) string {
function ScriptInline (line 181) | func ScriptInline(s string) string {
function Style (line 186) | func Style(href string) string {
function StyleInline (line 191) | func StyleInline(s string) string {
function Comment (line 196) | func Comment(s string) string {
function Segment (line 201) | func Segment(key string) string {
function GoogleAnalytics (line 211) | func GoogleAnalytics(trackingID string) string {
function Var (line 224) | func Var(kind, name string, v interface{}) string {
FILE: internal/inject/inject_test.go
function ExampleStyle (line 23) | func ExampleStyle() {
function ExampleStyleInline (line 29) | func ExampleStyleInline() {
function ExampleScript (line 35) | func ExampleScript() {
function ExampleScriptInline (line 41) | func ExampleScriptInline() {
function ExampleComment (line 47) | func ExampleComment() {
function ExampleHead (line 53) | func ExampleHead() {
function ExampleBody (line 70) | func ExampleBody() {
function ExampleSegment (line 87) | func ExampleSegment() {
function ExampleGoogleAnalytics (line 98) | func ExampleGoogleAnalytics() {
function ExampleVar (line 112) | func ExampleVar() {
function TestRule_Default (line 122) | func TestRule_Default(t *testing.T) {
function TestRule_Validate (line 129) | func TestRule_Validate(t *testing.T) {
function TestRules_Default (line 144) | func TestRules_Default(t *testing.T) {
function TestRules_Validate (line 159) | func TestRules_Validate(t *testing.T) {
FILE: internal/logs/logs.go
function Fields (line 11) | func Fields() log.Fields {
function Plugin (line 27) | func Plugin(name string) log.Interface {
FILE: internal/logs/parser/ast/ast.go
type Op (line 11) | type Op
constant LNOT (line 15) | LNOT Op = "not"
constant NOT (line 16) | NOT = "!"
constant IN (line 17) | IN = "in"
constant OR (line 18) | OR = "||"
constant AND (line 19) | AND = "&&"
constant NE (line 20) | NE = "!="
constant EQ (line 21) | EQ = "="
constant GT (line 22) | GT = ">"
constant LT (line 23) | LT = "<"
constant GE (line 24) | GE = ">="
constant LE (line 25) | LE = "<="
type Node (line 29) | type Node interface
type Root (line 34) | type Root struct
method String (line 39) | func (n Root) String() string {
type Expr (line 44) | type Expr struct
method String (line 49) | func (n Expr) String() string {
type Literal (line 54) | type Literal
method String (line 57) | func (n Literal) String() string {
type Tuple (line 62) | type Tuple
method String (line 65) | func (n Tuple) String() string {
type Contains (line 70) | type Contains struct
method String (line 75) | func (n Contains) String() string {
type String (line 85) | type String
method String (line 88) | func (n String) String() string {
type Property (line 93) | type Property
method String (line 96) | func (n Property) String() string {
type Field (line 101) | type Field
method String (line 104) | func (n Field) String() string {
type Subscript (line 109) | type Subscript struct
method String (line 115) | func (n Subscript) String() string {
type Member (line 120) | type Member struct
method String (line 126) | func (n Member) String() string {
type Number (line 131) | type Number struct
method String (line 137) | func (n Number) String() string {
type Binary (line 155) | type Binary struct
method String (line 162) | func (n Binary) String() string {
type Unary (line 178) | type Unary struct
method String (line 184) | func (n Unary) String() string {
function value (line 194) | func value(n Node) string {
FILE: internal/logs/parser/grammar.peg.go
constant endSymbol (line 14) | endSymbol rune = 1114112
type pegRule (line 17) | type pegRule
constant ruleUnknown (line 20) | ruleUnknown pegRule = iota
constant ruleQuery (line 21) | ruleQuery
constant rulePrimaryExpr (line 22) | rulePrimaryExpr
constant ruleTupleExpr (line 23) | ruleTupleExpr
constant ruleInExpr (line 24) | ruleInExpr
constant ruleNotInExpr (line 25) | ruleNotInExpr
constant rulePostfixExpr (line 26) | rulePostfixExpr
constant ruleUnaryExpr (line 27) | ruleUnaryExpr
constant ruleRelationalExpr (line 28) | ruleRelationalExpr
constant ruleEqualityExpr (line 29) | ruleEqualityExpr
constant ruleLogicalAndExpr (line 30) | ruleLogicalAndExpr
constant ruleLogicalOrExpr (line 31) | ruleLogicalOrExpr
constant ruleLowNotExpr (line 32) | ruleLowNotExpr
constant ruleExpr (line 33) | ruleExpr
constant ruleString (line 34) | ruleString
constant ruleStringChar (line 35) | ruleStringChar
constant ruleUnquotedString (line 36) | ruleUnquotedString
constant ruleUnquotedStringStartChar (line 37) | ruleUnquotedStringStartChar
constant ruleUnquotedStringChar (line 38) | ruleUnquotedStringChar
constant ruleEscape (line 39) | ruleEscape
constant ruleSimpleEscape (line 40) | ruleSimpleEscape
constant ruleOctalEscape (line 41) | ruleOctalEscape
constant ruleHexEscape (line 42) | ruleHexEscape
constant ruleUniversalCharacter (line 43) | ruleUniversalCharacter
constant ruleHexQuad (line 44) | ruleHexQuad
constant ruleHexDigit (line 45) | ruleHexDigit
constant ruleNumbers (line 46) | ruleNumbers
constant ruleNumber (line 47) | ruleNumber
constant ruleInteger (line 48) | ruleInteger
constant ruleFloat (line 49) | ruleFloat
constant ruleFraction (line 50) | ruleFraction
constant ruleExponent (line 51) | ruleExponent
constant ruleStage (line 52) | ruleStage
constant ruleDEVELOPMENT (line 53) | ruleDEVELOPMENT
constant ruleSTAGING (line 54) | ruleSTAGING
constant rulePRODUCTION (line 55) | rulePRODUCTION
constant ruleUnit (line 56) | ruleUnit
constant ruleDuration (line 57) | ruleDuration
constant ruleS (line 58) | ruleS
constant ruleMS (line 59) | ruleMS
constant ruleBytes (line 60) | ruleBytes
constant ruleB (line 61) | ruleB
constant ruleKB (line 62) | ruleKB
constant ruleMB (line 63) | ruleMB
constant ruleGB (line 64) | ruleGB
constant ruleId (line 65) | ruleId
constant ruleIdChar (line 66) | ruleIdChar
constant ruleIdCharNoDigit (line 67) | ruleIdCharNoDigit
constant ruleSeverity (line 68) | ruleSeverity
constant ruleIN (line 69) | ruleIN
constant ruleOR (line 70) | ruleOR
constant ruleAND (line 71) | ruleAND
constant ruleNOT (line 72) | ruleNOT
constant ruleCONTAINS (line 73) | ruleCONTAINS
constant ruleDEBUG (line 74) | ruleDEBUG
constant ruleINFO (line 75) | ruleINFO
constant ruleWARN (line 76) | ruleWARN
constant ruleERROR (line 77) | ruleERROR
constant ruleFATAL (line 78) | ruleFATAL
constant ruleKeyword (line 79) | ruleKeyword
constant ruleEQ (line 80) | ruleEQ
constant ruleLBRK (line 81) | ruleLBRK
constant ruleRBRK (line 82) | ruleRBRK
constant ruleLPAR (line 83) | ruleLPAR
constant ruleRPAR (line 84) | ruleRPAR
constant ruleDOT (line 85) | ruleDOT
constant ruleBANG (line 86) | ruleBANG
constant ruleLT (line 87) | ruleLT
constant ruleGT (line 88) | ruleGT
constant ruleLE (line 89) | ruleLE
constant ruleEQEQ (line 90) | ruleEQEQ
constant ruleGE (line 91) | ruleGE
constant ruleNE (line 92) | ruleNE
constant ruleANDAND (line 93) | ruleANDAND
constant ruleOROR (line 94) | ruleOROR
constant ruleCOMMA (line 95) | ruleCOMMA
constant rule_ (line 96) | rule_
constant ruleWhitespace (line 97) | ruleWhitespace
constant ruleEOL (line 98) | ruleEOL
constant ruleEOF (line 99) | ruleEOF
constant ruleAction0 (line 100) | ruleAction0
constant ruleAction1 (line 101) | ruleAction1
constant ruleAction2 (line 102) | ruleAction2
constant ruleAction3 (line 103) | ruleAction3
constant ruleAction4 (line 104) | ruleAction4
constant ruleAction5 (line 105) | ruleAction5
constant ruleAction6 (line 106) | ruleAction6
constant ruleAction7 (line 107) | ruleAction7
constant ruleAction8 (line 108) | ruleAction8
constant ruleAction9 (line 109) | ruleAction9
constant ruleAction10 (line 110) | ruleAction10
constant ruleAction11 (line 111) | ruleAction11
constant ruleAction12 (line 112) | ruleAction12
constant ruleAction13 (line 113) | ruleAction13
constant ruleAction14 (line 114) | ruleAction14
constant ruleAction15 (line 115) | ruleAction15
constant ruleAction16 (line 116) | ruleAction16
constant ruleAction17 (line 117) | ruleAction17
constant ruleAction18 (line 118) | ruleAction18
constant ruleAction19 (line 119) | ruleAction19
constant ruleAction20 (line 120) | ruleAction20
constant ruleAction21 (line 121) | ruleAction21
constant ruleAction22 (line 122) | ruleAction22
constant ruleAction23 (line 123) | ruleAction23
constant ruleAction24 (line 124) | ruleAction24
constant ruleAction25 (line 125) | ruleAction25
constant ruleAction26 (line 126) | ruleAction26
constant ruleAction27 (line 127) | ruleAction27
constant ruleAction28 (line 128) | ruleAction28
constant ruleAction29 (line 129) | ruleAction29
constant ruleAction30 (line 130) | ruleAction30
constant rulePegText (line 131) | rulePegText
constant ruleAction31 (line 132) | ruleAction31
type token32 (line 251) | type token32 struct
method String (line 256) | func (t *token32) String() string {
type node32 (line 260) | type node32 struct
method print (line 265) | func (node *node32) print(w io.Writer, pretty bool, buffer string) {
method Print (line 288) | func (node *node32) Print(w io.Writer, buffer string) {
method PrettyPrint (line 292) | func (node *node32) PrettyPrint(w io.Writer, buffer string) {
type tokens32 (line 296) | type tokens32 struct
method Trim (line 300) | func (t *tokens32) Trim(length uint32) {
method Print (line 304) | func (t *tokens32) Print() {
method AST (line 310) | func (t *tokens32) AST() *node32 {
method PrintSyntaxTree (line 335) | func (t *tokens32) PrintSyntaxTree(buffer string) {
method WriteSyntaxTree (line 339) | func (t *tokens32) WriteSyntaxTree(w io.Writer, buffer string) {
method PrettyPrintSyntaxTree (line 343) | func (t *tokens32) PrettyPrintSyntaxTree(buffer string) {
method Add (line 347) | func (t *tokens32) Add(rule pegRule, begin, end, index uint32) {
method Tokens (line 356) | func (t *tokens32) Tokens() []token32 {
type parser (line 360) | type parser struct
method Parse (line 373) | func (p *parser) Parse(rule ...int) error {
method Reset (line 377) | func (p *parser) Reset() {
method PrintSyntaxTree (line 441) | func (p *parser) PrintSyntaxTree() {
method WriteSyntaxTree (line 449) | func (p *parser) WriteSyntaxTree(w io.Writer) {
method Execute (line 453) | func (p *parser) Execute() {
method Init (line 546) | func (p *parser) Init(options ...func(*parser) error) error {
type textPosition (line 381) | type textPosition struct
type textPositionMap (line 385) | type textPositionMap
function translatePositions (line 387) | func translatePositions(buffer []rune, positions []int) textPositionMap {
type parseError (line 412) | type parseError struct
method Error (line 417) | func (e *parseError) Error() string {
function Pretty (line 533) | func Pretty(pretty bool) func(*parser) error {
function Size (line 540) | func Size(size int) func(*parser) error {
FILE: internal/logs/parser/parser.go
function Parse (line 15) | func Parse(s string) (ast.Node, error) {
method push (line 29) | func (p *parser) push(n ast.Node) {
method pop (line 34) | func (p *parser) pop() ast.Node {
method AddLevel (line 45) | func (p *parser) AddLevel(s string) {
method AddExpr (line 53) | func (p *parser) AddExpr() {
method AddField (line 60) | func (p *parser) AddField(s string) {
method AddString (line 70) | func (p *parser) AddString(s string) {
method AddSubscript (line 75) | func (p *parser) AddSubscript(s string) {
method AddMember (line 83) | func (p *parser) AddMember(s string) {
method SetNumber (line 91) | func (p *parser) SetNumber(s string) {
method AddNumber (line 96) | func (p *parser) AddNumber(unit string) {
method AddTuple (line 105) | func (p *parser) AddTuple() {
method AddTupleValue (line 110) | func (p *parser) AddTupleValue() {
method AddBinary (line 118) | func (p *parser) AddBinary(op ast.Op) {
method AddStage (line 127) | func (p *parser) AddStage(stage string) {
method AddBinaryContains (line 136) | func (p *parser) AddBinaryContains() {
method AddUnary (line 145) | func (p *parser) AddUnary(op ast.Op) {
FILE: internal/logs/parser/parser_test.go
function TestParse (line 95) | func TestParse(t *testing.T) {
function BenchmarkParse (line 111) | func BenchmarkParse(b *testing.B) {
FILE: internal/logs/text/text.go
type colorFunc (line 26) | type colorFunc
type Handler (line 57) | type Handler struct
method WithExpandedFields (line 72) | func (h *Handler) WithExpandedFields(v bool) *Handler {
method HandleLog (line 78) | func (h *Handler) HandleLog(e *log.Entry) error {
method handleExpanded (line 88) | func (h *Handler) handleExpanded(e *log.Entry) error {
method handleInline (line 117) | func (h *Handler) handleInline(e *log.Entry) error {
function New (line 65) | func New(w io.Writer) *Handler {
function value (line 164) | func value(name string, v interface{}) interface{} {
function formatDate (line 179) | func formatDate(t time.Time) string {
function version (line 184) | func version(e *log.Entry) string {
function bold (line 197) | func bold(s string) string {
FILE: internal/logs/text/text_test.go
function init (line 13) | func init() {
function Test (line 19) | func Test(t *testing.T) {
FILE: internal/logs/writer/writer.go
type Writer (line 16) | type Writer struct
method Write (line 30) | func (w *Writer) Write(b []byte) (int, error) {
method write (line 47) | func (w *Writer) write(s string) error {
method writeJSON (line 56) | func (w *Writer) writeJSON(s string) error {
method writeText (line 83) | func (w *Writer) writeText(s string) error {
function New (line 22) | func New(l log.Level, ctx log.Interface) *Writer {
FILE: internal/logs/writer/writer_test.go
function init (line 15) | func init() {
function TestWriter_plainTextFlat (line 21) | func TestWriter_plainTextFlat(t *testing.T) {
function TestWriter_json (line 48) | func TestWriter_json(t *testing.T) {
FILE: internal/metrics/metrics.go
type Metrics (line 12) | type Metrics struct
method Namespace (line 22) | func (m *Metrics) Namespace(name string) *Metrics {
method Metric (line 28) | func (m *Metrics) Metric(name string) *Metrics {
method Stats (line 34) | func (m *Metrics) Stats(names []string) *Metrics {
method Stat (line 40) | func (m *Metrics) Stat(name string) *Metrics {
method Dimension (line 46) | func (m *Metrics) Dimension(name, value string) *Metrics {
method Period (line 56) | func (m *Metrics) Period(seconds int) *Metrics {
method TimeRange (line 62) | func (m *Metrics) TimeRange(start, end time.Time) *Metrics {
method Params (line 69) | func (m *Metrics) Params() *cloudwatch.GetMetricStatisticsInput {
function New (line 17) | func New() *Metrics {
FILE: internal/progressreader/progressreader.go
type reader (line 14) | type reader struct
method Read (line 23) | func (r *reader) Read(b []byte) (int, error) {
function New (line 33) | func New(size int, r io.ReadCloser) io.ReadCloser {
FILE: internal/proxy/event.go
type Identity (line 4) | type Identity struct
type RequestContext (line 20) | type RequestContext struct
type Input (line 33) | type Input struct
type Output (line 47) | type Output struct
FILE: internal/proxy/event_test.go
function output (line 233) | func output(v interface{}) {
function ExampleInput_get (line 238) | func ExampleInput_get() {
function ExampleInput_post (line 300) | func ExampleInput_post() {
FILE: internal/proxy/lambda.go
function NewHandler (line 13) | func NewHandler(h http.Handler) apex.Handler {
FILE: internal/proxy/request.go
function NewRequest (line 15) | func NewRequest(e *Input) (*http.Request, error) {
FILE: internal/proxy/request_test.go
function TestNewRequest (line 11) | func TestNewRequest(t *testing.T) {
FILE: internal/proxy/response.go
type ResponseWriter (line 15) | type ResponseWriter struct
method Header (line 28) | func (w *ResponseWriter) Header() http.Header {
method Write (line 37) | func (w *ResponseWriter) Write(b []byte) (int, error) {
method WriteHeader (line 48) | func (w *ResponseWriter) WriteHeader(status int) {
method End (line 76) | func (w *ResponseWriter) End() Output {
function NewResponse (line 23) | func NewResponse() *ResponseWriter {
function isBinary (line 89) | func isBinary(h http.Header) bool {
function isTextMime (line 102) | func isTextMime(kind string) bool {
FILE: internal/proxy/response_test.go
function Test_JSON_isTextMime (line 10) | func Test_JSON_isTextMime(t *testing.T) {
function Test_XML_isTextMime (line 16) | func Test_XML_isTextMime(t *testing.T) {
function TestResponseWriter_Header (line 22) | func TestResponseWriter_Header(t *testing.T) {
function TestResponseWriter_Write_text (line 33) | func TestResponseWriter_Write_text(t *testing.T) {
function TestResponseWriter_Write_binary (line 59) | func TestResponseWriter_Write_binary(t *testing.T) {
function TestResponseWriter_Write_gzip (line 71) | func TestResponseWriter_Write_gzip(t *testing.T) {
function TestResponseWriter_WriteHeader (line 84) | func TestResponseWriter_WriteHeader(t *testing.T) {
FILE: internal/redirect/redirect.go
type Rule (line 18) | type Rule struct
method URL (line 30) | func (r Rule) URL(path string) string {
method IsDynamic (line 35) | func (r *Rule) IsDynamic() bool {
method IsRewrite (line 40) | func (r *Rule) IsRewrite() bool {
method Compile (line 45) | func (r *Rule) Compile() {
type Rules (line 52) | type Rules
type Matcher (line 55) | type Matcher struct
method Lookup (line 60) | func (m *Matcher) Lookup(path string) *Rule {
function Compile (line 71) | func Compile(rules Rules) (*Matcher, error) {
function compileSub (line 86) | func compileSub(path, s string, names map[string]bool) string {
function compilePath (line 107) | func compilePath(s string) (*regexp.Regexp, map[string]bool) {
function compilePattern (line 131) | func compilePattern(s string) string {
function isDynamic (line 136) | func isDynamic(s string) bool {
function hasPlaceholder (line 141) | func hasPlaceholder(s string) bool {
function hasSplat (line 146) | func hasSplat(s string) bool {
FILE: internal/redirect/redirect_test.go
function rule (line 10) | func rule(from, to string) Rule {
function TestRule_URL (line 20) | func TestRule_URL(t *testing.T) {
function TestMatcher_Lookup (line 71) | func TestMatcher_Lookup(t *testing.T) {
function BenchmarkMatcher_Lookup (line 117) | func BenchmarkMatcher_Lookup(b *testing.B) {
FILE: internal/setup/setup.go
type config (line 26) | type config struct
function Create (line 65) | func Create() error {
function defaultName (line 114) | func defaultName() string {
function defaultRegion (line 124) | func defaultRegion() string {
function validateName (line 137) | func validateName(v interface{}) error {
function awsProfiles (line 146) | func awsProfiles() []string {
FILE: internal/shim/index.js
function nextId (line 26) | function nextId(){
function handleLine (line 42) | function handleLine(line) {
constant NEWLINE (line 97) | const NEWLINE = '\n'.charCodeAt(0);
function handleChunk (line 100) | function handleChunk(chunk) {
FILE: internal/signal/signal.go
function init (line 15) | func init() {
type Func (line 22) | type Func
function Add (line 25) | func Add(fn Func) {
function trap (line 30) | func trap(ch chan os.Signal) {
FILE: internal/stats/stats.go
function Track (line 19) | func Track(name string, props map[string]interface{}) {
function SetProperties (line 33) | func SetProperties(props map[string]interface{}) {
function Flush (line 38) | func Flush() {
FILE: internal/userconfig/userconfig.go
type Team (line 26) | type Team struct
method IsPersonal (line 38) | func (t *Team) IsPersonal() bool {
type Config (line 43) | type Config struct
method initTeams (line 52) | func (c *Config) initTeams() {
method AddTeam (line 59) | func (c *Config) AddTeam(t *Team) {
method GetTeams (line 65) | func (c *Config) GetTeams() (teams []*Team) {
method GetTeam (line 73) | func (c *Config) GetTeam(id string) *Team {
method GetActiveTeam (line 78) | func (c *Config) GetActiveTeam() *Team {
method Authenticated (line 83) | func (c *Config) Authenticated() bool {
method Load (line 120) | func (c *Config) Load() error {
method Save (line 162) | func (c *Config) Save() error {
method path (line 181) | func (c *Config) path() (string, error) {
function Require (line 88) | func Require() (*Team, error) {
function Alter (line 103) | func Alter(fn func(*Config)) error {
FILE: internal/userconfig/userconfig_test.go
function init (line 12) | func init() {
function TestConfig_file (line 16) | func TestConfig_file(t *testing.T) {
function TestConfig_env (line 41) | func TestConfig_env(t *testing.T) {
FILE: internal/util/util.go
function ClearHeader (line 32) | func ClearHeader(h http.Header) {
function ManagedByUp (line 44) | func ManagedByUp(s string) string {
function Exists (line 53) | func Exists(path string) bool {
function ReadFileJSON (line 59) | func ReadFileJSON(path string, v interface{}) error {
function Camelcase (line 73) | func Camelcase(s string, v ...interface{}) string {
function NewProgressInt (line 78) | func NewProgressInt(total int) *progress.Bar {
function NewInlineProgressInt (line 90) | func NewInlineProgressInt(total int) *progress.Bar {
function Pad (line 102) | func Pad() func() {
function Fatal (line 110) | func Fatal(err error) {
function IsJSON (line 116) | func IsJSON(s string) bool {
function IsJSONLog (line 121) | func IsJSONLog(s string) bool {
function IsNotFound (line 126) | func IsNotFound(err error) bool {
function IsBucketExists (line 144) | func IsBucketExists(err error) bool {
function IsThrottled (line 156) | func IsThrottled(err error) bool {
function IsNoCredentials (line 168) | func IsNoCredentials(err error) bool {
function Env (line 180) | func Env(m map[string]string) (env []string) {
function PrefixLines (line 188) | func PrefixLines(s string, prefix string) string {
function Indent (line 197) | func Indent(s string) string {
function WaitForListen (line 202) | func WaitForListen(u *url.URL, timeout time.Duration) error {
function IsListening (line 224) | func IsListening(u *url.URL) bool {
function ExitStatus (line 235) | func ExitStatus(cmd *exec.Cmd, err error) string {
function StringsContains (line 253) | func StringsContains(list []string, s string) bool {
function BasePath (line 264) | func BasePath(s string) string {
function LogPad (line 269) | func LogPad(msg string, v ...interface{}) {
function Log (line 275) | func Log(msg string, v ...interface{}) {
function LogClear (line 280) | func LogClear(msg string, v ...interface{}) {
function LogTitle (line 287) | func LogTitle(msg string, v ...interface{}) {
function LogName (line 292) | func LogName(name, msg string, v ...interface{}) {
function LogListItem (line 297) | func LogListItem(msg string, v ...interface{}) {
function ToFloat (line 302) | func ToFloat(v interface{}) float64 {
function Milliseconds (line 334) | func Milliseconds(d time.Duration) int {
function MillisecondsSince (line 339) | func MillisecondsSince(t time.Time) int {
function ParseDuration (line 344) | func ParseDuration(s string) (d time.Duration, err error) {
function Md5 (line 372) | func Md5(s string) string {
function Domain (line 379) | func Domain(s string) string {
function CertDomainNames (line 390) | func CertDomainNames(s string) []string {
function IsWildcardDomain (line 401) | func IsWildcardDomain(s string) bool {
function WildcardMatches (line 407) | func WildcardMatches(wildcard, domain string) bool {
function RemoveSubdomains (line 418) | func RemoveSubdomains(s string, n int) string {
function ParseSections (line 424) | func ParseSections(r io.Reader) (sections []string, err error) {
function UniqueStrings (line 440) | func UniqueStrings(s []string) (v []string) {
function IsCI (line 453) | func IsCI() bool {
function EncodeAlias (line 459) | func EncodeAlias(s string) string {
function DecodeAlias (line 465) | func DecodeAlias(s string) string {
function DateSuffix (line 472) | func DateSuffix(t time.Time) string {
function StripLerna (line 487) | func StripLerna(s string) string {
function FixMultipleSetCookie (line 498) | func FixMultipleSetCookie(h http.Header) {
function BinaryCase (line 513) | func BinaryCase(s string, n int) string {
FILE: internal/util/util_test.go
function TestExitStatus (line 13) | func TestExitStatus(t *testing.T) {
function TestParseDuration (line 33) | func TestParseDuration(t *testing.T) {
function TestDomain (line 79) | func TestDomain(t *testing.T) {
function TestCertDomainNames (line 89) | func TestCertDomainNames(t *testing.T) {
function TestWildcardMatches (line 95) | func TestWildcardMatches(t *testing.T) {
function TestParseSections (line 102) | func TestParseSections(t *testing.T) {
function TestEncodeAlias (line 120) | func TestEncodeAlias(t *testing.T) {
function TestDecodeAlias (line 124) | func TestDecodeAlias(t *testing.T) {
function TestFixMultipleSetCookie (line 128) | func TestFixMultipleSetCookie(t *testing.T) {
function TestBinaryCase (line 140) | func TestBinaryCase(t *testing.T) {
FILE: internal/validate/validate.go
function RequiredString (line 12) | func RequiredString(s string) error {
function RequiredStrings (line 21) | func RequiredStrings(s []string) error {
function MinStrings (line 32) | func MinStrings(s []string, n int) error {
function Name (line 48) | func Name(s string) error {
function Stage (line 60) | func Stage(s string) error {
function List (line 69) | func List(s string, list []string) error {
function Lists (line 80) | func Lists(vals, list []string) error {
FILE: internal/zip/zip.go
function Build (line 29) | func Build(dir string) (io.ReadCloser, *archive.Stats, error) {
function read (line 68) | func read(path string) (io.ReadCloser, error) {
FILE: internal/zip/zip_test.go
function TestBuild (line 17) | func TestBuild(t *testing.T) {
FILE: platform.go
type LogsConfig (line 11) | type LogsConfig struct
type Logs (line 33) | type Logs interface
type Domains (line 39) | type Domains interface
type Deploy (line 47) | type Deploy struct
type Platform (line 57) | type Platform interface
type Pruner (line 92) | type Pruner interface
type Runtime (line 99) | type Runtime interface
type Zipper (line 105) | type Zipper interface
type Domain (line 110) | type Domain struct
type DomainContact (line 119) | type DomainContact struct
FILE: platform/aws/cost/cost.go
function Requests (line 64) | func Requests(n int) float64 {
function Rate (line 69) | func Rate(memory int) float64 {
function Invocations (line 74) | func Invocations(n int) float64 {
function Duration (line 79) | func Duration(ms, memory int) float64 {
FILE: platform/aws/cost/cost_test.go
function TestRequests (line 9) | func TestRequests(t *testing.T) {
function TestRate (line 24) | func TestRate(t *testing.T) {
function TestInvocations (line 40) | func TestInvocations(t *testing.T) {
function TestDuration (line 55) | func TestDuration(t *testing.T) {
FILE: platform/aws/cost/domains.go
function Domain (line 14) | func Domain(domain string) string {
function TLD (line 19) | func TLD(tld string) string {
function init (line 340) | func init() {
FILE: platform/aws/domains/domains.go
type Domains (line 13) | type Domains struct
method List (line 25) | func (d *Domains) List() (v []*up.Domain, err error) {
method Availability (line 46) | func (d *Domains) Availability(domain string) (*up.Domain, error) {
method Suggestions (line 69) | func (d *Domains) Suggestions(domain string) (domains []*up.Domain, er...
method Purchase (line 91) | func (d *Domains) Purchase(domain string, contact up.DomainContact) er...
function New (line 18) | func New() *Domains {
function contactDetails (line 105) | func contactDetails(c up.DomainContact) *r.ContactDetail {
FILE: platform/aws/logs/logs.go
type Logs (line 26) | type Logs struct
method start (line 58) | func (l *Logs) start() {
function New (line 35) | func New(group string, c up.LogsConfig) up.Logs {
function parseQuery (line 115) | func parseQuery(s string) (string, error) {
function skippable (line 129) | func skippable(s string) bool {
FILE: platform/aws/regions/regions.go
function Match (line 75) | func Match(regions []string) (v []string) {
function GetIdByName (line 95) | func GetIdByName(name string) string {
function GetHostedZoneID (line 105) | func GetHostedZoneID(region string) string {
FILE: platform/aws/regions/regions_test.go
function TestMatch (line 9) | func TestMatch(t *testing.T) {
FILE: platform/aws/runtime/runtime.go
type Runtime (line 11) | type Runtime struct
method Init (line 38) | func (r *Runtime) Init(stage string) error {
type Option (line 17) | type Option
function New (line 20) | func New(c *up.Config, options ...Option) *Runtime {
function WithLogger (line 31) | func WithLogger(l log.Interface) Option {
FILE: platform/event/event.go
type Events (line 17) | type Events
method Emit (line 20) | func (e Events) Emit(name string, fields Fields) {
method Time (line 32) | func (e Events) Time(name string, fields Fields) func() {
type Fields (line 54) | type Fields
type Event (line 58) | type Event struct
method Strings (line 64) | func (e *Event) Strings(name string) []string {
method String (line 73) | func (e *Event) String(name string) string {
method Duration (line 82) | func (e *Event) Duration(name string) time.Duration {
method Int64 (line 91) | func (e *Event) Int64(name string) int64 {
method Int (line 100) | func (e *Event) Int(name string) int {
FILE: platform/lambda/lambda.go
constant maxCodeSize (line 50) | maxCodeSize = 250 << 20
type Platform (line 78) | type Platform struct
method Build (line 95) | func (p *Platform) Build() error {
method Zip (line 134) | func (p *Platform) Zip() io.Reader {
method Init (line 139) | func (p *Platform) Init(stage string) error {
method Deploy (line 149) | func (p *Platform) Deploy(d up.Deploy) error {
method Logs (line 191) | func (p *Platform) Logs(c up.LogsConfig) up.Logs {
method Domains (line 197) | func (p *Platform) Domains() up.Domains {
method URL (line 202) | func (p *Platform) URL(region, stage string) (string, error) {
method CreateStack (line 220) | func (p *Platform) CreateStack(region, version string) error {
method DeleteStack (line 240) | func (p *Platform) DeleteStack(region string, wait bool) error {
method ShowStack (line 275) | func (p *Platform) ShowStack(region string) error {
method PlanStack (line 280) | func (p *Platform) PlanStack(region string) error {
method ApplyStack (line 299) | func (p *Platform) ApplyStack(region string) error {
method Exists (line 308) | func (p *Platform) Exists(region string) (bool, error) {
method getAliasVersions (line 328) | func (p *Platform) getAliasVersions(region string) (resources.Versions...
method getAliasVersion (line 368) | func (p *Platform) getAliasVersion(c *lambda.Lambda, stage string) (st...
method getHostedZone (line 382) | func (p *Platform) getHostedZone() (zones []*route53.HostedZone, err e...
method createCerts (line 404) | func (p *Platform) createCerts() error {
method deploy (line 486) | func (p *Platform) deploy(region string, d up.Deploy) (version string,...
method createFunction (line 529) | func (p *Platform) createFunction(c *lambda.Lambda, a *apigateway.APIG...
method updateFunction (line 591) | func (p *Platform) updateFunction(c *lambda.Lambda, a *apigateway.APIG...
method isPending (line 674) | func (p *Platform) isPending(c *lambda.Lambda) error {
method vpc (line 706) | func (p *Platform) vpc() *lambda.VpcConfig {
method alias (line 719) | func (p *Platform) alias(c *lambda.Lambda, alias, version string) error {
method deleteFunction (line 741) | func (p *Platform) deleteFunction(region string) error {
method loadEnvironment (line 753) | func (p *Platform) loadEnvironment(d up.Deploy) (*lambda.Environment, ...
method createRole (line 764) | func (p *Platform) createRole() error {
method updateRole (line 820) | func (p *Platform) updateRole(c *iam.IAM) error {
method setRoleARN (line 839) | func (p *Platform) setRoleARN(arn string) {
method roleName (line 845) | func (p *Platform) roleName() string {
method deleteRole (line 850) | func (p *Platform) deleteRole(region string) error {
method createBucket (line 881) | func (p *Platform) createBucket(region string) error {
method deleteBucketObjects (line 894) | func (p *Platform) deleteBucketObjects(region string) error {
method getAPI (line 924) | func (p *Platform) getAPI(c *apigateway.APIGateway) (api *apigateway.R...
method injectProxy (line 945) | func (p *Platform) injectProxy() error {
method removeProxy (line 960) | func (p *Platform) removeProxy() error {
method getS3Key (line 968) | func (p *Platform) getS3Key(stage string) string {
method getS3BucketName (line 975) | func (p *Platform) getS3BucketName(region string) string {
method getAccountID (line 981) | func (p *Platform) getAccountID() string {
method functionPolicy (line 986) | func (p *Platform) functionPolicy() (string, error) {
function New (line 86) | func New(c *up.Config, events event.Events) *Platform {
function isCreatingRole (line 1004) | func isCreatingRole(err error) bool {
function getCerts (line 1009) | func getCerts(a *acm.ACM) (certs []*acm.CertificateDetail, err error) {
function getCert (line 1045) | func getCert(certs []*acm.CertificateDetail, domain string) string {
FILE: platform/lambda/lambda_test.go
function TestGetCert (line 14) | func TestGetCert(t *testing.T) {
function TestCreateRole (line 62) | func TestCreateRole(t *testing.T) {
function TestDeleteRole (line 75) | func TestDeleteRole(t *testing.T) {
FILE: platform/lambda/metrics.go
type stat (line 18) | type stat struct
method Value (line 27) | func (s *stat) Value() int {
method ShowMetrics (line 61) | func (p *Platform) ShowMetrics(region, stage string, start time.Time) er...
FILE: platform/lambda/prune.go
method Prune (line 16) | func (p *Platform) Prune(region, stage string, versions int) error {
FILE: platform/lambda/reporter/reporter.go
function ResourceType (line 23) | func ResourceType(s string) string {
FILE: platform/lambda/stack/resources/resources.go
type Map (line 14) | type Map
type Versions (line 17) | type Versions
type Config (line 20) | type Config struct
function New (line 35) | func New(c *Config) map[string]interface{} {
function ref (line 45) | func ref(id string) Map {
function get (line 52) | func get(name, value string) Map {
function join (line 62) | func join(delim string, s ...interface{}) Map {
function stageVariable (line 72) | func stageVariable(name string) string {
function lambdaArn (line 77) | func lambdaArn(name string) Map {
function lambdaArnQualifier (line 82) | func lambdaArnQualifier(name, qualifier string) Map {
function getZone (line 87) | func getZone(c *Config, domain string) *route53.HostedZone {
function dnsZone (line 97) | func dnsZone(c *Config, m Map, domain string) interface{} {
function api (line 124) | func api(c *Config, m Map) {
function stages (line 182) | func stages(c *Config, m Map) {
function stage (line 191) | func stage(c *Config, s *config.Stage, m Map) {
function stageAlias (line 199) | func stageAlias(c *Config, s *config.Stage, m Map) string {
function stagePermissions (line 221) | func stagePermissions(c *Config, s *config.Stage, m Map, aliasID string) {
function stageDeployment (line 245) | func stageDeployment(c *Config, s *config.Stage, m Map, aliasID string) ...
function stageDomain (line 266) | func stageDomain(c *Config, s *config.Stage, m Map, deploymentID string) {
function stagePathMapping (line 289) | func stagePathMapping(c *Config, s *config.Stage, m Map, deploymentID, d...
function stageDNSRecord (line 305) | func stageDNSRecord(c *Config, s *config.Stage, m Map, domainID string) {
function dns (line 332) | func dns(c *Config, m Map) {
function resources (line 355) | func resources(c *Config) Map {
function parameters (line 363) | func parameters(c *Config) Map {
function outputs (line 377) | func outputs(c *Config) Map {
FILE: platform/lambda/stack/resources/resources_test.go
function keys (line 14) | func keys(m Map) (v []string) {
function getResource (line 22) | func getResource(c *Config, name string) Map {
function dump (line 36) | func dump(c *Config, name string) {
function Example_api (line 45) | func Example_api() {
function Example_apiRootMethod (line 68) | func Example_apiRootMethod() {
function Example_apiProxyResource (line 140) | func Example_apiProxyResource() {
function Example_apiProxyMethod (line 166) | func Example_apiProxyMethod() {
function Example_stageAlias (line 235) | func Example_stageAlias() {
function Example_stagePermission (line 265) | func Example_stagePermission() {
function Example_stageDeployment (line 341) | func Example_stageDeployment() {
function Example_stageDomain (line 379) | func Example_stageDomain() {
function Example_stagePathMapping (line 407) | func Example_stagePathMapping() {
function Example_stageDNSZone (line 442) | func Example_stageDNSZone() {
function Example_stageDNSZoneRecord (line 470) | func Example_stageDNSZoneRecord() {
function Example_dnsZone (line 510) | func Example_dnsZone() {
function Example_dnsZoneRecord (line 536) | func Example_dnsZoneRecord() {
FILE: platform/lambda/stack/stack.go
type Stack (line 37) | type Stack struct
method template (line 62) | func (s *Stack) template(versions resources.Versions) Map {
method Create (line 71) | func (s *Stack) Create(versions resources.Versions) error {
method Delete (line 121) | func (s *Stack) Delete(versions resources.Versions, wait bool) error {
method Show (line 141) | func (s *Stack) Show() error {
method Plan (line 208) | func (s *Stack) Plan(versions resources.Versions) error {
method Apply (line 304) | func (s *Stack) Apply() error {
method report (line 343) | func (s *Stack) report(states map[string]Status) error {
method showVersion (line 399) | func (s *Stack) showVersion(stage *config.Stage) error {
method showCloudfront (line 418) | func (s *Stack) showCloudfront(stage *config.Stage) error {
method showNameservers (line 444) | func (s *Stack) showNameservers(stage *config.Stage) error {
method getStack (line 489) | func (s *Stack) getStack() (*cloudformation.Stack, error) {
method getLatestEvents (line 503) | func (s *Stack) getLatestEvents() (v []*cloudformation.StackEvent, err...
method getFailedEvents (line 525) | func (s *Stack) getFailedEvents() (v []*cloudformation.StackEvent, err...
method getEvents (line 541) | func (s *Stack) getEvents() (events []*cloudformation.StackEvent, err ...
function New (line 48) | func New(c *up.Config, events event.Events, zones []*route53.HostedZone,...
function resourceStateFromTemplate (line 567) | func resourceStateFromTemplate(t Map, s Status) map[string]Status {
function resourceStateFromChanges (line 581) | func resourceStateFromChanges(changes []*cloudformation.Change) map[stri...
function resourcesCompleted (line 615) | func resourcesCompleted(resources []*cloudformation.StackResource, state...
function isNotFound (line 653) | func isNotFound(err error) bool {
FILE: platform/lambda/stack/stack_test.go
function TestResourcesCompleted (line 11) | func TestResourcesCompleted(t *testing.T) {
FILE: platform/lambda/stack/status.go
type State (line 40) | type State
constant Success (line 44) | Success State = iota
constant Pending (line 45) | Pending
constant Failure (line 46) | Failure
type Status (line 50) | type Status
method String (line 83) | func (s Status) String() string {
method IsDone (line 88) | func (s Status) IsDone() bool {
method Color (line 93) | func (s Status) Color(v string) string {
method State (line 107) | func (s Status) State() State {
constant Unknown (line 54) | Unknown Status = ""
constant CreateInProgress (line 56) | CreateInProgress = "CREATE_IN_PROGRESS"
constant CreateFailed (line 57) | CreateFailed = "CREATE_FAILED"
constant CreateComplete (line 58) | CreateComplete = "CREATE_COMPLETE"
constant CreatePending (line 59) | CreatePending = "CREATE_PENDING"
constant DeleteInProgress (line 61) | DeleteInProgress = "DELETE_IN_PROGRESS"
constant DeleteFailed (line 62) | DeleteFailed = "DELETE_FAILED"
constant DeleteComplete (line 63) | DeleteComplete = "DELETE_COMPLETE"
constant DeleteSkipped (line 64) | DeleteSkipped = "DELETE_SKIPPED"
constant UpdateInProgress (line 66) | UpdateInProgress = "UPDATE_IN_PROGRESS"
constant UpdateFailed (line 67) | UpdateFailed = "UPDATE_FAILED"
constant UpdateComplete (line 68) | UpdateComplete = "UPDATE_COMPLETE"
constant UpdateRollbackInProgress (line 70) | UpdateRollbackInProgress = "UPDATE_ROLLBACK_IN_PROGRESS"
constant UpdateRollbackComplete (line 71) | UpdateRollbackComplete = "UPDATE_ROLLBACK_COMPLETE"
constant UpdateRollbackCompleteCleanup (line 72) | UpdateRollbackCompleteCleanup = "UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PRO...
constant UpdateCompleteCleanup (line 73) | UpdateCompleteCleanup = "UPDATE_COMPLETE_CLEANUP_IN_PROGRESS"
constant RollbackInProgress (line 75) | RollbackInProgress = "ROLLBACK_IN_PROGRESS"
constant RollbackFailed (line 76) | RollbackFailed = "ROLLBACK_FAILED"
constant RollbackComplete (line 77) | RollbackComplete = "ROLLBACK_COMPLETE"
constant Failed (line 79) | Failed = "FAILED"
FILE: platform/lambda/stack/status_test.go
function TestStatus_String (line 9) | func TestStatus_String(t *testing.T) {
function TestStatus_State (line 16) | func TestStatus_State(t *testing.T) {
function TestStatus_IsDone (line 23) | func TestStatus_IsDone(t *testing.T) {
FILE: reporter/discard/discard.go
function Report (line 7) | func Report(events <-chan *event.Event) {
FILE: reporter/plain/plain.go
function Report (line 14) | func Report(events <-chan *event.Event) {
type reporter (line 23) | type reporter struct
method complete (line 28) | func (r *reporter) complete(name, value string, d time.Duration) {
method log (line 34) | func (r *reporter) log(name, value string) {
method error (line 39) | func (r *reporter) error(name, value string) {
method Start (line 44) | func (r *reporter) Start() {
FILE: reporter/text/text.go
function Report (line 28) | func Report(events <-chan *event.Event) {
type reporter (line 38) | type reporter struct
method spin (line 49) | func (r *reporter) spin() {
method clear (line 56) | func (r *reporter) clear() {
method pending (line 63) | func (r *reporter) pending(name, value string) {
method complete (line 71) | func (r *reporter) complete(name, value string, d time.Duration) {
method completeWithoutDuration (line 80) | func (r *reporter) completeWithoutDuration(name, value string) {
method log (line 88) | func (r *reporter) log(name, value string) {
method error (line 93) | func (r *reporter) error(name, value string) {
method Start (line 98) | func (r *reporter) Start() {
function currency (line 261) | func currency(n float64) string {
function countEventsByStatus (line 266) | func countEventsByStatus(events []*cloudformation.StackEvent, desired st...
function countEventsComplete (line 283) | func countEventsComplete(events []*cloudformation.StackEvent) (n int) {
function actionColor (line 300) | func actionColor(s string) colors.Func {
FILE: up.go
type Project (line 30) | type Project struct
method WithPlatform (line 45) | func (p *Project) WithPlatform(platform Platform) *Project {
method RunHook (line 51) | func (p *Project) RunHook(name string) error {
method RunHooks (line 82) | func (p *Project) RunHooks(names ...string) error {
method Build (line 92) | func (p *Project) Build(hooks bool) error {
method Deploy (line 113) | func (p *Project) Deploy(d Deploy) error {
method deploy (line 137) | func (p *Project) deploy(d Deploy) error {
method Zip (line 150) | func (p *Project) Zip() (io.Reader, error) {
method Init (line 160) | func (p *Project) Init(stage string) error {
method CreateStack (line 170) | func (p *Project) CreateStack(region, version string) error {
method DeleteStack (line 180) | func (p *Project) DeleteStack(region string, wait bool) error {
method ShowStack (line 189) | func (p *Project) ShowStack(region string) error {
method ShowMetrics (line 198) | func (p *Project) ShowMetrics(region, stage string, start time.Time) e...
method PlanStack (line 209) | func (p *Project) PlanStack(region string) error {
method ApplyStack (line 218) | func (p *Project) ApplyStack(region string) error {
method Prune (line 227) | func (p *Project) Prune(region, stage string, versions int) error {
function New (line 37) | func New(c *Config, events event.Events) *Project {
Condensed preview — 230 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (729K chars).
[
{
"path": ".gitattributes",
"chars": 69,
"preview": "internal/proxy/bin/bin_assets.go filter=lfs diff=lfs merge=lfs -text\n"
},
{
"path": ".github/FUNDING.yml",
"chars": 10,
"preview": "github: tj"
},
{
"path": ".github/ISSUE_TEMPLATE.md",
"chars": 421,
"preview": "## Prerequisites\n\n* [ ] I am running the latest version. (`up upgrade`)\n* [ ] I searched to see if the issue already exi"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 481,
"preview": "Open an issue and discuss changes before spending time on them, unless the change is trivial or an issue already exists."
},
{
"path": ".gitignore",
"chars": 160,
"preview": ".envrc\nnode_modules/\n.shards/\nlib\nvendor/\ntesting\nup-proxy\n!cmd/up-proxy\ndist\n.idea\n.vscode\n.DS_Store\ninternal/proxy/bin"
},
{
"path": ".goreleaser.yml",
"chars": 294,
"preview": "build:\n main: cmd/up/main.go\n binary: up\n goos:\n - darwin\n - linux\n - windows\n - freebsd\n - netbsd\n "
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 3207,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
},
{
"path": "CONTRIBUTING.md",
"chars": 2476,
"preview": "# Contributing\n\nBefore contributing to Up you'll need a few things:\n\n- Install [Golang 1.11](https://golang.org/dl/) for"
},
{
"path": "History.md",
"chars": 29694,
"preview": "\nv1.7.1 / 2021-09-27\n===================\n\n * fix Lambda state issue by waiting for an Active state. Closes #833\n\nv1.7.0"
},
{
"path": "LICENSE",
"chars": 1097,
"preview": "The MIT License\n\nCopyright (c) 2020 TJ Holowaychuk tj@tjholowaychuk.com\n\nPermission is hereby granted, free of charge, t"
},
{
"path": "Makefile",
"chars": 1171,
"preview": "\nGO ?= go\n\n# Build all files.\nbuild:\n\t@echo \"==> Building\"\n\t@$(GO) generate ./...\n.PHONY: build\n\n# Install from source.\n"
},
{
"path": "Readme.md",
"chars": 2621,
"preview": "\n\nUp deploys infinitely scalable serverless apps, APIs, and static websites in seconds, so you can "
},
{
"path": "cmd/up/main.go",
"chars": 1743,
"preview": "package main\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"runtime\"\n\n\t\"github.com/stripe/stripe-go\"\n\t\"github.com/tj/go/env\"\n\t\"github.com/t"
},
{
"path": "cmd/up-proxy/main.go",
"chars": 1396,
"preview": "package main\n\nimport (\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/apex/go-apex\"\n\t\"github.com/apex/log\"\n\t\"github.com/apex/log/handlers/j"
},
{
"path": "config/backoff.go",
"chars": 912,
"preview": "package config\n\nimport (\n\t\"time\"\n\t\n\t\"github.com/tj/backoff\"\n)\n\n// Backoff config.\ntype Backoff struct {\n\t// Min time in "
},
{
"path": "config/backoff_test.go",
"chars": 498,
"preview": "package config\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/tj/assert\"\n)\n\nfunc TestBackoff_Default(t *testing.T) {\n\ta := &"
},
{
"path": "config/config.go",
"chars": 6102,
"preview": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"os\"\n\n\t\"github.com/apex/log\"\n\t\"github.com/pkg/errors\"\n\n\t\"github."
},
{
"path": "config/config_test.go",
"chars": 7386,
"preview": "package config\n\nimport (\n\t\"io/ioutil\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/tj/assert\"\n)\n\nfunc TestConfig_Name(t *testing.T) {\n"
},
{
"path": "config/cors.go",
"chars": 1611,
"preview": "package config\n\n// CORS configuration.\ntype CORS struct {\n\t// AllowedOrigins is a list of origins a cross-domain request"
},
{
"path": "config/dns.go",
"chars": 2326,
"preview": "package config\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/apex/up/internal/validate\"\n\t\"github.com/pkg/errors\"\n)\n\n// record"
},
{
"path": "config/dns_test.go",
"chars": 3137,
"preview": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"log\"\n\t\"os\"\n\t\"sort\"\n\t\"testing\"\n\n\t\"github.com/tj/assert\"\n)\n\nfunc ExampleDNS() "
},
{
"path": "config/doc.go",
"chars": 118,
"preview": "// Package config provides configuration structures,\n// validation, and defaulting for up.json config.\npackage config\n"
},
{
"path": "config/duration.go",
"chars": 782,
"preview": "package config\n\nimport (\n\t\"bytes\"\n\t\"strconv\"\n\t\"time\"\n)\n\n// Duration may be specified as numerical seconds or\n// as a dur"
},
{
"path": "config/duration_test.go",
"chars": 670,
"preview": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/tj/assert\"\n)\n\nfunc TestDuration_UnmarshalJSON"
},
{
"path": "config/environment.go",
"chars": 77,
"preview": "package config\n\n// Environment variables.\ntype Environment map[string]string\n"
},
{
"path": "config/errorpages.go",
"chars": 404,
"preview": "package config\n\n// ErrorPages configuration.\ntype ErrorPages struct {\n\t// Enable error pages.\n\tEnable bool `json:\"enable"
},
{
"path": "config/errorpages_test.go",
"chars": 201,
"preview": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/tj/assert\"\n)\n\nfunc TestErrorPages(t *testing.T) {\n\tc := &ErrorPages{}\n"
},
{
"path": "config/hooks.go",
"chars": 1586,
"preview": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n)\n\n// Hook is one or more commands.\ntype Hook []string\n\n// Hooks for"
},
{
"path": "config/hooks_test.go",
"chars": 1239,
"preview": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/tj/assert\"\n)\n\nfunc TestHook(t *testing.T) {\n\tt.Run(\"m"
},
{
"path": "config/lambda.go",
"chars": 1744,
"preview": "package config\n\n// defaultRuntime is the default runtime.\nvar defaultRuntime = \"nodejs10.x\"\n\n// defaultPolicy is the def"
},
{
"path": "config/lambda_test.go",
"chars": 819,
"preview": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/tj/assert\"\n)\n\nfunc TestLambda(t *testing.T) {\n\tc := &Lambda{}\n\tassert."
},
{
"path": "config/logs.go",
"chars": 410,
"preview": "package config\n\n// Logs configuration.\ntype Logs struct {\n\t// Disable json log output.\n\tDisable bool `json:\"disable\"`\n\n\t"
},
{
"path": "config/relay.go",
"chars": 1269,
"preview": "package config\n\nimport (\n\t\"github.com/pkg/errors\"\n)\n\n// Relay config.\ntype Relay struct {\n\t// Command run to start your "
},
{
"path": "config/runtimes.go",
"chars": 5130,
"preview": "package config\n\nimport (\n\t\"os\"\n\n\t\"github.com/apex/up/internal/util\"\n\t\"github.com/pkg/errors\"\n)\n\n// Runtime is an app run"
},
{
"path": "config/stages.go",
"chars": 3102,
"preview": "package config\n\nimport (\n\t\"sort\"\n\n\t\"github.com/apex/up/internal/validate\"\n\t\"github.com/pkg/errors\"\n)\n\n// defaultStages i"
},
{
"path": "config/stages_test.go",
"chars": 3583,
"preview": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/tj/assert\"\n)\n\nfunc TestStage_Override(t *testing.T) {\n\tc, err := Parse"
},
{
"path": "config/static.go",
"chars": 551,
"preview": "package config\n\nimport (\n\t\"os\"\n\n\t\"github.com/pkg/errors\"\n)\n\n// Static configuration.\ntype Static struct {\n\t// Dir contai"
},
{
"path": "config/static_test.go",
"chars": 391,
"preview": "package config\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/tj/assert\"\n)\n\nfunc TestStatic(t *testing.T) {\n\tcwd, _ := os.Getw"
},
{
"path": "docs/00-introduction.md",
"chars": 751,
"preview": "---\ntitle: Introduction\nslug: introduction\n---\n\nUp deploys infinitely scalable serverless apps, APIs, and static website"
},
{
"path": "docs/01-installation.md",
"chars": 920,
"preview": "---\ntitle: Installation\nslug: setup\n---\n\nUp is distributed in a binary form and can be installed manually via the [tarba"
},
{
"path": "docs/02-aws-credentials.md",
"chars": 3057,
"preview": "---\ntitle: AWS Credentials\nslug: credentials\n---\n\nBefore using Up you need to first provide your AWS account credentials"
},
{
"path": "docs/03-getting-started.md",
"chars": 2232,
"preview": "---\ntitle: Getting Started\nslug: getting-started\n---\n\nThe simplest Up application is a single file for the application i"
},
{
"path": "docs/04-configuration.md",
"chars": 23831,
"preview": "---\ntitle: Configuration\nslug: configuration\n---\n\nConfiguration for your app lives in the `up.json` within your project'"
},
{
"path": "docs/05-runtimes.md",
"chars": 1310,
"preview": "---\ntitle: Runtimes\nslug: runtimes\n---\n\nUp supports a number of interpreted languages, and virtually any language which "
},
{
"path": "docs/06-commands.md",
"chars": 17288,
"preview": "---\ntitle: Commands\nslug: commands\n---\n\n\nUp provides the `up` command-line program, used to deploy the app, and manage a"
},
{
"path": "docs/07-guides.md",
"chars": 19064,
"preview": "---\ntitle: Guides\nslug: guides\n---\n\n## Subscribing to Up Pro\n\nUp Pro provides additional features which are not availabl"
},
{
"path": "docs/08-troubleshooting.md",
"chars": 2614,
"preview": "---\ntitle: Troubleshooting\nmenu: Help\nslug: troubleshooting\n---\n\nThis section contains self-help troubleshooting informa"
},
{
"path": "docs/09-faq.md",
"chars": 5578,
"preview": "---\ntitle: Questions\nmenu: FAQ\nslug: faq\n---\n\n<details>\n <summary>Is this a hosted service?</summary>\n <p>There are cu"
},
{
"path": "docs/10-links.md",
"chars": 1000,
"preview": "---\ntitle: Links\nslug: links\n---\n\nLinks to helpful resources such as the Up community, changelog, examples, articles, vi"
},
{
"path": "go.mod",
"chars": 4019,
"preview": "module github.com/apex/up\n\nrequire (\n\tgithub.com/NYTimes/gziphandler v0.0.0-20170916004738-97ae7fbaf816\n\tgithub.com/alec"
},
{
"path": "go.sum",
"chars": 23344,
"preview": "github.com/NYTimes/gziphandler v0.0.0-20170916004738-97ae7fbaf816 h1:wBaYm5ra+p6jEKkg9G3tCimdOwp/dcCPSfkePrWoc6w=\ngithub"
},
{
"path": "handler/handler.go",
"chars": 1638,
"preview": "// Package handler provides what is essentially the core of Up's\n// reverse proxy, complete with all middleware for hand"
},
{
"path": "handler/handler_test.go",
"chars": 5232,
"preview": "package handler\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/apex/up\"\n\t\"github.com/tj/asser"
},
{
"path": "handler/testdata/node/app.js",
"chars": 278,
"preview": "const http = require('http')\nconst port = process.env.PORT\n\nhttp.createServer((req, res) => {\n res.setHeader('X-Foo', '"
},
{
"path": "handler/testdata/node/up.json",
"chars": 57,
"preview": "{\n \"name\": \"app\",\n \"logs\": {\n \"enable\": false\n }\n}\n"
},
{
"path": "handler/testdata/node-pkg/app.js",
"chars": 134,
"preview": "const http = require('http')\nconst { PORT } = process.env\n\nhttp.createServer((req, res) => {\n res.end('Hello World')\n})"
},
{
"path": "handler/testdata/node-pkg/package.json",
"chars": 26,
"preview": "{\n \"name\": \"something\"\n}\n"
},
{
"path": "handler/testdata/node-pkg/up.json",
"chars": 57,
"preview": "{\n \"name\": \"app\",\n \"logs\": {\n \"enable\": false\n }\n}\n"
},
{
"path": "handler/testdata/node-pkg-start/index.js",
"chars": 134,
"preview": "const http = require('http')\nconst { PORT } = process.env\n\nhttp.createServer((req, res) => {\n res.end('Hello World')\n})"
},
{
"path": "handler/testdata/node-pkg-start/package.json",
"chars": 72,
"preview": "{\n \"name\": \"something\",\n \"scripts\": {\n \"start\": \"node index\"\n }\n}\n"
},
{
"path": "handler/testdata/node-pkg-start/up.json",
"chars": 57,
"preview": "{\n \"name\": \"app\",\n \"logs\": {\n \"enable\": false\n }\n}\n"
},
{
"path": "handler/testdata/spa/app.js",
"chars": 7,
"preview": "app js\n"
},
{
"path": "handler/testdata/spa/css/bar.css",
"chars": 8,
"preview": "bar css\n"
},
{
"path": "handler/testdata/spa/css/foo.css",
"chars": 8,
"preview": "foo css\n"
},
{
"path": "handler/testdata/spa/index.html",
"chars": 6,
"preview": "Index\n"
},
{
"path": "handler/testdata/spa/up.json",
"chars": 160,
"preview": "{\n \"name\": \"app\",\n \"type\": \"static\",\n \"logs\": {\n \"enable\": false\n },\n \"redirects\": {\n \"/*\": {\n \"location"
},
{
"path": "handler/testdata/static/index.html",
"chars": 12,
"preview": "Hello World\n"
},
{
"path": "handler/testdata/static/style.css",
"chars": 30,
"preview": "body { background: whatever }\n"
},
{
"path": "handler/testdata/static/up.json",
"chars": 77,
"preview": "{\n \"name\": \"app\",\n \"type\": \"static\",\n \"logs\": {\n \"enable\": false\n }\n}\n"
},
{
"path": "handler/testdata/static-redirects/help/ping/alerts/index.html",
"chars": 14,
"preview": "Alerting docs\n"
},
{
"path": "handler/testdata/static-redirects/index.html",
"chars": 12,
"preview": "Hello World\n"
},
{
"path": "handler/testdata/static-redirects/up.json",
"chars": 206,
"preview": "{\n \"name\": \"app\",\n \"type\": \"static\",\n \"logs\": {\n \"enable\": false\n },\n \"redirects\": {\n \"/docs/:product/guides/"
},
{
"path": "handler/testdata/static-rewrites/help/ping/alerts.html",
"chars": 14,
"preview": "Alerting docs\n"
},
{
"path": "handler/testdata/static-rewrites/index.html",
"chars": 12,
"preview": "Hello World\n"
},
{
"path": "handler/testdata/static-rewrites/up.json",
"chars": 211,
"preview": "{\n \"name\": \"app\",\n \"type\": \"static\",\n \"logs\": {\n \"enable\": false\n },\n \"redirects\": {\n \"/docs/:product/guides/"
},
{
"path": "http/cors/cors.go",
"chars": 683,
"preview": "// Package cors provides CORS support.\npackage cors\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/rs/cors\"\n\n\t\"github.com/apex/up\"\n"
},
{
"path": "http/cors/cors_test.go",
"chars": 3545,
"preview": "package cors\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/apex/up\"\n\t\"github.com/tj/assert\""
},
{
"path": "http/errorpages/errorpages.go",
"chars": 2263,
"preview": "// Package errorpages provides default and customizable\n// error pages, via error.html, 5xx.html, or 500.html\n// for exa"
},
{
"path": "http/errorpages/errorpages_test.go",
"chars": 6340,
"preview": "package errorpages\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/tj/assert\"\n\n\t\""
},
{
"path": "http/errorpages/testdata/defaults/index.html",
"chars": 11,
"preview": "Index HTML\n"
},
{
"path": "http/errorpages/testdata/defaults/up.json",
"chars": 20,
"preview": "{\n \"name\": \"app\"\n}\n"
},
{
"path": "http/errorpages/testdata/templates/404.html",
"chars": 24,
"preview": "Sorry! Can't find that.\n"
},
{
"path": "http/errorpages/testdata/templates/5xx.html",
"chars": 34,
"preview": "{{.StatusCode}} – {{.StatusText}}\n"
},
{
"path": "http/errorpages/testdata/templates/index.html",
"chars": 11,
"preview": "Index HTML\n"
},
{
"path": "http/errorpages/testdata/templates/up.json",
"chars": 20,
"preview": "{\n \"name\": \"app\"\n}\n"
},
{
"path": "http/gzip/gzip.go",
"chars": 265,
"preview": "// Package gzip provides gzip compression support.\npackage gzip\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/NYTimes/gziphandler\""
},
{
"path": "http/gzip/gzip_test.go",
"chars": 1510,
"preview": "package gzip\n\nimport (\n\t\"compress/gzip\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"gi"
},
{
"path": "http/headers/headers.go",
"chars": 1657,
"preview": "// Package headers provides header injection support.\npackage headers\n\nimport (\n\t\"net/http\"\n\t\"os\"\n\n\t\"github.com/apex/log"
},
{
"path": "http/headers/headers_test.go",
"chars": 1293,
"preview": "package headers\n\nimport (\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/tj/assert\"\n\t\"github.com/apex/up\"\n\n\t\"github"
},
{
"path": "http/headers/testdata/_headers",
"chars": 21,
"preview": "/*.css\n X-Type: css\n"
},
{
"path": "http/headers/testdata/index.html",
"chars": 11,
"preview": "Index HTML\n"
},
{
"path": "http/headers/testdata/style.css",
"chars": 20,
"preview": "body { color: red }\n"
},
{
"path": "http/headers/testdata/up.json",
"chars": 20,
"preview": "{\n \"name\": \"app\"\n}\n"
},
{
"path": "http/inject/inject.go",
"chars": 1341,
"preview": "// Package inject provides script and style injection.\npackage inject\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\t\""
},
{
"path": "http/inject/inject_test.go",
"chars": 2571,
"preview": "package inject\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/apex/up\"\n\t\"github.com/tj/"
},
{
"path": "http/inject/testdata/404.html",
"chars": 17,
"preview": "<p>Not Found</p>\n"
},
{
"path": "http/inject/testdata/index.html",
"chars": 97,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n </head>\n <body>\n\n </body>\n</html>\n"
},
{
"path": "http/inject/testdata/style.css",
"chars": 7,
"preview": "body{}\n"
},
{
"path": "http/inject/testdata/up.json",
"chars": 20,
"preview": "{\n \"name\": \"app\"\n}\n"
},
{
"path": "http/logs/logs.go",
"chars": 2114,
"preview": "// Package logs provides HTTP request and response logging.\npackage logs\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"git"
},
{
"path": "http/logs/logs_test.go",
"chars": 1137,
"preview": "package logs\n\nimport (\n\t\"bytes\"\n\t\"log\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/tj/assert\"\n\n\t\"github.com/apex/up\"\n\t"
},
{
"path": "http/logs/testdata/index.html",
"chars": 11,
"preview": "Index HTML\n"
},
{
"path": "http/logs/testdata/up.json",
"chars": 20,
"preview": "{\n \"name\": \"api\"\n}\n"
},
{
"path": "http/poweredby/poweredby.go",
"chars": 311,
"preview": "// Package poweredby provides nothing :).\npackage poweredby\n\nimport (\n\t\"net/http\"\n)\n\n// New powered-by middleware.\nfunc "
},
{
"path": "http/poweredby/poweredby_test.go",
"chars": 636,
"preview": "package poweredby\n\nimport (\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/tj/assert\"\n\t\"github.com/apex/up\"\n\n\t\"github.com"
},
{
"path": "http/poweredby/testdata/index.html",
"chars": 11,
"preview": "Index HTML\n"
},
{
"path": "http/poweredby/testdata/up.json",
"chars": 20,
"preview": "{\n \"name\": \"app\"\n}\n"
},
{
"path": "http/redirects/redirects.go",
"chars": 2485,
"preview": "// Package redirects provides redirection and URL rewriting.\npackage redirects\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.co"
},
{
"path": "http/redirects/redirects_test.go",
"chars": 5040,
"preview": "package redirects\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/apex/up\"\n\t"
},
{
"path": "http/relay/relay.go",
"chars": 5391,
"preview": "// Package relay provides a reverse proxy which\n// relays requests to your \"vanilla\" HTTP server,\n// and supports crash "
},
{
"path": "http/relay/relay_test.go",
"chars": 3978,
"preview": "package relay\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/tj/assert\"\n\n\t"
},
{
"path": "http/relay/testdata/basic/app.js",
"chars": 1003,
"preview": "const http = require('http');\nconst url = require('url');\nconst qs = require('querystring');\nconst port = process.env.PO"
},
{
"path": "http/relay/testdata/basic/up.json",
"chars": 20,
"preview": "{\n \"name\": \"app\"\n}\n"
},
{
"path": "http/relay/testdata/node/package.json",
"chars": 50,
"preview": "{\n \"scripts\": {\n \"start\": \"node server\"\n }\n}\n"
},
{
"path": "http/relay/testdata/node/server.js",
"chars": 142,
"preview": "const http = require('http')\nconst port = parseInt(process.env.PORT, 10)\n\nhttp.createServer((req, res) => {\n res.end('N"
},
{
"path": "http/relay/testdata/node/up.json",
"chars": 20,
"preview": "{\n \"name\": \"app\"\n}\n"
},
{
"path": "http/robots/robots.go",
"chars": 431,
"preview": "// Package robots provides a way of dealing with robots exclusion protocol\npackage robots\n\nimport (\n\t\"net/http\"\n\t\"os\"\n\n\t"
},
{
"path": "http/robots/robots_test.go",
"chars": 1216,
"preview": "package robots\n\nimport (\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/apex/up\"\n\t\"github.com/tj/assert\"\n\n\t\"github."
},
{
"path": "http/robots/testdata/index.html",
"chars": 11,
"preview": "Index HTML\n"
},
{
"path": "http/robots/testdata/up.json",
"chars": 20,
"preview": "{\n \"name\": \"app\"\n}\n"
},
{
"path": "http/static/static.go",
"chars": 1293,
"preview": "// Package static provides static file serving with HTTP cache support.\npackage static\n\nimport (\n\t\"net/http\"\n\t\"os\"\n\t\"pat"
},
{
"path": "http/static/static_test.go",
"chars": 4538,
"preview": "package static\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/apex/up\"\n\t\"github.com/ap"
},
{
"path": "http/static/testdata/dynamic/app.js",
"chars": 228,
"preview": "const http = require('http')\nconst port = process.env.PORT\n\nhttp.createServer((req, res) => {\n res.setHeader('X-Foo', '"
},
{
"path": "http/static/testdata/dynamic/public/css/style.css",
"chars": 30,
"preview": "body { background: whatever }\n"
},
{
"path": "http/static/testdata/dynamic/up.json",
"chars": 20,
"preview": "{\n \"name\": \"app\"\n}\n"
},
{
"path": "http/static/testdata/static/index.html",
"chars": 11,
"preview": "Index HTML\n"
},
{
"path": "http/static/testdata/static/style.css",
"chars": 30,
"preview": "body { background: whatever }\n"
},
{
"path": "http/static/testdata/static/up.json",
"chars": 20,
"preview": "{\n \"name\": \"app\"\n}\n"
},
{
"path": "install.sh",
"chars": 7998,
"preview": "#!/bin/sh\nset -e\n# Code generated by godownloader. DO NOT EDIT.\n#\n\nusage() {\n this=$1\n cat <<EOF\n$this: download go b"
},
{
"path": "internal/account/account.go",
"chars": 9898,
"preview": "package account\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n"
},
{
"path": "internal/account/cards.go",
"chars": 1380,
"preview": "package account\n\nimport (\n\t\"github.com/stripe/stripe-go\"\n\t\"github.com/tj/survey\"\n)\n\n// Questions.\nvar questions = []*sur"
},
{
"path": "internal/cli/app/app.go",
"chars": 305,
"preview": "package app\n\nimport (\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/apex/up/internal/cli/root\"\n\n\t\"github.com/apex/up/internal/stats\"\n)\n\n//"
},
{
"path": "internal/cli/build/build.go",
"chars": 2119,
"preview": "package build\n\nimport (\n\t\"archive/zip\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"sort\"\n\n\t\"github.com/dustin/go-humanize\"\n\t\"github.co"
},
{
"path": "internal/cli/config/config.go",
"chars": 600,
"preview": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"os\"\n\n\t\"github.com/apex/up/internal/cli/root\"\n\t\"github.com/apex/up/internal/s"
},
{
"path": "internal/cli/deploy/deploy.go",
"chars": 3849,
"preview": "package deploy\n\nimport (\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/pkg/errors\"\n\t\"github.com/tj/go/git\"\n\t\"github.com/tj/go/term\"\n\t\"gith"
},
{
"path": "internal/cli/disable-stats/disable-stats.go",
"chars": 420,
"preview": "package disablestats\n\nimport (\n\t\"github.com/pkg/errors\"\n\t\"github.com/tj/kingpin\"\n\n\t\"github.com/apex/up/internal/cli/root"
},
{
"path": "internal/cli/docs/docs.go",
"chars": 456,
"preview": "package docs\n\nimport (\n\t\"github.com/pkg/browser\"\n\t\"github.com/tj/kingpin\"\n\n\t\"github.com/apex/up/internal/cli/root\"\n\t\"git"
},
{
"path": "internal/cli/domains/domains.go",
"chars": 5405,
"preview": "package domains\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/pkg/errors\"\n\t\"github.com/tj/kingpin\"\n\t\"github.com/tj/s"
},
{
"path": "internal/cli/logs/logs.go",
"chars": 3075,
"preview": "package logs\n\nimport (\n\t\"io\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/pkg/errors\"\n\t\"github.com/tj/go/term\"\n\t\"github.com/tj/kingpin\"\n\n"
},
{
"path": "internal/cli/metrics/metrics.go",
"chars": 1123,
"preview": "package metrics\n\nimport (\n\t\"time\"\n\n\t\"github.com/pkg/errors\"\n\t\"github.com/tj/kingpin\"\n\n\t\"github.com/apex/up/internal/cli/"
},
{
"path": "internal/cli/prune/prune.go",
"chars": 1034,
"preview": "package prune\n\nimport (\n\t\"github.com/pkg/errors\"\n\t\"github.com/tj/kingpin\"\n\n\t\"github.com/apex/up/internal/cli/root\"\n\t\"git"
},
{
"path": "internal/cli/root/root.go",
"chars": 2259,
"preview": "package root\n\nimport (\n\t\"os\"\n\t\"runtime\"\n\n\t\"github.com/apex/log\"\n\t\"github.com/apex/log/handlers/cli\"\n\t\"github.com/apex/lo"
},
{
"path": "internal/cli/run/run.go",
"chars": 861,
"preview": "package run\n\nimport (\n\t\"github.com/apex/up/internal/cli/root\"\n\t\"github.com/apex/up/internal/stats\"\n\t\"github.com/apex/up/"
},
{
"path": "internal/cli/stack/stack.go",
"chars": 3408,
"preview": "package stack\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/pkg/errors\"\n\t\"github.com/tj/kingpin\"\n\t\"github.com/tj/survey\"\n\n\t\"github.com/"
},
{
"path": "internal/cli/start/start.go",
"chars": 2221,
"preview": "package start\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"os\"\n\n\t\"github.com/apex/log\"\n\t\"github.com/pkg/browser\"\n\t\"github.com/p"
},
{
"path": "internal/cli/team/team.go",
"chars": 17076,
"preview": "package team\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/pk"
},
{
"path": "internal/cli/upgrade/upgrade.go",
"chars": 4055,
"preview": "package upgrade\n\nimport (\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/pkg/errors\"\n\t\"gi"
},
{
"path": "internal/cli/url/url.go",
"chars": 1724,
"preview": "package url\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/pkg/browser\"\n\t\"github.com/pkg/errors\"\n\t\"github.com/tj/go/clipboard\"\n\t\"github."
},
{
"path": "internal/cli/version/version.go",
"chars": 344,
"preview": "package version\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/tj/kingpin\"\n\n\t\"github.com/apex/up/internal/cli/root\"\n\t\"github.com/apex/up"
},
{
"path": "internal/colors/colors.go",
"chars": 916,
"preview": "// Package colors provides colors used by the CLI.\npackage colors\n\nimport (\n\tcolor \"github.com/aybabtme/rgbterm\"\n)\n\n// F"
},
{
"path": "internal/errorpage/errorpage.go",
"chars": 2936,
"preview": "// Package errorpage provides error page loading utilities.\npackage errorpage\n\nimport (\n\t\"bytes\"\n\t\"html/template\"\n\t\"io/i"
},
{
"path": "internal/errorpage/errorpage_test.go",
"chars": 1470,
"preview": "package errorpage\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/tj/assert\"\n)\n\n// load pages from dir.\nfunc load(t "
},
{
"path": "internal/errorpage/template.go",
"chars": 2133,
"preview": "package errorpage\n\nimport \"html/template\"\n\n// defaultPage is the default error page.\nvar defaultPage = template.Must(tem"
},
{
"path": "internal/errorpage/testdata/200.html",
"chars": 10,
"preview": "200 page.\n"
},
{
"path": "internal/errorpage/testdata/404.html",
"chars": 10,
"preview": "404 page.\n"
},
{
"path": "internal/errorpage/testdata/4xx.html",
"chars": 10,
"preview": "4xx page.\n"
},
{
"path": "internal/errorpage/testdata/500.html",
"chars": 10,
"preview": "500 page.\n"
},
{
"path": "internal/errorpage/testdata/error.html",
"chars": 35,
"preview": "{{.StatusText}} - {{.StatusCode}}.\n"
},
{
"path": "internal/errorpage/testdata/other.html",
"chars": 0,
"preview": ""
},
{
"path": "internal/errorpage/testdata/somedir/test.html",
"chars": 0,
"preview": ""
},
{
"path": "internal/header/header.go",
"chars": 1018,
"preview": "// Package header provides path-matched header injection rules.\npackage header\n\nimport (\n\t\"github.com/fanyang01/radix\"\n)"
},
{
"path": "internal/header/header_test.go",
"chars": 1306,
"preview": "package header\n\nimport (\n\t\"testing\"\n\n\t\"github.com/tj/assert\"\n)\n\nfunc TestMatcher_Lookup(t *testing.T) {\n\trules := Rules{"
},
{
"path": "internal/inject/inject.go",
"chars": 6020,
"preview": "// Package inject provides script and style injection utilities.\npackage inject\n\nimport (\n\t\"encoding/json\"\n\t\"html\"\n\t\"io/"
},
{
"path": "internal/inject/inject_test.go",
"chars": 4765,
"preview": "package inject_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/tj/assert\"\n\t\"github.com/apex/up/internal/inject\"\n)\n\nvar ht"
},
{
"path": "internal/logs/logs.go",
"chars": 612,
"preview": "// Package logs provides logging utilities.\npackage logs\n\nimport (\n\t\"os\"\n\n\t\"github.com/apex/log\"\n)\n\n// Fields returns th"
},
{
"path": "internal/logs/parser/ast/ast.go",
"chars": 3279,
"preview": "// Package ast provides the log query language abstract syntax tree.\npackage ast\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n"
},
{
"path": "internal/logs/parser/grammar.peg",
"chars": 4843,
"preview": "package parser\n\nimport \"github.com/apex/up/internal/logs/parser/ast\"\n\ntype parser Peg {\n stack []ast.Node\n number stri"
},
{
"path": "internal/logs/parser/grammar.peg.go",
"chars": 85970,
"preview": "package parser\n\n// Code generated by peg -inline -switch grammar.peg DO NOT EDIT\n\nimport (\n\t\"fmt\"\n\t\"github.com/apex/up/i"
},
{
"path": "internal/logs/parser/parser.go",
"chars": 2473,
"preview": "//go:generate peg -inline -switch grammar.peg\n\n// Package parser provides a parser for Up's\n// log query language, abstr"
},
{
"path": "internal/logs/parser/parser_test.go",
"chars": 6065,
"preview": "package parser\n\nimport (\n\t\"testing\"\n)\n\n// TODO: precedence...\n// TODO: byte size literals\n// TODO: support literals: `me"
},
{
"path": "internal/logs/text/text.go",
"chars": 4044,
"preview": "// Package text implements a development-friendly textual handler.\npackage text\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"sync\"\n"
},
{
"path": "internal/logs/text/text_test.go",
"chars": 493,
"preview": "package text\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/apex/log\"\n)\n\nfunc init() {\n\tlog.Now = func("
},
{
"path": "internal/logs/writer/writer.go",
"chars": 1792,
"preview": "// Package writer provides an io.Writer for capturing\n// process output as logs, so that stdout may become\n// INFO, and "
},
{
"path": "internal/logs/writer/writer_test.go",
"chars": 1902,
"preview": "package writer\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/apex/log\"\n\t\"github.com/apex/log/hand"
},
{
"path": "internal/metrics/metrics.go",
"chars": 1467,
"preview": "// Package metrics provides higher level CloudWatch metrics operations.\npackage metrics\n\nimport (\n\t\"time\"\n\n\t\"github.com/"
},
{
"path": "internal/progressreader/progressreader.go",
"chars": 771,
"preview": "// Package progressreader provides an io.Reader progress bar.\npackage progressreader\n\nimport (\n\t\"io\"\n\t\"sync\"\n\n\t\"github.c"
},
{
"path": "internal/proxy/bin/bin.go",
"chars": 174,
"preview": "//go:generate sh -c \"GOOS=linux GOARCH=amd64 go build -o up-proxy ../../../cmd/up-proxy/main.go\"\n//go:generate go-bindat"
},
{
"path": "internal/proxy/event.go",
"chars": 2150,
"preview": "package proxy\n\n// Identity is the identity information associated with the request.\ntype Identity struct {\n\tAPIKey "
},
{
"path": "internal/proxy/event_test.go",
"chars": 10585,
"preview": "package proxy\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\nvar getEvent = `{\n \"resource\": \"/{proxy+}\",\n \"path\": \"/pets/tobi\",\n"
},
{
"path": "internal/proxy/lambda.go",
"chars": 683,
"preview": "// Package proxy provides API Gateway and Lambda interoperability.\npackage proxy\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n"
},
{
"path": "internal/proxy/request.go",
"chars": 1455,
"preview": "package proxy\n\nimport (\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/p"
},
{
"path": "internal/proxy/request_test.go",
"chars": 2115,
"preview": "package proxy\n\nimport (\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"testing\"\n\n\t\"github.com/tj/assert\"\n)\n\nfunc TestNewRequest(t *test"
},
{
"path": "internal/proxy/response.go",
"chars": 2302,
"preview": "package proxy\n\nimport (\n\t\"bytes\"\n\t\"encoding/base64\"\n\t\"mime\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/apex/up/internal/util\"\n"
},
{
"path": "internal/proxy/response_test.go",
"chars": 2341,
"preview": "package proxy\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/tj/assert\"\n)\n\nfunc Test_JSON_isTextMime(t *testing.T) {\n\tasser"
},
{
"path": "internal/redirect/redirect.go",
"chars": 3278,
"preview": "// Package redirect provides compiling and matching\n// redirect and rewrite rules.\npackage redirect\n\nimport (\n\t\"fmt\"\n\t\"r"
},
{
"path": "internal/redirect/redirect_test.go",
"chars": 3384,
"preview": "package redirect\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/tj/assert\"\n)\n\nfunc rule(from, to string) Rule {\n\tr := Rule{\n\t"
},
{
"path": "internal/setup/setup.go",
"chars": 3030,
"preview": "// Package setup provides up.json initialization.\npackage setup\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/ioutil\""
},
{
"path": "internal/shim/index.js",
"chars": 3609,
"preview": "const child = require('child_process');\n\n/**\n * Debug env var.\n */\n\nconst debug = process.env.DEBUG_SHIM;\n\n/**\n * A map "
},
{
"path": "internal/shim/shim.go",
"chars": 137,
"preview": "//go:generate go-bindata -modtime 0 -pkg shim .\n\n// Package shim provides a shim for running arbitrary languages on Lamb"
},
{
"path": "internal/signal/signal.go",
"chars": 562,
"preview": "package signal\n\nimport (\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\t\"github.com/apex/up/internal/util\"\n)\n\n// close funcs.\nvar fns ["
},
{
"path": "internal/stats/stats.go",
"chars": 905,
"preview": "// Package stats provides CLI analytics.\npackage stats\n\nimport (\n\t\"github.com/apex/log\"\n\t\"github.com/tj/go-cli-analytics"
},
{
"path": "internal/userconfig/userconfig.go",
"chars": 4004,
"preview": "// Package userconfig provides user machine-level configuration.\npackage userconfig\n\nimport (\n\t\"encoding/base64\"\n\t\"encod"
},
{
"path": "internal/userconfig/userconfig_test.go",
"chars": 934,
"preview": "package userconfig\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/mitchellh/go-homedir\"\n\t\"github.com/tj/asser"
},
{
"path": "internal/util/util.go",
"chars": 11892,
"preview": "// Package util haters gonna hate.\npackage util\n\nimport (\n\t\"bufio\"\n\t\"crypto/md5\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"fmt\""
},
{
"path": "internal/util/util_test.go",
"chars": 4381,
"preview": "package util\n\nimport (\n\t\"net/http\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/tj/assert\"\n)\n\nfunc TestExitSta"
},
{
"path": "internal/validate/validate.go",
"chars": 1622,
"preview": "// Package validate provides config validation functions.\npackage validate\n\nimport (\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/"
},
{
"path": "internal/zip/testdata/.file",
"chars": 3,
"preview": "👻 \n"
},
{
"path": "internal/zip/testdata/.upignore",
"chars": 5,
"preview": "*.md\n"
},
{
"path": "internal/zip/testdata/Readme.md",
"chars": 12,
"preview": "Hello World\n"
},
{
"path": "internal/zip/testdata/bar.js",
"chars": 4,
"preview": "bar\n"
}
]
// ... and 30 more files (download for full content)
About this extraction
This page contains the full source code of the apex/up GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 230 files (618.2 KB), approximately 190.8k tokens, and a symbol index with 968 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.