Skip to content

Deploy Staging Environments #88

Deploy Staging Environments

Deploy Staging Environments #88

name: Deploy Staging Environments
# Depends on Docker build: this workflow only starts after "Build and Push Docker Image" completes
# (GitHub has no cross-workflow `needs:`; `workflow_run` is the supported dependency).
on:
workflow_run:
workflows:
- Build and Push Docker Image
types:
- completed
concurrency:
group: deploy-staging
cancel-in-progress: true
permissions:
contents: read
actions: read
jobs:
verify-docker-build-ran:
# Gated on the triggering run: only proceed when that Docker workflow run succeeded overall.
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
outputs:
image_built: ${{ steps.check.outputs.image_built }}
steps:
- name: Check build-and-push job succeeded
id: check
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
RUN_ID="${{ github.event.workflow_run.id }}"
REPO="${{ github.repository }}"
echo "::group::Jobs in triggering workflow run ${RUN_ID}"
gh api "repos/${REPO}/actions/runs/${RUN_ID}/jobs?per_page=100" --jq '.jobs[] | "\(.name) -> \(.conclusion)"' || true
echo "::endgroup::"
# Match default job id "build-and-push" (exact) or names GitHub may emit for that job.
match="$(
gh api "repos/${REPO}/actions/runs/${RUN_ID}/jobs?per_page=100" \
--jq '.jobs[] | select(.conclusion == "success") | select(.name == "build-and-push" or (.name | startswith("build-and-push"))) | .name' \
| head -1
)"
if [ -n "$match" ]; then
echo "image_built=true" >> "$GITHUB_OUTPUT"
echo "Docker image build job succeeded (matched: $match); will refresh staging image tags."
else
echo "image_built=false" >> "$GITHUB_OUTPUT"
echo "::notice::Skipping staging tag update: no successful build-and-push job in this workflow run (no new image built)."
fi
staging-gitops-pr:
needs: verify-docker-build-ran
if: needs.verify-docker-build-ran.outputs.image_built == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Create GitHub App token
id: app-token
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf
with:
app-id: ${{ secrets.DEPLOYMENT_APP_ID }}
private-key: ${{ secrets.DEPLOYMENT_APP_PRIVATE_KEY }}
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
token: ${{ steps.app-token.outputs.token }}
ref: main
- name: Set image tag (short SHA)
id: vars
env:
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
run: echo "image_tag=sha-${HEAD_SHA::7}" >> "$GITHUB_OUTPUT"
- name: Update staging envs and indexer guard
env:
IMAGE_TAG: ${{ steps.vars.outputs.image_tag }}
run: |
set -euo pipefail
sync_staging() {
local staging="$1"
local prod="$2"
yq -i ".indexer.image.tag = strenv(IMAGE_TAG)" "$staging"
yq -i ".query.image.tag = strenv(IMAGE_TAG)" "$staging"
local prod_tag
prod_tag="$(yq '.indexer.image.tag' "$prod")"
if [ "$IMAGE_TAG" = "$prod_tag" ]; then
echo "Tag clash with prod ($prod): disabling indexer on $staging"
yq -i '.indexer.enabled = false' "$staging"
else
yq -i '.indexer.enabled = true' "$staging"
fi
}
sync_staging environments/main-s.yaml environments/main.yaml
sync_staging environments/test-s.yaml environments/test.yaml
sync_staging environments/main-us-s.yaml environments/main-us.yaml
sync_staging environments/test-us-s.yaml environments/test-us.yaml
- name: Open staging deployment PR
id: cpr
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0
with:
token: ${{ steps.app-token.outputs.token }}
author: "api-gitops[bot] <${{ secrets.DEPLOYMENT_APP_ID }}+api-gitops[bot]@users.noreply.github.com>"
branch: gitops/staging
delete-branch: true
base: main
commit-message: "chore(cd): update staging env tags to ${{ steps.vars.outputs.image_tag }}"
title: "chore(cd): update staging (main-s / test-s / main-us-s / test-us-s) image tags"
body: |
Automated **staging** image tag update (`main-s.yaml`, `test-s.yaml`, `main-us-s.yaml`, `test-us-s.yaml`) for the latest Docker build.
- Tag: `${{ steps.vars.outputs.image_tag }}`
- Triggering workflow run: ${{ github.event.workflow_run.html_url }}
If this tag matched production (`main.yaml` / `test.yaml` / `main-us.yaml` / `test-us.yaml`) for an environment, **indexer** was set to `enabled: false` on that staging file to avoid duplicate indexers on the same version.
labels: |
deployment
staging
add-paths: |
environments/main-s.yaml
environments/test-s.yaml
environments/main-us-s.yaml
environments/test-us-s.yaml
- name: Enable auto-merge (squash)
if: ${{ steps.cpr.outputs.pull-request-number != '' }}
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: gh pr merge ${{ steps.cpr.outputs.pull-request-number }} --auto --squash