Skip to content

Resolve SideRepoOps safe-outputs base branch from the checked-out target branch#32659

Merged
pelikhan merged 6 commits into
mainfrom
copilot/fix-e003-error-in-non-default-branch
May 16, 2026
Merged

Resolve SideRepoOps safe-outputs base branch from the checked-out target branch#32659
pelikhan merged 6 commits into
mainfrom
copilot/fix-e003-error-in-non-default-branch

Conversation

Copilot AI commented May 16, 2026

Copy link
Copy Markdown
Contributor

Safe outputs were generating create-PR patches against the target repo’s default branch, even when a SideRepoOps workflow had re-anchored the checkout to a non-default release branch. In that case the patch could include all default→release divergence and trigger E003 instead of containing only the agent’s actual change.

  • Base branch resolution

    • Extend safe-outputs base branch resolution to optionally prefer the branch actually checked out in git.
    • Keep existing precedence for explicit overrides and event-derived PR base refs; only fall back to the checked-out branch before repository-default-branch resolution.
  • Side-repo handler behavior

    • Resolve the target repo checkout before computing base_branch in create_pull_request and push_to_pull_request_branch.
    • Use the checked-out target repo branch as the patch baseline when operating in a side repo.
    • Apply the same logic when target-repo is configured, not only when repo is passed in the tool call.
  • Regression coverage

    • Add a side-repo test fixture with:
      • main as default branch
      • release-1.12.x diverged from main
      • one local-only commit on the checked-out release branch
    • Assert the generated patch contains only the local fix, not the pre-existing release-branch divergence.
const baseBranch = await getBaseBranch(repoParts, {
  preferCheckedOutBranch: Boolean(repoCwd),
  cwd: repoCwd || undefined,
});

This keeps safe-outputs aligned with the branch the agent is actually working on, so SideRepoOps PR creation against non-default branches does not require a custom DEFAULT_BRANCH override.

Copilot AI changed the title [WIP] Fix E003 error when creating PR against non-default branch Resolve SideRepoOps safe-outputs base branch from the checked-out target branch May 16, 2026
Copilot AI requested a review from pelikhan May 16, 2026 17:06
Comment thread actions/setup/js/get_base_branch.cjs Outdated
// re-anchors the checkout to a non-default release branch before generating the patch.
if (options?.preferCheckedOutBranch && options.cwd) {
try {
const checkedOutBranch = execSync("git rev-parse --abbrev-ref HEAD", {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@copilot use existing git helpers

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 13875d7 by switching get_base_branch.cjs to the shared execGitSync() helper instead of calling git inline.

Copilot AI requested a review from pelikhan May 16, 2026 17:45
@pelikhan pelikhan marked this pull request as ready for review May 16, 2026 17:46
Copilot AI review requested due to automatic review settings May 16, 2026 17:46
@github-actions github-actions Bot mentioned this pull request May 16, 2026

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

Fixes safe-outputs patch baseline selection for SideRepoOps (and other configured target-repo workflows) so patches are generated against the branch actually checked out in the target repository, instead of always using the target repo’s default branch.

Changes:

  • Extend getBaseBranch() to optionally prefer the checked-out git branch (opt-in via options).
  • Update safe-outputs handlers to resolve the target repo checkout first, then derive base_branch with a preference for the checked-out branch when operating in a side-repo/target-repo checkout.
  • Add a regression test fixture ensuring create-PR patches on a checked-out release branch exclude pre-existing default↔release divergence.
Show a summary per file
File Description
actions/setup/js/safe_outputs_handlers.cjs Resolve repo checkout before base branch selection; prefer checked-out branch for side-repo patch baselines.
actions/setup/js/get_base_branch.cjs Add optional “prefer checked-out branch” resolution step via git when requested.
actions/setup/js/safe_outputs_handlers.test.cjs Add regression test for side-repo release branch patch generation baseline.

Copilot's findings

Tip

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

  • Files reviewed: 3/3 changed files
  • Comments generated: 1

Comment thread actions/setup/js/get_base_branch.cjs Outdated
* 7. Fallback to DEFAULT_BRANCH env var or "main"
*
* @param {{owner: string, repo: string}|null} [targetRepo] - Optional target repository.
* If provided, API calls (steps 4 and 5) use this instead of context.repo,

@github-actions github-actions Bot 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.

Skills-Based Review 🧠

Applied /diagnose and /tdd — this is a targeted bug fix with regression coverage.

Key Themes

  • Root cause properly addressed: The reordering of repoCwd resolution before getBaseBranch in both handlers is the correct fix. The original code resolved the base branch before knowing which directory was checked out, so it could not prefer the checked-out branch even in principle.
  • Test coverage gap: pushToPullRequestBranchHandler received the same base-branch fix but has no corresponding regression test (see inline comment).
  • Test clarity: The test's branch value deliberately equals the resolved base_branch to trigger the git fallback — worth a short clarifying comment (see inline comment).

Positive Highlights

  • ✅ Clean opt-in API: preferCheckedOutBranch / cwd options keep getBaseBranch backward-compatible — callers that don't pass options get the existing behaviour unchanged.
  • Boolean(repoCwd) guard correctly avoids the git lookup when no checkout was found, so the fallback chain still applies in the normal case.
  • ✅ The execGitSync refactor (addressing the existing review thread) is a good use of the shared helper.
  • ✅ Regression test for createPullRequestHandler is thorough: it sets up a realistic diverged repo, asserts base_branch, and verifies the patch contains only the local commit.

Verdict

Minor suggestions only — commenting rather than blocking.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · ● 4.5M

});
});

