Skip to content
Merged
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
42 changes: 0 additions & 42 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,45 +128,3 @@ jobs:

- name: Build package
run: yarn prepare

release:
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
needs: [lint, typescript, unit-tests, build-package]
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
submodules: recursive
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
# 22.22.2's bundled npm is broken in the GH toolcache (missing `promise-retry`)
node-version: 22.21.0

- name: Restore node_modules
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: |
node_modules
example/node_modules
key: node-modules-${{ hashFiles('yarn.lock') }}

- name: Upgrade npm for OIDC trusted publishing
# not @latest: npm 12 needs node >=22.22.2, and this job pins 22.21 (broken toolcache npm)
run: npm install -g npm@11

- name: Configure git
run: |
git config --global user.email "julien.brayere@obitrain.com"
git config --global user.name "GitHub Actions"

- name: Release
run: yarn release --ci --npm.skipChecks
env:
NPM_CONFIG_PROVENANCE: true
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
91 changes: 91 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Releases only when a release/<version> PR merges (open one with scripts/release-pr.sh): npm publish via
# trusted publishing (the npmjs.com trusted publisher must point at this file), tag v<version>, GitHub
# release with the PR description as notes. Dispatch re-runs an existing release; every step is idempotent.
name: Release

on:
pull_request:
types: [closed]
branches: [main]
workflow_dispatch:
inputs:
version:
description: Existing version to re-publish (e.g. 1.5.0)
required: true

permissions:
contents: write
id-token: write

jobs:
release:
if: >-
github.event_name == 'workflow_dispatch' ||
(github.event.pull_request.merged == true &&
github.event.pull_request.head.repo.full_name == github.repository &&
startsWith(github.event.pull_request.head.ref, 'release/'))
runs-on: ubuntu-latest
steps:
- name: Resolve version
id: v
env:
HEAD_REF: ${{ github.event.pull_request.head.ref }}
INPUT_VERSION: ${{ inputs.version }}
run: |
VERSION="${INPUT_VERSION:-${HEAD_REF#release/}}"
VERSION="${VERSION#v}"
[[ $VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$ ]] || { echo "not a semver: '$VERSION'"; exit 1; }
echo "version=$VERSION" >> "$GITHUB_OUTPUT"

- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
ref: ${{ inputs.version && format('v{0}', steps.v.outputs.version) || github.event.pull_request.merge_commit_sha }}
submodules: recursive
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
# 22.22.2's bundled npm is broken in the GH toolcache (missing `promise-retry`)
node-version: 22.21.0
registry-url: https://registry.npmjs.org

- name: Upgrade npm for OIDC trusted publishing
# not @latest: npm 12 needs node >=22.22.2
run: npm install -g npm@11

- run: yarn install --immutable

- name: package.json must match the release version
env:
VERSION: ${{ steps.v.outputs.version }}
run: test "$(node -p "require('./package.json').version")" = "$VERSION"

- name: Build package
run: yarn prepare

- name: Publish to npm
env:
VERSION: ${{ steps.v.outputs.version }}
run: |
if npm view "$(node -p "require('./package.json').name")@$VERSION" version >/dev/null 2>&1; then
echo "$VERSION already on npm, skipping"
else
npm publish --provenance --access public
fi

- name: Tag and GitHub release
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ steps.v.outputs.version }}
PR_BODY: ${{ github.event.pull_request.body }}
run: |
TAG="v$VERSION"
git ls-remote --exit-code --tags origin "refs/tags/$TAG" >/dev/null || { git tag "$TAG" && git push origin "$TAG"; }
if gh release view "$TAG" >/dev/null 2>&1; then echo "release $TAG exists"; exit 0; fi
if [ -n "$PR_BODY" ]; then
printf '%s\n' "$PR_BODY" > notes.md
gh release create "$TAG" --title "$TAG" --notes-file notes.md
else
gh release create "$TAG" --title "$TAG" --generate-notes
fi
11 changes: 7 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,17 @@ Our pre-commit hooks verify that the linter and tests pass when committing.

### Publishing to npm

