Commit bd111f33b4d for nodejs

commit bd111f33b4dfd413629521c94fff00ed6528c08b
Author: Filip Skokan <panva.ip@gmail.com>
Date:   Thu Sep 24 16:35:23 2026 +0200

    tools: add resume-ci label handling

    Signed-off-by: Filip Skokan <panva.ip@gmail.com>
    Assisted-by: Codex
    PR-URL: https://github.com/nodejs/node/pull/65945
    Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
    Reviewed-By: James M Snell <jasnell@gmail.com>

diff --git a/.github/workflows/auto-start-ci.yml b/.github/workflows/auto-start-ci.yml
index dc827d62ba7..c8b090fdc04 100644
--- a/.github/workflows/auto-start-ci.yml
+++ b/.github/workflows/auto-start-ci.yml
@@ -1,6 +1,6 @@
 # This action uses the following secrets:
 #   JENKINS_USER: GitHub user whose Jenkins token is defined below
-#   JENKINS_TOKEN: Jenkins token, to be used to start CI
+#   JENKINS_TOKEN: Jenkins token, to be used to start or resume CI
 name: Auto Start CI

 on:
@@ -30,14 +30,14 @@ jobs:
     steps:
       - name: Get Pull Requests
         id: get_prs_for_ci
-        run: >
-          echo "numbers=$(gh pr list \
+        run: |
+          numbers=$(gh pr list \
                   --repo "$GITHUB_REPOSITORY" \
-                  --label 'request-ci' \
                   --json 'number' \
-                  --search 'review:approved' \
+                  --search 'review:approved label:request-ci,resume-ci' \
                   -t '{{ range . }}{{ .number }} {{ end }}' \
-                  --limit 5)" >> "$GITHUB_OUTPUT"
+                  --limit 5)
+          echo "numbers=$numbers" >> "$GITHUB_OUTPUT"
         env:
           GH_TOKEN: ${{ github.token }}
   start-ci:
@@ -70,7 +70,7 @@ jobs:
           GH_TOKEN: ${{ github.token }}
           JENKINS_TOKEN: ${{ secrets.JENKINS_TOKEN }}

-      - name: Start the CI
+      - name: Start or resume the CI
         run: |
           read -r -a numbers <<< "$PULL_REQUESTS"
           curl -fsSL "https://github.com/${GITHUB_REPOSITORY}/raw/${GITHUB_SHA}/tools/actions/start-ci.sh" \
diff --git a/doc/contributing/collaborator-guide.md b/doc/contributing/collaborator-guide.md
index 49ece70c2bb..96425ebc088 100644
--- a/doc/contributing/collaborator-guide.md
+++ b/doc/contributing/collaborator-guide.md
@@ -391,6 +391,21 @@ Once this label is added, `github-actions bot` will start
 the `node-test-pull-request` automatically. If the `github-actions bot`
 is unable to start the job, it will update the label with `request-ci-failed`.

+To resume an existing CI run, add the `resume-ci` label to the pull request.
+As with `request-ci`, the pull request must have an approving review. The bot
+removes `resume-ci` when processing the request. If it cannot resume the job, it
+adds `resume-ci-failed` and posts the command output with a link to the workflow
+run.
+
+Do not combine `request-ci` and `resume-ci`. If both labels are present, the bot
+removes both, adds `request-ci-failed` and `resume-ci-failed`, and reports the
+conflict once without starting or resuming CI.
+
+The job must be failed or aborted and resumable, and its CI-approved commit must
+still match the pull request's HEAD. Resuming is refused when available failure
+diagnostics reference files changed by the pull request. Use `request-ci` when a
+fresh CI run is needed instead.
+
 ### Internal vs. public API

 All functionality in the official Node.js documentation is part of the public
@@ -1011,6 +1026,8 @@ If you cannot find who to cc for a file, `git shortlog -n -s <file>` can help.
 * `never-stale`: Issues and pull requests exempt from automatic stale handling
 * `request-ci`: When this label is added to a PR, CI will be started
   automatically. See [Starting a Jenkins CI job](#starting-a-jenkins-ci-job)
+* `resume-ci`: When this label is added to a PR, the latest linked CI run will be
+  resumed if eligible. See [Starting a Jenkins CI job](#starting-a-jenkins-ci-job)
 * `stale`: Issues and pull requests with no activity for 90 days. See
   [Stale issues and pull requests](#stale-issues-and-pull-requests)
 * `tsc-agenda`: Open issues and pull requests with this label will be added to
diff --git a/tools/actions/start-ci.sh b/tools/actions/start-ci.sh
index a9ae07a365e..4573b17761c 100755
--- a/tools/actions/start-ci.sh
+++ b/tools/actions/start-ci.sh
@@ -2,8 +2,6 @@

 set -xe

-REQUEST_CI_LABEL="request-ci"
-REQUEST_CI_FAILED_LABEL="request-ci-failed"
 cqurl="${GITHUB_SERVER_URL:?}/${GITHUB_REPOSITORY:?}/actions/runs/${GITHUB_RUN_ID:?}"

 escape_code_block_or_line() {
@@ -21,16 +19,39 @@ escape_code_block_or_line() {
 }

 for pr in "$@"; do
-  gh -R "$GITHUB_REPOSITORY" pr edit "$pr" --remove-label "$REQUEST_CI_LABEL"
+  request_labels=$(gh -R "$GITHUB_REPOSITORY" pr view "$pr" --json labels \
+    --jq '[.labels[].name | select(. == "request-ci" or . == "resume-ci")] | sort | join(",")')
+  case "$request_labels" in
+    request-ci)
+      action=start
+      failed_labels=request-ci-failed
+      ;;
+    resume-ci)
+      action=resume
+      failed_labels=resume-ci-failed
+      ;;
+    request-ci,resume-ci)
+      action='start or resume'
+      failed_labels=request-ci-failed,resume-ci-failed
+      ;;
+    *) continue ;;
+  esac
+  gh -R "$GITHUB_REPOSITORY" pr edit "$pr" --remove-label "$request_labels"

-  ci_started=yes
+  ci_succeeded=yes
   rm -f output;
-  ncu-ci run --check-for-duplicates "$pr" >output 2>&1 || ci_started=no
+  if [ "$request_labels" = "request-ci,resume-ci" ]; then
+    echo 'Refusing to start or resume CI while both request-ci and resume-ci labels are present' >output
+    ci_succeeded=no
+  elif [ "$action" = "resume" ]; then
+    ncu-ci resume "$pr" >output 2>&1 || ci_succeeded=no
+  else
+    ncu-ci run --check-for-duplicates "$pr" >output 2>&1 || ci_succeeded=no
+  fi
   cat output

-  if [ "$ci_started" = "no" ]; then
-    # Do we need to reset?
-    gh -R "$GITHUB_REPOSITORY" pr edit "$pr" --add-label "$REQUEST_CI_FAILED_LABEL"
+  if [ "$ci_succeeded" = "no" ]; then
+    gh -R "$GITHUB_REPOSITORY" pr edit "$pr" --add-label "$failed_labels"

     reported_failure=$(grep -e '✘' -e '✖' -e '⚠' -e 'ℹ' output | tail -n 10)
     if [ -z "$reported_failure" ]; then
@@ -42,7 +63,7 @@ for pr in "$@"; do
     failure_body=$(escape_code_block_or_line "$reported_failure")
     raw_output=$(cat output)

-    body="### Failed to start CI
+    body="### Failed to $action CI

 $failure_body