fix: update golangci-lint and fix linting issues (#353)

This commit is contained in:
Devin Buhl 2025-04-15 16:57:31 -04:00 committed by GitHub
parent 4ace1abc7a
commit baacf8df6e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 96 additions and 85 deletions

View File

@ -8,11 +8,10 @@ runs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ">=1.19"
go-version: ">=1.23"
# Run golangcilint before `go get` is ran
# https://github.com/golangci/golangci-lint-action/issues/23
- uses: golangci/golangci-lint-action@v6
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v7
with:
version: v1.64.8
args: --timeout 5m --config .github/lint/golangci.yaml
version: v2.1
args: --timeout=5m --config=.github/lint/golangci.yaml

View File

@ -1,18 +1,26 @@
---
run:
timeout: 3m
version: "2"
linters:
# https://golangci-lint.run/usage/linters/#enabled-by-default
enable:
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- typecheck
- unused
issues:
exclude-rules:
- path: '(.+)_test\.go'
linters:
- errcheck
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- linters:
- errcheck
path: (.+)_test\.go
paths:
- third_party$
- builtin$
- examples$
formatters:
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$

View File

@ -9,18 +9,17 @@ import (
"github.com/onedr0p/exportarr/internal/arr/config"
"github.com/onedr0p/exportarr/internal/client"
base_client "github.com/onedr0p/exportarr/internal/client"
)
type Client = base_client.Client
type QueryParams = base_client.QueryParams
type Client = client.Client
type QueryParams = client.QueryParams
func NewClient(config *config.ArrConfig) (*Client, error) {
auth, err := NewAuth(config)
if err != nil {
return nil, err
}
return base_client.NewClient(config.BaseURL(), config.DisableSSLVerify, auth)
return client.NewClient(config.BaseURL(), config.DisableSSLVerify, auth)
}
func NewAuth(config *config.ArrConfig) (client.Authenticator, error) {
@ -97,7 +96,7 @@ func (a *FormAuth) Auth(req *http.Request) error {
authReq, err := http.NewRequest("POST", u.String(), strings.NewReader(form.Encode()))
if err != nil {
return fmt.Errorf("Failed to renew FormAuth Cookie: %w", err)
return fmt.Errorf("failed to renew FormAuth Cookie: %w", err)
}
authReq.Header.Add("Content-Type", "application/x-www-form-urlencoded")
@ -105,18 +104,18 @@ func (a *FormAuth) Auth(req *http.Request) error {
client := &http.Client{Transport: a.Transport, CheckRedirect: func(req *http.Request, via []*http.Request) error {
if req.URL.Query().Get("loginFailed") == "true" {
return fmt.Errorf("Failed to renew FormAuth Cookie: Login Failed")
return fmt.Errorf("failed to renew FormAuth Cookie: Login Failed")
}
return http.ErrUseLastResponse
}}
authResp, err := client.Do(authReq)
if err != nil {
return fmt.Errorf("Failed to renew FormAuth Cookie: %w", err)
return fmt.Errorf("failed to renew FormAuth Cookie: %w", err)
}
if authResp.StatusCode != 302 {
return fmt.Errorf("Failed to renew FormAuth Cookie: Received Status Code %d", authResp.StatusCode)
return fmt.Errorf("failed to renew FormAuth Cookie: Received Status Code %d", authResp.StatusCode)
}
found := false
@ -129,7 +128,7 @@ func (a *FormAuth) Auth(req *http.Request) error {
}
}
if !found {
return fmt.Errorf("Failed to renew FormAuth Cookie: No Cookie with suffix 'arrAuth' found")
return fmt.Errorf("failed to renew FormAuth Cookie: No Cookie with suffix 'arrAuth' found")
}
}

View File

@ -44,7 +44,7 @@ func TestBazarrCollect(t *testing.T) {
b, err := os.ReadFile(bazarr_test_fixtures_path + "expected_metrics.txt")
require.NoError(err)
expected := strings.Replace(string(b), "SOMEURL", ts.URL, -1)
expected := strings.ReplaceAll(string(b), "SOMEURL", ts.URL)
f := strings.NewReader(expected)
collections := []string{
"bazarr_episode_subtitles_downloaded_total",
@ -97,17 +97,20 @@ func TestBazarrCollect_Concurrency(t *testing.T) {
require := require.New(t)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Contains(r.URL.Path, "/api/")
if r.URL.Path == "/api/series" {
switch r.URL.Path {
case "/api/series":
w.WriteHeader(http.StatusOK)
json, err := os.ReadFile(bazarr_test_fixtures_path + "concurrency/series.json")
require.NoError(err)
_, err = w.Write(json)
require.NoError(err)
} else if r.URL.Path == "/api/episodes" {
case "/api/episodes":
seriesIDs := r.URL.Query()["seriesid[]"]
require.Len(seriesIDs, 2)
if slices.Contains(seriesIDs, "944") && slices.Contains(seriesIDs, "945") {
w.WriteHeader(http.StatusOK)
json, err := os.ReadFile(bazarr_test_fixtures_path + "concurrency/episodes944_945.json")
@ -123,7 +126,8 @@ func TestBazarrCollect_Concurrency(t *testing.T) {
} else {
w.WriteHeader(http.StatusInternalServerError)
}
} else {
default:
ts2, err := newTestBazarrServer(t, func(w http.ResponseWriter, r *http.Request) {
require.Contains(r.URL.Path, "/api/")
})
@ -149,7 +153,7 @@ func TestBazarrCollect_Concurrency(t *testing.T) {
b, err := os.ReadFile(bazarr_test_fixtures_path + "concurrency/expected_metrics.txt")
require.NoError(err)
expected := strings.Replace(string(b), "SOMEURL", ts.URL, -1)
expected := strings.ReplaceAll(string(b), "SOMEURL", ts.URL)
f := strings.NewReader(expected)
collections := []string{
"bazarr_episode_subtitles_downloaded_total",

View File

@ -71,8 +71,8 @@ func TestSystemHealthCollect(t *testing.T) {
b, err := os.ReadFile(test_util.COMMON_FIXTURES_PATH + "expected_health_metrics.txt")
require.NoError(err)
expected := strings.Replace(string(b), "SOMEURL", ts.URL, -1)
expected = strings.Replace(expected, "APP", tt.config.App, -1)
expected := strings.ReplaceAll(string(b), "SOMEURL", ts.URL)
expected = strings.ReplaceAll(expected, "APP", tt.config.App)
f := strings.NewReader(expected)

View File

@ -71,8 +71,8 @@ func TestHistoryCollect(t *testing.T) {
b, err := os.ReadFile(test_util.COMMON_FIXTURES_PATH + "expected_history_metrics.txt")
require.NoError(err)
expected := strings.Replace(string(b), "SOMEURL", ts.URL, -1)
expected = strings.Replace(expected, "APP", tt.config.App, -1)
expected := strings.ReplaceAll(string(b), "SOMEURL", ts.URL)
expected = strings.ReplaceAll(expected, "APP", tt.config.App)
f := strings.NewReader(expected)

View File

@ -51,9 +51,10 @@ func (collector *queueCollector) Collect(ch chan<- prometheus.Metric) {
params := client.QueryParams{}
params.Add("page", "1")
if collector.config.EnableUnknownQueueItems {
if collector.config.App == "sonarr" {
switch collector.config.App {
case "sonarr":
params.Add("includeUnknownSeriesItems", "true")
} else if collector.config.App == "radarr" {
case "radarr":
params.Add("includeUnknownMovieItems", "true")
}
}

View File

@ -71,8 +71,8 @@ func TestQueueCollect(t *testing.T) {
b, err := os.ReadFile(test_util.COMMON_FIXTURES_PATH + "expected_queue_metrics.txt")
require.NoError(err)
expected := strings.Replace(string(b), "SOMEURL", ts.URL, -1)
expected = strings.Replace(expected, "APP", tt.config.App, -1)
expected := strings.ReplaceAll(string(b), "SOMEURL", ts.URL)
expected = strings.ReplaceAll(expected, "APP", tt.config.App)
f := strings.NewReader(expected)

View File

@ -40,7 +40,7 @@ func TestRadarrCollect(t *testing.T) {
b, err := os.ReadFile(radarr_test_fixtures_path + "expected_metrics.txt")
require.NoError(err)
expected := strings.Replace(string(b), "SOMEURL", ts.URL, -1)
expected := strings.ReplaceAll(string(b), "SOMEURL", ts.URL)
f := strings.NewReader(expected)
require.NotPanics(func() {

View File

@ -40,7 +40,7 @@ func TestReadarrCollect(t *testing.T) {
b, err := os.ReadFile(readarr_test_fixtures_path + "expected_metrics.txt")
require.NoError(err)
expected := strings.Replace(string(b), "SOMEURL", ts.URL, -1)
expected := strings.ReplaceAll(string(b), "SOMEURL", ts.URL)
f := strings.NewReader(expected)
require.NotPanics(func() {

View File

@ -71,8 +71,8 @@ func TestRootFolderCollect(t *testing.T) {
b, err := os.ReadFile(test_util.COMMON_FIXTURES_PATH + "expected_rootfolder_metrics.txt")
require.NoError(err)
expected := strings.Replace(string(b), "SOMEURL", ts.URL, -1)
expected = strings.Replace(expected, "APP", tt.config.App, -1)
expected := strings.ReplaceAll(string(b), "SOMEURL", ts.URL)
expected = strings.ReplaceAll(expected, "APP", tt.config.App)
f := strings.NewReader(expected)

View File

@ -62,7 +62,7 @@ func TestSonarrCollect(t *testing.T) {
b, err := os.ReadFile(sonarr_test_fixtures_path + tt.expected_metrics_file)
require.NoError(err)
expected := strings.Replace(string(b), "SOMEURL", ts.URL, -1)
expected := strings.ReplaceAll(string(b), "SOMEURL", ts.URL)
f := strings.NewReader(expected)
require.NotPanics(func() {

View File

@ -71,8 +71,8 @@ func TestStatusCollect(t *testing.T) {
b, err := os.ReadFile(test_util.COMMON_FIXTURES_PATH + "expected_status_metrics.txt")
require.NoError(err)
expected := strings.Replace(string(b), "SOMEURL", ts.URL, -1)
expected = strings.Replace(expected, "APP", tt.config.App, -1)
expected := strings.ReplaceAll(string(b), "SOMEURL", ts.URL)
expected = strings.ReplaceAll(expected, "APP", tt.config.App)
f := strings.NewReader(expected)

View File

@ -74,8 +74,8 @@ func LoadArrConfig(conf base_config.Config, flags *flag.FlagSet) (*ArrConfig, er
// Environment
err = k.Load(env.Provider("", ".", func(s string) string {
s = strings.ToLower(s)
s = strings.Replace(s, "__", ".", -1)
s = strings.Replace(s, "_", "-", -1)
s = strings.ReplaceAll(s, "__", ".")
s = strings.ReplaceAll(s, "_", "-")
return backwardsCompatibilityTransforms(s)
}), nil)
if err != nil {

View File

@ -25,10 +25,10 @@ func (b BazarrConfig) Validate() error {
return v.Errors
}
if b.SeriesBatchSize < 1 {
return fmt.Errorf("series-batch-size must be greater than zero.")
return fmt.Errorf("series-batch-size must be greater than zero")
}
if b.SeriesBatchConcurrency < 1 {
return fmt.Errorf("series-batch-concurrency must be greater than zero.")
return fmt.Errorf("series-batch-concurrency must be greater than zero")
}
return nil
}

View File

@ -25,7 +25,7 @@ func NewClient(baseURL string, insecureSkipVerify bool, auth Authenticator) (*Cl
u, err := url.Parse(baseURL)
if err != nil {
return nil, fmt.Errorf("Failed to parse URL(%s): %w", baseURL, err)
return nil, fmt.Errorf("failed to parse URL(%s): %w", baseURL, err)
}
return &Client{
@ -43,7 +43,7 @@ func (c *Client) unmarshalBody(b io.Reader, target interface{}) (err error) {
defer func() {
if r := recover(); r != nil {
// return recovered panic as error
err = fmt.Errorf("Recovered from panic: %s", r)
err = fmt.Errorf("recovered from panic: %s", r)
log := zap.S()
if zap.S().Level() == zap.DebugLevel {
@ -83,11 +83,11 @@ func (c *Client) DoRequest(endpoint string, target interface{}, queryParams ...Q
req, err := http.NewRequest("GET", url.String(), nil)
if err != nil {
return fmt.Errorf("Failed to create HTTP Request(%s): %w", url, err)
return fmt.Errorf("failed to create HTTP Request(%s): %w", url, err)
}
resp, err := c.httpClient.Do(req)
if err != nil {
return fmt.Errorf("Failed to execute HTTP Request(%s): %w", url, err)
return fmt.Errorf("failed to execute HTTP Request(%s): %w", url, err)
}
defer resp.Body.Close()
return c.unmarshalBody(resp.Body, target)

View File

@ -26,7 +26,7 @@ func (t *ExportarrTransport) RoundTrip(req *http.Request) (*http.Response, error
if t.auth != nil {
err := t.auth.Auth(req)
if err != nil {
return nil, fmt.Errorf("Error authenticating request: %w", err)
return nil, fmt.Errorf("error authenticating request: %w", err)
}
}
@ -40,19 +40,19 @@ func (t *ExportarrTransport) RoundTrip(req *http.Request) (*http.Response, error
}
}
if err != nil {
return nil, fmt.Errorf("Error sending HTTP Request: %w", err)
return nil, fmt.Errorf("error sending HTTP Request: %w", err)
} else {
return nil, fmt.Errorf("Received Server Error Status Code: %d", resp.StatusCode)
return nil, fmt.Errorf("received Server Error Status Code: %d", resp.StatusCode)
}
}
if resp.StatusCode >= 400 && resp.StatusCode <= 499 {
return nil, fmt.Errorf("Received Client Error Status Code: %d", resp.StatusCode)
return nil, fmt.Errorf("received Client Error Status Code: %d", resp.StatusCode)
}
if resp.StatusCode >= 300 && resp.StatusCode <= 399 {
if location, err := resp.Location(); err == nil {
return nil, fmt.Errorf("Received Redirect Status Code: %d, Location: %s", resp.StatusCode, location.String())
return nil, fmt.Errorf("received Redirect Status Code: %d, Location: %s", resp.StatusCode, location.String())
} else {
return nil, fmt.Errorf("Received Redirect Status Code: %d, ", resp.StatusCode)
return nil, fmt.Errorf("received Redirect Status Code: %d, ", resp.StatusCode)
}
}
return resp, nil

View File

@ -57,8 +57,8 @@ func LoadConfig(flags *flag.FlagSet) (*Config, error) {
// Environment
err = k.Load(env.Provider("", ".", func(s string) string {
s = strings.ToLower(s)
s = strings.Replace(s, "__", ".", -1)
s = strings.Replace(s, "_", "-", -1)
s = strings.ReplaceAll(s, "__", ".")
s = strings.ReplaceAll(s, "_", "-")
return backwardsCompatibilityTransforms(s)
}), nil)
if err != nil {
@ -75,11 +75,11 @@ func LoadConfig(flags *flag.FlagSet) (*Config, error) {
if apiKeyFile != "" {
data, err := os.ReadFile(apiKeyFile)
if err != nil {
return nil, fmt.Errorf("Couldn't Read API Key file %w", err)
return nil, fmt.Errorf("couldn't Read API Key file %w", err)
}
if err := k.Set("api-key", strings.TrimSpace(string(data))); err != nil {
return nil, fmt.Errorf("Couldn't merge api-key into config: %w", err)
return nil, fmt.Errorf("couldn't merge api-key into config: %w", err)
}
}

View File

@ -27,7 +27,7 @@ func (s serverStatCache) Update(stat model.ServerStat) (ServerStats, error) {
if stat.DayParsed == "" && s.todayKey != "" {
// If the day parsed is empty, it means there are no server side stats.
// If we have exportarr stats, something likely went wrong,
return s, errors.New("No Parsed Dates from Server, but cache is not empty")
return s, errors.New("no Parsed Dates from Server, but cache is not empty")
}
s.total = stat.Total

View File

@ -176,7 +176,7 @@ func NewSabnzbdCollector(config *config.SabnzbdConfig) (*SabnzbdCollector, error
auther := auth.ApiKeyAuth{ApiKey: config.ApiKey}
client, err := client.NewClient(config.URL, config.DisableSSLVerify, auther)
if err != nil {
return nil, fmt.Errorf("Failed to build client: %w", err)
return nil, fmt.Errorf("failed to build client: %w", err)
}
return &SabnzbdCollector{
@ -197,7 +197,7 @@ func (s *SabnzbdCollector) getQueueStats() (*model.QueueStats, error) {
err := s.doRequest("queue", stats)
if err != nil {
return nil, fmt.Errorf("Failed to get queue stats: %w", err)
return nil, fmt.Errorf("failed to get queue stats: %w", err)
}
return stats, nil
@ -207,7 +207,7 @@ func (s *SabnzbdCollector) getServerStats() (*model.ServerStats, error) {
var stats = &model.ServerStats{}
err := s.doRequest("server_stats", stats)
if err != nil {
return nil, fmt.Errorf("Failed to get server stats: %w", err)
return nil, fmt.Errorf("failed to get server stats: %w", err)
}
return stats, nil
}

View File

@ -57,7 +57,7 @@ func TestCollect(t *testing.T) {
b, err := os.ReadFile("../test_fixtures/expected_metrics.txt")
require.NoError(err)
expected := strings.Replace(string(b), "http://127.0.0.1:39965", ts.URL, -1)
expected := strings.ReplaceAll(string(b), "http://127.0.0.1:39965", ts.URL)
f := strings.NewReader(expected)
require.NotPanics(func() {

View File

@ -149,7 +149,7 @@ func (q *QueueStats) UnmarshalJSON(data []byte) error {
q.TimeEstimate, err = parseDuration(queue["timeleft"], err)
if err != nil {
return fmt.Errorf("Error parsing queue stats: %w", err)
return fmt.Errorf("error parsing queue stats: %w", err)
}
q.DownloadDirDiskspaceTotal *= GB
@ -193,7 +193,7 @@ func parseFloat(s interface{}, prevErr error) (float64, error) {
f, ok := s.(string)
if !ok {
return 0, fmt.Errorf("Invalid float: %v", s)
return 0, fmt.Errorf("invalid float: %v", s)
}
if f == "" {
@ -220,7 +220,7 @@ func parseSize(s interface{}, prevErr error) (float64, error) {
sz, ok := s.(string)
if !ok {
return 0, fmt.Errorf("Invalid float: %v", s)
return 0, fmt.Errorf("invalid float: %v", s)
}
fields := strings.Fields(strings.TrimSpace(sz))
@ -229,7 +229,7 @@ func parseSize(s interface{}, prevErr error) (float64, error) {
}
if len(fields) > 2 {
return 0, fmt.Errorf("Invalid size: %s", sz)
return 0, fmt.Errorf("invalid size: %s", sz)
}
ret, err := strconv.ParseFloat(fields[0], 64)
@ -255,7 +255,7 @@ func parseSize(s interface{}, prevErr error) (float64, error) {
case "PB", "P":
return ret * 1024 * 1024 * 1024 * 1024 * 1024, nil
default:
return 0, fmt.Errorf("Invalid size suffix: %s", sz)
return 0, fmt.Errorf("invalid size suffix: %s", sz)
}
}
@ -271,7 +271,7 @@ func parseDuration(sd interface{}, prevErr error) (time.Duration, error) {
s, ok := sd.(string)
if !ok {
return 0, fmt.Errorf("Invalid float: %v", sd)
return 0, fmt.Errorf("invalid float: %v", sd)
}
if s == "" {
@ -280,7 +280,7 @@ func parseDuration(sd interface{}, prevErr error) (time.Duration, error) {
fields := strings.Split(strings.TrimSpace(s), ":")
if len(fields) < 1 || len(fields) > 4 {
return 0, fmt.Errorf("Invalid duration: %s", s)
return 0, fmt.Errorf("invalid duration: %s", s)
}
intFields := make([]int, len(fields))
@ -290,7 +290,7 @@ func parseDuration(sd interface{}, prevErr error) (time.Duration, error) {
// Reverse the order of the fields
intFields[len(intFields)-1-i], err = strconv.Atoi(f)
if err != nil {
return 0, fmt.Errorf("Invalid integer in duration: %s: %w", f, err)
return 0, fmt.Errorf("invalid integer in duration: %s: %w", f, err)
}
}

View File

@ -17,7 +17,7 @@ func NewTestServer(t *testing.T, fixture_dir string, fn func(http.ResponseWriter
fn(w, r)
require.NotEmpty(t, r.URL.Path)
// turns /api/some/path into some_path
endpoint := strings.Replace(strings.Replace(r.URL.Path, "/api/", "", -1), "/", "_", -1)
endpoint := strings.ReplaceAll(strings.ReplaceAll(r.URL.Path, "/api/", ""), "/", "_")
w.WriteHeader(http.StatusOK)
// NOTE: this assumes there is a file that matches the some_path
json, err := os.ReadFile(filepath.Join(fixture_dir, endpoint+".json"))