From ea30f5fef2ac509729fd9787f5815a7c1ad80217 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Fri, 28 Aug 2026 13:57:52 -0400 Subject: [PATCH 1/5] Use the Checks API to detect a timed out job. While the REST API documents `timed_out` as a possible value for a job's `conclusion`, it turns out that value is never surfaced for a job object. However, a cancelation and a time out can be determined by examining the annotations associated with a given job through the Checks API. --- .github/workflows/coding-standards.yml | 1 + .github/workflows/end-to-end-tests.yml | 1 + .github/workflows/install-testing.yml | 1 + .github/workflows/javascript-tests.yml | 1 + .../workflows/javascript-type-checking.yml | 1 + .../workflows/local-docker-environment.yml | 1 + .github/workflows/performance.yml | 1 + .github/workflows/php-compatibility.yml | 1 + .github/workflows/phpstan-static-analysis.yml | 1 + .github/workflows/phpunit-tests.yml | 1 + .github/workflows/slack-notifications.yml | 43 +++++++++++++++++-- .../workflows/test-and-zip-default-themes.yml | 1 + .github/workflows/test-build-processes.yml | 1 + .github/workflows/test-coverage.yml | 1 + .github/workflows/test-old-branches.yml | 1 + .github/workflows/upgrade-develop-testing.yml | 1 + .github/workflows/upgrade-testing.yml | 1 + .github/workflows/workflow-lint.yml | 1 + 18 files changed, 57 insertions(+), 3 deletions(-) diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index d579368eeb079..c512604bde65b 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -79,6 +79,7 @@ jobs: uses: ./.github/workflows/slack-notifications.yml permissions: actions: read + checks: read contents: read needs: [ phpcs, jshint ] if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} diff --git a/.github/workflows/end-to-end-tests.yml b/.github/workflows/end-to-end-tests.yml index f2eb5abb83ddb..8f65445104227 100644 --- a/.github/workflows/end-to-end-tests.yml +++ b/.github/workflows/end-to-end-tests.yml @@ -79,6 +79,7 @@ jobs: uses: ./.github/workflows/slack-notifications.yml permissions: actions: read + checks: read contents: read needs: [ e2e-tests ] if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} diff --git a/.github/workflows/install-testing.yml b/.github/workflows/install-testing.yml index d69dc103d2d3a..1fcb9e3f7f6d2 100644 --- a/.github/workflows/install-testing.yml +++ b/.github/workflows/install-testing.yml @@ -142,6 +142,7 @@ jobs: uses: ./.github/workflows/slack-notifications.yml permissions: actions: read + checks: read contents: read needs: [ install-tests-mysql ] if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} diff --git a/.github/workflows/javascript-tests.yml b/.github/workflows/javascript-tests.yml index 08a118e4a4056..fc12eae777973 100644 --- a/.github/workflows/javascript-tests.yml +++ b/.github/workflows/javascript-tests.yml @@ -67,6 +67,7 @@ jobs: uses: ./.github/workflows/slack-notifications.yml permissions: actions: read + checks: read contents: read needs: [ test-js ] if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} diff --git a/.github/workflows/javascript-type-checking.yml b/.github/workflows/javascript-type-checking.yml index 4983e0c619ec8..76f53064becaa 100644 --- a/.github/workflows/javascript-type-checking.yml +++ b/.github/workflows/javascript-type-checking.yml @@ -60,6 +60,7 @@ jobs: uses: ./.github/workflows/slack-notifications.yml permissions: actions: read + checks: read contents: read needs: [ typecheck ] if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} diff --git a/.github/workflows/local-docker-environment.yml b/.github/workflows/local-docker-environment.yml index 0f88d54ff4eb8..3bfeb2406220a 100644 --- a/.github/workflows/local-docker-environment.yml +++ b/.github/workflows/local-docker-environment.yml @@ -125,6 +125,7 @@ jobs: uses: ./.github/workflows/slack-notifications.yml permissions: actions: read + checks: read contents: read needs: [ build-test-matrix, environment-tests-mysql ] if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 22a3a27392859..a4b2421031f5a 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -143,6 +143,7 @@ jobs: uses: ./.github/workflows/slack-notifications.yml permissions: actions: read + checks: read contents: read needs: [ performance ] if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} diff --git a/.github/workflows/php-compatibility.yml b/.github/workflows/php-compatibility.yml index 37de91a73b24b..c3cf4e85d8833 100644 --- a/.github/workflows/php-compatibility.yml +++ b/.github/workflows/php-compatibility.yml @@ -56,6 +56,7 @@ jobs: uses: ./.github/workflows/slack-notifications.yml permissions: actions: read + checks: read contents: read needs: [ php-compatibility ] if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} diff --git a/.github/workflows/phpstan-static-analysis.yml b/.github/workflows/phpstan-static-analysis.yml index a07ee13e16467..9a45cf61a3cd9 100644 --- a/.github/workflows/phpstan-static-analysis.yml +++ b/.github/workflows/phpstan-static-analysis.yml @@ -56,6 +56,7 @@ jobs: uses: ./.github/workflows/slack-notifications.yml permissions: actions: read + checks: read contents: read needs: [ phpstan ] if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} diff --git a/.github/workflows/phpunit-tests.yml b/.github/workflows/phpunit-tests.yml index 30cf72bc606ae..3485fac08bfd2 100644 --- a/.github/workflows/phpunit-tests.yml +++ b/.github/workflows/phpunit-tests.yml @@ -401,6 +401,7 @@ jobs: uses: ./.github/workflows/slack-notifications.yml permissions: actions: read + checks: read contents: read needs: [ prepare-gutenberg, test-with-mysql, test-with-mariadb, test-innovation-releases, html-api-test-groups, limited-matrix-for-forks ] if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} diff --git a/.github/workflows/slack-notifications.yml b/.github/workflows/slack-notifications.yml index 6a2f23714e291..a59b4b6c2e1e9 100644 --- a/.github/workflows/slack-notifications.yml +++ b/.github/workflows/slack-notifications.yml @@ -46,6 +46,7 @@ jobs: # - Retrieves the current workflow run. # - Determines the conclusion of the previous workflow run or run attempt. # - Sets the previous conclusion as an output. + # - Determines if a canceled job timed out or was actually canceled. # - Prepares the commit message. # - Constructs and stores a message payload as an output. prepare: @@ -53,6 +54,7 @@ jobs: runs-on: ubuntu-24.04 permissions: actions: read + checks: read contents: read timeout-minutes: 5 if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event.workflow_run.event != 'pull_request' }} @@ -132,7 +134,11 @@ jobs: env: CALLING_STATUS: ${{ inputs.calling_status }} - # The REST API exposes a distinct `timed_out` job conclusion that is unavailable through workflow contexts. + # Distinguish between a truly canceled job and one that times out. + # + # While `timed_out` is documented as a possible value for `conclusion`, this value is never returned within a job + # object through the REST API. However, the checks API does return this detail and can be used to determine the + # true type of cancellation. - name: Determine whether the workflow timed out id: timeout-check uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -147,9 +153,40 @@ jobs: repo: context.repo.repo, run_id: `${context.runId}`, attempt_number: Number( process.env.GITHUB_RUN_ATTEMPT ), - }, ( response ) => response.data.jobs ); + per_page: 100, + } ); - return jobs.some( ( job ) => job.conclusion === 'timed_out' ) ? 'true' : 'false'; + const cancelledJobs = jobs.filter( ( job ) => job.conclusion === 'cancelled' ); + const BATCH_SIZE = 100; + + for ( let i = 0; i < cancelledJobs.length; i += BATCH_SIZE ) { + const batch = cancelledJobs.slice( i, i + BATCH_SIZE ); + + const { nodes } = await github.graphql( + `query( $ids: [ID!]! ) { + nodes( ids: $ids ) { + ... on CheckRun { + annotations( first: 10 ) { + nodes { + message + } + } + } + } + }`, + { ids: batch.map( ( job ) => job.node_id ) } + ); + + const timedOut = nodes.some( ( node ) => node && node.annotations.nodes.some( + ( annotation ) => /exceeded the maximum execution time/i.test( annotation.message ) + ) ); + + if ( timedOut ) { + return 'true'; + } + } + + return 'false'; - name: Get the commit message id: current-commit-message diff --git a/.github/workflows/test-and-zip-default-themes.yml b/.github/workflows/test-and-zip-default-themes.yml index 0464a1652d36b..66b7724b42f4d 100644 --- a/.github/workflows/test-and-zip-default-themes.yml +++ b/.github/workflows/test-and-zip-default-themes.yml @@ -274,6 +274,7 @@ jobs: uses: ./.github/workflows/slack-notifications.yml permissions: actions: read + checks: read contents: read needs: [ check-for-empty-files, bundle-theme, test-build-scripts ] if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} diff --git a/.github/workflows/test-build-processes.yml b/.github/workflows/test-build-processes.yml index ab3bea392cef8..6df5f433b4712 100644 --- a/.github/workflows/test-build-processes.yml +++ b/.github/workflows/test-build-processes.yml @@ -108,6 +108,7 @@ jobs: uses: ./.github/workflows/slack-notifications.yml permissions: actions: read + checks: read contents: read needs: [ test-core-build-process, test-core-build-process-additional-os ] if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} diff --git a/.github/workflows/test-coverage.yml b/.github/workflows/test-coverage.yml index 94f57628254c3..228788003527f 100644 --- a/.github/workflows/test-coverage.yml +++ b/.github/workflows/test-coverage.yml @@ -87,6 +87,7 @@ jobs: uses: ./.github/workflows/slack-notifications.yml permissions: actions: read + checks: read contents: read needs: [ prepare-gutenberg, test-coverage-report ] if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} diff --git a/.github/workflows/test-old-branches.yml b/.github/workflows/test-old-branches.yml index 7094550485c4f..80be892009484 100644 --- a/.github/workflows/test-old-branches.yml +++ b/.github/workflows/test-old-branches.yml @@ -148,6 +148,7 @@ jobs: uses: ./.github/workflows/slack-notifications.yml permissions: actions: read + checks: read contents: read needs: [ dispatch-workflows-for-old-branches ] if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} diff --git a/.github/workflows/upgrade-develop-testing.yml b/.github/workflows/upgrade-develop-testing.yml index a01e5239fac17..e8409c3a28692 100644 --- a/.github/workflows/upgrade-develop-testing.yml +++ b/.github/workflows/upgrade-develop-testing.yml @@ -130,6 +130,7 @@ jobs: uses: ./.github/workflows/slack-notifications.yml permissions: actions: read + checks: read contents: read needs: [ upgrade-tests-develop ] if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} diff --git a/.github/workflows/upgrade-testing.yml b/.github/workflows/upgrade-testing.yml index ba82f96a7b779..d6463e8c37779 100644 --- a/.github/workflows/upgrade-testing.yml +++ b/.github/workflows/upgrade-testing.yml @@ -196,6 +196,7 @@ jobs: uses: ./.github/workflows/slack-notifications.yml permissions: actions: read + checks: read contents: read needs: [ upgrade-tests-recent-releases, upgrade-tests-wp-6x-mysql, upgrade-tests-wp-5x-php-7x-mysql, upgrade-tests-wp-5x-php-8x-mysql, upgrade-tests-oldest-wp-mysql ] if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} diff --git a/.github/workflows/workflow-lint.yml b/.github/workflows/workflow-lint.yml index 1ef050f1b9b92..af02051f36441 100644 --- a/.github/workflows/workflow-lint.yml +++ b/.github/workflows/workflow-lint.yml @@ -51,6 +51,7 @@ jobs: uses: ./.github/workflows/slack-notifications.yml permissions: actions: read + checks: read contents: read needs: [ lint ] if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} From 64eeeed6710b7993b5906eee4dab0809665524e9 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Fri, 28 Aug 2026 20:51:34 -0400 Subject: [PATCH 2/5] Add some temporary debugging. --- .github/workflows/phpunit-tests.yml | 2 +- .github/workflows/reusable-phpunit-tests-v3.yml | 2 +- .github/workflows/slack-notifications.yml | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/phpunit-tests.yml b/.github/workflows/phpunit-tests.yml index 3485fac08bfd2..8d8c221d76781 100644 --- a/.github/workflows/phpunit-tests.yml +++ b/.github/workflows/phpunit-tests.yml @@ -404,7 +404,7 @@ jobs: checks: read contents: read needs: [ prepare-gutenberg, test-with-mysql, test-with-mariadb, test-innovation-releases, html-api-test-groups, limited-matrix-for-forks ] - if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} + if: ${{ always() }} with: calling_status: ${{ contains( needs.*.result, 'cancelled' ) && 'cancelled' || contains( needs.*.result, 'failure' ) && 'failure' || 'success' }} secrets: diff --git a/.github/workflows/reusable-phpunit-tests-v3.yml b/.github/workflows/reusable-phpunit-tests-v3.yml index 4f7addcd4e60e..1cc74a43fcf72 100644 --- a/.github/workflows/reusable-phpunit-tests-v3.yml +++ b/.github/workflows/reusable-phpunit-tests-v3.yml @@ -130,7 +130,7 @@ jobs: phpunit-tests: name: ${{ ( inputs.phpunit-test-groups || inputs.coverage-report ) && format( 'PHP {0} with ', inputs.php ) || '' }} ${{ 'mariadb' == inputs.db-type && 'MariaDB' || 'MySQL' }} ${{ inputs.db-version }}${{ inputs.multisite && ' multisite' || '' }}${{ inputs.db-innovation && ' (innovation release)' || '' }}${{ inputs.memcached && ' with memcached' || '' }}${{ inputs.report && ' (test reporting enabled)' || '' }} ${{ 'example.org' != inputs.tests-domain && inputs.tests-domain || '' }} runs-on: ${{ vars.RUNNERS_NAME || inputs.os }} - timeout-minutes: ${{ inputs.coverage-report && 120 || inputs.php == '8.4' && 30 || 20 }} + timeout-minutes: 1 permissions: contents: read diff --git a/.github/workflows/slack-notifications.yml b/.github/workflows/slack-notifications.yml index a59b4b6c2e1e9..27bc5bb11eb10 100644 --- a/.github/workflows/slack-notifications.yml +++ b/.github/workflows/slack-notifications.yml @@ -57,7 +57,7 @@ jobs: checks: read contents: read timeout-minutes: 5 - if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event.workflow_run.event != 'pull_request' }} + if: ${{ true }} outputs: previous_conclusion: ${{ steps.previous-attempt-result.outputs.result }} timed_out: ${{ steps.timeout-check.outputs.result }} @@ -156,6 +156,8 @@ jobs: per_page: 100, } ); + console.log( jobs ); + const cancelledJobs = jobs.filter( ( job ) => job.conclusion === 'cancelled' ); const BATCH_SIZE = 100; @@ -177,6 +179,8 @@ jobs: { ids: batch.map( ( job ) => job.node_id ) } ); + console.log( nodes ); + const timedOut = nodes.some( ( node ) => node && node.annotations.nodes.some( ( annotation ) => /exceeded the maximum execution time/i.test( annotation.message ) ) ); From 8a87f4bb98b1968178032dc5f8a0f48496ba46fd Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Fri, 28 Aug 2026 21:13:58 -0400 Subject: [PATCH 3/5] More debugging. --- .github/workflows/slack-notifications.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/slack-notifications.yml b/.github/workflows/slack-notifications.yml index 27bc5bb11eb10..9f320639353db 100644 --- a/.github/workflows/slack-notifications.yml +++ b/.github/workflows/slack-notifications.yml @@ -179,13 +179,14 @@ jobs: { ids: batch.map( ( job ) => job.node_id ) } ); - console.log( nodes ); + console.log( JSON.stringify( nodes, null, 2 ) ); const timedOut = nodes.some( ( node ) => node && node.annotations.nodes.some( ( annotation ) => /exceeded the maximum execution time/i.test( annotation.message ) ) ); if ( timedOut ) { + console.log( 'A timeout was detected' ); return 'true'; } } From 0f3087fd745488fb58093a8a741254489aabea22 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Fri, 28 Aug 2026 21:25:15 -0400 Subject: [PATCH 4/5] Revert "More debugging." This reverts commit 8a87f4bb98b1968178032dc5f8a0f48496ba46fd. --- .github/workflows/slack-notifications.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/slack-notifications.yml b/.github/workflows/slack-notifications.yml index 9f320639353db..27bc5bb11eb10 100644 --- a/.github/workflows/slack-notifications.yml +++ b/.github/workflows/slack-notifications.yml @@ -179,14 +179,13 @@ jobs: { ids: batch.map( ( job ) => job.node_id ) } ); - console.log( JSON.stringify( nodes, null, 2 ) ); + console.log( nodes ); const timedOut = nodes.some( ( node ) => node && node.annotations.nodes.some( ( annotation ) => /exceeded the maximum execution time/i.test( annotation.message ) ) ); if ( timedOut ) { - console.log( 'A timeout was detected' ); return 'true'; } } From e4163b220bfecc95715b5b978333f803fe9d69f7 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers <359867+desrosj@users.noreply.github.com> Date: Fri, 28 Aug 2026 21:25:19 -0400 Subject: [PATCH 5/5] Revert "Add some temporary debugging." This reverts commit 64eeeed6710b7993b5906eee4dab0809665524e9. --- .github/workflows/phpunit-tests.yml | 2 +- .github/workflows/reusable-phpunit-tests-v3.yml | 2 +- .github/workflows/slack-notifications.yml | 6 +----- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/phpunit-tests.yml b/.github/workflows/phpunit-tests.yml index 8d8c221d76781..3485fac08bfd2 100644 --- a/.github/workflows/phpunit-tests.yml +++ b/.github/workflows/phpunit-tests.yml @@ -404,7 +404,7 @@ jobs: checks: read contents: read needs: [ prepare-gutenberg, test-with-mysql, test-with-mariadb, test-innovation-releases, html-api-test-groups, limited-matrix-for-forks ] - if: ${{ always() }} + if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} with: calling_status: ${{ contains( needs.*.result, 'cancelled' ) && 'cancelled' || contains( needs.*.result, 'failure' ) && 'failure' || 'success' }} secrets: diff --git a/.github/workflows/reusable-phpunit-tests-v3.yml b/.github/workflows/reusable-phpunit-tests-v3.yml index 1cc74a43fcf72..4f7addcd4e60e 100644 --- a/.github/workflows/reusable-phpunit-tests-v3.yml +++ b/.github/workflows/reusable-phpunit-tests-v3.yml @@ -130,7 +130,7 @@ jobs: phpunit-tests: name: ${{ ( inputs.phpunit-test-groups || inputs.coverage-report ) && format( 'PHP {0} with ', inputs.php ) || '' }} ${{ 'mariadb' == inputs.db-type && 'MariaDB' || 'MySQL' }} ${{ inputs.db-version }}${{ inputs.multisite && ' multisite' || '' }}${{ inputs.db-innovation && ' (innovation release)' || '' }}${{ inputs.memcached && ' with memcached' || '' }}${{ inputs.report && ' (test reporting enabled)' || '' }} ${{ 'example.org' != inputs.tests-domain && inputs.tests-domain || '' }} runs-on: ${{ vars.RUNNERS_NAME || inputs.os }} - timeout-minutes: 1 + timeout-minutes: ${{ inputs.coverage-report && 120 || inputs.php == '8.4' && 30 || 20 }} permissions: contents: read diff --git a/.github/workflows/slack-notifications.yml b/.github/workflows/slack-notifications.yml index 27bc5bb11eb10..a59b4b6c2e1e9 100644 --- a/.github/workflows/slack-notifications.yml +++ b/.github/workflows/slack-notifications.yml @@ -57,7 +57,7 @@ jobs: checks: read contents: read timeout-minutes: 5 - if: ${{ true }} + if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event.workflow_run.event != 'pull_request' }} outputs: previous_conclusion: ${{ steps.previous-attempt-result.outputs.result }} timed_out: ${{ steps.timeout-check.outputs.result }} @@ -156,8 +156,6 @@ jobs: per_page: 100, } ); - console.log( jobs ); - const cancelledJobs = jobs.filter( ( job ) => job.conclusion === 'cancelled' ); const BATCH_SIZE = 100; @@ -179,8 +177,6 @@ jobs: { ids: batch.map( ( job ) => job.node_id ) } ); - console.log( nodes ); - const timedOut = nodes.some( ( node ) => node && node.annotations.nodes.some( ( annotation ) => /exceeded the maximum execution time/i.test( annotation.message ) ) );