From 1cedac749e46d308abfd19a66416c83cdfc1d4b2 Mon Sep 17 00:00:00 2001 From: Jakub Kasprzyk Date: Tue, 4 Aug 2026 16:51:18 +0200 Subject: [PATCH 1/2] chore(release): add CI release pipeline with npm provenance Publish from GitHub Actions via npm trusted publishing (OIDC) instead of a developer machine, so every release carries a provenance attestation and no long-lived npm token is stored anywhere. Version bumps are derived from conventional commits by release-it. CHANGELOG.md stays hand-curated, because behavior changes and migration notes cannot be derived from commit subjects; a workflow guard refuses to publish a version that has no changelog entry. --- .github/workflows/release.yml | 141 ++++++++++++++++++++++++++++++++++ CHANGELOG.md | 76 ++++++++++++++++++ CONTRIBUTING.md | 4 + RELEASING.md | 90 ++++++++++++++++++++++ bun.lock | 37 +++++++++ package/.release-it.json | 12 ++- package/package.json | 1 + 7 files changed, 358 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 CHANGELOG.md create mode 100644 RELEASING.md diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..9354358 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,141 @@ +name: Release + +on: + workflow_dispatch: + inputs: + increment: + description: 'Version increment (auto = derive from conventional commits)' + type: choice + options: + - auto + - patch + - minor + - major + default: auto + dry_run: + description: 'Dry run — resolve the version and print the plan without tagging or publishing' + type: boolean + default: true + +concurrency: + group: release + cancel-in-progress: false + +jobs: + release: + runs-on: ubuntu-latest + permissions: + # Push the version commit + tag and create the GitHub Release. + contents: write + # Mint the OIDC token npm exchanges for a short-lived publish token, + # and sign the provenance attestation. + id-token: write + steps: + - name: Checkout + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + # Full history so conventional-changelog can derive the bump from all + # commits since the previous tag. + fetch-depth: 0 + # release-it pushes the version commit and tag, so the checkout + # credentials must stay available. + persist-credentials: true + + - name: Setup Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version: latest + + - name: Setup Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + # Node 24 ships npm >= 11.5.1, which is required for npm trusted + # publishing (OIDC). Node 22 ships npm 10 and cannot authenticate. + node-version: 24 + registry-url: 'https://registry.npmjs.org' + + - name: Verify npm supports trusted publishing + run: | + npm_version="$(npm --version)" + required=11.5.1 + echo "npm $npm_version (need >= $required)" + if [ "$(printf '%s\n%s\n' "$required" "$npm_version" | sort -V | head -n1)" != "$required" ]; then + echo "::error::npm $npm_version is too old for trusted publishing (need >= $required)." + exit 1 + fi + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Codegen + run: bun run nitrogen + + - name: Lint + run: bun run lint + + - name: Typecheck + run: bun run typecheck + + - name: Build + run: bun run build + + - name: Test + run: bun run --filter react-native-better-maps test + + - name: Resolve target version + id: version + working-directory: package + env: + INCREMENT: ${{ inputs.increment }} + run: | + # `--hooks.before:init=` keeps the test gate from running a second time + # here; the Test step above and the release run below both cover it. + args=(--release-version --hooks.before:init=) + [ "$INCREMENT" != "auto" ] && args+=(--increment "$INCREMENT") + version="$(bunx release-it "${args[@]}")" + echo "Resolved version: $version" + echo "version=$version" >> "$GITHUB_OUTPUT" + + - name: Verify CHANGELOG entry exists + env: + VERSION: ${{ steps.version.outputs.version }} + run: | + if ! grep -qE "^## +${VERSION//./\\.}( |$)" CHANGELOG.md; then + echo "::error::CHANGELOG.md has no '## $VERSION' section. Add the release notes before publishing." + exit 1 + fi + + - name: Configure git identity + run: | + git config user.name 'github-actions[bot]' + git config user.email '41898282+github-actions[bot]@users.noreply.github.com' + + - name: Release + working-directory: package + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + INCREMENT: ${{ inputs.increment }} + DRY_RUN: ${{ inputs.dry_run }} + run: | + args=(--ci) + [ "$INCREMENT" != "auto" ] && args+=(--increment "$INCREMENT") + [ "$DRY_RUN" = "true" ] && args+=(--dry-run) + echo "release-it ${args[*]}" + bunx release-it "${args[@]}" + + - name: Summary + if: always() + env: + VERSION: ${{ steps.version.outputs.version }} + DRY_RUN: ${{ inputs.dry_run }} + run: | + { + echo "### Release ${VERSION:-unknown}" + echo + if [ "$DRY_RUN" = "true" ]; then + echo "Dry run — nothing was tagged or published." + else + echo "- npm: https://www.npmjs.com/package/react-native-better-maps/v/$VERSION" + echo "- GitHub Release: ${{ github.server_url }}/${{ github.repository }}/releases/tag/v$VERSION" + fi + } >> "$GITHUB_STEP_SUMMARY" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..09bd535 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,76 @@ +# Changelog + +All notable changes to this project are documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 1.1.0 + +### Behavior changes + +Two changes alter runtime behavior without changing any type signatures, so your +code keeps compiling but may behave differently after upgrading. + +**`onRegionChange` and `onRegionChangeComplete` now fire once per gesture** + +In 1.0.0 these fired repeatedly while the map was moving, and also fired for +programmatic camera updates. Now: + +- `onRegionChange` fires **once** when a user-initiated region change **begins** +- `onRegionChangeComplete` fires **once** when the user gesture **ends** +- Programmatic updates (`setCamera`, `animateCamera`, `fitToCoordinates`) no + longer emit either callback + +If you relied on a continuous stream of region updates — a live coordinate +readout, or a "search this area" button that re-renders while panning — move that +work to `onRegionChangeComplete`, which now marks the end of the gesture: + +```tsx +// Before: fired continuously during the gesture + setSearchArea(region)} /> + +// After: fires once when the user stops moving the map + setSearchArea(region)} /> +``` + +**`MapViewRef` camera methods now return `Promise`** + +`setCamera`, `animateCamera`, and `fitToCoordinates` previously returned `void`. +Existing call sites still compile, but linters configured with +`@typescript-eslint/no-floating-promises` will now flag them, and any custom +implementation or test mock of `MapViewRef` must be updated to match. + +```tsx +// Await the call, or explicitly ignore the promise +await mapRef.current?.animateCamera(camera, 300); +``` + +### Features + +- Add native POI press events with provider-specific payloads + (`onPoiPress`, `PoiPressEvent`, `ApplePoiPressEvent`, `GooglePoiPressEvent`) + ([#36](https://github.com/gmi-software/react-native-better-maps/pull/36)) +- Add Expo SDK 57 support + ([#49](https://github.com/gmi-software/react-native-better-maps/pull/49)) +- Rework map region change handling and camera update logic; programmatic + updates now skip no-op native calls + ([#48](https://github.com/gmi-software/react-native-better-maps/pull/48)) + +### Bug Fixes + +- **ios:** Remove `main.sync` from `HybridMapView` and make camera APIs async, + fixing main-thread deadlocks + ([#45](https://github.com/gmi-software/react-native-better-maps/pull/45)) +- **ios:** Fix threading issues in map view ownership + ([#43](https://github.com/gmi-software/react-native-better-maps/pull/43)) +- **android:** Align SDK versions with the nitro-modules prefab + ([#41](https://github.com/gmi-software/react-native-better-maps/pull/41)) +- Fix failure on first-time build + ([#39](https://github.com/gmi-software/react-native-better-maps/pull/39)) + +## 1.0.0 + +Initial public release: high-performance maps for React Native built on Nitro +Modules and the New Architecture, with Apple Maps and Google Maps providers on +iOS and Android. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cf3f4c4..e57e65e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -92,6 +92,10 @@ chore: add commitlint configuration - Place imports at the top of files. - Use exhaustive switch handling for discriminated unions. +## Releasing + +Maintainers cut releases from CI — see [RELEASING.md](RELEASING.md). + ## Reporting issues Please use [GitHub Issues](https://github.com/gmi-software/react-native-better-maps/issues) and include: diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000..4fadcd0 --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,90 @@ +# Releasing + +Releases are cut by the [Release workflow](.github/workflows/release.yml) and +published to npm from CI with [provenance](https://docs.npmjs.com/generating-provenance-statements). +Nothing is published from a developer machine, and no long-lived npm token +exists anywhere. + +## Versioning + +The version bump is derived from [Conventional Commits](https://www.conventionalcommits.org/) +since the previous tag: `fix:` gives a patch, `feat:` a minor, and a +`BREAKING CHANGE:` footer a major. You can override this with the workflow's +`increment` input. + +Two things are worth knowing because tooling cannot infer them: + +- A commit that is not conventional (for example `Fix threading issues on ios`) + is invisible to the bump calculation and to the generated release notes. Add + it to the changelog by hand. +- A change in runtime behavior that keeps the same types — such as a callback + that starts firing once per gesture instead of continuously — is a breaking + change for consumers even though their code still compiles. Either take the + major, or ship it as a minor with a prominent **Behavior changes** section, as + 1.1.0 did. + +## Changelog + +`CHANGELOG.md` is written by hand, not generated. This is deliberate: the parts +of a release that matter most to users — behavior changes, migration snippets, +the reason a fix exists — cannot be derived from commit subjects. + +The workflow **fails** if `CHANGELOG.md` has no `## ` section for the +version being released, so the notes cannot be forgotten. + +Auto-generated notes from conventional commits still go into the GitHub Release +body, so the commit-level detail is not lost. + +## Cutting a release + +1. Make sure `main` is green and contains everything you want to ship. +2. Add a `## ` section to `CHANGELOG.md` and merge it to `main`. +3. Run the **Release** workflow from the Actions tab with `dry_run: true`. It + resolves the version, runs the full gate, and prints the plan without tagging + or publishing. +4. Re-run with `dry_run: false`. + +The workflow then bumps `package/package.json`, commits `chore: release vX.Y.Z`, +tags `vX.Y.Z`, pushes both, publishes to npm with provenance, and creates the +GitHub Release. + +The iOS podspec reads its version from `package.json`, so there is no second +version to keep in sync. + +## One-time setup + +### npm trusted publishing + +Publishing uses OIDC, so it only works once npm knows which workflow is allowed +to publish this package. On npmjs.com, open the `react-native-better-maps` +package settings and add a **GitHub Actions** trusted publisher pointing at: + +- repository: `gmi-software/react-native-better-maps` +- workflow: `release.yml` + +Until this is configured the publish step will fail with an authentication +error. If an `NPM_TOKEN` secret still exists in the repository, delete it once +trusted publishing works — it is no longer used. + +### Branch protection + +The workflow pushes the release commit and tag directly to `main`. If `main` +requires pull requests or status checks, allow `github-actions[bot]` to bypass +those rules, or the push will be rejected after the package has already been +published. + +## Notes on the configuration + +`package/.release-it.json` sets `npm.skipChecks: true`. release-it otherwise +runs `npm whoami` during startup, which fails under trusted publishing because +the short-lived token is only minted at publish time. + +## Releasing locally + +Not supported for real releases — a local publish would produce a package +without provenance. To inspect what a release would do: + +```bash +cd package +bunx release-it --dry-run +``` diff --git a/bun.lock b/bun.lock index ae4efc3..9f6ea40 100644 --- a/bun.lock +++ b/bun.lock @@ -45,6 +45,7 @@ "version": "1.0.0", "devDependencies": { "@expo/config-plugins": "~57.0.0", + "@release-it/conventional-changelog": "^12.0.0", "@types/jest": "^29.5.14", "@types/react": "^19.2.15", "jest": "^29.7.0", @@ -592,8 +593,14 @@ "@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.86.0", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.2.0", "react": "*", "react-native": "0.86.0" }, "optionalPeers": ["@types/react"] }, "sha512-4/ZLXdf/OSpPDVO0AsQ1SJdRIzt5t9BNQ46QwGgxvX7/cirYR5k8KXctNGGgW8lQo2gZChEfY2zFCZg9nM/jiw=="], + "@release-it/conventional-changelog": ["@release-it/conventional-changelog@12.0.0", "", { "dependencies": { "@conventional-changelog/git-client": "^3.1.0", "concat-stream": "^2.0.0", "conventional-changelog": "^8.1.0", "conventional-changelog-angular": "^9.2.1", "conventional-changelog-conventionalcommits": "^10.2.1", "conventional-recommended-bump": "^12.1.0", "semver": "^7.8.5" }, "peerDependencies": { "release-it": "^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0" } }, "sha512-b9N8/tUjO9JNH1u2fVSmq8QmbqnE//Y5iCgvPcytsk0pj0GhgGCp+VmfzhEBIdd+lVGZJKs+ZSaGaOHjtmtv7g=="], + "@simple-libs/child-process-utils": ["@simple-libs/child-process-utils@2.0.0", "", { "dependencies": { "@simple-libs/stream-utils": "^2.0.0" } }, "sha512-dvNoRKLijXnD0XoJAz94pbNuB5GQgDr55UhpSPhffDkTT0Cmcqh9jSCOtwfT2d4H6MI9E7c4SgtMuJXZ6F3c6A=="], + "@simple-libs/hosted-git-info": ["@simple-libs/hosted-git-info@2.0.0", "", {}, "sha512-55XwK/GYgV58PuN8lZFhI1qRxdKoMLJocXl/yM1EPqazFDmM4QWY7q6BxPCPDNKTNunj794DSD4h0H7SrqUdMg=="], + + "@simple-libs/normalize-package-data": ["@simple-libs/normalize-package-data@1.0.0", "", { "dependencies": { "@simple-libs/hosted-git-info": "^2.0.0", "semver": "^7.8.5" } }, "sha512-/EOmFBekV9tGee8gac/k+5Ox3twkypNqh5TfxA9vTkmcJkjm6f1xqrlstDNOrEhTvnYyVtU6Du2ZhY/IV1+9GA=="], + "@simple-libs/stream-utils": ["@simple-libs/stream-utils@2.0.0", "", {}, "sha512-fCTuZK4QBa+39Oz9l4OGfJfz+GpwCp3AqO7Zch3to99xHPgstVsRFpeQ8LNd2o1Gv8raL2mCFwiaHh7bFSp5DQ=="], "@sinclair/typebox": ["@sinclair/typebox@0.27.12", "", {}, "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g=="], @@ -842,6 +849,8 @@ "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + "concat-stream": ["concat-stream@2.0.0", "", { "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.0.2", "typedarray": "^0.0.6" } }, "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A=="], + "confbox": ["confbox@0.2.4", "", {}, "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ=="], "connect": ["connect@3.7.0", "", { "dependencies": { "debug": "2.6.9", "finalhandler": "1.1.2", "parseurl": "~1.3.3", "utils-merge": "1.0.1" } }, "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ=="], @@ -850,12 +859,22 @@ "content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], + "conventional-changelog": ["conventional-changelog@8.1.0", "", { "dependencies": { "@conventional-changelog/git-client": "^3.1.0", "@simple-libs/hosted-git-info": "^2.0.0", "@simple-libs/normalize-package-data": "^1.0.0", "argue-cli": "^3.1.0", "conventional-changelog-preset-loader": "^6.0.1", "conventional-changelog-writer": "^9.2.0", "conventional-commits-parser": "^7.1.0", "fd-package-json": "^2.0.0" }, "bin": { "conventional-changelog": "./dist/cli/index.js" } }, "sha512-idt1JK+3+Nt7gqH/d/sEYWdDeR+5XPov/jssmFN6XxmYSRlonTWSDWhWUPkmm0zbwYjtVdt+4My5aiPkKyvocw=="], + "conventional-changelog-angular": ["conventional-changelog-angular@9.2.1", "", { "dependencies": { "@conventional-changelog/template": "^1.2.1" } }, "sha512-oWSL6ZhnXbYraOFTK3PgRAQJ8fADDAEv5K6AdeyQPLvjFmhG8+ejL0jZZp/R7vTmGJaBvZEE+sE7dB4bCv7sAw=="], "conventional-changelog-conventionalcommits": ["conventional-changelog-conventionalcommits@10.2.1", "", { "dependencies": { "@conventional-changelog/template": "^1.2.1" } }, "sha512-n4Kr1HFMTf3iMbES0TMxKIcYtUUv4rKqyQQp2JwfOEfFCOfGT3Tq4mCyJ8S9/YPyWhydjfKrrvnyl+gCjA+mJQ=="], + "conventional-changelog-preset-loader": ["conventional-changelog-preset-loader@6.0.1", "", {}, "sha512-GZ8E3RQzXQb3JFy0pKl8oeSf7ENIhvAMvJr+PlWkavZOesLHHdhkfNJ4SvW35eo1Fu2+EyVxWQ1tVvtzAG2iWg=="], + + "conventional-changelog-writer": ["conventional-changelog-writer@9.2.0", "", { "dependencies": { "@conventional-changelog/template": "^1.2.1", "@simple-libs/stream-utils": "^2.0.0", "argue-cli": "^3.1.0", "conventional-commits-filter": "^6.0.1", "semver": "^7.5.2" }, "bin": { "conventional-changelog-writer": "./dist/cli/index.js" } }, "sha512-eACD5BaAQCYjeI3RExkCZopNaaIuXzCP4kaAb2lEFXcGa/KOuxJfj8v/SnjhvF6377pYn0A2Gji+6GhwUK8rEA=="], + + "conventional-commits-filter": ["conventional-commits-filter@6.0.1", "", {}, "sha512-cs+LadpH7Kpw0M3k8wurk+sOVVDAENA0iK4OBOrkL94j5lEVYRJ4j3zd2bhY9qgzyrPqthdcYT3axzRN7AliMg=="], + "conventional-commits-parser": ["conventional-commits-parser@7.1.0", "", { "dependencies": { "@simple-libs/stream-utils": "^2.0.0", "argue-cli": "^3.1.0" }, "bin": { "conventional-commits-parser": "./dist/cli/index.js" } }, "sha512-DPp6hkUjvwIivxbkrTiLXeRswNv1A/4GFA2X6scXma0AMa9632V3TwxmrlkUIEtUktiM3Ln+RrSH2xlP3/jUTw=="], + "conventional-recommended-bump": ["conventional-recommended-bump@12.1.0", "", { "dependencies": { "@conventional-changelog/git-client": "^3.1.0", "argue-cli": "^3.1.0", "conventional-changelog-preset-loader": "^6.0.1", "conventional-commits-filter": "^6.0.1", "conventional-commits-parser": "^7.1.0" }, "bin": { "conventional-recommended-bump": "./dist/cli/index.js" } }, "sha512-HTNG3kEZXOOfKwrEx54ljURU9bG4nVPQzXMyCSeUcA/PE8EpNpQNujSrbXNBI8QZyN35zM+pVw+FuQk4KqHSHg=="], + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], "core-js-compat": ["core-js-compat@3.49.0", "", { "dependencies": { "browserslist": "^4.28.1" } }, "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA=="], @@ -1044,6 +1063,8 @@ "fb-watchman": ["fb-watchman@2.0.2", "", { "dependencies": { "bser": "2.1.1" } }, "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA=="], + "fd-package-json": ["fd-package-json@2.0.0", "", { "dependencies": { "walk-up-path": "^4.0.0" } }, "sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ=="], + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], "fetch-nodeshim": ["fetch-nodeshim@0.4.10", "", {}, "sha512-m6I8ALe4L4XpdETy7MJZWs6L1IVMbjs99bwbpIKphxX+0CTns4IKDWJY0LWfr4YsFjfg+z1TjzTMU8lKl8rG0w=="], @@ -1692,6 +1713,8 @@ "react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="], + "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + "readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], @@ -1836,6 +1859,8 @@ "string.prototype.trimstart": ["string.prototype.trimstart@1.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg=="], + "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "strip-bom": ["strip-bom@4.0.0", "", {}, "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="], @@ -1894,6 +1919,8 @@ "typed-array-length": ["typed-array-length@1.0.8", "", { "dependencies": { "call-bind": "^1.0.9", "for-each": "^0.3.5", "gopd": "^1.2.0", "is-typed-array": "^1.1.15", "possible-typed-array-names": "^1.1.0", "reflect.getprototypeof": "^1.0.10" } }, "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g=="], + "typedarray": ["typedarray@0.0.6", "", {}, "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="], + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "typescript-eslint": ["typescript-eslint@8.64.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.64.0", "@typescript-eslint/parser": "8.64.0", "@typescript-eslint/typescript-estree": "8.64.0", "@typescript-eslint/utils": "8.64.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-0qg+pDNMnqYzqH9AnNK+39tejHvsShUOUUoRUgtnTGE7QuMZhiFDnozq8nHJVq+Wae6NMLKNWLg5WmkcC/ndyQ=="], @@ -1928,6 +1955,8 @@ "url-join": ["url-join@5.0.0", "", {}, "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA=="], + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], "uuid": ["uuid@7.0.3", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg=="], @@ -1940,6 +1969,8 @@ "vlq": ["vlq@1.0.1", "", {}, "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w=="], + "walk-up-path": ["walk-up-path@4.0.0", "", {}, "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A=="], + "walker": ["walker@1.0.8", "", { "dependencies": { "makeerror": "1.0.12" } }, "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ=="], "wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="], @@ -2062,6 +2093,10 @@ "@react-native/dev-middleware/open": ["open@7.4.2", "", { "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" } }, "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q=="], + "@release-it/conventional-changelog/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + + "@simple-libs/normalize-package-data/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + "@ts-morph/common/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.6", "", {}, "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw=="], @@ -2092,6 +2127,8 @@ "connect/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + "conventional-changelog-writer/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + "cosmiconfig-typescript-loader/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], diff --git a/package/.release-it.json b/package/.release-it.json index 7f284a7..c1a8154 100644 --- a/package/.release-it.json +++ b/package/.release-it.json @@ -10,10 +10,16 @@ "releaseName": "v${version}" }, "npm": { - "publish": true + "publish": true, + "publishArgs": ["--provenance"], + "skipChecks": true }, "hooks": { - "before:init": ["bun run build", "bun run test:ci"] + "before:init": ["bun run test:ci"] }, - "plugins": {} + "plugins": { + "@release-it/conventional-changelog": { + "preset": "conventionalcommits" + } + } } diff --git a/package/package.json b/package/package.json index 954f5fa..3d9b4bf 100644 --- a/package/package.json +++ b/package/package.json @@ -82,6 +82,7 @@ }, "devDependencies": { "@expo/config-plugins": "~57.0.0", + "@release-it/conventional-changelog": "^12.0.0", "@types/jest": "^29.5.14", "@types/react": "^19.2.15", "jest": "^29.7.0", From 7cc03317564a44d30ecb6347cceef87ed9980de0 Mon Sep 17 00:00:00 2001 From: Jakub Kasprzyk Date: Tue, 4 Aug 2026 19:43:09 +0200 Subject: [PATCH 2/2] fix(release): drive publishing from a version tag instead of a CI push `main` enforces pull request reviews with `enforce_admins` enabled, so the previous design could not have worked: github-actions[bot] cannot push a release commit, and the failing push would have run after `npm publish` had already succeeded, leaving a published version with no tag or release. Publishing is now triggered by pushing a version tag. The version bump lands through a normal reviewed pull request, and CI never writes to git. It verifies the tag matches package.json, that a changelog section exists, and that the version is not already on npm, then publishes and creates the release. Also drops registry-url from setup-node: it writes an _authToken entry into .npmrc, which makes npm assume classic token auth and skip the OIDC flow. --- .github/workflows/release.yml | 139 ++++++++++++++++++---------------- RELEASING.md | 134 +++++++++++++++++--------------- package/.release-it.json | 1 - 3 files changed, 146 insertions(+), 128 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9354358..6322916 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,45 +1,40 @@ name: Release +# Publishing is driven by a version tag, not by a commit pushed from CI. +# `main` requires pull request reviews with `enforce_admins` enabled, so nothing — +# including github-actions[bot] — can push a release commit to it. The version +# bump therefore lands through a normal reviewed pull request, and pushing the +# matching tag afterwards triggers the publish. on: + push: + tags: + - 'v[0-9]+.[0-9]+.[0-9]+' + - 'v[0-9]+.[0-9]+.[0-9]+-*' + # Rehearsal against the current branch. Always a dry run: it validates the + # version, changelog and full gate without tagging or publishing anything. workflow_dispatch: - inputs: - increment: - description: 'Version increment (auto = derive from conventional commits)' - type: choice - options: - - auto - - patch - - minor - - major - default: auto - dry_run: - description: 'Dry run — resolve the version and print the plan without tagging or publishing' - type: boolean - default: true concurrency: - group: release + group: release-${{ github.ref }} cancel-in-progress: false jobs: release: runs-on: ubuntu-latest permissions: - # Push the version commit + tag and create the GitHub Release. + # Create the GitHub Release for the pushed tag. contents: write - # Mint the OIDC token npm exchanges for a short-lived publish token, - # and sign the provenance attestation. + # Mint the OIDC token npm exchanges for a short-lived publish token, and + # sign the provenance attestation. id-token: write steps: - name: Checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: - # Full history so conventional-changelog can derive the bump from all - # commits since the previous tag. + # Full history so conventional-changelog can build the release notes + # from every commit since the previous tag. fetch-depth: 0 - # release-it pushes the version commit and tag, so the checkout - # credentials must stay available. - persist-credentials: true + persist-credentials: false - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 @@ -49,10 +44,11 @@ jobs: - name: Setup Node.js uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: - # Node 24 ships npm >= 11.5.1, which is required for npm trusted - # publishing (OIDC). Node 22 ships npm 10 and cannot authenticate. + # Node 24 ships npm >= 11.5.1, required for npm trusted publishing. + # `registry-url` is deliberately omitted: it writes an `_authToken` + # entry into .npmrc, which makes npm assume classic token auth and skip + # the OIDC flow. The registry is already pinned by publishConfig. node-version: 24 - registry-url: 'https://registry.npmjs.org' - name: Verify npm supports trusted publishing run: | @@ -67,35 +63,24 @@ jobs: - name: Install dependencies run: bun install --frozen-lockfile - - name: Codegen - run: bun run nitrogen - - - name: Lint - run: bun run lint - - - name: Typecheck - run: bun run typecheck - - - name: Build - run: bun run build - - - name: Test - run: bun run --filter react-native-better-maps test - - - name: Resolve target version + - name: Resolve version id: version - working-directory: package - env: - INCREMENT: ${{ inputs.increment }} run: | - # `--hooks.before:init=` keeps the test gate from running a second time - # here; the Test step above and the release run below both cover it. - args=(--release-version --hooks.before:init=) - [ "$INCREMENT" != "auto" ] && args+=(--increment "$INCREMENT") - version="$(bunx release-it "${args[@]}")" - echo "Resolved version: $version" + version="$(node -p "require('./package/package.json').version")" + echo "package.json version: $version" echo "version=$version" >> "$GITHUB_OUTPUT" + - name: Verify tag matches package.json + if: github.event_name == 'push' + env: + VERSION: ${{ steps.version.outputs.version }} + TAG: ${{ github.ref_name }} + run: | + if [ "$TAG" != "v$VERSION" ]; then + echo "::error::Tag $TAG does not match package.json version $VERSION. Bump the version on main first." + exit 1 + fi + - name: Verify CHANGELOG entry exists env: VERSION: ${{ steps.version.outputs.version }} @@ -105,37 +90,57 @@ jobs: exit 1 fi - - name: Configure git identity + - name: Verify version is not already published + env: + VERSION: ${{ steps.version.outputs.version }} run: | - git config user.name 'github-actions[bot]' - git config user.email '41898282+github-actions[bot]@users.noreply.github.com' + if npm view "react-native-better-maps@$VERSION" version >/dev/null 2>&1; then + echo "::error::react-native-better-maps@$VERSION is already on npm." + exit 1 + fi + + - name: Codegen + run: bun run nitrogen + + - name: Lint + run: bun run lint - - name: Release + - name: Typecheck + run: bun run typecheck + + - name: Build + run: bun run build + + - name: Test + run: bun run --filter react-native-better-maps test + + - name: Publish working-directory: package env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - INCREMENT: ${{ inputs.increment }} - DRY_RUN: ${{ inputs.dry_run }} run: | - args=(--ci) - [ "$INCREMENT" != "auto" ] && args+=(--increment "$INCREMENT") - [ "$DRY_RUN" = "true" ] && args+=(--dry-run) - echo "release-it ${args[*]}" + # --no-increment: the version already lives in package.json, reviewed + # and merged through a pull request. + # --no-git: the tag is pushed by the maintainer; CI never writes to git. + args=(--ci --no-increment --no-git) + if [ "${{ github.event_name }}" != 'push' ]; then + args+=(--dry-run) + echo 'Rehearsal run — nothing will be tagged or published.' + fi bunx release-it "${args[@]}" - name: Summary if: always() env: VERSION: ${{ steps.version.outputs.version }} - DRY_RUN: ${{ inputs.dry_run }} run: | { - echo "### Release ${VERSION:-unknown}" + echo "### Release v$VERSION" echo - if [ "$DRY_RUN" = "true" ]; then - echo "Dry run — nothing was tagged or published." + if [ "${{ github.event_name }}" != 'push' ]; then + echo "Rehearsal only — nothing was published." else - echo "- npm: https://www.npmjs.com/package/react-native-better-maps/v/$VERSION" - echo "- GitHub Release: ${{ github.server_url }}/${{ github.repository }}/releases/tag/v$VERSION" + echo "- [npm](https://www.npmjs.com/package/react-native-better-maps/v/$VERSION)" + echo "- [GitHub Release](${{ github.server_url }}/${{ github.repository }}/releases/tag/v$VERSION)" fi } >> "$GITHUB_STEP_SUMMARY" diff --git a/RELEASING.md b/RELEASING.md index 4fadcd0..fbb5650 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -1,90 +1,104 @@ # Releasing -Releases are cut by the [Release workflow](.github/workflows/release.yml) and -published to npm from CI with [provenance](https://docs.npmjs.com/generating-provenance-statements). -Nothing is published from a developer machine, and no long-lived npm token -exists anywhere. +Releases are published to npm from CI with +[provenance](https://docs.npmjs.com/generating-provenance-statements) by the +[Release workflow](.github/workflows/release.yml). Nothing is published from a +developer machine, and no long-lived npm token exists anywhere. -## Versioning - -The version bump is derived from [Conventional Commits](https://www.conventionalcommits.org/) -since the previous tag: `fix:` gives a patch, `feat:` a minor, and a -`BREAKING CHANGE:` footer a major. You can override this with the workflow's -`increment` input. +Publishing is triggered by pushing a version tag. CI never writes to git: `main` +requires pull request reviews with `enforce_admins` enabled, so nothing — not +even `github-actions[bot]` — can push a release commit to it. The version bump +goes through a normal reviewed pull request instead, which has the useful side +effect of putting the changelog in front of a reviewer. -Two things are worth knowing because tooling cannot infer them: - -- A commit that is not conventional (for example `Fix threading issues on ios`) - is invisible to the bump calculation and to the generated release notes. Add - it to the changelog by hand. -- A change in runtime behavior that keeps the same types — such as a callback - that starts firing once per gesture instead of continuously — is a breaking - change for consumers even though their code still compiles. Either take the - major, or ship it as a minor with a prominent **Behavior changes** section, as - 1.1.0 did. +## Cutting a release -## Changelog +**1. Open a release pull request.** Bump the version and write the notes: -`CHANGELOG.md` is written by hand, not generated. This is deliberate: the parts -of a release that matter most to users — behavior changes, migration snippets, -the reason a fix exists — cannot be derived from commit subjects. +```bash +cd package +npm version 1.1.0 --no-git-tag-version +``` -The workflow **fails** if `CHANGELOG.md` has no `## ` section for the -version being released, so the notes cannot be forgotten. +Then add a matching `## 1.1.0` section to `CHANGELOG.md`, and open a pull request +with both changes. Review and merge it as usual. -Auto-generated notes from conventional commits still go into the GitHub Release -body, so the commit-level detail is not lost. +**2. Rehearse (optional).** Run the **Release** workflow manually from the +Actions tab. A manual run is always a dry run: it validates the version, the +changelog and the full gate without publishing. -## Cutting a release +**3. Push the tag.** -1. Make sure `main` is green and contains everything you want to ship. -2. Add a `## ` section to `CHANGELOG.md` and merge it to `main`. -3. Run the **Release** workflow from the Actions tab with `dry_run: true`. It - resolves the version, runs the full gate, and prints the plan without tagging - or publishing. -4. Re-run with `dry_run: false`. +```bash +git checkout main && git pull +git tag -a v1.1.0 -m 'v1.1.0' +git push origin v1.1.0 +``` -The workflow then bumps `package/package.json`, commits `chore: release vX.Y.Z`, -tags `vX.Y.Z`, pushes both, publishes to npm with provenance, and creates the -GitHub Release. +The workflow then verifies the tag matches `package/package.json`, that +`CHANGELOG.md` has a section for it, and that the version is not already on npm; +runs the full gate; publishes to npm with provenance; and creates the GitHub +Release with notes generated from the conventional commits since the last tag. The iOS podspec reads its version from `package.json`, so there is no second version to keep in sync. -## One-time setup +## Versioning -### npm trusted publishing +The bump is a judgement call, made when you open the release pull request. The +usual rules apply — `fix:` is a patch, `feat:` a minor, an incompatible API +change a major — but two cases are easy to get wrong: -Publishing uses OIDC, so it only works once npm knows which workflow is allowed -to publish this package. On npmjs.com, open the `react-native-better-maps` -package settings and add a **GitHub Actions** trusted publisher pointing at: +- A commit that is not conventional (for example `Fix threading issues on ios`) + is invisible to the generated release notes. Add it to the changelog by hand. +- A change in runtime behavior that keeps the same types — such as a callback + that starts firing once per gesture instead of continuously — breaks consumers + even though their code still compiles. Either take the major, or ship it as a + minor with a prominent **Behavior changes** section, as 1.1.0 did. -- repository: `gmi-software/react-native-better-maps` -- workflow: `release.yml` +## Changelog -Until this is configured the publish step will fail with an authentication -error. If an `NPM_TOKEN` secret still exists in the repository, delete it once -trusted publishing works — it is no longer used. +`CHANGELOG.md` is written by hand, not generated. This is deliberate: the parts +of a release that matter most — behavior changes, migration snippets, the reason +a fix exists — cannot be derived from commit subjects. The workflow **fails** if +there is no `## ` section, so the notes cannot be forgotten. -### Branch protection +Notes generated from conventional commits still go into the GitHub Release body, +so commit-level detail is not lost. -The workflow pushes the release commit and tag directly to `main`. If `main` -requires pull requests or status checks, allow `github-actions[bot]` to bypass -those rules, or the push will be rejected after the package has already been -published. +## One-time setup: npm trusted publishing + +Publishing uses OIDC, so it only works once npm knows which workflow may publish +this package. On npmjs.com, open the `react-native-better-maps` package settings +and add a **GitHub Actions** trusted publisher pointing at: + +- repository: `gmi-software/react-native-better-maps` +- workflow: `release.yml` + +Until this is configured the publish step fails with an authentication error. If +an `NPM_TOKEN` secret still exists in the repository, delete it once trusted +publishing works — it is no longer used. ## Notes on the configuration -`package/.release-it.json` sets `npm.skipChecks: true`. release-it otherwise -runs `npm whoami` during startup, which fails under trusted publishing because -the short-lived token is only minted at publish time. +A few settings exist for non-obvious reasons: + +- `npm.skipChecks: true` in `package/.release-it.json` — release-it otherwise + runs `npm whoami` at startup, which fails under trusted publishing because the + token is only minted at publish time. +- The workflow does **not** set `registry-url` on `actions/setup-node` — doing so + writes an `_authToken` entry into `.npmrc`, which makes npm assume classic + token auth and skip the OIDC flow. The registry is pinned by `publishConfig`. +- `release-it` runs with `--no-increment --no-git`: the version is already + committed and the tag already pushed, so CI only publishes and creates the + release. -## Releasing locally +## Inspecting a release locally -Not supported for real releases — a local publish would produce a package -without provenance. To inspect what a release would do: +A local publish would produce a package without provenance, so it is not +supported. To see what a release would do: ```bash cd package -bunx release-it --dry-run +bunx release-it --no-increment --no-git --dry-run ``` diff --git a/package/.release-it.json b/package/.release-it.json index c1a8154..7a956ce 100644 --- a/package/.release-it.json +++ b/package/.release-it.json @@ -1,6 +1,5 @@ { "git": { - "commitMessage": "chore: release v${version}", "tagName": "v${version}", "requireCleanWorkingDir": true, "requireUpstream": false