From 8a18f5f5658f45c625cbc01c176e5c17e98effe8 Mon Sep 17 00:00:00 2001 From: Arbian Shkodra Date: Fri, 30 Oct 2026 10:01:23 +0100 Subject: [PATCH] ci(repo): run this repository on the one-repo topology The generator will push here directly, so the four workflows that moved commits between a staging repository and this one have nothing left to move: promote, back-sync, the trunk lock and the release trigger go. The seal-dispatch now routes on this repository's name and mints its token from the GitHub App, with the old dispatch token as fallback. CI, release-please and the publish workflow stay. Co-Authored-By: Claude Fable 5.1 --- .github/workflows/seal-dispatch.yml | 28 +++++-- .github/workflows/stlc-promote.yml | 70 ------------------ .../workflows/stlc-sync-from-production.yml | 74 ------------------- .../trigger-back-sync-on-release.yml | 38 ---------- .github/workflows/trunk-sync-lock.yml | 69 ----------------- 5 files changed, 20 insertions(+), 259 deletions(-) delete mode 100644 .github/workflows/stlc-promote.yml delete mode 100644 .github/workflows/stlc-sync-from-production.yml delete mode 100644 .github/workflows/trigger-back-sync-on-release.yml delete mode 100644 .github/workflows/trunk-sync-lock.yml diff --git a/.github/workflows/seal-dispatch.yml b/.github/workflows/seal-dispatch.yml index 128bd54f7..66f52af48 100644 --- a/.github/workflows/seal-dispatch.yml +++ b/.github/workflows/seal-dispatch.yml @@ -5,20 +5,21 @@ name: Seal custom code (dispatch) # When genuine out-of-band custom code is merged to this SDK repo's `main` # (a direct staging commit, or a contribution pulled back from production), # notify the config repo to reseal so the custom-code tracking JSON absorbs it -# promptly instead of waiting for the config repo's poll. stlc-authored commits +# promptly instead of waiting for the config repo's poll. generator-authored commits # are skipped by the loop guards below, so the bot's own pushes (the "Build SDK" # squash commit and any regen commit) cannot trigger a reseal loop. # # This workflow is itself custom code on the SDK repo: seal it once with -# `stlc build --commit` to bootstrap, after which scaffold preservation keeps it +# the generator's commit step to bootstrap, after which scaffold preservation keeps it # across regenerations. If you would rather keep things simple, drop this file -# and rely on the config repo's scheduled `stlc-sync-tracking.yml` poll alone. +# and rely on the config repo's scheduled tracking-sync poll alone. # -# Lives in the STAGING repo. Requires CONFIG_DISPATCH_TOKEN — a token that can +# Requires the GitHub App secrets (SDK_APP_ID, SDK_APP_PRIVATE_KEY) or, as a +# fallback, CONFIG_DISPATCH_TOKEN — a token that can # send a repository_dispatch to the config repo. on: push: - # main only. stlc preview/integrated/codegen branches never push to main. + # main only. the generator's preview, integrated and codegen branches never push to main. branches: [main] concurrency: @@ -31,13 +32,24 @@ permissions: jobs: dispatch: runs-on: ubuntu-latest - if: github.repository == 'sentdm/sent-dm-java-staging' + if: github.repository == 'sentdm/sent-dm-java' env: CONFIG_REPO: sentdm/sent-dm-sdk-pipeline + HAS_APP: ${{ secrets.SDK_APP_ID != '' && secrets.SDK_APP_PRIVATE_KEY != '' }} steps: + - name: Mint a pipeline token from the GitHub App + id: app + if: env.HAS_APP == 'true' + uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v3.3.0 + with: + app-id: ${{ secrets.SDK_APP_ID }} + private-key: ${{ secrets.SDK_APP_PRIVATE_KEY }} + owner: sentdm + repositories: sent-dm-sdk-pipeline + - name: Loop-guard and send reseal dispatch env: - DISPATCH_TOKEN: ${{ secrets.CONFIG_DISPATCH_TOKEN }} + DISPATCH_TOKEN: ${{ steps.app.outputs.token || secrets.CONFIG_DISPATCH_TOKEN }} HEAD_MSG: ${{ github.event.head_commit.message }} HEAD_AUTHOR_NAME: ${{ github.event.head_commit.author.name }} SHA: ${{ github.sha }} @@ -45,7 +57,7 @@ jobs: run: | set -euo pipefail - # Loop guard 1: skip the stlc "Build SDK" squash commit (it carries + # Loop guard 1: skip the generator's "Build SDK" squash commit (it carries # the Stainless-Generated-From trailer in its message). if printf '%s' "$HEAD_MSG" | grep -q 'Stainless-Generated-From'; then echo "Head commit is an stlc build — skipping reseal dispatch." diff --git a/.github/workflows/stlc-promote.yml b/.github/workflows/stlc-promote.yml deleted file mode 100644 index 55bdec00c..000000000 --- a/.github/workflows/stlc-promote.yml +++ /dev/null @@ -1,70 +0,0 @@ -name: Promote SDKs - -# Promote staging to production by fast-forwarding production `main` up to the -# staging trunk, preserving commit SHAs. Because the SHAs are preserved, -# production `main` and staging `main` stay identical and linear, the sealed -# custom-code commit stays an ancestor of both, and there is no divergence to -# heal on the next `stlc build`. -# -# Manual dispatch (workflow_dispatch): spec/codegen changes accumulate on -# staging `main`, and a maintainer promotes the batch in one fast-forward when -# ready to cut a release. Optionally gate each run behind a required-reviewer -# approval — see the `environment` note on the job below. release-please then -# opens its version/changelog PR on production on top. -on: - workflow_dispatch: {} - -permissions: - contents: read - -jobs: - promote: - runs-on: ubuntu-latest - if: github.repository == 'sentdm/sent-dm-java-staging' - # Optional: add required reviewers on each promote run before the fast-forward push. - # With no reviewers it only scopes secrets/variables and adds no gate, so the manual dispatch - # above is the only checkpoint. Remove this line if you don't use it. - environment: production - env: - PRODUCTION_REPO: sentdm/sent-dm-java - GH_TOKEN: ${{ secrets.PRODUCTION_REPO_TOKEN }} - steps: - - name: Check out staging - uses: actions/checkout@v6 - with: - fetch-depth: 0 - persist-credentials: false - - - name: Fetch production main - 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 content - id: diff - run: | - # After a release, production carries release-please's version/changelog - # commits that staging lacks. Ask whether merging staging into production - # would change production's tree: if not, production already has staging's content. - MERGED=$(git merge-tree --write-tree production/main origin/main) || MERGED=conflict - PRODUCTION_TREE=$(git rev-parse 'production/main^{tree}') - if [ "$MERGED" = "$PRODUCTION_TREE" ]; then - echo "Production already contains staging's content. 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/main is an ancestor of staging/main. If it - # isn't, the trunks have forked (someone advanced production out of - # band without back-syncing first) and a fast-forward 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." - exit 1 - fi - git push production origin/main:refs/heads/main - echo "Fast-forwarded production/main to staging/main." diff --git a/.github/workflows/stlc-sync-from-production.yml b/.github/workflows/stlc-sync-from-production.yml deleted file mode 100644 index 18f649a23..000000000 --- a/.github/workflows/stlc-sync-from-production.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Sync from production - -# Bring production's commits back onto staging `main` by fast-forwarding. -# This keeps staging and production identical and linear so the next `stlc build` -# reseals against the released state. -# -# Triggered by the production-side release dispatch and by a periodic poll. -on: - schedule: - # Polls for non-release production changes. If you take frequent - # community PRs, tighten this or add an eager `on: push: [main]` - # dispatch on production alongside the release one. - - cron: '17 */6 * * *' - workflow_dispatch: {} - repository_dispatch: - types: [prod-released] - -permissions: - contents: write - -concurrency: - group: stlc-sync-from-production - cancel-in-progress: true - -jobs: - sync: - runs-on: ubuntu-latest - if: github.repository == 'sentdm/sent-dm-java-staging' - env: - PRODUCTION_REPO: sentdm/sent-dm-java - steps: - - name: Check out staging - uses: actions/checkout@v6 - with: - fetch-depth: 0 - - - name: Fetch production main - run: | - # Production is public, so the built-in token reads it with no - # credential. If your production repo is private, add a remote with - # PRODUCTION_REPO_TOKEN instead (the same token the promote uses). - git remote add production "https://github.com/${PRODUCTION_REPO}.git" - git fetch production main - - - name: Check whether production has content staging lacks - id: diff - run: | - # Inverse of the promote guard: would merging production into - # staging change staging's tree? If not, staging already has - # production's content. - MERGED=$(git merge-tree --write-tree origin/main production/main) || MERGED=conflict - STAGING_TREE=$(git rev-parse 'origin/main^{tree}') - if [ "$MERGED" = "$STAGING_TREE" ]; then - echo "Staging already has production's content. Nothing to pull back." - echo "behind=false" >> "$GITHUB_OUTPUT" - else - echo "behind=true" >> "$GITHUB_OUTPUT" - fi - - - name: Sync production to staging (fast-forward) - if: steps.diff.outputs.behind == 'true' - run: | - # Refuse unless staging/main is an ancestor of production/main. If it - # isn't, the trunks have forked (staging advanced out of band while a - # production change was unsynced) and a fast-forward is unsafe. - # - # The trunk-sync lock (trunk-sync-lock.yml) is what normally - # prevents this by freezing staging merges until the back-sync lands. - if ! git merge-base --is-ancestor origin/main production/main; then - echo "::error title=Back-sync blocked::staging main is not an ancestor of production/main." - exit 1 - fi - git push origin production/main:refs/heads/main - echo "Fast-forwarded staging/main to production/main." diff --git a/.github/workflows/trigger-back-sync-on-release.yml b/.github/workflows/trigger-back-sync-on-release.yml deleted file mode 100644 index e246fb448..000000000 --- a/.github/workflows/trigger-back-sync-on-release.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Trigger staging back-sync on release - -# On a published release, notify the staging repo to sync from production immediately. -# This workflow is dispatch-only: it cannot write production or staging contents. -on: - release: - types: [published] - workflow_dispatch: {} - -permissions: - contents: read - -jobs: - notify: - runs-on: ubuntu-latest - if: github.repository == 'sentdm/sent-dm-java' - env: - STAGING_REPO: sentdm/sent-dm-java-staging - steps: - - name: Dispatch back-sync to staging - env: - DISPATCH_TOKEN: ${{ secrets.STAGING_DISPATCH_TOKEN }} - REF_NAME: ${{ github.ref_name }} - run: | - set -euo pipefail - [ -n "${DISPATCH_TOKEN:-}" ] || { echo "STAGING_DISPATCH_TOKEN not set" >&2; exit 1; } - payload=$(jq -n --arg ref "$REF_NAME" '{event_type:"prod-released",client_payload:{ref:$ref}}') - code=$(curl -sS -o /tmp/dispatch.txt -w '%{http_code}' -X POST \ - -H "Authorization: Bearer ${DISPATCH_TOKEN}" \ - -H "Accept: application/vnd.github+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - "https://api.github.com/repos/${STAGING_REPO}/dispatches" \ - -d "$payload") - if [ "$code" = "204" ]; then - echo "Back-sync dispatched to ${STAGING_REPO}." - else - echo "Dispatch failed (HTTP $code)" >&2; cat /tmp/dispatch.txt >&2; exit 1 - fi diff --git a/.github/workflows/trunk-sync-lock.yml b/.github/workflows/trunk-sync-lock.yml deleted file mode 100644 index 2f85e3aa3..000000000 --- a/.github/workflows/trunk-sync-lock.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: Trunk sync lock - -# Posts a `trunk-synced` commit status to open PRs targeting staging `main`: -# red while production is ahead of staging (a release hasn't been synced back -# yet), green once they are in sync. -# -# You should make `trunk-synced` a required status check on staging `main` -# to block merges onto a stale trunk during the release -# window. -# -# This only gates PRs, not direct pushes. The back-sync bypasses this check -# by pushing to staging `main` directly. If staging `main` also requires a pull -# request, give the back-sync's identity ruleset-bypass so it can push. Never -# route the back-sync through a PR gated by this check, or it deadlocks. -# -# First-run note: GitHub treats a status check as "required" only once it has -# been reported at least once. At setup time staging and production are -# identical, so trigger this workflow once (push a PR or use the Run workflow -# button) BEFORE adding `trunk-synced` to the required checks, so the first -# status is green rather than missing. -on: - pull_request: - branches: [main] - types: [opened, synchronize, reopened] - workflow_run: - workflows: ["Sync from production"] - types: [completed] - repository_dispatch: - types: [prod-released] - workflow_dispatch: {} - schedule: - - cron: '*/30 * * * *' - -permissions: - contents: read - statuses: write - pull-requests: read - -jobs: - lock: - runs-on: ubuntu-latest - if: github.repository == 'sentdm/sent-dm-java-staging' - env: - PRODUCTION_REPO: sentdm/sent-dm-java - GH_TOKEN: ${{ github.token }} - steps: - - uses: actions/checkout@v6 - with: - fetch-depth: 0 - persist-credentials: false - - name: Evaluate sync state and post status to open main PRs - run: | - set -euo pipefail - # Production is public; the built-in token reads it with no credential. - git remote add production "https://github.com/${PRODUCTION_REPO}.git" - git fetch --no-tags production main - if git merge-base --is-ancestor production/main HEAD; then - state=success; desc="staging main is in sync with production" - else - state=failure; desc="production is ahead — wait for the back-sync before merging" - fi - echo "trunk-synced => $state ($desc)" - shas=$(gh pr list --repo "$GITHUB_REPOSITORY" --base main --state open --json headRefOid --jq '.[].headRefOid') - if [ -z "$shas" ]; then echo "no open PRs targeting main"; exit 0; fi - for sha in $shas; do - gh api -X POST "repos/$GITHUB_REPOSITORY/statuses/$sha" \ - -f state="$state" -f context="trunk-synced" -f description="$desc" >/dev/null - echo "posted trunk-synced=$state to $sha" - done