inspect: include a trail link in the post-to-trail confirmation · Entire

Inspect: Include a Trail Link in the Post-to-Trail Confirmation

fb0f37f→main

dipree·1mo ago·2 files·+84 added/-0 removed

When a run posts its verdict to the trail, print a browser link in addition to the existing confirmation, e.g.:
Posted the review verdict to trail #466 as a finding.
View the trail: https://entire.io/gh/entireio/cli/trails/466/review-profiles

trailWebURL builds ////trails// from the resolved trail target, matching the server's web layout and honoring ENTIRE_API_BASE_URL; it returns empty (link omitted) when the target lacks a trail number/forge/owner/repo. Local output and the failure path ('Could not post the review to the trail: ...') already confirm the outcome. Adds trailWebURL tests.

Sessions

74c4f7c8f5a9View transcript

?\ Checkout the hand off doc that I just added.Pi·Opus 4.8·2 steps

Changes

2

66 unmodified lines

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

66 unmodified lines

} else {
            fmt.Fprintln(out, "Posted the review verdict to the trail as a finding.")
        }
        if link := trailWebURL(target); link != "" {
            fmt.Fprintf(out, "View the trail: %s\n", link)
        }
        return nil
    })
}

// trailWebURL builds the browser URL for a trail, matching the server's
// `<base>/<forge>/<owner>/<repo>/trails/<number>/<branch>` layout (the web UI
// shares the API origin). Returns "" when the target lacks the parts needed for
// a stable link.
func trailWebURL(target trailReviewTarget) string {
    if target.Trail.Number <= 0 || target.Host == "" || target.Owner == "" || target.Repo == "" {
        return ""
    }
    base := strings.TrimRight(api.BaseURL(), "/")
    return fmt.Sprintf("%s/%s/%s/%s/trails/%d/%s",
        base, target.Host, target.Owner, target.Repo, target.Trail.Number, target.Trail.Branch)
}

// launchableReviewerFor returns the AgentReviewer for agents with a review-runner
// adapter, or nil for agents that are known to Entire but not yet wired into
// `entire review` fan-out. This lives in the cli package to avoid the import cycle:

Mcmd/entire/cli/review_bridge.go+16


package cli

import (
    "testing"

"github.com/entireio/cli/cmd/entire/cli/api"
)

func TestTrailWebURL(t *testing.T) {
    t.Setenv(api.BaseURLEnvVar, "https://entire.io")

cases := []struct {
        name   string
        target trailReviewTarget
        want   string
    }{
        {
        name: "full target",
        target: trailReviewTarget{
            Host:  "gh",
            Owner: "entireio",
            Repo:  "cli",
            Trail: api.TrailResource{Number: 466, Branch: "review-profiles"},
        },
        want: "https://entire.io/gh/entireio/cli/trails/466/review-profiles",
        },
        {
        name: "no trail number yields no link",
        target: trailReviewTarget{
            Host:  "gh",
            Owner: "entireio",
            Repo:  "cli",
            Trail: api.TrailResource{Branch: "review-profiles"},
        },
        want: "",
        },
        {
        name: "missing forge yields no link",
        target: trailReviewTarget{
            Owner: "entireio",
            Repo:  "cli",
            Trail: api.TrailResource{Number: 1, Branch: "main"},
        },
        want: "",
        },
    }
    for _, c := range cases {
        t.Run(c.name, func(t *testing.T) {
            if got := trailWebURL(c.target); got != c.want {
                t.Errorf("trailWebURL() = %q, want %q", got, c.want)
            }
        })
    }
}

func TestTrailWebURL_HonorsCustomBase(t *testing.T) {
    t.Setenv(api.BaseURLEnvVar, "https://entire.example.com/")
    target := trailReviewTarget{
        Host:  "gh",
        Owner: "acme",
        Repo:  "app",
        Trail: api.TrailResource{Number: 7, Branch: "feat/x"},
    }
    want := "https://entire.example.com/gh/acme/app/trails/7/feat/x"
    if got := trailWebURL(target); got != want {
        t.Errorf("trailWebURL() = %q, want %q", got, want)
    }
}
}

Acmd/entire/cli/review_bridge_test.go+68