ci: auto-scaffold release blog post every 5th tag (#638)

Adds a workflow that fires on every v* tag push, computes the window
since the latest release post's anchor version in the sencho-website
repo, and (when the window reaches 5) opens a draft PR in
sencho-website with a fully pre-filled scaffold: grouped
ChangelogSection blocks parsed from CHANGELOG.md, version field set to
the new anchor, and a checklist body covering intro, screenshot, docs
link, and reading time. No auto-publish; the human writes the
narrative.

Uses the same sencho-token-app GitHub App as release-please, with its
installation extended to include sencho-website.
This commit is contained in:
Anso
2026-04-16 16:16:04 -04:00
committed by GitHub
parent 1e97acf281
commit ce2fb1a5a0
3 changed files with 485 additions and 0 deletions
+122
View File
@@ -0,0 +1,122 @@
name: Release Blog Scaffold
# Fires on every v* tag push. Computes whether this tag completes the next
# every-5th-release window (source of truth = the latest release post's
# `version` field in the sencho-website repo). If yes, opens a DRAFT PR in
# sencho-website containing a pre-filled blog post scaffold; a human writes
# the narrative, adds the screenshot, and marks the PR ready.
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag:
description: 'Tag to scaffold against (e.g. v0.58.0). Must already exist.'
required: true
type: string
permissions:
contents: read
jobs:
scaffold:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
# Same App-token pattern as release-please.yml. The app's installation
# must include both Sencho and sencho-website for the push + PR to work.
- name: Generate GitHub App installation token
id: app-token
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: |
Sencho
sencho-website
permission-contents: write
permission-pull-requests: write
- name: Resolve target tag
id: target
run: |
set -euo pipefail
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
tag="${{ inputs.tag }}"
else
tag="${GITHUB_REF_NAME}"
fi
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
echo "Resolved target tag: ${tag}"
- name: Check out Sencho (full history for tags)
uses: actions/checkout@v6
with:
fetch-depth: 0
fetch-tags: true
- name: Check out sencho-website
uses: actions/checkout@v6
with:
repository: ${{ github.repository_owner }}/sencho-website
token: ${{ steps.app-token.outputs.token }}
path: website-repo
fetch-depth: 1
- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: '20'
- name: Run scaffold script
id: scaffold
run: |
set -euo pipefail
node .github/scripts/scaffold-release-post.mjs \
--tag "${{ steps.target.outputs.tag }}" \
--changelog CHANGELOG.md \
--website website-repo
- name: Commit and open draft PR in sencho-website
if: steps.scaffold.outputs.scaffold == 'true'
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
TAG: ${{ steps.target.outputs.tag }}
BRANCH: ${{ steps.scaffold.outputs.branch }}
POST_PATH: ${{ steps.scaffold.outputs.post_path }}
BODY_FILE: ${{ steps.scaffold.outputs.body_file }}
OWNER: ${{ github.repository_owner }}
run: |
set -euo pipefail
cd website-repo
# Short-circuit if a scaffold PR for this branch already exists (e.g.,
# a manual workflow_dispatch retry against the same tag).
existing=$(gh pr list \
--repo "${OWNER}/sencho-website" \
--head "${BRANCH}" \
--state open \
--json number --jq '.[0].number // empty')
if [ -n "${existing}" ]; then
echo "PR already exists for ${BRANCH} (#${existing}); nothing to do."
exit 0
fi
git config user.name "sencho-release-bot[bot]"
git config user.email "sencho-release-bot[bot]@users.noreply.github.com"
git checkout -B "${BRANCH}"
git add "${POST_PATH}" src/data/blog/index.ts
git commit -m "chore: scaffold release post for ${TAG}"
git push -u origin "${BRANCH}" --force-with-lease
gh pr create \
--repo "${OWNER}/sencho-website" \
--base main \
--head "${BRANCH}" \
--title "chore: scaffold release post for ${TAG}" \
--body-file "${BODY_FILE}" \
--draft
- name: Report skip
if: steps.scaffold.outputs.scaffold != 'true'
run: |
echo "No scaffold this run. Window did not reach the next every-5th-release anchor."