Skip to content

Commit 9c94a48

Browse files
snomiaoclaude
andcommitted
[feat] Remove Additions section and add hyperlinks to API changelog
- Remove Additions section from changelog output (no longer needed) - Add line number tracking in API snapshots - Generate GitHub permalinks to referenced code in changelog - Update workflows to pass git reference for link generation - Breaking changes and modifications now link to source code 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 779f539 commit 9c94a48

File tree

4 files changed

+87
-41
lines changed

4 files changed

+87
-41
lines changed

.github/workflows/manual-api-changelog.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,18 @@ jobs:
149149
- name: Compare API snapshots and generate changelog
150150
id: generate_changelog
151151
run: |
152+
# Get git ref for TO version
153+
GIT_REF=$(git rev-parse ${{ steps.validate_versions.outputs.to_tag }})
154+
152155
# Run the comparison script
153156
CHANGELOG_OUTPUT=$(node scripts/compare-api-snapshots.js \
154157
.api-snapshots/from.json \
155158
.api-snapshots/to.json \
156159
${{ steps.validate_versions.outputs.from_version }} \
157-
${{ steps.validate_versions.outputs.to_version }})
160+
${{ steps.validate_versions.outputs.to_version }} \
161+
Comfy-Org \
162+
ComfyUI_frontend \
163+
"$GIT_REF")
158164
159165
# Save changelog to file for artifact
160166
echo "$CHANGELOG_OUTPUT" > .api-snapshots/CHANGELOG-${{ steps.validate_versions.outputs.from_version }}-to-${{ steps.validate_versions.outputs.to_version }}.md

.github/workflows/release-api-changelogs.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,13 +141,19 @@ jobs:
141141
# Create docs directory if it doesn't exist
142142
mkdir -p docs
143143
144+
# Get current git ref (commit SHA)
145+
GIT_REF=$(git rev-parse HEAD)
146+
144147
# Run the comparison script
145148
if [ -f .api-snapshots/previous.json ]; then
146149
node scripts/compare-api-snapshots.js \
147150
.api-snapshots/previous.json \
148151
.api-snapshots/current.json \
149152
${{ steps.previous_version.outputs.version }} \
150153
${{ steps.current_version.outputs.version }} \
154+
Comfy-Org \
155+
ComfyUI_frontend \
156+
"$GIT_REF" \
151157
>> docs/API-CHANGELOG.md
152158
else
153159
# First release - just document the initial API surface

scripts/compare-api-snapshots.js

Lines changed: 56 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,20 @@ import * as fs from 'fs'
1010
const args = process.argv.slice(2)
1111
if (args.length < 4) {
1212
console.error(
13-
'Usage: compare-api-snapshots.js <previous.json> <current.json> <previous-version> <current-version>'
13+
'Usage: compare-api-snapshots.js <previous.json> <current.json> <previous-version> <current-version> [repo-owner] [repo-name] [git-ref]'
1414
)
1515
process.exit(1)
1616
}
1717

18-
const [previousPath, currentPath, previousVersion, currentVersion] = args
18+
const [
19+
previousPath,
20+
currentPath,
21+
previousVersion,
22+
currentVersion,
23+
repoOwner = 'Comfy-Org',
24+
repoName = 'ComfyUI_frontend',
25+
gitRef = 'main'
26+
] = args
1927

