Skip to content

Commit f62614e

Browse files
Merge branch 'main' into agent/remove-static-v-html
2 parents 92005a4 + c3c78ea commit f62614e

399 files changed

Lines changed: 42505 additions & 2368 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ packages/registry-types/src/comfyRegistryTypes.ts linguist-generated=true
66
packages/ingest-types/src/types.gen.ts linguist-generated=true
77
packages/ingest-types/src/zod.gen.ts linguist-generated=true
88
src/workbench/extensions/manager/types/generatedManagerTypes.ts linguist-generated=true
9+
browser_tests/fixtures/data/customNodeManifest.cloud.json linguist-generated=true

.github/actions/changes-filter/action.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ runs:
5151
- name: Filter typed changes
5252
if: ${{ github.event_name == 'pull_request' }}
5353
id: filter
54-
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
54+
uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3
5555
with:
5656
filters: |
5757
app_website:
@@ -75,7 +75,7 @@ runs:
7575
- name: Filter relevant changes
7676
if: ${{ github.event_name == 'pull_request' }}
7777
id: relevant
78-
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
78+
uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3
7979
with:
8080
predicate-quantifier: 'every'
8181
filters: |

.github/actions/comment-release-links/action.yaml

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: Post Release Summary Comment
2-
description: Post or update a PR comment summarizing release links with diff, derived versions, and optional extras.
2+
description: Upsert a release-links section (diff, derived versions, optional extras) into the unified PR report comment.
33
author: ComfyUI Frontend Team
44

55
inputs:
@@ -14,6 +14,9 @@ outputs:
1414
prev_version:
1515
description: Previous version derived from the parent commit
1616
value: ${{ steps.build.outputs.prev_version }}
17+
new_version:
18+
description: Current version read from the version file
19+
value: ${{ steps.build.outputs.new_version }}
1720

1821
runs:
1922
using: composite
@@ -49,7 +52,7 @@ runs:
4952
exit 1
5053
fi
5154
52-
MARKER='release-summary'
55+
SECTION_NAME='release'
5356
MESSAGE='Publish jobs finished successfully:'
5457
LINKS_VALUE=''
5558
@@ -60,11 +63,11 @@ runs:
6063
'npm types|https://www.npmjs.com/package/@comfyorg/comfyui-frontend-types/v/{{version}}')
6164
;;
6265
apps/desktop-ui/package.json)
63-
MARKER='desktop-release-summary'
66+
SECTION_NAME='desktop-release'
6467
LINKS_VALUE='npm desktop UI|https://www.npmjs.com/package/@comfyorg/desktop-ui/v/{{version}}'
6568
;;
6669
packages/design-system/package.json)
67-
MARKER='design-system-release-summary'
70+
SECTION_NAME='design-system-release'
6871
LINKS_VALUE='npm design-system|https://www.npmjs.com/package/@comfyorg/design-system/v/{{version}}'
6972
;;
7073
esac
@@ -75,7 +78,6 @@ runs:
7578
COMMENT_FILE=$(mktemp)
7679
7780
{
78-
echo "<!--$MARKER:$DIFF_PREFIX$NEW_VERSION-->"
7981
echo "$MESSAGE"
8082
echo ""
8183
echo "- $DIFF_LABEL: [\`$DIFF_PREFIX$PREV_VERSION...$DIFF_PREFIX$NEW_VERSION\`]($DIFF_URL)"
@@ -103,21 +105,14 @@ runs:
103105
echo "COMMENT_BODY_END_MARKER"
104106
} >> "$GITHUB_OUTPUT"
105107
echo "prev_version=$PREV_VERSION" >> "$GITHUB_OUTPUT"
106-
echo "marker_search=<!--$MARKER:" >> "$GITHUB_OUTPUT"
108+
echo "section_name=$SECTION_NAME" >> "$GITHUB_OUTPUT"
107109
echo "new_version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
108110
109-
- name: Find existing comment
110-
id: find
111-
uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0
111+
- name: Upsert release section into unified report
112+
uses: ./.github/actions/upsert-comment-section
112113
with:
113-
issue-number: ${{ inputs.issue-number || github.event.pull_request.number }}
114-
comment-author: github-actions[bot]
115-
body-includes: ${{ steps.build.outputs.marker_search }}
116-
117-
- name: Post or update comment
118-
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
119-
with:
120-
issue-number: ${{ inputs.issue-number || github.event.pull_request.number }}
121-
comment-id: ${{ steps.find.outputs.comment-id }}
122-
body: ${{ steps.build.outputs.body }}
123-
edit-mode: replace
114+
pr-number: ${{ inputs.issue-number || github.event.pull_request.number }}
115+
section-name: ${{ steps.build.outputs.section_name }}
116+
section-content: ${{ steps.build.outputs.body }}
117+
comment-marker: '<!-- COMFYUI_FRONTEND_PR_REPORT -->'
118+
token: ${{ github.token }}