We use [release-it](https://github.com/release-it/release-it) to make it easier to publish new versions. It handles common tasks like bumping version based on semver, creating tags and releases etc.

To publish new versions, run the following:
Merging to `main` never publishes. To release, open a release PR:

```sh
yarn release
yarn release 1.5.0
```

It bumps `package.json` on a `release/1.5.0` branch, adds a `CHANGELOG.md` entry and opens a PR whose
description (drafted from the commits since the last tag) becomes the release notes — edit it before
merging. Merging the PR publishes to npm, tags `v1.5.0` and creates the GitHub release
(`.github/workflows/release.yml`).

### Scripts

The `package.json` file contains various scripts for common tasks:
Expand Down
23 changes: 1 addition & 22 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib nitrogen",
"prepare": "bob build",
"nitrogen": "nitrogen",
"release": "release-it",
"release": "bash scripts/release-pr.sh",
"bootstrap": "git submodule update --init --recursive && yarn example install",
"pod:install": "cd example/ios && pod install",
"pod:deintegrate": "cd example/ios && pod deintegrate && rm -rf Pods && rm Podfile.lock"
Expand Down Expand Up @@ -79,7 +79,6 @@
"@react-native/babel-preset": "0.86.3",
"@react-native/eslint-config": "0.86.3",
"@react-native/jest-preset": "0.86.3",
"@release-it/conventional-changelog": "12.0.2",
"@types/jest": "^30.0.0",
"@types/react": "^19.2.18",
"commitlint": "^21.2.3",
Expand All @@ -97,7 +96,6 @@
"react-native": "0.86.3",
"react-native-builder-bob": "^0.43.1",
"react-native-nitro-modules": "^0.37.1",
"release-it": "^21.1.0",
"turbo": "^2.11.2",
"typescript": "^6.0.3"
},
Expand All @@ -122,25 +120,6 @@
"@commitlint/config-conventional"
]
},
"release-it": {
"git": {
"commitMessage": "chore: release ${version} [skip ci]",
"tagName": "v${version}"
},
"npm": {
"publish": true
},
"github": {
"release": true
},
"plugins": {
"@release-it/conventional-changelog": {
"preset": {
"name": "angular"
}
}
}
},
"prettier": {
"quoteProps": "consistent",
"singleQuote": true,
Expand Down
33 changes: 33 additions & 0 deletions scripts/release-pr.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/bash
# DESCRIPTION: Open a release PR (release/<version>): bumps package.json, drafts notes from the commits
# since the last tag. Merging the PR publishes to npm and creates the GitHub release;
# the PR description becomes the release notes, so edit it before merging.
# USAGE: scripts/release-pr.sh <version>
# EXAMPLES:
# scripts/release-pr.sh 1.5.0
set -euo pipefail

version=${1:?usage: scripts/release-pr.sh <version>}
version=${version#v}
[[ $version =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$ ]] || { echo "not a semver: $version" >&2; exit 1; }
[[ -z $(git status --porcelain --untracked-files=no) ]] || { echo "working tree has changes" >&2; exit 1; }

git fetch -q origin main --tags
prev=$(git describe --tags --abbrev=0 --match 'v*' origin/main 2>/dev/null || true)
notes=$(git log --no-merges --format='- %s' "${prev:+$prev..}origin/main" | grep -vE '^- chore(\(release\))?: release ' || true)
[[ -n $notes ]] || { echo "nothing to release since ${prev:-the first commit}" >&2; exit 1; }

git switch -q --no-track -c "release/$version" origin/main
npm version "$version" --no-git-tag-version --allow-same-version >/dev/null
if [[ -f CHANGELOG.md ]]; then
# new entry goes above the latest "## " section, i.e. under the "# Changelog" title
entry=$(mktemp)
printf '## %s (%s)\n\n%s\n\n' "$version" "$(date +%Y-%m-%d)" "$notes" >"$entry"
awk -v f="$entry" '!done && /^## / { while ((getline l < f) > 0) print l; done = 1 } { print }
END { if (!done) { print ""; while ((getline l < f) > 0) print l } }' CHANGELOG.md >CHANGELOG.md.tmp
mv CHANGELOG.md.tmp CHANGELOG.md
rm -f "$entry"
fi
git commit -qam "chore: release $version"
git push -q -u origin "release/$version"
gh pr create --base main --head "release/$version" --title "chore: release $version" --body "$notes"
Loading
Loading