Skip to content

Verify all destination remotes before pushing artifact#2022

Open
mglaman wants to merge 1 commit into
acquia:mainfrom
mglaman:fix/push-artifact-multi-remote-verify
Open

Verify all destination remotes before pushing artifact#2022
mglaman wants to merge 1 commit into
acquia:mainfrom
mglaman:fix/push-artifact-multi-remote-verify

Conversation

@mglaman

@mglaman mglaman commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

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

  1. Follow the contribution guide to set up your development environment or download a pre-built acli.phar for this PR.
  2. If running from source, clear the kernel cache to pick up new and changed commands: ./bin/acli ckc
  3. Check for regressions: (add specific steps for this pr)
  4. Check new functionality: (add specific steps for this pr)

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>
Copilot AI review requested due to automatic review settings July 15, 2026 14:01
@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.64%. Comparing base (0d9c5db) to head (6b80afe).

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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

Copy link
Copy Markdown

Try the dev build for this PR: https://acquia-cli.s3.amazonaws.com/build/pr/2022/acli.phar

curl -OL https://acquia-cli.s3.amazonaws.com/build/pr/2022/acli.phar
chmod +x acli.phar

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 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.

Comment on lines +219 to +226
$process = $this->localMachineHelper->execute([
'git',
'rev-parse',
'FETCH_HEAD',
], null, $artifactDir, false);
if ($process->isSuccessful() && trim($process->getOutput()) !== '') {
$tips[$vcsUrl] = trim($process->getOutput());
}
Comment on lines +439 to +447
foreach (array_keys($tips) as $vcsUrl) {
$this->localMachineHelper->execute([
'git',
'fetch',
'--deepen=50',
$vcsUrl,
$vcsPath,
], null, $artifactDir, false);
}
Comment on lines +453 to +462
$process = $this->localMachineHelper->execute([
'git',
'merge-base',
'--is-ancestor',
$other,
$candidate,
], null, $artifactDir, false);
if (!$process->isSuccessful()) {
continue 2;
}
Comment on lines +422 to +424
foreach ($vcsUrls as $vcsUrl) {
$tip = $tips[$vcsUrl];
$fetchProcess = $this->mockProcess($tip !== null);
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.

2 participants