Skip to content

Base full-mode patch/bundle on GITHUB_SHA when running from a non-default branch - #52164

Merged
pelikhan merged 6 commits into
mainfrom
copilot/bugfix-workflow-dispatch-patch
Aug 12, 2026
Merged

Base full-mode patch/bundle on GITHUB_SHA when running from a non-default branch#52164
pelikhan merged 6 commits into
mainfrom
copilot/bugfix-workflow-dispatch-patch

Conversation

Copilot AI commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

When a workflow runs from a ref that is not contained in the default branch (e.g. workflow_dispatch on a feature branch), generate_git_patch based the transport artifact on merge-base(defaultBranch, agentBranch). The patch then spanned the entire dispatched branch instead of the agent's commits, and on a partial clone it failed outright — diffing from that older base required base-side blobs that were never fetched, so git attempted a lazy promisor fetch which is unauthenticated (persist-credentials: false).

[generate_git_patch] Strategy 1 (full): Computed merge-base: <old-sha>
[generate_git_patch] Strategy 1: Found 13 commits between <old-sha> and <head-sha>   # agent made 1
[generate_git_patch] Strategy 1: Branch 'agent-fix/example' does not exist locally - ERR_SYSTEM: remote: Invalid username or token.

Both symptoms are invisible on a default-branch run, where merge-base == GITHUB_SHA.

Changes

  • generate_git_patch.cjs (full mode) — before falling back to the merge-base, prefer GITHUB_SHA as the base when it is an ancestor of the agent branch tip but not contained in the default branch. That is precisely the non-default-ref dispatch case; the patch then holds only the agent's commits and requires no objects beyond the checkout commit's tree, which also removes the partial-clone failure. Default-branch runs take the unchanged merge-base path.
  • generate_git_bundle.cjs — same base selection in its full-mode merge-base path. create_pull_request defaults to patch_format: bundle, so the bundle step would otherwise reproduce the failure immediately after the patch step.
  • Branch-existence reporting — existence is checked with git rev-parse --verify --quiet refs/heads/<branch> (local refs only), and the Strategy 1 failure path re-checks local refs before wording its message, so a network/auth failure is no longer reported as Branch 'X' does not exist locally. The incremental-mode error is likewise split by whether the branch actually exists.
  • Partial-clone diagnosticdescribeGitFailure appends an explanation when a git failure looks like a failed lazy hydration and remote.origin.promisor=true, since gh-aw knows it emitted persist-credentials: false.
  • git_patch_utils.cjs — new shared isAncestorCommit, isPartialClone, describeGitFailure helpers used by both generators.
  • Tests — integration coverage for a non-default-branch dispatch (patch contains only the agent commit, baseCommit === GITHUB_SHA), the default-branch regression case (still merge-base, all agent commits included), and the bundle equivalent.

run: https://github.com/github/gh-aw/actions/runs/31547117706> Generated by 👨‍🍳 PR Sous Chef · gpt54 · 7.19 AIC · ⌖ 5.2 AIC · ⊞ 8.5K ·

Comment /souschef to run again

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix git patch generation for non-default branch workflow_dispatch Base full-mode patch/bundle on GITHUB_SHA when running from a non-default branch Aug 11, 2026
Copilot AI requested a review from pelikhan August 11, 2026 23:12
@pelikhan
pelikhan marked this pull request as ready for review August 11, 2026 23:21
Copilot AI balanced review requested due to automatic review settings August 11, 2026 23:21
@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR does not have the 'implementation' label and has ≤100 new lines of code in business logic directories (0 additions detected in default business logic paths).

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • api.individual.githubcopilot.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "api.individual.githubcopilot.com"

See Network Configuration for more information.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Ponytail Reviewer completed successfully!

Generated by Ponytail Reviewer for #52164

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

🧪 Test quality analysis by Test Quality Sentinel

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

Review: Base full-mode patch/bundle on GITHUB_SHA when running from a non-default branch

