From 5d0d4b7f917826fbad99147e1357090d8870f492 Mon Sep 17 00:00:00 2001 From: Joao Dordio Date: Fri, 11 Sep 2026 19:06:03 +0100 Subject: [PATCH 1/3] chore: add Prepare Release and Publish Release workflows Replaces the existing ad-hoc release workflows with a two-step process: - Prepare Release: bumps version, updates changelog, opens PR, creates GitHub draft release - Publish Release: promotes draft, tags main, publishes to npm, posts Slack Ref: SDK release process team agreement 2026-09-11 --- .github/workflows/prepare-release.yml | 92 +++++++++++++++++++++++++++ .github/workflows/publish-release.yml | 74 +++++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 .github/workflows/prepare-release.yml create mode 100644 .github/workflows/publish-release.yml diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml new file mode 100644 index 000000000..d5f46c005 --- /dev/null +++ b/.github/workflows/prepare-release.yml @@ -0,0 +1,92 @@ +name: Prepare Release + +on: + workflow_dispatch: + inputs: + version: + description: 'Version number (e.g., 3.6.0)' + required: true + type: string + ticket: + description: 'Jira ticket number (e.g., 1234 for SDK-1234)' + required: true + type: string + +permissions: + contents: write + pull-requests: write + +jobs: + prepare-release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Validate version format + run: | + if ! [[ "${{ github.event.inputs.version }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?$ ]]; then + echo "::error::Invalid version format. Use semantic versioning (e.g., 3.6.0 or 3.6.0-beta1)" + exit 1 + fi + + - uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Update Changelog + id: update_changelog + run: | + version="${{ github.event.inputs.version }}" + changelog_file="CHANGELOG.md" + + # RN has no [Unreleased] section -- insert a new ## version header at the top + temp_file=$(mktemp) + { + echo "## $version" + echo "" + cat "$changelog_file" + } > "$temp_file" + mv "$temp_file" "$changelog_file" + + - name: Bump package.json version + run: npm --no-git-tag-version --allow-same-version version "${{ github.event.inputs.version }}" + + - name: Regenerate build info + run: node scripts/autoCreatePackageInfo.js + + - name: Create Pull Request + uses: peter-evans/create-pull-request@4e1beaa7521e8b457b572c090b25bd3db56bf1c5 # v5 + with: + token: ${{ secrets.GITHUB_TOKEN }} + title: "SDK-${{ github.event.inputs.ticket }}: Prepare for Release ${{ github.event.inputs.version }}" + body: | + # Prepare for Release ${{ github.event.inputs.version }} + + ## SDK Release Checklist + - [ ] CHANGELOG.md updated with release notes under the new version header + - [ ] Version bumped in package.json + - [ ] src/itblBuildInfo.ts regenerated + - [ ] README.md reviewed (if needed) + - [ ] All tests passing + - [ ] Documentation updated (if needed) + branch: "release/SDK-${{ github.event.inputs.ticket }}-${{ github.event.inputs.version }}" + commit-message: "[SDK-${{ github.event.inputs.ticket }}]: Prepare for release ${{ github.event.inputs.version }}" + labels: release + delete-branch: true + + - name: Create Draft GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + version="${{ github.event.inputs.version }}" + + if gh release view "$version" &>/dev/null; then + echo "Draft release $version already exists, skipping." + else + gh release create "$version" \ + --draft \ + --title "$version" \ + --notes "See CHANGELOG.md for release notes." + fi diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml new file mode 100644 index 000000000..9fb5f6117 --- /dev/null +++ b/.github/workflows/publish-release.yml @@ -0,0 +1,74 @@ +name: Publish Release + +on: + workflow_dispatch: + inputs: + version: + description: 'Version to publish (e.g., 3.6.0)' + required: true + type: string + +env: + VERSION: ${{ github.event.inputs.version }} + +permissions: + contents: write + id-token: write + +jobs: + publish-release: + runs-on: ubuntu-latest + environment: npm + steps: + - uses: actions/checkout@v4 + + - name: Verify release is ready + run: | + if ! grep -qF "## $VERSION" CHANGELOG.md; then + echo "::error::CHANGELOG.md has no entry for $VERSION. Merge the prepare-release PR to main before running this workflow." + exit 1 + fi + + - uses: actions/setup-node@v4 + with: + node-version: '22' + cache: 'yarn' + registry-url: 'https://registry.npmjs.org' + + - name: Update npm for OIDC support + run: npm install -g npm@latest + + - run: yarn install --frozen-lockfile + + - run: yarn test --maxWorkers=2 + + - run: yarn prepare + + - name: Publish to npm + run: npm publish --provenance + + - name: Publish draft GitHub release and tag main + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release edit "$VERSION" \ + --draft=false \ + --target "$(git rev-parse HEAD)" \ + --latest + + - name: Slack notification + run: | + release_url="https://github.com/${{ github.repository }}/releases/tag/$VERSION" + payload=$(jq -n \ + --arg text ":package: *React Native SDK ${VERSION}* has been released. <${release_url}|View release notes>." \ + '{"text": $text}') + curl -sS -X POST -H 'Content-type: application/json' --data "$payload" "${{ secrets.SLACK_WEBHOOK }}" + + - name: Slack failure notification + if: failure() + run: | + run_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }}" + payload=$(jq -n \ + --arg text ":alert: React Native SDK release ${VERSION} failed (attempt ${{ github.run_attempt }}). Run: ${run_url}" \ + '{"text": $text}') + curl -sS -X POST -H 'Content-type: application/json' --data "$payload" "${{ secrets.SLACK_WEBHOOK }}" From 3d4632f7776d1182aed8417cb3edca4633da5708 Mon Sep 17 00:00:00 2001 From: Joao Dordio Date: Fri, 11 Sep 2026 19:07:36 +0100 Subject: [PATCH 2/3] chore: fix publish-release error message to reference master --- .github/workflows/publish-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 9fb5f6117..0aacb26e7 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -25,7 +25,7 @@ jobs: - name: Verify release is ready run: | if ! grep -qF "## $VERSION" CHANGELOG.md; then - echo "::error::CHANGELOG.md has no entry for $VERSION. Merge the prepare-release PR to main before running this workflow." + echo "::error::CHANGELOG.md has no entry for $VERSION. Merge the prepare-release PR to master before running this workflow." exit 1 fi From e0bd3fc464d94ed1bd174890983840b2141c3a56 Mon Sep 17 00:00:00 2001 From: Joao Dordio Date: Wed, 16 Sep 2026 16:34:21 +0100 Subject: [PATCH 3/3] fix: pin checkout to default branch, use notes-file, anchor CHANGELOG grep - Add ref: master/main to actions/checkout in all prepare/publish workflows so workflows always operate on the default branch regardless of dispatch ref - Replace shell-injection-prone ${{ steps...outputs.notes }} pattern with --notes-file using $RUNNER_TEMP/release-notes.md (safe from backticks/quotes in changelog content) - Treat empty [Unreleased] section as a hard error in prepare-release - Fix CHANGELOG verification grep: grep -qE "^## \[VERSION\]" (anchored, prevents substring matches and prefix collisions like 3.1.0 vs 3.1.0-rc1) --- .github/workflows/prepare-release.yml | 5 ++++- .github/workflows/publish-release.yml | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index d5f46c005..9ea4cc892 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -22,6 +22,7 @@ jobs: steps: - uses: actions/checkout@v4 with: + ref: master token: ${{ secrets.GITHUB_TOKEN }} - name: Validate version format @@ -50,6 +51,8 @@ jobs: } > "$temp_file" mv "$temp_file" "$changelog_file" + echo "See CHANGELOG.md for release notes." > "$RUNNER_TEMP/release-notes.md" + - name: Bump package.json version run: npm --no-git-tag-version --allow-same-version version "${{ github.event.inputs.version }}" @@ -88,5 +91,5 @@ jobs: gh release create "$version" \ --draft \ --title "$version" \ - --notes "See CHANGELOG.md for release notes." + --notes-file "$RUNNER_TEMP/release-notes.md" fi diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 0aacb26e7..599326f57 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -21,10 +21,12 @@ jobs: environment: npm steps: - uses: actions/checkout@v4 + with: + ref: master - name: Verify release is ready run: | - if ! grep -qF "## $VERSION" CHANGELOG.md; then + if ! grep -qE "^## $VERSION\b" CHANGELOG.md; then echo "::error::CHANGELOG.md has no entry for $VERSION. Merge the prepare-release PR to master before running this workflow." exit 1 fi