Add golangci-lint, fix lint warnings (#227)

* Add golangci-lint, fix lint warnings

Signed-off-by: Russell Troxel <russell@troxel.io>

* Set `shell` on lint actions

Signed-off-by: Russell Troxel <russell@troxel.io>

* go fmt

Signed-off-by: Russell Troxel <russell@troxel.io>

---------

Signed-off-by: Russell Troxel <russell@troxel.io>
This commit is contained in:
Russell Troxel 2023-10-08 11:15:07 -07:00 committed by GitHub
parent 780dc842c3
commit b8426af721
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 102 additions and 40 deletions

View File

@ -10,6 +10,25 @@ runs:
with:
go-version: ">=1.19"
- name: Check Go Fmt
shell: bash
run: |
go version
go fmt ./...
git diff --exit-code
- name: Check Go Mod
shell: bash
run: |
go version
go mod tidy
git diff --exit-code
- uses: golangci/golangci-lint-action@v2
with:
version: v1.51.2
args: --timeout 5m --config .github/lint/golangci.yaml
- name: Run Unit tests
shell: bash
run: |

18
.github/lint/golangci.yaml vendored Normal file
View File

@ -0,0 +1,18 @@
---
run:
timeout: 3m
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

View File

@ -1,7 +1,10 @@
-include .env
.PHONY: build run check fmt tidy lint test
build:
docker build . -t exportarr:local
run:
docker rm --force exportarr || echo ""
docker run --name exportarr \
@ -11,7 +14,17 @@ run:
-e LOG_LEVEL="debug" \
-p 9707:9707 \
-d exportarr:local ${APP_NAME}
test:
go test -v -race -covermode atomic -coverprofile=covprofile ./...
check: fmt tidy lint test
fmt:
go fmt ./...
tidy:
go mod tidy
go mod tidy
lint:
golangci-lint run -c .github/lint/golangci.yaml
test:
go test -v -race -covermode atomic -coverprofile=covprofile ./...

View File

@ -1,6 +1,8 @@
package main
import "github.com/onedr0p/exportarr/internal/commands"
import (
"github.com/onedr0p/exportarr/internal/commands"
)
var (
appName = "exportarr"
@ -10,10 +12,13 @@ var (
)
func main() {
commands.Execute(commands.AppInfo{
err := commands.Execute(commands.AppInfo{
Name: appName,
Version: version,
BuildTime: buildTime,
Revision: revision,
})
if err != nil {
panic(err)
}
}

View File

@ -91,7 +91,9 @@ func (a *FormAuth) Auth(req *http.Request) error {
}
u := a.AuthBaseURL.JoinPath("login")
u.Query().Add("ReturnUrl", "/general/settings")
vals := u.Query()
vals.Add("ReturnUrl", "/general/settings")
u.RawQuery = vals.Encode()
authReq, err := http.NewRequest("POST", u.String(), strings.NewReader(form.Encode()))
if err != nil {
@ -117,12 +119,16 @@ func (a *FormAuth) Auth(req *http.Request) error {
return fmt.Errorf("Failed to renew FormAuth Cookie: Received Status Code %d", authResp.StatusCode)
}
found := false
for _, cookie := range authResp.Cookies() {
if strings.HasSuffix(cookie.Name, "arrAuth") {
copy := *cookie
a.cookie = &copy
found = true
break
}
}
if !found {
return fmt.Errorf("Failed to renew FormAuth Cookie: No Cookie with suffix 'arrAuth' found")
}
}

View File

@ -183,7 +183,7 @@ func TestRoundTrip_Retries(t *testing.T) {
{
name: "Err",
testFunc: func(req *http.Request) (*http.Response, error) {
return nil, &http.ProtocolError{}
return nil, http.ErrNotSupported
},
},
}

View File

@ -117,15 +117,15 @@ func (collector *radarrCollector) Collect(ch chan<- prometheus.Metric) {
}
var fileSize int64
var (
editions = 0
editions = 0
downloaded = 0
monitored = 0
unmonitored = 0
missing = 0
wanted = 0
qualities = map[string]int{}
tags = []struct {
Label string
tags = []struct {
Label string
Movies int
}{}
)
@ -166,22 +166,20 @@ func (collector *radarrCollector) Collect(ch chan<- prometheus.Metric) {
tagObjects := model.TagMovies{}
// https://radarr.video/docs/api/#/TagDetails/get_api_v3_tag_detail
if err := c.DoRequest("tag/detail", &tagObjects); err != nil {
log.Errorw("Error getting Tags", "error", err)
ch <- prometheus.NewInvalidMetric(collector.errorMetric, err)
return
}
log.Errorw("Error getting Tags", "error", err)
ch <- prometheus.NewInvalidMetric(collector.errorMetric, err)
return
}
for _, s := range tagObjects {
tag := struct {
Label string
Label string
Movies int
}{
Label: s.Label,
Label: s.Label,
Movies: len(s.MovieIds),
}
tags = append(tags, tag)
}
ch <- prometheus.MustNewConstMetric(collector.movieEdition, prometheus.GaugeValue, float64(editions))
ch <- prometheus.MustNewConstMetric(collector.movieMetric, prometheus.GaugeValue, float64(len(movies)))

View File

@ -12,7 +12,6 @@ import (
type systemStatusCollector struct {
config *config.ArrConfig // App configuration
configFile *model.Config // *arr configuration from config.xml
systemStatus *prometheus.Desc // Total number of system statuses
errorMetric *prometheus.Desc // Error Description for use with InvalidMetric
}

View File

@ -6,9 +6,9 @@ type Movie []struct {
HasFile bool `json:"hasFile"`
Available bool `json:"isAvailable"`
Monitored bool `json:"monitored"`
MovieFile struct {
Edition string `json:"edition"`
Size int64 `json:"size"`
MovieFile struct {
Edition string `json:"edition"`
Size int64 `json:"size"`
Quality struct {
Quality struct {
Name string `json:"name"`
@ -19,7 +19,7 @@ type Movie []struct {
}
type TagMovies []struct {
ID int `json:"id"`
Label string `json:"label"`
MovieIds []int `json:"movieIds"`
ID int `json:"id"`
Label string `json:"label"`
MovieIds []int `json:"movieIds"`
}

View File

@ -95,7 +95,6 @@ func TestDoRequest_PanicRecovery(t *testing.T) {
require.NoError(err)
w.Write(s)
w.WriteHeader(http.StatusOK)
return
}))
defer ts.Close()

View File

@ -33,7 +33,9 @@ func init() {
func UsageOnError(cmd *cobra.Command, err error) {
if err != nil {
fmt.Fprintln(os.Stderr, err)
cmd.Usage()
if err := cmd.Usage(); err != nil {
panic(err)
}
os.Exit(1)
}
}
@ -178,7 +180,9 @@ var prowlarrCmd = &cobra.Command{
return err
}
c.ApiVersion = "v1"
c.LoadProwlarrConfig(cmd.PersistentFlags())
if err := c.LoadProwlarrConfig(cmd.PersistentFlags()); err != nil {
return err
}
if err := c.Prowlarr.Validate(); err != nil {
return err
}

View File

@ -60,13 +60,17 @@ func initConfig() {
conf, err = config.LoadConfig(rootCmd.PersistentFlags())
if err != nil {
fmt.Fprintln(os.Stderr, err)
rootCmd.Usage()
if err := rootCmd.Usage(); err != nil {
panic(err)
}
os.Exit(1)
}
if err := conf.Validate(); err != nil {
fmt.Fprintln(os.Stderr, err)
rootCmd.Usage()
if err := rootCmd.Usage(); err != nil {
panic(err)
}
os.Exit(1)
}
}
@ -102,7 +106,7 @@ func initLogger() {
func finalizeLogger() {
// Flushes buffered log messages
zap.S().Sync()
zap.S().Sync() //nolint:errcheck
}
type registerFunc func(registry prometheus.Registerer)

View File

@ -78,7 +78,9 @@ func LoadConfig(flags *flag.FlagSet) (*Config, error) {
return nil, fmt.Errorf("Couldn't Read API Key file %w", err)
}
k.Set("api-key", string(data))
if err := k.Set("api-key", string(data)); err != nil {
return nil, fmt.Errorf("Couldn't merge api-key into config: %w", err)
}
}
var out Config

View File

@ -44,7 +44,7 @@ func TestLoadConfig_Flags(t *testing.T) {
require.True(config.DisableSSLVerify)
flags.Set("form-auth", "false")
config, err = LoadConfig(flags)
_, err = LoadConfig(flags)
require.NoError(err)
}

View File

@ -7,6 +7,6 @@ import (
func HealthzHandler(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
w.Write([]byte("OK")) //nolint:errcheck
fmt.Fprint(w)
}

View File

@ -7,5 +7,5 @@ import (
func IndexHandler(w http.ResponseWriter, _ *http.Request) {
response := `<h1>Exportarr</h1><p><a href='/metrics'>metrics</a></p>`
fmt.Fprintf(w, response)
fmt.Fprintln(w, response)
}

View File

@ -3,7 +3,6 @@ package model
import (
"encoding/json"
"fmt"
"reflect"
"sort"
"strconv"
"strings"
@ -178,10 +177,6 @@ func latestStat(m map[string]int) (string, int) {
return key, m[key]
}
func monadCast(i interface{}, t reflect.Type) {
}
// parseFloat is a monad version of strconv.ParseFloat
func parseFloat(s interface{}, prevErr error) (float64, error) {
if prevErr != nil {