2028
if (!fs.existsSync(previousPath)) {
2129
console.error(`Previous snapshot not found: ${previousPath}`)
@@ -30,6 +38,15 @@ if (!fs.existsSync(currentPath)) {
3038
const previousApi = JSON.parse(fs.readFileSync(previousPath, 'utf-8'))
3139
const currentApi = JSON.parse(fs.readFileSync(currentPath, 'utf-8'))
3240

41+
/**
42+
* Generate GitHub permalink to source code
43+
*/
44+
function generateGitHubLink(name, line) {
45+
if (!line) return name
46+
// Format: https://github.com/Comfy-Org/ComfyUI_frontend/blob/main/dist/index.d.ts#L123
47+
return `[\`${name}\`](https://github.com/${repoOwner}/${repoName}/blob/${gitRef}/dist/index.d.ts#L${line})`
48+
}
49+
3350
/**
3451
* Compare two API snapshots and generate changelog
3552
*/
@@ -263,37 +280,40 @@ function formatChangelog(changes, prevVersion, currVersion) {
263280
lines.push(`**${categoryToTitle(category)}**`)
264281
lines.push('')
265282
for (const item of items) {
266-
lines.push(`- **Removed**: \`${item.name}\``)
283+
const displayName = item.item?.line
284+
? generateGitHubLink(item.name, item.item.line)
285+
: `\`${item.name}\``
286+
lines.push(`- **Removed**: ${displayName}`)
267287
}
268288
lines.push('')
269289
}
270290
}
271291

272-
// Additions
273-
if (changes.additions.length > 0) {
274-
lines.push('### ✨ Additions')
275-
lines.push('')
276-
277-
const grouped = groupByCategory(changes.additions)
278-
for (const [category, items] of Object.entries(grouped)) {
279-
lines.push(`**${categoryToTitle(category)}**`)
280-
lines.push('')
281-
for (const item of items) {
282-
lines.push(`- \`${item.name}\``)
283-
if (item.item.members && item.item.members.length > 0) {
284-
const publicMembers = item.item.members.filter(
285-
(m) => !m.visibility || m.visibility === 'public'
286-
)
287-
if (publicMembers.length > 0 && publicMembers.length <= 5) {
288-
lines.push(
289-
` - Members: ${publicMembers.map((m) => `\`${m.name}\``).join(', ')}`
290-
)
291-
}
292-
}
293-
}
294-
lines.push('')
295-
}
296-
}
292+
// Additions - commented out as per feedback
293+
// if (changes.additions.length > 0) {
294+
// lines.push('### ✨ Additions')
295+
// lines.push('')
296+
//
297+
// const grouped = groupByCategory(changes.additions)
298+
// for (const [category, items] of Object.entries(grouped)) {
299+
// lines.push(`**${categoryToTitle(category)}**`)
300+
// lines.push('')
301+
// for (const item of items) {
302+
// lines.push(`- \`${item.name}\``)
303+
// if (item.item.members && item.item.members.length > 0) {
304+
// const publicMembers = item.item.members.filter(
305+
// (m) => !m.visibility || m.visibility === 'public'
306+
// )
307+
// if (publicMembers.length > 0 && publicMembers.length <= 5) {
308+
// lines.push(
309+
// ` - Members: ${publicMembers.map((m) => `\`${m.name}\``).join(', ')}`
310+
// )
311+
// }
312+
// }
313+
// }
314+
// lines.push('')
315+
// }
316+
// }
297317

298318
// Modifications
299319
if (changes.modifications.length > 0) {
@@ -314,7 +334,13 @@ function formatChangelog(changes, prevVersion, currVersion) {
314334
lines.push(`**${categoryToTitle(category)}**`)
315335
lines.push('')
316336
for (const item of items) {
317-
lines.push(`- \`${item.name}\``)
337+
// Get the current item to access line number
338+
const currItem =
339+
currentApi[item.category] && currentApi[item.category][item.name]
340+
const displayName = currItem?.line
341+
? generateGitHubLink(item.name, currItem.line)
342+
: `\`${item.name}\``
343+
lines.push(`- ${displayName}`)
318344
for (const change of item.changes) {
319345
const formatted = formatChange(change)
320346
if (formatted) {
@@ -326,11 +352,7 @@ function formatChangelog(changes, prevVersion, currVersion) {
326352
}
327353
}
328354

329-
if (
330-
changes.breaking.length === 0 &&
331-
changes.additions.length === 0 &&
332-
changes.modifications.length === 0
333-
) {
355+
if (changes.breaking.length === 0 && changes.modifications.length === 0) {
334356
lines.push('_No API changes detected._')
335357
lines.push('')
336358
}

scripts/snapshot-api.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,20 @@ function extractApiSurface(sourceFile) {
3838
// Extract type aliases
3939
if (ts.isTypeAliasDeclaration(node) && node.name) {
4040
const name = node.name.text
41+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart())
4142
api.types[name] = {
4243
kind: 'type',
4344
name,
4445
text: node.getText(sourceFile),
45-
exported: hasExportModifier(node)
46+
exported: hasExportModifier(node),
47+
line: line + 1 // Convert to 1-indexed
4648
}
4749
}
4850

4951
// Extract interfaces
5052
if (ts.isInterfaceDeclaration(node) && node.name) {
5153
const name = node.name.text
54+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart())
5255
const members = []
5356

5457
node.members.forEach((member) => {
@@ -83,13 +86,15 @@ function extractApiSurface(sourceFile) {
8386
clause.types.map((type) => type.getText(sourceFile))
8487
)
8588
.flat()
86-
: []
89+
: [],
90+
line: line + 1 // Convert to 1-indexed
8791
}
8892
}
8993

9094
// Extract enums
9195
if (ts.isEnumDeclaration(node) && node.name) {
9296
const name = node.name.text
97+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart())
9398
const members = node.members.map((member) => ({
9499
name: member.name.getText(sourceFile),
95100
value: member.initializer
@@ -101,13 +106,15 @@ function extractApiSurface(sourceFile) {
101106
kind: 'enum',
102107
name,
103108
members,
104-
exported: hasExportModifier(node)
109+
exported: hasExportModifier(node),
110+
line: line + 1 // Convert to 1-indexed
105111
}
106112
}
107113

108114
// Extract functions
109115
if (ts.isFunctionDeclaration(node) && node.name) {
110116
const name = node.name.text
117+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart())
111118
api.functions[name] = {
112119
kind: 'function',
113120
name,
@@ -117,13 +124,15 @@ function extractApiSurface(sourceFile) {
117124
optional: !!p.questionToken
118125
})),
119126
returnType: node.type ? node.type.getText(sourceFile) : 'any',
120-
exported: hasExportModifier(node)
127+
exported: hasExportModifier(node),
128+
line: line + 1 // Convert to 1-indexed
121129
}
122130
}
123131

124132
// Extract classes
125133
if (ts.isClassDeclaration(node) && node.name) {
126134
const name = node.name.text
135+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart())
127136
const members = []
128137
const methods = []
129138

@@ -162,20 +171,23 @@ function extractApiSurface(sourceFile) {
162171
clause.types.map((type) => type.getText(sourceFile))
163172
)
164173
.flat()
165-
: []
174+
: [],
175+
line: line + 1 // Convert to 1-indexed
166176
}
167177
}
168178

169179
// Extract variable declarations (constants)
170180
if (ts.isVariableStatement(node)) {
181+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart())
171182
node.declarationList.declarations.forEach((decl) => {
172183
if (decl.name && ts.isIdentifier(decl.name)) {
173184
const name = decl.name.text
174185
api.constants[name] = {
175186
kind: 'constant',
176187
name,
177188
type: decl.type ? decl.type.getText(sourceFile) : 'unknown',
178-
exported: hasExportModifier(node)
189+
exported: hasExportModifier(node),
190+
line: line + 1 // Convert to 1-indexed
179191
}
180192
}
181193
})

0 commit comments

Comments
 (0)