diff --git a/github.go b/github.go index fe862e3..7878fdf 100644 --- a/github.go +++ b/github.go @@ -1,6 +1,7 @@ package main import ( + "context" "encoding/json" "errors" "fmt" @@ -11,7 +12,7 @@ import ( ) // findGitHubREADME tries to find the correct README filename in a repository using GitHub API. -func findGitHubREADME(u *url.URL) (*source, error) { +func findGitHubREADME(ctx context.Context, u *url.URL) (*source, error) { owner, repo, ok := strings.Cut(strings.TrimPrefix(u.Path, "/"), "/") if !ok { return nil, fmt.Errorf("invalid url: %s", u.String()) @@ -23,12 +24,15 @@ func findGitHubREADME(u *url.URL) (*source, error) { apiURL := fmt.Sprintf("https://api.%s/repos/%s/%s/readme", u.Hostname(), owner, repo) - //nolint:bodyclose - // it is closed on the caller - res, err := http.Get(apiURL) //nolint: gosec,noctx + req, err := http.NewRequestWithContext(ctx, http.MethodGet, apiURL, nil) + if err != nil { + return nil, fmt.Errorf("unable to create request: %w", err) + } + res, err := http.DefaultClient.Do(req) if err != nil { return nil, fmt.Errorf("unable to get url: %w", err) } + defer res.Body.Close() //nolint:errcheck body, err := io.ReadAll(res.Body) if err != nil { @@ -41,9 +45,12 @@ func findGitHubREADME(u *url.URL) (*source, error) { } if res.StatusCode == http.StatusOK { - //nolint:bodyclose - // it is closed on the caller - resp, err := http.Get(result.DownloadURL) //nolint: noctx + // consumer of the source is responsible for closing the ReadCloser. + req, err := http.NewRequestWithContext(ctx, http.MethodGet, result.DownloadURL, nil) + if err != nil { + return nil, fmt.Errorf("unable to create request: %w", err) + } + resp, err := http.DefaultClient.Do(req) //nolint:bodyclose if err != nil { return nil, fmt.Errorf("unable to get url: %w", err) } diff --git a/gitlab.go b/gitlab.go index 68256be..d2915ef 100644 --- a/gitlab.go +++ b/gitlab.go @@ -1,6 +1,7 @@ package main import ( + "context" "encoding/json" "errors" "fmt" @@ -11,7 +12,7 @@ import ( ) // findGitLabREADME tries to find the correct README filename in a repository using GitLab API. -func findGitLabREADME(u *url.URL) (*source, error) { +func findGitLabREADME(ctx context.Context, u *url.URL) (*source, error) { owner, repo, ok := strings.Cut(strings.TrimPrefix(u.Path, "/"), "/") if !ok { return nil, fmt.Errorf("invalid url: %s", u.String()) @@ -25,12 +26,15 @@ func findGitLabREADME(u *url.URL) (*source, error) { apiURL := fmt.Sprintf("https://%s/api/v4/projects/%s", u.Hostname(), projectPath) - //nolint:bodyclose - // it is closed on the caller - res, err := http.Get(apiURL) //nolint: gosec,noctx + req, err := http.NewRequestWithContext(ctx, http.MethodGet, apiURL, nil) + if err != nil { + return nil, fmt.Errorf("unable to create request: %w", err) + } + res, err := http.DefaultClient.Do(req) if err != nil { return nil, fmt.Errorf("unable to get url: %w", err) } + defer res.Body.Close() //nolint:errcheck body, err := io.ReadAll(res.Body) if err != nil { @@ -45,9 +49,12 @@ func findGitLabREADME(u *url.URL) (*source, error) { readmeRawURL := strings.ReplaceAll(result.ReadmeURL, "blob", "raw") if res.StatusCode == http.StatusOK { - //nolint:bodyclose - // it is closed on the caller - resp, err := http.Get(readmeRawURL) //nolint: gosec,noctx + // consumer of the source is responsible for closing the ReadCloser. + req, err := http.NewRequestWithContext(ctx, http.MethodGet, readmeRawURL, nil) + if err != nil { + return nil, fmt.Errorf("unable to create request: %w", err) + } + resp, err := http.DefaultClient.Do(req) //nolint:bodyclose if err != nil { return nil, fmt.Errorf("unable to get url: %w", err) } diff --git a/main.go b/main.go index dd3bb7c..2b4000c 100644 --- a/main.go +++ b/main.go @@ -68,14 +68,14 @@ type source struct { } // sourceFromArg parses an argument and creates a readable source for it. -func sourceFromArg(arg string) (*source, error) { +func sourceFromArg(ctx context.Context, arg string) (*source, error) { // from stdin if arg == "-" { return &source{reader: os.Stdin}, nil } // a GitHub or GitLab URL (even without the protocol): - src, err := readmeURL(arg) + src, err := readmeURL(ctx, arg) if src != nil && err == nil { // if there's an error, try next methods... return src, nil @@ -88,7 +88,11 @@ func sourceFromArg(arg string) (*source, error) { return nil, fmt.Errorf("%s is not a supported protocol", u.Scheme) } // consumer of the source is responsible for closing the ReadCloser. - resp, err := http.Get(u.String()) //nolint: noctx,bodyclose + req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) + if err != nil { + return nil, fmt.Errorf("unable to create request: %w", err) + } + resp, err := http.DefaultClient.Do(req) //nolint:bodyclose if err != nil { return nil, fmt.Errorf("unable to get url: %w", err) } @@ -260,7 +264,7 @@ func execute(cmd *cobra.Command, args []string) error { func executeArg(cmd *cobra.Command, arg string, w io.Writer) error { // create an io.Reader from the markdown source in cli-args - src, err := sourceFromArg(arg) + src, err := sourceFromArg(cmd.Context(), arg) if err != nil { return err } diff --git a/url.go b/url.go index f716681..d92e70a 100644 --- a/url.go +++ b/url.go @@ -1,6 +1,7 @@ package main import ( + "context" "fmt" "net/url" "strings" @@ -26,16 +27,16 @@ func init() { }) } -func readmeURL(path string) (*source, error) { +func readmeURL(ctx context.Context, path string) (*source, error) { switch { case strings.HasPrefix(path, protoGithub): if u := githubReadmeURL(path); u != nil { - return readmeURL(u.String()) + return readmeURL(ctx, u.String()) } return nil, nil case strings.HasPrefix(path, protoGitlab): if u := gitlabReadmeURL(path); u != nil { - return readmeURL(u.String()) + return readmeURL(ctx, u.String()) } return nil, nil } @@ -50,9 +51,9 @@ func readmeURL(path string) (*source, error) { switch { case u.Hostname() == githubURL.Hostname(): - return findGitHubREADME(u) + return findGitHubREADME(ctx, u) case u.Hostname() == gitlabURL.Hostname(): - return findGitLabREADME(u) + return findGitLabREADME(ctx, u) } return nil, nil diff --git a/url_test.go b/url_test.go index 9683892..a23c1b1 100644 --- a/url_test.go +++ b/url_test.go @@ -1,6 +1,9 @@ package main -import "testing" +import ( + "context" + "testing" +) func TestURLParser(t *testing.T) { for path, url := range map[string]string{ @@ -15,7 +18,7 @@ func TestURLParser(t *testing.T) { } { t.Run(path, func(t *testing.T) { t.Skip("test uses network, sometimes fails for no reason") - got, err := readmeURL(path) + got, err := readmeURL(context.Background(), path) if err != nil { t.Fatalf("expected no error, got %v", err) }