Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
141 changes: 141 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -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'

Comment thread
coderabbitai[bot] marked this conversation as resolved.
- 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[@]}"
Comment on lines +117 to +130

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- release-it npm publish configuration ---'
sed -n '1,240p' package/.release-it.json
printf '%s\n' '--- configured npm tag arguments ---'
rg -n -C 3 --glob 'package.json' --glob '.release-it.json' \
  'publishArgs|npm[.]tag|"tag"|--tag|prerelease' package

Repository: gmi-software/react-native-better-maps

Length of output: 1017


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- workflow context ---'
sed -n '1,145p' .github/workflows/release.yml
printf '%s\n' '--- package metadata ---'
sed -n '1,180p' package/package.json
printf '%s\n' '--- deterministic prerelease/tag check ---'
python3 - <<'PY'
import json
from pathlib import Path

release = json.loads(Path("package/.release-it.json").read_text())
package = json.loads(Path("package/package.json").read_text())

publish_args = release.get("npm", {}).get("publishArgs", [])
version = package.get("version", "")
print("version:", version)
print("is_prerelease:", "-" in version.split("+", 1)[0])
print("publishArgs:", publish_args)
print("has_tag_option:", any(a == "--tag" or a.startswith("--tag=") for a in publish_args))
print("has_non_latest_tag:", any(
    (a.startswith("--tag=") and a.split("=", 1)[1] != "latest")
    for a in publish_args
))
PY

Repository: gmi-software/react-native-better-maps

Length of output: 8556


🌐 Web query:

npm publish default dist-tag prerelease version --tag latest release-it publishArgs documentation

💡 Result:

By default, the npm publish command automatically assigns the latest dist-tag to the version being published unless you explicitly specify a different tag using the --tag option [1][2][3]. This behavior applies even to pre-release versions (e.g., 1.0.0-beta.1), which can cause them to become the default version installed by users if they run npm install [4][5]. To avoid this, you should use the --tag flag to specify a non-latest tag (such as beta or next) when publishing pre-release versions [1][3]. Regarding release-it, if you are using it to automate your publishing process, you can configure the distribution tag and pass extra arguments to the underlying npm publish command via the configuration file (e.g.,.release-it.json or in package.json) [6][7][8]. To control the tag, use the npm.tag option [6][9]: { "npm": { "tag": "beta" } } To pass extra arguments to the publish command, use the npm.publishArgs option [6][9]: { "npm": { "publishArgs": ["--tag", "beta"] } } Note that npm.tag is the dedicated setting for managing the dist-tag, while npm.publishArgs provides a way to pass any additional arguments directly to the npm publish command [6][7].

Citations:


Set a non-latest dist-tag for prereleases.

The workflow accepts prerelease tags, but package/.release-it.json sets no npm tag. npm will publish a prerelease as latest unless the command supplies another tag. Pass --tag next for prereleases, or reject prerelease tags.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 117 - 130, Update the Publish
step’s release arguments to ensure prerelease versions are not published under
npm’s latest dist-tag. In the release flow around the args array and
package/.release-it.json configuration, supply a non-latest tag such as next
when publishing prereleases, or explicitly reject prerelease tags; preserve the
existing dry-run behavior for non-push events.


- 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"
76 changes: 76 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
<MapView onRegionChange={(region) => setSearchArea(region)} />

// After: fires once when the user stops moving the map
<MapView onRegionChangeComplete={(region) => setSearchArea(region)} />
```

**`MapViewRef` camera methods now return `Promise<void>`**

`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.
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
90 changes: 90 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -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 `## <version>` 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 `## <version>` 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
```
Loading
Loading