From 6dec05d89e10f432378baf1f101b99b8664540b9 Mon Sep 17 00:00:00 2001 From: CHIKAMATSU Naohiro Date: Tue, 21 Feb 2023 23:30:50 +0900 Subject: [PATCH 01/14] Add directory --- cmd/.gitkeep | 0 config/.gitkeep | 0 domain/model/.gitkeep | 0 domain/repository/.gitkeep | 0 domain/service/.gitkeep | 0 infrastructure/http/.gitkeep | 0 6 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 cmd/.gitkeep create mode 100644 config/.gitkeep create mode 100644 domain/model/.gitkeep create mode 100644 domain/repository/.gitkeep create mode 100644 domain/service/.gitkeep create mode 100644 infrastructure/http/.gitkeep diff --git a/cmd/.gitkeep b/cmd/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/config/.gitkeep b/config/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/domain/model/.gitkeep b/domain/model/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/domain/repository/.gitkeep b/domain/repository/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/domain/service/.gitkeep b/domain/service/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/infrastructure/http/.gitkeep b/infrastructure/http/.gitkeep new file mode 100644 index 0000000..e69de29 From e21da38f635fb5af869bfc942340903898c94e42 Mon Sep 17 00:00:00 2001 From: CHIKAMATSU Naohiro Date: Tue, 21 Feb 2023 23:59:11 +0900 Subject: [PATCH 02/14] Add Config & Argument struct --- config/config.go | 25 +++++++++++++++++++++++++ config/config_test.go | 25 +++++++++++++++++++++++++ go.mod | 2 ++ go.sum | 2 ++ 4 files changed, 54 insertions(+) create mode 100644 config/config.go create mode 100644 config/config_test.go create mode 100644 go.sum diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..c956deb --- /dev/null +++ b/config/config.go @@ -0,0 +1,25 @@ +// Package config get setting from environment variable or configuration file. +package config + +// Config represents configuration information for the leadtime CLI command. +// For example, include GitHub API access information. +type Config struct { + // GitHubAccessToken is access token for GitHub API. + GitHubAccessToken string +} + +// Argument represents the argument for leadtime CLI startup. +type Argument struct { + // GitHubOwner is GitHun owner name(e.g. nao1215) + GitHubOwner string + // GitHubRepository is GitHub repository name(e.g. leadtime) + GitHubRepository string +} + +// NewArgument initialize Argument struct. +func NewArgument(owner, repo string) *Argument { + return &Argument{ + GitHubOwner: owner, + GitHubRepository: repo, + } +} diff --git a/config/config_test.go b/config/config_test.go new file mode 100644 index 0000000..b3a9440 --- /dev/null +++ b/config/config_test.go @@ -0,0 +1,25 @@ +// Package config get setting from environment variable or configuration file. +package config + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestNewArgument(t *testing.T) { + t.Parallel() + t.Run("new argument", func(t *testing.T) { + t.Parallel() + + want := &Argument{ + GitHubOwner: "nao1215", + GitHubRepository: "leadtime", + } + + got := NewArgument(want.GitHubOwner, want.GitHubRepository) + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + }) +} diff --git a/go.mod b/go.mod index 7f69cfd..0a8d980 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module github.com/nao1215/leadtime go 1.20 + +require github.com/google/go-cmp v0.5.9 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..62841cd --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= From 0002a4c88dc316b3cac3b6a226190e14612c3408 Mon Sep 17 00:00:00 2001 From: CHIKAMATSU Naohiro Date: Wed, 22 Feb 2023 23:39:52 +0900 Subject: [PATCH 03/14] add ListRepositories() --- domain/model/.gitkeep | 0 domain/model/github.go | 22 ++++ go.mod | 15 ++- go.sum | 29 +++++ infrastructure/github/error.go | 16 +++ infrastructure/github/error_test.go | 38 ++++++ infrastructure/github/github.go | 50 ++++++++ infrastructure/github/github_test.go | 179 +++++++++++++++++++++++++++ infrastructure/http/.gitkeep | 0 9 files changed, 348 insertions(+), 1 deletion(-) delete mode 100644 domain/model/.gitkeep create mode 100644 domain/model/github.go create mode 100644 infrastructure/github/error.go create mode 100644 infrastructure/github/error_test.go create mode 100644 infrastructure/github/github.go create mode 100644 infrastructure/github/github_test.go delete mode 100644 infrastructure/http/.gitkeep diff --git a/domain/model/.gitkeep b/domain/model/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/domain/model/github.go b/domain/model/github.go new file mode 100644 index 0000000..bbe1b77 --- /dev/null +++ b/domain/model/github.go @@ -0,0 +1,22 @@ +// Package model is domain model and business logic. +package model + +// Repository represents GitHub repository information +type Repository struct { + // ID is repository id + ID *int64 `json:"id,omitempty"` + // Owner is repository owner + Owner *User `json:"owner,omitempty"` + // Name is repository name + Name *string `json:"name,omitempty"` + // FullName is repository full name + FullName *string `json:"full_name,omitempty"` + // Description is repository description + Description *string `json:"description,omitempty"` +} + +// User represents a GitHub user. +type User struct { + // Name is user name. + Name *string `json:"name,omitempty"` +} diff --git a/go.mod b/go.mod index 0a8d980..36c9f7a 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,17 @@ module github.com/nao1215/leadtime go 1.20 -require github.com/google/go-cmp v0.5.9 +require ( + github.com/google/go-cmp v0.5.9 + github.com/google/go-github/v50 v50.0.0 + golang.org/x/oauth2 v0.5.0 +) + +require ( + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/go-querystring v1.1.0 // indirect + golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect + golang.org/x/net v0.6.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.28.0 // indirect +) diff --git a/go.sum b/go.sum index 62841cd..68881ba 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,31 @@ +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-github/v50 v50.0.0 h1:gdO1AeuSZZK4iYWwVbjni7zg8PIQhp7QfmPunr016Jk= +github.com/google/go-github/v50 v50.0.0/go.mod h1:Ev4Tre8QoKiolvbpOSG3FIi4Mlon3S2Nt9W5JYqKiwA= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= diff --git a/infrastructure/github/error.go b/infrastructure/github/error.go new file mode 100644 index 0000000..6489eba --- /dev/null +++ b/infrastructure/github/error.go @@ -0,0 +1,16 @@ +package github + +import "fmt" + +// APIError is error for GitHub API. +type APIError struct { + // StatusCode is HTTP status code from GitHub. + StatusCode int + // Message is error message + Message string +} + +// Error return string that represents a GitHub API error +func (e *APIError) Error() string { + return fmt.Sprintf("GitHub API error: status code %d, message: %s", e.StatusCode, e.Message) +} diff --git a/infrastructure/github/error_test.go b/infrastructure/github/error_test.go new file mode 100644 index 0000000..db366c8 --- /dev/null +++ b/infrastructure/github/error_test.go @@ -0,0 +1,38 @@ +package github + +import ( + "net/http" + "testing" +) + +func TestAPIError_Error(t *testing.T) { + type fields struct { + StatusCode int + Message string + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "Get 401 error", + fields: fields{ + StatusCode: http.StatusUnauthorized, + Message: "unauthorized", + }, + want: "GitHub API error: status code 401, message: unauthorized", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := &APIError{ + StatusCode: tt.fields.StatusCode, + Message: tt.fields.Message, + } + if got := e.Error(); got != tt.want { + t.Errorf("APIError.Error() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/infrastructure/github/github.go b/infrastructure/github/github.go new file mode 100644 index 0000000..6217728 --- /dev/null +++ b/infrastructure/github/github.go @@ -0,0 +1,50 @@ +// Package github is http client for GitHub API. +// This package is wrapper for google/go-github package. +package github + +import ( + "context" + + "github.com/google/go-github/v50/github" + "github.com/nao1215/leadtime/domain/model" + "golang.org/x/oauth2" +) + +// Client is http client for GitHub API. +type Client struct { + // client is http client + client *github.Client +} + +// NewClient return http client for GitHub API. +func NewClient(token string) *Client { + tokenSource := oauth2.StaticTokenSource( + &oauth2.Token{AccessToken: token}, + ) + client := oauth2.NewClient(context.Background(), tokenSource) + return &Client{client: github.NewClient(client)} +} + +// ListRepositories return List the repositories for a user. +func (c *Client) ListRepositories(ctx context.Context) ([]*model.Repository, error) { + repos, resp, err := c.client.Repositories.List(ctx, "", nil) + if resp != nil { + defer resp.Body.Close() + } + if err != nil { + return nil, &APIError{StatusCode: resp.StatusCode, Message: "failed to gey repository list"} + } + + repoList := make([]*model.Repository, 0) + for _, v := range repos { + repo := &model.Repository{ + ID: v.ID, + Owner: &model.User{Name: v.Owner.Name}, + Name: v.Name, + FullName: v.FullName, + Description: v.Description, + } + repoList = append(repoList, repo) + } + return repoList, nil +} diff --git a/infrastructure/github/github_test.go b/infrastructure/github/github_test.go new file mode 100644 index 0000000..6033753 --- /dev/null +++ b/infrastructure/github/github_test.go @@ -0,0 +1,179 @@ +package github + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "net/url" + "strings" + "testing" + + "github.com/google/go-github/v50/github" + "github.com/nao1215/leadtime/domain/model" + + "github.com/google/go-cmp/cmp" +) + +func TestListRepositories(t *testing.T) { + t.Parallel() + + t.Run("Get repository list", func(t *testing.T) { + t.Parallel() + + token := "good_token" + client := NewClient(token) + ctx := context.Background() + + // Test server + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + respBody, err := json.Marshal([]github.Repository{ + { + ID: github.Int64(1), + Owner: &github.User{Name: github.String("user1")}, + Name: github.String("repo1"), + FullName: github.String("user1/repo1"), + Description: github.String("repo1 description"), + }, + { + ID: github.Int64(2), + Owner: &github.User{Name: github.String("user2")}, + Name: github.String("repo2"), + FullName: github.String("user2/repo2"), + Description: github.String("repo2 description"), + }, + }) + if err != nil { + t.Fatal(err) + } + w.WriteHeader(http.StatusOK) + w.Write(respBody) + })) + defer testServer.Close() + + testURL, err := url.Parse(testServer.URL) + if err != nil { + t.Fatal(err) + } + client.client.BaseURL = testURL + if !strings.HasSuffix(client.client.BaseURL.Path, "/") { + client.client.BaseURL.Path += "/" + } + + want := []*model.Repository{ + { + ID: github.Int64(1), + Owner: &model.User{Name: github.String("user1")}, + Name: github.String("repo1"), + FullName: github.String("user1/repo1"), + Description: github.String("repo1 description"), + }, + { + ID: github.Int64(2), + Owner: &model.User{Name: github.String("user2")}, + Name: github.String("repo2"), + FullName: github.String("user2/repo2"), + Description: github.String("repo2 description"), + }, + } + // test start + got, err := client.ListRepositories(ctx) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + }) + + t.Run("Return status code 500 from GitHub", func(t *testing.T) { + t.Parallel() + + token := "test_token" + client := NewClient(token) + ctx := context.Background() + + // Test server + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte("error message")) + })) + defer testServer.Close() + + testURL, err := url.Parse(testServer.URL) + if err != nil { + t.Fatal(err) + } + client.client.BaseURL = testURL + if !strings.HasSuffix(client.client.BaseURL.Path, "/") { + client.client.BaseURL.Path += "/" + } + + // test start + _, err = client.ListRepositories(ctx) + if err == nil { + t.Fatal("expect error occured, however got nil") + } + + apiErr, ok := err.(*APIError) + if !ok { + t.Fatalf("mismatch expect=%T, got=%T", &APIError{}, apiErr) + } + + if apiErr.StatusCode != http.StatusInternalServerError { + t.Errorf("mismatch expect=%d, got=%d", apiErr.StatusCode, http.StatusInternalServerError) + } + }) + + t.Run("Return status code 401 from GitHub", func(t *testing.T) { + t.Parallel() + + token := "bad_token" + client := NewClient(token) + ctx := context.Background() + + // Test server + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + respBody, err := json.Marshal([]github.Repository{ + { + ID: github.Int64(1), + Owner: &github.User{Name: github.String("user1")}, + Name: github.String("repo1"), + FullName: github.String("user1/repo1"), + Description: github.String("repo1 description"), + }, + }) + if err != nil { + t.Fatal(err) + } + w.WriteHeader(http.StatusUnauthorized) + w.Write(respBody) + })) + defer testServer.Close() + + testURL, err := url.Parse(testServer.URL) + if err != nil { + t.Fatal(err) + } + client.client.BaseURL = testURL + if !strings.HasSuffix(client.client.BaseURL.Path, "/") { + client.client.BaseURL.Path += "/" + } + + // test start + _, err = client.ListRepositories(ctx) + if err == nil { + t.Fatal("expect error occured, however got nil") + } + + apiErr, ok := err.(*APIError) + if !ok { + t.Fatalf("mismatch expect=%T, got=%T", &APIError{}, apiErr) + } + + if apiErr.StatusCode != http.StatusUnauthorized { + t.Errorf("mismatch expect=%d, got=%d", apiErr.StatusCode, http.StatusUnauthorized) + } + }) +} diff --git a/infrastructure/http/.gitkeep b/infrastructure/http/.gitkeep deleted file mode 100644 index e69de29..0000000 From 8c57bd478df976abd36581c4f718d9d6fef8a55a Mon Sep 17 00:00:00 2001 From: CHIKAMATSU Naohiro Date: Wed, 22 Feb 2023 23:44:10 +0900 Subject: [PATCH 04/14] Fix typo --- infrastructure/github/github_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/github/github_test.go b/infrastructure/github/github_test.go index 6033753..81c30e3 100644 --- a/infrastructure/github/github_test.go +++ b/infrastructure/github/github_test.go @@ -113,7 +113,7 @@ func TestListRepositories(t *testing.T) { // test start _, err = client.ListRepositories(ctx) if err == nil { - t.Fatal("expect error occured, however got nil") + t.Fatal("expect error occurred, however got nil") } apiErr, ok := err.(*APIError) @@ -164,7 +164,7 @@ func TestListRepositories(t *testing.T) { // test start _, err = client.ListRepositories(ctx) if err == nil { - t.Fatal("expect error occured, however got nil") + t.Fatal("expect error occurred, however got nil") } apiErr, ok := err.(*APIError) From f2787c74f121d1cda58613946d8b19f3fbaeed00 Mon Sep 17 00:00:00 2001 From: CHIKAMATSU Naohiro Date: Wed, 22 Feb 2023 23:47:10 +0900 Subject: [PATCH 05/14] Add tagliatelle setting --- .golangci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.golangci.yml b/.golangci.yml index 36a2a99..d2cb2a6 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -55,3 +55,9 @@ linters: - unparam - wastedassign - whitespace +linters-settings: + tagliatelle: + case: + use-field-name: true + rules: + json: snake From a7bd90e8ba0fb3949443754ddba85aed5cd4993a Mon Sep 17 00:00:00 2001 From: CHIKAMATSU Naohiro Date: Wed, 22 Feb 2023 23:51:43 +0900 Subject: [PATCH 06/14] Add t.Parallel() --- infrastructure/github/error_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/infrastructure/github/error_test.go b/infrastructure/github/error_test.go index db366c8..5936946 100644 --- a/infrastructure/github/error_test.go +++ b/infrastructure/github/error_test.go @@ -6,6 +6,8 @@ import ( ) func TestAPIError_Error(t *testing.T) { + t.Parallel() + type fields struct { StatusCode int Message string @@ -25,7 +27,10 @@ func TestAPIError_Error(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() + e := &APIError{ StatusCode: tt.fields.StatusCode, Message: tt.fields.Message, From af162f2065c751fd248d255c60e898f97fa76ea8 Mon Sep 17 00:00:00 2001 From: CHIKAMATSU Naohiro Date: Wed, 22 Feb 2023 23:53:04 +0900 Subject: [PATCH 07/14] Fix: return with no blank line before (nlreturn) --- infrastructure/github/github.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/infrastructure/github/github.go b/infrastructure/github/github.go index 6217728..0cac5b1 100644 --- a/infrastructure/github/github.go +++ b/infrastructure/github/github.go @@ -22,6 +22,7 @@ func NewClient(token string) *Client { &oauth2.Token{AccessToken: token}, ) client := oauth2.NewClient(context.Background(), tokenSource) + return &Client{client: github.NewClient(client)} } @@ -46,5 +47,6 @@ func (c *Client) ListRepositories(ctx context.Context) ([]*model.Repository, err } repoList = append(repoList, repo) } + return repoList, nil } From c77724bbf6f58305de46020271701be62c4e68c1 Mon Sep 17 00:00:00 2001 From: CHIKAMATSU Naohiro Date: Wed, 22 Feb 2023 23:53:45 +0900 Subject: [PATCH 08/14] comment out exhaustivestruct --- .golangci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.golangci.yml b/.golangci.yml index d2cb2a6..0df96fd 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -25,7 +25,7 @@ linters: - durationcheck - errorlint - exhaustive - - exhaustivestruct + #- exhaustivestruct - exportloopref - forcetypeassert - funlen From 48b0f38180a6a285b190f2efbbf5d8e579e7570e Mon Sep 17 00:00:00 2001 From: CHIKAMATSU Naohiro Date: Wed, 22 Feb 2023 23:56:26 +0900 Subject: [PATCH 09/14] Comment out funlen --- .golangci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.golangci.yml b/.golangci.yml index 0df96fd..5513ce4 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -28,7 +28,7 @@ linters: #- exhaustivestruct - exportloopref - forcetypeassert - - funlen + # - funlen - gci - gochecknoglobals - gochecknoinits From 8c0e2d126e985e35b636afaa0a61eb8a0c711996 Mon Sep 17 00:00:00 2001 From: CHIKAMATSU Naohiro Date: Wed, 22 Feb 2023 23:57:46 +0900 Subject: [PATCH 10/14] Comment out gci --- .golangci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.golangci.yml b/.golangci.yml index 5513ce4..0705099 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -29,7 +29,7 @@ linters: - exportloopref - forcetypeassert # - funlen - - gci + # - gci - gochecknoglobals - gochecknoinits - goconst From a28e4d9bb8f57400e02e1c70de3f0e8de56616f3 Mon Sep 17 00:00:00 2001 From: CHIKAMATSU Naohiro Date: Wed, 22 Feb 2023 23:58:58 +0900 Subject: [PATCH 11/14] Cooment out cyclop --- .golangci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.golangci.yml b/.golangci.yml index 0705099..fcd1fdf 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -19,7 +19,7 @@ linters: - varcheck - asciicheck - bodyclose - - cyclop + #- cyclop - dogsled - dupl - durationcheck From e95a477b3d07432dca8cba169781ec050a5fce8e Mon Sep 17 00:00:00 2001 From: CHIKAMATSU Naohiro Date: Thu, 23 Feb 2023 00:13:15 +0900 Subject: [PATCH 12/14] Use errors.As --- infrastructure/github/github.go | 4 +++- infrastructure/github/github_test.go | 27 ++++++++++++++++++--------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/infrastructure/github/github.go b/infrastructure/github/github.go index 0cac5b1..d9c5c7f 100644 --- a/infrastructure/github/github.go +++ b/infrastructure/github/github.go @@ -30,7 +30,9 @@ func NewClient(token string) *Client { func (c *Client) ListRepositories(ctx context.Context) ([]*model.Repository, error) { repos, resp, err := c.client.Repositories.List(ctx, "", nil) if resp != nil { - defer resp.Body.Close() + defer func() error { + return resp.Body.Close() + }() } if err != nil { return nil, &APIError{StatusCode: resp.StatusCode, Message: "failed to gey repository list"} diff --git a/infrastructure/github/github_test.go b/infrastructure/github/github_test.go index 81c30e3..3edb76f 100644 --- a/infrastructure/github/github_test.go +++ b/infrastructure/github/github_test.go @@ -3,6 +3,7 @@ package github import ( "context" "encoding/json" + "errors" "net/http" "net/http/httptest" "net/url" @@ -47,7 +48,9 @@ func TestListRepositories(t *testing.T) { t.Fatal(err) } w.WriteHeader(http.StatusOK) - w.Write(respBody) + if _, err := w.Write(respBody); err != nil { + t.Fatal(err) + } })) defer testServer.Close() @@ -97,7 +100,9 @@ func TestListRepositories(t *testing.T) { // Test server testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("error message")) + if _, err := w.Write([]byte("error message")); err != nil { + t.Fatal(err) + } })) defer testServer.Close() @@ -116,11 +121,12 @@ func TestListRepositories(t *testing.T) { t.Fatal("expect error occurred, however got nil") } - apiErr, ok := err.(*APIError) - if !ok { - t.Fatalf("mismatch expect=%T, got=%T", &APIError{}, apiErr) + var apiError *APIError + if !errors.As(err, &apiError) { + t.Fatalf("mismatch expect=%T, got=%T", &APIError{}, err) } + apiErr := err.(*APIError) if apiErr.StatusCode != http.StatusInternalServerError { t.Errorf("mismatch expect=%d, got=%d", apiErr.StatusCode, http.StatusInternalServerError) } @@ -148,7 +154,9 @@ func TestListRepositories(t *testing.T) { t.Fatal(err) } w.WriteHeader(http.StatusUnauthorized) - w.Write(respBody) + if _, err := w.Write(respBody); err != nil { + t.Fatal(err) + } })) defer testServer.Close() @@ -167,11 +175,12 @@ func TestListRepositories(t *testing.T) { t.Fatal("expect error occurred, however got nil") } - apiErr, ok := err.(*APIError) - if !ok { - t.Fatalf("mismatch expect=%T, got=%T", &APIError{}, apiErr) + var apiError *APIError + if !errors.As(err, &apiError) { + t.Fatalf("mismatch expect=%T, got=%T", &APIError{}, err) } + apiErr := err.(*APIError) if apiErr.StatusCode != http.StatusUnauthorized { t.Errorf("mismatch expect=%d, got=%d", apiErr.StatusCode, http.StatusUnauthorized) } From 76d46fe034d9d05f1240de52e162a40a45aca1dd Mon Sep 17 00:00:00 2001 From: CHIKAMATSU Naohiro Date: Thu, 23 Feb 2023 10:37:06 +0900 Subject: [PATCH 13/14] Check response.Body.Close() --- infrastructure/github/github.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/infrastructure/github/github.go b/infrastructure/github/github.go index d9c5c7f..518136b 100644 --- a/infrastructure/github/github.go +++ b/infrastructure/github/github.go @@ -4,6 +4,7 @@ package github import ( "context" + "fmt" "github.com/google/go-github/v50/github" "github.com/nao1215/leadtime/domain/model" @@ -31,7 +32,10 @@ func (c *Client) ListRepositories(ctx context.Context) ([]*model.Repository, err repos, resp, err := c.client.Repositories.List(ctx, "", nil) if resp != nil { defer func() error { - return resp.Body.Close() + if err != resp.Body.Close() { + return fmt.Errorf("failed to close response body: %w", err) + } + return nil }() } if err != nil { From 8ed027bca785f3479a9f21df1345132ee96e2411 Mon Sep 17 00:00:00 2001 From: CHIKAMATSU Naohiro Date: Thu, 23 Feb 2023 10:38:49 +0900 Subject: [PATCH 14/14] Fix linter comment --- infrastructure/github/github.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/infrastructure/github/github.go b/infrastructure/github/github.go index 518136b..837bb4e 100644 --- a/infrastructure/github/github.go +++ b/infrastructure/github/github.go @@ -32,9 +32,10 @@ func (c *Client) ListRepositories(ctx context.Context) ([]*model.Repository, err repos, resp, err := c.client.Repositories.List(ctx, "", nil) if resp != nil { defer func() error { - if err != resp.Body.Close() { + if err := resp.Body.Close(); err != nil { return fmt.Errorf("failed to close response body: %w", err) } + return nil }() }