From dcac2c5ec161bb76c93e4c35d616deee7304d16b Mon Sep 17 00:00:00 2001 From: bymyself Date: Sun, 23 Nov 2025 13:43:18 -0800 Subject: [PATCH 01/11] [feat] Add weekly ComfyUI release automation Adds scheduled workflow to bump ComfyUI frontend RC releases every Monday at noon PST. - Resolver script checks ComfyUI requirements.txt and determines next minor version - Triggers release workflow if commits exist since last patch tag - Creates draft PR to comfyanonymous/ComfyUI with updated requirements.txt - Reuses existing release-version-bump workflow and comment actions - Includes error handling and validation for all steps --- .github/workflows/weekly-comfyui-release.yaml | 270 ++++++++++++++++++ knip.config.ts | 2 +- scripts/cicd/resolve-comfyui-release.ts | 209 ++++++++++++++ 3 files changed, 480 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/weekly-comfyui-release.yaml create mode 100755 scripts/cicd/resolve-comfyui-release.ts diff --git a/.github/workflows/weekly-comfyui-release.yaml b/.github/workflows/weekly-comfyui-release.yaml new file mode 100644 index 0000000000..399e2f1344 --- /dev/null +++ b/.github/workflows/weekly-comfyui-release.yaml @@ -0,0 +1,270 @@ +name: "Weekly ComfyUI Release" +description: "Automated weekly workflow to bump ComfyUI frontend RC releases" + +on: + # Schedule for Monday at 12:00 PM PST (20:00 UTC) + schedule: + - cron: '0 20 * * 1' + + # Allow manual triggering + workflow_dispatch: + inputs: + comfyui_fork: + description: 'ComfyUI fork to use for PR (e.g., Comfy-Org/ComfyUI)' + required: false + default: 'Comfy-Org/ComfyUI' + type: string + +jobs: + resolve-version: + runs-on: ubuntu-latest + outputs: + current_version: ${{ steps.resolve.outputs.current_version }} + target_version: ${{ steps.resolve.outputs.target_version }} + target_minor: ${{ steps.resolve.outputs.target_minor }} + target_branch: ${{ steps.resolve.outputs.target_branch }} + needs_release: ${{ steps.resolve.outputs.needs_release }} + diff_url: ${{ steps.resolve.outputs.diff_url }} + latest_patch_tag: ${{ steps.resolve.outputs.latest_patch_tag }} + + steps: + - name: Checkout ComfyUI_frontend + uses: actions/checkout@v5 + with: + fetch-depth: 0 + path: frontend + + - name: Checkout ComfyUI (sparse) + uses: actions/checkout@v5 + with: + repository: comfyanonymous/ComfyUI + sparse-checkout: | + requirements.txt + path: comfyui + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: lts/* + + - name: Resolve release information + id: resolve + working-directory: frontend + run: | + set -euo pipefail + + # Run the resolver script + if ! RESULT=$(tsx scripts/cicd/resolve-comfyui-release.ts ../comfyui .); then + echo "Failed to resolve release information" + exit 1 + fi + + echo "Resolver output:" + echo "$RESULT" + + # Validate JSON output + if ! echo "$RESULT" | jq empty 2>/dev/null; then + echo "Invalid JSON output from resolver" + exit 1 + fi + + # Parse JSON output and set outputs + echo "current_version=$(echo "$RESULT" | jq -r '.current_version')" >> $GITHUB_OUTPUT + echo "target_version=$(echo "$RESULT" | jq -r '.target_version')" >> $GITHUB_OUTPUT + echo "target_minor=$(echo "$RESULT" | jq -r '.target_minor')" >> $GITHUB_OUTPUT + echo "target_branch=$(echo "$RESULT" | jq -r '.target_branch')" >> $GITHUB_OUTPUT + echo "needs_release=$(echo "$RESULT" | jq -r '.needs_release')" >> $GITHUB_OUTPUT + echo "diff_url=$(echo "$RESULT" | jq -r '.diff_url')" >> $GITHUB_OUTPUT + echo "latest_patch_tag=$(echo "$RESULT" | jq -r '.latest_patch_tag')" >> $GITHUB_OUTPUT + + - name: Summary + run: | + echo "## Release Information" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- Current version: ${{ steps.resolve.outputs.current_version }}" >> $GITHUB_STEP_SUMMARY + echo "- Target version: ${{ steps.resolve.outputs.target_version }}" >> $GITHUB_STEP_SUMMARY + echo "- Target branch: ${{ steps.resolve.outputs.target_branch }}" >> $GITHUB_STEP_SUMMARY + echo "- Needs release: ${{ steps.resolve.outputs.needs_release }}" >> $GITHUB_STEP_SUMMARY + echo "- Diff: [${{ steps.resolve.outputs.current_version }}...${{ steps.resolve.outputs.target_version }}](${{ steps.resolve.outputs.diff_url }})" >> $GITHUB_STEP_SUMMARY + + trigger-release-if-needed: + needs: resolve-version + if: needs.resolve-version.outputs.needs_release == 'true' + runs-on: ubuntu-latest + outputs: + pr_url: ${{ steps.trigger.outputs.pr_url }} + + steps: + - name: Trigger release workflow + id: trigger + env: + GH_TOKEN: ${{ secrets.PR_GH_TOKEN }} + run: | + set -euo pipefail + + echo "Triggering release workflow for branch ${{ needs.resolve-version.outputs.target_branch }}" + + # Trigger the release-version-bump workflow + if ! gh workflow run release-version-bump.yaml \ + --repo Comfy-Org/ComfyUI_frontend \ + --ref main \ + --field version_type=patch \ + --field branch=${{ needs.resolve-version.outputs.target_branch }}; then + echo "Failed to trigger release workflow" + exit 1 + fi + + # Wait a few seconds for the workflow run to be created + sleep 5 + + # Get the most recent workflow run + RUN_ID=$(gh run list \ + --repo Comfy-Org/ComfyUI_frontend \ + --workflow=release-version-bump.yaml \ + --limit 1 \ + --json databaseId \ + --jq '.[0].databaseId') + + if [ -z "$RUN_ID" ]; then + echo "Failed to get workflow run ID" + exit 1 + fi + + echo "Triggered release workflow run: $RUN_ID" + echo "pr_url=https://github.com/Comfy-Org/ComfyUI_frontend/actions/runs/$RUN_ID" >> $GITHUB_OUTPUT + + - name: Summary + run: | + echo "## Release PR Triggered" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Release workflow triggered: ${{ steps.trigger.outputs.pr_url }}" >> $GITHUB_STEP_SUMMARY + + create-comfyui-pr: + needs: [resolve-version, trigger-release-if-needed] + if: always() && needs.resolve-version.result == 'success' + runs-on: ubuntu-latest + + steps: + - name: Checkout ComfyUI fork + uses: actions/checkout@v5 + with: + repository: ${{ inputs.comfyui_fork || 'Comfy-Org/ComfyUI' }} + token: ${{ secrets.PR_GH_TOKEN }} + path: comfyui + + - name: Update requirements.txt + working-directory: comfyui + run: | + set -euo pipefail + + echo "Updating comfyui-frontend-package to ${{ needs.resolve-version.outputs.target_version }}" + + # Update the comfyui-frontend-package version + sed -i 's/comfyui-frontend-package==[0-9.]\+/comfyui-frontend-package==${{ needs.resolve-version.outputs.target_version }}/' requirements.txt + + # Verify the change was made + if ! grep -q "comfyui-frontend-package==${{ needs.resolve-version.outputs.target_version }}" requirements.txt; then + echo "Failed to update requirements.txt" + exit 1 + fi + + echo "Updated requirements.txt:" + grep comfyui-frontend-package requirements.txt + + - name: Build PR description + id: pr-body + run: | + BODY=$(cat <<'EOF' + Bumps frontend to ${{ needs.resolve-version.outputs.target_version }} + + Test quickly: + + ```bash + python main.py --front-end-version Comfy-Org/ComfyUI_frontend@${{ needs.resolve-version.outputs.target_version }} + ``` + + - Diff: [v${{ needs.resolve-version.outputs.current_version }}...v${{ needs.resolve-version.outputs.target_version }}](${{ needs.resolve-version.outputs.diff_url }}) + - PyPI: https://pypi.org/project/comfyui-frontend-package/${{ needs.resolve-version.outputs.target_version }}/ + - npm: https://www.npmjs.com/package/@comfyorg/comfyui-frontend-types/v/${{ needs.resolve-version.outputs.target_version }} + EOF + ) + + # Add release PR note if release was triggered + if [ "${{ needs.resolve-version.outputs.needs_release }}" = "true" ]; then + RELEASE_NOTE="⚠️ **Release PR must be merged first:** ${{ needs.trigger-release-if-needed.outputs.pr_url }}" + BODY="${RELEASE_NOTE}\n\n${BODY}" + fi + + # Save to file for later use + echo "$BODY" > pr-body.txt + cat pr-body.txt + + - name: Create PR to ComfyUI + working-directory: comfyui + env: + GH_TOKEN: ${{ secrets.PR_GH_TOKEN }} + COMFYUI_FORK: ${{ inputs.comfyui_fork || 'Comfy-Org/ComfyUI' }} + run: | + set -euo pipefail + + # Extract fork owner from repository name + FORK_OWNER=$(echo "$COMFYUI_FORK" | cut -d'/' -f1) + + echo "Creating PR from ${COMFYUI_FORK} to comfyanonymous/ComfyUI" + + # Configure git + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + # Create/update branch (reuse same branch name each week) + BRANCH="automation/comfyui-frontend-bump" + git checkout -B "$BRANCH" + git add requirements.txt + + if ! git diff --cached --quiet; then + git commit -m "Bump comfyui-frontend-package to ${{ needs.resolve-version.outputs.target_version }}" + else + echo "No changes to commit" + exit 0 + fi + + # Force push to fork (overwrites previous week's branch) + if ! git push -f origin "$BRANCH"; then + echo "Failed to push branch to fork" + exit 1 + fi + + # Create draft PR from fork to upstream + PR_BODY=$(cat ../pr-body.txt) + + # Try to create PR, ignore error if it already exists + if ! gh pr create \ + --repo comfyanonymous/ComfyUI \ + --head "${FORK_OWNER}:${BRANCH}" \ + --base master \ + --title "Bump comfyui-frontend-package to ${{ needs.resolve-version.outputs.target_version }}" \ + --body "$PR_BODY" \ + --draft 2>&1; then + + # Check if PR already exists + if gh pr list --repo comfyanonymous/ComfyUI --head "${FORK_OWNER}:${BRANCH}" --json number --jq '.[0].number' > /dev/null 2>&1; then + echo "PR already exists, updating branch will update the PR" + else + echo "Failed to create PR and no existing PR found" + exit 1 + fi + fi + + - name: Summary + run: | + echo "## ComfyUI PR Created" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Draft PR created in comfyanonymous/ComfyUI" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### PR Body:" >> $GITHUB_STEP_SUMMARY + cat pr-body.txt >> $GITHUB_STEP_SUMMARY diff --git a/knip.config.ts b/knip.config.ts index a77574f97b..f2907a266f 100644 --- a/knip.config.ts +++ b/knip.config.ts @@ -27,7 +27,7 @@ const config: KnipConfig = { project: ['src/**/*.{js,ts}'] } }, - ignoreBinaries: ['python3'], + ignoreBinaries: ['python3', 'gh'], ignoreDependencies: [ // Weird importmap things '@iconify/json', diff --git a/scripts/cicd/resolve-comfyui-release.ts b/scripts/cicd/resolve-comfyui-release.ts new file mode 100755 index 0000000000..a5fc865f13 --- /dev/null +++ b/scripts/cicd/resolve-comfyui-release.ts @@ -0,0 +1,209 @@ +#!/usr/bin/env tsx +import { execSync } from 'child_process' +import fs from 'fs' +import path from 'path' + +interface ReleaseInfo { + current_version: string + target_minor: number + target_version: string + target_branch: string + needs_release: boolean + latest_patch_tag: string | null + branch_head_sha: string | null + tag_commit_sha: string | null + diff_url: string + release_pr_url: string | null +} + +/** + * Execute a command and return stdout + */ +function exec(command: string, cwd?: string): string { + try { + return execSync(command, { + cwd, + encoding: 'utf-8', + stdio: ['pipe', 'pipe', 'pipe'] + }).trim() + } catch (error) { + return '' + } +} + +/** + * Parse version from requirements.txt + * Handles formats: comfyui-frontend-package==1.2.3, comfyui-frontend-package>=1.2.3, etc. + */ +function parseRequirementsVersion(requirementsPath: string): string | null { + if (!fs.existsSync(requirementsPath)) { + console.error(`Requirements file not found: ${requirementsPath}`) + return null + } + + const content = fs.readFileSync(requirementsPath, 'utf-8') + const match = content.match( + /comfyui-frontend-package\s*(?:==|>=|<=|~=|>|<)\s*([0-9]+\.[0-9]+\.[0-9]+)/ + ) + + if (!match) { + console.error( + 'Could not find comfyui-frontend-package version in requirements.txt' + ) + return null + } + + return match[1] +} + +/** + * Get the latest patch tag for a given minor version + */ +function getLatestPatchTag(repoPath: string, minor: number): string | null { + // Fetch all tags + exec('git fetch --tags', repoPath) + + // List all tags matching v1.{minor}.* + const tags = exec(`git tag -l 'v1.${minor}.*'`, repoPath) + .split('\n') + .filter((tag) => tag.trim() !== '') + + if (tags.length === 0) { + return null + } + + // Sort tags by version (semantic sort) + const sortedTags = tags.sort((a, b) => { + const aParts = a.replace('v', '').split('.').map(Number) + const bParts = b.replace('v', '').split('.').map(Number) + + for (let i = 0; i < 3; i++) { + if (aParts[i] !== bParts[i]) { + return aParts[i] - bParts[i] + } + } + return 0 + }) + + return sortedTags[sortedTags.length - 1] +} + +/** + * Resolve the ComfyUI release information + */ +function resolveRelease( + comfyuiRepoPath: string, + frontendRepoPath: string +): ReleaseInfo | null { + // Parse current version from ComfyUI requirements.txt + const requirementsPath = path.join(comfyuiRepoPath, 'requirements.txt') + const currentVersion = parseRequirementsVersion(requirementsPath) + + if (!currentVersion) { + return null + } + + const [major, currentMinor, patch] = currentVersion.split('.').map(Number) + + // Calculate target minor version (next minor) + const targetMinor = currentMinor + 1 + const targetBranch = `core/1.${targetMinor}` + + // Check if target branch exists in frontend repo + exec('git fetch origin', frontendRepoPath) + const branchExists = exec( + `git rev-parse --verify origin/${targetBranch}`, + frontendRepoPath + ) + + if (!branchExists) { + console.error( + `Target branch ${targetBranch} does not exist in frontend repo` + ) + return null + } + + // Get latest patch tag for target minor + const latestPatchTag = getLatestPatchTag(frontendRepoPath, targetMinor) + + let needsRelease = false + let branchHeadSha: string | null = null + let tagCommitSha: string | null = null + let targetVersion = currentVersion + + if (latestPatchTag) { + // Get commit SHA for the tag + tagCommitSha = exec(`git rev-list -n 1 ${latestPatchTag}`, frontendRepoPath) + + // Get commit SHA for branch head + branchHeadSha = exec( + `git rev-parse origin/${targetBranch}`, + frontendRepoPath + ) + + // Check if there are commits between tag and branch head + const commitsBetween = exec( + `git rev-list ${latestPatchTag}..origin/${targetBranch} --count`, + frontendRepoPath + ) + + needsRelease = parseInt(commitsBetween) > 0 + + // Parse existing patch number and increment if needed + const tagVersion = latestPatchTag.replace('v', '') + const [, , existingPatch] = tagVersion.split('.').map(Number) + + if (needsRelease) { + targetVersion = `1.${targetMinor}.${existingPatch + 1}` + } else { + targetVersion = tagVersion + } + } else { + // No tags exist for this minor version, need to create v1.{targetMinor}.0 + needsRelease = true + targetVersion = `1.${targetMinor}.0` + branchHeadSha = exec( + `git rev-parse origin/${targetBranch}`, + frontendRepoPath + ) + } + + const diffUrl = `https://github.com/Comfy-Org/ComfyUI_frontend/compare/v${currentVersion}...v${targetVersion}` + + return { + current_version: currentVersion, + target_minor: targetMinor, + target_version: targetVersion, + target_branch: targetBranch, + needs_release: needsRelease, + latest_patch_tag: latestPatchTag, + branch_head_sha: branchHeadSha, + tag_commit_sha: tagCommitSha, + diff_url: diffUrl, + release_pr_url: null // Will be populated by workflow if release is triggered + } +} + +// Main execution +const comfyuiRepoPath = process.argv[2] +const frontendRepoPath = process.argv[3] || process.cwd() + +if (!comfyuiRepoPath) { + console.error( + 'Usage: resolve-comfyui-release.ts [frontend-repo-path]' + ) + process.exit(1) +} + +const releaseInfo = resolveRelease(comfyuiRepoPath, frontendRepoPath) + +if (!releaseInfo) { + console.error('Failed to resolve release information') + process.exit(1) +} + +// Output as JSON for GitHub Actions +// eslint-disable-next-line no-console +console.log(JSON.stringify(releaseInfo, null, 2)) + +export { resolveRelease } From 056f19026afdf9bd6ebf2165e31ffa521421f174 Mon Sep 17 00:00:00 2001 From: bymyself Date: Sun, 23 Nov 2025 19:50:03 -0800 Subject: [PATCH 02/11] Add semantic version validation to resolver script - Validate currentVersion and tagVersion format before destructuring - Check for 3-part versions with numeric parts - Guard parseInt with radix and NaN check - Validate existingPatch is finite number before increment - Return null early on invalid formats with descriptive errors --- scripts/cicd/resolve-comfyui-release.ts | 45 ++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/scripts/cicd/resolve-comfyui-release.ts b/scripts/cicd/resolve-comfyui-release.ts index a5fc865f13..40483075c3 100755 --- a/scripts/cicd/resolve-comfyui-release.ts +++ b/scripts/cicd/resolve-comfyui-release.ts @@ -56,6 +56,25 @@ function parseRequirementsVersion(requirementsPath: string): string | null { return match[1] } +/** + * Validate semantic version string + */ +function isValidSemver(version: string): boolean { + if (!version || typeof version !== 'string') { + return false + } + + const parts = version.split('.') + if (parts.length !== 3) { + return false + } + + return parts.every((part) => { + const num = Number(part) + return Number.isFinite(num) && num >= 0 && String(num) === part + }) +} + /** * Get the latest patch tag for a given minor version */ @@ -103,6 +122,14 @@ function resolveRelease( return null } + // Validate version format + if (!isValidSemver(currentVersion)) { + console.error( + `Invalid semantic version format: ${currentVersion}. Expected format: X.Y.Z` + ) + return null + } + const [major, currentMinor, patch] = currentVersion.split('.').map(Number) // Calculate target minor version (next minor) @@ -147,12 +174,28 @@ function resolveRelease( frontendRepoPath ) - needsRelease = parseInt(commitsBetween) > 0 + const commitCount = parseInt(commitsBetween, 10) + needsRelease = !isNaN(commitCount) && commitCount > 0 // Parse existing patch number and increment if needed const tagVersion = latestPatchTag.replace('v', '') + + // Validate tag version format + if (!isValidSemver(tagVersion)) { + console.error( + `Invalid tag version format: ${tagVersion}. Expected format: X.Y.Z` + ) + return null + } + const [, , existingPatch] = tagVersion.split('.').map(Number) + // Validate existingPatch is a valid number + if (!Number.isFinite(existingPatch) || existingPatch < 0) { + console.error(`Invalid patch number in tag: ${existingPatch}`) + return null + } + if (needsRelease) { targetVersion = `1.${targetMinor}.${existingPatch + 1}` } else { From 7ceeecc794aa9503c8c57a7246511a9661d56b5b Mon Sep 17 00:00:00 2001 From: bymyself Date: Tue, 25 Nov 2025 01:24:13 -0800 Subject: [PATCH 03/11] Use POSIX-compatible sed in workflow - Replace -i with -i.bak for BSD/macOS compatibility - Use [0-9.][0-9.]* instead of GNU-specific [0-9.]\+ - Store version in variable for cleaner shell expansion - Remove .bak file after successful replace --- .github/workflows/weekly-comfyui-release.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/weekly-comfyui-release.yaml b/.github/workflows/weekly-comfyui-release.yaml index 399e2f1344..caa4bf410e 100644 --- a/.github/workflows/weekly-comfyui-release.yaml +++ b/.github/workflows/weekly-comfyui-release.yaml @@ -162,13 +162,15 @@ jobs: run: | set -euo pipefail - echo "Updating comfyui-frontend-package to ${{ needs.resolve-version.outputs.target_version }}" + TARGET_VERSION="${{ needs.resolve-version.outputs.target_version }}" + echo "Updating comfyui-frontend-package to ${TARGET_VERSION}" - # Update the comfyui-frontend-package version - sed -i 's/comfyui-frontend-package==[0-9.]\+/comfyui-frontend-package==${{ needs.resolve-version.outputs.target_version }}/' requirements.txt + # Update the comfyui-frontend-package version (POSIX-compatible) + sed -i.bak "s/comfyui-frontend-package==[0-9.][0-9.]*/comfyui-frontend-package==${TARGET_VERSION}/" requirements.txt + rm requirements.txt.bak # Verify the change was made - if ! grep -q "comfyui-frontend-package==${{ needs.resolve-version.outputs.target_version }}" requirements.txt; then + if ! grep -q "comfyui-frontend-package==${TARGET_VERSION}" requirements.txt; then echo "Failed to update requirements.txt" exit 1 fi From 4a15584d9c7913aed911578bfb461bf004563985 Mon Sep 17 00:00:00 2001 From: bymyself Date: Tue, 25 Nov 2025 14:06:33 -0800 Subject: [PATCH 04/11] Filter malformed tags before sorting in getLatestPatchTag - Add regex filter for valid semver tags (vX.Y.Z format) - Prevent NaN from malformed tags like v1.28.x or v1.28 - Return null if no valid tags found after filtering - Log descriptive error showing malformed tags --- scripts/cicd/resolve-comfyui-release.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/scripts/cicd/resolve-comfyui-release.ts b/scripts/cicd/resolve-comfyui-release.ts index 40483075c3..94e6667c69 100755 --- a/scripts/cicd/resolve-comfyui-release.ts +++ b/scripts/cicd/resolve-comfyui-release.ts @@ -91,8 +91,19 @@ function getLatestPatchTag(repoPath: string, minor: number): string | null { return null } + // Filter to only valid semver tags (vX.Y.Z format) + const validTagRegex = /^v\d+\.\d+\.\d+$/ + const validTags = tags.filter((tag) => validTagRegex.test(tag)) + + if (validTags.length === 0) { + console.error( + `No valid semver tags found for minor version ${minor}. Found: ${tags.join(', ')}` + ) + return null + } + // Sort tags by version (semantic sort) - const sortedTags = tags.sort((a, b) => { + const sortedTags = validTags.sort((a, b) => { const aParts = a.replace('v', '').split('.').map(Number) const bParts = b.replace('v', '').split('.').map(Number) From f5be2f6c76bb5ea7ecb23b8b237db332ad953fb2 Mon Sep 17 00:00:00 2001 From: bymyself Date: Tue, 25 Nov 2025 14:25:36 -0800 Subject: [PATCH 05/11] Add error logging to exec function in resolver - Log command, cwd, and error message when exec fails - Preserve existing empty-string fallback behavior - Improve debugging for command execution failures --- scripts/cicd/resolve-comfyui-release.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/cicd/resolve-comfyui-release.ts b/scripts/cicd/resolve-comfyui-release.ts index 94e6667c69..4d455d03bd 100755 --- a/scripts/cicd/resolve-comfyui-release.ts +++ b/scripts/cicd/resolve-comfyui-release.ts @@ -27,6 +27,11 @@ function exec(command: string, cwd?: string): string { stdio: ['pipe', 'pipe', 'pipe'] }).trim() } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error) + const cwdInfo = cwd ? ` in directory: ${cwd}` : '' + console.error( + `Command failed: ${command}${cwdInfo}\nError: ${errorMessage}` + ) return '' } } From 00aa90fb89e686baa9342dce7b361641b485115a Mon Sep 17 00:00:00 2001 From: bymyself Date: Tue, 25 Nov 2025 15:00:56 -0800 Subject: [PATCH 06/11] Simplify release workflow trigger - remove polling logic - Remove sleep + polling for workflow run ID - Use generic links to workflow runs page instead of specific run - Eliminates race condition and timeout complexity - Cleaner job summary with branch and version info --- .github/workflows/weekly-comfyui-release.yaml | 30 ++++--------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/.github/workflows/weekly-comfyui-release.yaml b/.github/workflows/weekly-comfyui-release.yaml index caa4bf410e..d1fb957ba8 100644 --- a/.github/workflows/weekly-comfyui-release.yaml +++ b/.github/workflows/weekly-comfyui-release.yaml @@ -96,12 +96,9 @@ jobs: needs: resolve-version if: needs.resolve-version.outputs.needs_release == 'true' runs-on: ubuntu-latest - outputs: - pr_url: ${{ steps.trigger.outputs.pr_url }} steps: - name: Trigger release workflow - id: trigger env: GH_TOKEN: ${{ secrets.PR_GH_TOKEN }} run: | @@ -119,30 +116,15 @@ jobs: exit 1 fi - # Wait a few seconds for the workflow run to be created - sleep 5 - - # Get the most recent workflow run - RUN_ID=$(gh run list \ - --repo Comfy-Org/ComfyUI_frontend \ - --workflow=release-version-bump.yaml \ - --limit 1 \ - --json databaseId \ - --jq '.[0].databaseId') - - if [ -z "$RUN_ID" ]; then - echo "Failed to get workflow run ID" - exit 1 - fi - - echo "Triggered release workflow run: $RUN_ID" - echo "pr_url=https://github.com/Comfy-Org/ComfyUI_frontend/actions/runs/$RUN_ID" >> $GITHUB_OUTPUT + echo "Release workflow triggered successfully for ${{ needs.resolve-version.outputs.target_branch }}" - name: Summary run: | - echo "## Release PR Triggered" >> $GITHUB_STEP_SUMMARY + echo "## Release Workflow Triggered" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "Release workflow triggered: ${{ steps.trigger.outputs.pr_url }}" >> $GITHUB_STEP_SUMMARY + echo "- Branch: ${{ needs.resolve-version.outputs.target_branch }}" >> $GITHUB_STEP_SUMMARY + echo "- Target version: ${{ needs.resolve-version.outputs.target_version }}" >> $GITHUB_STEP_SUMMARY + echo "- [View workflow runs](https://github.com/Comfy-Org/ComfyUI_frontend/actions/workflows/release-version-bump.yaml)" >> $GITHUB_STEP_SUMMARY create-comfyui-pr: needs: [resolve-version, trigger-release-if-needed] @@ -198,7 +180,7 @@ jobs: # Add release PR note if release was triggered if [ "${{ needs.resolve-version.outputs.needs_release }}" = "true" ]; then - RELEASE_NOTE="⚠️ **Release PR must be merged first:** ${{ needs.trigger-release-if-needed.outputs.pr_url }}" + RELEASE_NOTE="⚠️ **Release PR must be merged first** - check [release workflow runs](https://github.com/Comfy-Org/ComfyUI_frontend/actions/workflows/release-version-bump.yaml)" BODY="${RELEASE_NOTE}\n\n${BODY}" fi From 0b0cb45762b16fd180f3d50b75f860170ceb814f Mon Sep 17 00:00:00 2001 From: bymyself Date: Tue, 25 Nov 2025 16:02:06 -0800 Subject: [PATCH 07/11] Add pnpm install step before running tsx - Install dependencies in frontend directory - Ensures tsx devDependency is available for resolver script - Use --frozen-lockfile for reproducible builds --- .github/workflows/weekly-comfyui-release.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/weekly-comfyui-release.yaml b/.github/workflows/weekly-comfyui-release.yaml index d1fb957ba8..013688bd60 100644 --- a/.github/workflows/weekly-comfyui-release.yaml +++ b/.github/workflows/weekly-comfyui-release.yaml @@ -52,6 +52,10 @@ jobs: with: node-version: lts/* + - name: Install dependencies + working-directory: frontend + run: pnpm install --frozen-lockfile + - name: Resolve release information id: resolve working-directory: frontend From 335ea3e854d4435c83861d041dbd76c501e338ef Mon Sep 17 00:00:00 2001 From: bymyself Date: Tue, 25 Nov 2025 16:47:53 -0800 Subject: [PATCH 08/11] Remove invalid description field from workflow - Move description to YAML comment - GitHub Actions does not support top-level description field --- .github/workflows/weekly-comfyui-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/weekly-comfyui-release.yaml b/.github/workflows/weekly-comfyui-release.yaml index 013688bd60..2e15fe91e8 100644 --- a/.github/workflows/weekly-comfyui-release.yaml +++ b/.github/workflows/weekly-comfyui-release.yaml @@ -1,5 +1,5 @@ +# Automated weekly workflow to bump ComfyUI frontend RC releases name: "Weekly ComfyUI Release" -description: "Automated weekly workflow to bump ComfyUI frontend RC releases" on: # Schedule for Monday at 12:00 PM PST (20:00 UTC) From 48e03e835be587feb45677fb8e6ea3e495082fd2 Mon Sep 17 00:00:00 2001 From: bymyself Date: Wed, 26 Nov 2025 13:08:17 -0800 Subject: [PATCH 09/11] Improve workflow and resolver robustness - Add comment documenting force-push destroys history - Improve PR existence check to capture PR number - Use git native version sorting instead of manual sort - Keep semver validation on result for safety --- .github/workflows/weekly-comfyui-release.yaml | 7 ++-- scripts/cicd/resolve-comfyui-release.ts | 34 ++++++------------- 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/.github/workflows/weekly-comfyui-release.yaml b/.github/workflows/weekly-comfyui-release.yaml index 2e15fe91e8..1bcd051cc2 100644 --- a/.github/workflows/weekly-comfyui-release.yaml +++ b/.github/workflows/weekly-comfyui-release.yaml @@ -222,6 +222,8 @@ jobs: fi # Force push to fork (overwrites previous week's branch) + # Note: This intentionally destroys branch history to maintain a single PR + # Any review comments or manual commits will need to be re-applied if ! git push -f origin "$BRANCH"; then echo "Failed to push branch to fork" exit 1 @@ -240,8 +242,9 @@ jobs: --draft 2>&1; then # Check if PR already exists - if gh pr list --repo comfyanonymous/ComfyUI --head "${FORK_OWNER}:${BRANCH}" --json number --jq '.[0].number' > /dev/null 2>&1; then - echo "PR already exists, updating branch will update the PR" + EXISTING_PR=$(gh pr list --repo comfyanonymous/ComfyUI --head "${FORK_OWNER}:${BRANCH}" --json number --jq '.[0].number' 2>/dev/null || echo "") + if [ -n "$EXISTING_PR" ]; then + echo "PR already exists (#${EXISTING_PR}), updating branch will update the PR" else echo "Failed to create PR and no existing PR found" exit 1 diff --git a/scripts/cicd/resolve-comfyui-release.ts b/scripts/cicd/resolve-comfyui-release.ts index 4d455d03bd..b1d4c11562 100755 --- a/scripts/cicd/resolve-comfyui-release.ts +++ b/scripts/cicd/resolve-comfyui-release.ts @@ -87,40 +87,26 @@ function getLatestPatchTag(repoPath: string, minor: number): string | null { // Fetch all tags exec('git fetch --tags', repoPath) - // List all tags matching v1.{minor}.* - const tags = exec(`git tag -l 'v1.${minor}.*'`, repoPath) - .split('\n') - .filter((tag) => tag.trim() !== '') + // Use git's native version sorting to get the latest tag + const latestTag = exec( + `git tag -l 'v1.${minor}.*' --sort=-version:refname | head -n 1`, + repoPath + ) - if (tags.length === 0) { + if (!latestTag) { return null } - // Filter to only valid semver tags (vX.Y.Z format) + // Validate the tag is a valid semver (vX.Y.Z format) const validTagRegex = /^v\d+\.\d+\.\d+$/ - const validTags = tags.filter((tag) => validTagRegex.test(tag)) - - if (validTags.length === 0) { + if (!validTagRegex.test(latestTag)) { console.error( - `No valid semver tags found for minor version ${minor}. Found: ${tags.join(', ')}` + `Latest tag for minor version ${minor} is not valid semver: ${latestTag}` ) return null } - // Sort tags by version (semantic sort) - const sortedTags = validTags.sort((a, b) => { - const aParts = a.replace('v', '').split('.').map(Number) - const bParts = b.replace('v', '').split('.').map(Number) - - for (let i = 0; i < 3; i++) { - if (aParts[i] !== bParts[i]) { - return aParts[i] - bParts[i] - } - } - return 0 - }) - - return sortedTags[sortedTags.length - 1] + return latestTag } /** From bdd6608a145006ca60ec81bda61c018f57c18a2a Mon Sep 17 00:00:00 2001 From: bymyself Date: Wed, 26 Nov 2025 15:25:13 -0800 Subject: [PATCH 10/11] Fix PR existence check to properly handle gh command failures - Capture exit code separately from output - Fail workflow if gh pr list command fails - Distinguish between command failure vs no PR found - Check for null output from jq --- .github/workflows/weekly-comfyui-release.yaml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/weekly-comfyui-release.yaml b/.github/workflows/weekly-comfyui-release.yaml index 1bcd051cc2..76e37f27e2 100644 --- a/.github/workflows/weekly-comfyui-release.yaml +++ b/.github/workflows/weekly-comfyui-release.yaml @@ -242,8 +242,17 @@ jobs: --draft 2>&1; then # Check if PR already exists - EXISTING_PR=$(gh pr list --repo comfyanonymous/ComfyUI --head "${FORK_OWNER}:${BRANCH}" --json number --jq '.[0].number' 2>/dev/null || echo "") - if [ -n "$EXISTING_PR" ]; then + set +e + EXISTING_PR=$(gh pr list --repo comfyanonymous/ComfyUI --head "${FORK_OWNER}:${BRANCH}" --json number --jq '.[0].number' 2>&1) + PR_LIST_EXIT=$? + set -e + + if [ $PR_LIST_EXIT -ne 0 ]; then + echo "Failed to check for existing PR: $EXISTING_PR" + exit 1 + fi + + if [ -n "$EXISTING_PR" ] && [ "$EXISTING_PR" != "null" ]; then echo "PR already exists (#${EXISTING_PR}), updating branch will update the PR" else echo "Failed to create PR and no existing PR found" From 3894d659e4ef978acfc4c02123497224e5848316 Mon Sep 17 00:00:00 2001 From: bymyself Date: Wed, 26 Nov 2025 15:44:47 -0800 Subject: [PATCH 11/11] Fix PR body concatenation to use real newlines - Use ANSI-C quoting $'\n\n' for actual newlines - Replace echo with printf for robust file writing - Fixes literal \n\n appearing in PR description --- .github/workflows/weekly-comfyui-release.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/weekly-comfyui-release.yaml b/.github/workflows/weekly-comfyui-release.yaml index 76e37f27e2..41e6a4271e 100644 --- a/.github/workflows/weekly-comfyui-release.yaml +++ b/.github/workflows/weekly-comfyui-release.yaml @@ -185,11 +185,11 @@ jobs: # Add release PR note if release was triggered if [ "${{ needs.resolve-version.outputs.needs_release }}" = "true" ]; then RELEASE_NOTE="⚠️ **Release PR must be merged first** - check [release workflow runs](https://github.com/Comfy-Org/ComfyUI_frontend/actions/workflows/release-version-bump.yaml)" - BODY="${RELEASE_NOTE}\n\n${BODY}" + BODY=$''"${RELEASE_NOTE}"$'\n\n'"${BODY}" fi # Save to file for later use - echo "$BODY" > pr-body.txt + printf '%s\n' "$BODY" > pr-body.txt cat pr-body.txt - name: Create PR to ComfyUI