diff --git a/.golangci.yml b/.golangci.yml index 932a4b438..c63b521bc 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -24,6 +24,28 @@ linters: - reassign # checks that package variables are not reassigned - unused # checks for unused constants, variables, functions and types + # Medium/low effort linters: + - canonicalheader # checks whether net/http.Header uses canonical header + - embeddedstructfieldcheck # checks embedded types in structs + - errname # checks that sentinel errors are prefixed with the Err and error types are suffixed with the Error + - exhaustive # checks exhaustiveness of enum switch statements + - forbidigo # forbids identifiers + - gochecknoinits # checks that no init functions are present in Go code + - gocyclo # computes and checks the cyclomatic complexity of functions + - iface # checks the incorrect use of interfaces, helping developers avoid interface pollution + - intrange # finds places where for loops could make use of an integer range + - iotamixing # checks if iotas are being used in const blocks with other non-iota declarations + - makezero # finds slice declarations with non-zero initial length + - mirror # reports wrong mirror patterns of bytes/strings usage + - protogetter # reports direct reads from proto message fields when getters should be used + - recvcheck # checks for receiver type consistency + - testableexamples # checks if examples are testable (have an expected output) + - tparallel # detects inappropriate usage of t.Parallel() method in your Go test codes + - unconvert # removes unnecessary type conversions + - usetesting # reports uses of functions with replacement inside the testing package + - wastedassign # finds wasted assignment statements + - whitespace # detects leading and trailing whitespace + # To enable later due to too many issues, and confirm we need them: # - gosec # - staticcheck @@ -37,6 +59,14 @@ linters: - bodyclose - gosec settings: + exhaustive: + default-signifies-exhaustive: true + forbidigo: + forbid: + - pattern: ^(fmt\.Print(|f|ln)|print|println)$ + msg: use the IOStreams abstraction instead + gocyclo: + min-complexity: 30 gocritic: disabled-checks: - appendAssign diff --git a/api/client.go b/api/client.go index 207fd86d3..14fb246d4 100644 --- a/api/client.go +++ b/api/client.go @@ -19,7 +19,7 @@ const ( apiVersion = "X-GitHub-Api-Version" apiVersionValue = "2022-11-28" authorization = "Authorization" - cacheTTL = "X-GH-CACHE-TTL" + cacheTTL = "X-Gh-Cache-Ttl" graphqlFeatures = "GraphQL-Features" features = "merge_queue" userAgent = "User-Agent" @@ -46,6 +46,7 @@ type GraphQLError struct { type HTTPError struct { *ghAPI.HTTPError + scopesSuggestion string } diff --git a/api/http_client_test.go b/api/http_client_test.go index 824bc0f1b..df1fe8a2a 100644 --- a/api/http_client_test.go +++ b/api/http_client_test.go @@ -177,7 +177,7 @@ func TestNewHTTPClient(t *testing.T) { require.NoError(t, err) req, err := http.NewRequest("GET", ts.URL, nil) - req.Header.Set("time-zone", "Europe/Amsterdam") + req.Header.Set("Time-Zone", "Europe/Amsterdam") req.Host = tt.host require.NoError(t, err) diff --git a/api/queries_pr.go b/api/queries_pr.go index d0488c64b..e9c733816 100644 --- a/api/queries_pr.go +++ b/api/queries_pr.go @@ -387,7 +387,6 @@ func (pr *PullRequest) ChecksStatus() PullRequestChecksStatus { } else { summary.Pending++ } - } else { // c.TypeName == StatusContext switch parseCheckStatusFromStatusState(c.State) { case passing: diff --git a/context/remote.go b/context/remote.go index 6094179f4..2ea7b8eca 100644 --- a/context/remote.go +++ b/context/remote.go @@ -80,6 +80,7 @@ func (r Remotes) Less(i, j int) bool { // Remote represents a git remote mapped to a GitHub repository type Remote struct { *git.Remote + Repo ghrepo.Interface } diff --git a/git/client_test.go b/git/client_test.go index f59b26077..70f26ae74 100644 --- a/git/client_test.go +++ b/git/client_test.go @@ -128,7 +128,7 @@ func TestClientRemotes(t *testing.T) { ` f, err := os.OpenFile(remoteFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0755) assert.NoError(t, err) - _, err = f.Write([]byte(remotes)) + _, err = f.WriteString(remotes) assert.NoError(t, err) err = f.Close() assert.NoError(t, err) @@ -165,7 +165,7 @@ func TestClientRemotes_no_resolved_remote(t *testing.T) { ` f, err := os.OpenFile(remoteFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0755) assert.NoError(t, err) - _, err = f.Write([]byte(remotes)) + _, err = f.WriteString(remotes) assert.NoError(t, err) err = f.Close() assert.NoError(t, err) @@ -1141,6 +1141,7 @@ func TestClientParsePushRevision(t *testing.T) { } func TestRemoteTrackingRef(t *testing.T) { + t.Parallel() t.Run("parsing", func(t *testing.T) { t.Parallel() @@ -2098,6 +2099,7 @@ func TestCredentialPatternFromHost(t *testing.T) { } func TestPushDefault(t *testing.T) { + t.Parallel() t.Run("it parses valid values correctly", func(t *testing.T) { t.Parallel() diff --git a/git/command_test.go b/git/command_test.go index 033492e01..b941c370b 100644 --- a/git/command_test.go +++ b/git/command_test.go @@ -42,7 +42,6 @@ func TestOutput(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - cmd := Command{ &exec.Cmd{ Path: createMockExecutable(t, tt.stdout, tt.stderr, tt.exitCode), @@ -87,7 +86,6 @@ func createMockExecutable(t *testing.T, stdout string, stderr string, exitCode i t.Fatalf("failed to compile: %v\n%s", err, out) } return binaryPath - } func buildCommandSourceCode(exitCode int, stdout, stderr string) string { diff --git a/internal/codespaces/api/api.go b/internal/codespaces/api/api.go index 0d1eaf5b3..22de89188 100644 --- a/internal/codespaces/api/api.go +++ b/internal/codespaces/api/api.go @@ -952,7 +952,6 @@ func (a *API) startCreate(ctx context.Context, params *CreateCodespaceParams) (* resp.Body = io.NopCloser(bodyCopy) return nil, api.HandleHTTPError(resp) - } else if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { return nil, api.HandleHTTPError(resp) } diff --git a/internal/codespaces/connection/connection.go b/internal/codespaces/connection/connection.go index 155e349bb..56afeaa9b 100644 --- a/internal/codespaces/connection/connection.go +++ b/internal/codespaces/connection/connection.go @@ -19,6 +19,7 @@ const ( type TunnelClient struct { *tunnels.Client + connected bool mu sync.Mutex } diff --git a/internal/codespaces/connection/tunnels_api_server_mock.go b/internal/codespaces/connection/tunnels_api_server_mock.go index 8f040886c..a04a571ab 100644 --- a/internal/codespaces/connection/tunnels_api_server_mock.go +++ b/internal/codespaces/connection/tunnels_api_server_mock.go @@ -264,9 +264,9 @@ func newMockrelayServer(opts ...relayServerOption) (*relayServer, error) { return nil, fmt.Errorf("failed to parse private key: %w", err) } - server.sshConfig.AddHostKey(ssh.Signer(sshPrivateKey)) + server.sshConfig.AddHostKey(sshPrivateKey) - server.httpServer = httptest.NewServer(http.HandlerFunc(makeConnection(server))) + server.httpServer = httptest.NewServer(makeConnection(server)) for _, opt := range opts { opt(server) diff --git a/internal/codespaces/rpc/invoker.go b/internal/codespaces/rpc/invoker.go index 6ba8843ac..a188a6fd2 100644 --- a/internal/codespaces/rpc/invoker.go +++ b/internal/codespaces/rpc/invoker.go @@ -175,16 +175,16 @@ func (i *invoker) StartJupyterServer(ctx context.Context) (port int, serverUrl s return 0, "", fmt.Errorf("failed to invoke JupyterLab RPC: %w", err) } - if !response.Result { - return 0, "", fmt.Errorf("failed to start JupyterLab: %s", response.Message) + if !response.GetResult() { + return 0, "", fmt.Errorf("failed to start JupyterLab: %s", response.GetMessage()) } - port, err = strconv.Atoi(response.Port) + port, err = strconv.Atoi(response.GetPort()) if err != nil { return 0, "", fmt.Errorf("failed to parse JupyterLab port: %w", err) } - return port, response.ServerUrl, err + return port, response.GetServerUrl(), err } // Rebuilds the container using cached layers by default or from scratch if full is true @@ -200,7 +200,7 @@ func (i *invoker) RebuildContainer(ctx context.Context, full bool) error { return fmt.Errorf("failed to invoke rebuild RPC: %w", err) } - if !response.RebuildContainer { + if !response.GetRebuildContainer() { return fmt.Errorf("couldn't rebuild codespace") } @@ -233,19 +233,19 @@ func (i *invoker) StartSSHServerWithOptions(ctx context.Context, options StartSS return 0, "", fmt.Errorf("failed to invoke SSH RPC: %w", err) } - if !response.Result { - return 0, "", fmt.Errorf("failed to start SSH server: %s", response.Message) + if !response.GetResult() { + return 0, "", fmt.Errorf("failed to start SSH server: %s", response.GetMessage()) } - port, err := strconv.Atoi(response.ServerPort) + port, err := strconv.Atoi(response.GetServerPort()) if err != nil { return 0, "", fmt.Errorf("failed to parse SSH server port: %w", err) } - if !isUsernameValid(response.User) { - return 0, "", fmt.Errorf("invalid username: %s", response.User) + if !isUsernameValid(response.GetUser()) { + return 0, "", fmt.Errorf("invalid username: %s", response.GetUser()) } - return port, response.User, nil + return port, response.GetUser(), nil } func listenTCP() (*net.TCPListener, error) { @@ -278,7 +278,7 @@ func (i *invoker) heartbeat(ctx context.Context, interval time.Duration) { case <-ctx.Done(): return case <-ticker.C: - reason := "" + var reason string // If the keep alive override flag is set, we don't need to check for activity on the forwarder // Otherwise, grab the reason from the forwarder diff --git a/internal/codespaces/rpc/invoker_test.go b/internal/codespaces/rpc/invoker_test.go index d9b271c54..fc32cf9bf 100644 --- a/internal/codespaces/rpc/invoker_test.go +++ b/internal/codespaces/rpc/invoker_test.go @@ -126,11 +126,11 @@ func TestStartJupyterServerSuccess(t *testing.T) { if err != nil { t.Fatalf("expected %v, got %v", nil, err) } - if strconv.Itoa(port) != resp.Port { - t.Fatalf("expected %s, got %d", resp.Port, port) + if strconv.Itoa(port) != resp.GetPort() { + t.Fatalf("expected %s, got %d", resp.GetPort(), port) } - if url != resp.ServerUrl { - t.Fatalf("expected %s, got %s", resp.ServerUrl, url) + if url != resp.GetServerUrl() { + t.Fatalf("expected %s, got %s", resp.GetServerUrl(), url) } verifyNotifyCodespaceOfClientActivity(t, server) @@ -156,7 +156,7 @@ func TestStartJupyterServerFailure(t *testing.T) { } defer stop() - errorMessage := fmt.Sprintf("failed to start JupyterLab: %s", resp.Message) + errorMessage := fmt.Sprintf("failed to start JupyterLab: %s", resp.GetMessage()) port, url, err := invoker.StartJupyterServer(context.Background()) if err.Error() != errorMessage { t.Fatalf("expected %v, got %v", errorMessage, err) @@ -269,11 +269,11 @@ func TestStartSSHServerSuccess(t *testing.T) { if err != nil { t.Fatalf("expected %v, got %v", nil, err) } - if strconv.Itoa(port) != resp.ServerPort { - t.Fatalf("expected %s, got %d", resp.ServerPort, port) + if strconv.Itoa(port) != resp.GetServerPort() { + t.Fatalf("expected %s, got %d", resp.GetServerPort(), port) } - if user != resp.User { - t.Fatalf("expected %s, got %s", resp.User, user) + if user != resp.GetUser() { + t.Fatalf("expected %s, got %s", resp.GetUser(), user) } verifyNotifyCodespaceOfClientActivity(t, server) @@ -299,7 +299,7 @@ func TestStartSSHServerFailure(t *testing.T) { } defer stop() - errorMessage := fmt.Sprintf("failed to start SSH server: %s", resp.Message) + errorMessage := fmt.Sprintf("failed to start SSH server: %s", resp.GetMessage()) port, user, err := invoker.StartSSHServer(context.Background()) if err.Error() != errorMessage { t.Fatalf("expected %v, got %v", errorMessage, err) diff --git a/internal/config/migrate_test.go b/internal/config/migrate_test.go index 783f605a2..8c6a0fa1a 100644 --- a/internal/config/migrate_test.go +++ b/internal/config/migrate_test.go @@ -239,7 +239,6 @@ func mockMigration(doFunc func(config *ghConfig.Config) error) *ghmock.Migration return "not-expected" }, } - } func testFullConfig() string { diff --git a/internal/docs/man_test.go b/internal/docs/man_test.go index 4db6b7459..147ff501f 100644 --- a/internal/docs/man_test.go +++ b/internal/docs/man_test.go @@ -171,11 +171,7 @@ func TestManPrintFlagsHidesShortDeprecated(t *testing.T) { func TestGenManTree(t *testing.T) { c := &cobra.Command{Use: "do [OPTIONS] arg1 arg2"} - tmpdir, err := os.MkdirTemp("", "test-gen-man-tree") - if err != nil { - t.Fatalf("Failed to create tmpdir: %s", err.Error()) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() if err := GenManTree(c, tmpdir); err != nil { t.Fatalf("GenManTree failed: %s", err.Error()) @@ -310,7 +306,7 @@ func BenchmarkGenManToFile(b *testing.B) { defer file.Close() b.ResetTimer() - for i := 0; i < b.N; i++ { + for range b.N { if err := renderMan(rootCmd, nil, file); err != nil { b.Fatal(err) } diff --git a/internal/docs/markdown.go b/internal/docs/markdown.go index 7ae8c6862..e23e6b66b 100644 --- a/internal/docs/markdown.go +++ b/internal/docs/markdown.go @@ -32,7 +32,6 @@ func printAliases(w io.Writer, cmd *cobra.Command) { fmt.Fprint(w, text.FormatSlice(strings.Split(strings.Join(root.BuildAliasList(cmd, cmd.Aliases), ", "), ","), 0, 0, "", "", true)) fmt.Fprint(w, "\n\n") } - } func printOptions(w io.Writer, cmd *cobra.Command) error { @@ -80,7 +79,6 @@ var defaultValFormats = map[string]string{ } func getDefaultValueDisplayString(f *pflag.Flag) string { - if hiddenFlagDefaults[f.DefValue] || hiddenFlagDefaults[f.Value.Type()] { return "" } @@ -89,7 +87,6 @@ func getDefaultValueDisplayString(f *pflag.Flag) string { return fmt.Sprintf(dvf, f.Value) } return fmt.Sprintf(" (default %s)", f.Value) - } type flagView struct { diff --git a/internal/docs/markdown_test.go b/internal/docs/markdown_test.go index 59cb2b34d..e436cc9a7 100644 --- a/internal/docs/markdown_test.go +++ b/internal/docs/markdown_test.go @@ -101,11 +101,7 @@ func TestGenMdJSONFields(t *testing.T) { func TestGenMdTree(t *testing.T) { c := &cobra.Command{Use: "do [OPTIONS] arg1 arg2"} - tmpdir, err := os.MkdirTemp("", "test-gen-md-tree") - if err != nil { - t.Fatalf("Failed to create tmpdir: %v", err) - } - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() if err := GenMarkdownTreeCustom(c, tmpdir, func(s string) string { return s }, func(s string) string { return s }); err != nil { t.Fatalf("GenMarkdownTree failed: %v", err) @@ -126,7 +122,7 @@ func BenchmarkGenMarkdownToFile(b *testing.B) { linkHandler := func(s string) string { return s } b.ResetTimer() - for i := 0; i < b.N; i++ { + for range b.N { if err := genMarkdownCustom(rootCmd, file, linkHandler); err != nil { b.Fatal(err) } @@ -134,7 +130,6 @@ func BenchmarkGenMarkdownToFile(b *testing.B) { } func TestPrintFlagsHTMLShowsDefaultValues(t *testing.T) { - type TestOptions struct { Limit int Template string diff --git a/internal/featuredetection/detector_mock.go b/internal/featuredetection/detector_mock.go index 552f197d9..9bdb6ff53 100644 --- a/internal/featuredetection/detector_mock.go +++ b/internal/featuredetection/detector_mock.go @@ -76,6 +76,7 @@ func (md *EnabledDetectorMock) ActionsFeatures() (ActionsFeatures, error) { type AdvancedIssueSearchDetectorMock struct { EnabledDetectorMock + searchFeatures SearchFeatures } diff --git a/internal/featuredetection/feature_detection_test.go b/internal/featuredetection/feature_detection_test.go index 82132ab83..2cf6351e3 100644 --- a/internal/featuredetection/feature_detection_test.go +++ b/internal/featuredetection/feature_detection_test.go @@ -353,6 +353,7 @@ func TestRepositoryFeatures(t *testing.T) { } func TestProjectV1Support(t *testing.T) { + t.Parallel() tests := []struct { name string hostname string @@ -421,6 +422,7 @@ func TestProjectV1Support(t *testing.T) { } func TestAdvancedIssueSearchSupport(t *testing.T) { + t.Parallel() withIssueAdvanced := `{"data":{"SearchType":{"enumValues":[{"name":"ISSUE"},{"name":"ISSUE_ADVANCED"},{"name":"REPOSITORY"},{"name":"USER"},{"name":"DISCUSSION"}]}}}` withoutIssueAdvanced := `{"data":{"SearchType":{"enumValues":[{"name":"ISSUE"},{"name":"REPOSITORY"},{"name":"USER"},{"name":"DISCUSSION"}]}}}` @@ -653,6 +655,7 @@ func TestProjectFeatures(t *testing.T) { } func TestReleaseFeatures(t *testing.T) { + t.Parallel() withImmutableReleaseSupport := `{"data":{"Release":{"fields":[{"name":"author"},{"name":"name"},{"name":"immutable"}]}}}` withoutImmutableReleaseSupport := `{"data":{"Release":{"fields":[{"name":"author"},{"name":"name"}]}}}` @@ -764,6 +767,7 @@ func TestReleaseFeatures(t *testing.T) { } func TestActionsFeatures(t *testing.T) { + t.Parallel() tests := []struct { name string hostname string diff --git a/internal/prompter/accessible_prompter_test.go b/internal/prompter/accessible_prompter_test.go index 2c26a16a0..f73bc79fa 100644 --- a/internal/prompter/accessible_prompter_test.go +++ b/internal/prompter/accessible_prompter_test.go @@ -33,7 +33,6 @@ import ( // are sufficient to ensure that the accessible prompter behaves roughly as expected // but doesn't mandate that prompts always look exactly the same. func TestAccessiblePrompter(t *testing.T) { - beforePasswordSendTimeout := 100 * time.Microsecond t.Run("Select", func(t *testing.T) { diff --git a/internal/prompter/test.go b/internal/prompter/test.go index 599fd3893..ceada4932 100644 --- a/internal/prompter/test.go +++ b/internal/prompter/test.go @@ -23,8 +23,8 @@ func NewMockPrompter(t *testing.T) *MockPrompter { } type MockPrompter struct { - t *testing.T ghPrompter.PrompterMock + t *testing.T authTokenStubs []authTokenStub confirmDeletionStubs []confirmDeletionStub inputHostnameStubs []inputHostnameStub diff --git a/internal/tableprinter/table_printer.go b/internal/tableprinter/table_printer.go index 47128afb4..80da9020e 100644 --- a/internal/tableprinter/table_printer.go +++ b/internal/tableprinter/table_printer.go @@ -12,6 +12,7 @@ import ( type TablePrinter struct { tableprinter.TablePrinter + isTTY bool cs *iostreams.ColorScheme } diff --git a/internal/update/update_test.go b/internal/update/update_test.go index 089e36f68..8931ee547 100644 --- a/internal/update/update_test.go +++ b/internal/update/update_test.go @@ -416,7 +416,7 @@ func TestShouldCheckForUpdate(t *testing.T) { t.Run(tt.name, func(t *testing.T) { os.Clearenv() for k, v := range tt.env { - os.Setenv(k, v) + t.Setenv(k, v) } actual := ShouldCheckForUpdate() @@ -473,7 +473,7 @@ func TestShouldCheckForExtensionUpdate(t *testing.T) { t.Run(tt.name, func(t *testing.T) { os.Clearenv() for k, v := range tt.env { - os.Setenv(k, v) + t.Setenv(k, v) } actual := ShouldCheckForExtensionUpdate() diff --git a/pkg/cmd/agent-task/capi/client.go b/pkg/cmd/agent-task/capi/client.go index 2f6c649a1..5b431ac8d 100644 --- a/pkg/cmd/agent-task/capi/client.go +++ b/pkg/cmd/agent-task/capi/client.go @@ -71,7 +71,7 @@ func (ct *capiTransport) RoundTrip(req *http.Request) (*http.Response, error) { req.Header.Add("Copilot-Integration-Id", "copilot-4-cli") // Ensure we are not using GitHub API versions while targeting CAPI. - req.Header.Set("X-GitHub-Api-Version", "2026-01-09") + req.Header.Set("X-Github-Api-Version", "2026-01-09") } return ct.rp.RoundTrip(req) } diff --git a/pkg/cmd/agent-task/create/create.go b/pkg/cmd/agent-task/create/create.go index a9176e966..69f59add5 100644 --- a/pkg/cmd/agent-task/create/create.go +++ b/pkg/cmd/agent-task/create/create.go @@ -147,7 +147,7 @@ func createRun(opts *CreateOptions) error { return err } - trimmed := strings.TrimSpace(string(desc)) + trimmed := strings.TrimSpace(desc) if trimmed == "" { return errors.New("a task description is required") } diff --git a/pkg/cmd/api/pagination.go b/pkg/cmd/api/pagination.go index bf4a2f794..be927713f 100644 --- a/pkg/cmd/api/pagination.go +++ b/pkg/cmd/api/pagination.go @@ -113,6 +113,7 @@ func addPerPage(p string, perPage int, params map[string]interface{}) string { // JSON array in order to apply pagination context between multiple API requests. type paginatedArrayReader struct { io.Reader + isFirstPage bool isLastPage bool @@ -153,6 +154,7 @@ func (r *paginatedArrayReader) Read(p []byte) (int, error) { // and objects. Call Close to write the end of the array. type jsonArrayWriter struct { io.Writer + started bool color bool } diff --git a/pkg/cmd/api/pagination_test.go b/pkg/cmd/api/pagination_test.go index 746a73c4a..f6cf2da2e 100644 --- a/pkg/cmd/api/pagination_test.go +++ b/pkg/cmd/api/pagination_test.go @@ -265,6 +265,7 @@ func TestJsonArrayWriter_Copy(t *testing.T) { type noWriteToReader struct { io.Reader + limit int } diff --git a/pkg/cmd/attestation/api/attestation.go b/pkg/cmd/attestation/api/attestation.go index 68ccff77e..d600564c6 100644 --- a/pkg/cmd/attestation/api/attestation.go +++ b/pkg/cmd/attestation/api/attestation.go @@ -35,12 +35,12 @@ func FilterAttestations(predicateType string, attestations []*Attestation) ([]*A for _, each := range attestations { dsseEnvelope := each.Bundle.GetDsseEnvelope() if dsseEnvelope != nil { - if dsseEnvelope.PayloadType != "application/vnd.in-toto+json" { + if dsseEnvelope.GetPayloadType() != "application/vnd.in-toto+json" { // Don't fail just because an entry isn't intoto continue } var intotoStatement IntotoStatement - if err := json.Unmarshal([]byte(dsseEnvelope.Payload), &intotoStatement); err != nil { + if err := json.Unmarshal(dsseEnvelope.GetPayload(), &intotoStatement); err != nil { // Don't fail just because a single entry can't be unmarshalled continue } diff --git a/pkg/cmd/attestation/api/client_test.go b/pkg/cmd/attestation/api/client_test.go index d9381612d..7f6b7885f 100644 --- a/pkg/cmd/attestation/api/client_test.go +++ b/pkg/cmd/attestation/api/client_test.go @@ -332,7 +332,6 @@ func TestGetTrustDomain(t *testing.T) { td, err := c.GetTrustDomain() require.Nil(t, err) require.Equal(t, "foo", td) - }) t.Run("with error", func(t *testing.T) { @@ -346,7 +345,6 @@ func TestGetTrustDomain(t *testing.T) { require.Equal(t, "", td) require.ErrorContains(t, err, "test error") }) - } func TestGetAttestationsRetries(t *testing.T) { diff --git a/pkg/cmd/attestation/api/mock_githubApiClient_test.go b/pkg/cmd/attestation/api/mock_githubApiClient_test.go index fa9be7e7f..332181395 100644 --- a/pkg/cmd/attestation/api/mock_githubApiClient_test.go +++ b/pkg/cmd/attestation/api/mock_githubApiClient_test.go @@ -27,6 +27,7 @@ func (m mockAPIClient) REST(hostname, method, p string, body io.Reader, data int type mockDataGenerator struct { mock.Mock + NumUserAttestations int NumGitHubAttestations int } @@ -78,7 +79,7 @@ func (m *mockDataGenerator) OnREST500ErrorHandler() func(hostname, method, p str func (m *mockDataGenerator) OnRESTWithNextSuccessHelper(hostname, method, p string, body io.Reader, data interface{}, hasNext bool) (string, error) { atts := make([]*Attestation, m.NumUserAttestations+m.NumGitHubAttestations) - for j := 0; j < m.NumUserAttestations; j++ { + for j := range m.NumUserAttestations { att := makeTestAttestation() atts[j] = &att } @@ -148,7 +149,6 @@ func (m mockMetaGenerator) OnREST(hostname, method, p string, body io.Reader, da ` var jsonString = fmt.Sprintf(template, m.TrustDomain) return json.Unmarshal([]byte(jsonString), &data) - } func (m mockMetaGenerator) OnRESTError(hostname, method, p string, body io.Reader, data interface{}) error { diff --git a/pkg/cmd/attestation/api/mock_httpClient_test.go b/pkg/cmd/attestation/api/mock_httpClient_test.go index b082d13d2..1bc5321b3 100644 --- a/pkg/cmd/attestation/api/mock_httpClient_test.go +++ b/pkg/cmd/attestation/api/mock_httpClient_test.go @@ -59,6 +59,7 @@ func (m *reqFailHttpClient) Get(url string) (*http.Response, error) { type failAfterNCallsHttpClient struct { mock.Mock + mu sync.Mutex FailOnCallN int FailOnAllSubsequentCalls bool diff --git a/pkg/cmd/attestation/download/metadata.go b/pkg/cmd/attestation/download/metadata.go index 4bc353a96..10e654308 100644 --- a/pkg/cmd/attestation/download/metadata.go +++ b/pkg/cmd/attestation/download/metadata.go @@ -54,7 +54,7 @@ func (s *LiveStore) createMetadataFile(artifactDigest string, attestationsResp [ } withNewline := fmt.Sprintf("%s\n", attBytes) - _, err = f.Write([]byte(withNewline)) + _, err = f.WriteString(withNewline) if err != nil { if err = f.Close(); err != nil { return "", errors.Join(ErrAttestationFileCreation, fmt.Errorf("failed to close file while handling write error: %v", err)) diff --git a/pkg/cmd/attestation/inspect/bundle.go b/pkg/cmd/attestation/inspect/bundle.go index b8f9f8808..a0c84ac64 100644 --- a/pkg/cmd/attestation/inspect/bundle.go +++ b/pkg/cmd/attestation/inspect/bundle.go @@ -86,7 +86,7 @@ func getAttestationDetail(tenant string, attr api.Attestation) (AttestationDetai } var predicate Predicate - predicateJson, err := json.Marshal(statement.Predicate) + predicateJson, err := json.Marshal(statement.GetPredicate()) if err != nil { return AttestationDetail{}, fmt.Errorf("failed to marshal predicate: %v", err) } diff --git a/pkg/cmd/attestation/inspect/inspect.go b/pkg/cmd/attestation/inspect/inspect.go index 9a2bb5d3f..7dcf63c7e 100644 --- a/pkg/cmd/attestation/inspect/inspect.go +++ b/pkg/cmd/attestation/inspect/inspect.go @@ -147,6 +147,7 @@ type BundleInspection struct { type CertificateInspection struct { certificate.Summary + NotBefore time.Time `json:"notBefore"` NotAfter time.Time `json:"notAfter"` } @@ -188,7 +189,6 @@ func runInspect(opts *Options) error { // summarize cert if present if leafCert := verificationContent.Certificate(); leafCert != nil { - certSummary, err := certificate.SummarizeCertificate(leafCert) if err != nil { return fmt.Errorf("failed to summarize certificate: %w", err) @@ -199,7 +199,6 @@ func runInspect(opts *Options) error { NotBefore: leafCert.NotBefore, NotAfter: leafCert.NotAfter, } - } // parse the sig content and pop the statement diff --git a/pkg/cmd/attestation/inspect/inspect_test.go b/pkg/cmd/attestation/inspect/inspect_test.go index c94e80ad2..a33058298 100644 --- a/pkg/cmd/attestation/inspect/inspect_test.go +++ b/pkg/cmd/attestation/inspect/inspect_test.go @@ -62,6 +62,6 @@ func TestJSONOutput(t *testing.T) { err := json.Unmarshal(out.Bytes(), &target) assert.Equal(t, "https://github.com/sigstore/sigstore-js", target.InspectedBundles[0].Certificate.SourceRepositoryURI) - assert.Equal(t, "https://slsa.dev/provenance/v1", target.InspectedBundles[0].Statement.PredicateType) + assert.Equal(t, "https://slsa.dev/provenance/v1", target.InspectedBundles[0].Statement.GetPredicateType()) require.NoError(t, err) } diff --git a/pkg/cmd/attestation/trustedroot/trustedroot_test.go b/pkg/cmd/attestation/trustedroot/trustedroot_test.go index 0d67c4445..5e8db55ad 100644 --- a/pkg/cmd/attestation/trustedroot/trustedroot_test.go +++ b/pkg/cmd/attestation/trustedroot/trustedroot_test.go @@ -194,11 +194,11 @@ func TestGetTrustedRoot(t *testing.T) { require.Error(t, err) require.ErrorContains(t, err, "failed to read root file") }) - } type stubAuthConfig struct { config.AuthConfig + hasActiveToken bool } diff --git a/pkg/cmd/attestation/verification/attestation_test.go b/pkg/cmd/attestation/verification/attestation_test.go index 6826e2e40..b032153ec 100644 --- a/pkg/cmd/attestation/verification/attestation_test.go +++ b/pkg/cmd/attestation/verification/attestation_test.go @@ -44,7 +44,7 @@ func TestLoadBundlesFromJSONLinesFile(t *testing.T) { func TestLoadBundlesFromJSONLinesFile_RejectEmptyJSONLFile(t *testing.T) { // Create a temporary file - emptyJSONL, err := os.CreateTemp("", "empty.jsonl") + emptyJSONL, err := os.CreateTemp(t.TempDir(), "empty.jsonl") require.NoError(t, err) err = emptyJSONL.Close() require.NoError(t, err) diff --git a/pkg/cmd/attestation/verification/tuf_test.go b/pkg/cmd/attestation/verification/tuf_test.go index 41f766ac9..7c1e9474e 100644 --- a/pkg/cmd/attestation/verification/tuf_test.go +++ b/pkg/cmd/attestation/verification/tuf_test.go @@ -1,7 +1,6 @@ package verification import ( - "os" "path/filepath" "testing" @@ -11,7 +10,7 @@ import ( ) func TestGitHubTUFOptionsNoMetadataDir(t *testing.T) { - os.Setenv("CODESPACES", "true") + t.Setenv("CODESPACES", "true") opts := GitHubTUFOptions(o.None[string](), nil) require.Equal(t, GitHubTUFMirror, opts.RepositoryBaseURL) diff --git a/pkg/cmd/auth/logout/logout_test.go b/pkg/cmd/auth/logout/logout_test.go index 02386c55b..718b98bc0 100644 --- a/pkg/cmd/auth/logout/logout_test.go +++ b/pkg/cmd/auth/logout/logout_test.go @@ -316,7 +316,7 @@ func Test_logoutRun_tty(t *testing.T) { for _, hostUsers := range tt.cfgHosts { for _, user := range hostUsers.users { _, _ = cfg.Authentication().Login( - string(hostUsers.host), + hostUsers.host, user.name, user.token, "ssh", tt.secureStorage, ) @@ -511,7 +511,7 @@ func Test_logoutRun_nontty(t *testing.T) { for _, hostUsers := range tt.cfgHosts { for _, user := range hostUsers.users { _, _ = cfg.Authentication().Login( - string(hostUsers.host), + hostUsers.host, user.name, user.token, "ssh", tt.secureStorage, ) diff --git a/pkg/cmd/auth/shared/git_credential_test.go b/pkg/cmd/auth/shared/git_credential_test.go index 19ab9b752..10fb29407 100644 --- a/pkg/cmd/auth/shared/git_credential_test.go +++ b/pkg/cmd/auth/shared/git_credential_test.go @@ -73,7 +73,6 @@ func TestGitCredentialsSetup_setOurs_GH(t *testing.T) { if err := f.Setup("github.com", "monalisa", "PASSWD"); err != nil { t.Errorf("Setup() error = %v", err) } - } func TestSetup_setOurs_nonGH(t *testing.T) { diff --git a/pkg/cmd/auth/shared/oauth_scopes_test.go b/pkg/cmd/auth/shared/oauth_scopes_test.go index b1ea4c601..0c943529c 100644 --- a/pkg/cmd/auth/shared/oauth_scopes_test.go +++ b/pkg/cmd/auth/shared/oauth_scopes_test.go @@ -34,7 +34,7 @@ func Test_HasMinimumScopes(t *testing.T) { var gotAuthorization string fakehttp.Register(httpmock.REST("GET", ""), func(req *http.Request) (*http.Response, error) { - gotAuthorization = req.Header.Get("authorization") + gotAuthorization = req.Header.Get("Authorization") return &http.Response{ Request: req, StatusCode: 200, @@ -96,7 +96,6 @@ func Test_HeaderHasMinimumScopes(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := HeaderHasMinimumScopes(tt.header) if tt.wantErr != "" { assert.EqualError(t, err, tt.wantErr) diff --git a/pkg/cmd/auth/switch/switch_test.go b/pkg/cmd/auth/switch/switch_test.go index 6ca77f44c..ea55a33ca 100644 --- a/pkg/cmd/auth/switch/switch_test.go +++ b/pkg/cmd/auth/switch/switch_test.go @@ -80,7 +80,6 @@ func TestNewCmdSwitch(t *testing.T) { require.Equal(t, &tt.expectedOpts, gotOpts) }) } - } func TestSwitchRun(t *testing.T) { diff --git a/pkg/cmd/codespace/create.go b/pkg/cmd/codespace/create.go index bd2eb4623..8c580bed3 100644 --- a/pkg/cmd/codespace/create.go +++ b/pkg/cmd/codespace/create.go @@ -237,7 +237,6 @@ func (a *App) Create(ctx context.Context, opts createOptions) error { } if len(devcontainers) > 0 { - // if there is only one devcontainer.json file and it is one of the default paths we can auto-select it if len(devcontainers) == 1 && stringInSlice(devcontainers[0].Path, DEFAULT_DEVCONTAINER_DEFINITIONS) { devContainerPath = devcontainers[0].Path @@ -527,7 +526,7 @@ func getMachineName(ctx context.Context, apiClient apiClient, prompter SurveyPro } availableMachines := make([]string, len(machines)) - for i := 0; i < len(machines); i++ { + for i := range machines { availableMachines[i] = machines[i].Name } diff --git a/pkg/cmd/codespace/ports.go b/pkg/cmd/codespace/ports.go index ef386dc86..56c28a70e 100644 --- a/pkg/cmd/codespace/ports.go +++ b/pkg/cmd/codespace/ports.go @@ -268,7 +268,6 @@ func (a *App) UpdatePortVisibility(ctx context.Context, selector *CodespaceSelec if err != nil { return err } - } return nil diff --git a/pkg/cmd/codespace/select_test.go b/pkg/cmd/codespace/select_test.go index 02ea6f967..6b8e0b6c3 100644 --- a/pkg/cmd/codespace/select_test.go +++ b/pkg/cmd/codespace/select_test.go @@ -52,7 +52,7 @@ func TestApp_Select(t *testing.T) { opts := selectOptions{} if tt.outputToFile { - file, err := os.CreateTemp("", "codespace-selection-test") + file, err := os.CreateTemp(t.TempDir(), "codespace-selection-test") if err != nil { t.Fatal(err) } diff --git a/pkg/cmd/codespace/ssh.go b/pkg/cmd/codespace/ssh.go index cd90541f2..9550dd001 100644 --- a/pkg/cmd/codespace/ssh.go +++ b/pkg/cmd/codespace/ssh.go @@ -327,7 +327,7 @@ func selectSSHKeys( opts sshOptions, ) (*ssh.KeyPair, bool, error) { customConfigPath := "" - for i := 0; i < len(args); i += 1 { + for i := range args { arg := args[i] if arg == "-i" { @@ -703,6 +703,7 @@ func automaticPrivateKeyPath(sshContext ssh.Context) (string, error) { type cpOptions struct { sshOptions + recursive bool // -r expand bool // -e } @@ -778,7 +779,6 @@ func (a *App) Copy(ctx context.Context, args []string, opts cpOptions) error { if !opts.expand { arg = `remote:'` + strings.Replace(rest, `'`, `'\''`, -1) + `'` } - } else if !filepath.IsAbs(arg) { // scp treats a colon in the first path segment as a host identifier. // Escape it by prepending "./". diff --git a/pkg/cmd/extension/extension.go b/pkg/cmd/extension/extension.go index f30bf63c1..b62b204dc 100644 --- a/pkg/cmd/extension/extension.go +++ b/pkg/cmd/extension/extension.go @@ -74,7 +74,7 @@ func (e *Extension) URL() string { } case GitKind: if remoteURL, err := e.gitClient.Config("remote.origin.url"); err == nil { - url = strings.TrimSpace(string(remoteURL)) + url = strings.TrimSpace(remoteURL) } } @@ -196,7 +196,7 @@ func (e *Extension) Owner() string { } case GitKind: if remoteURL, err := e.gitClient.Config("remote.origin.url"); err == nil { - if url, err := git.ParseURL(strings.TrimSpace(string(remoteURL))); err == nil { + if url, err := git.ParseURL(strings.TrimSpace(remoteURL)); err == nil { if repo, err := ghrepo.FromURL(url); err == nil { owner = repo.RepoOwner() } diff --git a/pkg/cmd/extension/manager_test.go b/pkg/cmd/extension/manager_test.go index 1e8f82483..91887022c 100644 --- a/pkg/cmd/extension/manager_test.go +++ b/pkg/cmd/extension/manager_test.go @@ -261,7 +261,7 @@ func TestManager_UpgradeExtensions(t *testing.T) { exts, err := m.list(false) assert.NoError(t, err) assert.Equal(t, 3, len(exts)) - for i := 0; i < 3; i++ { + for i := range 3 { exts[i].currentVersion = "old version" exts[i].latestVersion = "new version" } @@ -300,7 +300,7 @@ func TestManager_UpgradeExtensions_DryRun(t *testing.T) { exts, err := m.list(false) assert.NoError(t, err) assert.Equal(t, 3, len(exts)) - for i := 0; i < 3; i++ { + for i := range 3 { exts[i].currentVersion = fmt.Sprintf("%d", i) exts[i].latestVersion = fmt.Sprintf("%d", i+1) } @@ -1010,7 +1010,6 @@ func TestManager_Install_binary_pinned(t *testing.T) { assert.Equal(t, "", stdout.String()) assert.Equal(t, "", stderr.String()) - } func TestManager_Install_binary_unsupported(t *testing.T) { diff --git a/pkg/cmd/factory/default_test.go b/pkg/cmd/factory/default_test.go index 7e0ed4af6..2edbe72be 100644 --- a/pkg/cmd/factory/default_test.go +++ b/pkg/cmd/factory/default_test.go @@ -675,7 +675,7 @@ func TestSSOURL(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if sso := r.URL.Query().Get("sso"); sso != "" { - w.Header().Set("X-GitHub-SSO", sso) + w.Header().Set("X-Github-Sso", sso) } w.WriteHeader(http.StatusNoContent) })) @@ -734,7 +734,7 @@ func TestPlainHttpClient(t *testing.T) { assert.Equal(t, 204, res.StatusCode) assert.Equal(t, []string{"GitHub CLI v1.2.3"}, receivedHeaders.Values("User-Agent")) - assert.Equal(t, []string{"2022-11-28"}, receivedHeaders.Values("X-GitHub-Api-Version")) + assert.Equal(t, []string{"2022-11-28"}, receivedHeaders.Values("X-Github-Api-Version")) assert.Nil(t, receivedHeaders.Values("Authorization")) assert.Nil(t, receivedHeaders.Values("Content-Type")) assert.Nil(t, receivedHeaders.Values("Accept")) diff --git a/pkg/cmd/gist/create/create.go b/pkg/cmd/gist/create/create.go index 06b2336b6..04429ddfd 100644 --- a/pkg/cmd/gist/create/create.go +++ b/pkg/cmd/gist/create/create.go @@ -105,7 +105,6 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co } func createRun(opts *CreateOptions) error { - readFromStdInArg, filenames := cmdutil.Partition(opts.Filenames, func(f string) bool { return f == "-" }) diff --git a/pkg/cmd/gist/delete/delete_test.go b/pkg/cmd/gist/delete/delete_test.go index 2c4df8d8d..cb938d6f2 100644 --- a/pkg/cmd/gist/delete/delete_test.go +++ b/pkg/cmd/gist/delete/delete_test.go @@ -292,7 +292,6 @@ func Test_deleteRun(t *testing.T) { return 0, nil }) } - } tt.opts.Prompter = pm diff --git a/pkg/cmd/gist/edit/edit.go b/pkg/cmd/gist/edit/edit.go index 6f00c906c..68414359c 100644 --- a/pkg/cmd/gist/edit/edit.go +++ b/pkg/cmd/gist/edit/edit.go @@ -335,12 +335,11 @@ func editRun(opts *EditOptions) error { break } - choice := "" result, err := opts.Prompter.Select("What next?", "", editNextOptions) if err != nil { return fmt.Errorf("could not prompt: %w", err) } - choice = editNextOptions[result] + choice := editNextOptions[result] stop := false diff --git a/pkg/cmd/issue/create/create_test.go b/pkg/cmd/issue/create/create_test.go index 80c8f76d3..9ffac6a1c 100644 --- a/pkg/cmd/issue/create/create_test.go +++ b/pkg/cmd/issue/create/create_test.go @@ -1255,7 +1255,6 @@ func TestIssueCreate_projectsV2(t *testing.T) { // TODO projectsV1Deprecation // Remove this test. func TestProjectsV1Deprecation(t *testing.T) { - t.Run("non-interactive submission", func(t *testing.T) { t.Run("when projects v1 is supported, queries for it", func(t *testing.T) { ios, _, _, _ := iostreams.Test() diff --git a/pkg/cmd/issue/edit/edit.go b/pkg/cmd/issue/edit/edit.go index 11921096a..35b86fdf6 100644 --- a/pkg/cmd/issue/edit/edit.go +++ b/pkg/cmd/issue/edit/edit.go @@ -21,6 +21,8 @@ import ( ) type EditOptions struct { + prShared.Editable + HttpClient func() (*http.Client, error) IO *iostreams.IOStreams BaseRepo func() (ghrepo.Interface, error) @@ -34,8 +36,6 @@ type EditOptions struct { IssueNumbers []int Interactive bool - - prShared.Editable } func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Command { diff --git a/pkg/cmd/issue/lock/lock.go b/pkg/cmd/issue/lock/lock.go index 2f332d21d..a97f57ed9 100644 --- a/pkg/cmd/issue/lock/lock.go +++ b/pkg/cmd/issue/lock/lock.go @@ -327,7 +327,6 @@ func lockLockable(httpClient *http.Client, repo ghrepo.Interface, lockable *api. // unlockLockable will unlock an issue or pull request func unlockLockable(httpClient *http.Client, repo ghrepo.Interface, lockable *api.Issue) error { - var mutation struct { UnlockLockable struct { UnlockedRecord struct { diff --git a/pkg/cmd/issue/shared/lookup_test.go b/pkg/cmd/issue/shared/lookup_test.go index f921ca49b..a5704caf0 100644 --- a/pkg/cmd/issue/shared/lookup_test.go +++ b/pkg/cmd/issue/shared/lookup_test.go @@ -74,7 +74,6 @@ func TestParseIssuesFromArgs(t *testing.T) { assert.Equal(t, tc.expectedRepo, repo) }) } - } func TestFindIssuesOrPRs(t *testing.T) { diff --git a/pkg/cmd/label/clone.go b/pkg/cmd/label/clone.go index a02c4764a..67984ac20 100644 --- a/pkg/cmd/label/clone.go +++ b/pkg/cmd/label/clone.go @@ -120,7 +120,7 @@ func cloneLabels(client *http.Client, destination ghrepo.Interface, opts *cloneO toCreate := make(chan createOptions) wg, ctx := errgroup.WithContext(context.Background()) - for i := 0; i < workers; i++ { + for range workers { wg.Go(func() error { for { select { diff --git a/pkg/cmd/pr/checkout/checkout_test.go b/pkg/cmd/pr/checkout/checkout_test.go index 496139423..bb92775bb 100644 --- a/pkg/cmd/pr/checkout/checkout_test.go +++ b/pkg/cmd/pr/checkout/checkout_test.go @@ -363,6 +363,7 @@ func Test_checkoutRun(t *testing.T) { } func TestSpecificPRResolver(t *testing.T) { + t.Parallel() t.Run("when the PR Finder returns results, those are returned", func(t *testing.T) { t.Parallel() @@ -398,6 +399,7 @@ func TestSpecificPRResolver(t *testing.T) { } func TestPromptingPRResolver(t *testing.T) { + t.Parallel() t.Run("when the PR Lister has results, then we prompt for a choice", func(t *testing.T) { t.Parallel() diff --git a/pkg/cmd/pr/create/create.go b/pkg/cmd/pr/create/create.go index 0dbdb3987..d67731095 100644 --- a/pkg/cmd/pr/create/create.go +++ b/pkg/cmd/pr/create/create.go @@ -540,7 +540,6 @@ func createRun(opts *CreateOptions) error { return err } } else { - if !opts.TitleProvided { err = shared.TitleSurvey(opts.Prompter, opts.IO, state) if err != nil { diff --git a/pkg/cmd/pr/create/create_test.go b/pkg/cmd/pr/create/create_test.go index ed2a9cf2e..baec719e0 100644 --- a/pkg/cmd/pr/create/create_test.go +++ b/pkg/cmd/pr/create/create_test.go @@ -2632,7 +2632,6 @@ func mockRetrieveProjects(_ *testing.T, reg *httpmock.Registry) { // TODO projectsV1Deprecation // Remove this test. func TestProjectsV1Deprecation(t *testing.T) { - t.Run("non-interactive submission", func(t *testing.T) { t.Run("when projects v1 is supported, queries for it", func(t *testing.T) { ios, _, _, _ := iostreams.Test() diff --git a/pkg/cmd/pr/diff/diff.go b/pkg/cmd/pr/diff/diff.go index 4d0ee80a3..cf6ad259e 100644 --- a/pkg/cmd/pr/diff/diff.go +++ b/pkg/cmd/pr/diff/diff.go @@ -341,7 +341,9 @@ type sanitizer struct{ transform.NopResetter } // Transform implements transform.Transformer. func (t sanitizer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { - for r, size := rune(0), 0; nSrc < len(src); { + var r rune + var size int + for nSrc < len(src) { if r = rune(src[nSrc]); r < utf8.RuneSelf { size = 1 } else if r, size = utf8.DecodeRune(src[nSrc:]); size == 1 && !atEOF && !utf8.FullRune(src[nSrc:]) { @@ -355,7 +357,7 @@ func (t sanitizer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err e err = transform.ErrShortDst break } - for i := 0; i < size; i++ { + for range size { dst[nDst] = src[nSrc] nDst++ nSrc++ diff --git a/pkg/cmd/pr/edit/edit.go b/pkg/cmd/pr/edit/edit.go index 157fc8f8a..f28a9afd2 100644 --- a/pkg/cmd/pr/edit/edit.go +++ b/pkg/cmd/pr/edit/edit.go @@ -22,6 +22,8 @@ import ( ) type EditOptions struct { + shared.Editable + HttpClient func() (*http.Client, error) IO *iostreams.IOStreams @@ -35,8 +37,6 @@ type EditOptions struct { SelectorArg string Interactive bool - - shared.Editable } func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Command { diff --git a/pkg/cmd/pr/revert/revert_test.go b/pkg/cmd/pr/revert/revert_test.go index a4e5fbe95..49e1a6efc 100644 --- a/pkg/cmd/pr/revert/revert_test.go +++ b/pkg/cmd/pr/revert/revert_test.go @@ -87,7 +87,6 @@ func TestPRRevert_acceptedIdentifierFormats(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - http := &httpmock.Registry{} defer http.Verify(t) diff --git a/pkg/cmd/pr/shared/display_test.go b/pkg/cmd/pr/shared/display_test.go index 89fdef129..0b466edcc 100644 --- a/pkg/cmd/pr/shared/display_test.go +++ b/pkg/cmd/pr/shared/display_test.go @@ -164,5 +164,4 @@ func TestPrCheckStatusSummaryWithColor(t *testing.T) { out := PrCheckStatusSummaryWithColor(cs, testCase.args) assert.Equal(t, testCase.want, out) } - } diff --git a/pkg/cmd/pr/shared/editable.go b/pkg/cmd/pr/shared/editable.go index 1b7c42be3..d294329ba 100644 --- a/pkg/cmd/pr/shared/editable.go +++ b/pkg/cmd/pr/shared/editable.go @@ -45,6 +45,7 @@ type EditableSlice struct { // It contains a flag to indicate whether the assignees are actors or not. type EditableAssignees struct { EditableSlice + ActorAssignees bool DefaultLogins []string // For disambiguating actors from display names } @@ -52,6 +53,7 @@ type EditableAssignees struct { // EditableReviewers is a special case of EditableSlice. type EditableReviewers struct { EditableSlice + DefaultLogins []string // For disambiguating actors from display names } @@ -59,6 +61,7 @@ type EditableReviewers struct { // Keep that map along with standard EditableSlice data. type EditableProjects struct { EditableSlice + ProjectItems map[string]string } diff --git a/pkg/cmd/pr/shared/find_refs_resolution_test.go b/pkg/cmd/pr/shared/find_refs_resolution_test.go index d2393bf10..424ce881c 100644 --- a/pkg/cmd/pr/shared/find_refs_resolution_test.go +++ b/pkg/cmd/pr/shared/find_refs_resolution_test.go @@ -484,7 +484,6 @@ func TestTryDetermineDefaultPRHead(t *testing.T) { require.Equal(t, "feature-branch", defaultPRHead.BranchName) }) }) - } func dummyRemotesFn() (ghContext.Remotes, error) { diff --git a/pkg/cmd/pr/shared/git_cached_config_client.go b/pkg/cmd/pr/shared/git_cached_config_client.go index aea25abee..b65df507e 100644 --- a/pkg/cmd/pr/shared/git_cached_config_client.go +++ b/pkg/cmd/pr/shared/git_cached_config_client.go @@ -9,8 +9,8 @@ import ( var _ GitConfigClient = &CachedBranchConfigGitConfigClient{} type CachedBranchConfigGitConfigClient struct { - CachedBranchConfig git.BranchConfig GitConfigClient + CachedBranchConfig git.BranchConfig } func (c CachedBranchConfigGitConfigClient) ReadBranchConfig(ctx context.Context, branchName string) (git.BranchConfig, error) { diff --git a/pkg/cmd/pr/shared/lister.go b/pkg/cmd/pr/shared/lister.go index cd140a950..4a7a609ed 100644 --- a/pkg/cmd/pr/shared/lister.go +++ b/pkg/cmd/pr/shared/lister.go @@ -167,7 +167,6 @@ func (m *mockLister) List(opt ListOptions) (*api.PullRequestAndTotalCount, error } if m.expectFields != nil { - if !isEqualSet(m.expectFields, opt.Fields) { return nil, fmt.Errorf("unexpected fields: %v", opt.Fields) } diff --git a/pkg/cmd/pr/shared/survey.go b/pkg/cmd/pr/shared/survey.go index cc66bbe5c..303f2e372 100644 --- a/pkg/cmd/pr/shared/survey.go +++ b/pkg/cmd/pr/shared/survey.go @@ -25,7 +25,9 @@ const ( EditCommitMessageAction EditCommitSubjectAction SubmitDraftAction +) +const ( noMilestone = "(none)" submitLabel = "Submit" @@ -35,14 +37,7 @@ const ( cancelLabel = "Cancel" ) -type Prompt interface { - Input(prompt string, defaultValue string) (string, error) - Select(prompt string, defaultValue string, options []string) (int, error) - MarkdownEditor(prompt string, defaultValue string, blankAllowed bool) (string, error) - Confirm(prompt string, defaultValue bool) (bool, error) - MultiSelect(prompt string, defaults []string, options []string) ([]int, error) - MultiSelectWithSearch(prompt, searchPrompt string, defaults []string, persistentOptions []string, searchFunc func(string) prompter.MultiSelectSearchResult) ([]string, error) -} +type Prompt = EditPrompter func ConfirmIssueSubmission(p Prompt, allowPreview bool, allowMetadata bool) (Action, error) { return confirmSubmission(p, allowPreview, allowMetadata, false, false) diff --git a/pkg/cmd/pr/shared/templates.go b/pkg/cmd/pr/shared/templates.go index b8c9ea719..9313467a8 100644 --- a/pkg/cmd/pr/shared/templates.go +++ b/pkg/cmd/pr/shared/templates.go @@ -189,9 +189,9 @@ func (m *templateManager) Choose() (Template, error) { return nil, nil } - names := make([]string, len(m.templates)) - for i, t := range m.templates { - names[i] = t.Name() + names := make([]string, 0, len(m.templates)) + for _, t := range m.templates { + names = append(names, t.Name()) } blankOption := "Open a blank issue" diff --git a/pkg/cmd/pr/status/status.go b/pkg/cmd/pr/status/status.go index 60202594f..33a6bd1af 100644 --- a/pkg/cmd/pr/status/status.go +++ b/pkg/cmd/pr/status/status.go @@ -298,7 +298,6 @@ func printPrs(io *iostreams.IOStreams, totalCount int, prs ...api.PullRequest) { if pr.AutoMergeRequest != nil { fmt.Fprintf(w, " %s", cs.Green("✓ Auto-merge enabled")) } - } else { fmt.Fprintf(w, " - %s", shared.StateTitleWithColor(cs, pr)) } diff --git a/pkg/cmd/project/delete/delete.go b/pkg/cmd/project/delete/delete.go index b396a2f1f..2b8de6604 100644 --- a/pkg/cmd/project/delete/delete.go +++ b/pkg/cmd/project/delete/delete.go @@ -100,7 +100,6 @@ func runDelete(config deleteConfig) error { } return printResults(config, query.DeleteProject.Project) - } func deleteItemArgs(config deleteConfig) (*deleteProjectMutation, map[string]interface{}) { diff --git a/pkg/cmd/project/item-add/item_add.go b/pkg/cmd/project/item-add/item_add.go index 00c610f0d..5f78ddfd4 100644 --- a/pkg/cmd/project/item-add/item_add.go +++ b/pkg/cmd/project/item-add/item_add.go @@ -111,7 +111,6 @@ func runAddItem(config addItemConfig) error { } return printResults(config, query.CreateProjectItem.ProjectV2Item) - } func addItemArgs(config addItemConfig) (*addProjectItemMutation, map[string]interface{}) { diff --git a/pkg/cmd/project/item-delete/item_delete.go b/pkg/cmd/project/item-delete/item_delete.go index df5df20e9..ec276caad 100644 --- a/pkg/cmd/project/item-delete/item_delete.go +++ b/pkg/cmd/project/item-delete/item_delete.go @@ -104,7 +104,6 @@ func runDeleteItem(config deleteItemConfig) error { } return printResults(config) - } func deleteItemArgs(config deleteItemConfig) (*deleteProjectItemMutation, map[string]interface{}) { diff --git a/pkg/cmd/project/link/link.go b/pkg/cmd/project/link/link.go index f2477dde4..0c752b66e 100644 --- a/pkg/cmd/project/link/link.go +++ b/pkg/cmd/project/link/link.go @@ -110,7 +110,6 @@ func NewCmdLink(f *cmdutil.Factory, runF func(config linkConfig) error) *cobra.C } func validateRepoOrTeamFlag(opts *linkOpts) error { - linkedTarget := "" if opts.repo != "" { linkedTarget = opts.repo diff --git a/pkg/cmd/project/mark-template/mark_template.go b/pkg/cmd/project/mark-template/mark_template.go index 170dda821..badd33db9 100644 --- a/pkg/cmd/project/mark-template/mark_template.go +++ b/pkg/cmd/project/mark-template/mark_template.go @@ -111,7 +111,6 @@ func runMarkTemplate(config markTemplateConfig) error { } return printResults(config, query.TemplateProject.Project) - } query, variables := markTemplateArgs(config) err = config.client.Mutate("MarkProjectTemplate", query, variables) diff --git a/pkg/cmd/project/shared/queries/export_data_test.go b/pkg/cmd/project/shared/queries/export_data_test.go index 25e3fbace..742c34171 100644 --- a/pkg/cmd/project/shared/queries/export_data_test.go +++ b/pkg/cmd/project/shared/queries/export_data_test.go @@ -324,7 +324,6 @@ func TestJSONProjectItem_DraftIssue_ProjectV2ItemFieldIterationValue(t *testing. t, `{"items":[{"sprint":{"title":"Iteration Title","startDate":"","duration":0,"iterationId":"iterationId"},"content":{"type":"DraftIssue","body":"a body","title":"Pull Request title","id":"draftIssueId"},"id":"draftIssueId"}],"totalCount":5}`, string(out)) - } func TestJSONProjectItem_DraftIssue_ProjectV2ItemFieldMilestoneValue(t *testing.T) { @@ -363,5 +362,4 @@ func TestJSONProjectItem_DraftIssue_ProjectV2ItemFieldMilestoneValue(t *testing. t, `{"items":[{"milestone":{"title":"Milestone Title","dueOn":"","description":""},"content":{"type":"DraftIssue","body":"a body","title":"Pull Request title","id":"draftIssueId"},"id":"draftIssueId"}],"totalCount":5}`, string(out)) - } diff --git a/pkg/cmd/project/shared/queries/queries.go b/pkg/cmd/project/shared/queries/queries.go index 9a3bd4909..138697e2d 100644 --- a/pkg/cmd/project/shared/queries/queries.go +++ b/pkg/cmd/project/shared/queries/queries.go @@ -61,6 +61,7 @@ type iprompter interface { type hostScopedClient struct { *api.Client + hostname string } @@ -207,6 +208,7 @@ type projectQueryBase struct { type projectQueryWithQueryableItems struct { projectQueryBase + Items struct { PageInfo PageInfo TotalCount int @@ -216,6 +218,7 @@ type projectQueryWithQueryableItems struct { type projectQueryWithoutQueryableItems struct { projectQueryBase + Items struct { PageInfo PageInfo TotalCount int @@ -1753,7 +1756,6 @@ func projectFieldValueData(v FieldValueNodes) interface{} { } } return names - } return nil diff --git a/pkg/cmd/project/shared/queries/queries_test.go b/pkg/cmd/project/shared/queries/queries_test.go index cc4850d86..33970abf0 100644 --- a/pkg/cmd/project/shared/queries/queries_test.go +++ b/pkg/cmd/project/shared/queries/queries_test.go @@ -408,7 +408,6 @@ func TestProjects_ViewerQueryDoesNotUseQueryItems(t *testing.T) { } func TestProjectFields_LowerLimit(t *testing.T) { - defer gock.Off() gock.Observe(gock.DumpRequest) @@ -605,7 +604,6 @@ func TestNewOwner_nonTTY(t *testing.T) { client := NewTestClient() _, err := client.NewOwner(false, "") assert.EqualError(t, err, "owner is required when not running interactively") - } func TestProjectItems_FieldTitle(t *testing.T) { diff --git a/pkg/cmd/project/unlink/unlink.go b/pkg/cmd/project/unlink/unlink.go index 8cc2c0747..e4ec1cede 100644 --- a/pkg/cmd/project/unlink/unlink.go +++ b/pkg/cmd/project/unlink/unlink.go @@ -110,7 +110,6 @@ func NewCmdUnlink(f *cmdutil.Factory, runF func(config unlinkConfig) error) *cob } func validateRepoOrTeamFlag(opts *unlinkOpts) error { - unlinkedTarget := "" if opts.repo != "" { unlinkedTarget = opts.repo diff --git a/pkg/cmd/project/view/view_test.go b/pkg/cmd/project/view/view_test.go index 557c9732f..a88b9358b 100644 --- a/pkg/cmd/project/view/view_test.go +++ b/pkg/cmd/project/view/view_test.go @@ -160,7 +160,6 @@ func TestRunView_User(t *testing.T) { err := runView(config) assert.NoError(t, err) - } func TestRunView_Viewer(t *testing.T) { diff --git a/pkg/cmd/release/create/create.go b/pkg/cmd/release/create/create.go index 8771b2477..56ca9d133 100644 --- a/pkg/cmd/release/create/create.go +++ b/pkg/cmd/release/create/create.go @@ -253,9 +253,9 @@ func createRun(opts *CreateOptions) error { } if len(tags) != 0 { - options := make([]string, len(tags)) - for i, tag := range tags { - options[i] = tag.Name + options := make([]string, 0, len(tags)+1) + for _, tag := range tags { + options = append(options, tag.Name) } createNewTagOption := "Create a new tag" options = append(options, createNewTagOption) diff --git a/pkg/cmd/release/download/download.go b/pkg/cmd/release/download/download.go index b90721412..ce417bdb8 100644 --- a/pkg/cmd/release/download/download.go +++ b/pkg/cmd/release/download/download.go @@ -259,7 +259,7 @@ func downloadAssets(dest *destinationWriter, httpClient *http.Client, toDownload close(jobs) var downloadError error - for i := 0; i < len(toDownload); i++ { + for range toDownload { if err := <-results; err != nil && !errors.Is(err, errSkipped) { downloadError = err } diff --git a/pkg/cmd/release/shared/attestation.go b/pkg/cmd/release/shared/attestation.go index 65990290b..3d18c03b1 100644 --- a/pkg/cmd/release/shared/attestation.go +++ b/pkg/cmd/release/shared/attestation.go @@ -58,13 +58,13 @@ func (v *AttestationVerifier) VerifyAttestation(art *artifact.DigestedArtifact, func FilterAttestationsByTag(attestations []*api.Attestation, tagName string) ([]*api.Attestation, error) { var filtered []*api.Attestation for _, att := range attestations { - statement := att.Bundle.Bundle.GetDsseEnvelope().Payload + statement := att.Bundle.Bundle.GetDsseEnvelope().GetPayload() var statementData v1.Statement - err := protojson.Unmarshal([]byte(statement), &statementData) + err := protojson.Unmarshal(statement, &statementData) if err != nil { return nil, fmt.Errorf("failed to unmarshal statement: %w", err) } - tagValue := statementData.Predicate.GetFields()["tag"].GetStringValue() + tagValue := statementData.GetPredicate().GetFields()["tag"].GetStringValue() if tagValue == tagName { filtered = append(filtered, att) @@ -76,14 +76,14 @@ func FilterAttestationsByTag(attestations []*api.Attestation, tagName string) ([ func FilterAttestationsByFileDigest(attestations []*api.Attestation, fileDigest string) ([]*api.Attestation, error) { var filtered []*api.Attestation for _, att := range attestations { - statement := att.Bundle.Bundle.GetDsseEnvelope().Payload + statement := att.Bundle.Bundle.GetDsseEnvelope().GetPayload() var statementData v1.Statement - err := protojson.Unmarshal([]byte(statement), &statementData) + err := protojson.Unmarshal(statement, &statementData) if err != nil { return nil, fmt.Errorf("failed to unmarshal statement: %w", err) } - subjects := statementData.Subject + subjects := statementData.GetSubject() for _, subject := range subjects { digestMap := subject.GetDigest() alg := "sha256" @@ -93,7 +93,6 @@ func FilterAttestationsByFileDigest(attestations []*api.Attestation, fileDigest filtered = append(filtered, att) } } - } return filtered, nil } diff --git a/pkg/cmd/release/verify/verify.go b/pkg/cmd/release/verify/verify.go index 65516764e..eb6570637 100644 --- a/pkg/cmd/release/verify/verify.go +++ b/pkg/cmd/release/verify/verify.go @@ -192,25 +192,25 @@ func printVerifiedSubjects(io *iostreams.IOStreams, att *verification.Attestatio cs := io.ColorScheme() w := io.Out - statement := att.Attestation.Bundle.GetDsseEnvelope().Payload + statement := att.Attestation.Bundle.GetDsseEnvelope().GetPayload() var statementData v1.Statement - err := protojson.Unmarshal([]byte(statement), &statementData) + err := protojson.Unmarshal(statement, &statementData) if err != nil { return err } // If there aren't at least two subjects, there are no assets to display - if len(statementData.Subject) < 2 { + if len(statementData.GetSubject()) < 2 { return nil } fmt.Fprintln(w, cs.Bold("Assets")) table := tableprinter.New(io, tableprinter.WithHeader("Name", "Digest")) - for _, s := range statementData.Subject { - name := s.Name - digest := s.Digest + for _, s := range statementData.GetSubject() { + name := s.GetName() + digest := s.GetDigest() if name != "" { digestStr := "" diff --git a/pkg/cmd/repo/create/create.go b/pkg/cmd/repo/create/create.go index be0be2ddd..8b73b3106 100644 --- a/pkg/cmd/repo/create/create.go +++ b/pkg/cmd/repo/create/create.go @@ -158,7 +158,6 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co if opts.Name == "" && !opts.Interactive { return cmdutil.FlagErrorf("name argument required to create new remote repository") } - } else if opts.Clone || opts.GitIgnoreTemplate != "" || opts.LicenseTemplate != "" || opts.Template != "" { return cmdutil.FlagErrorf("the `--source` option is not supported with `--clone`, `--template`, `--license`, or `--gitignore`") } @@ -428,7 +427,6 @@ func createFromScratch(opts *CreateOptions) error { } else if err := cloneWithRetry(opts, remoteURL, templateRepoMainBranch); err != nil { return err } - } return nil @@ -762,7 +760,7 @@ func hasCommits(gitClient *git.Client) (bool, error) { var execError *exec.ExitError if errors.As(err, &execError) { - exitCode := int(execError.ExitCode()) + exitCode := execError.ExitCode() if exitCode == 128 { return false, nil } @@ -784,7 +782,7 @@ func localRepoType(gitClient *git.Client) (repoType, error) { if projectDirErr != nil { var execError errWithExitCode if errors.As(projectDirErr, &execError) { - if exitCode := int(execError.ExitCode()); exitCode == 128 { + if exitCode := execError.ExitCode(); exitCode == 128 { return unknown, nil } return unknown, projectDirErr diff --git a/pkg/cmd/repo/create/create_test.go b/pkg/cmd/repo/create/create_test.go index 5f1f17e60..dd8937fde 100644 --- a/pkg/cmd/repo/create/create_test.go +++ b/pkg/cmd/repo/create/create_test.go @@ -258,7 +258,6 @@ func Test_createRun(t *testing.T) { reg.Register( httpmock.REST("POST", "user/repos"), httpmock.StringResponse(`{"name":"REPO", "owner":{"login": "OWNER"}, "html_url":"https://github.com/OWNER/REPO"}`)) - }, execStubs: func(cs *run.CommandStubber) { cs.Register(`git clone https://github.com/OWNER/REPO.git`, 0, "") diff --git a/pkg/cmd/repo/credits/credits.go b/pkg/cmd/repo/credits/credits.go index a26b6a731..5d4608102 100644 --- a/pkg/cmd/repo/credits/credits.go +++ b/pkg/cmd/repo/credits/credits.go @@ -198,12 +198,12 @@ func creditsRun(opts *CreditsOptions) error { margin := termWidth / 3 starLinesLeft := []string{} - for x := 0; x < len(lines); x++ { + for range lines { starLinesLeft = append(starLinesLeft, starLine(r, margin)) } starLinesRight := []string{} - for x := 0; x < len(lines); x++ { + for x := range lines { lineWidth := termWidth - (margin + len(lines[x])) starLinesRight = append(starLinesRight, starLine(r, lineWidth)) } @@ -248,7 +248,7 @@ func creditsRun(opts *CreditsOptions) error { func starLine(r *rand.Rand, width int) string { line := "" starChance := 0.1 - for y := 0; y < width; y++ { + for range width { chance := r.Float64() if chance <= starChance { charRoll := r.Float64() diff --git a/pkg/cmd/repo/edit/edit.go b/pkg/cmd/repo/edit/edit.go index aff7a5fe1..f47c8f856 100644 --- a/pkg/cmd/repo/edit/edit.go +++ b/pkg/cmd/repo/edit/edit.go @@ -607,7 +607,7 @@ func setTopics(ctx context.Context, httpClient *http.Client, repo ghrepo.Interfa return err } - req.Header.Set("Content-type", "application/json") + req.Header.Set("Content-Type", "application/json") // "mercy-preview" is still needed for some GitHub Enterprise versions req.Header.Set("Accept", "application/vnd.github.mercy-preview+json") res, err := httpClient.Do(req) diff --git a/pkg/cmd/repo/fork/fork.go b/pkg/cmd/repo/fork/fork.go index 3ebb02413..76a6fad0c 100644 --- a/pkg/cmd/repo/fork/fork.go +++ b/pkg/cmd/repo/fork/fork.go @@ -170,7 +170,6 @@ func forkRun(opts *ForkOptions) error { if err != nil { return fmt.Errorf("did not understand argument: %w", err) } - } else if strings.HasPrefix(repoArg, "git@") { parsedURL, err := git.ParseURL(repoArg) if err != nil { diff --git a/pkg/cmd/repo/garden/garden.go b/pkg/cmd/repo/garden/garden.go index d9342f9cb..097a4a34f 100644 --- a/pkg/cmd/repo/garden/garden.go +++ b/pkg/cmd/repo/garden/garden.go @@ -285,7 +285,7 @@ func gardenRun(opts *GardenOptions) error { sl := statusLine(garden, player, opts.IO) fmt.Fprint(out, "\033[;H") // move to top left - for y := 0; y < player.Geo.Height-1; y++ { + for range player.Geo.Height - 1 { fmt.Fprint(out, "\033[B") } fmt.Fprintln(out) @@ -342,12 +342,12 @@ func plantGarden(r *rand.Rand, commits []*Commit, geo *Geometry) [][]*Cell { streamIx-- } tint := 0 - for y := 0; y < geo.Height; y++ { + for y := range geo.Height { if cellIx == len(commits)-1 { break } garden = append(garden, []*Cell{}) - for x := 0; x < geo.Width; x++ { + for x := range geo.Width { if (y > 0 && (x == 0 || x == geo.Width-1)) || y == geo.Height-1 { garden[y] = append(garden[y], &Cell{ Char: RGB(0, 150, 0, "^"), @@ -417,7 +417,7 @@ func drawGarden(io *iostreams.IOStreams, garden [][]*Cell, player *Player) { sl := "" for y, gardenRow := range garden { for x, gardenCell := range gardenRow { - char := "" + var char string underPlayer := (player.X == x && player.Y == y) if underPlayer { sl = gardenCell.StatusLine diff --git a/pkg/cmd/repo/gitignore/list/list.go b/pkg/cmd/repo/gitignore/list/list.go index 89dbefaf3..a2e7964ed 100644 --- a/pkg/cmd/repo/gitignore/list/list.go +++ b/pkg/cmd/repo/gitignore/list/list.go @@ -31,7 +31,6 @@ func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman Aliases: []string{"ls"}, Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - if runF != nil { return runF(opts) } diff --git a/pkg/cmd/repo/license/list/list.go b/pkg/cmd/repo/license/list/list.go index ec003ad21..61e6f25a9 100644 --- a/pkg/cmd/repo/license/list/list.go +++ b/pkg/cmd/repo/license/list/list.go @@ -37,7 +37,6 @@ func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman Aliases: []string{"ls"}, Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - if runF != nil { return runF(opts) } diff --git a/pkg/cmd/run/list/list.go b/pkg/cmd/run/list/list.go index e6475d34a..87c00680f 100644 --- a/pkg/cmd/run/list/list.go +++ b/pkg/cmd/run/list/list.go @@ -175,7 +175,7 @@ func listRun(opts *ListOptions) error { tp.AddField(run.Title(), tableprinter.WithColor(cs.Bold)) tp.AddField(run.WorkflowName()) tp.AddField(run.HeadBranch, tableprinter.WithColor(cs.Bold)) - tp.AddField(string(run.Event)) + tp.AddField(run.Event) tp.AddField(fmt.Sprintf("%d", run.ID), tableprinter.WithColor(cs.Cyan)) tp.AddField(run.Duration(opts.now).String()) tp.AddTimeField(opts.now, run.StartedTime(), cs.Muted) diff --git a/pkg/cmd/run/rerun/rerun_test.go b/pkg/cmd/run/rerun/rerun_test.go index 77f0a922f..8e4687d19 100644 --- a/pkg/cmd/run/rerun/rerun_test.go +++ b/pkg/cmd/run/rerun/rerun_test.go @@ -160,7 +160,6 @@ func TestNewCmdRerun(t *testing.T) { assert.Equal(t, tt.wants.Prompt, gotOpts.Prompt) }) } - } func TestRerun(t *testing.T) { diff --git a/pkg/cmd/run/view/view.go b/pkg/cmd/run/view/view.go index bed9e3bfa..1fb2bd5dc 100644 --- a/pkg/cmd/run/view/view.go +++ b/pkg/cmd/run/view/view.go @@ -55,7 +55,6 @@ func (c RunLogCache) Create(key string, content io.Reader) error { if _, err := io.Copy(out, content); err != nil { return fmt.Errorf("writing cache entry: %v", err) - } return nil @@ -349,7 +348,7 @@ func runView(opts *ViewOptions) error { var artifacts []shared.Artifact if selectedJob == nil { - artifacts, err = shared.ListArtifacts(httpClient, repo, strconv.FormatInt(int64(run.ID), 10)) + artifacts, err = shared.ListArtifacts(httpClient, repo, strconv.FormatInt(run.ID, 10)) if err != nil { return fmt.Errorf("failed to get artifacts: %w", err) } diff --git a/pkg/cmd/search/shared/shared.go b/pkg/cmd/search/shared/shared.go index 1989bb9d3..1c30558c4 100644 --- a/pkg/cmd/search/shared/shared.go +++ b/pkg/cmd/search/shared/shared.go @@ -21,7 +21,9 @@ const ( // Limitation of GitHub search see: // https://docs.github.com/en/rest/reference/search SearchMaxResults = 1000 +) +const ( Both EntityType = iota Issues PullRequests diff --git a/pkg/cmd/secret/set/set.go b/pkg/cmd/secret/set/set.go index 40f2fac0d..944a6341e 100644 --- a/pkg/cmd/secret/set/set.go +++ b/pkg/cmd/secret/set/set.go @@ -171,7 +171,6 @@ func NewCmdSet(f *cmdutil.Factory, runF func(*SetOptions) error) *cobra.Command if opts.Visibility == shared.Selected && (len(opts.RepositoryNames) == 0 && !noRepositoriesSelected) { return cmdutil.FlagErrorf("`--repos` or `--no-repos-selected` required with `--visibility=selected`") } - } else { if len(opts.RepositoryNames) > 0 || noRepositoriesSelected { opts.Visibility = shared.Selected @@ -297,7 +296,7 @@ func setRun(opts *SetOptions) error { var errs []error cs := opts.IO.ColorScheme() - for i := 0; i < len(secrets); i++ { + for range len(secrets) { result := <-setc if result.err != nil { errs = append(errs, result.err) diff --git a/pkg/cmd/secret/set/set_test.go b/pkg/cmd/secret/set/set_test.go index 38c0fb5a9..940cb49dd 100644 --- a/pkg/cmd/secret/set/set_test.go +++ b/pkg/cmd/secret/set/set_test.go @@ -805,7 +805,7 @@ func Test_getBodyPrompt(t *testing.T) { func Test_getSecretsFromOptions(t *testing.T) { genFile := func(s string) string { - f, err := os.CreateTemp("", "gh-env.*") + f, err := os.CreateTemp(t.TempDir(), "gh-env.*") if err != nil { t.Fatal(err) return "" diff --git a/pkg/cmd/ssh-key/shared/user_keys.go b/pkg/cmd/ssh-key/shared/user_keys.go index 035d00244..97b3a6afe 100644 --- a/pkg/cmd/ssh-key/shared/user_keys.go +++ b/pkg/cmd/ssh-key/shared/user_keys.go @@ -37,7 +37,7 @@ func UserKeys(httpClient *http.Client, host, userHandle string) ([]sshKey, error return nil, err } - for i := 0; i < len(keys); i++ { + for i := range keys { keys[i].Type = AuthenticationKey } @@ -57,7 +57,7 @@ func UserSigningKeys(httpClient *http.Client, host, userHandle string) ([]sshKey return nil, err } - for i := 0; i < len(keys); i++ { + for i := range keys { keys[i].Type = SigningKey } diff --git a/pkg/cmd/status/status.go b/pkg/cmd/status/status.go index c9acce8bd..785b8405c 100644 --- a/pkg/cmd/status/status.go +++ b/pkg/cmd/status/status.go @@ -276,7 +276,7 @@ func (s *StatusGetter) LoadNotifications() error { fetched := make(chan StatusItem) wg := new(errgroup.Group) - for i := 0; i < fetchWorkers; i++ { + for range fetchWorkers { wg.Go(func() error { for { select { @@ -337,7 +337,7 @@ func (s *StatusGetter) LoadNotifications() error { // not work with PATs right now. nIndex := 0 p := fmt.Sprintf("notifications?%s", query.Encode()) - for pages := 0; pages < 3; pages++ { + for range 3 { var resp []Notification next, err := c.RESTWithNext(s.hostname(), "GET", p, nil, &resp) if err != nil { diff --git a/pkg/cmd/variable/set/set.go b/pkg/cmd/variable/set/set.go index 57f218221..2f924b651 100644 --- a/pkg/cmd/variable/set/set.go +++ b/pkg/cmd/variable/set/set.go @@ -203,7 +203,7 @@ func setRun(opts *SetOptions) error { var errs []error cs := opts.IO.ColorScheme() - for i := 0; i < len(variables); i++ { + for range len(variables) { result := <-setc if result.Err != nil { errs = append(errs, result.Err) diff --git a/pkg/cmd/variable/set/set_test.go b/pkg/cmd/variable/set/set_test.go index 4e77d5900..2120faf4d 100644 --- a/pkg/cmd/variable/set/set_test.go +++ b/pkg/cmd/variable/set/set_test.go @@ -477,7 +477,7 @@ func Test_getBody(t *testing.T) { func Test_getVariablesFromOptions(t *testing.T) { genFile := func(s string) string { - f, err := os.CreateTemp("", "gh-env.*") + f, err := os.CreateTemp(t.TempDir(), "gh-env.*") if err != nil { t.Fatal(err) return "" diff --git a/pkg/cmd/workflow/run/run_test.go b/pkg/cmd/workflow/run/run_test.go index a4e44e5da..d98dcfa60 100644 --- a/pkg/cmd/workflow/run/run_test.go +++ b/pkg/cmd/workflow/run/run_test.go @@ -315,7 +315,6 @@ jobs: assert.Equal(t, tt.wantOut, result) }) } - } func TestRun(t *testing.T) { @@ -994,7 +993,6 @@ jobs: pm.RegisterSelect("name", []string{"monalisa", "cschleiden"}, func(_, _ string, opts []string) (int, error) { return 0, nil }) - }, wantBody: map[string]interface{}{ "inputs": map[string]interface{}{ @@ -1052,7 +1050,6 @@ jobs: pm.RegisterSelect("name", []string{"monalisa", "cschleiden"}, func(_, _ string, opts []string) (int, error) { return 0, nil }) - }, wantBody: map[string]interface{}{ "inputs": map[string]interface{}{ diff --git a/pkg/cmd/workflow/shared/shared_test.go b/pkg/cmd/workflow/shared/shared_test.go index cd53b667c..c73c95dbb 100644 --- a/pkg/cmd/workflow/shared/shared_test.go +++ b/pkg/cmd/workflow/shared/shared_test.go @@ -412,7 +412,7 @@ func TestGetWorkflows(t *testing.T) { func generateWorkflows(t *testing.T, workflowCount int, pageNum int) []Workflow { t.Helper() workflows := []Workflow{} - for i := 0; i < workflowCount; i++ { + for i := range workflowCount { workflows = append(workflows, Workflow{ Name: fmt.Sprintf("Workflow-%d-%d", pageNum, i), ID: int64(i) + int64(pageNum-1)*100, diff --git a/pkg/cmd/workflow/view/view.go b/pkg/cmd/workflow/view/view.go index 2e550f496..2e9ef2081 100644 --- a/pkg/cmd/workflow/view/view.go +++ b/pkg/cmd/workflow/view/view.go @@ -252,7 +252,7 @@ func viewWorkflowInfo(opts *ViewOptions, client *api.Client, repo ghrepo.Interfa tp.AddField(run.WorkflowName()) tp.AddField(run.HeadBranch, tableprinter.WithColor(cs.Bold)) - tp.AddField(string(run.Event)) + tp.AddField(run.Event) if opts.Raw { tp.AddField(run.Duration(opts.now).String()) diff --git a/pkg/cmdutil/json_flags.go b/pkg/cmdutil/json_flags.go index 579d38552..f07b00aae 100644 --- a/pkg/cmdutil/json_flags.go +++ b/pkg/cmdutil/json_flags.go @@ -52,7 +52,6 @@ func addTemplateFlag(f *pflag.FlagSet, shorthand string) { } func setupJsonFlags(cmd *cobra.Command, exportTarget *Exporter, fields []string) { - _ = cmd.RegisterFlagCompletionFunc("json", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { var results []string var prefix string @@ -264,7 +263,7 @@ func (e *jsonExporter) exportData(v reflect.Value) interface{} { } case reflect.Slice: a := make([]interface{}, v.Len()) - for i := 0; i < v.Len(); i++ { + for i := range v.Len() { a[i] = e.exportData(v.Index(i)) } return a diff --git a/pkg/cmdutil/json_flags_test.go b/pkg/cmdutil/json_flags_test.go index ee089960b..422add77b 100644 --- a/pkg/cmdutil/json_flags_test.go +++ b/pkg/cmdutil/json_flags_test.go @@ -142,7 +142,6 @@ func TestAddJSONFlagsWithoutShorthand(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - cmd := &cobra.Command{Run: func(*cobra.Command, []string) {}} tt.setFlags(cmd) diff --git a/pkg/githubtemplate/github_template_test.go b/pkg/githubtemplate/github_template_test.go index 20709f7e6..6ae6803bd 100644 --- a/pkg/githubtemplate/github_template_test.go +++ b/pkg/githubtemplate/github_template_test.go @@ -8,19 +8,10 @@ import ( ) func TestFindNonLegacy(t *testing.T) { - tmpdir, err := os.MkdirTemp("", "gh-cli") - if err != nil { - t.Fatal(err) - } - - type args struct { - rootDir string - name string - } tests := []struct { name string prepare []string - args args + argName string want []string }{ { @@ -34,11 +25,8 @@ func TestFindNonLegacy(t *testing.T) { ".github/issue_template.md", "docs/issue_template.md", }, - args: args{ - rootDir: tmpdir, - name: "ISSUE_TEMPLATE", - }, - want: []string{}, + argName: "ISSUE_TEMPLATE", + want: []string{}, }, { name: "Template folder in .github takes precedence", @@ -48,13 +36,8 @@ func TestFindNonLegacy(t *testing.T) { "ISSUE_TEMPLATE/abc.md", ".github/ISSUE_TEMPLATE/abc.md", }, - args: args{ - rootDir: tmpdir, - name: "ISSUE_TEMPLATE", - }, - want: []string{ - path.Join(tmpdir, ".github/ISSUE_TEMPLATE/abc.md"), - }, + argName: "ISSUE_TEMPLATE", + want: []string{".github/ISSUE_TEMPLATE/abc.md"}, }, { name: "Template folder in root", @@ -63,13 +46,8 @@ func TestFindNonLegacy(t *testing.T) { "docs/ISSUE_TEMPLATE/abc.md", "ISSUE_TEMPLATE/abc.md", }, - args: args{ - rootDir: tmpdir, - name: "ISSUE_TEMPLATE", - }, - want: []string{ - path.Join(tmpdir, "ISSUE_TEMPLATE/abc.md"), - }, + argName: "ISSUE_TEMPLATE", + want: []string{"ISSUE_TEMPLATE/abc.md"}, }, { name: "Template folder in docs", @@ -77,13 +55,8 @@ func TestFindNonLegacy(t *testing.T) { "ISSUE_TEMPLATE.md", "docs/ISSUE_TEMPLATE/abc.md", }, - args: args{ - rootDir: tmpdir, - name: "ISSUE_TEMPLATE", - }, - want: []string{ - path.Join(tmpdir, "docs/ISSUE_TEMPLATE/abc.md"), - }, + argName: "ISSUE_TEMPLATE", + want: []string{"docs/ISSUE_TEMPLATE/abc.md"}, }, { name: "Multiple templates in template folder", @@ -95,14 +68,11 @@ func TestFindNonLegacy(t *testing.T) { ".github/PULL_REQUEST_TEMPLATE/three.md", "docs/pull_request_template.md", }, - args: args{ - rootDir: tmpdir, - name: "PuLl_ReQuEsT_TeMpLaTe", - }, + argName: "PuLl_ReQuEsT_TeMpLaTe", want: []string{ - path.Join(tmpdir, ".github/PULL_REQUEST_TEMPLATE/one.md"), - path.Join(tmpdir, ".github/PULL_REQUEST_TEMPLATE/three.md"), - path.Join(tmpdir, ".github/PULL_REQUEST_TEMPLATE/two.md"), + ".github/PULL_REQUEST_TEMPLATE/one.md", + ".github/PULL_REQUEST_TEMPLATE/three.md", + ".github/PULL_REQUEST_TEMPLATE/two.md", }, }, { @@ -112,15 +82,13 @@ func TestFindNonLegacy(t *testing.T) { ".docs/ISSUE_TEMPLATE/.keep", "ISSUE_TEMPLATE/.keep", }, - args: args{ - rootDir: tmpdir, - name: "ISSUE_TEMPLATE", - }, - want: []string{}, + argName: "ISSUE_TEMPLATE", + want: []string{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + tmpdir := t.TempDir() for _, p := range tt.prepare { fp := path.Join(tmpdir, p) _ = os.MkdirAll(path.Dir(fp), 0700) @@ -131,28 +99,22 @@ func TestFindNonLegacy(t *testing.T) { file.Close() } - if got := FindNonLegacy(tt.args.rootDir, tt.args.name); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Find() = %v, want %v", got, tt.want) + want := make([]string, len(tt.want)) + for i, w := range tt.want { + want[i] = path.Join(tmpdir, w) + } + if got := FindNonLegacy(tmpdir, tt.argName); !reflect.DeepEqual(got, want) { + t.Errorf("Find() = %v, want %v", got, want) } }) - os.RemoveAll(tmpdir) } } func TestFindLegacy(t *testing.T) { - tmpdir, err := os.MkdirTemp("", "gh-cli") - if err != nil { - t.Fatal(err) - } - - type args struct { - rootDir string - name string - } tests := []struct { name string prepare []string - args args + argName string want string }{ { @@ -164,11 +126,8 @@ func TestFindLegacy(t *testing.T) { "pull_request_template.md", "docs/issue_template.md", }, - args: args{ - rootDir: tmpdir, - name: "ISSUE_TEMPLATE", - }, - want: path.Join(tmpdir, "issue_template.md"), + argName: "ISSUE_TEMPLATE", + want: "issue_template.md", }, { name: "No extension", @@ -177,11 +136,8 @@ func TestFindLegacy(t *testing.T) { "issue_template", "docs/issue_template.md", }, - args: args{ - rootDir: tmpdir, - name: "ISSUE_TEMPLATE", - }, - want: path.Join(tmpdir, "issue_template"), + argName: "ISSUE_TEMPLATE", + want: "issue_template", }, { name: "Dash instead of underscore", @@ -190,11 +146,8 @@ func TestFindLegacy(t *testing.T) { "issue-template.txt", "docs/issue_template.md", }, - args: args{ - rootDir: tmpdir, - name: "ISSUE_TEMPLATE", - }, - want: path.Join(tmpdir, "issue-template.txt"), + argName: "ISSUE_TEMPLATE", + want: "issue-template.txt", }, { name: "Template in .github takes precedence", @@ -203,11 +156,8 @@ func TestFindLegacy(t *testing.T) { ".github/issue_template.md", "docs/issue_template.md", }, - args: args{ - rootDir: tmpdir, - name: "ISSUE_TEMPLATE", - }, - want: path.Join(tmpdir, ".github/issue_template.md"), + argName: "ISSUE_TEMPLATE", + want: ".github/issue_template.md", }, { name: "Template in docs", @@ -215,11 +165,8 @@ func TestFindLegacy(t *testing.T) { "README.md", "docs/issue_template.md", }, - args: args{ - rootDir: tmpdir, - name: "ISSUE_TEMPLATE", - }, - want: path.Join(tmpdir, "docs/issue_template.md"), + argName: "ISSUE_TEMPLATE", + want: "docs/issue_template.md", }, { name: "Non legacy templates ignored", @@ -229,15 +176,13 @@ func TestFindLegacy(t *testing.T) { "docs/PULL_REQUEST_TEMPLATE/abc.md", ".github/PULL_REQUEST_TEMPLATE.md", }, - args: args{ - rootDir: tmpdir, - name: "PuLl_ReQuEsT_TeMpLaTe", - }, - want: path.Join(tmpdir, ".github/PULL_REQUEST_TEMPLATE.md"), + argName: "PuLl_ReQuEsT_TeMpLaTe", + want: ".github/PULL_REQUEST_TEMPLATE.md", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + tmpdir := t.TempDir() for _, p := range tt.prepare { fp := path.Join(tmpdir, p) _ = os.MkdirAll(path.Dir(fp), 0700) @@ -248,14 +193,14 @@ func TestFindLegacy(t *testing.T) { file.Close() } - got := FindLegacy(tt.args.rootDir, tt.args.name) + want := path.Join(tmpdir, tt.want) + got := FindLegacy(tmpdir, tt.argName) if got == "" { - t.Errorf("FindLegacy() = nil, want %v", tt.want) - } else if got != tt.want { - t.Errorf("FindLegacy() = %v, want %v", got, tt.want) + t.Errorf("FindLegacy() = nil, want %v", want) + } else if got != want { + t.Errorf("FindLegacy() = %v, want %v", got, want) } }) - os.RemoveAll(tmpdir) } } diff --git a/pkg/iostreams/iostreams.go b/pkg/iostreams/iostreams.go index 22f966ac8..d0ed0e031 100644 --- a/pkg/iostreams/iostreams.go +++ b/pkg/iostreams/iostreams.go @@ -582,6 +582,7 @@ func (w *pagerWriter) Write(d []byte) (int, error) { // fdWriter represents a wrapped stdout Writer that preserves the original file descriptor type fdWriter struct { io.Writer + fd uintptr } @@ -592,6 +593,7 @@ func (w *fdWriter) Fd() uintptr { // fdWriteCloser represents a wrapped stdout Writer that preserves the original file descriptor type fdWriteCloser struct { io.WriteCloser + fd uintptr } @@ -602,6 +604,7 @@ func (w *fdWriteCloser) Fd() uintptr { // fdReader represents a wrapped stdin ReadCloser that preserves the original file descriptor type fdReader struct { io.ReadCloser + fd uintptr } diff --git a/pkg/option/option_test.go b/pkg/option/option_test.go index 0f28dd5d4..95948f3a5 100644 --- a/pkg/option/option_test.go +++ b/pkg/option/option_test.go @@ -60,7 +60,7 @@ func ExampleOption_UnwrapOrZero() { fmt.Println(o.Some(4).UnwrapOrZero()) fmt.Println(o.None[int]().UnwrapOrZero()) - // Output + // Output: // 4 // 0 } diff --git a/pkg/search/query.go b/pkg/search/query.go index f6e7fc05d..19d0b587b 100644 --- a/pkg/search/query.go +++ b/pkg/search/query.go @@ -238,7 +238,7 @@ func (q Qualifiers) Map() map[string][]string { m := map[string][]string{} v := reflect.ValueOf(q) t := reflect.TypeOf(q) - for i := 0; i < v.NumField(); i++ { + for i := range v.NumField() { fieldName := t.Field(i).Name key := camelToKebab(fieldName) typ := v.FieldByName(fieldName).Kind() @@ -255,7 +255,7 @@ func (q Qualifiers) Map() map[string][]string { continue } s := []string{} - for i := 0; i < value.Len(); i++ { + for i := range value.Len() { if value.Index(i).IsZero() { continue } diff --git a/pkg/surveyext/editor.go b/pkg/surveyext/editor.go index 82533f913..21af8a216 100644 --- a/pkg/surveyext/editor.go +++ b/pkg/surveyext/editor.go @@ -34,6 +34,7 @@ func init() { // EXTENDED to enable different prompting behavior type GhEditor struct { *survey.Editor + EditorCommand string BlankAllowed bool @@ -56,6 +57,7 @@ var EditorQuestionTemplate = ` // EXTENDED to pass editor name (to use in prompt) type EditorTemplateData struct { survey.Editor + EditorCommand string BlankAllowed bool Answer string diff --git a/pkg/surveyext/editor_test.go b/pkg/surveyext/editor_test.go index dae5e5273..9b60b5de9 100644 --- a/pkg/surveyext/editor_test.go +++ b/pkg/surveyext/editor_test.go @@ -252,6 +252,7 @@ func (t *testTerminal) Stdio() terminal.Stdio { // teeWriter is a writer that duplicates all writes to a file into a buffer type teeWriter struct { *os.File + buf bytes.Buffer mu sync.Mutex }