Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions .github/workflows/prepare-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
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:
ref: master
token: ${{ secrets.GITHUB_TOKEN }}
Comment on lines +23 to +26

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prepare has the same unpinned checkout.

What the code does
Checkout uses the dispatch ref; create-pull-request commits that working tree onto release/SDK-….

What the spec says
Prepare is the first step of a master-based release; publish then tags master.

Why it conflicts
Running Prepare from a feature branch opens a PR whose contents are that branch plus the bump, not “master + version bump”.

Suggested action
Pin Prepare to master (or otherwise guarantee the PR base and file contents are default-branch HEAD).


- 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"

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 }}"

- 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-file "$RUNNER_TEMP/release-notes.md"
fi
76 changes: 76 additions & 0 deletions .github/workflows/publish-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
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
with:
ref: master

- name: Verify release is ready
run: |
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
Comment on lines +23 to +32

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Publish does not constrain git to master, so it neither verifies merge nor tags master.

This comment also includes lines 50 -> 57

What the code does
actions/checkout@v4 has no ref. The “merged” check is grep -qF "## $VERSION" CHANGELOG.md on whatever ref the operator picked in “Use workflow from”. The tag is created with --target "$(git rev-parse HEAD)". The step is still named “tag main”.

What the spec says
“Verifies the prepare-release PR has been merged (checks CHANGELOG on master)” and “Publishes the draft release and creates the tag on master at this moment.”

Why it conflicts
workflow_dispatch checks out the selected branch, not the default branch. The unmerged prepare branch already contains## $version, so the grep passes without a merge. grep -qF "## 3.1.0" also matches a historical ## 3.1.0 or a prefix of ## 3.1.0-rc.1. If gh release create --draft already created a tag at prepare time, GitHub’s target_commitish is unused once the tag exists, so publish may not retarget.

Suggested action
Make publish (and prepare) operate on master only, and make the merge/version/tag gate actually prove “this version is on master at HEAD” before tagging.


- 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 }}"
Loading