Merge pull request #11704 from cli/babakks/add-web-flag-to-view-cmd
`gh agent-task view`: add `--web` flag
This commit is contained in:
commit
20c89043bb
7 changed files with 401 additions and 67 deletions
|
|
@ -21,7 +21,7 @@ type CapiClient interface {
|
|||
GetJob(ctx context.Context, owner, repo, jobID string) (*Job, error)
|
||||
GetSession(ctx context.Context, id string) (*Session, error)
|
||||
ListSessionsByResourceID(ctx context.Context, resourceType string, resourceID int64, limit int) ([]*Session, error)
|
||||
GetPullRequestDatabaseID(ctx context.Context, hostname string, owner string, repo string, number int) (int64, error)
|
||||
GetPullRequestDatabaseID(ctx context.Context, hostname string, owner string, repo string, number int) (int64, string, error)
|
||||
}
|
||||
|
||||
// CAPIClient is a client for interacting with the Copilot API
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ var _ CapiClient = &CapiClientMock{}
|
|||
// GetJobFunc: func(ctx context.Context, owner string, repo string, jobID string) (*Job, error) {
|
||||
// panic("mock out the GetJob method")
|
||||
// },
|
||||
// GetPullRequestDatabaseIDFunc: func(ctx context.Context, hostname string, owner string, repo string, number int) (int64, error) {
|
||||
// GetPullRequestDatabaseIDFunc: func(ctx context.Context, hostname string, owner string, repo string, number int) (int64, string, error) {
|
||||
// panic("mock out the GetPullRequestDatabaseID method")
|
||||
// },
|
||||
// GetSessionFunc: func(ctx context.Context, id string) (*Session, error) {
|
||||
|
|
@ -53,7 +53,7 @@ type CapiClientMock struct {
|
|||
GetJobFunc func(ctx context.Context, owner string, repo string, jobID string) (*Job, error)
|
||||
|
||||
// GetPullRequestDatabaseIDFunc mocks the GetPullRequestDatabaseID method.
|
||||
GetPullRequestDatabaseIDFunc func(ctx context.Context, hostname string, owner string, repo string, number int) (int64, error)
|
||||
GetPullRequestDatabaseIDFunc func(ctx context.Context, hostname string, owner string, repo string, number int) (int64, string, error)
|
||||
|
||||
// GetSessionFunc mocks the GetSession method.
|
||||
GetSessionFunc func(ctx context.Context, id string) (*Session, error)
|
||||
|
|
@ -245,7 +245,7 @@ func (mock *CapiClientMock) GetJobCalls() []struct {
|
|||
}
|
||||
|
||||
// GetPullRequestDatabaseID calls GetPullRequestDatabaseIDFunc.
|
||||
func (mock *CapiClientMock) GetPullRequestDatabaseID(ctx context.Context, hostname string, owner string, repo string, number int) (int64, error) {
|
||||
func (mock *CapiClientMock) GetPullRequestDatabaseID(ctx context.Context, hostname string, owner string, repo string, number int) (int64, string, error) {
|
||||
if mock.GetPullRequestDatabaseIDFunc == nil {
|
||||
panic("CapiClientMock.GetPullRequestDatabaseIDFunc: method is nil but CapiClient.GetPullRequestDatabaseID was just called")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import (
|
|||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
const AgentsHomeURL = "https://github.com/copilot/agents"
|
||||
|
||||
var defaultSessionsPerPage = 50
|
||||
|
||||
var ErrSessionNotFound = errors.New("not found")
|
||||
|
|
@ -378,12 +380,13 @@ func (c *CAPIClient) hydrateSessionPullRequestsAndUsers(sessions []session) ([]*
|
|||
return newSessions, nil
|
||||
}
|
||||
|
||||
// GetPullRequestDatabaseID retrieves the database ID of a pull request given its number in a repository.
|
||||
func (c *CAPIClient) GetPullRequestDatabaseID(ctx context.Context, hostname string, owner string, repo string, number int) (int64, error) {
|
||||
// GetPullRequestDatabaseID retrieves the database ID and URL of a pull request given its number in a repository.
|
||||
func (c *CAPIClient) GetPullRequestDatabaseID(ctx context.Context, hostname string, owner string, repo string, number int) (int64, string, error) {
|
||||
var resp struct {
|
||||
Repository struct {
|
||||
PullRequest struct {
|
||||
FullDatabaseID string `graphql:"fullDatabaseId"`
|
||||
URL string `graphql:"url"`
|
||||
} `graphql:"pullRequest(number: $number)"`
|
||||
} `graphql:"repository(owner: $owner, name: $repo)"`
|
||||
}
|
||||
|
|
@ -396,14 +399,14 @@ func (c *CAPIClient) GetPullRequestDatabaseID(ctx context.Context, hostname stri
|
|||
|
||||
apiClient := api.NewClientFromHTTP(c.httpClient)
|
||||
if err := apiClient.Query(hostname, "GetPullRequestFullDatabaseID", &resp, variables); err != nil {
|
||||
return 0, err
|
||||
return 0, "", err
|
||||
}
|
||||
|
||||
databaseID, err := strconv.ParseInt(resp.Repository.PullRequest.FullDatabaseID, 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return 0, "", err
|
||||
}
|
||||
return databaseID, nil
|
||||
return databaseID, resp.Repository.PullRequest.URL, nil
|
||||
}
|
||||
|
||||
// generatePullRequestNodeID converts an int64 databaseID and repoID to a GraphQL Node ID format
|
||||
|
|
|
|||
|
|
@ -1743,10 +1743,11 @@ func TestGetSession(t *testing.T) {
|
|||
}
|
||||
func TestGetPullRequestDatabaseID(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
httpStubs func(*testing.T, *httpmock.Registry)
|
||||
wantErr string
|
||||
wantOut int64
|
||||
name string
|
||||
httpStubs func(*testing.T, *httpmock.Registry)
|
||||
wantErr string
|
||||
wantDatabaseID int64
|
||||
wantURL string
|
||||
}{
|
||||
{
|
||||
name: "graphql error",
|
||||
|
|
@ -1764,24 +1765,26 @@ func TestGetPullRequestDatabaseID(t *testing.T) {
|
|||
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.WithHost(httpmock.GraphQL(`query GetPullRequestFullDatabaseID\b`), "api.github.com"),
|
||||
httpmock.StringResponse(`{"data": {"repository": {"pullRequest": {"fullDatabaseId": "non-int"}}}}`),
|
||||
httpmock.StringResponse(`{"data": {"repository": {"pullRequest": {"fullDatabaseId": "non-int", "url": "some-url"}}}}`),
|
||||
)
|
||||
},
|
||||
wantErr: `strconv.ParseInt: parsing "non-int": invalid syntax`,
|
||||
wantURL: "some-url",
|
||||
},
|
||||
{
|
||||
name: "success",
|
||||
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.WithHost(httpmock.GraphQL(`query GetPullRequestFullDatabaseID\b`), "api.github.com"),
|
||||
httpmock.GraphQLQuery(`{"data": {"repository": {"pullRequest": {"fullDatabaseId": "999"}}}}`, func(s string, m map[string]interface{}) {
|
||||
httpmock.GraphQLQuery(`{"data": {"repository": {"pullRequest": {"fullDatabaseId": "999", "url": "some-url"}}}}`, func(s string, m map[string]interface{}) {
|
||||
assert.Equal(t, "OWNER", m["owner"])
|
||||
assert.Equal(t, "REPO", m["repo"])
|
||||
assert.Equal(t, float64(42), m["number"])
|
||||
}),
|
||||
)
|
||||
},
|
||||
wantOut: 999,
|
||||
wantDatabaseID: 999,
|
||||
wantURL: "some-url",
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -1798,7 +1801,7 @@ func TestGetPullRequestDatabaseID(t *testing.T) {
|
|||
cfg := config.NewBlankConfig()
|
||||
capiClient := NewCAPIClient(httpClient, cfg.Authentication())
|
||||
|
||||
databaseID, err := capiClient.GetPullRequestDatabaseID(context.Background(), "github.com", "OWNER", "REPO", 42)
|
||||
databaseID, url, err := capiClient.GetPullRequestDatabaseID(context.Background(), "github.com", "OWNER", "REPO", 42)
|
||||
|
||||
if tt.wantErr != "" {
|
||||
require.ErrorContains(t, err, tt.wantErr)
|
||||
|
|
@ -1807,7 +1810,8 @@ func TestGetPullRequestDatabaseID(t *testing.T) {
|
|||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.wantOut, databaseID)
|
||||
require.Equal(t, tt.wantDatabaseID, databaseID)
|
||||
require.Equal(t, tt.wantURL, url)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ func listRun(opts *ListOptions) error {
|
|||
// based on repo, so we just open the agents dashboard with no args.
|
||||
// If that page is ever added in the future, we should route to that
|
||||
// page instead of the global one when --repo is set.
|
||||
const webURL = "https://github.com/copilot/agents"
|
||||
webURL := capi.AgentsHomeURL
|
||||
if opts.IO.IsStdoutTTY() {
|
||||
fmt.Fprintf(opts.IO.ErrOut, "Opening %s in your browser.\n", text.DisplayURL(webURL))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/v2/internal/browser"
|
||||
"github.com/cli/cli/v2/internal/ghinstance"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/internal/prompter"
|
||||
|
|
@ -31,10 +32,12 @@ type ViewOptions struct {
|
|||
HttpClient func() (*http.Client, error)
|
||||
Finder prShared.PRFinder
|
||||
Prompter prompter.Prompter
|
||||
Browser browser.Browser
|
||||
|
||||
SelectorArg string
|
||||
PRNumber int
|
||||
SessionID string
|
||||
Web bool
|
||||
}
|
||||
|
||||
func NewCmdView(f *cmdutil.Factory, runF func(*ViewOptions) error) *cobra.Command {
|
||||
|
|
@ -43,14 +46,31 @@ func NewCmdView(f *cmdutil.Factory, runF func(*ViewOptions) error) *cobra.Comman
|
|||
HttpClient: f.HttpClient,
|
||||
CapiClient: shared.CapiClientFunc(f),
|
||||
Prompter: f.Prompter,
|
||||
Browser: f.Browser,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "view [<session-id> | <pr-number> | <pr-url> | <pr-branch>]",
|
||||
Short: "View an agent task session",
|
||||
Short: "View an agent task session (preview)",
|
||||
Long: heredoc.Doc(`
|
||||
View an agent task session.
|
||||
`),
|
||||
Example: heredoc.Doc(`
|
||||
# View an agent task by session ID
|
||||
$ gh agent-task view e2fa49d2-f164-4a56-ab99-498090b8fcdf
|
||||
|
||||
# View an agent task by pull request number in current repo
|
||||
$ gh agent-task view 12345
|
||||
|
||||
# View an agent task by pull request number
|
||||
$ gh agent-task view --repo OWNER/REPO 12345
|
||||
|
||||
# View an agent task by pull request reference
|
||||
$ gh agent-task view OWNER/REPO#12345
|
||||
|
||||
# View a pull request agents tasks in the browser
|
||||
$ gh agent-task view 12345 --web
|
||||
`),
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
// Support -R/--repo override
|
||||
|
|
@ -80,6 +100,8 @@ func NewCmdView(f *cmdutil.Factory, runF func(*ViewOptions) error) *cobra.Comman
|
|||
|
||||
cmdutil.EnableRepoOverride(cmd, f)
|
||||
|
||||
cmd.Flags().BoolVarP(&opts.Web, "web", "w", false, "Open agent task in the browser")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
|
@ -98,17 +120,37 @@ func viewRun(opts *ViewOptions) error {
|
|||
var session *capi.Session
|
||||
|
||||
if opts.SessionID != "" {
|
||||
if sess, err := capiClient.GetSession(ctx, opts.SessionID); err != nil {
|
||||
sess, err := capiClient.GetSession(ctx, opts.SessionID)
|
||||
if err != nil {
|
||||
if errors.Is(err, capi.ErrSessionNotFound) {
|
||||
fmt.Fprintln(opts.IO.ErrOut, "session not found")
|
||||
return cmdutil.SilentError
|
||||
}
|
||||
return err
|
||||
} else {
|
||||
session = sess
|
||||
}
|
||||
|
||||
opts.IO.StopProgressIndicator()
|
||||
|
||||
if opts.Web {
|
||||
var webURL string
|
||||
if sess.PullRequest != nil {
|
||||
webURL = fmt.Sprintf("%s/agent-sessions/%s", sess.PullRequest.URL, url.PathEscape(sess.ID))
|
||||
} else {
|
||||
// Currently the web Copilot Agents home GUI does not support focusing
|
||||
// on a given session, so we should just navigate to the home page.
|
||||
webURL = capi.AgentsHomeURL
|
||||
}
|
||||
|
||||
if opts.IO.IsStdoutTTY() {
|
||||
fmt.Fprintf(opts.IO.ErrOut, "Opening %s in your browser.\n", text.DisplayURL(webURL))
|
||||
}
|
||||
return opts.Browser.Browse(webURL)
|
||||
}
|
||||
|
||||
session = sess
|
||||
} else {
|
||||
var resourceID int64
|
||||
var prURL string
|
||||
|
||||
if opts.SelectorArg != "" {
|
||||
// Finder does not support the PR/issue reference format (e.g. owner/repo#123)
|
||||
|
|
@ -127,7 +169,7 @@ func viewRun(opts *ViewOptions) error {
|
|||
return fmt.Errorf("agent tasks are not supported on this host: %s", hostname)
|
||||
}
|
||||
|
||||
resourceID, err = capiClient.GetPullRequestDatabaseID(ctx, hostname, repo.RepoOwner(), repo.RepoName(), num)
|
||||
resourceID, prURL, err = capiClient.GetPullRequestDatabaseID(ctx, hostname, repo.RepoOwner(), repo.RepoName(), num)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to fetch pull request: %w", err)
|
||||
}
|
||||
|
|
@ -155,6 +197,7 @@ func viewRun(opts *ViewOptions) error {
|
|||
}
|
||||
|
||||
resourceID = databaseID
|
||||
prURL = pr.URL
|
||||
}
|
||||
|
||||
// TODO(babakks): currently we just fetch a pre-defined number of
|
||||
|
|
@ -171,6 +214,23 @@ func viewRun(opts *ViewOptions) error {
|
|||
return cmdutil.SilentError
|
||||
}
|
||||
|
||||
opts.IO.StopProgressIndicator()
|
||||
|
||||
if opts.Web {
|
||||
// Note that, we needed to make sure the PR exists and it has at least one session
|
||||
// associated with it, other wise the `/agent-sessions` page would display the 404
|
||||
// error.
|
||||
|
||||
// We don't need to navigate to a specific session; if there's only one session
|
||||
// then the GUI will automatically show it, otherwise the user can select from the
|
||||
// list. This is to avoid unnecessary prompting.
|
||||
webURL := prURL + "/agent-sessions"
|
||||
if opts.IO.IsStdoutTTY() {
|
||||
fmt.Fprintf(opts.IO.ErrOut, "Opening %s in your browser.\n", text.DisplayURL(webURL))
|
||||
}
|
||||
return opts.Browser.Browse(webURL)
|
||||
}
|
||||
|
||||
session = sessions[0]
|
||||
if len(sessions) > 1 {
|
||||
now := time.Now()
|
||||
|
|
@ -184,7 +244,6 @@ func viewRun(opts *ViewOptions) error {
|
|||
))
|
||||
}
|
||||
|
||||
opts.IO.StopProgressIndicator()
|
||||
selected, err := opts.Prompter.Select("Select a session", "", options)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -194,8 +253,6 @@ func viewRun(opts *ViewOptions) error {
|
|||
}
|
||||
}
|
||||
|
||||
opts.IO.StopProgressIndicator()
|
||||
|
||||
out := opts.IO.Out
|
||||
|
||||
if session.PullRequest != nil {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/v2/api"
|
||||
"github.com/cli/cli/v2/internal/browser"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/internal/prompter"
|
||||
"github.com/cli/cli/v2/pkg/cmd/agent-task/capi"
|
||||
|
|
@ -68,6 +69,15 @@ func TestNewCmdList(t *testing.T) {
|
|||
SelectorArg: "some-arg",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "web mode",
|
||||
tty: true,
|
||||
args: "some-arg -w",
|
||||
wantOpts: ViewOptions{
|
||||
SelectorArg: "some-arg",
|
||||
Web: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
@ -116,14 +126,15 @@ func Test_viewRun(t *testing.T) {
|
|||
sampleDate := time.Now().Add(-6 * time.Hour) // 6h ago
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
tty bool
|
||||
opts ViewOptions
|
||||
promptStubs func(*testing.T, *prompter.MockPrompter)
|
||||
capiStubs func(*testing.T, *capi.CapiClientMock)
|
||||
wantOut string
|
||||
wantErr error
|
||||
wantStderr string
|
||||
name string
|
||||
tty bool
|
||||
opts ViewOptions
|
||||
promptStubs func(*testing.T, *prompter.MockPrompter)
|
||||
capiStubs func(*testing.T, *capi.CapiClientMock)
|
||||
wantOut string
|
||||
wantErr error
|
||||
wantStderr string
|
||||
wantBrowserURL string
|
||||
}{
|
||||
{
|
||||
name: "with session id, not found (tty)",
|
||||
|
|
@ -273,14 +284,85 @@ func Test_viewRun(t *testing.T) {
|
|||
Started about 6 hours ago
|
||||
`),
|
||||
},
|
||||
{
|
||||
name: "with session id, not found, web mode (tty)",
|
||||
tty: true,
|
||||
opts: ViewOptions{
|
||||
SelectorArg: "some-session-id",
|
||||
SessionID: "some-session-id",
|
||||
Web: true,
|
||||
},
|
||||
capiStubs: func(t *testing.T, m *capi.CapiClientMock) {
|
||||
m.GetSessionFunc = func(_ context.Context, _ string) (*capi.Session, error) {
|
||||
return nil, capi.ErrSessionNotFound
|
||||
}
|
||||
},
|
||||
wantStderr: "session not found\n",
|
||||
wantErr: cmdutil.SilentError,
|
||||
},
|
||||
{
|
||||
name: "with session id, without pr data, web mode (tty)",
|
||||
tty: true,
|
||||
opts: ViewOptions{
|
||||
SelectorArg: "some-session-id",
|
||||
SessionID: "some-session-id",
|
||||
Web: true,
|
||||
},
|
||||
capiStubs: func(t *testing.T, m *capi.CapiClientMock) {
|
||||
m.GetSessionFunc = func(_ context.Context, id string) (*capi.Session, error) {
|
||||
assert.Equal(t, "some-session-id", id)
|
||||
return &capi.Session{
|
||||
ID: "some-session-id",
|
||||
State: "completed",
|
||||
CreatedAt: sampleDate,
|
||||
// User data is irrelevant in this case
|
||||
}, nil
|
||||
}
|
||||
},
|
||||
wantBrowserURL: "https://github.com/copilot/agents",
|
||||
wantStderr: "Opening https://github.com/copilot/agents in your browser.\n",
|
||||
},
|
||||
{
|
||||
name: "with session id, with pr data, web mode (tty)",
|
||||
tty: true,
|
||||
opts: ViewOptions{
|
||||
SelectorArg: "some-session-id",
|
||||
SessionID: "some-session-id",
|
||||
Web: true,
|
||||
},
|
||||
capiStubs: func(t *testing.T, m *capi.CapiClientMock) {
|
||||
m.GetSessionFunc = func(_ context.Context, id string) (*capi.Session, error) {
|
||||
assert.Equal(t, "some-session-id", id)
|
||||
return &capi.Session{
|
||||
ID: "some-session-id",
|
||||
State: "completed",
|
||||
CreatedAt: sampleDate,
|
||||
PullRequest: &api.PullRequest{
|
||||
Title: "fix something",
|
||||
Number: 101,
|
||||
URL: "https://github.com/OWNER/REPO/pull/101",
|
||||
Repository: &api.PRRepository{
|
||||
NameWithOwner: "OWNER/REPO",
|
||||
},
|
||||
},
|
||||
// User data is irrelevant in this case
|
||||
}, nil
|
||||
}
|
||||
},
|
||||
wantBrowserURL: "https://github.com/OWNER/REPO/pull/101/agent-sessions/some-session-id",
|
||||
wantStderr: "Opening https://github.com/OWNER/REPO/pull/101/agent-sessions/some-session-id in your browser.\n",
|
||||
},
|
||||
{
|
||||
name: "with pr number, api error (tty)",
|
||||
tty: true,
|
||||
opts: ViewOptions{
|
||||
SelectorArg: "pr-number",
|
||||
SelectorArg: "101",
|
||||
Finder: prShared.NewMockFinder(
|
||||
"pr-number",
|
||||
&api.PullRequest{FullDatabaseID: "999999"},
|
||||
"101",
|
||||
&api.PullRequest{
|
||||
FullDatabaseID: "999999",
|
||||
URL: "https://github.com/OWNER/REPO/pull/101",
|
||||
},
|
||||
ghrepo.New("OWNER", "REPO"),
|
||||
),
|
||||
},
|
||||
|
|
@ -295,7 +377,7 @@ func Test_viewRun(t *testing.T) {
|
|||
name: "with pr reference, unsupported hostname (tty)",
|
||||
tty: true,
|
||||
opts: ViewOptions{
|
||||
SelectorArg: "OWNER/REPO#999",
|
||||
SelectorArg: "OWNER/REPO#101",
|
||||
BaseRepo: func() (ghrepo.Interface, error) {
|
||||
return ghrepo.NewWithHost("OWNER", "REPO", "foo.com"), nil
|
||||
},
|
||||
|
|
@ -306,14 +388,14 @@ func Test_viewRun(t *testing.T) {
|
|||
name: "with pr reference, api error when fetching pr database ID (tty)",
|
||||
tty: true,
|
||||
opts: ViewOptions{
|
||||
SelectorArg: "OWNER/REPO#999",
|
||||
SelectorArg: "OWNER/REPO#101",
|
||||
BaseRepo: func() (ghrepo.Interface, error) {
|
||||
return ghrepo.New("OWNER", "REPO"), nil
|
||||
},
|
||||
},
|
||||
capiStubs: func(t *testing.T, m *capi.CapiClientMock) {
|
||||
m.GetPullRequestDatabaseIDFunc = func(_ context.Context, _ string, _ string, _ string, _ int) (int64, error) {
|
||||
return 0, errors.New("some error")
|
||||
m.GetPullRequestDatabaseIDFunc = func(_ context.Context, _ string, _ string, _ string, _ int) (int64, string, error) {
|
||||
return 0, "", errors.New("some error")
|
||||
}
|
||||
},
|
||||
wantErr: errors.New("failed to fetch pull request: some error"),
|
||||
|
|
@ -322,14 +404,14 @@ func Test_viewRun(t *testing.T) {
|
|||
name: "with pr reference, api error when fetching session (tty)",
|
||||
tty: true,
|
||||
opts: ViewOptions{
|
||||
SelectorArg: "OWNER/REPO#999",
|
||||
SelectorArg: "OWNER/REPO#101",
|
||||
BaseRepo: func() (ghrepo.Interface, error) {
|
||||
return ghrepo.New("OWNER", "REPO"), nil
|
||||
},
|
||||
},
|
||||
capiStubs: func(t *testing.T, m *capi.CapiClientMock) {
|
||||
m.GetPullRequestDatabaseIDFunc = func(_ context.Context, _ string, _ string, _ string, _ int) (int64, error) {
|
||||
return 999999, nil
|
||||
m.GetPullRequestDatabaseIDFunc = func(_ context.Context, _ string, _ string, _ string, _ int) (int64, string, error) {
|
||||
return 999999, "some-url", nil
|
||||
}
|
||||
m.ListSessionsByResourceIDFunc = func(_ context.Context, _ string, _ int64, _ int) ([]*capi.Session, error) {
|
||||
return nil, errors.New("some error")
|
||||
|
|
@ -338,13 +420,16 @@ func Test_viewRun(t *testing.T) {
|
|||
wantErr: errors.New("failed to list sessions for pull request: some error"),
|
||||
},
|
||||
{
|
||||
name: "with pr number, success, single session with pr and user data (tty)",
|
||||
name: "with pr number, success, single session (tty)",
|
||||
tty: true,
|
||||
opts: ViewOptions{
|
||||
SelectorArg: "pr-number",
|
||||
SelectorArg: "101",
|
||||
Finder: prShared.NewMockFinder(
|
||||
"pr-number",
|
||||
&api.PullRequest{FullDatabaseID: "999999"},
|
||||
"101",
|
||||
&api.PullRequest{
|
||||
FullDatabaseID: "999999",
|
||||
URL: "https://github.com/OWNER/REPO/pull/101",
|
||||
},
|
||||
ghrepo.New("OWNER", "REPO"),
|
||||
),
|
||||
},
|
||||
|
|
@ -382,13 +467,16 @@ func Test_viewRun(t *testing.T) {
|
|||
`),
|
||||
},
|
||||
{
|
||||
name: "with pr number, success, multiple sessions with pr and user data (tty)",
|
||||
name: "with pr number, success, multiple sessions (tty)",
|
||||
tty: true,
|
||||
opts: ViewOptions{
|
||||
SelectorArg: "pr-number",
|
||||
SelectorArg: "101",
|
||||
Finder: prShared.NewMockFinder(
|
||||
"pr-number",
|
||||
&api.PullRequest{FullDatabaseID: "999999"},
|
||||
"101",
|
||||
&api.PullRequest{
|
||||
FullDatabaseID: "999999",
|
||||
URL: "https://github.com/OWNER/REPO/pull/101",
|
||||
},
|
||||
ghrepo.New("OWNER", "REPO"),
|
||||
),
|
||||
},
|
||||
|
|
@ -421,9 +509,9 @@ func Test_viewRun(t *testing.T) {
|
|||
State: "completed",
|
||||
CreatedAt: sampleDate,
|
||||
PullRequest: &api.PullRequest{
|
||||
Title: "fix something else",
|
||||
Number: 102,
|
||||
URL: "https://github.com/OWNER/REPO/pull/102",
|
||||
Title: "fix something",
|
||||
Number: 101,
|
||||
URL: "https://github.com/OWNER/REPO/pull/101",
|
||||
Repository: &api.PRRepository{
|
||||
NameWithOwner: "OWNER/REPO",
|
||||
},
|
||||
|
|
@ -456,21 +544,21 @@ func Test_viewRun(t *testing.T) {
|
|||
`),
|
||||
},
|
||||
{
|
||||
name: "with pr reference, success, multiple sessions with pr and user data (tty)",
|
||||
name: "with pr reference, success, multiple sessions (tty)",
|
||||
tty: true,
|
||||
opts: ViewOptions{
|
||||
SelectorArg: "OWNER/REPO#999",
|
||||
SelectorArg: "OWNER/REPO#101",
|
||||
BaseRepo: func() (ghrepo.Interface, error) {
|
||||
return ghrepo.New("OWNER", "REPO"), nil
|
||||
},
|
||||
},
|
||||
capiStubs: func(t *testing.T, m *capi.CapiClientMock) {
|
||||
m.GetPullRequestDatabaseIDFunc = func(_ context.Context, hostname string, owner string, repo string, number int) (int64, error) {
|
||||
m.GetPullRequestDatabaseIDFunc = func(_ context.Context, hostname string, owner string, repo string, number int) (int64, string, error) {
|
||||
assert.Equal(t, "github.com", hostname)
|
||||
assert.Equal(t, "OWNER", owner)
|
||||
assert.Equal(t, "REPO", repo)
|
||||
assert.Equal(t, 999, number)
|
||||
return 999999, nil
|
||||
assert.Equal(t, 101, number)
|
||||
return 999999, "https://github.com/OWNER/REPO/pull/101", nil
|
||||
}
|
||||
m.ListSessionsByResourceIDFunc = func(_ context.Context, resourceType string, resourceID int64, limit int) ([]*capi.Session, error) {
|
||||
assert.Equal(t, "pull", resourceType)
|
||||
|
|
@ -500,9 +588,9 @@ func Test_viewRun(t *testing.T) {
|
|||
State: "completed",
|
||||
CreatedAt: sampleDate,
|
||||
PullRequest: &api.PullRequest{
|
||||
Title: "fix something else",
|
||||
Number: 102,
|
||||
URL: "https://github.com/OWNER/REPO/pull/102",
|
||||
Title: "fix something",
|
||||
Number: 101,
|
||||
URL: "https://github.com/OWNER/REPO/pull/101",
|
||||
Repository: &api.PRRepository{
|
||||
NameWithOwner: "OWNER/REPO",
|
||||
},
|
||||
|
|
@ -534,6 +622,185 @@ func Test_viewRun(t *testing.T) {
|
|||
https://github.com/OWNER/REPO/pull/101/agent-sessions/some-session-id
|
||||
`),
|
||||
},
|
||||
{
|
||||
name: "with pr number, api error, web mode (tty)",
|
||||
tty: true,
|
||||
opts: ViewOptions{
|
||||
SelectorArg: "101",
|
||||
Finder: prShared.NewMockFinder(
|
||||
"101",
|
||||
&api.PullRequest{
|
||||
FullDatabaseID: "999999",
|
||||
URL: "https://github.com/OWNER/REPO/pull/101",
|
||||
},
|
||||
ghrepo.New("OWNER", "REPO"),
|
||||
),
|
||||
Web: true,
|
||||
},
|
||||
capiStubs: func(t *testing.T, m *capi.CapiClientMock) {
|
||||
m.ListSessionsByResourceIDFunc = func(_ context.Context, _ string, _ int64, _ int) ([]*capi.Session, error) {
|
||||
return nil, errors.New("some error")
|
||||
}
|
||||
},
|
||||
wantErr: errors.New("failed to list sessions for pull request: some error"),
|
||||
},
|
||||
{
|
||||
name: "with pr number, single session, web mode (tty)",
|
||||
tty: true,
|
||||
opts: ViewOptions{
|
||||
SelectorArg: "101",
|
||||
Finder: prShared.NewMockFinder(
|
||||
"101",
|
||||
&api.PullRequest{
|
||||
FullDatabaseID: "999999",
|
||||
URL: "https://github.com/OWNER/REPO/pull/101",
|
||||
},
|
||||
ghrepo.New("OWNER", "REPO"),
|
||||
),
|
||||
Web: true,
|
||||
},
|
||||
capiStubs: func(t *testing.T, m *capi.CapiClientMock) {
|
||||
m.ListSessionsByResourceIDFunc = func(_ context.Context, resourceType string, resourceID int64, limit int) ([]*capi.Session, error) {
|
||||
assert.Equal(t, "pull", resourceType)
|
||||
assert.Equal(t, int64(999999), resourceID)
|
||||
assert.Equal(t, defaultLimit, limit)
|
||||
return []*capi.Session{
|
||||
{
|
||||
ID: "some-session-id",
|
||||
State: "completed",
|
||||
CreatedAt: sampleDate,
|
||||
PullRequest: &api.PullRequest{
|
||||
Title: "fix something",
|
||||
Number: 101,
|
||||
URL: "https://github.com/OWNER/REPO/pull/101",
|
||||
Repository: &api.PRRepository{
|
||||
NameWithOwner: "OWNER/REPO",
|
||||
},
|
||||
},
|
||||
// User data is irrelevant in this case
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
},
|
||||
wantBrowserURL: "https://github.com/OWNER/REPO/pull/101/agent-sessions",
|
||||
wantStderr: "Opening https://github.com/OWNER/REPO/pull/101/agent-sessions in your browser.\n",
|
||||
},
|
||||
{
|
||||
name: "with pr number, multiple sessions, web mode (tty)",
|
||||
tty: true,
|
||||
opts: ViewOptions{
|
||||
SelectorArg: "101",
|
||||
Finder: prShared.NewMockFinder(
|
||||
"101",
|
||||
&api.PullRequest{
|
||||
FullDatabaseID: "999999",
|
||||
URL: "https://github.com/OWNER/REPO/pull/101",
|
||||
},
|
||||
ghrepo.New("OWNER", "REPO"),
|
||||
),
|
||||
Web: true,
|
||||
},
|
||||
capiStubs: func(t *testing.T, m *capi.CapiClientMock) {
|
||||
m.ListSessionsByResourceIDFunc = func(_ context.Context, resourceType string, resourceID int64, limit int) ([]*capi.Session, error) {
|
||||
assert.Equal(t, "pull", resourceType)
|
||||
assert.Equal(t, int64(999999), resourceID)
|
||||
assert.Equal(t, defaultLimit, limit)
|
||||
return []*capi.Session{
|
||||
{
|
||||
ID: "some-session-id",
|
||||
Name: "session one",
|
||||
State: "completed",
|
||||
CreatedAt: sampleDate,
|
||||
PullRequest: &api.PullRequest{
|
||||
Title: "fix something",
|
||||
Number: 101,
|
||||
URL: "https://github.com/OWNER/REPO/pull/101",
|
||||
Repository: &api.PRRepository{
|
||||
NameWithOwner: "OWNER/REPO",
|
||||
},
|
||||
},
|
||||
// User data is irrelevant in this case
|
||||
},
|
||||
{
|
||||
ID: "some-other-session-id",
|
||||
Name: "session two",
|
||||
State: "completed",
|
||||
CreatedAt: sampleDate,
|
||||
PullRequest: &api.PullRequest{
|
||||
Title: "fix something",
|
||||
Number: 101,
|
||||
URL: "https://github.com/OWNER/REPO/pull/101",
|
||||
Repository: &api.PRRepository{
|
||||
NameWithOwner: "OWNER/REPO",
|
||||
},
|
||||
},
|
||||
// User data is irrelevant in this case
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
},
|
||||
wantBrowserURL: "https://github.com/OWNER/REPO/pull/101/agent-sessions",
|
||||
wantStderr: "Opening https://github.com/OWNER/REPO/pull/101/agent-sessions in your browser.\n",
|
||||
},
|
||||
{
|
||||
name: "with pr reference, multiple sessions, web mode (tty)",
|
||||
tty: true,
|
||||
opts: ViewOptions{
|
||||
SelectorArg: "OWNER/REPO#101",
|
||||
BaseRepo: func() (ghrepo.Interface, error) {
|
||||
return ghrepo.New("OWNER", "REPO"), nil
|
||||
},
|
||||
Web: true,
|
||||
},
|
||||
capiStubs: func(t *testing.T, m *capi.CapiClientMock) {
|
||||
m.GetPullRequestDatabaseIDFunc = func(_ context.Context, hostname string, owner string, repo string, number int) (int64, string, error) {
|
||||
assert.Equal(t, "github.com", hostname)
|
||||
assert.Equal(t, "OWNER", owner)
|
||||
assert.Equal(t, "REPO", repo)
|
||||
assert.Equal(t, 101, number)
|
||||
return 999999, "https://github.com/OWNER/REPO/pull/101", nil
|
||||
}
|
||||
m.ListSessionsByResourceIDFunc = func(_ context.Context, resourceType string, resourceID int64, limit int) ([]*capi.Session, error) {
|
||||
assert.Equal(t, "pull", resourceType)
|
||||
assert.Equal(t, int64(999999), resourceID)
|
||||
assert.Equal(t, defaultLimit, limit)
|
||||
return []*capi.Session{
|
||||
{
|
||||
ID: "some-session-id",
|
||||
Name: "session one",
|
||||
State: "completed",
|
||||
CreatedAt: sampleDate,
|
||||
PullRequest: &api.PullRequest{
|
||||
Title: "fix something",
|
||||
Number: 101,
|
||||
URL: "https://github.com/OWNER/REPO/pull/101",
|
||||
Repository: &api.PRRepository{
|
||||
NameWithOwner: "OWNER/REPO",
|
||||
},
|
||||
},
|
||||
// User data is irrelevant in this case
|
||||
},
|
||||
{
|
||||
ID: "some-other-session-id",
|
||||
Name: "session two",
|
||||
State: "completed",
|
||||
CreatedAt: sampleDate,
|
||||
PullRequest: &api.PullRequest{
|
||||
Title: "fix something",
|
||||
Number: 101,
|
||||
URL: "https://github.com/OWNER/REPO/pull/101",
|
||||
Repository: &api.PRRepository{
|
||||
NameWithOwner: "OWNER/REPO",
|
||||
},
|
||||
},
|
||||
// User data is irrelevant in this case
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
},
|
||||
wantBrowserURL: "https://github.com/OWNER/REPO/pull/101/agent-sessions",
|
||||
wantStderr: "Opening https://github.com/OWNER/REPO/pull/101/agent-sessions in your browser.\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
@ -551,9 +818,12 @@ func Test_viewRun(t *testing.T) {
|
|||
ios, _, stdout, stderr := iostreams.Test()
|
||||
ios.SetStdoutTTY(tt.tty)
|
||||
|
||||
browser := &browser.Stub{}
|
||||
|
||||
opts := tt.opts
|
||||
opts.IO = ios
|
||||
opts.Prompter = prompter
|
||||
opts.Browser = browser
|
||||
opts.CapiClient = func() (capi.CapiClient, error) {
|
||||
return capiClientMock, nil
|
||||
}
|
||||
|
|
@ -566,9 +836,9 @@ func Test_viewRun(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
got := stdout.String()
|
||||
require.Equal(t, tt.wantOut, got)
|
||||
require.Equal(t, tt.wantStderr, stderr.String())
|
||||
assert.Equal(t, tt.wantOut, stdout.String())
|
||||
assert.Equal(t, tt.wantStderr, stderr.String())
|
||||
assert.Equal(t, tt.wantBrowserURL, browser.BrowsedURL())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue