From 88418cad256e03bb966d0f5f3d2e595b3eeabb47 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 22:17:28 +0000 Subject: [PATCH 1/3] Initial plan From 81c93c5a2006f1fbd2bdeaa23c286389eec16507 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 22:39:22 +0000 Subject: [PATCH 2/3] fix: use GH_HOST env var instead of --hostname flag for gh repo view and gh pr create The --hostname flag is only valid for `gh api`, not for `gh repo view` or `gh pr create`. This caused failures on GHES/Proxima with: "unknown flag: --hostname" Replace the invalid --hostname flag with the GH_HOST environment variable, which is the correct approach for these commands. Extract the env var setup into a reusable setGHHostEnv helper to avoid duplication. Fixes: gh aw add-wizard --create-pull-request on GHES/Proxima deployments Agent-Logs-Url: https://github.com/github/gh-aw/sessions/9ad4e273-0356-4650-a286-ade3682b979c Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --- pkg/cli/pr_command.go | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/pkg/cli/pr_command.go b/pkg/cli/pr_command.go index de7bdb4d5a5..1d2aa12eaca 100644 --- a/pkg/cli/pr_command.go +++ b/pkg/cli/pr_command.go @@ -771,14 +771,11 @@ func createPR(branchName, title, body string, verbose bool) (int, string, error) // repositories are targeted correctly instead of defaulting to github.com. remoteHost := getHostFromOriginRemote() - // Build gh repo view args, adding --hostname for GHES instances. - repoViewArgs := []string{"repo", "view", "--json", "owner,name"} - if remoteHost != "github.com" { - repoViewArgs = append(repoViewArgs, "--hostname", remoteHost) - } - - // Get the current repository info to ensure PR is created in the correct repo - repoOutput, err := workflow.RunGH("Fetching repository info...", repoViewArgs...) + // Get the current repository info to ensure PR is created in the correct repo. + // Use GH_HOST env var instead of --hostname (which is only valid for gh api, not gh repo view). + repoViewCmd := workflow.ExecGH("repo", "view", "--json", "owner,name") + setGHHostEnv(repoViewCmd, remoteHost) + repoOutput, err := repoViewCmd.Output() if err != nil { return 0, "", fmt.Errorf("failed to get current repository info: %w", err) } @@ -797,14 +794,12 @@ func createPR(branchName, title, body string, verbose bool) (int, string, error) repoSpec := fmt.Sprintf("%s/%s", repoInfo.Owner.Login, repoInfo.Name) // Build gh pr create args. Explicitly specifying --repo ensures the PR is created in the - // current repo (not an upstream fork). For GHES instances, --hostname routes the request - // to the correct GitHub Enterprise host instead of defaulting to github.com. + // current repo (not an upstream fork). Use GH_HOST env var instead of --hostname + // (which is only valid for gh api, not gh pr create). prCreateArgs := []string{"pr", "create", "--repo", repoSpec, "--title", title, "--body", body, "--head", branchName} - if remoteHost != "github.com" { - prCreateArgs = append(prCreateArgs, "--hostname", remoteHost) - } - - output, err := workflow.RunGH("Creating pull request...", prCreateArgs...) + prCreateCmd := workflow.ExecGH(prCreateArgs...) + setGHHostEnv(prCreateCmd, remoteHost) + output, err := prCreateCmd.Output() if err != nil { // Try to get stderr for better error reporting var exitError *exec.ExitError @@ -827,3 +822,18 @@ func createPR(branchName, title, body string, verbose bool) (int, string, error) return prNumber, prURL, nil } + +// setGHHostEnv sets the GH_HOST environment variable on the command for non-github.com hosts. +// This is needed for GitHub Enterprise Server (GHES) and Proxima (data residency) instances +// because commands like `gh repo view` and `gh pr create` do not accept a --hostname flag +// (unlike `gh api` which does). +func setGHHostEnv(cmd *exec.Cmd, host string) { + if host == "github.com" { + return + } + if cmd.Env == nil { + cmd.Env = append(os.Environ(), "GH_HOST="+host) + } else { + cmd.Env = append(cmd.Env, "GH_HOST="+host) + } +} From e463fc935e2b6ac666b3365eae2ae2d2acf3eb9b Mon Sep 17 00:00:00 2001 From: Landon Cox Date: Tue, 14 Apr 2026 16:04:17 -0700 Subject: [PATCH 3/3] fix: replace --hostname with GH_HOST env var for non-api gh commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address review feedback on the original PR: 1. Add RunGHWithHost() and SetGHHostEnv() to pkg/workflow/github_cli.go as shared helpers, preserving spinner UX and enrichGHError wrapping. 2. Fix pr_command.go to use RunGHWithHost() for gh repo view and gh pr create (restores spinner + error enrichment lost in original PR). 3. Fix audit.go:588 — gh run view also does not support --hostname. This was the third affected call site documented in #26310 but missed in the original PR. 4. Remove the local setGHHostEnv() from pr_command.go in favor of the shared exported SetGHHostEnv() in github_cli.go. 5. Add TestSetGHHostEnv with 5 test cases covering github.com no-op, empty host no-op, GHES host, Proxima host, and append-to-existing-env. Fixes #26310 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pkg/cli/audit.go | 12 +++---- pkg/cli/pr_command.go | 23 ++----------- pkg/workflow/github_cli.go | 40 ++++++++++++++++++++++ pkg/workflow/github_cli_test.go | 60 +++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 28 deletions(-) diff --git a/pkg/cli/audit.go b/pkg/cli/audit.go index 9d3d5f19472..8e685b31b55 100644 --- a/pkg/cli/audit.go +++ b/pkg/cli/audit.go @@ -580,14 +580,10 @@ func auditJobRun(runID int64, jobID int64, stepNumber int, owner, repo, hostname return fmt.Errorf("failed to create output directory: %w", err) } - // Fetch job logs using gh CLI + // Fetch job logs using gh CLI. + // Use GH_HOST env var instead of --hostname (which is only valid for gh api, not gh run view). args := []string{"run", "view"} - // Add hostname flag if specified (for GitHub Enterprise) - if hostname != "" && hostname != "github.com" { - args = append(args, "--hostname", hostname) - } - // Add repository flag if specified if owner != "" && repo != "" { args = append(args, "-R", fmt.Sprintf("%s/%s", owner, repo)) @@ -600,7 +596,9 @@ func auditJobRun(runID int64, jobID int64, stepNumber int, owner, repo, hostname fmt.Fprintln(os.Stderr, console.FormatVerboseMessage("Executing: gh "+strings.Join(args, " "))) } - output, err := workflow.RunGHCombined("Fetching job logs...", args...) + cmd := workflow.ExecGH(args...) + workflow.SetGHHostEnv(cmd, hostname) + output, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("failed to fetch job logs: %w\nOutput: %s", err, string(output)) } diff --git a/pkg/cli/pr_command.go b/pkg/cli/pr_command.go index 1d2aa12eaca..e6f1c24fc98 100644 --- a/pkg/cli/pr_command.go +++ b/pkg/cli/pr_command.go @@ -773,9 +773,7 @@ func createPR(branchName, title, body string, verbose bool) (int, string, error) // Get the current repository info to ensure PR is created in the correct repo. // Use GH_HOST env var instead of --hostname (which is only valid for gh api, not gh repo view). - repoViewCmd := workflow.ExecGH("repo", "view", "--json", "owner,name") - setGHHostEnv(repoViewCmd, remoteHost) - repoOutput, err := repoViewCmd.Output() + repoOutput, err := workflow.RunGHWithHost("Fetching repository info...", remoteHost, "repo", "view", "--json", "owner,name") if err != nil { return 0, "", fmt.Errorf("failed to get current repository info: %w", err) } @@ -797,9 +795,7 @@ func createPR(branchName, title, body string, verbose bool) (int, string, error) // current repo (not an upstream fork). Use GH_HOST env var instead of --hostname // (which is only valid for gh api, not gh pr create). prCreateArgs := []string{"pr", "create", "--repo", repoSpec, "--title", title, "--body", body, "--head", branchName} - prCreateCmd := workflow.ExecGH(prCreateArgs...) - setGHHostEnv(prCreateCmd, remoteHost) - output, err := prCreateCmd.Output() + output, err := workflow.RunGHWithHost("Creating pull request...", remoteHost, prCreateArgs...) if err != nil { // Try to get stderr for better error reporting var exitError *exec.ExitError @@ -822,18 +818,3 @@ func createPR(branchName, title, body string, verbose bool) (int, string, error) return prNumber, prURL, nil } - -// setGHHostEnv sets the GH_HOST environment variable on the command for non-github.com hosts. -// This is needed for GitHub Enterprise Server (GHES) and Proxima (data residency) instances -// because commands like `gh repo view` and `gh pr create` do not accept a --hostname flag -// (unlike `gh api` which does). -func setGHHostEnv(cmd *exec.Cmd, host string) { - if host == "github.com" { - return - } - if cmd.Env == nil { - cmd.Env = append(os.Environ(), "GH_HOST="+host) - } else { - cmd.Env = append(cmd.Env, "GH_HOST="+host) - } -} diff --git a/pkg/workflow/github_cli.go b/pkg/workflow/github_cli.go index 51c315cc5af..88c629ba91d 100644 --- a/pkg/workflow/github_cli.go +++ b/pkg/workflow/github_cli.go @@ -184,3 +184,43 @@ func RunGHContext(ctx context.Context, spinnerMessage string, args ...string) ([ func RunGHCombined(spinnerMessage string, args ...string) ([]byte, error) { return runGHWithSpinner(spinnerMessage, true, args...) } + +// RunGHWithHost executes a gh CLI command with a spinner, targeting a specific GitHub host. +// For non-github.com hosts (GHES, Proxima/data residency), the GH_HOST environment variable +// is set on the command. This is necessary because most gh subcommands (repo, pr, run, etc.) +// do not accept a --hostname flag — only `gh api` does. +// +// Usage: +// +// output, err := RunGHWithHost("Fetching repo info...", "myorg.ghe.com", "repo", "view", "--json", "owner,name") +func RunGHWithHost(spinnerMessage string, host string, args ...string) ([]byte, error) { + cmd := ExecGH(args...) + SetGHHostEnv(cmd, host) + + if tty.IsStderrTerminal() { + spinner := console.NewSpinner(spinnerMessage) + spinner.Start() + output, err := cmd.Output() + err = enrichGHError(err) + spinner.Stop() + return output, err + } + + output, err := cmd.Output() + return output, enrichGHError(err) +} + +// SetGHHostEnv sets the GH_HOST environment variable on the command for non-github.com hosts. +// This is needed for GitHub Enterprise Server (GHES) and Proxima (data residency) instances +// because commands like `gh repo view`, `gh pr create`, and `gh run view` do not accept a +// --hostname flag (unlike `gh api` which does). +func SetGHHostEnv(cmd *exec.Cmd, host string) { + if host == "" || host == "github.com" { + return + } + if cmd.Env == nil { + cmd.Env = append(os.Environ(), "GH_HOST="+host) + } else { + cmd.Env = append(cmd.Env, "GH_HOST="+host) + } +} diff --git a/pkg/workflow/github_cli_test.go b/pkg/workflow/github_cli_test.go index 9e47015ee98..89574c3637a 100644 --- a/pkg/workflow/github_cli_test.go +++ b/pkg/workflow/github_cli_test.go @@ -417,3 +417,63 @@ func TestEnrichGHError(t *testing.T) { assert.Contains(t, enriched.Error(), "exit status 1", "enriched error should still contain original error") }) } + +func TestSetGHHostEnv(t *testing.T) { + tests := []struct { + name string + host string + expectSet bool + initialEnv []string + }{ + { + name: "github.com is a no-op", + host: "github.com", + expectSet: false, + }, + { + name: "empty host is a no-op", + host: "", + expectSet: false, + }, + { + name: "GHES host sets GH_HOST", + host: "myorg.ghe.com", + expectSet: true, + }, + { + name: "Proxima host sets GH_HOST", + host: "verizon.ghe.com", + expectSet: true, + }, + { + name: "appends to existing env", + host: "myorg.ghe.com", + expectSet: true, + initialEnv: []string{"FOO=bar"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cmd := exec.Command("echo", "test") + if tt.initialEnv != nil { + cmd.Env = tt.initialEnv + } + + SetGHHostEnv(cmd, tt.host) + + if !tt.expectSet { + if tt.initialEnv == nil { + assert.Nil(t, cmd.Env, "Env should remain nil for %s", tt.host) + } + return + } + + require.NotNil(t, cmd.Env, "Env should be set for host %s", tt.host) + found := slices.ContainsFunc(cmd.Env, func(e string) bool { + return e == "GH_HOST="+tt.host + }) + assert.True(t, found, "GH_HOST=%s should be in cmd.Env", tt.host) + }) + } +}