feat: add directory-scoped host defaults (match_dirs) and repo list --limit
Some checks are pending
CI / lint (push) Waiting to run
CI / build (push) Waiting to run
CI / test (push) Waiting to run
CI / functional (push) Blocked by required conditions

Add match_dirs field to host config entries for directory-based host
resolution. When no --hostname flag, FGJ_HOST env var, or git remote is
detected, the longest matching directory prefix determines the host.
Symlinks are resolved on both sides for macOS compatibility (/tmp →
/private/tmp). Also adds --limit/-L flag to repo list.
This commit is contained in:
sid 2026-03-23 12:39:51 -06:00
parent 113505de95
commit c293e233d2
17 changed files with 252 additions and 79 deletions

View file

@ -420,7 +420,7 @@ func runRunList(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
@ -469,7 +469,7 @@ func runRunView(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
@ -668,7 +668,7 @@ func runRunWatch(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
@ -718,7 +718,7 @@ func runRunRerun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
@ -749,7 +749,7 @@ func runRunCancel(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
@ -866,7 +866,7 @@ func runWorkflowList(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
@ -939,7 +939,7 @@ func runWorkflowView(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
@ -1000,7 +1000,7 @@ func runWorkflowRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
@ -1077,7 +1077,7 @@ func runWorkflowEnable(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
@ -1122,7 +1122,7 @@ func runWorkflowDisable(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
@ -1206,7 +1206,7 @@ func runActionsSecretList(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
@ -1241,7 +1241,7 @@ func runActionsSecretCreate(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
@ -1282,7 +1282,7 @@ func runActionsSecretDelete(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
@ -1318,7 +1318,7 @@ func runActionsVariableList(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
@ -1359,7 +1359,7 @@ func runActionsVariableGet(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
@ -1387,7 +1387,7 @@ func runActionsVariableCreate(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
@ -1416,7 +1416,7 @@ func runActionsVariableUpdate(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
@ -1445,7 +1445,7 @@ func runActionsVariableDelete(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to load config: %w", err)
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}

View file

@ -72,7 +72,7 @@ func runAPI(cmd *cobra.Command, args []string) error {
detectedHost := getDetectedHost()
host, err := cfg.GetHost(hostname, detectedHost)
host, err := cfg.GetHost(hostname, detectedHost, getCwd())
if err != nil {
return err
}

View file

@ -203,7 +203,7 @@ func runIssueList(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -275,7 +275,7 @@ func runIssueView(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -375,7 +375,7 @@ func runIssueCreate(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -464,7 +464,7 @@ func runIssueComment(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -503,7 +503,7 @@ func runIssueClose(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -564,7 +564,7 @@ func runIssueEdit(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -687,7 +687,7 @@ func runIssueDelete(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -732,7 +732,7 @@ func runIssueReopen(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}

View file

@ -116,7 +116,7 @@ func newLabelClient(cmd *cobra.Command) (*api.Client, string, string, error) {
return nil, "", "", err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return nil, "", "", err
}

View file

@ -183,7 +183,7 @@ func runMilestoneList(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -249,7 +249,7 @@ func runMilestoneView(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -264,7 +264,7 @@ func runMilestoneView(cmd *cobra.Command, args []string) error {
if web, _ := cmd.Flags().GetBool("web"); web {
// Milestones don't have HTMLURL in the API, construct it
cfg2, _ := config.Load()
host, _ := cfg2.GetHost("", getDetectedHost())
host, _ := cfg2.GetHost("", getDetectedHost(), getCwd())
url := fmt.Sprintf("https://%s/%s/%s/milestone/%d", host.Hostname, owner, name, ms.ID)
return ios.OpenInBrowser(url)
}
@ -315,7 +315,7 @@ func runMilestoneCreate(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -363,7 +363,7 @@ func runMilestoneEdit(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -450,7 +450,7 @@ func runMilestoneDelete(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}

View file

@ -228,7 +228,7 @@ func runPRList(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -367,7 +367,7 @@ func runPRView(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -500,7 +500,7 @@ func runPRCreate(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -611,7 +611,7 @@ func runPRMerge(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -678,7 +678,7 @@ func runPRClose(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -727,7 +727,7 @@ func runPRReopen(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -766,7 +766,7 @@ func runPRCheckout(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -886,7 +886,7 @@ func runPREdit(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}

View file

@ -46,7 +46,7 @@ func runPRChecks(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}

View file

@ -58,7 +58,7 @@ func runPRDiff(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}

View file

@ -121,7 +121,7 @@ func runPRComment(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -191,7 +191,7 @@ func runPRReview(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}

View file

@ -180,7 +180,7 @@ func runReleaseList(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -251,7 +251,7 @@ func runReleaseView(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -363,7 +363,7 @@ func runReleaseCreate(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -420,7 +420,7 @@ func runReleaseUpload(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -460,7 +460,7 @@ func runReleaseDownload(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -547,7 +547,7 @@ func runReleaseDelete(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}

View file

@ -125,6 +125,7 @@ func init() {
repoViewCmd.Flags().BoolP("web", "w", false, "Open in web browser")
addJSONFlags(repoListCmd, "Output repositories as JSON")
repoListCmd.Flags().IntP("limit", "L", 0, "Maximum number of repositories to list (0 = no limit)")
repoCloneCmd.Flags().StringP("protocol", "p", "https", "Clone protocol: https or ssh")
@ -158,7 +159,7 @@ func runRepoView(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -203,7 +204,7 @@ func runRepoList(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -221,6 +222,11 @@ func runRepoList(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to list repositories: %w", err)
}
limit, _ := cmd.Flags().GetInt("limit")
if limit > 0 && len(repos) > limit {
repos = repos[:limit]
}
if wantJSON(cmd) {
return outputJSON(cmd, repos)
}
@ -257,7 +263,7 @@ func runRepoClone(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -324,7 +330,7 @@ func runRepoFork(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -371,7 +377,7 @@ func runRepoCreate(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -439,7 +445,7 @@ func runRepoCreate(cmd *cobra.Command, args []string) error {
if doClone {
cloneURL := repo.CloneURL
if hostCfg, hostErr := cfg.GetHost("", getDetectedHost()); hostErr == nil {
if hostCfg, hostErr := cfg.GetHost("", getDetectedHost(), getCwd()); hostErr == nil {
if hostCfg.GitProtocol == "ssh" {
cloneURL = repo.SSHURL
}
@ -494,7 +500,7 @@ func runRepoEdit(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}
@ -591,7 +597,7 @@ func runRepoRename(cmd *cobra.Command, args []string) error {
return err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return err
}

View file

@ -96,6 +96,15 @@ func getDetectedHost() string {
return host
}
// getCwd returns the current working directory, or "" on error.
func getCwd() string {
cwd, err := os.Getwd()
if err != nil {
return ""
}
return cwd
}
// promptLine prints a prompt to stderr and reads a line from stdin.
func promptLine(prompt string) (string, error) {
fmt.Fprint(ios.ErrOut, prompt)

View file

@ -185,7 +185,7 @@ func newWikiClient(cmd *cobra.Command) (*api.Client, string, string, error) {
return nil, "", "", err
}
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
if err != nil {
return nil, "", "", err
}