From 545b420ff8804a1fdaf05320f75ed60048380451 Mon Sep 17 00:00:00 2001 From: Sam Coe Date: Tue, 1 Jul 2025 14:10:30 +0200 Subject: [PATCH 1/4] Transform `extension` and `filename` qualifiers into `path` qualifier --- pkg/cmd/search/code/code.go | 33 ++++++++++++++++-- pkg/cmd/search/code/code_test.go | 60 +++++++++++++++++++++++++++++--- pkg/search/query.go | 1 + 3 files changed, 88 insertions(+), 6 deletions(-) diff --git a/pkg/cmd/search/code/code.go b/pkg/cmd/search/code/code.go index d51ec8fa6be..944d11795d6 100644 --- a/pkg/cmd/search/code/code.go +++ b/pkg/cmd/search/code/code.go @@ -6,6 +6,8 @@ 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/ghinstance" "github.com/cli/cli/v2/internal/text" "github.com/cli/cli/v2/pkg/cmd/search/shared" "github.com/cli/cli/v2/pkg/cmdutil" @@ -16,6 +18,7 @@ import ( 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,33 @@ 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 legacy `filename` and `extension` elasticsearch qualifiers to Blackbird's `path` + // qualifier when opening web search. + 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 Blackbird. + if host == ghinstance.Default() { + filename, extension, _ := strings.Cut(opts.Query.Qualifiers.Filename, ".") + if filename == "" { + filename = "*" + } + // Prioritize file extension that may have been provided with the `--filename` flag. + if extension == "" { + if opts.Query.Qualifiers.Extension != "" { + extension, _ = strings.CutPrefix(opts.Query.Qualifiers.Extension, ".") + } else { + 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..a484a227c01 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,52 @@ 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: "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 +376,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 +388,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 0181a2240ab..31d728618ac 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 From f87451ff56362dee05eb87ad9b03565a692cf34d Mon Sep 17 00:00:00 2001 From: Sam Coe Date: Thu, 10 Jul 2025 12:33:08 +0200 Subject: [PATCH 2/4] Simplify path qualifier building logic --- pkg/cmd/search/code/code.go | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/pkg/cmd/search/code/code.go b/pkg/cmd/search/code/code.go index 944d11795d6..a2e152960f0 100644 --- a/pkg/cmd/search/code/code.go +++ b/pkg/cmd/search/code/code.go @@ -7,12 +7,12 @@ 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/ghinstance" "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" ) @@ -117,22 +117,15 @@ func codeRun(opts *CodeOptions) error { } host, _ := cfg.Authentication().DefaultHost() // FIXME: Remove this check once GHES supports Blackbird. - if host == ghinstance.Default() { - filename, extension, _ := strings.Cut(opts.Query.Qualifiers.Filename, ".") - if filename == "" { - filename = "*" - } - // Prioritize file extension that may have been provided with the `--filename` flag. - if extension == "" { - if opts.Query.Qualifiers.Extension != "" { - extension, _ = strings.CutPrefix(opts.Query.Qualifiers.Extension, ".") - } else { - extension = "*" - } + 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) + opts.Query.Qualifiers.Path = fmt.Sprintf("%s%s", filename, extension) } } url := opts.Searcher.URL(opts.Query) From e2b444452d06dfe1d7366457b9c2b3ee6edccfdc Mon Sep 17 00:00:00 2001 From: Sam Coe Date: Thu, 17 Jul 2025 17:32:48 +0200 Subject: [PATCH 3/4] Add additional test case for when extension is prefixed with a dot --- pkg/cmd/search/code/code_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pkg/cmd/search/code/code_test.go b/pkg/cmd/search/code/code_test.go index a484a227c01..efb5f4b5740 100644 --- a/pkg/cmd/search/code/code_test.go +++ b/pkg/cmd/search/code/code_test.go @@ -341,6 +341,24 @@ func TestCodeRun(t *testing.T) { }, 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{ From 7f97bcfcd67f7806e04f749d9636788066270fbc Mon Sep 17 00:00:00 2001 From: Kynan Ware <47394200+BagToad@users.noreply.github.com> Date: Thu, 17 Jul 2025 12:00:17 -0600 Subject: [PATCH 4/4] doc: remove codenames from code comments --- pkg/cmd/search/code/code.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/cmd/search/code/code.go b/pkg/cmd/search/code/code.go index 481c417bfe6..d03526c4d9e 100644 --- a/pkg/cmd/search/code/code.go +++ b/pkg/cmd/search/code/code.go @@ -108,15 +108,15 @@ func NewCmdCode(f *cmdutil.Factory, runF func(*CodeOptions) error) *cobra.Comman func codeRun(opts *CodeOptions) error { io := opts.IO if opts.WebMode { - // Convert legacy `filename` and `extension` elasticsearch qualifiers to Blackbird's `path` - // qualifier when opening web search. + // 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 Blackbird. + // 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