Skip to content

Honor GH_HOST in gh aw trial --clone-repo repository URLs#41159

Open
Copilot wants to merge 6 commits into
mainfrom
copilot/fix-gh-aw-clone-repo-issue
Open

Honor GH_HOST in gh aw trial --clone-repo repository URLs#41159
Copilot wants to merge 6 commits into
mainfrom
copilot/fix-gh-aw-clone-repo-issue

Conversation

Copilot AI commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

gh aw trial --clone-repo was deriving clone and display URLs from github.com unconditionally, which broke GHES trials even when gh was authenticated to the enterprise host. Fully-qualified GHES clone URLs were also normalized back to owner/repo and then rebuilt against the wrong host.

  • Use the active GitHub host for all trial repository URLs

    • Centralized trial-mode URL construction on getGitHubHost()
    • Applied it to:
      • host repository clone URLs
      • source repository clone URLs for --clone-repo
      • host remote URLs used for force-push
      • displayed host repository URLs
      • Actions settings links shown during setup
  • Keep clone-mode behavior consistent on GHES

    • --clone-repo owner/repo now resolves against the configured GitHub host instead of hard-coding github.com
    • fully-qualified GHES repo specs continue to parse to owner/repo, but trial clone/push operations now rebuild URLs against the active host instead of public GitHub
  • Add focused GHES coverage

    • Added tests for host-aware trial repository URL generation
    • Added repo-spec coverage for GHES URLs in clone mode

Example of the resolved behavior:

GH_HOST=example.ghe.com gh aw trial .github/workflows/my-workflow.md \
  --host-repo myorg/gh-aw-trial \
  --clone-repo myorg/source-repo \
  --yes

Trial clone/push URLs now resolve as:

https://example.ghe.com/myorg/source-repo.git
https://example.ghe.com/myorg/gh-aw-trial.git

pr-sous-chef: requested branch update from run https://github.com/github/gh-aw/actions/runs/28079516670

Generated by 👨‍🍳 PR Sous Chef · 43.4 AIC · ⌖ 1.14 AIC · ⊞ 17.4K ·


pr-sous-chef: update branch requested from workflow run 28095175203

Generated by 👨‍🍳 PR Sous Chef · 59 AIC · ⌖ 1.05 AIC · ⊞ 17.6K ·

Copilot AI and others added 2 commits June 24, 2026 05:02
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix gh aw trial --clone-repo to use GH_HOST for GitHub Enterprise Server Honor GH_HOST in gh aw trial --clone-repo repository URLs Jun 24, 2026
Copilot AI requested a review from pelikhan June 24, 2026 05:06
@pelikhan pelikhan marked this pull request as ready for review June 24, 2026 05:55
Copilot AI review requested due to automatic review settings June 24, 2026 05:55
@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

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 gh aw trial --clone-repo to construct all displayed and git remote/clone URLs using the active GitHub host (via getGitHubHost()), fixing GitHub Enterprise Server (GHES) scenarios where URLs were previously hard-coded to github.com.

Changes:

  • Centralized trial-mode URL construction into helper functions (trialRepositoryURL, trialRepositoryGitURL, trialRepositoryActionsSettingsURL) and applied them across trial host creation messaging and clone/push operations.
  • Updated clone-mode (--clone-repo) to build clone and host-remote URLs against the configured GitHub host.
  • Added focused unit coverage for host-aware trial URL helpers and GHES URL parsing in clone-mode tests.
Show a summary per file
File Description
pkg/cli/trial_repository.go Introduces host-aware URL helpers and replaces hard-coded github.com URLs for trial display, clone, and push remotes.
pkg/cli/trial_repository_test.go Adds unit tests verifying URL helper behavior across default host, GH_HOST, and GITHUB_SERVER_URL precedence.
pkg/cli/trial_command_test.go Extends repo-spec parsing coverage to include GHES URL forms when GH_HOST is configured.

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: 0

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (>100 new lines in pkg/cli/) but does not have a linked Architecture Decision Record (ADR).

