|
| 1 | +--- |
| 2 | +name: metro-release |
| 3 | +description: Draft a react/metro GitHub release — build a changelog from commits since the last tag and create a draft release. |
| 4 | +disable-model-invocation: true |
| 5 | +--- |
| 6 | + |
| 7 | +# New Metro Release |
| 8 | + |
| 9 | +## Overview |
| 10 | + |
| 11 | +Creates a **draft** GitHub release for [`react/metro`](https://github.com/react/metro) by reading commits since the last tag and turning them into a labeled changelog. The release process is manual; this skill automates the mechanical parts (diffing commits, fetching PR/author metadata, formatting notes) and leaves the editorial judgment to you. |
| 12 | + |
| 13 | +**Source of truth is the `react/metro` remote on GitHub, not your local checkout.** Always fetch fresh before diffing. |
| 14 | + |
| 15 | +**Never publish.** Always create the release as a draft and stop. A human reviews and publishes. |
| 16 | + |
| 17 | +## Step 1 — Sync from react/metro |
| 18 | + |
| 19 | +Fetch the canonical tags and `main` directly from `react/metro` so the diff is authoritative regardless of how your local remotes are configured: |
| 20 | + |
| 21 | +```bash |
| 22 | +git fetch https://github.com/react/metro.git main --tags |
| 23 | +``` |
| 24 | + |
| 25 | +Find the latest release tag (tags are `vMAJOR.MINOR.PATCH`, e.g. `v0.84.4`): |
| 26 | + |
| 27 | +```bash |
| 28 | +LAST_TAG=$(git tag --list 'v*' --sort=-v:refname | head -1) |
| 29 | +echo "$LAST_TAG" |
| 30 | +``` |
| 31 | + |
| 32 | +## Step 2 — List candidate commits |
| 33 | + |
| 34 | +```bash |
| 35 | +git log --oneline "$LAST_TAG"..FETCH_HEAD |
| 36 | +``` |
| 37 | + |
| 38 | +Squash-merged PRs end with `(#NNNN)`. Use the PR number to pull the title, URL, and author's GitHub login: |
| 39 | + |
| 40 | +```bash |
| 41 | +gh pr view <NNNN> --repo react/metro --json title,url,author -q '.author.login + " | " + .url + " | " + .title' |
| 42 | +``` |
| 43 | + |
| 44 | +For a direct commit with no PR, link the commit instead: `https://github.com/react/metro/commit/<sha>`. |
| 45 | + |
| 46 | +## Step 3 — Decide which commits to include |
| 47 | + |
| 48 | +Include only **observable, public-facing** changes. Map each to a label: |
| 49 | + |
| 50 | +| Label | When | |
| 51 | +|---|---| |
| 52 | +| `[Breaking]` | Any semver-major / backwards-incompatible change | |
| 53 | +| `[Deprecated]` | A public feature or API marked deprecated | |
| 54 | +| `[Feature]` | New API or observable capability | |
| 55 | +| `[Fix]` | Fix for an observable bug | |
| 56 | +| `[Performance]` | Non-functional change that observably improves performance | |
| 57 | +| `[Types]` | Additions/improvements to Flow or TypeScript coverage for public APIs | |
| 58 | +| `[Experimental]` | Changes to experimental features (e.g. `unstable_`-prefixed config) — see below | |
| 59 | + |
| 60 | +**Exclude** (no changelog entry): |
| 61 | +- Meta-internal sync commits — `Deploy X.Y.Z to xplat`, and anything with no observable OSS effect. |
| 62 | +- Flow version upgrades, reformatting, refactors with no behavior change. |
| 63 | +- Tests, CI, website/docs-only changes. |
| 64 | + |
| 65 | +Judgment notes: |
| 66 | +- One commit can produce multiple entries; one entry can reference multiple related commits/PRs. 1-to-1 is typical. |
| 67 | +- Reword commit titles for clarity when needed. |
| 68 | +- When unsure whether something is user-facing, lean toward including it (and bumping minor). |
| 69 | + |
| 70 | +## Step 4 — Decide the version |
| 71 | + |
| 72 | +Semantic versioning with the **major pinned at 0**: |
| 73 | +- **Any breaking change** → bump the **minor** (`0.84.4` → `0.85.0`). |
| 74 | +- **Otherwise** (fixes, new features, perf, types — all backwards-compatible) → bump the **patch** (`0.84.4` → `0.84.5`). |
| 75 | + |
| 76 | +The tag and the release title are both the `v`-prefixed version, e.g. `v0.84.5`. |
| 77 | + |
| 78 | +Changes to experimental features are **never** treated as breaking, even if they break between versions. |
| 79 | + |
| 80 | +## Step 5 — Build the release notes |
| 81 | + |
| 82 | +Match the established format exactly. Each entry: `` - **[Label]**: description (PR-or-commit-URL by @author)``. Always @-mention the author's GitHub login. If an author has no linked GitHub account, fall back to their full name. |
| 83 | + |
| 84 | +```markdown |
| 85 | + - **[Feature]**: Support `/[metro-watchFolders]/n/` paths for `.bundle` and `.map` requests (https://github.com/react/metro/pull/1695 by @huntie) |
| 86 | + - **[Fix]**: Treat `import().catch()` as optional under `transformer.allowOptionalDependencies` (https://github.com/react/metro/pull/1697 by @robhogan) |
| 87 | + - **[Performance]**: Interleave resolution attempts with building node_modules candidate paths (https://github.com/react/metro/commit/a817960e5d783c9463173aa84c0245e5864bb5a8 by @kitten) |
| 88 | + |
| 89 | + **Full Changelog**: https://github.com/react/metro/compare/<LAST_TAG>...<NEW_TAG> |
| 90 | +``` |
| 91 | + |
| 92 | +Put experimental entries in a **separate list** below the main changelog, under this exact disclaimer: |
| 93 | + |
| 94 | +```markdown |
| 95 | +> NOTE: Experimental features are not covered by semver and can change at any time. |
| 96 | +
|
| 97 | + - **[Experimental]**: ... (URL by @author) |
| 98 | +``` |
| 99 | + |
| 100 | +## Step 6 — Create the draft release (or fall back to a file) |
| 101 | + |
| 102 | +Always write the notes to a file first (preserves Markdown): |
| 103 | + |
| 104 | +```bash |
| 105 | +NOTES_FILE=/tmp/metro-release-notes.md # write the changelog here |
| 106 | +``` |
| 107 | + |
| 108 | +Then check whether you can actually create the release. You need `gh` authenticated **and** write/admin access to `react/metro`: |
| 109 | + |
| 110 | +```bash |
| 111 | +gh auth status >/dev/null 2>&1 \ |
| 112 | + && gh api repos/react/metro --jq '.permissions.push' 2>/dev/null |
| 113 | +# prints "true" only if authenticated with write access |
| 114 | +``` |
| 115 | + |
| 116 | +**If that prints `true`** — create the draft. The tag does not need to exist yet; for a draft, GitHub creates it on publish. |
| 117 | + |
| 118 | +```bash |
| 119 | +gh release create <NEW_TAG> \ |
| 120 | + --repo react/metro \ |
| 121 | + --draft \ |
| 122 | + --target main \ |
| 123 | + --title <NEW_TAG> \ |
| 124 | + --notes-file "$NOTES_FILE" |
| 125 | +``` |
| 126 | + |
| 127 | +Print the draft URL from the command output and **stop**. Do not publish — a human reviews and publishes. |
| 128 | + |
| 129 | +**If `gh` is not authenticated, or push access is missing/`false`** — do not attempt the API call. Fall back to the manual path: |
| 130 | + |
| 131 | +1. Leave the formatted notes in `$NOTES_FILE` and print its path. |
| 132 | +2. Tell the user to open https://github.com/react/metro/releases/new, set the tag to `<NEW_TAG>`, target `main`, title `<NEW_TAG>`, paste the notes, and **Save draft** (not publish). |
| 133 | +3. If `gh` is installed but unauthenticated, mention they can run `! gh auth login` and re-run this skill to automate it; if they lack write access, they need admin/maintainer permission on `react/metro` first. |
0 commit comments