.github/actions/setup-comfyui-server/action.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ inputs:
99
description: 'Whether to launch the server after setup'
1010
required: false
1111
default: 'false'
12+
comfyui_ref:
13+
description: 'ComfyUI git ref to check out (tag/branch/SHA). Empty = default branch (master).'
14+
required: false
15+
default: ''
1216
runs:
1317
using: 'composite'
1418
steps:
@@ -19,6 +23,7 @@ runs:
1923
uses: actions/checkout@v7
2024
with:
2125
repository: 'comfyanonymous/ComfyUI'
26+
ref: ${{ inputs.comfyui_ref }}
2227
path: 'ComfyUI'
2328

2429
- name: Install ComfyUI_devtools from frontend repo

.github/actions/setup-frontend/action.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ inputs:
55
description: 'Include the build step to build the frontend. Set to true for workflows that need a built frontend'
66
required: false
77
default: 'false'
8+
node_cache:
9+
description: "Share the lockfile-keyed pnpm store cache. Set to 'false' in jobs that execute unreviewed third-party code: setup-node's post step writes the store AFTER the job body, and the same key is restored by the publish workflows, which hold NPM_TOKEN, PYPI_TOKEN and id-token: write."
10+
required: false
11+
default: 'true'
812
runs:
913
using: 'composite'
1014
steps:
@@ -18,7 +22,7 @@ runs:
1822
uses: actions/setup-node@v6
1923
with:
2024
node-version-file: '.nvmrc'
21-
cache: 'pnpm'
25+
cache: ${{ inputs.node_cache == 'true' && 'pnpm' || '' }}
2226
cache-dependency-path: './pnpm-lock.yaml'
2327

2428
- name: Install dependencies

.github/actions/setup-playwright/action.yaml

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
name: Setup Playwright
22
description: Cache and install Playwright browsers with dependencies
3+
inputs:
4+
install_deps:
5+
description: Install Playwright operating-system dependencies
6+
required: false
7+
default: 'true'
38
runs:
49
using: composite
510
steps:
@@ -17,12 +22,33 @@ runs:
1722
path: '~/.cache/ms-playwright'
1823
key: ${{ runner.os }}-playwright-browsers-${{ steps.detect-version.outputs.playwright-version }}
1924

