diff --git a/.github/workflows/feature-request-comment.yml b/.github/workflows/feature-request-comment.yml new file mode 100644 index 00000000000..8426d7af2d9 --- /dev/null +++ b/.github/workflows/feature-request-comment.yml @@ -0,0 +1,36 @@ +name: Add feature-request comment +on: + issues: + types: + - labeled + +permissions: + issues: write + +jobs: + add-comment-to-feature-request-issues: + if: github.event.label.name == 'enhancement' + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + NUMBER: ${{ github.event.issue.number }} + BODY: > + Thank you for your issue! We have categorized it as a feature request, + and it has been added to our backlog. In doing so, **we are not + committing to implementing this feature at this time**, but, we will + consider it for future releases based on community feedback and our own + product roadmap. + + + Unless you see the + https://github.com/cli/cli/labels/help%20wanted label, we are + not currently looking for external contributions for this feature. + + + **If you come across this issue and would like to see it implemented, + please add a thumbs up!** This will help us prioritize the feature. + Please only comment if you have additional information or viewpoints to + contribute. + steps: + - run: gh issue comment "$NUMBER" --body "$BODY" diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml index 3ed27a5f2ba..a2ca1716068 100644 --- a/.github/workflows/triage.yml +++ b/.github/workflows/triage.yml @@ -1,5 +1,6 @@ name: Discussion Triage run-name: ${{ github.event_name == 'issues' && github.event.issue.title || github.event.pull_request.title }} +permissions: {} on: issues: types: diff --git a/pkg/cmd/release/shared/attestation.go b/pkg/cmd/release/shared/attestation.go index 4e0377fed99..b4490373b6f 100644 --- a/pkg/cmd/release/shared/attestation.go +++ b/pkg/cmd/release/shared/attestation.go @@ -46,7 +46,7 @@ func (v *AttestationVerifier) VerifyAttestation(art *artifact.DigestedArtifact, return nil, err } - policy := buildVerificationPolicy(*art) + policy := buildVerificationPolicy(*art, td) sigstoreVerified, err := verifier.Verify([]*api.Attestation{att}, policy) if err != nil { return nil, err @@ -99,9 +99,13 @@ func FilterAttestationsByFileDigest(attestations []*api.Attestation, fileDigest } // buildVerificationPolicy constructs a verification policy for GitHub releases -func buildVerificationPolicy(a artifact.DigestedArtifact) verify.PolicyBuilder { +func buildVerificationPolicy(a artifact.DigestedArtifact, trustDomain string) verify.PolicyBuilder { + // If no trust domain is specified, default to "dotcom" + if trustDomain == "" { + trustDomain = "dotcom" + } // SAN must match the GitHub releases domain. No issuer extension (match anything) - sanMatcher, _ := verify.NewSANMatcher("", "^https://.*\\.releases\\.github\\.com$") + sanMatcher, _ := verify.NewSANMatcher("", fmt.Sprintf("^https://%s\\.releases\\.github\\.com$", trustDomain)) issuerMatcher, _ := verify.NewIssuerMatcher("", ".*") certId, _ := verify.NewCertificateIdentity(sanMatcher, issuerMatcher, certificate.Extensions{}) 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