📄 Draft ADR committed: docs/adr/41159-honor-gh-host-in-trial-repository-urls.md — review and complete it before merging.

🔒 This PR cannot merge until an ADR is linked in the PR body.

📋 What to do next
  1. Review the draft ADR committed to your branch — it was generated from the PR diff (the decision to centralize trial-mode URL construction on getGitHubHost()).
  2. Complete the missing sections — confirm the decision rationale, refine the alternatives (e.g. inlining vs. threading the host as a parameter), and add any context the AI couldn't infer.
  3. Commit the finalized ADR to docs/adr/ on your branch.
  4. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-41159: Honor the active GitHub host for trial repository URLs

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

❓ Why ADRs Matter

"AI made me procrastinate on key design decisions. Because refactoring was cheap, I could always say 'I'll deal with this later.' Deferring decisions corroded my ability to think clearly."

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 0042-use-postgresql.md for PR #42).

🔒 This PR cannot merge until an ADR is linked in the PR body.

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · 91.3 AIC · ⌖ 10.4 AIC · ⊞ 11.6K ·

@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 /tdd, /diagnose, and /zoom-out — no blocking issues; 4 targeted observations.

📋 Key Themes & Highlights

Key Themes

  • Test struct dead fields (trial_repository_test.go): enterpriseHost and githubHost are declared but never populated, so GITHUB_ENTERPRISE_HOST (priority 2) and GITHUB_HOST (priority 3) remain untested. Either add cases or remove the fields.
  • Missing negative test (trial_command_test.go): The new GHES happy-path case has no companion "GHES URL without GH_HOST set → error" test.
  • Regression coverage gap (trial_repository.go:564): The actual bug call sites are validated only transitively through the helper tests; a lightweight test stubbing RunGitCombined would fully close the loop.
  • Intentional behavior change (trialRepositoryURL): getGitHubHost() rather than getGitHubHostForRepo() is used for the clone-source URL — this silently changes behavior for github/, githubnext/, microsoft/ repos on GHES. Likely correct for trial mode, but worth a brief comment.

Positive Highlights

  • ✅ Clean centralization of URL construction into three well-named helpers — easy to audit and change in one place
  • ✅ Diff is tightly scoped; no unrelated changes
  • GITHUB_SERVER_URL vs GH_HOST precedence is tested, covering the GitHub Actions runtime case
  • ✅ PR description is thorough with a concrete before/after example

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 80.5 AIC · ⌖ 8.2 AIC · ⊞ 6.5K

expectedGitURL: "https://server.ghe.com/owner/repo.git",
expectedActionsURL: "https://server.ghe.com/owner/repo/settings/actions",
},
}

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] enterpriseHost and githubHost fields are declared but never populated in any test case — GITHUB_ENTERPRISE_HOST (priority 2) and GITHUB_HOST (priority 3) are both silently untested.

Since getGitHubHost() checks env vars in order (GITHUB_SERVER_URLGITHUB_ENTERPRISE_HOSTGITHUB_HOSTGH_HOST), the precedence of the two middle vars isn't verified.

💡 Suggested additions or cleanup

Either add test cases:

{
    name:           "GITHUB_ENTERPRISE_HOST used when no GITHUB_SERVER_URL",
    enterpriseHost: "enterprise.ghe.com",
    repoSlug:       "owner/repo",
    expectedRepoURL: "(enterprise.ghe.com/redacted),
    expectedGitURL:  "(enterprise.ghe.com/redacted),
    expectedActionsURL: "(enterprise.ghe.com/redacted),
},

Or remove the unused enterpriseHost and githubHost struct fields to avoid misleading future contributors.

expectedVersion: "v2.1.0",
shouldError: false,
description: "Should parse GHES URL with tag when GH_HOST is configured",
},

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 new case covers the happy path (GHES URL + GH_HOST set), but there's no companion test for the error path: a GHES URL passed when GH_HOST is not configured should fail gracefully.

