Verify all destination remotes before pushing artifact#2022
Conversation
push:artifact only cloned and fetched from the first destination git URL, then pushed to the rest blind. Because every run generates a fresh commit SHA, any drift between destinations (branch left over on one remote, concurrent builds, a partial push failure) made later pushes fail with a non-fast-forward rejection that only a force push could clear. This hit PR/build branches constantly while main survived because merges serialize its pushes. Now the branch tip is fetched from every destination before the artifact is built. If tips differ but are ancestor-related, the build bases on the most advanced tip so every remote can fast-forward. If tips have truly diverged, the command aborts with an error naming each remote and its tip before anything is built. A push failure on one remote no longer skips the remaining remotes, which was how the drift started in the first place. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2022 +/- ##
============================================
+ Coverage 92.49% 92.64% +0.14%
- Complexity 1991 2004 +13
============================================
Files 123 123
Lines 7232 7283 +51
============================================
+ Hits 6689 6747 +58
+ Misses 543 536 -7 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Try the dev build for this PR: https://acquia-cli.s3.amazonaws.com/build/pr/2022/acli.phar |
There was a problem hiding this comment.
Pull request overview
This PR improves push:artifact reliability when pushing to multiple destination Git remotes by verifying the destination branch tips across all remotes before building, selecting an appropriate base tip when remotes are ancestor-related, and aborting early when remotes have truly diverged.
Changes:
- Fetch destination branch tips from every configured remote and select a base tip that allows fast-forward pushes to all remotes (or abort if diverged).
- Continue pushing to remaining remotes even if one push fails, and report all push failures together.
- Add PHPUnit coverage for diverged remotes, missing branches, behind remotes, new branches, and partial push failures.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
src/Command/Push/PushArtifactCommand.php |
Fetch and compare tips across all destination remotes before building; choose a base tip; aggregate push failures. |
tests/phpunit/src/Commands/Push/PushArtifactCommandTest.php |
Adds/extends tests and mocking helpers to cover multi-remote tip verification and partial push failure behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| $process = $this->localMachineHelper->execute([ | ||
| 'git', | ||
| 'rev-parse', | ||
| 'FETCH_HEAD', | ||
| ], null, $artifactDir, false); | ||
| if ($process->isSuccessful() && trim($process->getOutput()) !== '') { | ||
| $tips[$vcsUrl] = trim($process->getOutput()); | ||
| } |
| foreach (array_keys($tips) as $vcsUrl) { | ||
| $this->localMachineHelper->execute([ | ||
| 'git', | ||
| 'fetch', | ||
| '--deepen=50', | ||
| $vcsUrl, | ||
| $vcsPath, | ||
| ], null, $artifactDir, false); | ||
| } |
| $process = $this->localMachineHelper->execute([ | ||
| 'git', | ||
| 'merge-base', | ||
| '--is-ancestor', | ||
| $other, | ||
| $candidate, | ||
| ], null, $artifactDir, false); | ||
| if (!$process->isSuccessful()) { | ||
| continue 2; | ||
| } |
| foreach ($vcsUrls as $vcsUrl) { | ||
| $tip = $tips[$vcsUrl]; | ||
| $fetchProcess = $this->mockProcess($tip !== null); |
push:artifact only cloned and fetched from the first destination git URL, then pushed to the rest blind. Because every run generates a fresh commit SHA, any drift between destinations (branch left over on one remote, concurrent builds, a partial push failure) made later pushes fail with a non-fast-forward rejection that only a force push could clear. This hit PR/build branches constantly while main survived because merges serialize its pushes.
Now the branch tip is fetched from every destination before the artifact is built. If tips differ but are ancestor-related, the build bases on the most advanced tip so every remote can fast-forward. If tips have truly diverged, the command aborts with an error naming each remote and its tip before anything is built. A push failure on one remote no longer skips the remaining remotes, which was how the drift started in the first place.
Motivation
Fixes #NNN
Proposed changes
Alternatives considered
Testing steps
./bin/acli ckc