mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-08 17:10:07 +00:00
[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>
This commit is contained in:
8
.github/workflows/manual-api-changelog.yaml
vendored
8
.github/workflows/manual-api-changelog.yaml
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <previous.json> <current.json> <previous-version> <current-version>'
|
||||
'Usage: compare-api-snapshots.js <previous.json> <current.json> <previous-version> <current-version> [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('')
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user