20-
- name: Install Playwright Browsers
21-
if: steps.cache-playwright-browsers.outputs.cache-hit != 'true'
25+
- name: Bound Playwright dependency downloads
26+
if: inputs.install_deps == 'true'
2227
shell: bash
23-
run: pnpm exec playwright install chromium --with-deps
28+
run: |
29+
set -euo pipefail
30+
printf '%s\n' \
31+
'Acquire::Retries "3";' \
32+
'Acquire::http::Timeout "60";' \
33+
'Acquire::https::Timeout "60";' \
34+
| sudo tee /etc/apt/apt.conf.d/80-playwright-ci >/dev/null
2435
25-
- name: Install Playwright Browsers (operating system dependencies)
26-
if: steps.cache-playwright-browsers.outputs.cache-hit == 'true'
36+
- name: Install Playwright browser and dependencies
2737
shell: bash
28-
run: pnpm exec playwright install-deps
38+
env:
39+
BROWSER_CACHE_HIT: ${{ steps.cache-playwright-browsers.outputs.cache-hit }}
40+
INSTALL_DEPS: ${{ inputs.install_deps }}
41+
run: |
42+
set -euo pipefail
43+
if [ "$INSTALL_DEPS" != true ]; then
44+
playwright_args=(install chromium)
45+
elif [ "$BROWSER_CACHE_HIT" = true ]; then
46+
playwright_args=(install-deps chromium)
47+
else
48+
playwright_args=(install chromium --with-deps)
49+
fi
50+
for attempt in 1 2; do
51+
pnpm exec playwright "${playwright_args[@]}" && exit 0
52+
[ "$attempt" -lt 2 ] || exit 1
53+
sleep 2
54+
done

.github/actions/upsert-comment-section/action.yaml

