Every CI template follows the same life of a preview environment as the GitHub Action:
apply when the pull request
opens or changes (it stops with status partial at the deploy barrier), apply --wait once the preview is deploying
(it finishes the lines that needed the preview URL), apply --destroy when the pull request closes, and production as
a step a human starts, recorded with --approved-by.
What every CI needs, whichever it is:
npx -y sponson@<version>, pinned to the version you reviewed, on Node.js 22 or later.- The scope flags
--pr,--branchand--sha, filled from the CI’s predefined variables. Each template passes them explicitly; Sponson 0.5.0 and later also read GitLab’s, CircleCI’s and Bitbucket’s variables themselves (as they read GitHub Actions’), see the run context. - Provider tokens as the CI’s secret variables, in every job that runs Sponson, destroy included.
- A token that can push receipts. The git-branch receipt store pushes orphan branches
sponson-receipts/<env>/<scope>from a clone of its own, so the CI’s read-only checkout credentials are not enough. Each template setsSPONSON_RECEIPTS_REMOTEto an HTTPS URL carrying a write token; its README says which token to create. Sponson strips credentials from every git error it prints.
The pull request comment
The GitHub Action comments on the pull request (what the comment looks like). The other templates print to the job log and post nothing, because posting needs a token with more rights than pushing receipts. To get the same comment on a merge request or pull request, run the command with--format markdown (instead of the default text) and post the file it prints; the exit code is the same, and a
refusal or failure prints a comment too. The first line is the marker <!-- sponson:<env> -->: update the note that
starts with it instead of adding one per run.
GitLab, in sponson:apply, sponson:finish and sponson:destroy (a project access token with the api scope,
saved as the masked variable SPONSON_GITLAB_NOTES_TOKEN; the merge request notes API):
{ "content": { "raw": … } } (Bitbucket does not render the <pre> and <sub> HTML the comment
uses for manual steps and its footer; the text stays readable); from CircleCI, post it to the GitHub pull request with
the issue comments API. A tool that already holds the --json result
can render the same markdown with renderMarkdown(envelope) from the sponson package instead of running Sponson
twice.
How the templates are checked
On everypnpm test, scenarios/docs/integrations.test.ts parses every template, checks the GitLab template’s
structure (stages, jobs, rules, environments and their on_stop job) and Bitbucket’s (no pipeline starts with a
manual step), and runs every Sponson command line in them through the CLI to the expected scope, with the flags and
through detection of the host’s variables alike.
End to end, in Docker, scripts/try-ci-templates.sh [gitlab] [circleci] [bitbucket] runs each template’s whole
preview life against the fake cloud (@sponson/sim): a scratch repository whose main has a release plan (a Neon
branch, the preview’s DATABASE_URL from it, a production variable from a secret) and the template, and a pull
request branch that adds a Clerk callback on the preview URL. Per host it runs the pull request pipeline (plan; apply,
which stops at the deploy barrier because the fake deploy takes 20 seconds; finish, which waits for it), checks the
resources exist, runs production with an approver, runs the destroy the host would run when the pull request closes,
checks the preview resources are gone and production kept, and checks the receipts reached the repository. It also
runs the plan command without --pr/--branch/--sha in each host’s environment and checks the detected scope (pull
request, main, and a tag build on CircleCI and Bitbucket). It needs Docker and the network, so it is not part of
pnpm test; KEEP=1 keeps the scratch directory, SPONSON_TRY_VERSION=0.5.0 runs a release from npm instead of
this checkout.
What is real and what is emulated:
Not covered: the hosts’ own triggers (when a pipeline starts, GitLab stopping the environment on merge), their
runners’ networks and checkout credentials, merged-results pipelines, and real provider APIs. Each README’s notes say
which behaviour of the host the template relies on.