From 20b9fcc066dccfe04c8dff6c4840c69442e73d62 Mon Sep 17 00:00:00 2001 From: Conduction Release Bot Date: Tue, 11 Aug 2026 15:12:33 +0200 Subject: [PATCH] fix(quality): a required additional app that will not enable must fail the job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `php occ app:enable "$name" || echo "::warning::Failed to enable $name, continuing..."` let a run proceed WITHOUT the dependency the repository under test is built on. The absence then resurfaced as APPLICATION failures, which is indistinguishable from real debt in the log. Measured on ConductionNL/hermiq, full-scope run 31490144919, six PHPUnit cells, perfect 6/6 correlation between `grep -c 'Failed to enable openregister'` and the error count: 93774658402 8.4/stable33 enable ok -> Tests: 1500, Errors: 5, Failures: 1 93774658407 8.3/stable33 enable ok -> Tests: 1500, Errors: 5, Failures: 1 93774658415 8.4/stable32 enable ok -> Tests: 1500, Errors: 5, Failures: 1 93774658413 8.3/stable31 enable FAILED -> Tests: 1500, Errors: 12 93774658418 8.3/stable32 enable FAILED -> Tests: 1500, Errors: 12 93774658420 8.4/stable31 enable FAILED -> Tests: 1500, Errors: 12 The seven extra "errors" were `Interface "OCA\OpenRegister\Service\Flow\ IFlowNodeLogActions" not found` and `Call to undefined method MockObject_ToolRegistryFacade::describeTools()` — an absent app wearing the costume of app debt. Two causes, both deserving a red job: one deterministic (OpenRegister declares min-version="32"; the cell tested stable31) and one transient (`curl error 60 ... self-signed certificate` during composer install left Twig missing, so enabling crashed). Applied to all four install sites (phpunit, newman, and both playwright legs). ⚠️ The failure flag goes through a FILE, not a variable: the loop body runs in a subshell because it is fed by a pipeline, so a variable set inside it is invisible after `done` — the same trap run-hydra-gates.sh documents at its gate-30 loop. Verified with a three-app simulation: exit 0 when all enable, exit 1 when the FIRST fails and exit 1 when the LAST fails. ⚠️ Grep for the failure with the APP NAME (`Failed to enable openregister`). The bare `Failed to enable` also matches the workflow's own echoed script line, which contains `$name` unexpanded — it returns 1 on a clean run and 2 on a failing one, so an off-by-one reads as a correlation that is not there. --- .github/workflows/quality.yml | 144 +++++++++++++++++++++++++++++++++- 1 file changed, 140 insertions(+), 4 deletions(-) diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index f008bdc5..f167909f 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -1730,11 +1730,45 @@ jobs: --admin-user admin \ --admin-pass admin fi + # A REQUIRED additional app that does not enable is an ENVIRONMENT + # failure, and it must not be allowed to resurface as APPLICATION + # failures. It used to: `|| echo "::warning::…, continuing"` let the + # run proceed without the dependency, and the consuming app's tests + # then died on the absent classes. + # + # Measured on ConductionNL/hermiq, full-scope run 31490144919, six + # PHPUnit cells, perfect 6/6 correlation: + # + # enable ok -> Tests: 1500, Errors: 5, Failures: 1 (x3) + # enable FAILED -> Tests: 1500, Errors: 12 (x3) + # + # The seven extra "errors" were `Interface + # "OCA\OpenRegister\Service\Flow\IFlowNodeLogActions" not found` and + # `Call to undefined method MockObject_ToolRegistryFacade:: + # describeTools()` — which read as app debt and were an absent app. + # Two distinct causes, one deterministic (OpenRegister declares + # min-version="32"; the cell was stable31) and one transient + # (`curl error 60 … self-signed certificate` during composer install + # left Twig missing, so enabling crashed). Both deserve a red job: + # the first is a real configuration error, the second is re-runnable. + # + # ⚠️ The failure flag goes through a FILE, not a variable. The loop + # body runs in a subshell (it is fed by a pipeline), so a variable set + # inside it is invisible after `done` — the same trap the gate runner + # documents at its gate-30 loop. if [ '${{ inputs.additional-apps }}' != '[]' ]; then + rm -f "${RUNNER_TEMP:-/tmp}/additional-app-enable-failed" echo '${{ inputs.additional-apps }}' | jq -r '.[].app' | while read -r name; do echo "Enabling app: $name" - php occ app:enable "$name" || echo "::warning::Failed to enable $name, continuing..." + if ! php occ app:enable "$name"; then + echo "::error::Failed to enable required additional app '$name'. This is an ENVIRONMENT failure, not an application failure — the run cannot measure this repository without it. Common causes: the app declares a min-version above the Nextcloud ref this cell tests, or its composer install did not complete." + echo "$name" >> "${RUNNER_TEMP:-/tmp}/additional-app-enable-failed" + fi done + if [ -s "${RUNNER_TEMP:-/tmp}/additional-app-enable-failed" ]; then + echo "::error::Aborting: $(tr '\n' ' ' < "${RUNNER_TEMP:-/tmp}/additional-app-enable-failed")could not be enabled." + exit 1 + fi fi chmod -R a+w config @@ -1999,11 +2033,45 @@ jobs: --admin-user admin \ --admin-pass admin fi + # A REQUIRED additional app that does not enable is an ENVIRONMENT + # failure, and it must not be allowed to resurface as APPLICATION + # failures. It used to: `|| echo "::warning::…, continuing"` let the + # run proceed without the dependency, and the consuming app's tests + # then died on the absent classes. + # + # Measured on ConductionNL/hermiq, full-scope run 31490144919, six + # PHPUnit cells, perfect 6/6 correlation: + # + # enable ok -> Tests: 1500, Errors: 5, Failures: 1 (x3) + # enable FAILED -> Tests: 1500, Errors: 12 (x3) + # + # The seven extra "errors" were `Interface + # "OCA\OpenRegister\Service\Flow\IFlowNodeLogActions" not found` and + # `Call to undefined method MockObject_ToolRegistryFacade:: + # describeTools()` — which read as app debt and were an absent app. + # Two distinct causes, one deterministic (OpenRegister declares + # min-version="32"; the cell was stable31) and one transient + # (`curl error 60 … self-signed certificate` during composer install + # left Twig missing, so enabling crashed). Both deserve a red job: + # the first is a real configuration error, the second is re-runnable. + # + # ⚠️ The failure flag goes through a FILE, not a variable. The loop + # body runs in a subshell (it is fed by a pipeline), so a variable set + # inside it is invisible after `done` — the same trap the gate runner + # documents at its gate-30 loop. if [ '${{ inputs.additional-apps }}' != '[]' ]; then + rm -f "${RUNNER_TEMP:-/tmp}/additional-app-enable-failed" echo '${{ inputs.additional-apps }}' | jq -r '.[].app' | while read -r name; do echo "Enabling app: $name" - php occ app:enable "$name" || echo "::warning::Failed to enable $name, continuing..." + if ! php occ app:enable "$name"; then + echo "::error::Failed to enable required additional app '$name'. This is an ENVIRONMENT failure, not an application failure — the run cannot measure this repository without it. Common causes: the app declares a min-version above the Nextcloud ref this cell tests, or its composer install did not complete." + echo "$name" >> "${RUNNER_TEMP:-/tmp}/additional-app-enable-failed" + fi done + if [ -s "${RUNNER_TEMP:-/tmp}/additional-app-enable-failed" ]; then + echo "::error::Aborting: $(tr '\n' ' ' < "${RUNNER_TEMP:-/tmp}/additional-app-enable-failed")could not be enabled." + exit 1 + fi fi # ── Composer's DOWNLOAD cache, not `vendor/` ────────────────────────── @@ -2370,11 +2438,45 @@ jobs: --admin-user admin \ --admin-pass admin fi + # A REQUIRED additional app that does not enable is an ENVIRONMENT + # failure, and it must not be allowed to resurface as APPLICATION + # failures. It used to: `|| echo "::warning::…, continuing"` let the + # run proceed without the dependency, and the consuming app's tests + # then died on the absent classes. + # + # Measured on ConductionNL/hermiq, full-scope run 31490144919, six + # PHPUnit cells, perfect 6/6 correlation: + # + # enable ok -> Tests: 1500, Errors: 5, Failures: 1 (x3) + # enable FAILED -> Tests: 1500, Errors: 12 (x3) + # + # The seven extra "errors" were `Interface + # "OCA\OpenRegister\Service\Flow\IFlowNodeLogActions" not found` and + # `Call to undefined method MockObject_ToolRegistryFacade:: + # describeTools()` — which read as app debt and were an absent app. + # Two distinct causes, one deterministic (OpenRegister declares + # min-version="32"; the cell was stable31) and one transient + # (`curl error 60 … self-signed certificate` during composer install + # left Twig missing, so enabling crashed). Both deserve a red job: + # the first is a real configuration error, the second is re-runnable. + # + # ⚠️ The failure flag goes through a FILE, not a variable. The loop + # body runs in a subshell (it is fed by a pipeline), so a variable set + # inside it is invisible after `done` — the same trap the gate runner + # documents at its gate-30 loop. if [ '${{ inputs.additional-apps }}' != '[]' ]; then + rm -f "${RUNNER_TEMP:-/tmp}/additional-app-enable-failed" echo '${{ inputs.additional-apps }}' | jq -r '.[].app' | while read -r name; do echo "Enabling app: $name" - php occ app:enable "$name" || echo "::warning::Failed to enable $name, continuing..." + if ! php occ app:enable "$name"; then + echo "::error::Failed to enable required additional app '$name'. This is an ENVIRONMENT failure, not an application failure — the run cannot measure this repository without it. Common causes: the app declares a min-version above the Nextcloud ref this cell tests, or its composer install did not complete." + echo "$name" >> "${RUNNER_TEMP:-/tmp}/additional-app-enable-failed" + fi done + if [ -s "${RUNNER_TEMP:-/tmp}/additional-app-enable-failed" ]; then + echo "::error::Aborting: $(tr '\n' ' ' < "${RUNNER_TEMP:-/tmp}/additional-app-enable-failed")could not be enabled." + exit 1 + fi fi # ── Composer's DOWNLOAD cache, not `vendor/` ────────────────────────── @@ -3477,11 +3579,45 @@ jobs: --admin-user admin \ --admin-pass admin fi + # A REQUIRED additional app that does not enable is an ENVIRONMENT + # failure, and it must not be allowed to resurface as APPLICATION + # failures. It used to: `|| echo "::warning::…, continuing"` let the + # run proceed without the dependency, and the consuming app's tests + # then died on the absent classes. + # + # Measured on ConductionNL/hermiq, full-scope run 31490144919, six + # PHPUnit cells, perfect 6/6 correlation: + # + # enable ok -> Tests: 1500, Errors: 5, Failures: 1 (x3) + # enable FAILED -> Tests: 1500, Errors: 12 (x3) + # + # The seven extra "errors" were `Interface + # "OCA\OpenRegister\Service\Flow\IFlowNodeLogActions" not found` and + # `Call to undefined method MockObject_ToolRegistryFacade:: + # describeTools()` — which read as app debt and were an absent app. + # Two distinct causes, one deterministic (OpenRegister declares + # min-version="32"; the cell was stable31) and one transient + # (`curl error 60 … self-signed certificate` during composer install + # left Twig missing, so enabling crashed). Both deserve a red job: + # the first is a real configuration error, the second is re-runnable. + # + # ⚠️ The failure flag goes through a FILE, not a variable. The loop + # body runs in a subshell (it is fed by a pipeline), so a variable set + # inside it is invisible after `done` — the same trap the gate runner + # documents at its gate-30 loop. if [ '${{ inputs.additional-apps }}' != '[]' ]; then + rm -f "${RUNNER_TEMP:-/tmp}/additional-app-enable-failed" echo '${{ inputs.additional-apps }}' | jq -r '.[].app' | while read -r name; do echo "Enabling app: $name" - php occ app:enable "$name" || echo "::warning::Failed to enable $name, continuing..." + if ! php occ app:enable "$name"; then + echo "::error::Failed to enable required additional app '$name'. This is an ENVIRONMENT failure, not an application failure — the run cannot measure this repository without it. Common causes: the app declares a min-version above the Nextcloud ref this cell tests, or its composer install did not complete." + echo "$name" >> "${RUNNER_TEMP:-/tmp}/additional-app-enable-failed" + fi done + if [ -s "${RUNNER_TEMP:-/tmp}/additional-app-enable-failed" ]; then + echo "::error::Aborting: $(tr '\n' ' ' < "${RUNNER_TEMP:-/tmp}/additional-app-enable-failed")could not be enabled." + exit 1 + fi fi # ── Composer's DOWNLOAD cache, not `vendor/` ──────────────────────────