The logic is correct and well-tested. The new conditional correctly handles the non-default-branch dispatch scenario:

  • GITHUB_SHA is used as base only when it is an ancestor of the agent branch and not contained in the default branch — preventing regressions for normal (default-branch) runs.
  • Falls back to the existing merge-base path in all other cases.
  • Diagnostic improvements (describeGitFailure, isPartialClone) are clearly scoped and do not affect the happy path.
  • The switch from show-ref to rev-parse for local-branch existence checks is strictly better: both are local-only, but rev-parse --verify exits with a predictable non-zero code when the ref is absent.
  • Three new integration tests cover the feature and the fallback.

No blocking issues found.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 23.2 AIC · ⌖ 6.27 AIC · ⊞ 5.4K

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

Generated by ✂️ Ponytail Reviewer for #52164 · auto · 20 AIC · ⌖ 5.71 AIC · ⊞ 6.8K
Comment /ponytail to run again

Comments that could not be inline-anchored

actions/setup/js/generate_git_bundle.cjs:43

shrink: dispatched-branch base-selection block (compute dispatchedSha + isAncestorCommit check) duplicated verbatim in generate_git_patch.cjs L98-101. Extract a shared selectFullModeBaseRef(githubSha, tipRef, defaultBranchRef, cwd) helper in git_patch_utils.cjs, 1 caller each.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 90/100 — Excellent

Analyzed 3 test(s): 3 design, 0 implementation, 0 violation(s).

📊 Metrics (3 tests)
Metric Value
Analyzed 3 (Go: 0, JS: 3)
✅ Design 3 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 2 (67%)
Duplicate clusters 0
Inflation No (test:prod ≈ 0.95:1)
🚨 Violations 0
Test File Classification Issues
should base the full-mode patch on GITHUB_SHA when dispatched from a non-default branch git_patch_integration.test.cjs behavioral_contract · high_value · design_test
should still use the merge-base in full mode when GITHUB_SHA is on the default branch git_patch_integration.test.cjs behavioral_contract · high_value · design_test
should base the full-mode bundle on GITHUB_SHA when dispatched from a non-default branch git_patch_integration.test.cjs behavioral_contract · high_value · design_test ⚠️ Minor: no assertion on bundle content (only baseCommit verified)
🔍 Per-test notes

Test 1 — patch on non-default branch GITHUB_SHA
Sets up a dispatch branch ahead of main, creates an agent branch on top, and sets GITHUB_SHA to the dispatch SHA. Asserts result.baseCommit === dispatchedSha, that the patch contains the agent commit, and does not contain the dispatch branch commits — the negative assertions are the strongest signal in this PR. behavioral_contract, high_value.

Test 2 — merge-base fallback when GITHUB_SHA is on default branch
Sets GITHUB_SHA to the current main SHA and verifies both agent commits appear in the patch. This is the complementary invariant: the fix does not break the default-branch case. behavioral_contract, high_value.

Test 3 — bundle on non-default branch GITHUB_SHA
Mirrors test 1 for generateGitBundle. Verifies result.success and result.baseCommit. The test is correct and meaningful, but asserting bundle content (e.g. that the bundle references the expected commit range) would make it stronger. Minor gap only — not flagged as a violation.

Verdict

Passed. 0% implementation tests (threshold: 30%). No violations. Score: 90/100.

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 · 40.7 AIC · ⌖ 6.88 AIC · ⊞ 7.6K ·
Comment /review to run again

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

✅ Test Quality Sentinel: 90/100. 0% implementation tests (threshold: 30%).

@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 /diagnosing-bugs and /tdd — commenting with a few targeted suggestions; no blocking issues.

📋 Key Themes & Highlights

Key Themes

  • Regex over-breadth: "could not fetch" in describeGitFailure is wide enough to annotate unrelated network errors with the partial-clone explanation.
  • Missing no-commit edge case: The GITHUB_SHA base-selection guard does not prevent an empty patch when GITHUB_SHA === tipRef (agent branch tip, no commits yet).
  • Test coverage is solid — three well-structured integration tests cover the fix and the regression path. Minor: the regression test could benefit from an explicit commit-count assertion.

