|
| 1 | +--- |
| 2 | +name: release-notes |
| 3 | +description: This skill should be used when the user asks to "create release note", "generate release notes", "release notes", "release changelog", "update GitHub release", or wants to generate categorized release notes between tags. Gathers PR/commit data via gh CLI, categorizes changes, and outputs formatted release notes. The user can optionally specify a release version (e.g. "create release note v0.31.0") to bypass auto-detection. |
| 4 | +version: 0.1.0 |
| 5 | +--- |
| 6 | + |
| 7 | +# Release Notes Generation |
| 8 | + |
| 9 | +Generate categorized release notes for Pipelines-as-Code releases by gathering PR/commit data between two git tags and producing formatted markdown output. |
| 10 | + |
| 11 | +## Purpose |
| 12 | + |
| 13 | +Replace the `hack/generate-releasenotes.py` + Gemini workflow with a Claude-native skill that: |
| 14 | + |
| 15 | +- Auto-detects current and previous tags |
| 16 | +- Gathers PR and commit data via `gh` CLI |
| 17 | +- Uses Claude itself for intelligent categorization (no external AI API needed) |
| 18 | +- Outputs release notes matching the project's established format |
| 19 | +- Optionally updates the GitHub release |
| 20 | + |
| 21 | +## Workflow |
| 22 | + |
| 23 | +### Step 1: Pull latest tags |
| 24 | + |
| 25 | +```bash |
| 26 | +git pull origin --tags |
| 27 | +``` |
| 28 | + |
| 29 | +Ensure all tags are available locally before detection. |
| 30 | + |
| 31 | +### Step 2: Detect repository info |
| 32 | + |
| 33 | +```bash |
| 34 | +gh repo view --json owner,name |
| 35 | +``` |
| 36 | + |
| 37 | +Extract `owner` and `repo` name for API calls. |
| 38 | + |
| 39 | +### Step 3: Detect tags |
| 40 | + |
| 41 | +**If the user specified a version** (e.g. "create release note v0.31.0"), use that directly as the current tag — skip auto-detection. Validate that the tag exists locally: |
| 42 | + |
| 43 | +```bash |
| 44 | +git tag --list 'v0.31.0' |
| 45 | +``` |
| 46 | + |
| 47 | +If the tag doesn't exist locally, error and ask the user to verify. |
| 48 | + |
| 49 | +**Otherwise, auto-detect current tag:** |
| 50 | + |
| 51 | +```bash |
| 52 | +git tag --points-at HEAD |
| 53 | +``` |
| 54 | + |
| 55 | +Filter for `v*` prefixed tags. If no tag points at HEAD, list recent tags and ask the user which tag to use: |
| 56 | + |
| 57 | +```bash |
| 58 | +git tag --list 'v*' --sort=-version:refname | head -10 |
| 59 | +``` |
| 60 | + |
| 61 | +**Previous tag:** |
| 62 | + |
| 63 | +```bash |
| 64 | +git tag --list 'v*' --sort=-version:refname |
| 65 | +``` |
| 66 | + |
| 67 | +Find the entry immediately after the current tag in the version-sorted list. |
| 68 | + |
| 69 | +**CRITICAL**: Confirm both tags with the user before proceeding. Display: |
| 70 | + |
| 71 | +```text |
| 72 | +Current tag: v0.31.0 |
| 73 | +Previous tag: v0.30.0 |
| 74 | +
|
| 75 | +Proceed with these tags? (y/n) |
| 76 | +``` |
| 77 | + |
| 78 | +### Step 4: Verify prerequisites |
| 79 | + |
| 80 | +Check `gh` authentication: |
| 81 | + |
| 82 | +```bash |
| 83 | +gh auth status |
| 84 | +``` |
| 85 | + |
| 86 | +If not authenticated, instruct the user to run `gh auth login`. |
| 87 | + |
| 88 | +**Validate that both tags exist on GitHub:** |
| 89 | + |
| 90 | +```bash |
| 91 | +gh api repos/{owner}/{repo}/git/ref/tags/{current_tag} |
| 92 | +gh api repos/{owner}/{repo}/git/ref/tags/{previous_tag} |
| 93 | +``` |
| 94 | + |
| 95 | +If either tag does not exist on GitHub, **stop and report the error** — do not proceed. |
| 96 | + |
| 97 | +**Check GitHub release status for the current tag:** |
| 98 | + |
| 99 | +```bash |
| 100 | +gh release view {current_tag} --json isDraft,isPrerelease,tagName |
| 101 | +``` |
| 102 | + |
| 103 | +- If **no release exists** for the tag: warn the user, but allow proceeding (notes can be generated for preview, but cannot be uploaded). |
| 104 | +- If the release is a **draft** (`isDraft: true`): proceed normally — this is the expected state for generating release notes. |
| 105 | +- If the release is **published** (not draft, not prerelease): **ask for explicit confirmation** before proceeding, since updating will override an already-published release: |
| 106 | + |
| 107 | +```text |
| 108 | +⚠️ The release for {current_tag} is already published (not a draft). |
| 109 | +Updating it will override the existing release notes. |
| 110 | +Are you sure you want to proceed? (y/n) |
| 111 | +``` |
| 112 | + |
| 113 | +Only continue if the user confirms. |
| 114 | + |
| 115 | +### Step 5: Gather PR/commit data |
| 116 | + |
| 117 | +Use `gh api` to collect data between the two tags: |
| 118 | + |
| 119 | +**Compare commits:** |
| 120 | + |
| 121 | +```bash |
| 122 | +gh api repos/{owner}/{repo}/compare/{previous_tag}...{current_tag} --jq '.commits[].sha' |
| 123 | +``` |
| 124 | + |
| 125 | +**For each commit, find associated PRs:** |
| 126 | + |
| 127 | +```bash |
| 128 | +gh api repos/{owner}/{repo}/commits/{sha}/pulls |
| 129 | +``` |
| 130 | + |
| 131 | +**Deduplicate by PR number.** For each PR/commit, extract: |
| 132 | + |
| 133 | +- PR number, title, body, author, URL, labels |
| 134 | +- JIRA tickets using regex pattern: `SRVKP-\d+` (search in PR title, PR body, and commit message) |
| 135 | + |
| 136 | +For commits not associated with any PR, include them as standalone commit entries with their SHA, message, author, and URL. |
| 137 | + |
| 138 | +**IMPORTANT**: This step involves many API calls. Process commits in reasonable batches and report progress to the user. |
| 139 | + |
| 140 | +### Step 6: Categorize changes |
| 141 | + |
| 142 | +Using the gathered PR/commit data, categorize each entry into exactly these sections (skip empty ones): |
| 143 | + |
| 144 | +- `## ✨ Major changes and Features` |
| 145 | +- `## 🐛 Bug Fixes` |
| 146 | +- `## 📚 Documentation Updates` |
| 147 | +- `## ⚙️ Chores` |
| 148 | + |
| 149 | +Use the entry format specified in `references/release-notes-format.md`. |
| 150 | + |
| 151 | +**Categorization guidelines:** |
| 152 | + |
| 153 | +- New capabilities, enhancements, significant behavior changes → Features |
| 154 | +- Bug fixes, error corrections, regression fixes → Bug Fixes |
| 155 | +- Documentation-only changes (docs/, README, comments) → Documentation Updates |
| 156 | +- Dependencies, CI/CD, refactoring, formatting, test-only changes → Chores |
| 157 | +- Within each section, entries with JIRA tickets go FIRST, before entries without JIRA tickets |
| 158 | + |
| 159 | +**Internal vs user-facing detection:** |
| 160 | + |
| 161 | +Changes that match ANY of these patterns are internal and belong in Chores, NOT Features — regardless of `feat:` prefix: |
| 162 | + |
| 163 | +- CI/CD pipeline changes (`.tekton/`, `.github/workflows/`, Makefile targets) |
| 164 | +- Release infrastructure (release scripts, release pipeline tasks, goreleaser config) |
| 165 | +- Test infrastructure (test helpers, e2e framework, test configuration) |
| 166 | +- Build system changes (Dockerfile, ko config, build scripts) |
| 167 | +- Developer tooling (linter config, pre-commit hooks, code generation) |
| 168 | +- Internal refactoring that doesn't change user-visible behavior |
| 169 | + |
| 170 | +Only classify as Features when the change is **visible to end users**: new CLI flags, new API fields, new provider capabilities, new webhook behaviors, new configuration options, new user-facing commands. |
| 171 | + |
| 172 | +### Step 7: Assemble complete release notes |
| 173 | + |
| 174 | +Combine all sections in this order: |
| 175 | + |
| 176 | +1. **Header** (see `references/release-notes-format.md` for template) |
| 177 | +2. **Categorized sections** from Step 6 |
| 178 | +3. **Installation section** (see `references/release-notes-format.md` for template) |
| 179 | +4. **GitHub auto-generated changelog**: |
| 180 | + |
| 181 | +```bash |
| 182 | +gh api repos/{owner}/{repo}/releases/generate-notes -f tag_name="{current_tag}" -f previous_tag_name="{previous_tag}" |
| 183 | +``` |
| 184 | + |
| 185 | +Extract the `body` field from the response. |
| 186 | + |
| 187 | +### Step 8: Output, save, and optional GitHub release update |
| 188 | + |
| 189 | +1. **Always write** the complete release notes to `/tmp/release-notes-{current_tag}.md` and tell the user the file path. |
| 190 | +2. **Display** the complete release notes to the user. |
| 191 | +3. **Ask** if they want to update the GitHub release: |
| 192 | + |
| 193 | +```text |
| 194 | +Release notes saved to /tmp/release-notes-{current_tag}.md |
| 195 | +
|
| 196 | +Would you like to update the GitHub release for {current_tag} with these notes? (y/n) |
| 197 | +``` |
| 198 | + |
| 199 | +1. If yes, update via: |
| 200 | + |
| 201 | +```bash |
| 202 | +gh release edit {current_tag} --notes-file /tmp/release-notes-{current_tag}.md |
| 203 | +``` |
| 204 | + |
| 205 | +If the release has a TODO placeholder (matching pattern `TODO: XXXXX.*?see older releases for some example`), replace only that placeholder in the existing release body rather than overwriting the entire body. |
| 206 | + |
| 207 | +### Step 9: Slack announcement (optional) |
| 208 | + |
| 209 | +After Step 8, ask the user if they want a Slack announcement message. |
| 210 | + |
| 211 | +If yes: |
| 212 | + |
| 213 | +1. Generate a friendly summary with a few emojis (not excessive), listing the top 5-7 most important features and/or bug fixes. Max 7 items total. |
| 214 | +2. Save to `/tmp/release-notes-slack-{current_tag}.txt` and tell the user the file path so they can copy-paste. |
| 215 | +3. Append the GitHub release URL at the end of the message. |
| 216 | + |
| 217 | +## Error Handling |
| 218 | + |
| 219 | +| Scenario | Action | |
| 220 | +| --- | --- | |
| 221 | +| No tag at HEAD | List recent tags, ask user to pick one | |
| 222 | +| User-specified tag doesn't exist locally | Error and ask user to verify the tag name | |
| 223 | +| Tag doesn't exist on GitHub | Stop and report error — do not proceed | |
| 224 | +| `gh` not authenticated | Instruct user to run `gh auth login` | |
| 225 | +| No previous tag found | Ask user to provide one manually | |
| 226 | +| No GitHub release for tag | Warn but allow generating notes for preview | |
| 227 | +| Release is a draft | Proceed normally (expected state) | |
| 228 | +| Release is already published | Ask for explicit confirmation before overriding | |
| 229 | +| API rate limiting | Report the error, suggest waiting or using a different token | |
| 230 | + |
| 231 | +## User Confirmation Requirements |
| 232 | + |
| 233 | +**CRITICAL**: Always confirm tags before gathering data. Always confirm before updating a GitHub release. Never update a release without explicit user approval. |
0 commit comments