From 9c94a4818f52f87e73a9e2952db2d6aa9137ec12 Mon Sep 17 00:00:00 2001 From: snomiao Date: Wed, 5 Nov 2025 10:15:37 +0000 Subject: [PATCH] [feat] Remove Additions section and add hyperlinks to API changelog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- .github/workflows/manual-api-changelog.yaml | 8 +- .github/workflows/release-api-changelogs.yaml | 6 ++ scripts/compare-api-snapshots.js | 90 ++++++++++++------- scripts/snapshot-api.js | 24 +++-- 4 files changed, 87 insertions(+), 41 deletions(-) diff --git a/.github/workflows/manual-api-changelog.yaml b/.github/workflows/manual-api-changelog.yaml index 468a69aa6..457176113 100644 --- a/.github/workflows/manual-api-changelog.yaml +++ b/.github/workflows/manual-api-changelog.yaml @@ -149,12 +149,18 @@ jobs: - name: Compare API snapshots and generate changelog id: generate_changelog run: | + # Get git ref for TO version + GIT_REF=$(git rev-parse ${{ steps.validate_versions.outputs.to_tag }}) + # Run the comparison script CHANGELOG_OUTPUT=$(node scripts/compare-api-snapshots.js \ .api-snapshots/from.json \ .api-snapshots/to.json \ ${{ steps.validate_versions.outputs.from_version }} \ - ${{ steps.validate_versions.outputs.to_version }}) + ${{ steps.validate_versions.outputs.to_version }} \ + Comfy-Org \ + ComfyUI_frontend \ + "$GIT_REF") # Save changelog to file for artifact echo "$CHANGELOG_OUTPUT" > .api-snapshots/CHANGELOG-${{ steps.validate_versions.outputs.from_version }}-to-${{ steps.validate_versions.outputs.to_version }}.md diff --git a/.github/workflows/release-api-changelogs.yaml b/.github/workflows/release-api-changelogs.yaml index e03a92a72..a66a5d8fe 100644 --- a/.github/workflows/release-api-changelogs.yaml +++ b/.github/workflows/release-api-changelogs.yaml @@ -141,6 +141,9 @@ jobs: # Create docs directory if it doesn't exist mkdir -p docs + # Get current git ref (commit SHA) + GIT_REF=$(git rev-parse HEAD) + # Run the comparison script if [ -f .api-snapshots/previous.json ]; then node scripts/compare-api-snapshots.js \ @@ -148,6 +151,9 @@ jobs: .api-snapshots/current.json \ ${{ steps.previous_version.outputs.version }} \ ${{ steps.current_version.outputs.version }} \ + Comfy-Org \ + ComfyUI_frontend \ + "$GIT_REF" \ >> docs/API-CHANGELOG.md else # First release - just document the initial API surface diff --git a/scripts/compare-api-snapshots.js b/scripts/compare-api-snapshots.js index d27017cea..9bc4dda89 100644 --- a/scripts/compare-api-snapshots.js +++ b/scripts/compare-api-snapshots.js @@ -10,12 +10,20 @@ import * as fs from 'fs' const args = process.argv.slice(2) if (args.length < 4) { console.error( - 'Usage: compare-api-snapshots.js ' + 'Usage: compare-api-snapshots.js [repo-owner] [repo-name] [git-ref]' ) process.exit(1) } -const [previousPath, currentPath, previousVersion, currentVersion] = args +const [ + previousPath, + currentPath, + previousVersion, + currentVersion, + repoOwner = 'Comfy-Org', + repoName = 'ComfyUI_frontend', + gitRef = 'main' +] = args if (!fs.existsSync(previousPath)) { console.error(`Previous snapshot not found: ${previousPath}`) @@ -30,6 +38,15 @@ if (!fs.existsSync(currentPath)) { const previousApi = JSON.parse(fs.readFileSync(previousPath, 'utf-8')) const currentApi = JSON.parse(fs.readFileSync(currentPath, 'utf-8')) +/** + * Generate GitHub permalink to source code + */ +function generateGitHubLink(name, line) { + if (!line) return name + // Format: https://github.com/Comfy-Org/ComfyUI_frontend/blob/main/dist/index.d.ts#L123 + return `[\`${name}\`](https://github.com/${repoOwner}/${repoName}/blob/${gitRef}/dist/index.d.ts#L${line})` +} + /** * Compare two API snapshots and generate changelog */ @@ -263,37 +280,40 @@ function formatChangelog(changes, prevVersion, currVersion) { lines.push(`**${categoryToTitle(category)}**`) lines.push('') for (const item of items) { - lines.push(`- **Removed**: \`${item.name}\``) + const displayName = item.item?.line + ? generateGitHubLink(item.name, item.item.line) + : `\`${item.name}\`` + lines.push(`- **Removed**: ${displayName}`) } lines.push('') } } - // Additions - if (changes.additions.length > 0) { - lines.push('### ✨ Additions') - lines.push('') - - const grouped = groupByCategory(changes.additions) - for (const [category, items] of Object.entries(grouped)) { - lines.push(`**${categoryToTitle(category)}**`) - lines.push('') - for (const item of items) { - lines.push(`- \`${item.name}\``) - if (item.item.members && item.item.members.length > 0) { - const publicMembers = item.item.members.filter( - (m) => !m.visibility || m.visibility === 'public' - ) - if (publicMembers.length > 0 && publicMembers.length <= 5) { - lines.push( - ` - Members: ${publicMembers.map((m) => `\`${m.name}\``).join(', ')}` - ) - } - } - } - lines.push('') - } - } + // Additions - commented out as per feedback + // if (changes.additions.length > 0) { + // lines.push('### ✨ Additions') + // lines.push('') + // + // const grouped = groupByCategory(changes.additions) + // for (const [category, items] of Object.entries(grouped)) { + // lines.push(`**${categoryToTitle(category)}**`) + // lines.push('') + // for (const item of items) { + // lines.push(`- \`${item.name}\``) + // if (item.item.members && item.item.members.length > 0) { + // const publicMembers = item.item.members.filter( + // (m) => !m.visibility || m.visibility === 'public' + // ) + // if (publicMembers.length > 0 && publicMembers.length <= 5) { + // lines.push( + // ` - Members: ${publicMembers.map((m) => `\`${m.name}\``).join(', ')}` + // ) + // } + // } + // } + // lines.push('') + // } + // } // Modifications if (changes.modifications.length > 0) { @@ -314,7 +334,13 @@ function formatChangelog(changes, prevVersion, currVersion) { lines.push(`**${categoryToTitle(category)}**`) lines.push('') for (const item of items) { - lines.push(`- \`${item.name}\``) + // Get the current item to access line number + const currItem = + currentApi[item.category] && currentApi[item.category][item.name] + const displayName = currItem?.line + ? generateGitHubLink(item.name, currItem.line) + : `\`${item.name}\`` + lines.push(`- ${displayName}`) for (const change of item.changes) { const formatted = formatChange(change) if (formatted) { @@ -326,11 +352,7 @@ function formatChangelog(changes, prevVersion, currVersion) { } } - if ( - changes.breaking.length === 0 && - changes.additions.length === 0 && - changes.modifications.length === 0 - ) { + if (changes.breaking.length === 0 && changes.modifications.length === 0) { lines.push('_No API changes detected._') lines.push('') } diff --git a/scripts/snapshot-api.js b/scripts/snapshot-api.js index 360b6d838..15edb7e63 100644 --- a/scripts/snapshot-api.js +++ b/scripts/snapshot-api.js @@ -38,17 +38,20 @@ function extractApiSurface(sourceFile) { // Extract type aliases if (ts.isTypeAliasDeclaration(node) && node.name) { const name = node.name.text + const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart()) api.types[name] = { kind: 'type', name, text: node.getText(sourceFile), - exported: hasExportModifier(node) + exported: hasExportModifier(node), + line: line + 1 // Convert to 1-indexed } } // Extract interfaces if (ts.isInterfaceDeclaration(node) && node.name) { const name = node.name.text + const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart()) const members = [] node.members.forEach((member) => { @@ -83,13 +86,15 @@ function extractApiSurface(sourceFile) { clause.types.map((type) => type.getText(sourceFile)) ) .flat() - : [] + : [], + line: line + 1 // Convert to 1-indexed } } // Extract enums if (ts.isEnumDeclaration(node) && node.name) { const name = node.name.text + const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart()) const members = node.members.map((member) => ({ name: member.name.getText(sourceFile), value: member.initializer @@ -101,13 +106,15 @@ function extractApiSurface(sourceFile) { kind: 'enum', name, members, - exported: hasExportModifier(node) + exported: hasExportModifier(node), + line: line + 1 // Convert to 1-indexed } } // Extract functions if (ts.isFunctionDeclaration(node) && node.name) { const name = node.name.text + const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart()) api.functions[name] = { kind: 'function', name, @@ -117,13 +124,15 @@ function extractApiSurface(sourceFile) { optional: !!p.questionToken })), returnType: node.type ? node.type.getText(sourceFile) : 'any', - exported: hasExportModifier(node) + exported: hasExportModifier(node), + line: line + 1 // Convert to 1-indexed } } // Extract classes if (ts.isClassDeclaration(node) && node.name) { const name = node.name.text + const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart()) const members = [] const methods = [] @@ -162,12 +171,14 @@ function extractApiSurface(sourceFile) { clause.types.map((type) => type.getText(sourceFile)) ) .flat() - : [] + : [], + line: line + 1 // Convert to 1-indexed } } // Extract variable declarations (constants) if (ts.isVariableStatement(node)) { + const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart()) node.declarationList.declarations.forEach((decl) => { if (decl.name && ts.isIdentifier(decl.name)) { const name = decl.name.text @@ -175,7 +186,8 @@ function extractApiSurface(sourceFile) { kind: 'constant', name, type: decl.type ? decl.type.getText(sourceFile) : 'unknown', - exported: hasExportModifier(node) + exported: hasExportModifier(node), + line: line + 1 // Convert to 1-indexed } } })