1
0
mirror of https://github.com/offen/docker-volume-backup.git synced 2025-11-29 05:46:50 +02:00

Update golangci integration (#637)

* Update golangci integration

* Fix newly discovered errcheck complaints

* Increase timeout value
This commit is contained in:
Frederik Ring
2025-09-09 20:50:46 +02:00
committed by GitHub
parent cbaa17d048
commit 746b8f71f9
13 changed files with 99 additions and 90 deletions

View File

@@ -7,7 +7,6 @@ on:
permissions: permissions:
contents: read contents: read
# Optional: allow read access to pull request. Use with `only-new-issues` option.
pull-requests: read pull-requests: read
jobs: jobs:
@@ -15,40 +14,12 @@ jobs:
name: lint name: lint
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: actions/setup-go@v5 - uses: actions/setup-go@v6
with: with:
go-version: '1.24' go-version: '1.25'
cache: false
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v6 uses: golangci/golangci-lint-action@v8
with: with:
# Require: The version of golangci-lint to use. version: v2.4
# When `install-mode` is `binary` (default) the value can be v1.2 or v1.2.3 or `latest` to use the latest version. args: --timeout 5m
# When `install-mode` is `goinstall` the value can be v1.2.3, `latest`, or the hash of a commit.
version: v1.64
# Optional: working directory, useful for monorepos
# working-directory: somedir
# Optional: golangci-lint command line arguments.
#
# Note: By default, the `.golangci.yml` file should be at the root of the repository.
# The location of the configuration file can be changed by using `--config=`
# args: --timeout=30m --config=/my/path/.golangci.yml --issues-exit-code=0
# Optional: show only new issues if it's a pull request. The default value is `false`.
# only-new-issues: true
# Optional: if set to true, then all caching functionality will be completely disabled,
# takes precedence over all other caching options.
# skip-cache: true
# Optional: if set to true, then the action won't cache or restore ~/go/pkg.
# skip-pkg-cache: true
# Optional: if set to true, then the action won't cache or restore ~/.cache/go-build.
# skip-build-cache: true
# Optional: The mode to install golangci-lint. It can be 'binary' or 'goinstall'.
# install-mode: "goinstall"

View File

@@ -14,7 +14,7 @@ jobs:
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v4 uses: actions/setup-go@v4
with: with:
go-version: '1.24.x' go-version: '1.25.x'
- name: Install dependencies - name: Install dependencies
run: go mod download run: go mod download
- name: Test with the Go CLI - name: Test with the Go CLI

View File

@@ -1,9 +1,7 @@
version: '2'
linters: linters:
# Enable specific linter # Enable specific linter
# https://golangci-lint.run/usage/linters/#enabled-by-default # https://golangci-lint.run/usage/linters/#enabled-by-default
enable: enable:
- staticcheck - staticcheck
- govet - govet
output:
formats:
- format: colored-line-number

View File

@@ -121,10 +121,11 @@ func getCompressionWriter(file *os.File, algo string, concurrency int) (io.Write
} }
} }
func writeTarball(path string, tarWriter *tar.Writer, prefix string) error { func writeTarball(path string, tarWriter *tar.Writer, prefix string) (returnErr error) {
fileInfo, err := os.Lstat(path) fileInfo, err := os.Lstat(path)
if err != nil { if err != nil {
return errwrap.Wrap(err, fmt.Sprintf("error getting file info for %s", path)) returnErr = errwrap.Wrap(err, fmt.Sprintf("error getting file info for %s", path))
return
} }
if fileInfo.Mode()&os.ModeSocket == os.ModeSocket { if fileInfo.Mode()&os.ModeSocket == os.ModeSocket {
@@ -135,19 +136,22 @@ func writeTarball(path string, tarWriter *tar.Writer, prefix string) error {
if fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink { if fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink {
var err error var err error
if link, err = os.Readlink(path); err != nil { if link, err = os.Readlink(path); err != nil {
return errwrap.Wrap(err, fmt.Sprintf("error resolving symlink %s", path)) returnErr = errwrap.Wrap(err, fmt.Sprintf("error resolving symlink %s", path))
return
} }
} }
header, err := tar.FileInfoHeader(fileInfo, link) header, err := tar.FileInfoHeader(fileInfo, link)
if err != nil { if err != nil {
return errwrap.Wrap(err, "error getting file info header") returnErr = errwrap.Wrap(err, "error getting file info header")
return
} }
header.Name = strings.TrimPrefix(path, prefix) header.Name = strings.TrimPrefix(path, prefix)
err = tarWriter.WriteHeader(header) err = tarWriter.WriteHeader(header)
if err != nil { if err != nil {
return errwrap.Wrap(err, "error writing file info header") returnErr = errwrap.Wrap(err, "error writing file info header")
return
} }
if !fileInfo.Mode().IsRegular() { if !fileInfo.Mode().IsRegular() {
@@ -156,13 +160,17 @@ func writeTarball(path string, tarWriter *tar.Writer, prefix string) error {
file, err := os.Open(path) file, err := os.Open(path)
if err != nil { if err != nil {
return errwrap.Wrap(err, fmt.Sprintf("error opening %s", path)) returnErr = errwrap.Wrap(err, fmt.Sprintf("error opening %s", path))
return
} }
defer file.Close() defer func() {
returnErr = file.Close()
}()
_, err = io.Copy(tarWriter, file) _, err = io.Copy(tarWriter, file)
if err != nil { if err != nil {
return errwrap.Wrap(err, fmt.Sprintf("error copying %s to tar writer", path)) returnErr = errwrap.Wrap(err, fmt.Sprintf("error copying %s to tar writer", path))
return
} }
return nil return nil

View File

@@ -153,13 +153,13 @@ func source(path string) (map[string]string, error) {
currentValue, currentOk := os.LookupEnv(key) currentValue, currentOk := os.LookupEnv(key)
defer func() { defer func() {
if currentOk { if currentOk {
os.Setenv(key, currentValue) _ = os.Setenv(key, currentValue)
return return
} }
os.Unsetenv(key) _ = os.Unsetenv(key)
}() }()
result[key] = value result[key] = value
os.Setenv(key, value) _ = os.Setenv(key, value)
} }
} }
return result, nil return result, nil

View File

@@ -60,8 +60,10 @@ func TestSource(t *testing.T) {
}, },
} }
os.Setenv("QUX", "yyy") _ = os.Setenv("QUX", "yyy")
defer os.Unsetenv("QUX") defer func() {
_ = os.Unsetenv("QUX")
}()
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {

View File

@@ -177,8 +177,12 @@ func (s *script) runLabeledCommands(label string) error {
s.logger.Info(fmt.Sprintf("Running %s command %s for container %s", label, cmd, strings.TrimPrefix(c.Names[0], "/"))) s.logger.Info(fmt.Sprintf("Running %s command %s for container %s", label, cmd, strings.TrimPrefix(c.Names[0], "/")))
stdout, stderr, err := s.exec(c.ID, cmd, user) stdout, stderr, err := s.exec(c.ID, cmd, user)
if s.c.ExecForwardOutput { if s.c.ExecForwardOutput {
os.Stderr.Write(stderr) if _, err := os.Stderr.Write(stderr); err != nil {
os.Stdout.Write(stdout) return errwrap.Wrap(err, "error writing to stderr")
}
if _, err := os.Stdout.Write(stdout); err != nil {
return errwrap.Wrap(err, "error writing to stdout")
}
} }
if err != nil { if err != nil {
return errwrap.Wrap(err, "error executing command") return errwrap.Wrap(err, "error executing command")

View File

@@ -13,7 +13,6 @@ import (
"time" "time"
"github.com/docker/cli/cli/command/service/progress" "github.com/docker/cli/cli/command/service/progress"
"github.com/docker/docker/api/types/container"
ctr "github.com/docker/docker/api/types/container" ctr "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm" "github.com/docker/docker/api/types/swarm"
@@ -66,7 +65,7 @@ func awaitContainerCountForService(cli *client.Client, serviceID string, count i
), ),
) )
case <-poll.C: case <-poll.C:
containers, err := cli.ContainerList(context.Background(), container.ListOptions{ containers, err := cli.ContainerList(context.Background(), ctr.ListOptions{
Filters: filters.NewArgs(filters.KeyValuePair{ Filters: filters.NewArgs(filters.KeyValuePair{
Key: "label", Key: "label",
Value: fmt.Sprintf("com.docker.swarm.service.id=%s", serviceID), Value: fmt.Sprintf("com.docker.swarm.service.id=%s", serviceID),
@@ -124,11 +123,11 @@ func (s *script) stopContainersAndServices() (func() error, error) {
labelValue, labelValue,
) )
allContainers, err := s.cli.ContainerList(context.Background(), container.ListOptions{}) allContainers, err := s.cli.ContainerList(context.Background(), ctr.ListOptions{})
if err != nil { if err != nil {
return noop, errwrap.Wrap(err, "error querying for containers") return noop, errwrap.Wrap(err, "error querying for containers")
} }
containersToStop, err := s.cli.ContainerList(context.Background(), container.ListOptions{ containersToStop, err := s.cli.ContainerList(context.Background(), ctr.ListOptions{
Filters: filters.NewArgs(filters.KeyValuePair{ Filters: filters.NewArgs(filters.KeyValuePair{
Key: "label", Key: "label",
Value: filterMatchLabel, Value: filterMatchLabel,
@@ -215,7 +214,7 @@ func (s *script) stopContainersAndServices() (func() error, error) {
) )
} }
var stoppedContainers []container.Summary var stoppedContainers []ctr.Summary
var stopErrors []error var stopErrors []error
for _, container := range containersToStop { for _, container := range containersToStop {
if err := s.cli.ContainerStop(context.Background(), container.ID, ctr.StopOptions{}); err != nil { if err := s.cli.ContainerStop(context.Background(), container.ID, ctr.StopOptions{}); err != nil {

2
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/offen/docker-volume-backup module github.com/offen/docker-volume-backup
go 1.24.0 go 1.25
require ( require (
filippo.io/age v1.2.1 filippo.io/age v1.2.1

View File

@@ -87,7 +87,7 @@ func (b *dropboxStorage) Name() string {
} }
// Copy copies the given file to the WebDav storage backend. // Copy copies the given file to the WebDav storage backend.
func (b *dropboxStorage) Copy(file string) error { func (b *dropboxStorage) Copy(file string) (returnErr error) {
_, name := path.Split(file) _, name := path.Split(file)
folderArg := files.NewCreateFolderArg(b.DestinationPath) folderArg := files.NewCreateFolderArg(b.DestinationPath)
@@ -95,19 +95,24 @@ func (b *dropboxStorage) Copy(file string) error {
switch err := err.(type) { switch err := err.(type) {
case files.CreateFolderV2APIError: case files.CreateFolderV2APIError:
if err.EndpointError.Path.Tag != files.WriteErrorConflict { if err.EndpointError.Path.Tag != files.WriteErrorConflict {
return errwrap.Wrap(err, fmt.Sprintf("error creating directory '%s'", b.DestinationPath)) returnErr = errwrap.Wrap(err, fmt.Sprintf("error creating directory '%s'", b.DestinationPath))
return
} }
b.Log(storage.LogLevelInfo, b.Name(), "Destination path '%s' already exists, no new directory required.", b.DestinationPath) b.Log(storage.LogLevelInfo, b.Name(), "Destination path '%s' already exists, no new directory required.", b.DestinationPath)
default: default:
return errwrap.Wrap(err, fmt.Sprintf("error creating directory '%s'", b.DestinationPath)) returnErr = errwrap.Wrap(err, fmt.Sprintf("error creating directory '%s'", b.DestinationPath))
return
} }
} }
r, err := os.Open(file) r, err := os.Open(file)
if err != nil { if err != nil {
return errwrap.Wrap(err, "error opening the file to be uploaded") returnErr = errwrap.Wrap(err, "error opening the file to be uploaded")
return
} }
defer r.Close() defer func() {
returnErr = r.Close()
}()
// Start new upload session and get session id // Start new upload session and get session id
b.Log(storage.LogLevelInfo, b.Name(), "Starting upload session for backup '%s' at path '%s'.", file, b.DestinationPath) b.Log(storage.LogLevelInfo, b.Name(), "Starting upload session for backup '%s' at path '%s'.", file, b.DestinationPath)
@@ -116,7 +121,8 @@ func (b *dropboxStorage) Copy(file string) error {
uploadSessionStartArg := files.NewUploadSessionStartArg() uploadSessionStartArg := files.NewUploadSessionStartArg()
uploadSessionStartArg.SessionType = &files.UploadSessionType{Tagged: dropbox.Tagged{Tag: files.UploadSessionTypeConcurrent}} uploadSessionStartArg.SessionType = &files.UploadSessionType{Tagged: dropbox.Tagged{Tag: files.UploadSessionTypeConcurrent}}
if res, err := b.client.UploadSessionStart(uploadSessionStartArg, nil); err != nil { if res, err := b.client.UploadSessionStart(uploadSessionStartArg, nil); err != nil {
return errwrap.Wrap(err, "error starting the upload session") returnErr = errwrap.Wrap(err, "error starting the upload session")
return
} else { } else {
sessionId = res.SessionId sessionId = res.SessionId
} }
@@ -197,7 +203,8 @@ loop:
files.NewCommitInfo(path.Join(b.DestinationPath, name)), files.NewCommitInfo(path.Join(b.DestinationPath, name)),
), nil) ), nil)
if err != nil { if err != nil {
return errwrap.Wrap(err, "error finishing the upload session") returnErr = errwrap.Wrap(err, "error finishing the upload session")
return
} }
b.Log(storage.LogLevelInfo, b.Name(), "Uploaded a copy of backup '%s' at path '%s'.", file, b.DestinationPath) b.Log(storage.LogLevelInfo, b.Name(), "Uploaded a copy of backup '%s' at path '%s'.", file, b.DestinationPath)

View File

@@ -11,14 +11,14 @@ import (
"strings" "strings"
"time" "time"
"crypto/tls"
"github.com/offen/docker-volume-backup/internal/errwrap" "github.com/offen/docker-volume-backup/internal/errwrap"
"github.com/offen/docker-volume-backup/internal/storage" "github.com/offen/docker-volume-backup/internal/storage"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google" "golang.org/x/oauth2/google"
"google.golang.org/api/drive/v3" "google.golang.org/api/drive/v3"
"google.golang.org/api/option" "google.golang.org/api/option"
"golang.org/x/oauth2"
"net/http" "net/http"
"crypto/tls"
) )
type googleDriveStorage struct { type googleDriveStorage struct {
@@ -84,15 +84,18 @@ func (b *googleDriveStorage) Name() string {
} }
// Copy copies the given file to the Google Drive storage backend. // Copy copies the given file to the Google Drive storage backend.
func (b *googleDriveStorage) Copy(file string) error { func (b *googleDriveStorage) Copy(file string) (returnErr error) {
_, name := filepath.Split(file) _, name := filepath.Split(file)
b.Log(storage.LogLevelInfo, b.Name(), "Starting upload for backup '%s'.", name) b.Log(storage.LogLevelInfo, b.Name(), "Starting upload for backup '%s'.", name)
f, err := os.Open(file) f, err := os.Open(file)
if err != nil { if err != nil {
return errwrap.Wrap(err, fmt.Sprintf("failed to open file %s", file)) returnErr = errwrap.Wrap(err, fmt.Sprintf("failed to open file %s", file))
return
} }
defer f.Close() defer func() {
returnErr = f.Close()
}()
driveFile := &drive.File{Name: name} driveFile := &drive.File{Name: name}
if b.DestinationPath != "" { if b.DestinationPath != "" {
@@ -104,7 +107,8 @@ func (b *googleDriveStorage) Copy(file string) error {
createCall := b.client.Files.Create(driveFile).SupportsAllDrives(true).Fields("id") createCall := b.client.Files.Create(driveFile).SupportsAllDrives(true).Fields("id")
created, err := createCall.Media(f).Do() created, err := createCall.Media(f).Do()
if err != nil { if err != nil {
return errwrap.Wrap(err, fmt.Sprintf("failed to upload %s", name)) returnErr = errwrap.Wrap(err, fmt.Sprintf("failed to upload %s", name))
return
} }
b.Log(storage.LogLevelInfo, b.Name(), "Finished upload for %s. File ID: %s", name, created.Id) b.Log(storage.LogLevelInfo, b.Name(), "Finished upload for %s. File ID: %s", name, created.Id)

View File

@@ -55,7 +55,9 @@ func (b *localStorage) Copy(file string) error {
if b.latestSymlink != "" { if b.latestSymlink != "" {
symlink := path.Join(b.DestinationPath, b.latestSymlink) symlink := path.Join(b.DestinationPath, b.latestSymlink)
if _, err := os.Lstat(symlink); err == nil { if _, err := os.Lstat(symlink); err == nil {
os.Remove(symlink) if err := os.Remove(symlink); err != nil {
return errwrap.Wrap(err, "error removing existing symlink")
}
} }
if err := os.Symlink(name, symlink); err != nil { if err := os.Symlink(name, symlink); err != nil {
return errwrap.Wrap(err, "error creating latest symlink") return errwrap.Wrap(err, "error creating latest symlink")
@@ -146,22 +148,25 @@ func (b *localStorage) Prune(deadline time.Time, pruningPrefix string) (*storage
} }
// copy creates a copy of the file located at `dst` at `src`. // copy creates a copy of the file located at `dst` at `src`.
func copyFile(src, dst string) error { func copyFile(src, dst string) (returnErr error) {
in, err := os.Open(src) in, err := os.Open(src)
if err != nil { if err != nil {
return err returnErr = err
return
} }
defer in.Close() defer func() {
returnErr = in.Close()
}()
out, err := os.Create(dst) out, err := os.Create(dst)
if err != nil { if err != nil {
return err returnErr = err
return
} }
_, err = io.Copy(out, in) _, err = io.Copy(out, in)
if err != nil { if err != nil {
out.Close() return errors.Join(err, out.Close())
return err
} }
return out.Close() return out.Close()
} }

View File

@@ -106,19 +106,25 @@ func (b *sshStorage) Name() string {
} }
// Copy copies the given file to the SSH storage backend. // Copy copies the given file to the SSH storage backend.
func (b *sshStorage) Copy(file string) error { func (b *sshStorage) Copy(file string) (returnErr error) {
source, err := os.Open(file) source, err := os.Open(file)
_, name := path.Split(file) _, name := path.Split(file)
if err != nil { if err != nil {
return errwrap.Wrap(err, " error reading the file to be uploaded") returnErr = errwrap.Wrap(err, " error reading the file to be uploaded")
return
} }
defer source.Close() defer func() {
returnErr = source.Close()
}()
destination, err := b.sftpClient.Create(path.Join(b.DestinationPath, name)) destination, err := b.sftpClient.Create(path.Join(b.DestinationPath, name))
if err != nil { if err != nil {
return errwrap.Wrap(err, "error creating file") returnErr = errwrap.Wrap(err, "error creating file")
return
} }
defer destination.Close() defer func() {
returnErr = destination.Close()
}()
chunk := make([]byte, 1e9) chunk := make([]byte, 1e9)
for { for {
@@ -126,27 +132,32 @@ func (b *sshStorage) Copy(file string) error {
if err == io.EOF { if err == io.EOF {
tot, err := destination.Write(chunk[:num]) tot, err := destination.Write(chunk[:num])
if err != nil { if err != nil {
return errwrap.Wrap(err, "error uploading the file") returnErr = errwrap.Wrap(err, "error uploading the file")
return
} }
if tot != len(chunk[:num]) { if tot != len(chunk[:num]) {
return errwrap.Wrap(nil, "failed to write stream") returnErr = errwrap.Wrap(nil, "failed to write stream")
return
} }
break break
} }
if err != nil { if err != nil {
return errwrap.Wrap(err, "error uploading the file") returnErr = errwrap.Wrap(err, "error uploading the file")
return
} }
tot, err := destination.Write(chunk[:num]) tot, err := destination.Write(chunk[:num])
if err != nil { if err != nil {
return errwrap.Wrap(err, "error uploading the file") returnErr = errwrap.Wrap(err, "error uploading the file")
return
} }
if tot != len(chunk[:num]) { if tot != len(chunk[:num]) {
return errwrap.Wrap(nil, "failed to write stream") returnErr = errwrap.Wrap(nil, "failed to write stream")
return
} }
} }