Pull Request Previews
Give every pull request its own running copy of your app, at its own URL, rebuilt on each push and removed when the pull request closes.
Overview
With previews on, each pull request against your app's deployed branch gets an isolated copy of the app built from the pull request's code. Reviewers open a link instead of checking out the branch.
- The preview is built when the pull request is opened, and again on every push to it.
- The pull request shows a commit status and one comment with the preview's link, kept up to date as it builds.
- The preview is removed when the pull request is merged or closed.
Previews are in beta, for apps built from a GitHub repository. They are included at no extra cost for projects with at least one paid app.
Before you start
- The app deploys from a GitHub repository. Previews are not built for apps that run a container image, or for GitLab and Bitbucket repositories yet.
- The project has at least one paid app.
- The Cosmoner GitHub app has the permissions previews need. Previews read pull requests and post commit statuses and comments, which the app could not do before previews existed. GitHub asks an owner of the account the app is installed on to approve the new permissions once. Until then pushes keep deploying as usual, but no previews are built. The app's page tells you when this approval is missing; approve it in the account's settings on GitHub, under Applications.
Turn previews on
Previews are off for every app until you turn them on. On the app's page, open Overview and find Pull request previews, then turn on Build a preview of every pull request.
Before anything changes, a dialog lists every environment variable a preview will receive (see below). Check it, then select Turn on.
Turning previews on needs the developer, admin or owner role.
What a preview gets
Which pull requests
A pull request gets a preview when it targets the branch the app deploys from.
- Draft pull requests are skipped until they are marked ready for review.
- Pull requests from forks are skipped, because they run code from outside your repository. The commit status says so.
Its URL
Each preview is served at its own address on cosmoner.app, named after the app
and the pull request number, for example
https://my-app-pr-12.cosmoner.app. The link is in the pull request's comment
and on the app's page. HTTPS is set up for you.
Preview addresses are public, so anyone with the link can open them. They are on a different domain from your app and from the control panel, so a preview never sees your session.
Size and limits
- A preview runs as one instance of the smallest size, whatever the app's own plan. A static site's preview is served as a static site.
- At most 2 previews of an app, and 5 across the project, are live at once. A pull request beyond that gets a status saying there is no room, and is built by its next push once a preview has been removed.
- The platform also keeps a limited amount of room for previews. When it is full, the pull request's status says so in the same way.
- A preview is removed after 72 hours without a push. The next push to the pull request builds it again.
Environment variables and secrets
A preview builds and runs with:
| From the app | In the preview |
|---|---|
| Plain values | Copied |
| Linked project variables | Copied |
| Secrets set on the app | Never copied |
| Linked project secrets | Never copied |
A pull request's code can read every variable it is given, while it builds and while it runs. Secrets are left out so that a pull request can never see more than its author could already push. A plain value is copied like any other, so if you keep something sensitive as a plain value, such as a database URL, store it as a secret instead before you turn previews on.
Every preview also gets:
| Variable | Value |
|---|---|
COSMONER_PREVIEW | true |
COSMONER_PR_NUMBER | The pull request's number |
COSMONER_PREVIEW_URL | The preview's address |
COSMONER_GIT_SHA | The commit being built |
Use COSMONER_PREVIEW to change behaviour in previews, for example to skip
sending real emails.
Previews get no database of their own. An app whose code needs one should fall
back to something safe, such as an in-memory store, when COSMONER_PREVIEW is
set.
Watching and removing previews
The app's page lists its live previews with the pull request number, the status, the address, the commit and how long ago the preview was created.
| Status | Meaning |
|---|---|
| Queued, Building, Deploying | On its way up. |
| Ready | Serving the pull request's latest commit. |
| Failed | The last build or rollout failed. If an earlier build had succeeded, that version keeps serving. |
Select Build log next to a preview to read the log of its latest build. When a build fails, the commit status on the pull request links straight to it on the app's page, with the reason it failed.
To stop a preview early, select Tear down next to it. The pull request is left open, and its next push builds the preview again. Tearing down a preview needs the developer, admin or owner role.
Turning previews off removes every live preview of the app straight away, and pull requests stop getting new ones.
Billing
During the beta, previews are included for projects with at least one paid app, within the limits above. They do not appear on your invoice.
Using the API
Previews can be managed with an API key that has the apps scope:
| Request | What it does | Needs |
|---|---|---|
GET /v1/projects/{projectId}/apps/{appId}/previews/settings | Whether previews are on, whether they can be, and which variables a preview receives | apps:read |
PATCH /v1/projects/{projectId}/apps/{appId}/previews/settings | Turns previews on or off, with { "enabled": true } | apps:write, developer role or above |
GET /v1/projects/{projectId}/apps/{appId}/previews | Lists the app's previews | apps:read |
GET /v1/projects/{projectId}/apps/{appId}/previews/{previewId} | Fetches one preview | apps:read |
GET /v1/projects/{projectId}/apps/{appId}/previews/{previewId}/build-log | Reads the log of a preview's latest build | apps:read |
DELETE /v1/projects/{projectId}/apps/{appId}/previews/{previewId} | Tears one preview down | apps:write, developer role or above |
See Apps in the API reference for the request and response shapes.
Troubleshooting
A pull request got no preview. Check that previews are on for the app, that the pull request targets the app's deployed branch, that it is not a draft and not from a fork, and that the GitHub permissions are approved. The commit status on the pull request says why when a preview was skipped or there was no room for it.
The preview fails to build or start. Follow the link in the failed commit
status, or select Build log next to the preview on the app's page. A missing secret is the usual cause: secrets are
never copied, so an app that refuses to start without one needs a fallback when
COSMONER_PREVIEW is set.
Deploy a Container Image
Run any Docker image as an app — from your Cosmoner registry, Docker Hub or the GitHub container registry — and redeploy it from CI when you push a new tag.
Passkeys
Sign in with Touch ID, Face ID, Windows Hello, or a security key — no password and no code, and nothing a phishing site can capture.