Lines changed: 135 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -50,36 +50,144 @@ runs:
5050
5151
// Escape special regex characters in delimiter strings
5252
const escapeRegex = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
53-
54-
const comments = await github.paginate(
55-
github.rest.issues.listComments,
56-
{ ...context.repo, issue_number: prNumber }
53+
const sectionRegex = new RegExp(
54+
`${escapeRegex(sectionStart)}[\\s\\S]*?${escapeRegex(sectionEnd)}`
5755
)
5856
59-
const existing = comments.find(
60-
(c) =>
61-
c.user?.login === 'github-actions[bot]' &&
62-
c.body?.includes(commentMarker)
63-
)
57+
// Every section-start marker in a body, used to detect whether a
58+
// concurrent writer's section was lost across our write.
59+
const sectionStartsIn = (body) =>
60+
body.match(/<!-- section:[a-z0-9-]+:start -->/g) ?? []
6461
65-
if (!existing) {
66-
return github.rest.issues.createComment({
67-
...context.repo,
68-
issue_number: prNumber,
69-
body: `${commentMarker}\n${sectionBlock}`
70-
})
62+
const findComment = async () => {
63+
const comments = await github.paginate(
64+
github.rest.issues.listComments,
65+
{ ...context.repo, issue_number: prNumber }
66+
)
67+
return comments.find(
68+
(c) =>
69+
c.user?.login === 'github-actions[bot]' &&
70+
c.body?.includes(commentMarker)
71+
)
7172
}
7273
73-
const body = existing.body ?? ''
74-
const sectionRegex = new RegExp(
75-
`${escapeRegex(sectionStart)}[\\s\\S]*?${escapeRegex(sectionEnd)}`
76-
)
77-
const updated = sectionRegex.test(body)
78-
? body.replace(sectionRegex, sectionBlock)
79-
: body.trimEnd() + '\n\n' + sectionBlock
74+
// Several workflows share one comment via read-modify-write, which the
75+
// REST API can't do atomically. Re-read immediately before each write
76+
// and verify our section plus every previously-present section
77+
// survived; on a detected clobber, re-read and retry so writers
78+
// converge instead of silently dropping each other's sections.
79+
const maxAttempts = 5
80+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
81+
const existing = await findComment()
82+
83+
if (!existing) {
84+
try {
85+
await github.rest.issues.createComment({
86+
...context.repo,
87+
issue_number: prNumber,
88+
body: `${commentMarker}\n${sectionBlock}`
89+
})
90+
// Concurrent writers may have also created a comment; merge all
91+
// sections from every duplicate into the lowest-id copy, verify,
92+
// then delete the rest so no report content is lost.
93+
const allComments = await github.paginate(
94+
github.rest.issues.listComments,
95+
{ ...context.repo, issue_number: prNumber }
96+
)
97+
const markers = allComments.filter(
98+
(c) =>
99+
c.user?.login === 'github-actions[bot]' &&
100+
c.body?.includes(commentMarker)
101+
)
102+
if (markers.length > 1) {
103+
markers.sort((a, b) => a.id - b.id)
104+
const canonical = markers[0]
105+
// Merge sections from all duplicates into the canonical body
106+
let mergedBody = canonical.body ?? ''
107+
for (const dup of markers.slice(1)) {
108+
const dupSections = (dup.body ?? '').match(
109+
/<!-- section:[a-z0-9-]+:start -->[\s\S]*?<!-- section:[a-z0-9-]+:end -->/g
110+
) ?? []
111+
for (const block of dupSections) {
112+
const nameMatch = block.match(/<!-- section:([a-z0-9-]+):start -->/)
113+
if (!nameMatch) continue
114+
const name = nameMatch[1]
115+
const startTag = `<!-- section:${name}:start -->`
116+
const endTag = `<!-- section:${name}:end -->`
117+
const existingRegex = new RegExp(
118+
`${escapeRegex(startTag)}[\\s\\S]*?${escapeRegex(endTag)}`
119+
)
120+
mergedBody = existingRegex.test(mergedBody)
121+
? mergedBody.replace(existingRegex, block)
122+
: mergedBody.trimEnd() + '\n\n' + block
123+
}
124+
}
125+
try {
126+
await github.rest.issues.updateComment({
127+
...context.repo,
128+
comment_id: canonical.id,
129+
body: mergedBody
130+
})
131+
// Verify canonical has all sections before deleting duplicates
132+
const verified = (await github.rest.issues.getComment({
133+
...context.repo,
134+
comment_id: canonical.id
135+
})).data.body ?? ''
136+
const allSections = markers.flatMap(
137+
(m) => sectionStartsIn(m.body ?? '')
138+
)
139+
const allPresent = allSections.every((s) => verified.includes(s))
140+
if (allPresent) {
141+
for (const dup of markers.slice(1)) {
142+
try {
143+
await github.rest.issues.deleteComment({
144+
...context.repo,
145+
comment_id: dup.id
146+
})
147+
} catch (_) {}
148+
}
149+
}
150+
} catch (_) {
151+
// Leave duplicates rather than risk losing content
152+
}
153+
}
154+
return
155+
} catch (err) {
156+
if (attempt === maxAttempts) throw err
157+
continue // another writer likely created it first; retry updates
158+
}
159+
}
160+
161+
const body = existing.body ?? ''
162+
const expectedSections = sectionStartsIn(body)
163+
const updated = sectionRegex.test(body)
164+
? body.replace(sectionRegex, sectionBlock)
165+
: body.trimEnd() + '\n\n' + sectionBlock
80166
81-
return github.rest.issues.updateComment({
82-
...context.repo,
83-
comment_id: existing.id,
84-
body: updated
85-
})
167+
try {
168+
await github.rest.issues.updateComment({
169+
...context.repo,
170+
comment_id: existing.id,
171+
body: updated
172+
})
173+
} catch (err) {
174+
if (attempt === maxAttempts) throw err
175+
continue // transient failure; retry
176+
}
177+
178+
const current = (await findComment())?.body ?? ''
179+
const survived =
180+
current.includes(sectionBlock) &&
181+
expectedSections.every((s) => current.includes(s))
182+
if (survived) return
183+
184+
if (attempt === maxAttempts) {
185+
core.warning(
186+
`upsert-comment-section: section "${sectionName}" may have been clobbered by a concurrent writer after ${maxAttempts} attempts`
187+
)
188+
return
189+
}
190+
await new Promise((resolve) =>
191+
setTimeout(resolve, 250 * attempt + Math.floor(Math.random() * 250))
192+
)
193+
}

0 commit comments

Comments
 (0)