Deployments from CI

Embed
Preview of the card
<a href="https://watchtowerops.net/docs/ci"><img src="https://watchtowerops.net/docs/_api/public/orgs/aa5959cb-1a0b-4a9a-bc9a-913e7ac31cd9/spaces/b7aac181-9916-4805-b253-becc5fd2ca62/pages/093c4e93-31e6-4365-aee7-5679743d49bd/social-card.svg?v=3e7ae33eec8b" alt="Deployments from CI" width="600" height="315"></a>

A deployment tells Watchtower which release is live in which environment. It becomes a chart annotation, the "new in this release" view, and (with the GitHub or GitLab connector) a comment on each pull request of the release.

Record it from CI with wtctl release create --deploy. It creates the release (idempotent by version), uploads the commits and the files they touched, and records the deployment. Use an API key with the ManageProject role in WT_API_KEY, and run it after the deploy step succeeds.

If you also installed the GitHub or GitLab connector and let the platform report deployments (deployment_status or Deployment events), do not call --deploy as well: that records the deployment twice. Either is fine on its own; keep wtctl release create (without --deploy) if you want commits before the deploy finishes.

GitHub Actions

name: deploy
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      - run: ./deploy.sh
      - name: Tell Watchtower
        env:
          WT_API_KEY: ${{ secrets.WT_API_KEY }}
        run: >
          wtctl release create "${GITHUB_SHA::12}"
          --api "${{ vars.WT_API_URL }}" --project "${{ vars.WT_PROJECT_ID }}"
          --commits auto --deploy production

GitLab CI

deploy:
  stage: deploy
  environment: production
  script:
    - ./deploy.sh
    - >
      wtctl release create "${CI_COMMIT_SHORT_SHA}"
      --api "$WT_API_URL" --project "$WT_PROJECT_ID"
      --commits auto --deploy production
  variables:
    GIT_DEPTH: 0

Set WT_API_KEY as a masked CI variable. The environment name must already exist in the project. Status: the snippets were checked against wtctl release create's flags, not run on a real runner.

Plain HTTP

Without wtctl, two calls do the same (API key with ManageProject in $WT_API_KEY):

curl -sS -X POST "$WT_API_URL/v1/projects/$WT_PROJECT_ID/releases" \
  -H "Authorization: Bearer $WT_API_KEY" -H "Content-Type: application/json" \
  -d '{"version":"'"$SHA"'","commits":[{"sha":"'"$SHA"'","repo":"owner/repo"}]}'
curl -sS -X POST "$WT_API_URL/v1/projects/$WT_PROJECT_ID/deployments" \
  -H "Authorization: Bearer $WT_API_KEY" -H "Content-Type: application/json" \
  -d '{"version":"'"$SHA"'","env_id":"'"$WT_ENV_ID"'","service":"api","status":"succeeded","source":"ci"}'

Coolify

Coolify exposes the deployed commit to the build and the container as SOURCE_COMMIT only when the application's Include Source Commit in Build setting (include_source_commit_in_build in the API) is on; it is off by default. Turn it on, then:

  • set service.version from it, e.g. OTEL_RESOURCE_ATTRIBUTES=service.version=${SOURCE_COMMIT} (or the short form your releases use, ${SOURCE_COMMIT:0:7} in a shell entrypoint), so spans, logs and metrics carry the release;

  • record the deployment from a post-deployment command or your CI with the same version: wtctl release create "$SOURCE_COMMIT" --deploy production, or POST /v1/projects/{prj}/deployments with service.

Use one form of the sha (full or short) everywhere: deploy markers, service.version, RUM release and source-map uploads must match exactly.

Updated