Files
nexu-io--open-design/.github/workflows/bake-plugin-previews-release.yml
wehub-resource-sync 070959e133
landing-page-staging / Deploy landing page to staging (push) Has been skipped
landing-page-ci / Validate landing page (push) Failing after 4s
visual-baseline / Capture visual baselines (push) Has been cancelled
bake-plugin-previews / Bake plugin previews (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:00:47 +08:00

123 lines
5.8 KiB
YAML

name: bake-plugin-previews-release
# Release-cut full bake (spec slice 3). On a push to a release/** branch, render
# every preview (hash-skip reuses unchanged), publish the immutable clips to R2,
# and commit the authoritative manifest snapshot onto the release branch. The
# manifest then flows to main via the normal non-squash release back-merge.
#
# Bumping BAKE_VERSION at release time is the explicit lever to refresh shared-
# input changes (fonts / web CSS / design systems / renderer) that per-file
# triggers cannot detect — a full sweep alone would reuse, not re-render, them.
on:
push:
branches: ['release/**']
paths-ignore:
- 'data/plugin-previews/**' # our own manifest commit must not re-trigger
workflow_dispatch: {}
permissions:
contents: write # commit the authoritative manifest onto the release branch
concurrency:
group: bake-plugin-previews-release-${{ github.ref }}
cancel-in-progress: false
jobs:
bake:
name: Bake plugin previews (release cut)
# `push` is already limited to release/**, but `workflow_dispatch` can be run
# from any ref. The commit step pushes the authoritative manifest to the
# triggering ref with contents:write, so a dispatch on `main` would write
# straight to main and bypass the release back-merge/review path. Hard-gate
# the whole job to release branches.
if: ${{ startsWith(github.ref, 'refs/heads/release/') }}
runs-on: ubuntu-24.04
timeout-minutes: 90
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
with:
ref: ${{ github.ref }}
fetch-depth: 0
# Read-only clone with the default token, but do NOT persist it as a
# github.com credential. release/** is guarded by the "Protected
# branches (preview/*, release/v*)" ruleset (deletion / non_fast_forward
# / pull_request), so a direct push is rejected (GH013) unless the pusher
# is a bypass actor. github-actions[bot] is NOT one — so the manifest
# writeback below force-authenticates as open-design-bot, which IS a
# bypass actor, via an explicit token URL. A persisted github.token
# extraheader would override that inline token on push (see #5357), so
# drop it; nothing between here and the push needs the persisted cred.
persist-credentials: false
- name: Loop guard — skip the bake bot's own manifest commit
id: guard
# Belt-and-suspenders with paths-ignore above: also skip when the head
# commit was authored by the bake bot, so the manifest writeback cannot
# re-trigger this workflow.
run: |
AUTHOR="$(git log -1 --format='%ae')"
echo "head commit author: $AUTHOR"
if [ "$AUTHOR" = "bot@open-design.ai" ]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "head commit is the bake bot's manifest commit — skipping to break the loop"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: Setup workspace
if: ${{ steps.guard.outputs.skip != 'true' }}
uses: ./.github/actions/setup-workspace
- name: Render previews + publish clips to R2
if: ${{ steps.guard.outputs.skip != 'true' }}
uses: ./.github/actions/bake-previews
with:
upload: 'true'
r2-access-key-id: ${{ secrets.CLOUDFLARE_R2_REPOSITORY_ASSETS_AK }}
r2-secret-access-key: ${{ secrets.CLOUDFLARE_R2_REPOSITORY_ASSETS_SK }}
r2-bucket: ${{ secrets.CLOUDFLARE_R2_REPOSITORY_ASSETS_BUCKET }}
r2-endpoint: ${{ secrets.CLOUDFLARE_R2_REPOSITORY_ASSETS_URL }}
- name: Mint the open-design-bot token for the release-branch push
if: ${{ steps.guard.outputs.skip != 'true' }}
id: bot
# open-design-bot (app id 3640364) is a bypass actor on the
# "Protected branches (preview/*, release/v*)" ruleset, so its push clears
# the pull_request rule that rejects github-actions[bot] (GH013). The
# release bake pushes the manifest directly (it then rides the non-squash
# release back-merge to main). Minted here — after the long render, not at
# job start — because an App token lives ~1h and the render can run long.
uses: actions/create-github-app-token@v3.2.0
with:
client-id: ${{ secrets.BOT_APP_CLIENT_ID }}
private-key: ${{ secrets.BOT_APP_PRIVATE_KEY }}
owner: nexu-io
repositories: open-design
- name: Commit the authoritative manifest onto the release branch
if: ${{ steps.guard.outputs.skip != 'true' }}
env:
BOT_TOKEN: ${{ steps.bot.outputs.token }}
run: |
OLD=data/plugin-previews/manifest.json
NEW=.tmp/plugin-previews/manifest.json
# Capture on its own line so `set -e` surfaces a helper error (exit 2)
# rather than command substitution swallowing it into the test.
diff_result="$(node scripts/plugin-previews-diff.mjs "$OLD" "$NEW")"
case "$diff_result" in
changed) ;;
unchanged) echo "previews unchanged — nothing to commit"; exit 0 ;;
*) echo "unexpected diff result: '$diff_result'" >&2; exit 1 ;;
esac
cp "$NEW" "$OLD"
git config user.name "open-design-bot"
git config user.email "bot@open-design.ai"
git add "$OLD"
git commit -m "chore(plugin-previews): refresh baked preview manifest (release cut)"
# Push as open-design-bot (a ruleset bypass actor) via an explicit token
# URL. A plain `git push origin` would authenticate as github-actions[bot]
# and be rejected by the release/** pull_request rule (GH013).
git push "https://x-access-token:${BOT_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "HEAD:${GITHUB_REF#refs/heads/}"