From 502460410ea867ea26cd430f06691b02d0cb941d Mon Sep 17 00:00:00 2001 From: Will Stull Date: Thu, 3 Aug 2023 12:46:00 -0400 Subject: [PATCH 1/6] feat: add Go modules and Go 1.19 compatibility --- .github/workflows/test.yml | 2 +- .gitignore | 1 + README.md | 2 + docker/example.go | 41 +++-- go.mod | 5 + go.sum | 7 + rest.go | 4 +- rest_test.go | 3 +- v2/go.mod | 5 + v2/go.sum | 7 + v2/rest.go | 161 ++++++++++++++++ v2/rest_test.go | 364 +++++++++++++++++++++++++++++++++++++ 12 files changed, 578 insertions(+), 24 deletions(-) create mode 100644 go.mod create mode 100644 go.sum create mode 100644 v2/go.mod create mode 100644 v2/go.sum create mode 100644 v2/rest.go create mode 100644 v2/rest_test.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2208ae5..aadb897 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,7 @@ jobs: timeout-minutes: 20 strategy: matrix: - go: [ '1.14', '1.15', '1.16', '1.17' ] + go: [ '1.14', '1.15', '1.16', '1.17', '1.18', '1.19' ] steps: - name: Checkout rest uses: actions/checkout@v2 diff --git a/.gitignore b/.gitignore index 60ef913..28aec86 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ _testmain.go .settings.json temp.go +.vscode diff --git a/README.md b/README.md index 8cfbb01..32b70e1 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,8 @@ This library supports the following Go implementations: * Go 1.15 * Go 1.16 * Go 1.17 +* Go 1.18 +* Go 1.19 ## Install Package diff --git a/docker/example.go b/docker/example.go index 8f4df54..4470bf3 100644 --- a/docker/example.go +++ b/docker/example.go @@ -1,24 +1,27 @@ package main -import "github.com/sendgrid/rest" -import "fmt" +import ( + "fmt" + + "github.com/sendgrid/rest" +) func main() { - const host = "https://httpbin.org" - param := "get" - endpoint := "/" + param - baseURL := host + endpoint - method := rest.Get - request := rest.Request{ - Method: method, - BaseURL: baseURL, - } - response, err := rest.Send(request) - if err != nil { - fmt.Println(err) - } else { - fmt.Println(response.StatusCode) - fmt.Println(response.Body) - fmt.Println(response.Headers) - } + const host = "https://httpbin.org" + param := "get" + endpoint := "/" + param + baseURL := host + endpoint + method := rest.Get + request := rest.Request{ + Method: method, + BaseURL: baseURL, + } + response, err := rest.Send(request) + if err != nil { + fmt.Println(err) + } else { + fmt.Println(response.StatusCode) + fmt.Println(response.Body) + fmt.Println(response.Headers) + } } diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..845acb7 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/sendgrid/rest + +go 1.14 + +require golang.org/x/net v0.0.0-20220708220712-1185a9018129 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..64cf5c2 --- /dev/null +++ b/go.sum @@ -0,0 +1,7 @@ +golang.org/x/net v0.0.0-20220708220712-1185a9018129 h1:vucSRfWwTsoXro7P+3Cjlr6flUMtzCwzlvkxEQtHHB0= +golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/rest.go b/rest.go index b3e578c..7aab0ff 100644 --- a/rest.go +++ b/rest.go @@ -4,7 +4,7 @@ package rest import ( "bytes" "context" - "io/ioutil" + "io" "net/http" "net/url" ) @@ -97,7 +97,7 @@ func MakeRequest(req *http.Request) (*http.Response, error) { // BuildResponse builds the response struct. func BuildResponse(res *http.Response) (*Response, error) { - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) response := Response{ StatusCode: res.StatusCode, Body: string(body), diff --git a/rest_test.go b/rest_test.go index 7ca4369..2a5aa80 100644 --- a/rest_test.go +++ b/rest_test.go @@ -3,7 +3,6 @@ package rest import ( "errors" "fmt" - "io/ioutil" "net/http" "net/http/httptest" "net/http/httputil" @@ -324,7 +323,7 @@ func TestRepoFiles(t *testing.T) { func TestLicenseYear(t *testing.T) { t.Parallel() - dat, err := ioutil.ReadFile("LICENSE") + dat, err := os.ReadFile("LICENSE") currentYear := time.Now().Year() r := fmt.Sprintf("%d", currentYear) diff --git a/v2/go.mod b/v2/go.mod new file mode 100644 index 0000000..6c00642 --- /dev/null +++ b/v2/go.mod @@ -0,0 +1,5 @@ +module github.com/sendgrid/rest/v2 + +go 1.14 + +require golang.org/x/net v0.0.0-20220708220712-1185a9018129 diff --git a/v2/go.sum b/v2/go.sum new file mode 100644 index 0000000..64cf5c2 --- /dev/null +++ b/v2/go.sum @@ -0,0 +1,7 @@ +golang.org/x/net v0.0.0-20220708220712-1185a9018129 h1:vucSRfWwTsoXro7P+3Cjlr6flUMtzCwzlvkxEQtHHB0= +golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/v2/rest.go b/v2/rest.go new file mode 100644 index 0000000..7aab0ff --- /dev/null +++ b/v2/rest.go @@ -0,0 +1,161 @@ +// Package rest allows for quick and easy access any REST or REST-like API. +package rest + +import ( + "bytes" + "context" + "io" + "net/http" + "net/url" +) + +// Version represents the current version of the rest library +const Version = "2.6.9" + +// Method contains the supported HTTP verbs. +type Method string + +// Supported HTTP verbs. +const ( + Get Method = "GET" + Post Method = "POST" + Put Method = "PUT" + Patch Method = "PATCH" + Delete Method = "DELETE" +) + +// Request holds the request to an API Call. +type Request struct { + Method Method + BaseURL string // e.g. https://api.sendgrid.com + Headers map[string]string + QueryParams map[string]string + Body []byte +} + +// RestError is a struct for an error handling. +type RestError struct { + Response *Response +} + +// Error is the implementation of the error interface. +func (e *RestError) Error() string { + return e.Response.Body +} + +// DefaultClient is used if no custom HTTP client is defined +var DefaultClient = &Client{HTTPClient: &http.Client{}} + +// Client allows modification of client headers, redirect policy +// and other settings +// See https://golang.org/pkg/net/http +type Client struct { + HTTPClient *http.Client +} + +// Response holds the response from an API call. +type Response struct { + StatusCode int // e.g. 200 + Body string // e.g. {"result: success"} + Headers map[string][]string // e.g. map[X-Ratelimit-Limit:[600]] +} + +// AddQueryParameters adds query parameters to the URL. +func AddQueryParameters(baseURL string, queryParams map[string]string) string { + baseURL += "?" + params := url.Values{} + for key, value := range queryParams { + params.Add(key, value) + } + return baseURL + params.Encode() +} + +// BuildRequestObject creates the HTTP request object. +func BuildRequestObject(request Request) (*http.Request, error) { + // Add any query parameters to the URL. + if len(request.QueryParams) != 0 { + request.BaseURL = AddQueryParameters(request.BaseURL, request.QueryParams) + } + req, err := http.NewRequest(string(request.Method), request.BaseURL, bytes.NewBuffer(request.Body)) + if err != nil { + return req, err + } + for key, value := range request.Headers { + req.Header.Set(key, value) + } + _, exists := req.Header["Content-Type"] + if len(request.Body) > 0 && !exists { + req.Header.Set("Content-Type", "application/json") + } + return req, err +} + +// MakeRequest makes the API call. +func MakeRequest(req *http.Request) (*http.Response, error) { + return DefaultClient.HTTPClient.Do(req) +} + +// BuildResponse builds the response struct. +func BuildResponse(res *http.Response) (*Response, error) { + body, err := io.ReadAll(res.Body) + response := Response{ + StatusCode: res.StatusCode, + Body: string(body), + Headers: res.Header, + } + res.Body.Close() // nolint + return &response, err +} + +// Deprecated: API supports old implementation +func API(request Request) (*Response, error) { + return Send(request) +} + +// Send uses the DefaultClient to send your request +func Send(request Request) (*Response, error) { + return SendWithContext(context.Background(), request) +} + +// SendWithContext uses the DefaultClient to send your request with the provided context. +func SendWithContext(ctx context.Context, request Request) (*Response, error) { + return DefaultClient.SendWithContext(ctx, request) +} + +// The following functions enable the ability to define a +// custom HTTP Client + +// MakeRequest makes the API call. +func (c *Client) MakeRequest(req *http.Request) (*http.Response, error) { + return c.HTTPClient.Do(req) +} + +// Deprecated: API supports old implementation +func (c *Client) API(request Request) (*Response, error) { + return c.Send(request) +} + +// Send will build your request, make the request, and build your response. +func (c *Client) Send(request Request) (*Response, error) { + return c.SendWithContext(context.Background(), request) +} + +// SendWithContext will build your request passing in the provided context, make the request, and build your response. +func (c *Client) SendWithContext(ctx context.Context, request Request) (*Response, error) { + // Build the HTTP request object. + req, err := BuildRequestObject(request) + if err != nil { + return nil, err + } + // Pass in the user provided context + req = req.WithContext(ctx) + + // Build the HTTP client and make the request. + res, err := c.MakeRequest(req) + if err != nil { + return nil, err + } + + // Build Response object. + return BuildResponse(res) +} diff --git a/v2/rest_test.go b/v2/rest_test.go new file mode 100644 index 0000000..535e098 --- /dev/null +++ b/v2/rest_test.go @@ -0,0 +1,364 @@ +package rest + +import ( + "errors" + "fmt" + "net/http" + "net/http/httptest" + "net/http/httputil" + "os" + "regexp" + "strings" + "testing" + "time" + + "golang.org/x/net/context" +) + +func TestBuildURL(t *testing.T) { + t.Parallel() + host := "http://api.test.com" + queryParams := make(map[string]string) + queryParams["test"] = "1" + queryParams["test2"] = "2" + testURL := AddQueryParameters(host, queryParams) + if testURL != "http://api.test.com?test=1&test2=2" { + t.Error("Bad BuildURL result") + } +} + +func TestBuildRequest(t *testing.T) { + t.Parallel() + method := Get + baseURL := "http://api.test.com" + key := "API_KEY" + Headers := make(map[string]string) + Headers["Content-Type"] = "application/json" + Headers["Authorization"] = "Bearer " + key + queryParams := make(map[string]string) + queryParams["test"] = "1" + queryParams["test2"] = "2" + request := Request{ + Method: method, + BaseURL: baseURL, + Headers: Headers, + QueryParams: queryParams, + } + req, e := BuildRequestObject(request) + if e != nil { + t.Errorf("Rest failed to BuildRequest. Returned error: %v", e) + } + if req == nil { + t.Errorf("Failed to BuildRequest.") + } + + //Start PrintRequest + requestDump, err := httputil.DumpRequest(req, true) + if err != nil { + t.Errorf("Error : %v", err) + } + fmt.Println("Request : ", string(requestDump)) + //End Print Request +} + +func TestBuildBadRequest(t *testing.T) { + t.Parallel() + request := Request{ + Method: Method("@"), + } + req, e := BuildRequestObject(request) + if e == nil { + t.Errorf("Expected an error for a bad HTTP Method") + } + if req != nil { + t.Errorf("If there's an error there shouldn't be a Request.") + } +} + +func TestBuildBadAPI(t *testing.T) { + t.Parallel() + request := Request{ + Method: Method("@"), + } + res, e := API(request) + if e == nil { + t.Errorf("Expected an error for a bad HTTP Method") + } + if res != nil { + t.Errorf("If there's an error there shouldn't be a Response.") + } +} + +func TestBuildResponse(t *testing.T) { + t.Parallel() + fakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "{\"message\": \"success\"}") + })) + defer fakeServer.Close() + baseURL := fakeServer.URL + method := Get + request := Request{ + Method: method, + BaseURL: baseURL, + } + req, e := BuildRequestObject(request) + if e != nil { + t.Error("Failed to BuildRequestObject", e) + } + res, e := MakeRequest(req) + if e != nil { + t.Error("Failed to MakeRequest", e) + } + response, e := BuildResponse(res) + if response.StatusCode != 200 { + t.Error("Invalid status code in BuildResponse") + } + if len(response.Body) == 0 { + t.Error("Invalid response body in BuildResponse") + } + if len(response.Headers) == 0 { + t.Error("Invalid response headers in BuildResponse") + } + if e != nil { + t.Errorf("Rest failed to make a valid API request. Returned error: %v", e) + } + + //Start Print Request + requestDump, err := httputil.DumpRequest(req, true) + if err != nil { + t.Errorf("Error : %v", err) + } + fmt.Println("Request :", string(requestDump)) + //End Print Request + +} + +type panicResponse struct{} + +func (*panicResponse) Read([]byte) (n int, err error) { + return 0, errors.New("test error") +} + +func (*panicResponse) Close() error { + return nil +} + +func TestBuildBadResponse(t *testing.T) { + t.Parallel() + res := &http.Response{ + Body: new(panicResponse), + } + _, e := BuildResponse(res) + if e == nil { + t.Errorf("This was a bad response and error should be returned") + } +} + +func TestRest(t *testing.T) { + t.Parallel() + testingAPI(t, Send) + testingAPI(t, API) +} + +func testingAPI(t *testing.T, fn func(request Request) (*Response, error)) { + fakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "{\"message\": \"success\"}") + })) + defer fakeServer.Close() + + host := fakeServer.URL + endpoint := "/test_endpoint" + baseURL := host + endpoint + key := "API_KEY" + Headers := make(map[string]string) + Headers["Content-Type"] = "application/json" + Headers["Authorization"] = "Bearer " + key + method := Get + queryParams := make(map[string]string) + queryParams["test"] = "1" + queryParams["test2"] = "2" + request := Request{ + Method: method, + BaseURL: baseURL, + Headers: Headers, + QueryParams: queryParams, + } + + //Start Print Request + req, e := BuildRequestObject(request) + if e != nil { + t.Errorf("Error during BuildRequestObject: %v", e) + } + requestDump, err := httputil.DumpRequest(req, true) + if err != nil { + t.Errorf("Error : %v", err) + } + fmt.Println("Request :", string(requestDump)) + //End Print Request + + response, e := fn(request) + + if response.StatusCode != 200 { + t.Error("Invalid status code") + } + if len(response.Body) == 0 { + t.Error("Invalid response body") + } + if len(response.Headers) == 0 { + t.Error("Invalid response headers") + } + if e != nil { + t.Errorf("Rest failed to make a valid API request. Returned error: %v", e) + } +} + +func TestDefaultContentTypeWithBody(t *testing.T) { + t.Parallel() + host := "http://localhost" + method := Get + request := Request{ + Method: method, + BaseURL: host, + Body: []byte("Hello World"), + } + + response, _ := BuildRequestObject(request) + if response.Header.Get("Content-Type") != "application/json" { + t.Error("Content-Type not set to the correct default value when a body is set.") + } + + //Start Print Request + fmt.Println("Request Body: ", string(request.Body)) + + requestDump, err := httputil.DumpRequest(response, true) + if err != nil { + t.Errorf("Error : %v", err) + } + fmt.Println("Request :", string(requestDump)) + //End Print Request +} + +func TestCustomContentType(t *testing.T) { + t.Parallel() + host := "http://localhost" + Headers := make(map[string]string) + Headers["Content-Type"] = "custom" + method := Get + request := Request{ + Method: method, + BaseURL: host, + Headers: Headers, + Body: []byte("Hello World"), + } + response, _ := BuildRequestObject(request) + if response.Header.Get("Content-Type") != "custom" { + t.Error("Content-Type not modified correctly") + } + + //Start Print Request + requestDump, err := httputil.DumpRequest(response, true) + if err != nil { + t.Errorf("Error : %v", err) + } + fmt.Println("Request :", string(requestDump)) + //End Print Request +} + +func TestCustomHTTPClient(t *testing.T) { + t.Parallel() + fakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + time.Sleep(time.Millisecond * 20) + fmt.Fprintln(w, "{\"message\": \"success\"}") + })) + defer fakeServer.Close() + host := fakeServer.URL + endpoint := "/test_endpoint" + baseURL := host + endpoint + method := Get + request := Request{ + Method: method, + BaseURL: baseURL, + } + + customClient := &Client{&http.Client{Timeout: time.Millisecond * 10}} + _, err := customClient.Send(request) + if err == nil { + t.Error("A timeout did not trigger as expected") + } + if !strings.Contains(err.Error(), "Client.Timeout exceeded while awaiting headers") { + t.Error("We did not receive the Timeout error") + } +} + +func TestRestError(t *testing.T) { + t.Parallel() + headers := make(map[string][]string) + headers["Content-Type"] = []string{"application/json"} + + response := &Response{ + StatusCode: 400, + Body: `{"result": "failure"}`, + Headers: headers, + } + + var err error = &RestError{Response: response} + + if err.Error() != `{"result": "failure"}` { + t.Error("Invalid error message.") + } +} + +func TestRepoFiles(t *testing.T) { + files := []string{"../.env_sample", "../.gitignore", "../.github/workflows/test.yml", "../CHANGELOG.md", + "../CODE_OF_CONDUCT.md", "../CONTRIBUTING.md", + "../LICENSE", "../PULL_REQUEST_TEMPLATE.md", "../README.md", + "../TROUBLESHOOTING.md", "../USAGE.md"} + + for _, file := range files { + if _, err := os.Stat(file); os.IsNotExist(err) { + t.Errorf("Repo file does not exist: %v", file) + } + } +} + +func TestLicenseYear(t *testing.T) { + t.Parallel() + dat, err := os.ReadFile("../LICENSE") + + currentYear := time.Now().Year() + r := fmt.Sprintf("%d", currentYear) + match, _ := regexp.MatchString(r, string(dat)) + + if err != nil { + t.Error("License File Not Found") + } + if !match { + t.Error("Incorrect Year in License Copyright") + } +} + +func TestSendWithContext(t *testing.T) { + t.Parallel() + fakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + time.Sleep(time.Millisecond * 20) + fmt.Fprintln(w, "{\"message\": \"success\"}") + })) + defer fakeServer.Close() + host := fakeServer.URL + endpoint := "/test_endpoint" + baseURL := host + endpoint + method := Get + request := Request{ + Method: method, + BaseURL: baseURL, + } + + ctx, _ := context.WithTimeout(context.Background(), time.Millisecond*10) + _, err := SendWithContext(ctx, request) + if err == nil { + t.Error("A timeout did not trigger as expected") + } + if !strings.Contains(err.Error(), "context deadline exceeded") { + t.Error("We did not receive the Timeout error") + } +} From 23c6262b836ea841dfc098f6de80b0034375d69d Mon Sep 17 00:00:00 2001 From: Will Stull Date: Fri, 4 Aug 2023 12:12:39 -0400 Subject: [PATCH 2/6] fix: switch to v3 due to breaking changes --- rest.go | 4 ++-- rest_test.go | 3 ++- v2/go.mod | 5 ----- v2/go.sum | 7 ------- v3/go.mod | 5 +++++ v3/go.sum | 2 ++ {v2 => v3}/rest.go | 0 {v2 => v3}/rest_test.go | 0 8 files changed, 11 insertions(+), 15 deletions(-) delete mode 100644 v2/go.mod delete mode 100644 v2/go.sum create mode 100644 v3/go.mod create mode 100644 v3/go.sum rename {v2 => v3}/rest.go (100%) rename {v2 => v3}/rest_test.go (100%) diff --git a/rest.go b/rest.go index 7aab0ff..b3e578c 100644 --- a/rest.go +++ b/rest.go @@ -4,7 +4,7 @@ package rest import ( "bytes" "context" - "io" + "io/ioutil" "net/http" "net/url" ) @@ -97,7 +97,7 @@ func MakeRequest(req *http.Request) (*http.Response, error) { // BuildResponse builds the response struct. func BuildResponse(res *http.Response) (*Response, error) { - body, err := io.ReadAll(res.Body) + body, err := ioutil.ReadAll(res.Body) response := Response{ StatusCode: res.StatusCode, Body: string(body), diff --git a/rest_test.go b/rest_test.go index 2a5aa80..7ca4369 100644 --- a/rest_test.go +++ b/rest_test.go @@ -3,6 +3,7 @@ package rest import ( "errors" "fmt" + "io/ioutil" "net/http" "net/http/httptest" "net/http/httputil" @@ -323,7 +324,7 @@ func TestRepoFiles(t *testing.T) { func TestLicenseYear(t *testing.T) { t.Parallel() - dat, err := os.ReadFile("LICENSE") + dat, err := ioutil.ReadFile("LICENSE") currentYear := time.Now().Year() r := fmt.Sprintf("%d", currentYear) diff --git a/v2/go.mod b/v2/go.mod deleted file mode 100644 index 6c00642..0000000 --- a/v2/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/sendgrid/rest/v2 - -go 1.14 - -require golang.org/x/net v0.0.0-20220708220712-1185a9018129 diff --git a/v2/go.sum b/v2/go.sum deleted file mode 100644 index 64cf5c2..0000000 --- a/v2/go.sum +++ /dev/null @@ -1,7 +0,0 @@ -golang.org/x/net v0.0.0-20220708220712-1185a9018129 h1:vucSRfWwTsoXro7P+3Cjlr6flUMtzCwzlvkxEQtHHB0= -golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/v3/go.mod b/v3/go.mod new file mode 100644 index 0000000..4e2f6eb --- /dev/null +++ b/v3/go.mod @@ -0,0 +1,5 @@ +module github.com/sendgrid/rest/v3 + +go 1.18 + +require golang.org/x/net v0.13.0 diff --git a/v3/go.sum b/v3/go.sum new file mode 100644 index 0000000..d565f8e --- /dev/null +++ b/v3/go.sum @@ -0,0 +1,2 @@ +golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY= +golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= diff --git a/v2/rest.go b/v3/rest.go similarity index 100% rename from v2/rest.go rename to v3/rest.go diff --git a/v2/rest_test.go b/v3/rest_test.go similarity index 100% rename from v2/rest_test.go rename to v3/rest_test.go From 7974b71f324091cf19a2124be908336e8ebcf5fc Mon Sep 17 00:00:00 2001 From: Will Stull Date: Fri, 4 Aug 2023 12:27:19 -0400 Subject: [PATCH 3/6] fix: add test-v3 job and upgrade GitHub Actions --- .github/workflows/pr-lint.yml | 2 +- .github/workflows/test.yml | 33 +++++++++++++++++++++++++++++---- Makefile | 4 ++-- v3/Makefile | 7 +++++++ 4 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 v3/Makefile diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml index dc7af3d..ea165ea 100644 --- a/.github/workflows/pr-lint.yml +++ b/.github/workflows/pr-lint.yml @@ -8,7 +8,7 @@ jobs: name: Validate title runs-on: ubuntu-latest steps: - - uses: amannn/action-semantic-pull-request@v4 + - uses: amannn/action-semantic-pull-request@v5 with: types: chore docs fix feat test env: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index aadb897..e893576 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,13 +17,13 @@ jobs: timeout-minutes: 20 strategy: matrix: - go: [ '1.14', '1.15', '1.16', '1.17', '1.18', '1.19' ] + go: [ '1.14', '1.15', '1.16', '1.17' ] steps: - name: Checkout rest - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup Go environment - uses: actions/setup-go@v2 + uses: actions/setup-go@v4 with: go-version: ${{ matrix.go }} @@ -36,6 +36,31 @@ jobs: - name: Run Tests run: make test + test-v3: + name: Build & Test + runs-on: ubuntu-latest + timeout-minutes: 20 + strategy: + matrix: + go: [ '1.18', '1.19' ] + steps: + - name: Checkout rest + uses: actions/checkout@v3 + + - name: Setup Go environment + uses: actions/setup-go@v4 + with: + go-version: ${{ matrix.go }} + + - name: Set Go env vars + run: | + echo "GOPATH=$HOME" >> $GITHUB_ENV + echo "GOBIN=$HOME/bin" >> $GITHUB_ENV + echo "GO111MODULE=off" >> $GITHUB_ENV + + - name: Run Tests + run: cd v3 && make test + deploy: name: Deploy if: success() && github.ref_type == 'tag' @@ -43,7 +68,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout rest - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Create GitHub Release uses: sendgrid/dx-automator/actions/release@main diff --git a/Makefile b/Makefile index 07d1cdf..55e8a4e 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ .PHONY: test install install: - go get -t -v ./... + go get -t -v test: install - go test -race -cover -v ./... + go test -race -cover -v diff --git a/v3/Makefile b/v3/Makefile new file mode 100644 index 0000000..55e8a4e --- /dev/null +++ b/v3/Makefile @@ -0,0 +1,7 @@ +.PHONY: test install + +install: + go get -t -v + +test: install + go test -race -cover -v From 226edb84ade591eb162673e08678dff010be31d1 Mon Sep 17 00:00:00 2001 From: Will Stull Date: Fri, 4 Aug 2023 12:52:45 -0400 Subject: [PATCH 4/6] fix: update documentation --- CONTRIBUTING.md | 2 +- README.md | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index af00037..a52b900 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,7 +18,7 @@ We welcome direct contributions to the rest code base. Thank you! ##### Supported Versions ##### -- Go version 1.14, 1.15 or 1.16 +- Go version 1.14, 1.15, 1.16, 1.17, 1.18, or 1.19 ##### Initial setup: ##### diff --git a/README.md b/README.md index 32b70e1..86f703b 100644 --- a/README.md +++ b/README.md @@ -39,10 +39,18 @@ This library supports the following Go implementations: ## Install Package +If you are using Go 1.14 through 1.17: + ```bash go get github.com/sendgrid/rest ``` +If you are using Go 1.18 or above: + +```bash +go get github.com/sendgrid/rest/v3 +``` + ## Setup Environment Variables ### Initial Setup @@ -109,7 +117,7 @@ Your go files will be executed relative to the root of this directory. So in the ```go package main -import "github.com/sendgrid/rest" +import "github.com/sendgrid/rest" // Or github.com/sendgrid/rest/v3 if using Go 1.18 or above import "fmt" func main() { @@ -138,7 +146,7 @@ func main() { ```go package main -import "github.com/sendgrid/rest" +import "github.com/sendgrid/rest" // Or github.com/sendgrid/rest/v3 if using Go 1.18 or above import "fmt" func main() { From 557c9baf4e8e42ae67885c28707d74cbac61cd11 Mon Sep 17 00:00:00 2001 From: Will Stull Date: Fri, 4 Aug 2023 13:33:22 -0400 Subject: [PATCH 5/6] fix: update current version --- v3/rest.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v3/rest.go b/v3/rest.go index 7aab0ff..c6c31c2 100644 --- a/v3/rest.go +++ b/v3/rest.go @@ -10,7 +10,7 @@ import ( ) // Version represents the current version of the rest library -const Version = "2.6.9" +const Version = "3.0.0" // Method contains the supported HTTP verbs. type Method string From 4afca7d43e2779128ff969313cb7d1e16048bc64 Mon Sep 17 00:00:00 2001 From: Will Stull Date: Mon, 7 Aug 2023 09:53:30 -0400 Subject: [PATCH 6/6] fix: add Go 1.20 to supported versions --- .github/workflows/test.yml | 2 +- CONTRIBUTING.md | 2 +- README.md | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e893576..a89264b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,7 +42,7 @@ jobs: timeout-minutes: 20 strategy: matrix: - go: [ '1.18', '1.19' ] + go: [ '1.18', '1.19', '1.20' ] steps: - name: Checkout rest uses: actions/checkout@v3 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a52b900..2d2fdec 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,7 +18,7 @@ We welcome direct contributions to the rest code base. Thank you! ##### Supported Versions ##### -- Go version 1.14, 1.15, 1.16, 1.17, 1.18, or 1.19 +- Go version 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, or 1.20 ##### Initial setup: ##### diff --git a/README.md b/README.md index 86f703b..e9462e9 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ This library supports the following Go implementations: * Go 1.17 * Go 1.18 * Go 1.19 +* Go 1.20 ## Install Package