Skip to content

Merge pull request #7 from privacy-com/stlc/promote-ancestry-check #1

Merge pull request #7 from privacy-com/stlc/promote-ancestry-check

Merge pull request #7 from privacy-com/stlc/promote-ancestry-check #1

Workflow file for this run

name: Promote SDKs
# Promote staging to production by fast-forwarding production main up to staging,
# preserving SHAs so the trunks stay identical and linear (nothing to heal on the
# next stlc build). Runs on every push to staging main, so production main always
# mirrors staging and release-please (running on production) keeps its version PR
# current. The human gate is merging that release PR, not this push: production main
# is not what customers install until a release is tagged. workflow_dispatch remains
# for a manual re-run.
#
# This file is promoted into production along with everything else; the repository
# guard below keeps it inert there. Back-sync pushes to staging use GITHUB_TOKEN, which
# does not fire workflows, so a release cannot loop back through here.
#
# Credentials: a lithic-com GitHub App (LITHIC_SDK_RELEASE_APP_ID / _PRIVATE_KEY),
# installed on the production repo and listed as a bypass actor on its main branch
# ruleset. No PATs.
on:
push:
# main only. stlc preview/integrated/codegen and conflict branches never push to main.
branches: [main]
workflow_dispatch: {}
permissions:
contents: read
concurrency:
group: stlc-promote
cancel-in-progress: false
jobs:
promote:
# Runner comes from the STLC_RUNNER repo/org variable when set; defaults to GitHub-hosted.
runs-on: ${{ vars.STLC_RUNNER || 'ubuntu-latest' }}
if: github.repository == 'privacy-com/lithic-python-staging'
env:
PRODUCTION_REPO: lithic-com/lithic-python
steps:
- name: Check out staging
uses: actions/checkout@v6
with:
fetch-depth: 0
persist-credentials: false
- name: Mint production token
id: app
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.LITHIC_SDK_RELEASE_APP_ID }}
private-key: ${{ secrets.LITHIC_SDK_RELEASE_APP_PRIVATE_KEY }}
owner: lithic-com
repositories: lithic-python
- name: Fetch production main
env:
GH_TOKEN: ${{ steps.app.outputs.token }}
run: |
git remote add production \
"https://x-access-token:${GH_TOKEN}@github.com/${PRODUCTION_REPO}.git"
git fetch production main
- name: Check whether production already has staging's tip
id: diff
run: |
# Ancestry, not content. Production may be *ahead* of staging right after a release
# (release-please's version commit, not yet back-synced): then it already contains
# staging's tip and there is nothing to promote. A tree comparison was used here
# before and wrongly skipped commits that change no files (e.g. empty Conventional
# Commits seeded for release-please), leaving production without them.
if git merge-base --is-ancestor origin/main production/main; then
echo "Production already contains staging's tip $(git rev-parse --short origin/main). Nothing to promote."
echo "synced=true" >> "$GITHUB_OUTPUT"
else
echo "synced=false" >> "$GITHUB_OUTPUT"
fi
- name: Promote staging to production (fast-forward)
if: steps.diff.outputs.synced == 'false'
run: |
# Refuse unless production is an ancestor of staging: otherwise the trunks
# have forked (production advanced without a back-sync) and FF is unsafe.
if ! git merge-base --is-ancestor production/main origin/main; then
echo "::error title=Promote blocked::production/main is not an ancestor of staging main. Back-sync production into staging first (stlc-sync.yml)."
exit 1
fi
git push production origin/main:refs/heads/main
echo "Fast-forwarded production/main $(git rev-parse --short production/main) -> $(git rev-parse --short origin/main)."
- name: Alert on failure
if: failure()
env:
ALERT_WEBHOOK_URL: ${{ secrets.STLC_ALERT_WEBHOOK_URL }}
run: |
run_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
msg="stlc promote failed in ${{ github.repository }}. A stalled promote or back-sync lets custom-code tracking drift, which later builds refuse on — investigate before the next build. Run: $run_url"
echo "::error title=stlc workflow failed::$msg"
{ echo "### ⚠️ stlc workflow failed"; echo ""; echo "$msg"; } >> "$GITHUB_STEP_SUMMARY"
if [ -n "${ALERT_WEBHOOK_URL:-}" ]; then
curl -sS -X POST -H 'Content-Type: application/json' \
-d "$(jq -n --arg text "$msg" '{text:$text}')" "$ALERT_WEBHOOK_URL" \
|| echo "::warning::Alert webhook POST failed"
fi