From 78b09e55e5f8fe3a4c061c53b495b7a847c5bf85 Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Wed, 10 Sep 2025 18:43:40 +0100 Subject: [PATCH 1/8] fix(pr/shared): add rest return value to `ParseURL` Signed-off-by: Babak K. Shandiz --- pkg/cmd/pr/edit/edit.go | 2 +- pkg/cmd/pr/shared/finder.go | 23 +++++++++++++--------- pkg/cmd/pr/shared/finder_test.go | 33 +++++++++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/pkg/cmd/pr/edit/edit.go b/pkg/cmd/pr/edit/edit.go index c01364d24..b196546cd 100644 --- a/pkg/cmd/pr/edit/edit.go +++ b/pkg/cmd/pr/edit/edit.go @@ -97,7 +97,7 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman // needs to know the API host. If the command is run outside of // a git repo, we cannot instantiate the detector unless we have // already parsed the URL. - if baseRepo, _, err := shared.ParseURL(opts.SelectorArg); err == nil { + if baseRepo, _, _, err := shared.ParseURL(opts.SelectorArg); err == nil { opts.BaseRepo = func() (ghrepo.Interface, error) { return baseRepo, nil } diff --git a/pkg/cmd/pr/shared/finder.go b/pkg/cmd/pr/shared/finder.go index cb8237d58..ac9289486 100644 --- a/pkg/cmd/pr/shared/finder.go +++ b/pkg/cmd/pr/shared/finder.go @@ -112,7 +112,7 @@ func (f *finder) Find(opts FindOptions) (*api.PullRequest, ghrepo.Interface, err return nil, nil, errors.New("Find error: no fields specified") } - if repo, prNumber, err := ParseURL(opts.Selector); err == nil { + if repo, prNumber, _, err := ParseURL(opts.Selector); err == nil { f.prNumber = prNumber f.baseRefRepo = repo } @@ -300,32 +300,37 @@ func (f *finder) Find(opts FindOptions) (*api.PullRequest, ghrepo.Interface, err return pr, f.baseRefRepo, g.Wait() } -var pullURLRE = regexp.MustCompile(`^/([^/]+)/([^/]+)/pull/(\d+)`) +var pullURLRE = regexp.MustCompile(`^/([^/]+)/([^/]+)/pull/(\d+)(/.*)?$`) // ParseURL parses a pull request URL and returns the repository and pull -// request number. -func ParseURL(prURL string) (ghrepo.Interface, int, error) { +// request number. If there is no error, the returned repo is not nil and will +// have non-empty hostname. +// +// Any path components (not query params or fragments) after the pull request +// number are also returned. +func ParseURL(prURL string) (ghrepo.Interface, int, string, error) { if prURL == "" { - return nil, 0, fmt.Errorf("invalid URL: %q", prURL) + return nil, 0, "", fmt.Errorf("invalid URL: %q", prURL) } u, err := url.Parse(prURL) if err != nil { - return nil, 0, err + return nil, 0, "", err } if u.Scheme != "https" && u.Scheme != "http" { - return nil, 0, fmt.Errorf("invalid scheme: %s", u.Scheme) + return nil, 0, "", fmt.Errorf("invalid scheme: %s", u.Scheme) } m := pullURLRE.FindStringSubmatch(u.Path) if m == nil { - return nil, 0, fmt.Errorf("not a pull request URL: %s", prURL) + return nil, 0, "", fmt.Errorf("not a pull request URL: %s", prURL) } repo := ghrepo.NewWithHost(m[1], m[2], u.Hostname()) prNumber, _ := strconv.Atoi(m[3]) - return repo, prNumber, nil + rest := m[4] + return repo, prNumber, rest, nil } var fullReferenceRE = regexp.MustCompile(`^(?:([^/]+)/([^/]+))#(\d+)$`) diff --git a/pkg/cmd/pr/shared/finder_test.go b/pkg/cmd/pr/shared/finder_test.go index 5e33ee876..61acc892b 100644 --- a/pkg/cmd/pr/shared/finder_test.go +++ b/pkg/cmd/pr/shared/finder_test.go @@ -21,6 +21,7 @@ func TestParseURL(t *testing.T) { arg string wantRepo ghrepo.Interface wantNum int + wantRest string wantErr string }{ { @@ -35,15 +36,39 @@ func TestParseURL(t *testing.T) { wantRepo: ghrepo.NewWithHost("owner", "repo", "example.com"), wantNum: 123, }, + { + name: "valid HTTP URL with rest", + arg: "http://example.com/owner/repo/pull/123/foo/bar", + wantRepo: ghrepo.NewWithHost("owner", "repo", "example.com"), + wantNum: 123, + wantRest: "/foo/bar", + }, + { + name: "valid HTTP URL with a trailing slash", + arg: "http://example.com/owner/repo/pull/123/", + wantRepo: ghrepo.NewWithHost("owner", "repo", "example.com"), + wantNum: 123, + wantRest: "/", + }, { name: "empty URL", wantErr: "invalid URL: \"\"", }, + { + name: "no scheme", + arg: "github.com/owner/repo/pull/123", + wantErr: "invalid scheme: ", + }, { name: "invalid scheme", arg: "ftp://github.com/owner/repo/pull/123", wantErr: "invalid scheme: ftp", }, + { + name: "no hostname", + arg: "/owner/repo/pull/123", + wantErr: "invalid scheme: ", + }, { name: "incorrect path", arg: "https://github.com/owner/repo/issues/123", @@ -59,11 +84,16 @@ func TestParseURL(t *testing.T) { arg: "https://github.com/owner/repo/pull/foo", wantErr: "not a pull request URL: https://github.com/owner/repo/pull/foo", }, + { + name: "invalid PR number, non-numeric suffix", + arg: "https://github.com/owner/repo/pull/123foo", + wantErr: "not a pull request URL: https://github.com/owner/repo/pull/123foo", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - repo, num, err := ParseURL(tt.arg) + repo, num, rest, err := ParseURL(tt.arg) if tt.wantErr != "" { require.Error(t, err) @@ -73,6 +103,7 @@ func TestParseURL(t *testing.T) { require.NoError(t, err) require.Equal(t, tt.wantNum, num) + require.Equal(t, tt.wantRest, rest) require.NotNil(t, repo) require.True(t, ghrepo.IsSame(tt.wantRepo, repo)) }) From 7e21837f3d91553861cf759f2374022000424913 Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Wed, 10 Sep 2025 18:44:24 +0100 Subject: [PATCH 2/8] fix(agent-task/shared): add `ParsePullRequestAgentSessionURL` Signed-off-by: Babak K. Shandiz --- pkg/cmd/agent-task/shared/capi.go | 20 +++++++++ pkg/cmd/agent-task/shared/capi_test.go | 56 ++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/pkg/cmd/agent-task/shared/capi.go b/pkg/cmd/agent-task/shared/capi.go index f064eac2e..36f206e34 100644 --- a/pkg/cmd/agent-task/shared/capi.go +++ b/pkg/cmd/agent-task/shared/capi.go @@ -1,13 +1,16 @@ package shared import ( + "errors" "regexp" "github.com/cli/cli/v2/pkg/cmd/agent-task/capi" + prShared "github.com/cli/cli/v2/pkg/cmd/pr/shared" "github.com/cli/cli/v2/pkg/cmdutil" ) var uuidRE = regexp.MustCompile(`^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$`) +var agentSessionsPathRE = regexp.MustCompile(`^/agent-sessions/([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$`) func CapiClientFunc(f *cmdutil.Factory) func() (capi.CapiClient, error) { return func() (capi.CapiClient, error) { @@ -29,3 +32,20 @@ func CapiClientFunc(f *cmdutil.Factory) func() (capi.CapiClient, error) { func IsSessionID(s string) bool { return uuidRE.MatchString(s) } + +// ParsePullRequestAgentSessionURL parses session ID from a pull request's agent +// session URL, which is of the form: +// +// https://github.com/OWNER/REPO/pull/NUMBER/agent-sessions/SESSION-ID +func ParsePullRequestAgentSessionURL(u string) (string, error) { + _, _, rest, err := prShared.ParseURL(u) + if err != nil { + return "", err + } + + match := agentSessionsPathRE.FindStringSubmatch(rest) + if match == nil { + return "", errors.New("not a valid agent session URL") + } + return match[1], nil +} diff --git a/pkg/cmd/agent-task/shared/capi_test.go b/pkg/cmd/agent-task/shared/capi_test.go index d6a106d1b..d29f50624 100644 --- a/pkg/cmd/agent-task/shared/capi_test.go +++ b/pkg/cmd/agent-task/shared/capi_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestIsSession(t *testing.T) { @@ -18,3 +19,58 @@ func TestIsSession(t *testing.T) { assert.False(t, IsSessionID("000000000000000000000000000000000000")) assert.False(t, IsSessionID("00000000-0000-0000-0000-000000000000-extra")) } + +func TestParsePullRequestAgentSessionURL(t *testing.T) { + tests := []struct { + name string + url string + wantSessionID string + wantErr bool + }{ + { + name: "valid", + url: "https://github.com/OWNER/REPO/pull/123/agent-sessions/e2fa49d2-f164-4a56-ab99-498090b8fcdf", + wantSessionID: "e2fa49d2-f164-4a56-ab99-498090b8fcdf", + }, + { + name: "invalid session id", + url: "https://github.com/OWNER/REPO/pull/123/agent-sessions/fff", + wantErr: true, + }, + { + name: "no session id, trailing slash", + url: "https://github.com/OWNER/REPO/pull/123/agent-sessions/", + wantErr: true, + }, + { + name: "no session id", + url: "https://github.com/OWNER/REPO/pull/123/agent-sessions", + wantErr: true, + }, + { + name: "invalid pr url", + url: "https://github.com/OWNER/REPO/issues/123", + wantErr: true, + }, + { + name: "empty", + url: "", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sessionID, err := ParsePullRequestAgentSessionURL(tt.url) + + if tt.wantErr { + require.Error(t, err) + assert.Zero(t, sessionID) + return + } + + require.NoError(t, err) + assert.Equal(t, tt.wantSessionID, sessionID) + }) + } +} From 3798d98969fb7cc3bbf45d93118713775805c69e Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Wed, 10 Sep 2025 18:45:06 +0100 Subject: [PATCH 3/8] feat(agent-task view): support PR `/agent-sessions/*` URL as argument Signed-off-by: Babak K. Shandiz --- pkg/cmd/agent-task/view/view.go | 2 ++ pkg/cmd/agent-task/view/view_test.go | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/pkg/cmd/agent-task/view/view.go b/pkg/cmd/agent-task/view/view.go index 787157ffe..4f9d6dc3a 100644 --- a/pkg/cmd/agent-task/view/view.go +++ b/pkg/cmd/agent-task/view/view.go @@ -80,6 +80,8 @@ func NewCmdView(f *cmdutil.Factory, runF func(*ViewOptions) error) *cobra.Comman opts.SelectorArg = args[0] if shared.IsSessionID(opts.SelectorArg) { opts.SessionID = opts.SelectorArg + } else if sessionID, err := shared.ParsePullRequestAgentSessionURL(opts.SelectorArg); err == nil { + opts.SessionID = sessionID } } diff --git a/pkg/cmd/agent-task/view/view_test.go b/pkg/cmd/agent-task/view/view_test.go index a4636c369..bdff45793 100644 --- a/pkg/cmd/agent-task/view/view_test.go +++ b/pkg/cmd/agent-task/view/view_test.go @@ -46,6 +46,15 @@ func TestNewCmdList(t *testing.T) { SessionID: "00000000-0000-0000-0000-000000000000", }, }, + { + name: "PR agent-session URL arg tty", + tty: true, + args: "https://github.com/OWNER/REPO/pull/101/agent-sessions/00000000-0000-0000-0000-000000000000", + wantOpts: ViewOptions{ + SelectorArg: "https://github.com/OWNER/REPO/pull/101/agent-sessions/00000000-0000-0000-0000-000000000000", + SessionID: "00000000-0000-0000-0000-000000000000", + }, + }, { name: "non-session ID arg tty", tty: true, From 6b872923ea58f7ac824b6dd86a3e6125666b6073 Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Wed, 10 Sep 2025 18:57:11 +0100 Subject: [PATCH 4/8] refactor(agent-task view): rename `resourceID` to `prID` Signed-off-by: Babak K. Shandiz --- pkg/cmd/agent-task/view/view.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/cmd/agent-task/view/view.go b/pkg/cmd/agent-task/view/view.go index 4f9d6dc3a..0f8c9f794 100644 --- a/pkg/cmd/agent-task/view/view.go +++ b/pkg/cmd/agent-task/view/view.go @@ -151,7 +151,7 @@ func viewRun(opts *ViewOptions) error { session = sess } else { - var resourceID int64 + var prID int64 var prURL string if opts.SelectorArg != "" { @@ -171,14 +171,14 @@ func viewRun(opts *ViewOptions) error { return fmt.Errorf("agent tasks are not supported on this host: %s", hostname) } - resourceID, prURL, err = capiClient.GetPullRequestDatabaseID(ctx, hostname, repo.RepoOwner(), repo.RepoName(), num) + prID, prURL, err = capiClient.GetPullRequestDatabaseID(ctx, hostname, repo.RepoOwner(), repo.RepoName(), num) if err != nil { return fmt.Errorf("failed to fetch pull request: %w", err) } } } - if resourceID == 0 { + if prID == 0 { findOptions := prShared.FindOptions{ Selector: opts.SelectorArg, Fields: []string{"id", "url", "fullDatabaseId"}, @@ -198,7 +198,7 @@ func viewRun(opts *ViewOptions) error { return fmt.Errorf("failed to parse pull request: %w", err) } - resourceID = databaseID + prID = databaseID prURL = pr.URL } @@ -206,7 +206,7 @@ func viewRun(opts *ViewOptions) error { // matching sessions to avoid hitting the API too many times, but it's // technically possible for a PR to be associated with lots of sessions // (i.e. above our selected limit). - sessions, err := capiClient.ListSessionsByResourceID(ctx, "pull", resourceID, defaultLimit) + sessions, err := capiClient.ListSessionsByResourceID(ctx, "pull", prID, defaultLimit) if err != nil { return fmt.Errorf("failed to list sessions for pull request: %w", err) } From b079ea82e516d67237531422c3dd62307d05b1ef Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Wed, 10 Sep 2025 19:07:03 +0100 Subject: [PATCH 5/8] refactor(agent-task/shared): extract uuid pattern Signed-off-by: Babak K. Shandiz --- pkg/cmd/agent-task/shared/capi.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/cmd/agent-task/shared/capi.go b/pkg/cmd/agent-task/shared/capi.go index 36f206e34..656538c80 100644 --- a/pkg/cmd/agent-task/shared/capi.go +++ b/pkg/cmd/agent-task/shared/capi.go @@ -2,6 +2,7 @@ package shared import ( "errors" + "fmt" "regexp" "github.com/cli/cli/v2/pkg/cmd/agent-task/capi" @@ -9,8 +10,10 @@ import ( "github.com/cli/cli/v2/pkg/cmdutil" ) -var uuidRE = regexp.MustCompile(`^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$`) -var agentSessionsPathRE = regexp.MustCompile(`^/agent-sessions/([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$`) +const uuidPattern = `[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}` + +var uuidRE = regexp.MustCompile(fmt.Sprintf("^%s$", uuidPattern)) +var agentSessionsPathRE = regexp.MustCompile(fmt.Sprintf("^/agent-sessions/(%s)$", uuidPattern)) func CapiClientFunc(f *cmdutil.Factory) func() (capi.CapiClient, error) { return func() (capi.CapiClient, error) { From 2311a046886df4274b83bd9b684582073b74c299 Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Wed, 10 Sep 2025 19:07:52 +0100 Subject: [PATCH 6/8] fix(pr/shared): ensure `ParseURL` regexp is backward-compatible Signed-off-by: Babak K. Shandiz --- pkg/cmd/pr/shared/finder.go | 2 +- pkg/cmd/pr/shared/finder_test.go | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pkg/cmd/pr/shared/finder.go b/pkg/cmd/pr/shared/finder.go index ac9289486..786704fbb 100644 --- a/pkg/cmd/pr/shared/finder.go +++ b/pkg/cmd/pr/shared/finder.go @@ -300,7 +300,7 @@ func (f *finder) Find(opts FindOptions) (*api.PullRequest, ghrepo.Interface, err return pr, f.baseRefRepo, g.Wait() } -var pullURLRE = regexp.MustCompile(`^/([^/]+)/([^/]+)/pull/(\d+)(/.*)?$`) +var pullURLRE = regexp.MustCompile(`^/([^/]+)/([^/]+)/pull/(\d+)(.*$)`) // ParseURL parses a pull request URL and returns the repository and pull // request number. If there is no error, the returned repo is not nil and will diff --git a/pkg/cmd/pr/shared/finder_test.go b/pkg/cmd/pr/shared/finder_test.go index 61acc892b..470709480 100644 --- a/pkg/cmd/pr/shared/finder_test.go +++ b/pkg/cmd/pr/shared/finder_test.go @@ -43,6 +43,13 @@ func TestParseURL(t *testing.T) { wantNum: 123, wantRest: "/foo/bar", }, + { + name: "valid HTTP URL with .patch as rest", + arg: "http://example.com/owner/repo/pull/123.patch", + wantRepo: ghrepo.NewWithHost("owner", "repo", "example.com"), + wantNum: 123, + wantRest: ".patch", + }, { name: "valid HTTP URL with a trailing slash", arg: "http://example.com/owner/repo/pull/123/", @@ -84,11 +91,6 @@ func TestParseURL(t *testing.T) { arg: "https://github.com/owner/repo/pull/foo", wantErr: "not a pull request URL: https://github.com/owner/repo/pull/foo", }, - { - name: "invalid PR number, non-numeric suffix", - arg: "https://github.com/owner/repo/pull/123foo", - wantErr: "not a pull request URL: https://github.com/owner/repo/pull/123foo", - }, } for _, tt := range tests { From 1c37ab94537a64028e032914980ddf7299dbcfd1 Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Thu, 11 Sep 2025 09:03:26 +0100 Subject: [PATCH 7/8] refactor(agent-task/shared): enhance symbol names Signed-off-by: Babak K. Shandiz --- pkg/cmd/agent-task/shared/capi.go | 16 ++++++++-------- pkg/cmd/agent-task/shared/capi_test.go | 2 +- pkg/cmd/agent-task/view/view.go | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pkg/cmd/agent-task/shared/capi.go b/pkg/cmd/agent-task/shared/capi.go index 656538c80..c61aa13a7 100644 --- a/pkg/cmd/agent-task/shared/capi.go +++ b/pkg/cmd/agent-task/shared/capi.go @@ -12,8 +12,8 @@ import ( const uuidPattern = `[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}` -var uuidRE = regexp.MustCompile(fmt.Sprintf("^%s$", uuidPattern)) -var agentSessionsPathRE = regexp.MustCompile(fmt.Sprintf("^/agent-sessions/(%s)$", uuidPattern)) +var sessionIDRegexp = regexp.MustCompile(fmt.Sprintf("^%s$", uuidPattern)) +var agentSessionURLRegexp = regexp.MustCompile(fmt.Sprintf("^/agent-sessions/(%s)$", uuidPattern)) func CapiClientFunc(f *cmdutil.Factory) func() (capi.CapiClient, error) { return func() (capi.CapiClient, error) { @@ -33,20 +33,20 @@ func CapiClientFunc(f *cmdutil.Factory) func() (capi.CapiClient, error) { } func IsSessionID(s string) bool { - return uuidRE.MatchString(s) + return sessionIDRegexp.MatchString(s) } -// ParsePullRequestAgentSessionURL parses session ID from a pull request's agent -// session URL, which is of the form: +// ParseSessionIDFromURL parses session ID from a pull request's agent session +// URL, which is of the form: // -// https://github.com/OWNER/REPO/pull/NUMBER/agent-sessions/SESSION-ID -func ParsePullRequestAgentSessionURL(u string) (string, error) { +// `https://github.com/OWNER/REPO/pull/NUMBER/agent-sessions/SESSION-ID` +func ParseSessionIDFromURL(u string) (string, error) { _, _, rest, err := prShared.ParseURL(u) if err != nil { return "", err } - match := agentSessionsPathRE.FindStringSubmatch(rest) + match := agentSessionURLRegexp.FindStringSubmatch(rest) if match == nil { return "", errors.New("not a valid agent session URL") } diff --git a/pkg/cmd/agent-task/shared/capi_test.go b/pkg/cmd/agent-task/shared/capi_test.go index d29f50624..205d881c8 100644 --- a/pkg/cmd/agent-task/shared/capi_test.go +++ b/pkg/cmd/agent-task/shared/capi_test.go @@ -61,7 +61,7 @@ func TestParsePullRequestAgentSessionURL(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - sessionID, err := ParsePullRequestAgentSessionURL(tt.url) + sessionID, err := ParseSessionIDFromURL(tt.url) if tt.wantErr { require.Error(t, err) diff --git a/pkg/cmd/agent-task/view/view.go b/pkg/cmd/agent-task/view/view.go index 0f8c9f794..024101b0e 100644 --- a/pkg/cmd/agent-task/view/view.go +++ b/pkg/cmd/agent-task/view/view.go @@ -80,7 +80,7 @@ func NewCmdView(f *cmdutil.Factory, runF func(*ViewOptions) error) *cobra.Comman opts.SelectorArg = args[0] if shared.IsSessionID(opts.SelectorArg) { opts.SessionID = opts.SelectorArg - } else if sessionID, err := shared.ParsePullRequestAgentSessionURL(opts.SelectorArg); err == nil { + } else if sessionID, err := shared.ParseSessionIDFromURL(opts.SelectorArg); err == nil { opts.SessionID = sessionID } } From 10e4abc51545e3485b88b7486aa568510bb022d3 Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Thu, 11 Sep 2025 09:04:17 +0100 Subject: [PATCH 8/8] refactor(pr/shared): rename `rest` to `tail` Signed-off-by: Babak K. Shandiz --- pkg/cmd/pr/shared/finder.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/pkg/cmd/pr/shared/finder.go b/pkg/cmd/pr/shared/finder.go index 786704fbb..7d66d60f3 100644 --- a/pkg/cmd/pr/shared/finder.go +++ b/pkg/cmd/pr/shared/finder.go @@ -302,12 +302,9 @@ func (f *finder) Find(opts FindOptions) (*api.PullRequest, ghrepo.Interface, err var pullURLRE = regexp.MustCompile(`^/([^/]+)/([^/]+)/pull/(\d+)(.*$)`) -// ParseURL parses a pull request URL and returns the repository and pull -// request number. If there is no error, the returned repo is not nil and will -// have non-empty hostname. -// -// Any path components (not query params or fragments) after the pull request -// number are also returned. +// ParseURL parses a pull request URL and returns the repository, pull request +// number, and any tailing path components. If there is no error, the returned +// repo is not nil and will have non-empty hostname. func ParseURL(prURL string) (ghrepo.Interface, int, string, error) { if prURL == "" { return nil, 0, "", fmt.Errorf("invalid URL: %q", prURL) @@ -329,8 +326,8 @@ func ParseURL(prURL string) (ghrepo.Interface, int, string, error) { repo := ghrepo.NewWithHost(m[1], m[2], u.Hostname()) prNumber, _ := strconv.Atoi(m[3]) - rest := m[4] - return repo, prNumber, rest, nil + tail := m[4] + return repo, prNumber, tail, nil } var fullReferenceRE = regexp.MustCompile(`^(?:([^/]+)/([^/]+))#(\d+)$`)