Repository navigation
Merge pull request #7 from privacy-com/stlc/promote-ancestry-check #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |