diff --git a/.github/workflows/pr-playwright-deploy.yaml b/.github/workflows/pr-playwright-deploy.yaml
index 12051fa99..19bb28253 100644
--- a/.github/workflows/pr-playwright-deploy.yaml
+++ b/.github/workflows/pr-playwright-deploy.yaml
@@ -1,4 +1,4 @@
-name: PR Playwright Deploy and Comment
+name: PR Playwright Deploy (Forks)
on:
workflow_run:
@@ -9,272 +9,84 @@ env:
DATE_FORMAT: '+%m/%d/%Y, %I:%M:%S %p'
jobs:
- deploy-reports:
+ deploy-and-comment-forked-pr:
runs-on: ubuntu-latest
- if: github.repository == 'Comfy-Org/ComfyUI_frontend' && github.event.workflow_run.event == 'pull_request' && github.event.action == 'completed'
+ if: |
+ github.repository == 'Comfy-Org/ComfyUI_frontend' &&
+ github.event.workflow_run.event == 'pull_request' &&
+ github.event.workflow_run.head_repository != null &&
+ github.event.workflow_run.repository != null &&
+ github.event.workflow_run.head_repository.full_name != github.event.workflow_run.repository.full_name
permissions:
+ pull-requests: write
actions: read
- strategy:
- fail-fast: false
- matrix:
- browser: [chromium, chromium-2x, chromium-0.5x, mobile-chrome]
steps:
- - name: Get PR info
- id: pr-info
+ - name: Log workflow trigger info
+ run: |
+ echo "Repository: ${{ github.repository }}"
+ echo "Event: ${{ github.event.workflow_run.event }}"
+ echo "Head repo: ${{ github.event.workflow_run.head_repository.full_name || 'null' }}"
+ echo "Base repo: ${{ github.event.workflow_run.repository.full_name || 'null' }}"
+ echo "Is forked: ${{ github.event.workflow_run.head_repository.full_name != github.event.workflow_run.repository.full_name }}"
+
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Get PR Number
+ id: pr
uses: actions/github-script@v7
with:
script: |
- const { data: pullRequests } = await github.rest.pulls.list({
+ const { data: prs } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
- head: `${context.repo.owner}:${context.payload.workflow_run.head_branch}`,
});
- if (pullRequests.length === 0) {
- console.log('No open PR found for this branch');
- return { number: null, sanitized_branch: null };
+ const pr = prs.find(p => p.head.sha === context.payload.workflow_run.head_sha);
+
+ if (!pr) {
+ console.log('No PR found for SHA:', context.payload.workflow_run.head_sha);
+ return null;
}
- const pr = pullRequests[0];
- const branchName = context.payload.workflow_run.head_branch;
- const sanitizedBranch = branchName.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/--+/g, '-').replace(/^-|-$/g, '');
-
- return {
- number: pr.number,
- sanitized_branch: sanitizedBranch
- };
+ console.log(`Found PR #${pr.number} from fork: ${context.payload.workflow_run.head_repository.full_name}`);
+ return pr.number;
- - name: Set project name
- if: fromJSON(steps.pr-info.outputs.result).number != null
- id: project-name
+ - name: Handle Test Start
+ if: steps.pr.outputs.result != 'null' && github.event.action == 'requested'
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
run: |
- if [ "${{ matrix.browser }}" = "chromium-0.5x" ]; then
- echo "name=comfyui-playwright-chromium-0-5x" >> $GITHUB_OUTPUT
- else
- echo "name=comfyui-playwright-${{ matrix.browser }}" >> $GITHUB_OUTPUT
- fi
- echo "branch=${{ fromJSON(steps.pr-info.outputs.result).sanitized_branch }}" >> $GITHUB_OUTPUT
+ chmod +x scripts/cicd/pr-playwright-deploy-and-comment.sh
+ ./scripts/cicd/pr-playwright-deploy-and-comment.sh \
+ "${{ steps.pr.outputs.result }}" \
+ "${{ github.event.workflow_run.head_branch }}" \
+ "starting" \
+ "$(date -u '${{ env.DATE_FORMAT }}')"
- - name: Download playwright report
- if: fromJSON(steps.pr-info.outputs.result).number != null
+ - name: Download and Deploy Reports
+ if: steps.pr.outputs.result != 'null' && github.event.action == 'completed'
uses: actions/download-artifact@v4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
- name: playwright-report-${{ matrix.browser }}
- path: playwright-report
-
- - name: Install Wrangler
- if: fromJSON(steps.pr-info.outputs.result).number != null
- run: npm install -g wrangler
-
- - name: Deploy to Cloudflare Pages (${{ matrix.browser }})
- if: fromJSON(steps.pr-info.outputs.result).number != null
- id: cloudflare-deploy
- continue-on-error: true
- run: |
- # Retry logic for wrangler deploy (3 attempts)
- RETRY_COUNT=0
- MAX_RETRIES=3
- SUCCESS=false
+ pattern: playwright-report-*
+ path: reports
- while [ $RETRY_COUNT -lt $MAX_RETRIES ] && [ $SUCCESS = false ]; do
- RETRY_COUNT=$((RETRY_COUNT + 1))
- echo "Deployment attempt $RETRY_COUNT of $MAX_RETRIES..."
-
- if npx wrangler pages deploy playwright-report --project-name=${{ steps.project-name.outputs.name }} --branch=${{ steps.project-name.outputs.branch }}; then
- SUCCESS=true
- echo "Deployment successful on attempt $RETRY_COUNT"
- else
- echo "Deployment failed on attempt $RETRY_COUNT"
- if [ $RETRY_COUNT -lt $MAX_RETRIES ]; then
- echo "Retrying in 10 seconds..."
- sleep 10
- fi
- fi
- done
-
- if [ $SUCCESS = false ]; then
- echo "All deployment attempts failed"
- exit 1
- fi
+ - name: Handle Test Completion
+ if: steps.pr.outputs.result != 'null' && github.event.action == 'completed'
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
-
- comment-tests-starting:
- runs-on: ubuntu-latest
- if: github.repository == 'Comfy-Org/ComfyUI_frontend' && github.event.workflow_run.event == 'pull_request' && github.event.action == 'requested'
- permissions:
- pull-requests: write
- actions: read
- steps:
- - name: Get PR number
- id: pr
- uses: actions/github-script@v7
- with:
- script: |
- const { data: pullRequests } = await github.rest.pulls.list({
- owner: context.repo.owner,
- repo: context.repo.repo,
- state: 'open',
- head: `${context.repo.owner}:${context.payload.workflow_run.head_branch}`,
- });
-
- if (pullRequests.length === 0) {
- console.log('No open PR found for this branch');
- return null;
- }
-
- return pullRequests[0].number;
-
- - name: Get completion time
- id: completion-time
- run: echo "time=$(date -u '${{ env.DATE_FORMAT }}')" >> $GITHUB_OUTPUT
-
- - name: Generate comment body for start
- if: steps.pr.outputs.result != 'null'
- id: comment-body-start
+ GITHUB_TOKEN: ${{ github.token }}
run: |
- echo "" > comment.md
- echo "## ๐ญ Playwright Test Results" >> comment.md
- echo "" >> comment.md
- echo "
**Tests are starting...** " >> comment.md
- echo "" >> comment.md
- echo "โฐ Started at: ${{ steps.completion-time.outputs.time }} UTC" >> comment.md
- echo "" >> comment.md
- echo "### ๐ Running Tests" >> comment.md
- echo "- ๐งช **chromium**: Running tests..." >> comment.md
- echo "- ๐งช **chromium-0.5x**: Running tests..." >> comment.md
- echo "- ๐งช **chromium-2x**: Running tests..." >> comment.md
- echo "- ๐งช **mobile-chrome**: Running tests..." >> comment.md
- echo "" >> comment.md
- echo "---" >> comment.md
- echo "โฑ๏ธ Please wait while tests are running across all browsers..." >> comment.md
-
- - name: Comment PR - Tests Started
- if: steps.pr.outputs.result != 'null'
- uses: edumserrano/find-create-or-update-comment@82880b65c8a3a6e4c70aa05a204995b6c9696f53 # v3.0.0
- with:
- issue-number: ${{ steps.pr.outputs.result }}
- body-includes: ''
- comment-author: 'github-actions[bot]'
- edit-mode: replace
- body-path: comment.md
-
- comment-tests-completed:
- runs-on: ubuntu-latest
- needs: deploy-reports
- if: github.repository == 'Comfy-Org/ComfyUI_frontend' && github.event.workflow_run.event == 'pull_request' && github.event.action == 'completed' && always()
- permissions:
- pull-requests: write
- actions: read
- steps:
- - name: Get PR number
- id: pr
- uses: actions/github-script@v7
- with:
- script: |
- const { data: pullRequests } = await github.rest.pulls.list({
- owner: context.repo.owner,
- repo: context.repo.repo,
- state: 'open',
- head: `${context.repo.owner}:${context.payload.workflow_run.head_branch}`,
- });
-
- if (pullRequests.length === 0) {
- console.log('No open PR found for this branch');
- return null;
- }
-
- return pullRequests[0].number;
-
- - name: Download all deployment info
- if: steps.pr.outputs.result != 'null'
- uses: actions/download-artifact@v4
- with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- run-id: ${{ github.event.workflow_run.id }}
- pattern: deployment-info-*
- merge-multiple: true
- path: deployment-info
-
- - name: Get completion time
- id: completion-time
- run: echo "time=$(date -u '${{ env.DATE_FORMAT }}')" >> $GITHUB_OUTPUT
-
- - name: Generate comment body for completion
- if: steps.pr.outputs.result != 'null'
- id: comment-body-completed
- run: |
- echo "" > comment.md
- echo "## ๐ญ Playwright Test Results" >> comment.md
- echo "" >> comment.md
-
- # Check if all tests passed
- ALL_PASSED=true
- for file in deployment-info/*.txt; do
- if [ -f "$file" ]; then
- browser=$(basename "$file" .txt)
- info=$(cat "$file")
- exit_code=$(echo "$info" | cut -d'|' -f2)
- if [ "$exit_code" != "0" ]; then
- ALL_PASSED=false
- break
- fi
- fi
- done
-
- if [ "$ALL_PASSED" = "true" ]; then
- echo "โ
**All tests passed across all browsers!**" >> comment.md
- else
- echo "โ **Some tests failed!**" >> comment.md
- fi
-
- echo "" >> comment.md
- echo "โฐ Completed at: ${{ steps.completion-time.outputs.time }} UTC" >> comment.md
- echo "" >> comment.md
- echo "### ๐ Test Reports by Browser" >> comment.md
-
- for file in deployment-info/*.txt; do
- if [ -f "$file" ]; then
- browser=$(basename "$file" .txt)
- info=$(cat "$file")
- exit_code=$(echo "$info" | cut -d'|' -f2)
- url=$(echo "$info" | cut -d'|' -f3)
-
- # Validate URLs before using them in comments
- sanitized_url=$(echo "$url" | grep -E '^https://[a-z0-9.-]+\.pages\.dev(/.*)?$' || echo "INVALID_URL")
- if [ "$sanitized_url" = "INVALID_URL" ]; then
- echo "Invalid deployment URL detected: $url"
- url="#" # Use safe fallback
- fi
-
- if [ "$exit_code" = "0" ]; then
- status="โ
"
- else
- status="โ"
- fi
-
- echo "- $status **$browser**: [View Report]($url)" >> comment.md
- fi
- done
-
- echo "" >> comment.md
- echo "---" >> comment.md
- if [ "$ALL_PASSED" = "true" ]; then
- echo "๐ Your tests are passing across all browsers!" >> comment.md
- else
- echo "โ ๏ธ Please check the test reports for details on failures." >> comment.md
- fi
-
- - name: Comment PR - Tests Complete
- if: steps.pr.outputs.result != 'null'
- uses: edumserrano/find-create-or-update-comment@82880b65c8a3a6e4c70aa05a204995b6c9696f53 # v3.0.0
- with:
- issue-number: ${{ steps.pr.outputs.result }}
- body-includes: ''
- comment-author: 'github-actions[bot]'
- edit-mode: replace
- body-path: comment.md
\ No newline at end of file
+ # Rename merged report if exists
+ [ -d "reports/playwright-report-chromium-merged" ] && \
+ mv reports/playwright-report-chromium-merged reports/playwright-report-chromium
+
+ chmod +x scripts/cicd/pr-playwright-deploy-and-comment.sh
+ ./scripts/cicd/pr-playwright-deploy-and-comment.sh \
+ "${{ steps.pr.outputs.result }}" \
+ "${{ github.event.workflow_run.head_branch }}" \
+ "completed"
\ No newline at end of file
diff --git a/.github/workflows/test-ui.yaml b/.github/workflows/test-ui.yaml
index 451c4b903..f8f6cf955 100644
--- a/.github/workflows/test-ui.yaml
+++ b/.github/workflows/test-ui.yaml
@@ -284,3 +284,65 @@ jobs:
name: playwright-report-chromium
path: ComfyUI_frontend/playwright-report/
retention-days: 30
+
+ #### BEGIN Deployment and commenting (non-forked PRs only)
+ # when using pull_request event, we have permission to comment directly
+ # if its a forked repo, we need to use workflow_run event in a separate workflow (pr-playwright-deploy.yaml)
+
+ # Post starting comment for non-forked PRs
+ comment-on-pr-start:
+ runs-on: ubuntu-latest
+ if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false
+ permissions:
+ pull-requests: write
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Get start time
+ id: start-time
+ run: echo "time=$(date -u '+%m/%d/%Y, %I:%M:%S %p')" >> $GITHUB_OUTPUT
+
+ - name: Post starting comment
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ run: |
+ chmod +x scripts/cicd/pr-playwright-deploy-and-comment.sh
+ ./scripts/cicd/pr-playwright-deploy-and-comment.sh \
+ "${{ github.event.pull_request.number }}" \
+ "${{ github.head_ref }}" \
+ "starting" \
+ "${{ steps.start-time.outputs.time }}"
+
+ # Deploy and comment for non-forked PRs only
+ deploy-and-comment:
+ needs: [playwright-tests, merge-reports]
+ runs-on: ubuntu-latest
+ if: always() && github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false
+ permissions:
+ pull-requests: write
+ contents: read
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Download all playwright reports
+ uses: actions/download-artifact@v4
+ with:
+ pattern: playwright-report-*
+ path: reports
+
+ - name: Make deployment script executable
+ run: chmod +x scripts/cicd/pr-playwright-deploy-and-comment.sh
+
+ - name: Deploy reports and comment on PR
+ env:
+ CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
+ CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
+ GITHUB_TOKEN: ${{ github.token }}
+ run: |
+ ./scripts/cicd/pr-playwright-deploy-and-comment.sh \
+ "${{ github.event.pull_request.number }}" \
+ "${{ github.head_ref }}" \
+ "completed"
+ #### END Deployment and commenting (non-forked PRs only)
\ No newline at end of file
diff --git a/scripts/cicd/pr-playwright-deploy-and-comment.sh b/scripts/cicd/pr-playwright-deploy-and-comment.sh
new file mode 100755
index 000000000..767a7f514
--- /dev/null
+++ b/scripts/cicd/pr-playwright-deploy-and-comment.sh
@@ -0,0 +1,241 @@
+#!/bin/bash
+set -e
+
+# Deploy Playwright test reports to Cloudflare Pages and comment on PR
+# Usage: ./pr-playwright-deploy-and-comment.sh [start_time]
+
+# Input validation
+# Validate PR number is numeric
+case "$1" in
+ ''|*[!0-9]*)
+ echo "Error: PR_NUMBER must be numeric" >&2
+ exit 1
+ ;;
+esac
+PR_NUMBER="$1"
+
+# Sanitize and validate branch name (allow alphanumeric, dots, dashes, underscores, slashes)
+BRANCH_NAME=$(echo "$2" | sed 's/[^a-zA-Z0-9._/-]//g')
+if [ -z "$BRANCH_NAME" ]; then
+ echo "Error: Invalid or empty branch name" >&2
+ exit 1
+fi
+
+# Validate status parameter
+STATUS="${3:-completed}"
+case "$STATUS" in
+ starting|completed) ;;
+ *)
+ echo "Error: STATUS must be 'starting' or 'completed'" >&2
+ exit 1
+ ;;
+esac
+
+START_TIME="${4:-$(date -u '+%m/%d/%Y, %I:%M:%S %p')}"
+
+# Required environment variables
+: "${GITHUB_TOKEN:?GITHUB_TOKEN is required}"
+: "${GITHUB_REPOSITORY:?GITHUB_REPOSITORY is required}"
+
+# Cloudflare variables only required for deployment
+if [ "$STATUS" = "completed" ]; then
+ : "${CLOUDFLARE_API_TOKEN:?CLOUDFLARE_API_TOKEN is required for deployment}"
+ : "${CLOUDFLARE_ACCOUNT_ID:?CLOUDFLARE_ACCOUNT_ID is required for deployment}"
+fi
+
+# Configuration
+COMMENT_MARKER=""
+# Use dot notation for artifact names (as Playwright creates them)
+BROWSERS="chromium chromium-2x chromium-0.5x mobile-chrome"
+
+# Install wrangler if not available (output to stderr for debugging)
+if ! command -v wrangler > /dev/null 2>&1; then
+ echo "Installing wrangler v4..." >&2
+ npm install -g wrangler@^4.0.0 >&2 || {
+ echo "Failed to install wrangler" >&2
+ echo "failed"
+ return
+ }
+fi
+
+# Deploy a single browser report, WARN: ensure inputs are sanitized before calling this function
+deploy_report() {
+ dir="$1"
+ browser="$2"
+ branch="$3"
+
+ [ ! -d "$dir" ] && echo "failed" && return
+
+
+ # Project name with dots converted to dashes for Cloudflare
+ sanitized_browser=$(echo "$browser" | sed 's/\./-/g')
+ project="comfyui-playwright-${sanitized_browser}"
+
+ echo "Deploying $browser to project $project on branch $branch..." >&2
+
+ # Try deployment up to 3 times
+ i=1
+ while [ $i -le 3 ]; do
+ echo "Deployment attempt $i of 3..." >&2
+ # Branch and project are already sanitized, use them directly
+ # Branch was sanitized at script start, project uses sanitized_browser
+ if output=$(wrangler pages deploy "$dir" \
+ --project-name="$project" \
+ --branch="$branch" 2>&1); then
+
+ # Extract URL from output (improved regex for valid URL characters)
+ url=$(echo "$output" | grep -oE 'https://[a-zA-Z0-9.-]+\.pages\.dev\S*' | head -1)
+ result="${url:-https://${branch}.${project}.pages.dev}"
+ echo "Success! URL: $result" >&2
+ echo "$result" # Only this goes to stdout for capture
+ return
+ else
+ echo "Deployment failed on attempt $i: $output" >&2
+ fi
+ [ $i -lt 3 ] && sleep 10
+ i=$((i + 1))
+ done
+
+ echo "failed"
+}
+
+# Post or update GitHub comment
+post_comment() {
+ body="$1"
+ temp_file=$(mktemp)
+ echo "$body" > "$temp_file"
+
+ if command -v gh > /dev/null 2>&1; then
+ # Find existing comment ID
+ existing=$(gh api "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments" \
+ --jq ".[] | select(.body | contains(\"$COMMENT_MARKER\")) | .id" | head -1)
+
+ if [ -n "$existing" ]; then
+ # Update specific comment by ID
+ gh api --method PATCH "repos/$GITHUB_REPOSITORY/issues/comments/$existing" \
+ --field body="$(cat "$temp_file")"
+ else
+ # Create new comment
+ gh pr comment "$PR_NUMBER" --body-file "$temp_file"
+ fi
+ else
+ echo "GitHub CLI not available, outputting comment:"
+ cat "$temp_file"
+ fi
+
+ rm -f "$temp_file"
+}
+
+# Main execution
+if [ "$STATUS" = "starting" ]; then
+ # Post starting comment
+ comment=$(cat < **Tests are starting...**
+
+โฐ Started at: $START_TIME UTC
+
+### ๐ Running Tests
+- ๐งช **chromium**: Running tests...
+- ๐งช **chromium-0.5x**: Running tests...
+- ๐งช **chromium-2x**: Running tests...
+- ๐งช **mobile-chrome**: Running tests...
+
+---
+โฑ๏ธ Please wait while tests are running...
+EOF
+)
+ post_comment "$comment"
+
+else
+ # Deploy and post completion comment
+ # Convert branch name to Cloudflare-compatible format (lowercase, only alphanumeric and dashes)
+ cloudflare_branch=$(echo "$BRANCH_NAME" | tr '[:upper:]' '[:lower:]' | \
+ sed 's/[^a-z0-9-]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g')
+
+ echo "Looking for reports in: $(pwd)/reports"
+ echo "Available reports:"
+ ls -la reports/ 2>/dev/null || echo "Reports directory not found"
+
+ # Deploy all reports in parallel and collect URLs
+ temp_dir=$(mktemp -d)
+ pids=""
+ i=0
+
+ # Start parallel deployments
+ for browser in $BROWSERS; do
+ if [ -d "reports/playwright-report-$browser" ]; then
+ echo "Found report for $browser, deploying in parallel..."
+ (
+ url=$(deploy_report "reports/playwright-report-$browser" "$browser" "$cloudflare_branch")
+ echo "$url" > "$temp_dir/$i.url"
+ echo "Deployment result for $browser: $url"
+ ) &
+ pids="$pids $!"
+ else
+ echo "Report not found for $browser at reports/playwright-report-$browser"
+ echo "failed" > "$temp_dir/$i.url"
+ fi
+ i=$((i + 1))
+ done
+
+ # Wait for all deployments to complete
+ for pid in $pids; do
+ wait $pid
+ done
+
+ # Collect URLs in order
+ urls=""
+ i=0
+ for browser in $BROWSERS; do
+ if [ -f "$temp_dir/$i.url" ]; then
+ url=$(cat "$temp_dir/$i.url")
+ else
+ url="failed"
+ fi
+ if [ -z "$urls" ]; then
+ urls="$url"
+ else
+ urls="$urls $url"
+ fi
+ i=$((i + 1))
+ done
+
+ # Clean up temp directory
+ rm -rf "$temp_dir"
+
+ # Generate completion comment
+ comment="$COMMENT_MARKER
+## ๐ญ Playwright Test Results
+
+โ
**Tests completed successfully!**
+
+โฐ Completed at: $(date -u '+%m/%d/%Y, %I:%M:%S %p') UTC
+
+### ๐ Test Reports by Browser"
+
+ # Add browser results
+ i=0
+ for browser in $BROWSERS; do
+ # Get URL at position i
+ url=$(echo "$urls" | cut -d' ' -f$((i + 1)))
+
+ if [ "$url" != "failed" ] && [ -n "$url" ]; then
+ comment="$comment
+- โ
**${browser}**: [View Report](${url})"
+ else
+ comment="$comment
+- โ **${browser}**: Deployment failed"
+ fi
+ i=$((i + 1))
+ done
+
+ comment="$comment
+
+---
+๐ Click on the links above to view detailed test results for each browser configuration."
+
+ post_comment "$comment"
+fi
\ No newline at end of file