fix: fuzzy schedule scattering works with non-origin remote names#24390
fix: fuzzy schedule scattering works with non-origin remote names#24390
origin remote names#24390Conversation
The fuzzy schedule scattering previously required a remote named 'origin' to determine the repository context. This commit adds a smarter fallback: 1. First tries the 'origin' remote for backward compatibility 2. If 'origin' is not configured but exactly one other remote exists, that remote is used automatically 3. If multiple remotes exist without 'origin', falls through to the existing warning behavior Adds a new `resolveRemoteURL(dir)` helper function that encapsulates this logic, and updates `getRepositorySlugFromRemote()`, `getRepositorySlugFromRemoteForPath()`, and `getHostFromOriginRemote()` to use it. Fixes: fuzzy schedule scattering without repository context warning when using non-'origin' remote names. Agent-Logs-Url: https://github.com/github/gh-aw/sessions/b2039ff1-76de-419b-9155-60b3110faf4b Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
origin remote names
|
@copilot Add a compile command CLI argument |
Allows users to override the repository slug used as the seed for fuzzy schedule scattering, bypassing git remote detection entirely. This is useful when no 'origin' remote is configured and multiple remotes exist (where automatic detection is ambiguous). Usage: gh aw compile --schedule-seed owner/repo The value is validated to be in 'owner/repo' format; an invalid value emits a warning and falls back to automatic detection. Agent-Logs-Url: https://github.com/github/gh-aw/sessions/301bc69e-22a6-4499-8a41-de8b59db9c50 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Added in commit |
There was a problem hiding this comment.
Pull request overview
Fixes fuzzy schedule scattering’s repository-context detection when a repo lacks an origin remote, and adds an explicit CLI override to control the scattering seed.
Changes:
- Added
resolveRemoteURL(dir)to preferorigin, otherwise use a single configured non-originremote, otherwise error on ambiguity. - Updated git-remote consumers to use
resolveRemoteURL(host detection and repo slug extraction). - Added
--schedule-seed owner/repoflag wiring to override the schedule scattering seed and bypass git remote detection.
Show a summary per file
| File | Description |
|---|---|
pkg/cli/git.go |
Introduces resolveRemoteURL and updates host/slug detection to support non-origin remotes. |
pkg/cli/git_test.go |
Adds test coverage for resolveRemoteURL and non-origin/multi-remote behaviors. |
pkg/cli/compile_config.go |
Adds ScheduleSeed to compilation config to support explicit seed overrides. |
pkg/cli/compile_compiler_setup.go |
Implements --schedule-seed validation + repository slug override behavior. |
cmd/gh-aw/main.go |
Plumbs the new --schedule-seed flag into CompileConfig. |
pkg/agentdrain/data/default_weights.json |
Reformats JSON arrays (no functional behavior change). |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 6/6 changed files
- Comments generated: 5
| // Validate owner/repo format: must contain exactly one '/' with non-empty parts | ||
| parts := strings.SplitN(config.ScheduleSeed, "/", 2) | ||
| if len(parts) != 2 || parts[0] == "" || parts[1] == "" { | ||
| compileCompilerSetupLog.Printf("Invalid --schedule-seed value %q: expected 'owner/repo' format", config.ScheduleSeed) | ||
| fmt.Fprintln(os.Stderr, console.FormatWarningMessage( | ||
| fmt.Sprintf("--schedule-seed %q is not in 'owner/repo' format; ignoring and falling back to git remote detection", config.ScheduleSeed), | ||
| )) | ||
| } else { | ||
| compiler.SetRepositorySlug(config.ScheduleSeed) | ||
| compileCompilerSetupLog.Printf("Repository slug overridden via --schedule-seed: %s", config.ScheduleSeed) |
There was a problem hiding this comment.
--schedule-seed validation does not enforce the documented “exactly one '/'” requirement. Using strings.SplitN(seed, "/", 2) allows values like owner/repo/extra to be treated as valid and used as the repository slug, which can lead to unexpected scattering seeds. Consider validating with strings.Count(seed, "/") == 1 (or splitting on all '/' and requiring exactly 2 non-empty parts) and optionally trimming surrounding whitespace before validation.
| // Validate owner/repo format: must contain exactly one '/' with non-empty parts | |
| parts := strings.SplitN(config.ScheduleSeed, "/", 2) | |
| if len(parts) != 2 || parts[0] == "" || parts[1] == "" { | |
| compileCompilerSetupLog.Printf("Invalid --schedule-seed value %q: expected 'owner/repo' format", config.ScheduleSeed) | |
| fmt.Fprintln(os.Stderr, console.FormatWarningMessage( | |
| fmt.Sprintf("--schedule-seed %q is not in 'owner/repo' format; ignoring and falling back to git remote detection", config.ScheduleSeed), | |
| )) | |
| } else { | |
| compiler.SetRepositorySlug(config.ScheduleSeed) | |
| compileCompilerSetupLog.Printf("Repository slug overridden via --schedule-seed: %s", config.ScheduleSeed) | |
| seed := strings.TrimSpace(config.ScheduleSeed) | |
| // Validate owner/repo format: must contain exactly one '/' with non-empty parts | |
| parts := strings.Split(seed, "/") | |
| if strings.Count(seed, "/") != 1 || len(parts) != 2 || parts[0] == "" || parts[1] == "" { | |
| compileCompilerSetupLog.Printf("Invalid --schedule-seed value %q: expected 'owner/repo' format", config.ScheduleSeed) | |
| fmt.Fprintln(os.Stderr, console.FormatWarningMessage( | |
| fmt.Sprintf("--schedule-seed %q is not in 'owner/repo' format; ignoring and falling back to git remote detection", config.ScheduleSeed), | |
| )) | |
| } else { | |
| compiler.SetRepositorySlug(seed) | |
| compileCompilerSetupLog.Printf("Repository slug overridden via --schedule-seed: %s", seed) |
| // First try 'origin' for backward compatibility | ||
| if output, err := gitArgs("config", "--get", "remote.origin.url").Output(); err == nil { | ||
| url := strings.TrimSpace(string(output)) | ||
| if url != "" { | ||
| gitLog.Print("Using 'origin' remote") | ||
| return url, "origin", nil | ||
| } | ||
| } |
There was a problem hiding this comment.
git config --get remote.<name>.url can return multiple lines when multiple URLs are configured for a remote. In that case strings.TrimSpace(string(output)) will contain embedded newlines, causing parseGitHubRepoSlugFromURL / extractHostFromRemoteURL to fail. Consider using --get-urlmatch/--get-all handling explicitly and selecting the first URL line (or erroring with a clear message) before returning from resolveRemoteURL.
| return "", "", fmt.Errorf("failed to get URL for remote %q: %w", remoteName, err) | ||
| } | ||
|
|
||
| url := strings.TrimSpace(string(urlOutput)) |
There was a problem hiding this comment.
When falling back to the single configured remote, resolveRemoteURL returns success even if the resolved URL is empty (it doesn’t perform the non-empty check that the origin branch does). This can silently propagate an empty remote URL to callers. Consider validating url != "" here and returning an error if the remote has no URL configured.
| url := strings.TrimSpace(string(urlOutput)) | |
| url := strings.TrimSpace(string(urlOutput)) | |
| if url == "" { | |
| return "", "", fmt.Errorf("remote %q has no URL configured", remoteName) | |
| } |
| // getHostFromOriginRemote returns the hostname of the git remote. | ||
| // It prefers the 'origin' remote for backward compatibility. If 'origin' is not | ||
| // configured but exactly one other remote exists, that remote is used instead. | ||
| // For example, a remote URL of "https://ghes.example.com/org/repo.git" returns "ghes.example.com", | ||
| // and "git@github.com:owner/repo.git" returns "github.com". | ||
| // Returns "github.com" as the default if the remote URL cannot be determined. | ||
| func getHostFromOriginRemote() string { | ||
| cmd := exec.Command("git", "config", "--get", "remote.origin.url") | ||
| output, err := cmd.Output() | ||
| remoteURL, remoteName, err := resolveRemoteURL("") |
There was a problem hiding this comment.
getHostFromOriginRemote now falls back to a non-origin remote when origin is absent, so the function name is no longer accurate. If this is an internal API, consider renaming to something like getHostFromRemote and keeping getHostFromOriginRemote as a thin backward-compatible wrapper (or update call sites to the new name) to avoid future confusion.
| // If a schedule seed is explicitly provided, use it directly | ||
| if config.ScheduleSeed != "" { | ||
| // Validate owner/repo format: must contain exactly one '/' with non-empty parts | ||
| parts := strings.SplitN(config.ScheduleSeed, "/", 2) | ||
| if len(parts) != 2 || parts[0] == "" || parts[1] == "" { | ||
| compileCompilerSetupLog.Printf("Invalid --schedule-seed value %q: expected 'owner/repo' format", config.ScheduleSeed) | ||
| fmt.Fprintln(os.Stderr, console.FormatWarningMessage( | ||
| fmt.Sprintf("--schedule-seed %q is not in 'owner/repo' format; ignoring and falling back to git remote detection", config.ScheduleSeed), | ||
| )) | ||
| } else { | ||
| compiler.SetRepositorySlug(config.ScheduleSeed) | ||
| compileCompilerSetupLog.Printf("Repository slug overridden via --schedule-seed: %s", config.ScheduleSeed) | ||
| return | ||
| } |
There was a problem hiding this comment.
New --schedule-seed behavior in setupRepositoryContext isn’t covered by tests yet. Since schedule scattering behavior depends on Compiler.repositorySlug, consider adding unit tests that (1) a valid seed sets the repository slug and bypasses git detection, and (2) an invalid seed emits a warning and falls back to remote-based detection.
|
Thanks!! |
Fuzzy schedule scattering silently fell back to a context-free (and collision-prone) seed when the repo had no remote named
origin, even if a perfectly usable remote was configured under a different name.Changes
New
resolveRemoteURL(dir string)helper — encapsulates remote resolution with priority:originremote (backward compatible)originremotes → existing warning behavior preserved)Updated consumers to use the new helper:
getRepositorySlugFromRemote()— used for schedule scattering seedgetRepositorySlugFromRemoteForPath()— used during per-file compilationgetHostFromOriginRemote()— used for GHES host detectionNew
--schedule-seed owner/repoflag ongh aw compile— explicitly overrides the repository slug used as the fuzzy schedule scattering seed, bypassing all git remote detection. Useful when multiple remotes exist with noorigin. Invalid values (not inowner/repoformat) emit a warning and fall back to automatic detection.Behavior
originexistsoriginoriginoriginremote (e.g.myorg)myorgorigin--schedule-seedoriginpresentoriginorigin--schedule-seed owner/repoprovided