describe("pushToPullRequestBranchHandler", () => {

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.

[/tdd] pushToPullRequestBranchHandler received the same base-branch fix in this PR but has no parallel regression test. The createPullRequestHandler test added here verifies the new behaviour precisely — a matching test for the push handler would guard against the same class of regression on that code path.

Consider adding a sibling test in the pushToPullRequestBranchHandler describe block that reuses createSideRepoOnReleaseBranchWithLocalCommit and asserts base_branch: "release-1.12.x" in the appended entry.

body: "Prepare release branch fix",
});

expect(result.isError).toBeUndefined();

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.

[/tdd] The test passes branch: "release-1.12.x" which equals the resolved base_branch, triggering the fallback logic that replaces it with the current git branch. That's the correct path to exercise, but the test comment doesn't explain it — a reader might think the branch value is arbitrary. A short inline comment would make the intent explicit:

// branch intentionally equals base_branch to exercise the git-fallback path
branch: "release-1.12.x",

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 92/100

Excellent test quality

Metric Value
New/modified tests analyzed 5
✅ Design tests (behavioral contracts) 5 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 4 (80%)
Duplicate test clusters 0
Test inflation detected No (1.26:1 ratio)
🚨 Coding-guideline violations None

Test Classification Details

View test classification table (5 tests)
Test File Classification Issues Detected
should derive base_branch from the checked out side-repo branch for patch generation safe_outputs_handlers.test.cjs:740 ✅ Design None
should store resolved base_branch in the safe output entry (allow-empty mode) safe_outputs_handlers.test.cjs:680 ✅ Design None
should store GITHUB_BASE_REF as base_branch when no config override (allow-empty mode) safe_outputs_handlers.test.cjs:711 ✅ Design None
should detect branch from defaultTargetRepo checkout when entry.repo is not provided safe_outputs_handlers.test.cjs:888 ✅ Design None
should detect branch from the checked out target repo when repo is provided safe_outputs_handlers.test.cjs:918 ✅ Design None

Key Strengths

should derive base_branch from the checked out side-repo branch for patch generation is the centerpiece of this PR's test additions. It:

  • Creates a real git repo on a non-default (release-1.12.x) branch using execSync — no internal mocking
  • Calls the production handler end-to-end with a target-repo config
  • Asserts the observable output: base_branch: "release-1.12.x" stored in the safe output entry (proving the fix — it used to fall back to the repo default main)
  • Verifies the patch content directly from disk: checks that only the local commit appears ("Subject: [PATCH] local only fix") and the release-tracked commit is excluded
  • This is exactly the regression test needed: deleting it would allow the original E003 bug to reappear undetected

The should detect branch from... tests at lines 888 and 918 complement this by covering the pushToPullRequestBranchHandler path with and without an explicit repo parameter — good conditional coverage.

Minor Observations

  • The 3 tests at lines 680–738 test allow-empty mode with GITHUB_BASE_REF resolution — behavioral contracts, but purely success-path. No error/edge-case assertions within them. This is acceptable given the feature scope.
  • Vitest doesn't require message arguments on expect() calls (unlike testify in Go), so no assertion-message violations apply here.

Flagged Tests — None

No tests require remediation.


Language Support

Tests analyzed:

  • 🐹 Go (*_test.go): 0 tests — no Go test files changed
  • 🟨 JavaScript (*.test.cjs): 5 tests (vitest)

Verdict

Check passed. 0% of new tests are implementation tests (threshold: 30%). All 5 new tests verify behavioral contracts using real git operations, asserting observable outputs rather than internal call sequences.

📖 Understanding Test Classifications

Design Tests (High Value) verify what the system does:

  • Assert on observable outputs, return values, or state changes
  • Cover error paths and boundary conditions
  • Would catch a behavioral regression if deleted
  • Remain valid even after internal refactoring

Implementation Tests (Low Value) verify how the system does it:

  • Assert on internal function calls (mocking internals)
  • Only test the happy path with typical inputs
  • Break during legitimate refactoring even when behavior is correct
  • Give false assurance: they pass even when the system is wrong

Goal: Shift toward tests that describe the system's behavioral contract — the promises it makes to its users and collaborators.

References: §25968749492

🧪 Test quality analysis by Test Quality Sentinel · ● 10.7M ·

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot review all review comments

Copilot AI commented May 16, 2026

Copy link
Copy Markdown
Contributor Author

@copilot review all review comments

Reviewed the remaining review feedback and addressed the outstanding JSDoc mismatch in 35a12d8.

@pelikhan pelikhan merged commit b4e127d into main May 16, 2026
@pelikhan pelikhan deleted the copilot/fix-e003-error-in-non-default-branch branch May 16, 2026 18:06
@github-actions

Copy link
Copy Markdown
Contributor

@copilot review all comments and address the unresolved review feedback.
Please add a regression test for base-branch resolution on the checked-out target branch.

Generated by 👨‍🍳 PR Sous Chef ·

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.

SideRepoOps: creating a PR against a non-default branch generates E003 without a custom DEFAULT_BRANCH override

3 participants