Without GH_HOST, getGitHubHost() returns https://github.com, so parseRepoSpec("(example.ghe.com/redacted) will hit the else` branch and return an error about unexpected URL format. A test documenting this behaviour makes the contract explicit.

💡 Suggested error-path test case
{
    name:          "GHES URL without GH_HOST set returns error",
    cloneRepoSpec: "(example.ghe.com/redacted),
    ghHost:        "",
    shouldError:   true,
    description:   "GHES URL is rejected when GH_HOST is not configured",
},

var checkoutActionPattern = regexp.MustCompile(`^(\s*)(uses: actions/checkout@[^\s]*)(.*)$`)

func trialRepositoryURL(repoSlug string) string {
return fmt.Sprintf("%s/%s", getGitHubHost(), repoSlug)

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.

[/zoom-out] trialRepositoryURL calls getGitHubHost() unconditionally, which is correct for the host repository. It's also used in cloneRepoContentsIntoHost for the source clone URL (line ~564).

Before this PR, all URLs were hardcoded to github.com. After this PR, --clone-repo github/some-public-repo on a GHES instance will attempt to clone from https://<ghes-host>/github/some-public-repo.git — whereas getGitHubHostForRepo() would fall back to https://github.com for the github, githubnext, and microsoft orgs.

This is likely intentional for trial mode (where both repos are on the same host), but worth a brief comment so future readers understand the choice isn't accidental.


// Clone the source repository
cloneURL := fmt.Sprintf("https://github.com/%s.git", cloneRepoSlug)
cloneURL := trialRepositoryGitURL(cloneRepoSlug)

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.

[/diagnose] This is one of the two call sites where the bug actually manifested (the other is line ~585), but there's no test that exercises cloneRepoContentsIntoHost with a GHES host and verifies the clone URL used. The new tests in trial_repository_test.go validate the URL helpers in isolation — a missing integration-style test here means a future regression at this call site would not be caught until runtime.

💡 Approach

Even a lightweight table-driven test that stubs workflow.RunGitCombined and asserts the URL argument contains the expected GHES host would close this gap. Alternatively, document explicitly in a comment that the helper tests are considered sufficient coverage.

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

Non-blocking observation

The core fix is correct: // properly centralise host resolution through getGitHubHost(), and all hard-coded https://github.com strings in the trial flow are replaced consistently. Using getGitHubHost() (not getGitHubHostForRepo) is intentional and right here — trial repos always live on the configured host, unlike canonical workflow-source repos.

One testing gap noted inline: the new TestTrialRepositoryURLHelpers file declares struct fields for GITHUB_ENTERPRISE_HOST and GITHUB_HOST but has no test cases that actually set them, leaving two of the four priority tiers untested.

🔎 Code quality review by PR Code Quality Reviewer · 90.4 AIC · ⌖ 7.09 AIC · ⊞ 5.2K

Comment on lines +11 to +12
enterpriseHost string
githubHost string

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.

Dead test fields: enterpriseHost and githubHost are declared in the struct but never populated in any test case, so GITHUB_ENTERPRISE_HOST and GITHUB_HOST are never exercised — the two middle tiers of GetGitHubHost()'s priority chain are untested.

💡 Suggested additions

GetGitHubHost() resolves four env vars in priority order:

GITHUB_SERVER_URL → GITHUB_ENTERPRISE_HOST → GITHUB_HOST → GH_HOST

This test file covers the highest-priority (GITHUB_SERVER_URL) and lowest-priority (GH_HOST) vars only. A regression — accidentally swapping GITHUB_ENTERPRISE_HOST and GITHUB_HOST in the priority slice, or dropping one — would go completely undetected.

Add at least two more cases:

{
    name:               "uses GITHUB_ENTERPRISE_HOST",
    enterpriseHost:     "enterprise.ghe.com",
    repoSlug:           "owner/repo",
    expectedRepoURL:    "(enterprise.ghe.com/redacted),
    expectedGitURL:     "(enterprise.ghe.com/redacted),
    expectedActionsURL: "(enterprise.ghe.com/redacted),
},
{
    name:               "GITHUB_ENTERPRISE_HOST beats GH_HOST",
    enterpriseHost:     "enterprise.ghe.com",
    ghHost:             "other.ghe.com",
    repoSlug:           "owner/repo",
    expectedRepoURL:    "(enterprise.ghe.com/redacted),
    expectedGitURL:     "(enterprise.ghe.com/redacted),
    expectedActionsURL: "(enterprise.ghe.com/redacted),
},

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 90/100 — Excellent

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

📊 Metrics & Test Classification (2 tests analyzed)
Metric Value
New/modified tests analyzed 2
✅ Design tests (behavioral contracts) 2 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 2 (100%)
Duplicate test clusters 0
Test inflation detected YES — trial_repository_test.go +63 lines vs trial_repository.go +21 lines (3:1, threshold 2:1)
🚨 Coding-guideline violations 0
Test File Classification Issues Detected
TestTrialRepositoryURLHelpers pkg/cli/trial_repository_test.go:7 ✅ Design Test inflation (see below)
TestCloneRepoWithVersion (modified) pkg/cli/trial_command_test.go:95 ✅ Design

Go: 2 (*_test.go); JavaScript: 0. Other languages detected but not scored.

i️ Flagged: Test Inflation (1 notice)

TestTrialRepositoryURLHelpers (pkg/cli/trial_repository_test.go:7) — i️ Test inflation: 63 lines added in the test file vs 21 in trial_repository.go (3:1 ratio, threshold 2:1).

Context: This is a justified, benign inflation. The 21 production lines introduce 3 new helper functions (trialRepositoryURL, trialRepositoryGitURL, trialRepositoryActionsSettingsURL), and the test exhaustively covers all three with 3 table-driven cases each (defaults, GH_HOST override, GITHUB_SERVER_URL precedence). No action required.

Verdict

Check passed. 0% implementation tests (threshold: 30%). Both tests verify observable URL-construction behavior (the behavioral contract exposed by GH_HOST / GITHUB_SERVER_URL environment handling), not internal implementation details.

References: §28078386190

🧪 Test quality analysis by Test Quality Sentinel · 142.5 AIC · ⌖ 12.9 AIC · ⊞ 8.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.

✅ Test Quality Sentinel: 90/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%). Both tests verify observable behavioral contracts for GH_HOST / GITHUB_SERVER_URL URL-construction. No coding-guideline violations detected.

@github-actions

Copy link
Copy Markdown
Contributor

@copilot please add the remaining GH_HOST and GITHUB_ENTERPRISE_HOST test coverage, then refresh checks.

Generated by 👨‍🍳 PR Sous Chef · 43.4 AIC · ⌖ 1.14 AIC · ⊞ 17.4K ·

@github-actions

Copy link
Copy Markdown
Contributor

@copilot please add the remaining GH_HOST and GITHUB_ENTERPRISE_HOST test coverage, then refresh checks.

Generated by 👨‍🍳 PR Sous Chef · 65 AIC · ⌖ 1.06 AIC · ⊞ 17.6K ·

@github-actions

Copy link
Copy Markdown
Contributor

pr-sous-chef

@copilot review all comments and address unresolved review feedback. Please summarize the remaining blockers and refresh checks after that.

Generated by 👨‍🍳 PR Sous Chef · 59 AIC · ⌖ 1.05 AIC · ⊞ 17.6K ·

@github-actions

Copy link
Copy Markdown
Contributor

@copilot please refresh checks after addressing review feedback and summarize any remaining blockers.

Generated by 👨‍🍳 PR Sous Chef · 59 AIC · ⌖ 1.05 AIC · ⊞ 17.6K ·

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