Skip to content

Build/Test Tools: Propagate and retry the local environment commands - #12735

Open
adimoldovan wants to merge 13 commits into
WordPress:trunkfrom
adimoldovan:fix-local-env-discarded-exit-status
Open

Build/Test Tools: Propagate and retry the local environment commands#12735
adimoldovan wants to merge 13 commits into
WordPress:trunkfrom
adimoldovan:fix-local-env-discarded-exit-status

Conversation

@adimoldovan

@adimoldovan adimoldovan commented Jul 28, 2026

Copy link
Copy Markdown

Trac ticket: https://core.trac.wordpress.org/ticket/65745

start.js and docker.js propagate the exit status of the Docker Compose command they run, falling back to 1 when status is null. docker.js treats SIGINT as cancellation rather than failure. start.js stops before composer update -W when the containers did not come up.

compose_with_retry() in utils.js re-attempts a command three times, 10 and 20 seconds apart. It covers docker compose pull and docker compose up, which reach Docker Hub, and composer install and composer update, which reach repo.packagist.org. Every other command runs once, including typecheck:php and typecheck:php:baselines. The loop stops early when the command was killed by a signal or could not be spawned.

ensure_env_file() in utils.js creates .env from .env.example, resolved against the repository root. start.js, docker.js and install.js all call it, so npm run env:pull no longer resolves image tags without it.

Backport

affected branches why
discarded exit status 6.8, 6.9, 7.0, 7.1 6.7 and earlier call execSync, which throws
asynchronous .env copy 6.7, 6.8, 7.0 6.9 and 7.1 already use copyFileSync
no retry all branches with the scripts new behaviour, not a defect

Testing instructions

  1. The exit status of a failed start. Before this change it is 0. After it, 1, after three attempts (~33s).

    LOCAL_PHP=this-tag-does-not-exist node ./tools/local-env/scripts/start.js; echo $?
    
  2. The exit status when Docker cannot be run. Before this change it is 0, reported after 30s of retries. After it, 1, reported immediately.

    env PATH=/var/empty $(which node) ./tools/local-env/scripts/docker.js pull; echo $?
    
  3. The pull retry. Three attempts, 10 and 20 seconds apart, ending with docker compose pull failed after 3 attempts. and exit 1.

    LOCAL_PHP=this-tag-does-not-exist npm run env:pull; echo $?
    
  4. Commands that are not re-attempted run once. The first exits 1 in about a second with no retry message.

    npm run env:composer -- nonexistent-script; echo $?
    npm run env:logs
    

    Ctrl-C ends env:logs and does not restart it.

  5. .env is created before the image tags are resolved. Delete .env, then run the pull and confirm .env exists afterwards. Before this change only npm run env:start created it.

    rm .env && npm run env:pull && ls .env
    
  6. A cold start still works.

    npm run env:stop && docker compose down -v
    npm run env:start && npm run env:install
    

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5
Used for: Investigating the CI failures, writing the patch, and iterative code review. Every behaviour and branch range described above was verified locally.


This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

…commands.

`start.js` runs `docker compose up` through `spawnSync` and never inspects the
result, so a failed pull does not fail the script. Execution continues into
`composer update -W` with containers that may not exist, and the error surfaces
later and in the wrong place.

`docker.js` calls `process.exit( returns.status )`, and `status` is `null` when
Docker cannot be spawned. `process.exit( null )` exits 0, so `npm run env:pull`
reports success when the Docker CLI is missing.

Reproduce with:

    LOCAL_PHP=this-tag-does-not-exist npm run env:start; echo $?

See #65745.
Copilot AI review requested due to automatic review settings July 28, 2026 14:15
@adimoldovan adimoldovan self-assigned this Jul 28, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the local Docker environment helper scripts to correctly propagate failures from spawnSync() so npm commands fail at the correct step (instead of continuing after Docker failures and surfacing errors later).

Changes:

  • Capture and check the result of docker compose up in start.js, exiting non-zero when container startup fails.
  • Avoid exiting 0 when the Docker CLI cannot be spawned in docker.js by handling status === null and reporting a clearer error.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
