mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 03:01:54 +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
|
- name: Compare API snapshots and generate changelog
|
||||||
id: generate_changelog
|
id: generate_changelog
|
||||||
run: |
|
run: |
|
||||||
|
# Get git ref for TO version
|
||||||
|
GIT_REF=$(git rev-parse ${{ steps.validate_versions.outputs.to_tag }})
|
||||||
|
|
||||||
# Run the comparison script
|
# Run the comparison script
|
||||||
CHANGELOG_OUTPUT=$(node scripts/compare-api-snapshots.js \
|
CHANGELOG_OUTPUT=$(node scripts/compare-api-snapshots.js \
|
||||||
.api-snapshots/from.json \
|
.api-snapshots/from.json \
|
||||||
.api-snapshots/to.json \
|
.api-snapshots/to.json \
|
||||||
${{ steps.validate_versions.outputs.from_version }} \
|
${{ 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
|
# 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
|
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
|
# Create docs directory if it doesn't exist
|
||||||
mkdir -p docs
|
mkdir -p docs
|
||||||
|
|
||||||
|
# Get current git ref (commit SHA)
|
||||||
|
GIT_REF=$(git rev-parse HEAD)
|
||||||
|
|
||||||
# Run the comparison script
|
# Run the comparison script
|
||||||
if [ -f .api-snapshots/previous.json ]; then
|
if [ -f .api-snapshots/previous.json ]; then
|
||||||
node scripts/compare-api-snapshots.js \
|
node scripts/compare-api-snapshots.js \
|
||||||
@@ -148,6 +151,9 @@ jobs:
|
|||||||
.api-snapshots/current.json \
|
.api-snapshots/current.json \
|
||||||
${{ steps.previous_version.outputs.version }} \
|
${{ steps.previous_version.outputs.version }} \
|
||||||
${{ steps.current_version.outputs.version }} \
|
${{ steps.current_version.outputs.version }} \
|
||||||
|
Comfy-Org \
|
||||||
|
ComfyUI_frontend \
|
||||||
|
"$GIT_REF" \
|
||||||
>> docs/API-CHANGELOG.md
|
>> docs/API-CHANGELOG.md
|
||||||
else
|
else
|
||||||
# First release - just document the initial API surface
|
# First release - just document the initial API surface
|
||||||
|
|||||||
@@ -10,12 +10,20 @@ import * as fs from 'fs'
|
|||||||
const args = process.argv.slice(2)
|
const args = process.argv.slice(2)
|
||||||
if (args.length < 4) {
|
if (args.length < 4) {
|
||||||
console.error(
|
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)
|
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)) {
|
if (!fs.existsSync(previousPath)) {
|
||||||
console.error(`Previous snapshot not found: ${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 previousApi = JSON.parse(fs.readFileSync(previousPath, 'utf-8'))
|
||||||
const currentApi = JSON.parse(fs.readFileSync(currentPath, '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
|
* Compare two API snapshots and generate changelog
|
||||||
*/
|
*/
|
||||||
@@ -263,37 +280,40 @@ function formatChangelog(changes, prevVersion, currVersion) {
|
|||||||
lines.push(`**${categoryToTitle(category)}**`)
|
lines.push(`**${categoryToTitle(category)}**`)
|
||||||
lines.push('')
|
lines.push('')
|
||||||
for (const item of items) {
|
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('')
|
lines.push('')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Additions
|
// Additions - commented out as per feedback
|
||||||
if (changes.additions.length > 0) {
|
// if (changes.additions.length > 0) {
|
||||||
lines.push('### ✨ Additions')
|
// lines.push('### ✨ Additions')
|
||||||
lines.push('')
|
// lines.push('')
|
||||||
|
//
|
||||||
const grouped = groupByCategory(changes.additions)
|
// const grouped = groupByCategory(changes.additions)
|
||||||
for (const [category, items] of Object.entries(grouped)) {
|
// for (const [category, items] of Object.entries(grouped)) {
|
||||||
lines.push(`**${categoryToTitle(category)}**`)
|
// lines.push(`**${categoryToTitle(category)}**`)
|
||||||
lines.push('')
|
// lines.push('')
|
||||||
for (const item of items) {
|
// for (const item of items) {
|
||||||
lines.push(`- \`${item.name}\``)
|
// lines.push(`- \`${item.name}\``)
|
||||||
if (item.item.members && item.item.members.length > 0) {
|
// if (item.item.members && item.item.members.length > 0) {
|
||||||
const publicMembers = item.item.members.filter(
|
// const publicMembers = item.item.members.filter(
|
||||||
(m) => !m.visibility || m.visibility === 'public'
|
// (m) => !m.visibility || m.visibility === 'public'
|
||||||
)
|
// )
|
||||||
if (publicMembers.length > 0 && publicMembers.length <= 5) {
|
// if (publicMembers.length > 0 && publicMembers.length <= 5) {
|
||||||
lines.push(
|
// lines.push(
|
||||||
` - Members: ${publicMembers.map((m) => `\`${m.name}\``).join(', ')}`
|
// ` - Members: ${publicMembers.map((m) => `\`${m.name}\``).join(', ')}`
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
lines.push('')
|
// lines.push('')
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Modifications
|
// Modifications
|
||||||
if (changes.modifications.length > 0) {
|
if (changes.modifications.length > 0) {
|
||||||
@@ -314,7 +334,13 @@ function formatChangelog(changes, prevVersion, currVersion) {
|
|||||||
lines.push(`**${categoryToTitle(category)}**`)
|
lines.push(`**${categoryToTitle(category)}**`)
|
||||||
lines.push('')
|
lines.push('')
|
||||||
for (const item of items) {
|
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) {
|
for (const change of item.changes) {
|
||||||
const formatted = formatChange(change)
|
const formatted = formatChange(change)
|
||||||
if (formatted) {
|
if (formatted) {
|
||||||
@@ -326,11 +352,7 @@ function formatChangelog(changes, prevVersion, currVersion) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (changes.breaking.length === 0 && changes.modifications.length === 0) {
|
||||||
changes.breaking.length === 0 &&
|
|
||||||
changes.additions.length === 0 &&
|
|
||||||
changes.modifications.length === 0
|
|
||||||
) {
|
|
||||||
lines.push('_No API changes detected._')
|
lines.push('_No API changes detected._')
|
||||||
lines.push('')
|
lines.push('')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,17 +38,20 @@ function extractApiSurface(sourceFile) {
|
|||||||
// Extract type aliases
|
// Extract type aliases
|
||||||
if (ts.isTypeAliasDeclaration(node) && node.name) {
|
if (ts.isTypeAliasDeclaration(node) && node.name) {
|
||||||
const name = node.name.text
|
const name = node.name.text
|
||||||
|
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart())
|
||||||
api.types[name] = {
|
api.types[name] = {
|
||||||
kind: 'type',
|
kind: 'type',
|
||||||
name,
|
name,
|
||||||
text: node.getText(sourceFile),
|
text: node.getText(sourceFile),
|
||||||
exported: hasExportModifier(node)
|
exported: hasExportModifier(node),
|
||||||
|
line: line + 1 // Convert to 1-indexed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract interfaces
|
// Extract interfaces
|
||||||
if (ts.isInterfaceDeclaration(node) && node.name) {
|
if (ts.isInterfaceDeclaration(node) && node.name) {
|
||||||
const name = node.name.text
|
const name = node.name.text
|
||||||
|
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart())
|
||||||
const members = []
|
const members = []
|
||||||
|
|
||||||
node.members.forEach((member) => {
|
node.members.forEach((member) => {
|
||||||
@@ -83,13 +86,15 @@ function extractApiSurface(sourceFile) {
|
|||||||
clause.types.map((type) => type.getText(sourceFile))
|
clause.types.map((type) => type.getText(sourceFile))
|
||||||
)
|
)
|
||||||
.flat()
|
.flat()
|
||||||
: []
|
: [],
|
||||||
|
line: line + 1 // Convert to 1-indexed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract enums
|
// Extract enums
|
||||||
if (ts.isEnumDeclaration(node) && node.name) {
|
if (ts.isEnumDeclaration(node) && node.name) {
|
||||||
const name = node.name.text
|
const name = node.name.text
|
||||||
|
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart())
|
||||||
const members = node.members.map((member) => ({
|
const members = node.members.map((member) => ({
|
||||||
name: member.name.getText(sourceFile),
|
name: member.name.getText(sourceFile),
|
||||||
value: member.initializer
|
value: member.initializer
|
||||||
@@ -101,13 +106,15 @@ function extractApiSurface(sourceFile) {
|
|||||||
kind: 'enum',
|
kind: 'enum',
|
||||||
name,
|
name,
|
||||||
members,
|
members,
|
||||||
exported: hasExportModifier(node)
|
exported: hasExportModifier(node),
|
||||||
|
line: line + 1 // Convert to 1-indexed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract functions
|
// Extract functions
|
||||||
if (ts.isFunctionDeclaration(node) && node.name) {
|
if (ts.isFunctionDeclaration(node) && node.name) {
|
||||||
const name = node.name.text
|
const name = node.name.text
|
||||||
|
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart())
|
||||||
api.functions[name] = {
|
api.functions[name] = {
|
||||||
kind: 'function',
|
kind: 'function',
|
||||||
name,
|
name,
|
||||||
@@ -117,13 +124,15 @@ function extractApiSurface(sourceFile) {
|
|||||||
optional: !!p.questionToken
|
optional: !!p.questionToken
|
||||||
})),
|
})),
|
||||||
returnType: node.type ? node.type.getText(sourceFile) : 'any',
|
returnType: node.type ? node.type.getText(sourceFile) : 'any',
|
||||||
exported: hasExportModifier(node)
|
exported: hasExportModifier(node),
|
||||||
|
line: line + 1 // Convert to 1-indexed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract classes
|
// Extract classes
|
||||||
if (ts.isClassDeclaration(node) && node.name) {
|
if (ts.isClassDeclaration(node) && node.name) {
|
||||||
const name = node.name.text
|
const name = node.name.text
|
||||||
|
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart())
|
||||||
const members = []
|
const members = []
|
||||||
const methods = []
|
const methods = []
|
||||||
|
|
||||||
@@ -162,12 +171,14 @@ function extractApiSurface(sourceFile) {
|
|||||||
clause.types.map((type) => type.getText(sourceFile))
|
clause.types.map((type) => type.getText(sourceFile))
|
||||||
)
|
)
|
||||||
.flat()
|
.flat()
|
||||||
: []
|
: [],
|
||||||
|
line: line + 1 // Convert to 1-indexed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract variable declarations (constants)
|
// Extract variable declarations (constants)
|
||||||
if (ts.isVariableStatement(node)) {
|
if (ts.isVariableStatement(node)) {
|
||||||
|
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart())
|
||||||
node.declarationList.declarations.forEach((decl) => {
|
node.declarationList.declarations.forEach((decl) => {
|
||||||
if (decl.name && ts.isIdentifier(decl.name)) {
|
if (decl.name && ts.isIdentifier(decl.name)) {
|
||||||
const name = decl.name.text
|
const name = decl.name.text
|
||||||
@@ -175,7 +186,8 @@ function extractApiSurface(sourceFile) {
|
|||||||
kind: 'constant',
|
kind: 'constant',
|
||||||
name,
|
name,
|
||||||
type: decl.type ? decl.type.getText(sourceFile) : 'unknown',
|
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