diff --git a/.github/workflows/auto-start-ci.yml b/.github/workflows/auto-start-ci.yml index 8c01b0592c2e..8bd15c5d4519 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: @@ -27,10 +27,11 @@ jobs: runs-on: ubuntu-slim outputs: numbers: ${{ steps.get_prs_for_ci.outputs.numbers }} + resume_numbers: ${{ steps.get_prs_for_ci.outputs.resume_numbers }} steps: - name: Get Pull Requests id: get_prs_for_ci - run: > + run: | echo "numbers=$(gh pr list \ --repo "$GITHUB_REPOSITORY" \ --label 'request-ci' \ @@ -38,6 +39,13 @@ jobs: --search 'review:approved' \ -t '{{ range . }}{{ .number }} {{ end }}' \ --limit 5)" >> "$GITHUB_OUTPUT" + echo "resume_numbers=$(gh pr list \ + --repo "$GITHUB_REPOSITORY" \ + --label 'resume-ci' \ + --json 'number' \ + --search 'review:approved' \ + -t '{{ range . }}{{ .number }} {{ end }}' \ + --limit 5)" >> "$GITHUB_OUTPUT" env: GH_TOKEN: ${{ github.token }} start-ci: @@ -47,7 +55,9 @@ jobs: pull-requests: write statuses: read needs: get-prs-for-ci - if: needs.get-prs-for-ci.outputs.numbers != '' + if: >- + needs.get-prs-for-ci.outputs.numbers != '' || + needs.get-prs-for-ci.outputs.resume_numbers != '' runs-on: ubuntu-slim steps: - name: Install Node.js @@ -71,8 +81,17 @@ jobs: JENKINS_TOKEN: ${{ secrets.JENKINS_TOKEN }} - name: Start the CI + if: needs.get-prs-for-ci.outputs.numbers != '' run: | curl -fsSL "https://github.com/${GITHUB_REPOSITORY}/raw/${GITHUB_SHA}/tools/actions/start-ci.sh" \ | sh -s -- ${{ needs.get-prs-for-ci.outputs.numbers }} env: GH_TOKEN: ${{ github.token }} + + - name: Resume the CI + if: needs.get-prs-for-ci.outputs.resume_numbers != '' + run: | + curl -fsSL "https://github.com/${GITHUB_REPOSITORY}/raw/${GITHUB_SHA}/tools/actions/resume-ci.sh" \ + | sh -s -- ${{ needs.get-prs-for-ci.outputs.resume_numbers }} + env: + GH_TOKEN: ${{ github.token }} diff --git a/doc/contributing/collaborator-guide.md b/doc/contributing/collaborator-guide.md index 49ece70c2bb0..dd36763b2a13 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`. Each script checks the current labels +and reports a failure if the other request label is present, 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 ` 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/resume-ci.sh b/tools/actions/resume-ci.sh new file mode 100755 index 000000000000..becd65a76169 --- /dev/null +++ b/tools/actions/resume-ci.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +set -xe + +RESUME_CI_LABEL="resume-ci" +RESUME_CI_FAILED_LABEL="resume-ci-failed" +cqurl="${GITHUB_SERVER_URL:?}/${GITHUB_REPOSITORY:?}/actions/runs/${GITHUB_RUN_ID:?}" + +for pr in "$@"; do + start_requested=$(gh -R "$GITHUB_REPOSITORY" pr view "$pr" --json labels \ + --jq 'any(.labels[]; .name == "request-ci")') + gh -R "$GITHUB_REPOSITORY" pr edit "$pr" --remove-label "$RESUME_CI_LABEL" + + ci_resumed=yes + rm -f output; + if [ "$start_requested" = "true" ]; then + echo 'Refusing to resume CI while the request-ci label is present' >output + ci_resumed=no + else + ncu-ci resume "$pr" >output 2>&1 || ci_resumed=no + fi + cat output + + if [ "$ci_resumed" = "no" ]; then + gh -R "$GITHUB_REPOSITORY" pr edit "$pr" --add-label "$RESUME_CI_FAILED_LABEL" + + body="
Failed to resume CI
$(cat output)
$cqurl
" + echo "$body" + + gh -R "$GITHUB_REPOSITORY" pr comment "$pr" --body "$body" + + rm output + fi +done; diff --git a/tools/actions/start-ci.sh b/tools/actions/start-ci.sh index d4d19b92082d..3c300283942c 100755 --- a/tools/actions/start-ci.sh +++ b/tools/actions/start-ci.sh @@ -7,11 +7,18 @@ REQUEST_CI_FAILED_LABEL="request-ci-failed" cqurl="${GITHUB_SERVER_URL:?}/${GITHUB_REPOSITORY:?}/actions/runs/${GITHUB_RUN_ID:?}" for pr in "$@"; do + resume_requested=$(gh -R "$GITHUB_REPOSITORY" pr view "$pr" --json labels \ + --jq 'any(.labels[]; .name == "resume-ci")') gh -R "$GITHUB_REPOSITORY" pr edit "$pr" --remove-label "$REQUEST_CI_LABEL" ci_started=yes rm -f output; - ncu-ci run --check-for-duplicates "$pr" >output 2>&1 || ci_started=no + if [ "$resume_requested" = "true" ]; then + echo 'Refusing to start CI while the resume-ci label is present' >output + ci_started=no + else + ncu-ci run --check-for-duplicates "$pr" >output 2>&1 || ci_started=no + fi cat output if [ "$ci_started" = "no" ]; then