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
40 changes: 5 additions & 35 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,6 @@
name: Release

on:
workflow_dispatch:
inputs:
release_tag:
description: 'Existing release tag to publish (leave empty for a dry run)'
required: false
type: string
pull_request:
branches:
- main
paths:
- '.github/actions/setup/**'
- '.github/workflows/ci.yml'
- '.github/workflows/release.yml'
- 'package.json'
- 'scripts/check-package.mjs'
- 'scripts/check-release.mjs'
- 'tsconfig.build.json'
push:
tags:
- 'v*'
Expand All @@ -31,32 +14,24 @@ concurrency:

jobs:
verify:
if: github.event_name != 'pull_request'
uses: ./.github/workflows/ci.yml

package:
needs: verify
if: >-
always() &&
(github.event_name == 'pull_request' || needs.verify.result == 'success')
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.0.0
with:
fetch-depth: 0
ref: ${{ inputs.release_tag || github.ref }}

- name: Setup
uses: ./.github/actions/setup

- name: Validate release tag
if: github.event_name == 'push' || inputs.release_tag != ''
env:
RELEASE_TAG: ${{ github.event_name == 'push' && github.ref_name || inputs.release_tag }}
run: |
git merge-base --is-ancestor HEAD origin/main
node scripts/check-release.mjs "$RELEASE_TAG"
node scripts/check-release.mjs "$GITHUB_REF_NAME"

- name: Build package
run: yarn build
Expand All @@ -73,12 +48,9 @@ jobs:
name: npm-package
path: artifacts/*.tgz
if-no-files-found: error
retention-days: 1
retention-days: 7

publish:
if: >-
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) ||
(github.event_name == 'workflow_dispatch' && inputs.release_tag != '')
needs: package
runs-on: ubuntu-latest
environment: release
Expand All @@ -101,13 +73,11 @@ jobs:

- name: Publish with npm trusted publishing
shell: bash
env:
RELEASE_TAG: ${{ github.event_name == 'push' && github.ref_name || inputs.release_tag }}
run: |
set -euo pipefail

package_name=react-native-ease
version="${RELEASE_TAG#v}"
version="${GITHUB_REF_NAME#v}"
tarball="./artifacts/$package_name-$version.tgz"
dist_tag=latest
if [[ "$version" == *-* ]]; then dist_tag=next; fi
Expand Down Expand Up @@ -137,7 +107,7 @@ jobs:

npm publish "$tarball" --provenance --access public --tag "$dist_tag"

for attempt in {1..12}; do
for attempt in {1..60}; do
if npm view "$package_name@$version" version dist.integrity --json > "$registry_file" &&
npm view "$package_name" "dist-tags.$dist_tag" --json > "$RUNNER_TEMP/dist-tag.json" &&
node -e '
Expand All @@ -158,5 +128,5 @@ jobs:
sleep 10
done

echo "Registry verification failed." >&2
echo "npm accepted publication, but registry verification is still pending. Check the exact version before retrying with the saved artifact." >&2
exit 1
59 changes: 15 additions & 44 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,6 @@ This repository publishes one npm package, `react-native-ease`. The example and
documentation site are not published to npm. Keep this document aligned with
[the Release workflow](.github/workflows/release.yml).

## One-time trusted-publisher setup

Configure a GitHub Actions trusted publisher in the npm package settings:

| Field | Value |
| ----------------- | ------------------------------------ |
| Organization | `appandflow` |
| Repository | `react-native-ease` |
| Workflow filename | `release.yml` |
| Environment | `release` |
| Allowed action | Direct publishing with `npm publish` |

The workflow uses npm's OpenID Connect integration and does not need an npm
write token. It publishes with Node 24 and npm provenance. See
[npm's trusted publishing guide](https://docs.npmjs.com/trusted-publishers/).

Create the GitHub `release` environment, require a maintainer review, and limit
deployment tags to `v*`. Declaring the environment in the workflow does not
create its protection rules, and the npm trust relationship must also be
configured separately.

## Prepare and verify a candidate

Start from reviewed, current `main`. Check npm before choosing a version; a Git
Expand Down Expand Up @@ -57,15 +36,6 @@ node scripts/check-release.mjs vX.Y.Z
CI also builds the Android, iOS, and tvOS examples. Device behavior affected by
the release still needs device validation.

After this workflow has been merged into the default branch, use **Actions →
Release → Run workflow** with `release_tag` empty for a publication-free
integration test. The manual run executes the full reusable CI workflow, builds
and validates the npm tarball, and uploads it as a one-day workflow artifact.

The dry run cannot test npm's OIDC trust relationship because npm authenticates
the workflow only when `npm publish` runs. Use the first intentional prerelease
to validate trusted publishing end to end.

## Tag and publish

1. Run `yarn release X.Y.Z` from current `main`. `release-it` creates the release
Expand Down Expand Up @@ -93,17 +63,18 @@ move a newer dist-tag backward.
- If authentication fails, verify the npm publisher's organization, repository,
workflow filename, and environment. Do not add a long-lived npm token as a
workaround.
- If validation fails before publication, fix the issue on `main` and prepare a
new version. Never move a pushed release tag.
- If a publish is interrupted, query the exact npm version before retrying. The
workflow refuses registry errors other than a real missing-version response.
If the tagged workflow itself needs a fix, merge the fix to `main`, then run
the Release workflow manually with the existing tag in `release_tag`. It
checks out and validates that immutable tag before publishing its exact package.
- npm versions cannot be overwritten. Publish a new version for any correction.
- Do not rerun an old release to change `latest` or `next` after a newer release
has advanced that dist-tag.

Adding this workflow does not publish anything. npm publication begins only when
a matching release tag is pushed, or supplied explicitly as `release_tag` to a
manual recovery run, and the protected environment is approved.
- Retry a failed publish with `gh run rerun RUN_ID --failed`. This reuses the
inspected tarball, retained for seven days, without repeating native CI.
- npm processing can take several minutes. The workflow allows approximately
ten minutes for verification after acceptance. If verification times out,
inspect the exact npm version before retrying with the same artifact.
- If the artifact has expired, rerun all jobs. A rerun uses the original workflow
revision, including its checkout and scripts. Merging a workflow fix does not
update an existing run.
- Never move an already-published tag. npm versions cannot be overwritten;
publish a new version for corrections to a published package.
- An existing version is skipped only when its integrity matches the saved
tarball. This does not change `latest` or `next`.

Adding this workflow does not publish anything. Publication requires a matching
`v*` tag push, successful CI, and approval of the protected release environment.
Loading