diff --git a/.cursor/skills/sdk-pr-create/SKILL.md b/.cursor/skills/sdk-pr-create/SKILL.md index 264ea204ae..317c5c68e7 100644 --- a/.cursor/skills/sdk-pr-create/SKILL.md +++ b/.cursor/skills/sdk-pr-create/SKILL.md @@ -18,14 +18,18 @@ Generate PR titles and descriptions for SDK pod packages, following the team's t ## Workflow -1. Identify base (main) and current branch -2. Collect commits/diff from `main...origin/` -3. Infer ticket, prefix, and tags from changes (see Inference Strategy) -4. Only ask user for input when inference confidence is low -5. Generate title: `TICKET prefix[tags]: subject` -6. Fill template sections based on changes -7. Validate tag requirements ([bc]/[api]/[mod]) -8. Output complete PR description +1. Identify base and current branch: + - **Normal PR** β†’ base is `main` + - **Release PR** β†’ base is `release--` (PR is the release commit on the release branch) + - **Backmerge PR** β†’ base is `main`, head is `release--` (or a hand-crafted branch with the release-branch artifacts) +2. Collect commits/diff from `...origin/` +3. Determine PR shape (normal / release / backmerge β€” see "Release & Backmerge PRs" below) +4. Infer ticket, prefix, and tags from changes (see Inference Strategy) +5. Only ask user for input when inference confidence is low +6. Generate title using the right format for the PR shape +7. Fill template sections based on changes +8. Validate tag requirements ([bc]/[api]/[mod]) +9. Output complete PR description ## Inference Strategy @@ -63,6 +67,80 @@ Infer first, ask only if uncertain: Fill template sections based on the diff analysis. Delete sections that don't apply. +## Release & Backmerge PRs + +The standard format `TICKET prefix[tags]: subject` covers normal feature/fix PRs. The release flow has two additional PR shapes that follow established conventions in this repo. **Pick the shape first**, then fill in the template. + +**Body always uses the same headings.** Regardless of PR shape (normal / release / backmerge), the body MUST use the standard section headings from `.github/PULL_REQUEST_TEMPLATE/sdk-pod.md`: + +- `## 🎯 What problem does this PR solve?` (always) +- `## πŸ“ How does it solve it?` (always) +- `## πŸ§ͺ How was it tested?` (delete if not applicable) +- `## πŸ’₯ Breaking Changes` (only if `[bc]`) +- `## πŸ”Œ API Changes` (only if `[api]`) +- `## πŸ“¦ Models` (only if `[mod]`) + +Do NOT invent custom headings like `## Summary`, `## Changes`, `## Why`, or `## Test plan` β€” they break tooling and reviewer expectations. Map the content of every PR shape onto these standard sections (see "Mapping release/backmerge content onto the template" below). + +### Release PR (fork β†’ release branch) + +Cuts a new package version onto a `release--` branch on `tetherto/qvac`. Bumps `package.json` version, adds the per-version changelog folder, and prepends an entry to the aggregated `CHANGELOG.md`. Merging this PR triggers GPR publish. + +**Title format:** + +- With ticket: `TICKET chore: release ` + - Example: `QVAC-18184 chore: release sdk 0.9.2` +- Without ticket: `chore[notask|skiplog]: release ` + - Example: `chore[notask|skiplog]: release @qvac/infer-base v0.4.1` (#1781) + +**Notes:** +- `[skiplog]` is **not** used when the release PR itself is what generates the changelog (it would be self-contradictory). +- Use `[notask]` only when there is no ticket; combine with `[skiplog]` via `|` if both are needed. +- Body should describe what's in the release at a high level, link to the per-version `CHANGELOG.md`, and call out any post-merge actions (npm publish via backmerge, etc.). + +### Backmerge PR (release branch β†’ main) + +Brings the release artifacts (changelog folder, aggregated `CHANGELOG.md` entry, version bump in `package.json`) from the release branch back into `main` after the package is published. **Should usually be hand-crafted, not a literal `git merge`** β€” `main` often has progressed past the release branch on dependencies and other files, and a blind merge regresses them. + +**Title format:** + +- With ticket: `TICKET chore[skiplog]: backmerge release ` + - Examples: + - `QVAC-18184 chore[skiplog]: backmerge release sdk 0.9.2` (#1857) + - `QVAC-16776 chore[skiplog]: backmerge release-sdk-0.9.0 β€” changelog, NOTICE, model registry, and tooling fixes` (#1645) + - `QVAC-16495 chore[skiplog]: backmerge sdk v0.8.1 release, changelog & NOTICE` (#1301) +- Without ticket: `chore[notask|skiplog]: backmerge release ` + - Examples: + - `chore[notask|skiplog]: backmerge release sdk v0.8.3` (#1552) + - `chore[notask]: backmerge release @qvac/cli v0.2.2` (#1076) + +**Tag rules:** +- **`[skiplog]` is required** for backmerges β€” the changelog has already been written on the release branch; main shouldn't generate another entry from this PR. +- `[notask]` is **only** used when there is no ticket. Do **not** combine `[notask]` with a ticket in the title (`QVAC-XXX chore[notask|skiplog]: ...` is wrong). +- The two metadata tags `[notask]` and `[skiplog]` may be combined via `|` (e.g. `[notask|skiplog]`); this is distinct from the rule that content tags `[api]/[bc]/[mod]` cannot be combined. + +### Mapping release/backmerge content onto the template + +Use the standard sdk-pod headings for every shape. Suggested mapping: + +**Release PR:** +- `## 🎯 What problem does this PR solve?` β€” what's in the release at a high level (single hotfix? feature batch? security patch?), and which downstream consumer has been waiting on it. +- `## πŸ“ How does it solve it?` β€” what files change (`packages//package.json` version bump, the new `changelog//` folder, the prepended aggregated `CHANGELOG.md` entry), what the merge triggers (GPR publish), and the post-merge follow-up (open the backmerge PR to publish to npm). +- `## πŸ§ͺ How was it tested?` β€” `bun lint`, `bun run build`, `bun test` results; any release-scripts that were run (`generate-changelog-sdk-pod.cjs`, `generate-notice.cjs` for SDK). + +**Backmerge PR:** +- `## 🎯 What problem does this PR solve?` β€” name the published version, link the release PR, state that `main` is currently behind and would otherwise have a hole in its changelog history. +- `## πŸ“ How does it solve it?` β€” list the artifacts brought back (changelog folder, aggregated `CHANGELOG.md` entry, `package.json` version), reference the precedent backmerge PR for the previous version so reviewers can compare shape. +- `## πŸ§ͺ How was it tested?` β€” **if hand-crafted, this is where you justify it.** Explain why a literal `git merge` would regress something on `main` (usually a table of `package.json` dependencies that have advanced past the release branch). Confirm the diff touches only the four expected files. Note any post-merge automation (NOTICE regeneration, etc.) that's expected to follow. + +### Decision rule (quick reference) + +| You are opening… | Base | Title format | Body | +|---|---|---|---| +| A normal feature/fix/doc PR | `main` | `TICKET prefix[tags]: subject` | sdk-pod template | +| A release PR for a new version | `release--` | `TICKET chore: release ` (or `chore[notask|skiplog]: release ...` if no ticket) | sdk-pod template | +| A backmerge PR after publish | `main` | `TICKET chore[skiplog]: backmerge release ` (or `chore[notask|skiplog]: backmerge ...` if no ticket) | sdk-pod template | + ## Output Format ALWAYS output the PR in this copy-ready format, even when making corrections: @@ -117,7 +195,10 @@ gh pr view --repo UPSTREAM_ORG/REPO BRANCH --web Before outputting the PR description, verify: -- [ ] Title follows format: `TICKET prefix[tags]: subject` +- [ ] Title follows format: `TICKET prefix[tags]: subject` (or the release / backmerge variants above) +- [ ] If the PR has a ticket, `[notask]` is **NOT** in the title +- [ ] If the PR is a backmerge, `[skiplog]` is in the title +- [ ] Body uses the standard sdk-pod headings (`## 🎯 What problem...`, `## πŸ“ How does it solve...`, `## πŸ§ͺ How was it tested?`) β€” no custom headings like `## Summary` / `## Changes` / `## Test plan` - [ ] "What problem" describes user impact, not implementation - [ ] "How it solves" is high-level approach, not line-by-line - [ ] Unused sections are deleted