Commit 02c44e7d9ae for woocommerce

commit 02c44e7d9aef7611a887774fde5378de323f0658
Author: Adrian Moldovan <3854374+adimoldovan@users.noreply.github.com>
Date:   Fri Jul 10 15:31:57 2026 +0300

    Retry wp-env start in CI to survive transient network timeouts (#66491)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 474d8059bcc..f937b605996 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -201,7 +201,35 @@ jobs:
       - name: 'Start Test Environment: start'
         id: 'prepare-test-environment'
         if: ${{ matrix.testEnv.shouldCreate }}
-        run: pnpm --filter="${{ matrix.projectName }}" ${{ matrix.testEnv.start }}
+        # `wp-env start` fails on transient network timeouts from several subsystems:
+        # composer fetching packagist inside the Docker build ("curl error 28"), wp-env's
+        # own `got` client downloading WordPress core ("ETIMEDOUT"), and the Docker daemon
+        # pulling images from Docker Hub ("context deadline exceeded"). Retry the whole
+        # start to ride out those blips -- BuildKit reuses layers that already succeeded,
+        # so a retry only re-runs whatever failed. Each retried attempt emits a
+        # "::warning::wp-env-start-retry reason=<subsystem>" marker (grep-friendly) so the
+        # underlying incident rate stays measurable even when the retry keeps the job green.
+        run: |
+          attempt=1
+          max_attempts=3
+          log="$(mktemp)"
+          trap 'rm -f "$log"' EXIT
+          until pnpm --filter="${{ matrix.projectName }}" ${{ matrix.testEnv.start }} 2>&1 | tee "$log"; do
+            # We retry regardless of cause -- transient failures aren't limited to the
+            # patterns below, so reason= is for monitoring only, not a retry gate.
+            if grep -qF 'curl error 28' "$log"; then reason=packagist
+            elif grep -qE 'registry-1\.docker\.io|context deadline exceeded' "$log"; then reason=dockerhub
+            elif grep -qF 'ETIMEDOUT' "$log"; then reason=wordpress
+            else reason=unknown
+            fi
+            if [ "$attempt" -ge "$max_attempts" ]; then
+              echo "::error::wp-env start failed after ${max_attempts} attempts (last reason=${reason})"
+              exit 1
+            fi
+            echo "::warning::wp-env-start-retry reason=${reason} attempt=${attempt}/${max_attempts} -- retrying in $((attempt * 15))s"
+            sleep "$((attempt * 15))"
+            attempt=$((attempt + 1))
+          done

       - name: 'Resolve artifacts path'
         if: ${{ always() && matrix.report.resultsPath != '' }}