Files
Ruslan KonviserandClaude Fable 5 0caa9ae72c ci: only the newest commit builds — supersede policy across all 67 workflows
Four merges to develop this morning left five superseded runs building dead
commits while the branch head waited. Applied one policy, per class:

- build.yml: cancel-in-progress was `github.event_name == 'pull_request'`, so
  branch pushes never superseded each other — every merge started its own 3-h
  compile. Now true for all events; it writes nothing outside the run.
- release-{demo,stage,prod}: made the release ATOMIC so it becomes safe to
  supersede. `github-tag-action` now runs with dry_run (calculate only) and
  `ncipollo/release-action` creates the tag AND the release in one call with
  `commit: github.sha`. Previously the tag was pushed by an earlier step, so a
  cancelled run stranded a tag with no release forever (the next run computes the
  NEXT version and never backfills). With that window gone: cancel-in-progress true.
- 6 non-prod image builds: now supersede within their own workflow+ref, matching
  what the prod image builds already did. Group stays per-workflow — the shared
  `gauzy-docker-build` group is what starved them before. Trade-off documented in
  the file: an intermediate version tag may end up without an image, which is inert
  because demo/stage deploy from :latest.
- 26 deploy workflows had NO concurrency key at all, so every merge queued its own
  deploy. They now share a group per workflow+ref with cancel-in-progress FALSE:
  superseded PENDING runs collapse to the newest, but a rollout already applying is
  never interrupted.

Left alone deliberately: cache-janitor and external-uptime-monitor (cron probes,
must not cancel each other) and harvest-secrets-to-openbao (manual only).

Every file parses as YAML; the classification came from reading each workflow's
steps for external side effects, not from its name.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 14:24:27 +02:00

76 lines
3.6 KiB
YAML

name: Deploy to Civo Demo
on:
workflow_run:
workflows: ['Build and Publish Docker Images Demo']
branches:
- civo
types:
- completed
# Least-privilege scope for the automatic GITHUB_TOKEN.
# This workflow only builds/tests/deploys from a checkout — read access is sufficient.
concurrency:
# Collapse superseded runs WITHOUT interrupting one that is already applying: GitHub
# keeps a single pending run per group, so a newer commit replaces the one waiting
# while the in-flight deploy finishes. `cancel-in-progress: true` is deliberately NOT
# used here — killing a rollout mid-apply can leave the target half-updated.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: read
jobs:
deploy-demo:
runs-on: ${{ vars.RUNNER_LINUX_X64_4 || 'ubuntu-latest' }}
timeout-minutes: 300
environment: demo
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Create kubeconfig
run: |
mkdir ${HOME}/.kube
echo ${{ secrets.CIVO_KUBECONFIG }} | base64 --decode > ${HOME}/.kube/config
- name: Generate TLS Secrets for DemoCIVO and APIDemoCIVO
run: |
rm -f ${HOME}/ingress.api.crt ${HOME}/ingress.api.key ${HOME}/ingress.webapp.crt ${HOME}/ingress.webapp.key
echo ${{ secrets.INGRESS_API_CERT }} | base64 --decode > ${HOME}/ingress.api.crt
echo ${{ secrets.INGRESS_API_CERT_KEY }} | base64 --decode > ${HOME}/ingress.api.key
echo ${{ secrets.INGRESS_WEBAPP_CERT }} | base64 --decode > ${HOME}/ingress.webapp.crt
echo ${{ secrets.INGRESS_WEBAPP_CERT_KEY }} | base64 --decode > ${HOME}/ingress.webapp.key
kubectl create secret tls apidemocivo.gauzy.co-tls --save-config --dry-run=client --cert=${HOME}/ingress.api.crt --key=${HOME}/ingress.api.key -o yaml | kubectl apply -f -
kubectl create secret tls democivo.gauzy.co-tls --save-config --dry-run=client --cert=${HOME}/ingress.webapp.crt --key=${HOME}/ingress.webapp.key -o yaml | kubectl apply -f -
- name: Apply k8s manifests changes in Civo k8s cluster (if any)
run: |
envsubst < $GITHUB_WORKSPACE/.deploy/k8s/k8s-manifest.civo.demo.yaml | kubectl --context ever apply -f -
env:
# below we are using GitHub secrets for both frontend and backend
DB_NAME: '${{ secrets.DB_NAME }}'
CLOUD_PROVIDER: 'CIVO'
SENTRY_DSN: '${{ secrets.SENTRY_DSN }}'
SENTRY_TRACES_SAMPLE_RATE: '${{ secrets.SENTRY_TRACES_SAMPLE_RATE }}'
SENTRY_PROFILE_SAMPLE_RATE: '${{ secrets.SENTRY_PROFILE_SAMPLE_RATE }}'
SENTRY_HTTP_TRACING_ENABLED: '${{ secrets.SENTRY_HTTP_TRACING_ENABLED }}'
SENTRY_POSTGRES_TRACKING_ENABLED: '${{ secrets.SENTRY_POSTGRES_TRACKING_ENABLED }}'
SENTRY_PROFILING_ENABLED: '${{ secrets.SENTRY_PROFILING_ENABLED }}'
OTEL_ENABLED: '${{ secrets.OTEL_ENABLED }}'
OTEL_PROVIDER: '${{ secrets.OTEL_PROVIDER }}'
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${{ secrets.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT }}'
OTEL_EXPORTER_OTLP_HEADERS: '${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}'
FEATURE_OPEN_STATS: '${{ vars.FEATURE_OPEN_STATS }}'
ALLOWED_ORIGINS: '${{ secrets.ALLOWED_ORIGINS }}'
# we need this step because for now we just use :latest tag
# note: for production we will use different strategy later
- name: Restart Pods to pick up :latest tag version
run: |
kubectl --context ever rollout restart deployment/gauzy-demo-api
kubectl --context ever rollout restart deployment/gauzy-demo-webapp