feat(trail): require explicit branch/selector when --repo is set · Entire

feat(trail): require explicit branch/selector when --repo is set

f713c2f·

toothbrush·3w ago·5 files·+53 added/-1 removed

With --repo targeting a repo other than the local clone, the branch-defaulting commands (show, update, delete, watch, finding) fell back to the local checkout's current branch, which could silently resolve the wrong trail when a branch name is shared. Require an explicit --branch or trail selector alongside --repo and fail clearly otherwise.

Also restores a //nolint:ireturn directive in agentimport.go that a prior local mise run lint --fix pass had stripped (CI lints without --fix).

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

Sessions

53294056bf83View transcript

Changes

5

69 unmodified lines

// Get returns the importer registered under name.
//
//nolint:ireturn // Importer is the intended polymorphic seam returned to callers.
func Get(name string) (Importer, bool) {
    for _, imp := range importers {
        if imp.Name() == name {

Mcmd/entire/cli/agentimport/agentimport.go+1/-1

107 unmodified lines

return nil
}

// ensureTrailRepoHasTarget requires an explicit branch or trail selector when
// --repo targets a repository other than the local clone. Without one, the
// branch-defaulting commands fall back to the local checkout's current branch,
// which would silently resolve the wrong trail (a shared branch name) in the
// overridden repo. hint names the acceptable targets for the command.
func ensureTrailRepoHasTarget(cmd *cobra.Command, hasTarget bool, hint string) error {
    if trailRepoFlag(cmd) != "" && !hasTarget {
        return fmt.Errorf("--repo requires an explicit target: %s", hint)
    }
    return nil
}

// trailListOptions are the inputs to runTrailListAll. Keeping them on a
// struct avoids a long positional argument list at the two call sites.
type trailListOptions struct {

}

// --repo must not silently fall back to the local checkout's branch: the
// branch-defaulting commands require an explicit branch or selector alongside it.
func TestTrailRepoRequiresExplicitTarget(t *testing.T) {
    t.Parallel()
    tests := []struct {
        name string
        args []string
    }{
        {name: "show", args: []string{"show", "--repo", "gh/acme/app"}},
        {name: "watch", args: []string{"watch", "--repo", "gh/acme/app"}},
        {name: "update", args: []string{"update", "--repo", "gh/acme/app"}},
        {name: "delete", args: []string{"delete", "--repo", "gh/acme/app"}},
        {name: "finding list", args: []string{"finding", "list", "--repo", "gh/acme/app"}},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            t.Parallel()
            err := execTrailCmdExpectErr(t, tt.args...)
            if err == nil || !strings.Contains(err.Error(), "--repo requires an explicit target") {
                    t.Fatalf("err = %v, want '--repo requires an explicit target'", err)
            }
        })
    }
}

// Sanity: the persistent --repo flag is registered on the trail root and shows
// up in help, so every read subcommand inherits it.
func TestTrailRepoFlagRegisteredOnRoot(t *testing.T) {

}