Positive Highlights

  • ✅ Root cause correctly identified and fixed symmetrically in both patch and bundle generators
  • ✅ The GITHUB_SHA not-on-default-branch guard is precise and leaves default-branch runs untouched
  • ✅ Improved diagnostics for auth failures on partial clones are a genuine UX win
  • ✅ Shared helpers in git_patch_utils.cjs follow the existing module pattern cleanly
  • ✅ Changeset entry is clear and accurate

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 42.5 AIC · ⌖ 6.92 AIC · ⊞ 7K
Comment /matt to run again

function describeGitFailure(message, cwd) {
if (!/promisor|Authentication failed|Invalid username or token|could not fetch/i.test(message)) {
return message;
}

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.

[/diagnosing-bugs] The "could not fetch" pattern in describeGitFailure is broad and may decorate unrelated network errors with a partial-clone explanation.

💡 Suggestion

"could not fetch" can appear in many git error messages unrelated to lazy object hydration. Since isPartialClone is already checked, the string pattern only needs to match the lazy-fetch indicators. Consider narrowing to promisor-specific strings:

if (!/promisor|Authentication failed|Invalid username or token|fetch-pack|object not found/i.test(message)) {

This prevents misleading diagnostics for ordinary network failures in partial-clone repos.

@copilot please address this.

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.

Narrowed the regex to promisor-specific indicators (promisor|Authentication failed|Invalid username or token|fetch-pack|object not found), dropping the broad could not fetch match. Fixed in bccc136.

Comment thread actions/setup/js/generate_git_patch.cjs Outdated
// and fails). GITHUB_SHA is the commit the agent started from and every
// object it needs is already present in the checkout.
const dispatchedSha = normalizeCommitSHA(githubSha);
if (defaultBranchRef && dispatchedSha && isAncestorCommit(dispatchedSha, tipRef, cwd) && !isAncestorCommit(dispatchedSha, defaultBranchRef, cwd)) {

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.

[/diagnosing-bugs] The GITHUB_SHA base selection condition runs two isAncestorCommit calls (each spawning git merge-base --is-ancestor) even in the common default-branch case where both will succeed quickly. More importantly, if GITHUB_SHA equals the agent branch tip (no commits added yet), the condition is still true and will produce an empty patch.

💡 Suggested guard

Add a check that dispatchedSha is not identical to tipRef to ensure there is at least one agent commit in the patch:

if (defaultBranchRef && dispatchedSha && dispatchedSha !== tipRef &&
    isAncestorCommit(dispatchedSha, tipRef, cwd) &&
    !isAncestorCommit(dispatchedSha, defaultBranchRef, cwd)) {

This also avoids silently producing a zero-commit patch when the agent branch was created but no commits were made yet.

@copilot please address this.

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.

Added dispatchedSha !== tipRef to the guard in both generate_git_patch.cjs and generate_git_bundle.cjs so the GITHUB_SHA base is never selected when there are zero agent commits. Fixed in bccc136.

expect(result.success).toBe(true);
expect(result.baseCommit).toBe(dispatchedSha);

const patchContent = fs.readFileSync(result.patchPath, "utf8");

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 default-branch regression test checks that result.baseCommit === mainSha, but mainSha was captured before the agent branch was created — if main advances between these two points (e.g. in a parallel test), the assertion could fail spuriously. More critically, the test does not assert that the patch content contains both "Agent commit one" and "Agent commit two" — only two expect calls on patchContent are present. This gap means a regressed single-commit path would still pass.

💡 Suggested addition
expect(patchContent).toContain("Agent commit one");
expect(patchContent).toContain("Agent commit two");

Both lines are actually already there — just confirming they cover the full agent commit range. Pair this with a count check if the full-mode invariant matters:

const logLines = execGit(["log", "--oneline", `${mainSha}..HEAD`], { cwd: workingRepo }).stdout.trim().split("
");
expect(logLines).toHaveLength(2);

@copilot please address this.

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.

Added a commit-count assertion (git log --oneline mainSha..HEAD has length 2) to the regression test. Fixed in bccc136.

function isAncestorCommit(ancestor, descendant, cwd) {
try {
execGitSync(["merge-base", "--is-ancestor", "--", ancestor, descendant], { cwd, suppressLogs: true });
return true;

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.

[/codebase-design] isAncestorCommit silently returns false on any git failure, including unexpected ones like a corrupt object store. This is the right behaviour for the caller decision, but consider adding a suppressLogs: true comment note or an explicit debugLog path for non-expected failures so future diagnostics are not silently swallowed.

💡 Optional improvement
function isAncestorCommit(ancestor, descendant, cwd) {
  try {
    execGitSync(["merge-base", "--is-ancestor", "--", ancestor, descendant], { cwd, suppressLogs: true });
    return true;
  } catch (err) {
    // treat all failures (unknown revision, missing object, etc.) as "not an ancestor"
    return false;
  }
}

The comment captures the intent; callers who need richer diagnostics can call describeGitFailure on the caught error separately.

@copilot please address this.

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.

Added a doc-comment note clarifying that failures are intentionally suppressed here and that callers needing richer diagnostics should call describeGitFailure on their own caught error. Fixed in bccc136.

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

Updates full-mode patch and bundle generation to use the workflow’s starting commit for non-default-branch runs.

Changes:

  • Selects GITHUB_SHA as the transport base when appropriate.
  • Improves branch and partial-clone diagnostics.
  • Adds integration coverage and release notes.
Show a summary per file
File Description
.changeset/patch-fix-non-default-branch-patch-base.md Documents the fix.
actions/setup/js/git_patch_utils.cjs Adds ancestry and diagnostic helpers.
actions/setup/js/generate_git_patch.cjs Updates patch base selection and errors.
actions/setup/js/generate_git_bundle.cjs Updates bundle base selection.
actions/setup/js/git_patch_integration.test.cjs Tests default and non-default branch behavior.

Review details

Tip

Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 5/5 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment on lines +221 to +223
if (hasLocalDefaultBranch && dispatchedSha && isAncestorCommit(dispatchedSha, branchName, cwd) && !isAncestorCommit(dispatchedSha, `origin/${defaultBranch}`, cwd)) {
baseRef = dispatchedSha;
debugLog(`Strategy 1 (full): GITHUB_SHA ${dispatchedSha} is not contained in origin/${defaultBranch} (non-default-branch run); using it as the bundle base instead of the merge-base`);
Comment on lines +265 to +270
function describeGitFailure(message, cwd) {
if (!/promisor|Authentication failed|Invalid username or token|could not fetch/i.test(message)) {
return message;
}
if (!isPartialClone(cwd)) {
return message;
…verage

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

🤖 Triage: PR #52164

  • Category: bug | Risk: high | Score: 71/100
  • Breakdown: impact 35, urgency 22, quality 14
  • Recommended action: fast_track
  • CI: no check runs found (unknown) — verify before merge. Fixes patch/bundle basing on GITHUB_SHA for non-default-branch dispatch; touches Actions workflow internals (474/-11, 6 files) — critical-path change warranting expedited human review rather than auto-merge.

Generated by 🔧 PR Triage Agent · auto · 44.5 AIC · ⌖ 2.66 AIC · ⊞ 7.8K ·

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot merge main recompile
Add git integration test

…ow-dispatch-patch

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

@copilot merge main recompile
Add git integration test

Merged main into the branch and ran make recompile (no .md workflow changes needed regeneration). The non-default-branch integration test coverage for both generate_git_patch and generate_git_bundle was already added in git_patch_integration.test.cjs in a previous commit on this branch (GITHUB_SHA-based patch, merge-base fallback when no agent commits yet, and default-branch regression). All 116 targeted JS tests pass in commit f79401e.

@pelikhan
pelikhan merged commit 11047e3 into main Aug 12, 2026
9 checks passed
@pelikhan
pelikhan deleted the copilot/bugfix-workflow-dispatch-patch branch August 12, 2026 01:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: on a non-default-branch workflow_dispatch, generate_git_patch bases the patch on the default branch instead of GITHUB_SHA

4 participants