tools/local-env/scripts/start.js Capture spawnSync() result for docker compose up and exit non-zero on failure to start/pull containers.
tools/local-env/scripts/docker.js Emit an error when Docker cannot be spawned and ensure a non-zero exit code when appropriate.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tools/local-env/scripts/docker.js Outdated
@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

…nment command.

`docker.js` exited 0 for any signal, so a command killed by SIGTERM or SIGKILL reported success. That reintroduced the false success this ticket set out to remove: the retry loop in `reusable-phpunit-tests-v3.yml` branches on the status of `npm run env:pull` and would treat a killed pull as a completed one.

Restrict the exemption to SIGINT, which is how a long-running command such as `env:logs` is normally ended. Report every other signal and exit non-zero.

`start.js` exempts no signal, because `env:start` runs `composer update -W` next and that must not run against containers that never came up. Say so in the comment, so the difference between the two files is deliberate.

Also fold the unreachable `up.error` branch in `start.js` into the failure message. The `docker info` check above it already throws when the Docker CLI is missing or the daemon is down.
Copilot AI review requested due to automatic review settings July 28, 2026 14:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@adimoldovan
adimoldovan marked this pull request as ready for review July 28, 2026 15:30
@adimoldovan
adimoldovan requested a review from lancewillett July 28, 2026 15:30
@github-actions

github-actions Bot commented Jul 28, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props adrianmoldovanwp, lancewillett.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@lancewillett lancewillett left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested with head a88479c

Confirmed failed image pulls and a missing Docker executable exit non-zero. SIGTERM exits non-zero, SIGINT remains clean for interactive commands, and a normal environment start and install > succeeded

The affected code shape was also verified on 6.8, 6.9, and 7.0.

Good to land.

Copilot AI review requested due to automatic review settings July 29, 2026 21:12

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@lancewillett

Copy link
Copy Markdown
Member

This change looks correct, I'd like a 2nd review from a core committer on the backports since that will involve SVN commits to 7.0, 6.9, and 6.8. CC @aaronjorbin @desrosj @johnbillion

Copilot AI review requested due to automatic review settings July 30, 2026 09:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

…egistry.

Moves the retry loop from [63163] into `utils.js` so `start.js` can use it too, and
adds `ensure_env_file()` so every script creates `.env` before Compose reads it.

`docker.js` retries `pull` and any command containing `composer`. `start.js` retries
`docker compose up`.

Folds in the changes from PR WordPress#12736.

See #65745.
@adimoldovan adimoldovan changed the title Build/Test Tools: Propagate the exit status of the local environment commands Build/Test Tools: Propagate and retry the local environment commands Aug 13, 2026
@adimoldovan

Copy link
Copy Markdown
Author

Tested with head a88479c

Confirmed failed image pulls and a missing Docker executable exit non-zero. SIGTERM exits non-zero, SIGINT remains clean for interactive commands, and a normal environment start and install > succeeded

The affected code shape was also verified on 6.8, 6.9, and 7.0.

Good to land.

@lancewillett this needs a new round of review, I just folded #12736 into it.

…mpted.

Stop the retry loop when the command could not be spawned at all. That error fails
the same way every time, so re-attempting it only delays the report by 30 seconds.

Re-attempt `composer install` and `composer update`, rather than every Composer run.
`typecheck:php` and `typecheck:php:baselines` reach no registry, so a PHPStan failure
is a real result and was being reported three times.

See #65745.
Comment thread tools/local-env/scripts/docker.js Outdated
Composer accepts global options before the subcommand, so `env:composer -- -n update`
placed `-n` where the subcommand was expected and lost the retry.

See #65745.
Global options can precede the command, and `--working-dir` takes a separate value, so
searching the arguments matched tokens that were never the command. Both
`env:composer -- --working-dir update validate` and `typecheck:php -- update` were
re-attempted three times despite reaching no registry.

See #65745.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants