From 839467c557916b5f6b77c3ec2f14449a5a6cbf23 Mon Sep 17 00:00:00 2001 From: Dan Anglin Date: Wed, 15 Sep 2021 10:09:48 +0100 Subject: [PATCH] refactor: lint fixes with golangci-lint --- .golangci.yaml | 35 ++++++++++++++++ db.go | 67 ++++++++++++++++++++++--------- db_test.go => db_internal_test.go | 44 +++++++++++++++----- errors.go | 11 +++++ kanban.go | 6 +-- magefile.go | 5 +++ 6 files changed, 134 insertions(+), 34 deletions(-) create mode 100644 .golangci.yaml rename db_test.go => db_internal_test.go (92%) create mode 100644 errors.go diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..707986c --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,35 @@ +--- +run: + concurrency: 2 + timeout: 1m + issues-exit-code: 1 + tests: true + +output: + format: colored-line-number + print-issues-lines: true + print-linter-name: true + uniq-by-line: true + sort-results: true + +linters-settings: + exhaustivestruct: + struct-patterns: + - 'forge.dananglin.me.uk/code/dananglin/pelican.Status' + - 'forge.dananglin.me.uk/code/dananglin/pelican.Card' + lll: + line-length: 140 + testpackage: + skip-regexp: (internal)_test\.go + +linters: + enable-all: true + disable: + - gomnd + fast: false + +issues: + exclude-rules: + - path: db_internal_test.go + linters: + - funlen diff --git a/db.go b/db.go index ded4365..53c4e10 100644 --- a/db.go +++ b/db.go @@ -19,7 +19,11 @@ const ( ) func mkDataDir(dir string) error { - return os.MkdirAll(dir, 0700) + if err := os.MkdirAll(dir, 0o700); err != nil { + return fmt.Errorf("error while making directory %s, %w", dir, err) + } + + return nil } // dbPath returns the path to the database file. If a path is given then that is returned. Otherwise the default path is returned. @@ -32,6 +36,7 @@ func mkDataDir(dir string) error { func dbPath(path string) (string, error) { if len(path) > 0 { filepath.Dir(path) + return path, mkDataDir(filepath.Dir(path)) } @@ -53,14 +58,13 @@ func dbPath(path string) (string, error) { dataDir = filepath.Join(os.Getenv("HOME"), ".pelican") } - if err := os.MkdirAll(dataDir, 0700); err != nil { + if err := os.MkdirAll(dataDir, 0o700); err != nil { return "", fmt.Errorf("unable to make directory %s, %w", dataDir, err) } path = filepath.Join(dataDir, dbFilename) return path, mkDataDir(dataDir) - } // openDatabase opens the database, at a given path, for reading and writing. If the file does not exist it will be created. @@ -69,7 +73,7 @@ func openDatabase(path string) (*bolt.DB, error) { Timeout: 1 * time.Second, } - db, err := bolt.Open(path, 0600, &opts) + db, err := bolt.Open(path, 0o600, &opts) if err != nil { return nil, fmt.Errorf("unable to open database at %s, %w", path, err) } @@ -81,14 +85,20 @@ func openDatabase(path string) (*bolt.DB, error) { func ensureBuckets(db *bolt.DB) error { buckets := []string{statusBucket, cardBucket} - return db.Update(func(tx *bolt.Tx) error { + err := db.Update(func(tx *bolt.Tx) error { for _, v := range buckets { if _, err := tx.CreateBucketIfNotExists([]byte(v)); err != nil { return fmt.Errorf("unable to ensure that %s bucket is created in the database, %w", v, err) } } + return nil }) + if err != nil { + return fmt.Errorf("error while ensuring buckets exist in the database, %w", err) + } + + return nil } // saveStatuses saves one or more statuses to the status bucket. @@ -99,22 +109,22 @@ func saveStatuses(db *bolt.DB, statuses []Status) error { bucket := []byte(statusBucket) - return db.Update(func(tx *bolt.Tx) error { + err := db.Update(func(tx *bolt.Tx) error { b := tx.Bucket(bucket) if b == nil { - return fmt.Errorf("bucket %s does not exist", bucket) + return bucketNotExistError{bucket: string(bucket)} } for _, v := range statuses { var err error - if v.Id == 0 { + if v.ID < 1 { var id uint64 if id, err = b.NextSequence(); err != nil { return fmt.Errorf("unable to generate ID, %w", err) } - v.Id = int(id) + v.ID = int(id) } buf := new(bytes.Buffer) @@ -123,25 +133,31 @@ func saveStatuses(db *bolt.DB, statuses []Status) error { return fmt.Errorf("unable to encode data, %w", err) } - if err = b.Put([]byte(strconv.Itoa(v.Id)), buf.Bytes()); err != nil { + if err = b.Put([]byte(strconv.Itoa(v.ID)), buf.Bytes()); err != nil { return fmt.Errorf("unable to add the status to the bucket, %w", err) } } return nil }) + if err != nil { + return fmt.Errorf("error while saving the statuses to the database, %w", err) + } + + return nil } // loadAllStatuses retrieves all the statuses from the status bucket. func loadAllStatuses(db *bolt.DB) ([]Status, error) { var statuses []Status + bucket := []byte(statusBucket) err := db.View(func(tx *bolt.Tx) error { b := tx.Bucket(bucket) if b == nil { - return fmt.Errorf("bucket %s does not exist", bucket) + return bucketNotExistError{bucket: string(bucket)} } if err := b.ForEach(func(_, v []byte) error { @@ -156,12 +172,16 @@ func loadAllStatuses(db *bolt.DB) ([]Status, error) { return nil }); err != nil { - return err + return fmt.Errorf("unable to load status, %w", err) } + return nil }) + if err != nil { + return statuses, fmt.Errorf("error while loading statuses from the database, %w", err) + } - return statuses, err + return statuses, nil } // saveCard writes a card to the card bucket in BoltDB. @@ -173,15 +193,15 @@ func saveCard(db *bolt.DB, card Card) (int, error) { b := tx.Bucket(bucket) if b == nil { - return fmt.Errorf("bucket %s does not exist", bucket) + return bucketNotExistError{bucket: string(bucket)} } - if card.Id == 0 { + if card.ID < 1 { var id uint64 if id, err = b.NextSequence(); err != nil { return fmt.Errorf("unable to generate an ID for the card, %w", err) } - card.Id = int(id) + card.ID = int(id) } buf := new(bytes.Buffer) @@ -190,26 +210,30 @@ func saveCard(db *bolt.DB, card Card) (int, error) { return fmt.Errorf("unable to encode data, %w", err) } - if err = b.Put([]byte(strconv.Itoa(card.Id)), buf.Bytes()); err != nil { + if err = b.Put([]byte(strconv.Itoa(card.ID)), buf.Bytes()); err != nil { return fmt.Errorf("unable to write the card to the bucket, %w", err) } return nil }) + if err != nil { + return card.ID, fmt.Errorf("error while saving the card to the database, %w", err) + } - return card.Id, err + return card.ID, nil } // loadCard retrieves a card from the cards bucket in BoltDB. func loadCard(db *bolt.DB, id int) (Card, error) { var card Card + bucket := []byte(cardBucket) err := db.View(func(tx *bolt.Tx) error { b := tx.Bucket(bucket) if b == nil { - return fmt.Errorf("bucket %s does not exist", bucket) + return bucketNotExistError{bucket: string(bucket)} } buf := bytes.NewBuffer(b.Get([]byte(strconv.Itoa(id)))) @@ -221,6 +245,9 @@ func loadCard(db *bolt.DB, id int) (Card, error) { return nil }) + if err != nil { + return card, fmt.Errorf("error while loading the card from the database, %w", err) + } - return card, err + return card, nil } diff --git a/db_test.go b/db_internal_test.go similarity index 92% rename from db_test.go rename to db_internal_test.go index 8cb0b63..6b8f748 100644 --- a/db_test.go +++ b/db_internal_test.go @@ -12,6 +12,8 @@ import ( ) func TestDbCustomPath(t *testing.T) { + t.Parallel() + cwd, err := os.Getwd() if err != nil { t.Fatalf("An error occurred whilst getting the current directory, %s", err) @@ -35,6 +37,8 @@ func TestDbCustomPath(t *testing.T) { } func TestDbDefaultPath(t *testing.T) { + t.Parallel() + cwd, err := os.Getwd() if err != nil { t.Fatalf("An error occurred whilst getting the current directory, %s", err) @@ -70,7 +74,10 @@ func TestDbDefaultPath(t *testing.T) { } func TestEnsureBuckets(t *testing.T) { + t.Parallel() + var db *bolt.DB + var err error testDB := "test/databases/TestEnsureBuckets.db" @@ -93,9 +100,10 @@ func TestEnsureBuckets(t *testing.T) { if err = db.View(func(tx *bolt.Tx) error { for _, b := range expectedBuckets { if bucket := tx.Bucket([]byte(b)); bucket == nil { - return fmt.Errorf("bucket %s does not exist in the database", b) + return bucketNotExistError{bucket: b} } } + return nil }); err != nil { t.Fatalf("An error occurred whilst checking for the buckets, %s.", err) @@ -103,7 +111,10 @@ func TestEnsureBuckets(t *testing.T) { } func TestReadAndWriteStatuses(t *testing.T) { + t.Parallel() + var db *bolt.DB + var err error testDB := "test/databases/TestWriteAndReadStatuses.db" @@ -122,18 +133,22 @@ func TestReadAndWriteStatuses(t *testing.T) { // Begin with an initial list of statuses initialStatusList := []Status{ { + ID: -1, Name: "Backlog", CardIds: []int{1, 14, 9, 10}, }, { + ID: -1, Name: "Next", CardIds: []int{2, 5, 12}, }, { + ID: -1, Name: "In progress", CardIds: []int{3}, }, { + ID: -1, Name: "Finished!", CardIds: []int{4, 6, 7, 8, 11, 13}, }, @@ -146,6 +161,7 @@ func TestReadAndWriteStatuses(t *testing.T) { // load the status list from the database, modify it a little and write it to the database. var modifiedStatusList []Status + if modifiedStatusList, err = loadAllStatuses(db); err != nil { t.Fatalf("An error occurred whilst reading the initial status list to the database, %s", err) } @@ -153,6 +169,7 @@ func TestReadAndWriteStatuses(t *testing.T) { modifiedStatusList[2].CardIds = []int{3, 14} archiveStatus := Status{ + ID: -1, Name: "Archived", CardIds: []int{34, 51, 894}, } @@ -166,33 +183,34 @@ func TestReadAndWriteStatuses(t *testing.T) { // read the final status list from the database and compare to the expected status list. want := []Status{ { - Id: 1, + ID: 1, Name: "Backlog", CardIds: []int{1, 14, 9, 10}, }, { - Id: 2, + ID: 2, Name: "Next", CardIds: []int{2, 5, 12}, }, { - Id: 3, + ID: 3, Name: "In progress", CardIds: []int{3, 14}, }, { - Id: 4, + ID: 4, Name: "Finished!", CardIds: []int{4, 6, 7, 8, 11, 13}, }, { - Id: 5, + ID: 5, Name: "Archived", CardIds: []int{34, 51, 894}, }, } var got []Status + if got, err = loadAllStatuses(db); err != nil { t.Fatalf("An error occurred whilst reading the modified status list from the database, %s", err) } @@ -205,7 +223,10 @@ func TestReadAndWriteStatuses(t *testing.T) { } func TestReadAndWriteCards(t *testing.T) { + t.Parallel() + var db *bolt.DB + var err error testDB := "test/databases/TestReadWriteCards.db" @@ -220,35 +241,36 @@ func TestReadAndWriteCards(t *testing.T) { } initialCard := Card{ + ID: -1, Title: "A test task.", Content: "This task should be completed.", } // Save the card - cardId, err := saveCard(db, initialCard) + cardID, err := saveCard(db, initialCard) if err != nil { t.Fatalf("An error occurred whilst saving the initial card to the database, %s", err) } - modifiedCard, err := loadCard(db, cardId) + modifiedCard, err := loadCard(db, cardID) if err != nil { t.Fatalf("An error occurred whilst loading the card from the database, %s", err) } modifiedCard.Title = "Task: Foo bar baz." - modifiedCardId, err := saveCard(db, modifiedCard) + modifiedCardID, err := saveCard(db, modifiedCard) if err != nil { t.Fatalf("An error occurred whilst saving the modified card to the database, %s", err) } want := Card{ - Id: 1, + ID: 1, Title: "Task: Foo bar baz.", Content: "This task should be completed.", } - got, err := loadCard(db, modifiedCardId) + got, err := loadCard(db, modifiedCardID) if err != nil { t.Fatalf("An error occurred whilst loading the modified from the database, %s", err) } diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..5289617 --- /dev/null +++ b/errors.go @@ -0,0 +1,11 @@ +package main + +import "fmt" + +type bucketNotExistError struct { + bucket string +} + +func (e bucketNotExistError) Error() string { + return fmt.Sprintf("bucket %s does not exist", e.bucket) +} diff --git a/kanban.go b/kanban.go index e1c43f8..ece220b 100644 --- a/kanban.go +++ b/kanban.go @@ -2,14 +2,14 @@ package main // Status represents the status of the Kanban board. type Status struct { - Id int + ID int Name string CardIds []int } -// Card represents a card on a Kanban board +// Card represents a card on a Kanban board. type Card struct { - Id int + ID int Title string Content string } diff --git a/magefile.go b/magefile.go index 2a8fcec..4169806 100644 --- a/magefile.go +++ b/magefile.go @@ -35,6 +35,11 @@ func Test() error { return goTest(args...) } +// Lint runs golangci-lint against the code. +func Lint() error { + return sh.RunV("golangci-lint", "run", "--color", "always") +} + // Build build the executable func Build() error { return sh.Run("go", "build", "-o", binary, "main.go")