diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index fb4910c..f888003 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,19 +1,44 @@ name: Stage npm release on: + workflow_dispatch: + inputs: + version: + description: Version increment + required: true + default: patch + type: choice + options: + - patch + - minor + - major push: tags: - 'v*' permissions: - contents: read + contents: write id-token: write +concurrency: + group: npm-release + cancel-in-progress: false + jobs: stage: runs-on: ubuntu-latest + timeout-minutes: 15 steps: + - name: Require master for manual releases + if: github.event_name == 'workflow_dispatch' + run: | + if [[ "$GITHUB_REF" != "refs/heads/master" ]]; then + echo "::error::Select master when starting a release." + exit 1 + fi - uses: actions/checkout@v6 + with: + fetch-depth: 0 - uses: actions/setup-node@v6 with: node-version: '26' @@ -25,7 +50,20 @@ jobs: npm --version - name: Install dependencies run: npm ci + - name: Prepare version commit and tag + if: github.event_name == 'workflow_dispatch' + env: + VERSION_INCREMENT: ${{ inputs.version }} + run: | + case "$VERSION_INCREMENT" in + patch|minor|major) ;; + *) echo "::error::Invalid version increment"; exit 1 ;; + esac + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + npm version "$VERSION_INCREMENT" --ignore-scripts --lockfile-version=1 -m "Release %s" - name: Verify release tag and package version + if: github.event_name == 'push' shell: bash run: | VERSION=$(node -p "require('./package.json').version") @@ -37,5 +75,17 @@ jobs: run: npm test - name: Check package tarball run: npm pack --dry-run + - name: Push version commit and tag + if: github.event_name == 'workflow_dispatch' + run: | + VERSION=$(node -p "require('./package.json').version") + git push --atomic origin HEAD:refs/heads/master "refs/tags/v$VERSION" - name: Stage package for npm approval run: npm stage publish + - name: Explain final approval + run: | + VERSION=$(node -p "require('./package.json').version") + { + echo "## Version $VERSION staged" + echo "Open npm's Staged Packages tab and approve react-select-country-list@$VERSION with 2FA to publish it." + } >> "$GITHUB_STEP_SUMMARY" diff --git a/README.md b/README.md index 70a95ec..50b4dc2 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,31 @@ countries.native().getLabel('TW') // è‡şç£ ``` +## Releasing (maintainers) + +1. Open **Actions → Stage npm release → Run workflow** on GitHub. +2. Select the **master** branch and choose **patch**, **minor**, or **major**. +3. Run the workflow. It updates the package and lockfile versions, runs tests and + package checks, pushes the version commit and matching `v` tag together, and + stages the package with npm in the same workflow. +4. After the workflow succeeds, approve the version in npm's **Staged Packages** + tab with two-factor authentication to make it publicly available. + +The npm trusted publisher must allow this repository's `publish.yml` workflow. +The workflow needs permission to push to `master`; branch protection rules still +apply. If the push is rejected, no package is staged. + +If staging fails after the version commit and tag have been pushed, do not start +another manual release (that would bump the version again). Fix the staging +issue, then check out the existing release tag locally and run `npm ci` followed +by `npm stage publish`. Rerunning a failed manually started job is not supported +after its version commit and tag have already been pushed. + +Manual `v*` tag pushes are also supported. The tag must match `package.json`, +for example `v2.2.4` for version `2.2.4`. GitHub's default workflow token does not +trigger another workflow when it pushes a tag, so the manual release stages the +package directly rather than relying on the tag-triggered run. + ## License MIT