|
1 | 1 | --- |
2 | 2 | name: changelog-generator |
3 | | -description: Generate and maintain CHANGELOG.md following Keep a Changelog format with human-readable descriptions. Use when: (1) Creating initial changelog from git tags, (2) Updating changelog for new releases, (3) Generating unreleased section for pull requests. Rule: NEVER use commit messages as source of truth - analyze code diffs instead. |
| 3 | +description: Generate or refresh human-readable CHANGELOG.md files that follow Keep a Changelog by comparing git tags and code diffs instead of commit messages. Use when Codex needs to bootstrap a changelog for a repository, backfill undocumented tagged releases, update release entries, or rewrite the Unreleased section for current branch work using the phly/keep-a-changelog commands available in the project. |
4 | 4 | --- |
5 | 5 |
|
6 | 6 | # Changelog Generator |
7 | 7 |
|
8 | | -Generates and maintains CHANGELOG.md following the Keep a Changelog format with clear, specific, and self-sufficient descriptions. |
| 8 | +Generate changelog entries that a reader can understand without opening the code. |
9 | 9 |
|
10 | | -## Dependencies |
| 10 | +## Deterministic Helpers |
11 | 11 |
|
12 | | -- `phly/keep-a-changelog` - Installed in project |
13 | | -- Git - For analyzing code changes |
14 | | -- GitHub CLI (`gh`) - For reading PR context |
15 | | -- Filesystem - For reading/writing CHANGELOG.md |
| 12 | +Use the bundled PHP scripts before manual analysis: |
16 | 13 |
|
17 | | -## PR Context Integration |
18 | | - |
19 | | -When generating changelog for changes that belong to a PR: |
20 | | - |
21 | | -1. Detect PR reference: Check git branch name or recent PR comments |
22 | | -2. Fetch PR description: Use `gh pr view <pr-number> --json body` |
23 | | -3. Extract context: Read the PR Summary and Changes sections |
24 | | -4. Enhance descriptions: Use PR context to write more accurate changelog entries |
25 | | - |
26 | | -Example workflow: |
27 | 14 | ```bash |
28 | | -# Detect current PR |
29 | | -BRANCH=$(git branch --show-current) |
30 | | -PR_NUM=$(echo "$BRANCH" | grep -oE '[0-9]+' | head -1) |
31 | | - |
32 | | -# Fetch PR context if exists |
33 | | -if [ -n "$PR_NUM" ]; then |
34 | | - PR_BODY=$(gh pr view "$PR_NUM" --json body --jq '.body') |
35 | | - # Use PR body as an extra context to define the changelog descriptions |
36 | | -fi |
| 15 | +php .agents/skills/changelog-generator/scripts/changelog-state.php |
| 16 | +php .agents/skills/changelog-generator/scripts/diff-inventory.php <from-ref> <to-ref> |
37 | 17 | ``` |
38 | 18 |
|
39 | | -This ensures changelog descriptions align with the PR intent and provide better context. |
40 | | - |
41 | | -## Key Commands |
| 19 | +- `changelog-state.php` reports changelog presence, documented versions, discovered tags, undocumented tags, and suggested release ranges as JSON. |
| 20 | +- `diff-inventory.php` reports changed files, line counts, and likely user-visible paths for a specific diff range as JSON. |
| 21 | +- Both scripts auto-discover the repository root and opportunistically load `vendor/autoload.php` when it exists. |
| 22 | + |
| 23 | +## Workflow |
| 24 | + |
| 25 | +1. Establish current state. |
| 26 | +- Read `CHANGELOG.md` if it exists. |
| 27 | +- Prefer `changelog-state.php` to gather versions and ranges before inspecting files manually. |
| 28 | +- Record documented versions and whether `## Unreleased - TBD` already exists. |
| 29 | +- List tags in ascending semantic order with `git tag --sort=version:refname`, and capture their commit dates when the repository may have retroactive or out-of-sequence tags. |
| 30 | +- Treat commit messages as navigation hints only; never derive final changelog text from them. |
| 31 | + |
| 32 | +2. Choose diff ranges. |
| 33 | +- If `CHANGELOG.md` is missing or empty, analyze each tag range from the first tagged version onward. |
| 34 | +- If `CHANGELOG.md` already documents releases, start at the first tag after the last documented version. |
| 35 | +- When tag publication order differs from semantic order, prefer the actual tag chronology for release ordering and use diffs that follow that real release sequence. |
| 36 | +- Build `Unreleased` from the diff between the latest documented release or tag and `HEAD`. |
| 37 | + |
| 38 | +3. Analyze changes from diffs. |
| 39 | +- Prefer `diff-inventory.php <from> <to>` first so you can focus on the files most likely to affect user-visible behavior. |
| 40 | +- Start with `git diff --name-status <from> <to>` and `git diff --stat <from> <to>`. |
| 41 | +- Open targeted `git diff --unified=0 <from> <to> -- <path>` views for files that define public behavior, commands, config, schemas, workflows, or exposed APIs. |
| 42 | +- Classify entries by observed impact: |
| 43 | + - `Added`: new files, APIs, commands, options, configuration, workflows, or user-visible capabilities |
| 44 | + - `Changed`: modified behavior, signature or default changes, renamed flows, or compatibility-preserving refactors with visible impact |
| 45 | + - `Fixed`: bug fixes, validation corrections, edge-case handling, or broken workflows |
| 46 | + - `Removed`: deleted APIs, commands, config, or capabilities |
| 47 | + - `Deprecated`: explicit deprecation notices or migration paths |
| 48 | + - `Security`: hardening or vulnerability fixes |
| 49 | +- Skip pure churn that a reader would not care about unless it changes behavior or release expectations. |
| 50 | +- Deduplicate multiple file changes that describe the same user-visible outcome. |
| 51 | + |
| 52 | +4. Write human-readable entries. |
| 53 | +- Write one line per change. |
| 54 | +- Prefer the functional effect over implementation detail. |
| 55 | +- Mention the concrete command, class, option, workflow, or API when that improves comprehension. |
| 56 | +- When a matching PR exists, append it to the line in the format `(#123)` after the diff already supports the entry. |
| 57 | +- Avoid vague phrases such as `misc improvements`, `refactorings`, or `code cleanup`. |
| 58 | + |
| 59 | +5. Apply changes with project tooling. |
| 60 | +- Prefer the local wrappers when available: |
42 | 61 |
|
43 | 62 | ```bash |
44 | | -vendor/bin/changelog # Main CLI |
45 | | -vendor/bin/changelog add:entry # Add entry to version |
46 | | -vendor/bin/changelog release # Create release |
| 63 | +composer dev-tools changelog:init |
| 64 | +composer dev-tools changelog:check |
47 | 65 | ``` |
48 | 66 |
|
49 | | -## Execution Pipeline (Deterministic) |
50 | | - |
51 | | -### Stage 1: Initial State |
52 | | - |
53 | | -1. Check if CHANGELOG.md exists and has content: |
54 | | - ```bash |
55 | | - ls -la CHANGELOG.md 2>/dev/null || echo "NO_FILE" |
56 | | - ``` |
57 | | - |
58 | | -### Stage 2: Version Discovery |
59 | | - |
60 | | -1. List all tags sorted semantically: |
61 | | - ```bash |
62 | | - git tag --sort=-version:refname |
63 | | - ``` |
64 | | - |
65 | | -2. Identify: |
66 | | - - Last documented version in CHANGELOG |
67 | | - - Tags not yet documented |
68 | | - |
69 | | -### Stage 3: Historical Content Generation |
70 | | - |
71 | | -**Case A: No CHANGELOG or Empty** |
72 | | - |
73 | | -For each tag (ascending order): |
74 | | -1. Calculate diff between current tag and previous tag (or first commit for initial version) |
75 | | -2. Analyze code diff to infer changes (NOT commit messages) |
76 | | -3. Group changes by type (Added, Changed, Fixed, Removed, Deprecated, Security) |
77 | | -4. Insert version section |
78 | | - |
79 | | -**B: Existing CHANGELOG** |
80 | | - |
81 | | -1. Identify last documented version |
82 | | -2. For each subsequent tag: |
83 | | - - Generate diff between versions |
84 | | - - Insert new section in changelog |
85 | | - |
86 | | -### Stage 4: Unreleased Section |
87 | | - |
88 | | -1. Calculate diff between last documented tag and HEAD |
89 | | -2. Generate [Unreleased] section with current changes |
90 | | - |
91 | | -## Change Classification (Inferred from Diff) |
92 | | - |
93 | | -Analyze actual code changes, NOT commit messages: |
94 | | - |
95 | | -| Pattern | Category | |
96 | | -|---------|----------| |
97 | | -| New files, new classes, new methods | Added | |
98 | | -| Behavior changes, refactors, signature changes | Changed | |
99 | | -| Bug fixes, validation fixes | Fixed | |
100 | | -| Deleted classes, removed methods | Removed | |
101 | | -| @deprecated markers | Deprecated | |
102 | | -| Security patches | Security | |
103 | | - |
104 | | -## Quality Rules |
105 | | - |
106 | | -- **SHORT**: One line per change |
107 | | -- **SPECIFIC**: Include class/method names |
108 | | -- **SELF-SUFFICIENT**: Understand without reading code |
109 | | -- **FUNCTIONAL**: Describe impact, not implementation |
110 | | -- **PR-AWARE**: Use PR description to enhance accuracy when available |
111 | | - |
112 | | -Good: "Added `Bootstrapper::bootstrap()` to create CHANGELOG.md when missing" |
113 | | -Bad: "Add bootstrap command" |
114 | | - |
115 | | -## PR Context Usage |
116 | | - |
117 | | -When a PR number is available: |
118 | | - |
119 | | -1. Read PR description for implementation intent |
120 | | -2. Extract key capabilities mentioned in Summary |
121 | | -3. Use specific feature names from the PR to write accurate descriptions |
122 | | -4. Reference PR in changelog: "Added changelog automation (#40)" |
123 | | - |
124 | | -## Integration with keep-a-changelog |
125 | | - |
126 | | -Use CLI commands when possible: |
| 67 | +- Use the official CLI for entries and releases: |
127 | 68 |
|
128 | 69 | ```bash |
129 | | -# Add unreleased entry |
130 | | -vendor/bin/changelog add:entry --unreleased --type=added "Description" |
| 70 | +vendor/bin/keep-a-changelog entry:added "..." |
| 71 | +vendor/bin/keep-a-changelog entry:changed "..." |
| 72 | +vendor/bin/keep-a-changelog entry:fixed "..." |
| 73 | +vendor/bin/keep-a-changelog unreleased:create --no-interaction |
| 74 | +vendor/bin/keep-a-changelog unreleased:promote 1.2.0 --date=2026-04-12 --no-interaction |
| 75 | +vendor/bin/keep-a-changelog version:show 1.2.0 |
| 76 | +vendor/bin/keep-a-changelog version:release 1.2.0 --provider-token=... |
| 77 | +``` |
131 | 78 |
|
132 | | -# Add release entry |
133 | | -vendor/bin/changelog add:entry 1.0.0 --type=added "Description" |
| 79 | +- For large historical backfills, direct markdown editing is acceptable for the first draft. After that, use the CLI to keep `Unreleased` and future entries consistent. |
134 | 80 |
|
135 | | -# Create release |
136 | | -vendor/bin/changelog release 1.0.0 --date="2026-04-11" |
137 | | -``` |
| 81 | +6. Verify the result. |
| 82 | +- Keep `Unreleased` first and released versions in reverse chronological order. |
| 83 | +- Keep section order as `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`, `Security`. |
| 84 | +- Do not duplicate the same change across sections or versions. |
| 85 | +- Ensure every documented version maps to a real tag or intentional unreleased state. |
| 86 | +- Run local helpers such as `composer dev-tools changelog:check` when the project provides them. |
| 87 | + |
| 88 | +## PR Context |
138 | 89 |
|
139 | | -Edit CHANGELOG.md directly if CLI insufficient. |
| 90 | +Use PR descriptions, issue text, or release notes only to refine wording after diff analysis confirms the change. Good uses: |
140 | 91 |
|
141 | | -## Verification |
| 92 | +- naming a feature exactly as presented to users |
| 93 | +- adding a stable reference like `(#123)` |
| 94 | +- understanding why a visible change matters when the diff alone is ambiguous |
142 | 95 |
|
143 | | -Valid changelog MUST have: |
144 | | -- All sections: Added, Changed, Deprecated, Removed, Fixed, Security |
145 | | -- No "Nothing." placeholders (unless truly empty) |
146 | | -- Reverse chronological order (newest first) |
147 | | -- [Unreleased] at top when applicable |
| 96 | +Do not use PR text to invent entries that are not supported by the code diff. |
148 | 97 |
|
149 | 98 | ## Reference Files |
150 | 99 |
|
151 | | -- [references/keep-a-changelog-format.md](references/keep-a-changelog-format.md) - Format spec |
152 | | -- [references/change-categories.md](references/change-categories.md) - Classification guide |
153 | | -- [references/description-patterns.md](references/description-patterns.md) - Human-readable patterns |
| 100 | +- Read [references/keep-a-changelog-format.md](references/keep-a-changelog-format.md) for heading format, section order, and CLI mapping. |
| 101 | +- Read [references/change-categories.md](references/change-categories.md) when the diff spans multiple change types. |
| 102 | +- Read [references/description-patterns.md](references/description-patterns.md) when the first draft still sounds too internal or vague. |
0 commit comments