diff --git a/pkg/cmd/search/code/code.go b/pkg/cmd/search/code/code.go index 88f84a125b0..d03526c4d9e 100644 --- a/pkg/cmd/search/code/code.go +++ b/pkg/cmd/search/code/code.go @@ -6,16 +6,19 @@ import ( "github.com/MakeNowJust/heredoc" "github.com/cli/cli/v2/internal/browser" + "github.com/cli/cli/v2/internal/gh" "github.com/cli/cli/v2/internal/text" "github.com/cli/cli/v2/pkg/cmd/search/shared" "github.com/cli/cli/v2/pkg/cmdutil" "github.com/cli/cli/v2/pkg/iostreams" "github.com/cli/cli/v2/pkg/search" + ghauth "github.com/cli/go-gh/v2/pkg/auth" "github.com/spf13/cobra" ) type CodeOptions struct { Browser browser.Browser + Config func() (gh.Config, error) Exporter cmdutil.Exporter IO *iostreams.IOStreams Query search.Query @@ -26,6 +29,7 @@ type CodeOptions struct { func NewCmdCode(f *cmdutil.Factory, runF func(*CodeOptions) error) *cobra.Command { opts := &CodeOptions{ Browser: f.Browser, + Config: f.Config, IO: f.IOStreams, Query: search.Query{Kind: search.KindCode}, } @@ -104,8 +108,26 @@ func NewCmdCode(f *cmdutil.Factory, runF func(*CodeOptions) error) *cobra.Comman func codeRun(opts *CodeOptions) error { io := opts.IO if opts.WebMode { - // FIXME: convert legacy `filename` and `extension` ES qualifiers to Blackbird's `path` qualifier - // when opening web search, otherwise the Blackbird search UI will complain. + // Convert `filename` and `extension` legacy search qualifiers to the new code search's `path` + // qualifier when used with `--web` because they are incompatible. + if opts.Query.Qualifiers.Filename != "" || opts.Query.Qualifiers.Extension != "" { + cfg, err := opts.Config() + if err != nil { + return err + } + host, _ := cfg.Authentication().DefaultHost() + // FIXME: Remove this check once GHES supports the new `path` search qualifier. + if !ghauth.IsEnterprise(host) { + filename := opts.Query.Qualifiers.Filename + extension := opts.Query.Qualifiers.Extension + if extension != "" && !strings.HasPrefix(extension, ".") { + extension = "." + extension + } + opts.Query.Qualifiers.Filename = "" + opts.Query.Qualifiers.Extension = "" + opts.Query.Qualifiers.Path = fmt.Sprintf("%s%s", filename, extension) + } + } url := opts.Searcher.URL(opts.Query) if io.IsStdoutTTY() { fmt.Fprintf(io.ErrOut, "Opening %s in your browser.\n", text.DisplayURL(url)) diff --git a/pkg/cmd/search/code/code_test.go b/pkg/cmd/search/code/code_test.go index 4b493c6d5c4..efb5f4b5740 100644 --- a/pkg/cmd/search/code/code_test.go +++ b/pkg/cmd/search/code/code_test.go @@ -6,6 +6,9 @@ import ( "testing" "github.com/cli/cli/v2/internal/browser" + "github.com/cli/cli/v2/internal/config" + "github.com/cli/cli/v2/internal/gh" + ghmock "github.com/cli/cli/v2/internal/gh/mock" "github.com/cli/cli/v2/pkg/cmdutil" "github.com/cli/cli/v2/pkg/iostreams" "github.com/cli/cli/v2/pkg/search" @@ -146,6 +149,7 @@ func TestCodeRun(t *testing.T) { wantErr bool wantStderr string wantStdout string + wantBrowse string }{ { name: "displays results tty", @@ -294,8 +298,7 @@ func TestCodeRun(t *testing.T) { { name: "opens browser for web mode tty", opts: &CodeOptions{ - Browser: &browser.Stub{}, - Query: query, + Query: query, Searcher: &search.SearcherMock{ URLFunc: func(query search.Query) string { return "https://github.com/search?type=code&q=map+repo%3Acli%2Fcli" @@ -305,12 +308,12 @@ func TestCodeRun(t *testing.T) { }, tty: true, wantStderr: "Opening https://github.com/search in your browser.\n", + wantBrowse: "https://github.com/search?type=code&q=map+repo%3Acli%2Fcli", }, { name: "opens browser for web mode notty", opts: &CodeOptions{ - Browser: &browser.Stub{}, - Query: query, + Query: query, Searcher: &search.SearcherMock{ URLFunc: func(query search.Query) string { return "https://github.com/search?type=code&q=map+repo%3Acli%2Fcli" @@ -318,6 +321,70 @@ func TestCodeRun(t *testing.T) { }, WebMode: true, }, + wantBrowse: "https://github.com/search?type=code&q=map+repo%3Acli%2Fcli", + }, + { + name: "converts filename and extension qualifiers for github.com web search", + opts: &CodeOptions{ + Config: func() (gh.Config, error) { return config.NewBlankConfig(), nil }, + Query: search.Query{ + Keywords: []string{"map"}, + Kind: "code", + Limit: 30, + Qualifiers: search.Qualifiers{ + Filename: "testing", + Extension: "go", + }, + }, + Searcher: search.NewSearcher(nil, "github.com"), + WebMode: true, + }, + wantBrowse: "https://github.com/search?q=map+path%3Atesting.go&type=code", + }, + { + name: "properly handles extension with dot prefix when converting to path qualifier", + opts: &CodeOptions{ + Config: func() (gh.Config, error) { return config.NewBlankConfig(), nil }, + Query: search.Query{ + Keywords: []string{"map"}, + Kind: "code", + Limit: 30, + Qualifiers: search.Qualifiers{ + Filename: "testing", + Extension: ".cpp", + }, + }, + Searcher: search.NewSearcher(nil, "github.com"), + WebMode: true, + }, + wantBrowse: "https://github.com/search?q=map+path%3Atesting.cpp&type=code", + }, + { + name: "does not convert filename and extension qualifiers for GHES web search", + opts: &CodeOptions{ + Config: func() (gh.Config, error) { + cfg := &ghmock.ConfigMock{ + AuthenticationFunc: func() gh.AuthConfig { + authCfg := &config.AuthConfig{} + authCfg.SetDefaultHost("example.com", "GH_HOST") + return authCfg + }, + } + return cfg, nil + }, + Query: search.Query{ + Keywords: []string{"map"}, + Kind: "code", + Limit: 30, + Qualifiers: search.Qualifiers{ + Filename: "testing", + Extension: "go", + }, + }, + Searcher: search.NewSearcher(nil, "example.com"), + WebMode: true, + }, + wantBrowse: "https://example.com/search?q=map+extension%3Ago+filename%3Atesting&type=code", }, } @@ -327,6 +394,8 @@ func TestCodeRun(t *testing.T) { ios.SetStdoutTTY(tt.tty) ios.SetStderrTTY(tt.tty) tt.opts.IO = ios + browser := &browser.Stub{} + tt.opts.Browser = browser t.Run(tt.name, func(t *testing.T) { err := codeRun(tt.opts) if tt.wantErr { @@ -337,6 +406,7 @@ func TestCodeRun(t *testing.T) { } assert.Equal(t, tt.wantStdout, stdout.String()) assert.Equal(t, tt.wantStderr, stderr.String()) + browser.Verify(t, tt.wantBrowse) }) } } diff --git a/pkg/search/query.go b/pkg/search/query.go index 4e1990ea26c..c517f90d833 100644 --- a/pkg/search/query.go +++ b/pkg/search/query.go @@ -64,6 +64,7 @@ type Qualifiers struct { Milestone string No []string Parent string + Path string Project string Pushed string Reactions string