From 4ee8629ce5db0b392b658c6ca188270e183bdc0d Mon Sep 17 00:00:00 2001 From: Fabian Jocks <24557998+iamfj@users.noreply.github.com> Date: Thu, 23 Apr 2026 09:18:35 +0200 Subject: [PATCH 1/2] ci(release): use app token and list included PRs --- .github/workflows/promote-next-to-main.yml | 54 +++++++++++++++++++--- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/.github/workflows/promote-next-to-main.yml b/.github/workflows/promote-next-to-main.yml index b2c1b712..d14cf935 100644 --- a/.github/workflows/promote-next-to-main.yml +++ b/.github/workflows/promote-next-to-main.yml @@ -31,8 +31,17 @@ jobs: - name: Fetch main and next refs run: git fetch origin main next + - name: Generate linearis-bot app token + id: app-token + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ secrets.RELEASE_APP_ID }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + - name: Build PR metadata id: meta + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} shell: bash run: | set -euo pipefail @@ -40,10 +49,43 @@ jobs: version=$(node -p "require('./package.json').version.replace(/-next\\.\\d+$/, '')") title="release ${version} to stable channel" compare_url="https://github.com/${GITHUB_REPOSITORY}/compare/main...next" + owner="${GITHUB_REPOSITORY%/*}" + repo="${GITHUB_REPOSITORY#*/}" + + mapfile -t commit_shas < <(git rev-list --no-merges origin/main..origin/next) + + declare -A seen_prs=() + included_prs="" + + for sha in "${commit_shas[@]}"; do + response=$(gh api graphql \ + -f owner="$owner" \ + -f repo="$repo" \ + -f oid="$sha" \ + -f query='query($owner: String!, $repo: String!, $oid: GitObjectID!) { repository(owner: $owner, name: $repo) { object(oid: $oid) { ... on Commit { associatedPullRequests(first: 10) { nodes { number title url author { login } } } } } } }' \ + 2>/dev/null || true) + + if [ -z "$response" ]; then + continue + fi + + while IFS=$'\t' read -r number pr_title pr_url pr_author; do + if [ -z "$number" ] || [ -n "${seen_prs[$number]:-}" ]; then + continue + fi + + seen_prs[$number]=1 + + if [ -z "$pr_author" ] || [ "$pr_author" = "null" ]; then + pr_author="unknown" + fi + + included_prs+="- [#${number}](${pr_url}) ${pr_title} by @${pr_author} — thanks @${pr_author}!\n" + done < <(printf '%s' "$response" | jq -r '.data.repository.object.associatedPullRequests.nodes[]? | [.number, .title, .url, .author.login] | @tsv') + done - commits=$(git log --no-merges --pretty='- %h %s' origin/main..origin/next | head -n 200) - if [ -z "$commits" ]; then - commits="- (no new commits; branches currently aligned)" + if [ -z "$included_prs" ]; then + included_prs="- (no included pull requests found; branches may be aligned)" fi { @@ -57,8 +99,8 @@ jobs: echo "## Target stable version" echo "\\`$version\\`" echo - echo "## Included commits (next ahead of main)" - echo "$commits" + echo "## Included pull requests (next ahead of main)" + printf '%b\n' "$included_prs" echo echo "## Compare" echo "$compare_url" @@ -71,7 +113,7 @@ jobs: - name: Upsert promotion PR env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} shell: bash run: | set -euo pipefail From db27e148bc95acb610e8dea6471e14896e13be26 Mon Sep 17 00:00:00 2001 From: Fabian Jocks <24557998+iamfj@users.noreply.github.com> Date: Thu, 23 Apr 2026 09:31:47 +0200 Subject: [PATCH 2/2] fix(ci): address review feedback for release and history guards --- .github/workflows/ci.yml | 4 ++-- .releaserc.cjs | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4f5e103d..a0d205a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,7 +113,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | base_ref="origin/${GITHUB_BASE_REF:-main}" - plan_files=$(git log "$base_ref"...HEAD \ + plan_files=$(git log "$base_ref"..HEAD \ --diff-filter=A --name-only --pretty=format: \ -- 'docs/plans/*.md' | sed '/^$/d') @@ -164,7 +164,7 @@ jobs: fi base_ref="origin/${GITHUB_BASE_REF:-main}" - output=$(git log "$base_ref"...HEAD --name-status --pretty=format: -- CHANGELOG.md | sed '/^$/d') + output=$(git log "$base_ref"..HEAD --name-status --pretty=format: -- CHANGELOG.md | sed '/^$/d') if [ -n "$output" ]; then echo "::error::CHANGELOG.md is release-workflow-owned and must not appear in PR branch history" diff --git a/.releaserc.cjs b/.releaserc.cjs index 39398d88..bd128607 100644 --- a/.releaserc.cjs +++ b/.releaserc.cjs @@ -15,7 +15,10 @@ module.exports = { ["@semantic-release/npm", { npmPublish: false, pkgRoot: "." }], [ "@semantic-release/exec", - { publishCmd: "npx clean-publish --access public -- --provenance" }, + { + publishCmd: + 'npx clean-publish --access public --tag $( [ "$GITHUB_REF_NAME" = "next" ] && echo next || echo latest ) -- --provenance', + }, ], ["@semantic-release/github", { successComment: false, failComment: false }], [