promote-to-prod
Promote the duckgres control-plane image to prod from the CLI — resolve the built image ref from the charts state file, fire the charts Promote-to-Prod…
npx skills add https://github.com/posthog/duckgres --skill promote-to-prodPromote duckgres to prod
Prod promotion is manual by policy: state/duckgres.yaml in PostHog/charts
has require_prod_approval: true, so the ONLY path to prod is the charts
repo's promote-to-prod.yml workflow, gated by required reviewers on the
prod-promote-<team> GitHub environment. The result posts to
#alerts-managed-warehouse.
How images reach the state file (no action needed)
Merge to duckgres main → container-image-cd.yml builds per-arch images +
a multi-arch manifest, then repo-dispatches commit_state_update to
PostHog/charts → the deploy bot writes state.duckgres.image.sha and
auto-promotes image.dev (mw-dev rolls immediately). The promotable ref is
the MULTI-ARCH MANIFEST digest in the state file — never a per-arch digest,
and never the .dockerbuild artifacts on the CD run (those are build
provenance).
Procedure
- Resolve the ref (and sanity-check it is the merge you expect):
STATE=$(gh api -H "Accept: application/vnd.github.raw" \
/repos/PostHog/charts/contents/state/duckgres.yaml)
DEV=$(echo "$STATE" | yq '.state.duckgres.image.dev')
PROD=$(echo "$STATE" | yq '.state.duckgres.image.prod')
echo "dev: $DEV"
echo "prod: $PROD"
# The <git-sha> prefix of $DEV must be the duckgres main commit you intend
# to ship. If dev != sha the CD/deploy-bot hop hasn't landed yet — wait.
- Show the delta going out (what prod is about to receive):
git log --oneline "${PROD%%@*}..${DEV%%@*}"
- Fire the promotion (parks at the approval gate — nothing deploys yet):
gh workflow run promote-to-prod.yml -R PostHog/charts \
-f app=duckgres -f image="$DEV"
sleep 8
RUN_URL=$(gh run list -R PostHog/charts --workflow=promote-to-prod.yml \
--limit 1 --json url --jq '.[0].url')
echo "$RUN_URL"
# Land the approver directly on the approval page:
open "$RUN_URL"
-
Approval: a required reviewer approves the pending deployment on the run page just opened. Never self-approve programmatically on the operator's behalf — open the page and wait.
-
Watch to completion (after approval):
gh run watch <run-id> -R PostHog/charts --exit-status
# Verify the write landed:
gh api -H "Accept: application/vnd.github.raw" \
/repos/PostHog/charts/contents/state/duckgres.yaml | yq '.state.duckgres.image.prod'
ArgoCD picks up the new image.prod and rolls the prod control plane;
watch pods with kubectl -n duckgres get pods -w if verification beyond
ArgoCD is wanted.
Notes
run-nameshows as " promoted duckgres to prod ()" in the Actions list; the commit the run page header shows is main's HEAD at dispatch, NOT the commit the run creates — the created commit is linked from the job summary.- The cache-proxy image is a separate deploy target: same workflow with
-f app=duckgres-cache-proxy(state filestate/duckgres-cache-proxy.yaml). - Rollback = promote the previous known-good ref (visible in
git log -- state/duckgres.yamlin the charts repo) through the same workflow.