diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1e5f801706c912312d2e98bd349771bc8f664d59 --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,29 @@ +linters: + enable: + - errorlint + - forbidigo + - gochecknoinits + - gocritic + - goconst + - gocyclo + - gofumpt + - goimports + - misspell + - revive + - unconvert + - unparam + - wastedassign + +linters-settings: + gocyclo: + min-complexity: 12 + gofumpt: + extra-rules: true + govet: + enable-all: true + disable: + - fieldalignment + +run: + skip-dirs: + - goreleaser diff --git a/pkg/config/config.go b/pkg/config/config.go index c5dc9d0d123366b1924f24500c1e43c9d0e47339..8c37b89a23d2243d2efb548a3753b3b9b2b37b00 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -1,6 +1,7 @@ package config import ( + "errors" "os" "strings" @@ -142,18 +143,20 @@ func must(err error) { } } +var trueString = "true" + func detectCI() string { - if os.Getenv("GITHUB_ACTIONS") == "true" { + if os.Getenv("GITHUB_ACTIONS") == trueString { return "github" } - if os.Getenv("GITLAB_CI") == "true" { + if os.Getenv("GITLAB_CI") == trueString { return "gitlab" } return "default" } func defaultProvider() string { - if os.Getenv("GITLAB_CI") == "true" { + if os.Getenv("GITLAB_CI") == trueString { return "gitlab" } return "github" @@ -218,7 +221,8 @@ func InitConfig(cmd *cobra.Command) error { viper.SetConfigType("json") if err := viper.ReadInConfig(); err != nil { - if _, ok := err.(viper.ConfigFileNotFoundError); !ok { + var viperConfigNotFound viper.ConfigFileNotFoundError + if !errors.As(err, &viperConfigNotFound) { return err } } diff --git a/pkg/plugin/discovery/discovery.go b/pkg/plugin/discovery/discovery.go index 6ddf072090c95fc6c38d7ebca2f171207768b3cb..e84e6b447ad6139fb3d97bfd8395ef7a48fa888b 100644 --- a/pkg/plugin/discovery/discovery.go +++ b/pkg/plugin/discovery/discovery.go @@ -69,7 +69,9 @@ func (d *Discovery) FindPlugin(t, name string) (*plugin.PluginInfo, error) { if err != nil { return nil, err } - if err := setAndEnsurePluginPath(pInfo); err != nil { + + err = setAndEnsurePluginPath(pInfo) + if err != nil { return nil, err } diff --git a/pkg/plugin/discovery/download.go b/pkg/plugin/discovery/download.go index 492124e73bb6f23a9a11d1ce4cb7cafc04b54170..c34da1fc3ddd3f0386f0828aaa6bc8e8fc1e4da5 100644 --- a/pkg/plugin/discovery/download.go +++ b/pkg/plugin/discovery/download.go @@ -5,6 +5,7 @@ import ( "compress/gzip" "crypto/sha256" "encoding/hex" + "errors" "fmt" "io" "os" @@ -66,7 +67,7 @@ func extractFileFromTarGz(name, inputFile, outputFile string) error { tarReader := tar.NewReader(decompressedFile) for { header, err := tarReader.Next() - if err == io.EOF { + if errors.Is(err, io.EOF) { return fmt.Errorf("could not extract file") } if err != nil { @@ -97,9 +98,9 @@ func downloadPlugin(pluginInfo *plugin.PluginInfo, downloadInfo *resolver.Plugin return "", err } if downloadInfo.Checksum != "" { - sum, err := hex.DecodeString(downloadInfo.Checksum) - if err != nil { - return "", err + sum, decErr := hex.DecodeString(downloadInfo.Checksum) + if decErr != nil { + return "", decErr } req.SetChecksum(sha256.New(), sum, true) } @@ -108,7 +109,8 @@ func downloadPlugin(pluginInfo *plugin.PluginInfo, downloadInfo *resolver.Plugin if showProgress { showDownloadProgressBar(pluginInfo.ShortNormalizedName, res) } - if err := res.Err(); err != nil { + err = res.Err() + if err != nil { return "", err } diff --git a/pkg/plugin/discovery/local.go b/pkg/plugin/discovery/local.go index dbb346d9c7a0903752f3e971d3402e4431f6281a..cfeb036bc56251abf835590d1bcde98f4ef7fec0 100644 --- a/pkg/plugin/discovery/local.go +++ b/pkg/plugin/discovery/local.go @@ -2,15 +2,14 @@ package discovery import ( "errors" - "io/ioutil" + "fmt" "os" "path" "runtime" "sort" - "github.com/go-semantic-release/semantic-release/v2/pkg/plugin" - "github.com/Masterminds/semver/v3" + "github.com/go-semantic-release/semantic-release/v2/pkg/plugin" ) const PluginDir = ".semrel" @@ -20,7 +19,8 @@ var osArchDir = runtime.GOOS + "_" + runtime.GOARCH func setAndEnsurePluginPath(pluginInfo *plugin.PluginInfo) error { pluginPath := path.Join(PluginDir, osArchDir, pluginInfo.NormalizedName) if _, err := os.Stat(pluginPath); os.IsNotExist(err) { - if err := os.MkdirAll(pluginPath, 0o755); err != nil { + err = os.MkdirAll(pluginPath, 0o755) + if err != nil { return err } } else if err != nil { @@ -33,7 +33,7 @@ func setAndEnsurePluginPath(pluginInfo *plugin.PluginInfo) error { var ErrPluginNotFound = errors.New("no plugin was found") func getMatchingVersionDir(pluginInfo *plugin.PluginInfo) (string, error) { - vDirs, err := ioutil.ReadDir(pluginInfo.PluginPath) + vDirs, err := os.ReadDir(pluginInfo.PluginPath) if err != nil { return "", err } @@ -75,7 +75,7 @@ func findPluginLocally(pluginInfo *plugin.PluginInfo) (string, error) { return "", ErrPluginNotFound } - files, err := ioutil.ReadDir(vPth) + files, err := os.ReadDir(vPth) if err != nil { return "", err } @@ -86,7 +86,12 @@ func findPluginLocally(pluginInfo *plugin.PluginInfo) (string, error) { if f.IsDir() { continue } - if f.Mode()&0o100 == 0 { + fInfo, err := f.Info() + if err != nil { + return "", fmt.Errorf("failed to get file info for %s: %w", f.Name(), err) + } + // check if the file is executable by the user + if fInfo.Mode()&0o100 == 0 { continue } return path.Join(vPth, f.Name()), nil diff --git a/pkg/plugin/discovery/resolver/github/github.go b/pkg/plugin/discovery/resolver/github/github.go index 8fd0acab168da46f7f364cfcdbe1bd592920e41e..29196052ee6c614fff8a67161508c82de8691539 100644 --- a/pkg/plugin/discovery/resolver/github/github.go +++ b/pkg/plugin/discovery/resolver/github/github.go @@ -3,7 +3,7 @@ package github import ( "context" "fmt" - "io/ioutil" + "io" "net/http" "os" "regexp" @@ -18,21 +18,22 @@ import ( "golang.org/x/oauth2" ) -type GitHubResolver struct { +type Resolver struct { ghClient *github.Client } -func NewResolver() *GitHubResolver { +func NewResolver() *Resolver { var tc *http.Client if ghToken := os.Getenv("GITHUB_TOKEN"); ghToken != "" { tc = oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(&oauth2.Token{AccessToken: ghToken})) } - return &GitHubResolver{ + return &Resolver{ ghClient: github.NewClient(tc), } } -func (g *GitHubResolver) githubReleaseToDownloadInfo(repoOwner, repoName string, release *github.RepositoryRelease) (*resolver.PluginDownloadInfo, error) { +//gocyclo:ignore +func (g *Resolver) githubReleaseToDownloadInfo(repoOwner, repoName string, release *github.RepositoryRelease) (*resolver.PluginDownloadInfo, error) { var checksumAsset *github.ReleaseAsset var pluginAsset *github.ReleaseAsset osArchRe := regexp.MustCompile("(?i)" + runtime.GOOS + "(_|-)" + runtime.GOARCH) @@ -56,7 +57,7 @@ func (g *GitHubResolver) githubReleaseToDownloadInfo(repoOwner, repoName string, if err != nil { return nil, err } - checksumData, err := ioutil.ReadAll(checksumDownload) + checksumData, err := io.ReadAll(checksumDownload) checksumDownload.Close() if err != nil { return nil, err @@ -91,7 +92,7 @@ func (gr ghReleases) Len() int { return len(gr) } func (gr ghReleases) Less(i, j int) bool { return gr[j].version.LessThan(gr[i].version) } func (gr ghReleases) Swap(i, j int) { gr[i], gr[j] = gr[j], gr[i] } -func (g *GitHubResolver) getAllValidGitHubReleases(repoOwner, repoName string) (ghReleases, error) { +func (g *Resolver) getAllValidGitHubReleases(repoOwner, repoName string) (ghReleases, error) { ret := make(ghReleases, 0) opts := &github.ListOptions{Page: 1, PerPage: 100} for { @@ -118,7 +119,7 @@ func (g *GitHubResolver) getAllValidGitHubReleases(repoOwner, repoName string) ( return ret, nil } -func (g *GitHubResolver) ResolvePlugin(pluginInfo *plugin.PluginInfo) (*resolver.PluginDownloadInfo, error) { +func (g *Resolver) ResolvePlugin(pluginInfo *plugin.PluginInfo) (*resolver.PluginDownloadInfo, error) { if pluginInfo.RepoSlug == "" { pluginInfo.RepoSlug = knownPlugins[pluginInfo.ShortNormalizedName] } @@ -155,6 +156,6 @@ func (g *GitHubResolver) ResolvePlugin(pluginInfo *plugin.PluginInfo) (*resolver return di, err } -func (g *GitHubResolver) Names() []string { +func (g *Resolver) Names() []string { return []string{"github", "gh"} } diff --git a/pkg/plugin/discovery/resolver/registry/registry.go b/pkg/plugin/discovery/resolver/registry/registry.go index 64a6405052ac2dee95511561b87a6ec292f1b89b..68eb4e206cb89ffec8df0a1cd50c90d69ba4847d 100644 --- a/pkg/plugin/discovery/resolver/registry/registry.go +++ b/pkg/plugin/discovery/resolver/registry/registry.go @@ -11,24 +11,24 @@ import ( "github.com/go-semantic-release/semantic-release/v2/pkg/plugin/discovery/resolver" ) -type RegistryResolver struct{} +type Resolver struct{} -func NewResolver() *RegistryResolver { - return &RegistryResolver{} +func NewResolver() *Resolver { + return &Resolver{} } -func (r *RegistryResolver) ResolvePlugin(pluginInfo *plugin.PluginInfo) (*resolver.PluginDownloadInfo, error) { - pluginApiRes, err := getPluginInfo(pluginInfo.NormalizedName) +func (r *Resolver) ResolvePlugin(pluginInfo *plugin.PluginInfo) (*resolver.PluginDownloadInfo, error) { + pluginAPIRes, err := getPluginInfo(pluginInfo.NormalizedName) if err != nil { return nil, err } foundVersion := "" if pluginInfo.Constraint == nil { - foundVersion = pluginApiRes.LatestRelease + foundVersion = pluginAPIRes.LatestRelease } else { versions := make(semver.Collection, 0) - for v := range pluginApiRes.Versions { + for v := range pluginAPIRes.Versions { pv, err := semver.NewVersion(v) if err != nil { return nil, err @@ -48,7 +48,7 @@ func (r *RegistryResolver) ResolvePlugin(pluginInfo *plugin.PluginInfo) (*resolv return nil, errors.New("version not found") } - releaseAsset := pluginApiRes.Versions[foundVersion].getMatchingAsset() + releaseAsset := pluginAPIRes.Versions[foundVersion].getMatchingAsset() if releaseAsset == nil { return nil, fmt.Errorf("a matching plugin was not found for %s/%s", runtime.GOOS, runtime.GOARCH) } @@ -60,6 +60,6 @@ func (r *RegistryResolver) ResolvePlugin(pluginInfo *plugin.PluginInfo) (*resolv }, nil } -func (r *RegistryResolver) Names() []string { +func (r *Resolver) Names() []string { return []string{"registry"} }