golangci-lint: enable perfsprint linter

Signed-off-by: Sebastiaan van Stijn <[email protected]>
This commit is contained in:
Sebastiaan van Stijn
2026-09-10 10:25:34 +02:00
committed by Guillaume Lours
parent e9491499f1
commit 063ef45da1
46 changed files with 161 additions and 151 deletions
+1
View File
@@ -27,6 +27,7 @@ linters:
- misspell
- nakedret
- nolintlint
- perfsprint
- revive
- staticcheck
- testifylint
+2 -2
View File
@@ -718,13 +718,13 @@ func selectEventProcessor(dockerCli command.Cli, progress, ansi string, detached
}
case display.ModeTTY:
if ansi == "never" {
return nil, fmt.Errorf("can't use --progress tty while ANSI support is disabled")
return nil, errors.New("can't use --progress tty while ANSI support is disabled")
}
display.Mode = display.ModeTTY
return display.Full(dockerCli.Err(), stdinfo(dockerCli), detached), nil
case display.ModePlain:
if ansi == "always" {
return nil, fmt.Errorf("can't use --progress plain while ANSI support is forced")
return nil, errors.New("can't use --progress plain while ANSI support is forced")
}
display.Mode = display.ModePlain
return display.Plain(dockerCli.Err()), nil
+3 -2
View File
@@ -18,6 +18,7 @@ package compose
import (
"context"
"errors"
"fmt"
"slices"
"strconv"
@@ -63,10 +64,10 @@ func createCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *Bac
PreRunE: AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error {
opts.pullChanged = cmd.Flags().Changed("pull")
if opts.Build && opts.noBuild {
return fmt.Errorf("--build and --no-build are incompatible")
return errors.New("--build and --no-build are incompatible")
}
if opts.forceRecreate && opts.noRecreate {
return fmt.Errorf("--force-recreate and --no-recreate are incompatible")
return errors.New("--force-recreate and --no-recreate are incompatible")
}
return nil
}),
+2 -2
View File
@@ -19,8 +19,8 @@ package compose
import (
"context"
"errors"
"fmt"
"os"
"strconv"
"github.com/compose-spec/compose-go/v2/types"
"github.com/docker/cli/cli"
@@ -133,7 +133,7 @@ func runExec(ctx context.Context, dockerCli command.Cli, backendOptions *Backend
}
exitCode, err := backend.Exec(ctx, projectName, execOpts)
if exitCode != 0 {
errMsg := fmt.Sprintf("exit status %d", exitCode)
errMsg := "exit status " + strconv.Itoa(exitCode)
if err != nil && err.Error() != "" {
errMsg = err.Error()
}
+2 -1
View File
@@ -18,6 +18,7 @@ package compose
import (
"context"
"errors"
"fmt"
"os"
@@ -58,7 +59,7 @@ func generateCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *B
func runGenerate(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts generateOptions, containers []string) error {
_, _ = fmt.Fprintln(os.Stderr, "generate command is EXPERIMENTAL")
if len(containers) == 0 {
return fmt.Errorf("at least one container must be specified")
return errors.New("at least one container must be specified")
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
+3 -2
View File
@@ -18,6 +18,7 @@ package compose
import (
"context"
"errors"
"fmt"
"io"
"os"
@@ -169,7 +170,7 @@ func promptForInterpolatedVariables(ctx context.Context, dockerCli command.Cli,
}
if !confirmed {
return fmt.Errorf("operation cancelled by user")
return errors.New("operation cancelled by user")
}
return nil
@@ -292,7 +293,7 @@ func confirmRemoteIncludes(dockerCli command.Cli, options buildOptions, assumeYe
return err
}
if !confirmed {
return fmt.Errorf("operation cancelled by user")
return errors.New("operation cancelled by user")
}
return nil
+4 -4
View File
@@ -18,7 +18,7 @@ package compose
import (
"context"
"fmt"
"errors"
"os"
"strings"
@@ -168,7 +168,7 @@ func runCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *Backen
options.Command = args[1:]
}
if len(options.publish) > 0 && options.servicePorts {
return fmt.Errorf("--service-ports and --publish are incompatible")
return errors.New("--service-ports and --publish are incompatible")
}
if cmd.Flags().Changed("entrypoint") {
command, err := shellwords.Parse(options.entrypoint)
@@ -179,7 +179,7 @@ func runCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *Backen
}
if cmd.Flags().Changed("tty") {
if cmd.Flags().Changed("no-tty") {
return fmt.Errorf("--tty and --no-tty can't be used together")
return errors.New("--tty and --no-tty can't be used together")
} else {
options.noTty = !ttyFlag
}
@@ -303,7 +303,7 @@ func runRun(ctx context.Context, backend api.Compose, project *types.Project, op
for _, s := range options.labels {
key, val, ok := strings.Cut(s, "=")
if !ok {
return fmt.Errorf("label must be set as KEY=VALUE")
return errors.New("label must be set as KEY=VALUE")
}
labels[key] = val
}
+11 -11
View File
@@ -138,7 +138,7 @@ func upCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *Backend
up.resolveNavigationMenu(dockerCli)
if !p.All && len(project.Services) == 0 {
return fmt.Errorf("no service selected")
return errors.New("no service selected")
}
return runUp(ctx, dockerCli, backendOptions, create, up, build, project, services)
@@ -188,41 +188,41 @@ func upCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *Backend
func validateFlags(up *upOptions, create *createOptions) error {
if up.waitTimeout < 0 {
return fmt.Errorf("--wait-timeout must be a non-negative integer")
return errors.New("--wait-timeout must be a non-negative integer")
}
if up.exitCodeFrom != "" && !up.cascadeFail {
up.cascadeStop = true
}
if up.cascadeStop && up.cascadeFail {
return fmt.Errorf("--abort-on-container-failure cannot be combined with --abort-on-container-exit")
return errors.New("--abort-on-container-failure cannot be combined with --abort-on-container-exit")
}
if up.wait {
if up.attachDependencies || up.cascadeStop || len(up.attach) > 0 {
return fmt.Errorf("--wait cannot be combined with --abort-on-container-exit, --attach or --attach-dependencies")
return errors.New("--wait cannot be combined with --abort-on-container-exit, --attach or --attach-dependencies")
}
up.Detach = true
}
if create.Build && create.noBuild {
return fmt.Errorf("--build and --no-build are incompatible")
return errors.New("--build and --no-build are incompatible")
}
if up.Detach && (up.attachDependencies || up.cascadeStop || up.cascadeFail || len(up.attach) > 0 || up.watch) {
if up.wait {
return fmt.Errorf("--wait cannot be combined with --abort-on-container-exit, --abort-on-container-failure, --attach, --attach-dependencies or --watch")
return errors.New("--wait cannot be combined with --abort-on-container-exit, --abort-on-container-failure, --attach, --attach-dependencies or --watch")
} else {
return fmt.Errorf("--detach cannot be combined with --abort-on-container-exit, --abort-on-container-failure, --attach, --attach-dependencies or --watch")
return errors.New("--detach cannot be combined with --abort-on-container-exit, --abort-on-container-failure, --attach, --attach-dependencies or --watch")
}
}
if create.noInherit && create.noRecreate {
return fmt.Errorf("--no-recreate and --renew-anon-volumes are incompatible")
return errors.New("--no-recreate and --renew-anon-volumes are incompatible")
}
if create.forceRecreate && create.noRecreate {
return fmt.Errorf("--force-recreate and --no-recreate are incompatible")
return errors.New("--force-recreate and --no-recreate are incompatible")
}
if create.recreateDeps && create.noRecreate {
return fmt.Errorf("--always-recreate-deps and --no-recreate are incompatible")
return errors.New("--always-recreate-deps and --no-recreate are incompatible")
}
if create.noBuild && up.watch {
return fmt.Errorf("--no-build and --watch are incompatible")
return errors.New("--no-build and --watch are incompatible")
}
return nil
}
+1 -1
View File
@@ -283,7 +283,7 @@ func (c *ContainerContext) Mounts() string {
// LocalVolumes returns the number of volumes using the "local" volume driver.
func (c *ContainerContext) LocalVolumes() string {
return fmt.Sprintf("%d", c.c.LocalVolumes)
return strconv.Itoa(c.c.LocalVolumes)
}
// Networks returns a comma-separated string of networks that the container is
+6 -6
View File
@@ -61,7 +61,7 @@ func (ke *KeyboardError) printError(height int, info string) {
func (ke *KeyboardError) addError(prefix string, err error) {
ke.timeStart = time.Now()
prefix = ansiColor(CYAN, fmt.Sprintf("%s →", prefix), BOLD)
prefix = ansiColor(CYAN, prefix+" →", BOLD)
errorString := fmt.Sprintf("%s %s", prefix, err.Error())
ke.err = errors.New(errorString)
@@ -210,10 +210,10 @@ func (lk *LogKeyboard) openDockerDesktop(ctx context.Context, project *types.Pro
go func() {
_ = tracing.EventWrapFuncForErrGroup(ctx, "menu/gui", tracing.SpanOptions{},
func(ctx context.Context) error {
link := fmt.Sprintf("docker-desktop://dashboard/apps/%s", project.Name)
link := "docker-desktop://dashboard/apps/" + project.Name
err := open.Run(link)
if err != nil {
err = fmt.Errorf("could not open Docker Desktop")
err = errors.New("could not open Docker Desktop")
lk.keyboardError("View", err)
}
return err
@@ -228,10 +228,10 @@ func (lk *LogKeyboard) openDDComposeUI(ctx context.Context, project *types.Proje
go func() {
_ = tracing.EventWrapFuncForErrGroup(ctx, "menu/gui/composeview", tracing.SpanOptions{},
func(ctx context.Context) error {
link := fmt.Sprintf("docker-desktop://dashboard/docker-compose/%s", project.Name)
link := "docker-desktop://dashboard/docker-compose/" + project.Name
err := open.Run(link)
if err != nil {
err = fmt.Errorf("could not open Docker Desktop Compose UI")
err = errors.New("could not open Docker Desktop Compose UI")
lk.keyboardError("View Config", err)
}
return err
@@ -264,7 +264,7 @@ func (lk *LogKeyboard) openDDWatchDocs(ctx context.Context, project *types.Proje
link := fmt.Sprintf("docker-desktop://dashboard/docker-compose/%s/watch", project.Name)
err := open.Run(link)
if err != nil {
err = fmt.Errorf("could not open Docker Desktop Compose UI")
err = errors.New("could not open Docker Desktop Compose UI")
lk.keyboardError("Watch Docs", err)
}
return err
+1 -2
View File
@@ -17,7 +17,6 @@
package locker
import (
"fmt"
"path/filepath"
)
@@ -30,6 +29,6 @@ func NewPidfile(projectName string) (*Pidfile, error) {
if err != nil {
return nil, err
}
path := filepath.Join(run, fmt.Sprintf("%s.pid", projectName))
path := filepath.Join(run, projectName+".pid")
return &Pidfile{path: path}, nil
}
+3 -3
View File
@@ -20,7 +20,7 @@ package memnet
import (
"context"
"fmt"
"errors"
"net"
"syscall"
)
@@ -28,12 +28,12 @@ import (
const maxUnixSocketPathSize = len(syscall.RawSockaddrUnix{}.Path)
func dialNamedPipe(_ context.Context, _ string) (net.Conn, error) {
return nil, fmt.Errorf("named pipes are only available on Windows")
return nil, errors.New("named pipes are only available on Windows")
}
func validateSocketPath(addr string) error {
if len(addr) > maxUnixSocketPathSize {
return fmt.Errorf("socket address is too long: %s", addr)
return errors.New("socket address is too long: " + addr)
}
return nil
}
+2 -2
View File
@@ -19,8 +19,8 @@ package tracing
import (
"context"
"crypto/sha256"
hex "encoding/hex"
"encoding/json"
"fmt"
"strings"
"time"
@@ -192,5 +192,5 @@ func projectHash(p *types.Project) (string, bool) {
return "", false
}
d := sha256.Sum256(projData)
return fmt.Sprintf("%x", d), true
return hex.EncodeToString(d[:]), true
}
+3 -3
View File
@@ -485,7 +485,7 @@ func (s *composeService) getBuildxPlugin() (*manager.Plugin, error) {
}
if buildx.Version == "" {
return nil, fmt.Errorf("failed to get version of buildx")
return nil, errors.New("failed to get version of buildx")
}
if versions.LessThan(buildx.Version[1:], buildxMinVersion) {
@@ -647,12 +647,12 @@ func (s *composeService) dryRunBake(cfg bakeConfig) map[string]string {
s.events.On(api.Resource{
ID: name + " ==>",
Status: api.Done,
Text: fmt.Sprintf("==> writing image %s", dryRunUUID),
Text: "==> writing image " + dryRunUUID,
})
s.events.On(api.Resource{
ID: name + " ==> ==>",
Status: api.Done,
Text: fmt.Sprintf(`naming to %s`, target.Tags[0]),
Text: "naming to " + target.Tags[0],
})
bakeResponse[name] = dryRunUUID
}
+6 -6
View File
@@ -232,19 +232,19 @@ func (s *composeService) doBuildImage(ctx context.Context, project *types.Projec
// doesn't implement
func checkClassicBuilderSupported(service types.ServiceConfig) error {
if len(service.Build.Platforms) > 1 {
return fmt.Errorf("the classic builder doesn't support multi-arch build; building with BuildKit requires the buildx Docker CLI plugin, and DOCKER_BUILDKIT must not be set to 0")
return errors.New("the classic builder doesn't support multi-arch build; building with BuildKit requires the buildx Docker CLI plugin, and DOCKER_BUILDKIT must not be set to 0")
}
if service.Build.Privileged {
return fmt.Errorf("the classic builder doesn't support privileged mode; building with BuildKit requires the buildx Docker CLI plugin, and DOCKER_BUILDKIT must not be set to 0")
return errors.New("the classic builder doesn't support privileged mode; building with BuildKit requires the buildx Docker CLI plugin, and DOCKER_BUILDKIT must not be set to 0")
}
if len(service.Build.AdditionalContexts) > 0 {
return fmt.Errorf("the classic builder doesn't support additional contexts; building with BuildKit requires the buildx Docker CLI plugin, and DOCKER_BUILDKIT must not be set to 0")
return errors.New("the classic builder doesn't support additional contexts; building with BuildKit requires the buildx Docker CLI plugin, and DOCKER_BUILDKIT must not be set to 0")
}
if len(service.Build.SSH) > 0 {
return fmt.Errorf("the classic builder doesn't support SSH keys; building with BuildKit requires the buildx Docker CLI plugin, and DOCKER_BUILDKIT must not be set to 0")
return errors.New("the classic builder doesn't support SSH keys; building with BuildKit requires the buildx Docker CLI plugin, and DOCKER_BUILDKIT must not be set to 0")
}
if len(service.Build.Secrets) > 0 {
return fmt.Errorf("the classic builder doesn't support secrets; building with BuildKit requires the buildx Docker CLI plugin, and DOCKER_BUILDKIT must not be set to 0")
return errors.New("the classic builder doesn't support secrets; building with BuildKit requires the buildx Docker CLI plugin, and DOCKER_BUILDKIT must not be set to 0")
}
return nil
}
@@ -260,7 +260,7 @@ func prepareClassicBuildContext(specifiedContext, dockerfileName string, progBuf
bctx := &classicBuildContext{cleanup: func() {}}
switch contextType {
case build.ContextTypeStdin:
return nil, fmt.Errorf("building from STDIN is not supported")
return nil, errors.New("building from STDIN is not supported")
case build.ContextTypeLocal:
bctx.contextDir, bctx.relDockerfile, err = build.GetContextFromLocalDir(specifiedContext, dockerfileName)
if err != nil {
+1 -2
View File
@@ -18,7 +18,6 @@ package compose
import (
"context"
"fmt"
"strings"
"github.com/moby/moby/client"
@@ -71,7 +70,7 @@ func (s *composeService) commit(ctx context.Context, projectName string, options
s.events.On(api.Resource{
ID: name,
Text: fmt.Sprintf("Committed as %s", response.ID),
Text: "Committed as " + response.ID,
Status: api.Done,
})
+1 -1
View File
@@ -526,7 +526,7 @@ func (s *composeService) RuntimeAPIVersion(ctx context.Context) (string, error)
version := cli.ClientVersion()
if version == "" {
return "", fmt.Errorf("docker client returned empty version after successful API negotiation")
return "", errors.New("docker client returned empty version after successful API negotiation")
}
s.runtimeAPIVersion.val = version
+2 -2
View File
@@ -1452,7 +1452,7 @@ func (s *composeService) createNetwork(ctx context.Context, n *types.NetworkConf
EnableIPv4: n.EnableIPv4,
}
networkEventName := fmt.Sprintf("Network %s", n.Name)
networkEventName := "Network " + n.Name
s.events.On(creatingEvent(networkEventName))
if _, err := s.apiClient().NetworkCreate(ctx, n.Name, networkCreateOptions); err != nil {
@@ -1523,7 +1523,7 @@ func (s *composeService) resolveExternalNetwork(ctx context.Context, n *types.Ne
}
func (s *composeService) createVolume(ctx context.Context, volume types.VolumeConfig) error {
eventName := fmt.Sprintf("Volume %s", volume.Name)
eventName := "Volume " + volume.Name
s.events.On(creatingEvent(eventName))
hash, err := VolumeHash(volume)
if err != nil {
+6 -8
View File
@@ -18,8 +18,8 @@ package compose
import (
"context"
"fmt"
"sort"
"strconv"
"sync"
"testing"
@@ -62,12 +62,10 @@ func TestTraversalWithMultipleParents(t *testing.T) {
Services: types.Services{"dependent": dependent},
}
for i := 1; i <= 100; i++ {
name := fmt.Sprintf("svc_%d", i)
for i := range 100 {
name := "svc_" + strconv.Itoa(i+1)
dependent.DependsOn[name] = types.ServiceDependency{}
svc := types.ServiceConfig{Name: name}
project.Services[name] = svc
project.Services[name] = types.ServiceConfig{Name: name}
}
svc := make(chan string, 10)
@@ -262,7 +260,7 @@ func TestBuildGraph(t *testing.T) {
}
graph, err := NewGraph(&project, ServiceStopped)
assert.NilError(t, err, fmt.Sprintf("failed to build graph for: %s", tC.desc))
assert.NilError(t, err, "failed to build graph for: "+tC.desc)
for k, vertex := range graph.Vertices {
expected, ok := tC.expectedVertices[k]
@@ -312,7 +310,7 @@ func TestBuildGraphDependsOn(t *testing.T) {
}
graph, err := NewGraph(&project, ServiceStopped)
assert.NilError(t, err, fmt.Sprintf("failed to build graph for: %s", tC.desc))
assert.NilError(t, err, "failed to build graph for: "+tC.desc)
for k, vertex := range graph.Vertices {
expected, ok := tC.expectedVertices[k]
+2 -2
View File
@@ -232,7 +232,7 @@ func (s *composeService) removeNetwork(ctx context.Context, composeNetworkName s
return nil
}
eventName := fmt.Sprintf("Network %s", name)
eventName := "Network " + name
s.events.On(removingEvent(eventName))
var found int
@@ -277,7 +277,7 @@ func (s *composeService) removeNetwork(ctx context.Context, composeNetworkName s
}
func (s *composeService) removeVolume(ctx context.Context, id string) error {
resource := fmt.Sprintf("Volume %s", id)
resource := "Volume " + id
_, err := s.apiClient().VolumeInspect(ctx, id, client.VolumeInspectOptions{})
if errdefs.IsNotFound(err) {
+2 -1
View File
@@ -17,6 +17,7 @@
package compose
import (
"errors"
"fmt"
"os"
"strings"
@@ -669,7 +670,7 @@ func TestDownHookContainerRemovalFailureIsNonFatal(t *testing.T) {
// Removal fails — Down must still return nil.
api.EXPECT().ContainerRemove(gomock.Any(), "hook-2",
client.ContainerRemoveOptions{Force: true, RemoveVolumes: true}).
Return(client.ContainerRemoveResult{}, fmt.Errorf("daemon busy"))
Return(client.ContainerRemoveResult{}, errors.New("daemon busy"))
err = tested.Down(t.Context(), strings.ToLower(testProject), compose.DownOptions{})
assert.NilError(t, err)
+6 -6
View File
@@ -19,7 +19,7 @@ package compose
import (
"context"
"errors"
"fmt"
"strconv"
"testing"
"github.com/compose-spec/compose-go/v2/types"
@@ -233,11 +233,11 @@ func TestExecutePlanConcurrentRemovesCacheCoherence(t *testing.T) {
ctrs := make([]container.Summary, replicas)
for i := range ctrs {
ctrs[i] = container.Summary{
ID: fmt.Sprintf("c%d", i),
Names: []string{fmt.Sprintf("/test-web-%d", i+1)},
ID: "c" + strconv.Itoa(i),
Names: []string{"/test-web-" + strconv.Itoa(i+1)},
Labels: map[string]string{
api.ServiceLabel: "web",
api.ContainerNumberLabel: fmt.Sprintf("%d", i+1),
api.ContainerNumberLabel: strconv.Itoa(i + 1),
},
}
}
@@ -268,13 +268,13 @@ func TestExecutePlanConcurrentRemovesCacheCoherence(t *testing.T) {
for i := range ctrs {
stop := plan.addNode(Operation{
Type: OpStopContainer,
ResourceID: fmt.Sprintf("service:web:%d", i+1),
ResourceID: "service:web:" + strconv.Itoa(i+1),
Cause: "scale down",
Container: &ctrs[i],
}, "")
plan.addNode(Operation{
Type: OpRemoveContainer,
ResourceID: fmt.Sprintf("service:web:%d", i+1),
ResourceID: "service:web:" + strconv.Itoa(i+1),
Cause: "scale down",
Container: &ctrs[i],
}, "", stop)
+2 -1
View File
@@ -18,6 +18,7 @@ package compose
import (
"context"
"errors"
"fmt"
"io"
"strings"
@@ -45,7 +46,7 @@ func (s *composeService) export(ctx context.Context, projectName string, options
if options.Output == "" {
if s.stdout().IsTerminal() {
return fmt.Errorf("output option is required when exporting to terminal")
return errors.New("output option is required when exporting to terminal")
}
} else if err := command.ValidateOutputPath(options.Output); err != nil {
return fmt.Errorf("failed to export container: %w", err)
+5 -5
View File
@@ -22,7 +22,7 @@ import (
"bufio"
"context"
"encoding/binary"
"fmt"
"errors"
"io"
"net"
"os"
@@ -460,7 +460,7 @@ func TestRunHook_CopyError(t *testing.T) {
// Build a pipe whose read side immediately returns a hard error, simulating
// an I/O failure mid-stream rather than a clean EOF.
pr, pw := io.Pipe()
_ = pw.CloseWithError(fmt.Errorf("simulated I/O failure"))
_ = pw.CloseWithError(errors.New("simulated I/O failure"))
// Use net.Pipe() only for the Conn field (Close); reads come from pr.
serverConn, clientConn := net.Pipe()
@@ -524,7 +524,7 @@ func TestRunHook_ExecCreateError(t *testing.T) {
mockAPI.EXPECT().
ExecCreate(gomock.Any(), "ctr-1", gomock.Any()).
Return(client.ExecCreateResult{}, fmt.Errorf("exec create failed"))
Return(client.ExecCreateResult{}, errors.New("exec create failed"))
s, err := NewComposeService(mockCli)
assert.NilError(t, err)
@@ -552,7 +552,7 @@ func TestRunHook_ExecAttachError(t *testing.T) {
Return(client.ExecCreateResult{ID: "exec-1"}, nil)
mockAPI.EXPECT().
ExecAttach(gomock.Any(), "exec-1", gomock.Any()).
Return(client.ExecAttachResult{}, fmt.Errorf("exec attach failed"))
Return(client.ExecAttachResult{}, errors.New("exec attach failed"))
s, err := NewComposeService(mockCli)
assert.NilError(t, err)
@@ -590,7 +590,7 @@ func TestRunHook_ExecInspectError(t *testing.T) {
mockAPI.EXPECT().
ExecInspect(gomock.Any(), "exec-1", gomock.Any()).
Return(client.ExecInspectResult{}, fmt.Errorf("inspect failed"))
Return(client.ExecInspectResult{}, errors.New("inspect failed"))
s, err := NewComposeService(mockCli)
assert.NilError(t, err)
+2 -1
View File
@@ -20,6 +20,7 @@ import (
"bufio"
"context"
"encoding/json"
"errors"
"fmt"
"os/exec"
"slices"
@@ -82,7 +83,7 @@ func (s *composeService) newModelAPI(project *types.Project) (*modelAPI, error)
dockerModel, err := manager.GetPlugin("model", s.dockerCli, &cobra.Command{})
if err != nil {
if errdefs.IsNotFound(err) {
return nil, fmt.Errorf("'models' support requires Docker Model plugin")
return nil, errors.New("'models' support requires Docker Model plugin")
}
return nil, err
}
+1 -1
View File
@@ -287,7 +287,7 @@ func (s *composeService) setupPluginCommand(ctx context.Context, project *types.
return nil, err
}
args := []string{"compose", fmt.Sprintf("--project-name=%s", project.Name), command}
args := []string{"compose", "--project-name=" + project.Name, command}
for k, v := range provider.Options {
for _, value := range v {
if _, ok := currentCommandMetadata.GetParameter(k); commandMetadataIsEmpty || ok {
+16 -16
View File
@@ -19,7 +19,7 @@ package compose
import (
"bytes"
"context"
"fmt"
"errors"
"io"
"strings"
"testing"
@@ -301,7 +301,7 @@ func TestPreStart_ContainerCreateFailurePropagates(t *testing.T) {
scan := expectEmptyOrphanScan(apiClient)
apiClient.EXPECT().ContainerCreate(gomock.Any(), gomock.Any()).
Return(client.ContainerCreateResult{}, fmt.Errorf("no such image: missing:latest")).After(scan)
Return(client.ContainerCreateResult{}, errors.New("no such image: missing:latest")).After(scan)
err := tested.runPreStart(t.Context(), project, service, ctr, func(api.ContainerEvent) {})
assert.ErrorContains(t, err, "no such image")
@@ -328,7 +328,7 @@ func TestPreStart_ContainerStartFailurePropagates(t *testing.T) {
logs1 := apiClient.EXPECT().ContainerLogs(gomock.Any(), "hook-1", gomock.Any()).
Return(emptyLogs(), nil).After(wait1)
start1 := apiClient.EXPECT().ContainerStart(gomock.Any(), "hook-1", gomock.Any()).
Return(client.ContainerStartResult{}, fmt.Errorf("daemon: container start failed")).After(logs1)
Return(client.ContainerStartResult{}, errors.New("daemon: container start failed")).After(logs1)
// AutoRemove never fires when start fails, so the hook must drop the ghost
// container explicitly. This is distinct from the success-path removal
// (RemoveVolumes:true) — the never-started container has no logs to preserve.
@@ -404,7 +404,7 @@ func TestWaitPreStart_RaceRealErrorAndResult(t *testing.T) {
resultC := make(chan container.WaitResponse, 1)
errC := make(chan error, 1)
resultC <- container.WaitResponse{StatusCode: 0}
errC <- fmt.Errorf("daemon: connection lost")
errC <- errors.New("daemon: connection lost")
waitRes := client.ContainerWaitResult{Result: resultC, Error: errC}
err := waitPreStart(t.Context(), "web", 0, waitRes)
assert.ErrorContains(t, err, "connection lost")
@@ -691,7 +691,7 @@ func TestPreStart_SuccessRemoveFailureIsNonFatal(t *testing.T) {
// Simulate a removal failure.
apiClient.EXPECT().
ContainerRemove(gomock.Any(), "hook-1", client.ContainerRemoveOptions{RemoveVolumes: true}).
Return(client.ContainerRemoveResult{}, fmt.Errorf("already removed"))
Return(client.ContainerRemoveResult{}, errors.New("already removed"))
// The hook succeeded; the service must start even if removal failed.
err := tested.runPreStart(t.Context(), project, service, ctr, nil)
@@ -778,7 +778,7 @@ func TestPreStart_StreamLogsError_NilListener(t *testing.T) {
Return(waitResultExit(0))
// ContainerLogs fails; nil listener → no warning event, done closed immediately.
apiClient.EXPECT().ContainerLogs(gomock.Any(), "hook-1", gomock.Any()).
Return(nil, fmt.Errorf("logs: connection refused"))
Return(nil, errors.New("logs: connection refused"))
apiClient.EXPECT().ContainerStart(gomock.Any(), "hook-1", gomock.Any()).
Return(client.ContainerStartResult{}, nil)
expectSuccessRemove(apiClient, "hook-1")
@@ -809,7 +809,7 @@ func TestPreStart_StreamLogsError_WithListener(t *testing.T) {
apiClient.EXPECT().ContainerWait(gomock.Any(), "hook-1", gomock.Any()).
Return(waitResultExit(0))
apiClient.EXPECT().ContainerLogs(gomock.Any(), "hook-1", gomock.Any()).
Return(nil, fmt.Errorf("logs: daemon unavailable"))
Return(nil, errors.New("logs: daemon unavailable"))
apiClient.EXPECT().ContainerStart(gomock.Any(), "hook-1", gomock.Any()).
Return(client.ContainerStartResult{}, nil)
expectSuccessRemove(apiClient, "hook-1")
@@ -917,7 +917,7 @@ func TestPreStart_ConnectExtraNetworksFails(t *testing.T) {
apiClient.EXPECT().
NetworkConnect(gomock.Any(), "proj_extra", gomock.Any()).
Return(client.NetworkConnectResult{}, fmt.Errorf("network not found"))
Return(client.NetworkConnectResult{}, errors.New("network not found"))
err := tested.connectPreStartExtraNetworks(t.Context(), project, service, "ctr-id", "proj_default")
assert.ErrorContains(t, err, "network not found")
@@ -947,10 +947,10 @@ func TestPreStart_ContainerStartFailureAndRemoveFails(t *testing.T) {
logs1 := apiClient.EXPECT().ContainerLogs(gomock.Any(), "hook-1", gomock.Any()).
Return(emptyLogs(), nil)
start1 := apiClient.EXPECT().ContainerStart(gomock.Any(), "hook-1", gomock.Any()).
Return(client.ContainerStartResult{}, fmt.Errorf("start failed")).After(logs1)
Return(client.ContainerStartResult{}, errors.New("start failed")).After(logs1)
// Both the start AND the cleanup removal fail.
apiClient.EXPECT().ContainerRemove(gomock.Any(), "hook-1", client.ContainerRemoveOptions{Force: true, RemoveVolumes: true}).
Return(client.ContainerRemoveResult{}, fmt.Errorf("removal failed")).After(start1)
Return(client.ContainerRemoveResult{}, errors.New("removal failed")).After(start1)
err := tested.runPreStart(t.Context(), project, service, ctr, nil)
// The original start error must be returned, not the removal error.
@@ -975,7 +975,7 @@ func TestPreStart_OrphanScanFails(t *testing.T) {
// ContainerList fails → Warnf in runPreStart; hook still proceeds.
apiClient.EXPECT().ContainerList(gomock.Any(), gomock.Any()).
Return(client.ContainerListResult{}, fmt.Errorf("daemon unavailable"))
Return(client.ContainerListResult{}, errors.New("daemon unavailable"))
apiClient.EXPECT().ContainerCreate(gomock.Any(), gomock.Any()).
Return(client.ContainerCreateResult{ID: "hook-1"}, nil)
apiClient.EXPECT().ContainerWait(gomock.Any(), "hook-1", gomock.Any()).
@@ -1012,7 +1012,7 @@ func TestPreStart_OrphanRemovalFails(t *testing.T) {
Return(client.ContainerListResult{Items: []container.Summary{orphan}}, nil)
apiClient.EXPECT().
ContainerRemove(gomock.Any(), "orphan-123", client.ContainerRemoveOptions{Force: true, RemoveVolumes: true}).
Return(client.ContainerRemoveResult{}, fmt.Errorf("permission denied"))
Return(client.ContainerRemoveResult{}, errors.New("permission denied"))
// Hook still runs and succeeds.
apiClient.EXPECT().ContainerCreate(gomock.Any(), gomock.Any()).
Return(client.ContainerCreateResult{ID: "hook-1"}, nil)
@@ -1059,7 +1059,7 @@ func TestPreStart_OldAPINetworkConnectFails(t *testing.T) {
Return(client.ContainerCreateResult{ID: "hook-1"}, nil).After(scan)
// NetworkConnect for the secondary network fails.
apiClient.EXPECT().NetworkConnect(gomock.Any(), "proj_extra", gomock.Any()).
Return(client.NetworkConnectResult{}, fmt.Errorf("network not found"))
Return(client.NetworkConnectResult{}, errors.New("network not found"))
// The never-started container is cleaned up (Force:true).
apiClient.EXPECT().
ContainerRemove(gomock.Any(), "hook-1", client.ContainerRemoveOptions{Force: true, RemoveVolumes: true}).
@@ -1098,11 +1098,11 @@ func TestPreStart_OldAPINetworkConnectAndRemoveFails(t *testing.T) {
apiClient.EXPECT().ContainerCreate(gomock.Any(), gomock.Any()).
Return(client.ContainerCreateResult{ID: "hook-1"}, nil).After(scan)
apiClient.EXPECT().NetworkConnect(gomock.Any(), "proj_extra", gomock.Any()).
Return(client.NetworkConnectResult{}, fmt.Errorf("network not found"))
Return(client.NetworkConnectResult{}, errors.New("network not found"))
// Cleanup removal also fails → Warnf; original error is still returned.
apiClient.EXPECT().
ContainerRemove(gomock.Any(), "hook-1", client.ContainerRemoveOptions{Force: true, RemoveVolumes: true}).
Return(client.ContainerRemoveResult{}, fmt.Errorf("removal also failed"))
Return(client.ContainerRemoveResult{}, errors.New("removal also failed"))
err := tested.runPreStart(t.Context(), project, service, ctr, nil)
assert.ErrorContains(t, err, "network not found")
@@ -1139,7 +1139,7 @@ func TestPreStart_RuntimeAPIVersionError(t *testing.T) {
// createPreStartContainer calls RuntimeAPIVersion → Ping fails.
apiClient.EXPECT().
Ping(gomock.Any(), client.PingOptions{NegotiateAPIVersion: true}).
Return(client.PingResult{}, fmt.Errorf("daemon unreachable"))
Return(client.PingResult{}, errors.New("daemon unreachable"))
err = s.runPreStart(t.Context(), project, service, ctr, nil)
assert.ErrorContains(t, err, "daemon unreachable")
+2 -1
View File
@@ -26,6 +26,7 @@ import (
"io"
"os"
"slices"
"strconv"
"strings"
"github.com/DefangLabs/secret-detector/pkg/detectors/keyword"
@@ -610,7 +611,7 @@ func buildEnvPromptMessage(services map[string]*serviceEnvFindings) string {
if keys := f.sortedSuspiciousKeys(); len(keys) > 0 {
quoted := make([]string, len(keys))
for i, k := range keys {
quoted[i] = fmt.Sprintf("%q", k)
quoted[i] = strconv.Quote(k)
}
fmt.Fprintf(&b, " service %q: literal value for %s\n", name, strings.Join(quoted, ", "))
}
+9 -9
View File
@@ -229,7 +229,7 @@ func (r *reconciler) reconcileNetworks() error {
func (r *reconciler) planCreateNetwork(key string, networkConfig *types.NetworkConfig, cause string) {
r.networkNodes[key] = r.plan.addNode(Operation{
Type: OpCreateNetwork,
ResourceID: fmt.Sprintf("network:%s", key),
ResourceID: "network:" + key,
Cause: cause,
Name: networkConfig.Name,
Network: networkConfig,
@@ -299,7 +299,7 @@ func (r *reconciler) planRecreateNetworks(keys []string) {
removeNode := r.plan.addNode(Operation{
Type: OpRemoveNetwork,
ResourceID: fmt.Sprintf("network:%s", key),
ResourceID: "network:" + key,
Cause: removeCause,
Name: observed.Name,
BestEffort: rename,
@@ -311,7 +311,7 @@ func (r *reconciler) planRecreateNetworks(keys []string) {
}
createNode := r.plan.addNode(Operation{
Type: OpCreateNetwork,
ResourceID: fmt.Sprintf("network:%s", key),
ResourceID: "network:" + key,
Cause: createCause,
Name: desired.Name,
Network: &desired,
@@ -403,7 +403,7 @@ func (r *reconciler) reconcileVolumes() error {
func (r *reconciler) planCreateVolume(key string, vol *types.VolumeConfig, cause string) {
r.volumeNodes[key] = r.plan.addNode(Operation{
Type: OpCreateVolume,
ResourceID: fmt.Sprintf("volume:%s", key),
ResourceID: "volume:" + key,
Cause: cause,
Name: vol.Name,
Volume: vol,
@@ -477,13 +477,13 @@ func (r *reconciler) planRecreateVolumes(keys []string) {
desired := r.project.Volumes[key]
removeVolNode := r.plan.addNode(Operation{
Type: OpRemoveVolume,
ResourceID: fmt.Sprintf("volume:%s", key),
ResourceID: "volume:" + key,
Cause: "config hash diverged",
Name: r.resolvedVolumes[key].Name,
}, "", removeNodes...)
createVolNode := r.plan.addNode(Operation{
Type: OpCreateVolume,
ResourceID: fmt.Sprintf("volume:%s", key),
ResourceID: "volume:" + key,
Cause: "recreate after config change",
Name: desired.Name,
Volume: &desired,
@@ -649,7 +649,7 @@ func (r *reconciler) reconcileService(service types.ServiceConfig) error {
deps := r.infrastructureDeps(service)
node := r.plan.addNode(Operation{
Type: OpRunProvider,
ResourceID: fmt.Sprintf("provider:%s", service.Name),
ResourceID: "provider:" + service.Name,
Cause: "provider service",
Service: &serviceCopy,
}, "", deps...)
@@ -1051,14 +1051,14 @@ func (r *reconciler) reconcileOrphans() {
for i, oc := range r.observed.Orphans {
stopNode := r.plan.addNode(Operation{
Type: OpStopContainer,
ResourceID: fmt.Sprintf("orphan:%s", oc.Name),
ResourceID: "orphan:" + oc.Name,
Cause: "orphaned container",
Container: &r.observed.Orphans[i].Summary,
Timeout: r.options.Timeout,
}, "")
r.plan.addNode(Operation{
Type: OpRemoveContainer,
ResourceID: fmt.Sprintf("orphan:%s", oc.Name),
ResourceID: "orphan:" + oc.Name,
Cause: "orphaned container",
Container: &r.observed.Orphans[i].Summary,
}, "", stopNode)
+2 -1
View File
@@ -17,6 +17,7 @@
package compose
import (
"errors"
"fmt"
"strconv"
"strings"
@@ -511,7 +512,7 @@ func TestReconcileVolumes_DivergedPromptMessage(t *testing.T) {
func TestReconcileVolumes_DivergedPromptError(t *testing.T) {
project, observed := divergedVolumeProject(t, 1, 1)
boom := func(_ string, _ bool) (bool, error) { return false, fmt.Errorf("boom") }
boom := func(_ string, _ bool) (bool, error) { return false, errors.New("boom") }
_, err := reconcile(t.Context(), project, observed, defaultReconcileOptions(), boom)
assert.ErrorContains(t, err, "boom")
}
+1 -1
View File
@@ -80,7 +80,7 @@ func (s *composeService) Remove(ctx context.Context, projectName string, options
return api.ErrNoResources
}
msg := fmt.Sprintf("Going to remove %s", strings.Join(names, ", "))
msg := "Going to remove " + strings.Join(names, ", ")
if options.Force {
_, _ = fmt.Fprintln(s.stdout(), msg)
} else {
+3 -3
View File
@@ -189,7 +189,7 @@ func (s *composeService) waitDependencies(ctx context.Context, project *types.Pr
}
err := eg.Wait()
if errors.Is(err, context.DeadlineExceeded) {
return fmt.Errorf("timeout waiting for dependencies")
return errors.New("timeout waiting for dependencies")
}
return err
}
@@ -299,12 +299,12 @@ func (s *composeService) checkDependencyCompleted(ctx context.Context, dep strin
if !config.Required {
// optional -> mark as skipped & don't propagate error
s.events.On(containerReasonEvents(waitingFor, skippedEvent,
fmt.Sprintf("optional dependency %s", messageSuffix))...)
"optional dependency "+messageSuffix)...)
logrus.Warnf("optional dependency %s", messageSuffix)
return true, nil
}
msg := fmt.Sprintf("service %s", messageSuffix)
msg := "service " + messageSuffix
s.events.On(containerEvents(waitingFor, func(s string) api.Resource {
return errorEventf(s, "service %s", messageSuffix)
})...)
+2 -1
View File
@@ -18,6 +18,7 @@ package compose
import (
"context"
"errors"
"fmt"
"net/netip"
"strings"
@@ -695,7 +696,7 @@ func TestCreateMobyContainerLegacyAPI_NetworkConnectFailure(t *testing.T) {
Return(client.ContainerCreateResult{ID: "an-id"}, nil)
// NetworkConnect fails
connectErr := fmt.Errorf("network connect failed")
connectErr := errors.New("network connect failed")
apiClient.EXPECT().NetworkConnect(gomock.Any(), gomock.Eq("a-moby-name"), gomock.Any()).
Return(client.NetworkConnectResult{}, connectErr)
+3 -3
View File
@@ -77,7 +77,7 @@ func NewWatcher(project *types.Project, options api.UpOptions, w WatchFunc, cons
}
}
// none of the services is eligible to watch
return nil, fmt.Errorf("none of the selected services is configured for watch, see https://docs.docker.com/compose/how-tos/file-watch/")
return nil, errors.New("none of the selected services is configured for watch, see https://docs.docker.com/compose/how-tos/file-watch/")
}
// ensure state changes are atomic
@@ -236,7 +236,7 @@ func (s *composeService) watch(ctx context.Context, project *types.Project, opti
}
if len(paths) == 0 {
return nil, fmt.Errorf("none of the selected services is configured for watch, consider setting a 'develop' section")
return nil, errors.New("none of the selected services is configured for watch, consider setting a 'develop' section")
}
watcher, err := watch.NewWatcher(paths)
@@ -543,7 +543,7 @@ func (t tarDockerClient) Exec(ctx context.Context, containerID string, cmd []str
return errors.New("process still running")
}
if execResult.ExitCode != 0 {
return fmt.Errorf("exit code %d", execResult.ExitCode)
return errors.New("exit code " + strconv.Itoa(execResult.ExitCode))
}
return nil
}
+2 -1
View File
@@ -20,6 +20,7 @@ import (
"bytes"
"context"
"crypto/rand"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
@@ -300,7 +301,7 @@ func (d *DryRunClient) VolumeRemove(ctx context.Context, volumeID string, option
func (d *DryRunClient) ExecCreate(ctx context.Context, container string, config client.ExecCreateOptions) (client.ExecCreateResult, error) {
b := make([]byte, 32)
_, _ = rand.Read(b)
id := fmt.Sprintf("%x", b)
id := hex.EncodeToString(b)
d.execs.Store(id, execDetails{
container: container,
command: config.Cmd,
+2 -3
View File
@@ -19,7 +19,6 @@
package e2e
import (
"fmt"
"os"
"path/filepath"
"testing"
@@ -49,7 +48,7 @@ func TestBridgeConvertOutputNotEmptyDeclined(t *testing.T) {
s.Step("convert without confirmation leaves the non-empty output directory untouched",
ComposeCmd("bridge", "convert", "--output", outDir,
"--transformation", fmt.Sprintf("docker/compose-bridge-kubernetes:%s", bridgeImageVersion)).MayFail(),
"--transformation", "docker/compose-bridge-kubernetes:"+bridgeImageVersion).MayFail(),
ExitCode(1),
FileContains(guardFile, "do not delete me"))
}
@@ -60,7 +59,7 @@ func TestBridgeConvertOutputNotEmptyConfirmed(t *testing.T) {
s.Step("convert --yes wipes the stale content and regenerates the output",
ComposeCmd("bridge", "convert", "--output", outDir, "--yes",
"--transformation", fmt.Sprintf("docker/compose-bridge-kubernetes:%s", bridgeImageVersion)),
"--transformation", "docker/compose-bridge-kubernetes:"+bridgeImageVersion),
FileAbsent(guardFile),
FileExists(filepath.Join(outDir, "base", "0-"+s.Project()+"-namespace.yaml")))
}
+3 -4
View File
@@ -19,7 +19,6 @@
package e2e
import (
"fmt"
"os"
"path/filepath"
"strings"
@@ -39,7 +38,7 @@ func TestConvertAndTransformList(t *testing.T) {
t.Run("kubernetes manifests", func(t *testing.T) {
kubedir := filepath.Join(tmpDir, "kubernetes")
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/bridge/compose.yaml", "--project-name", projectName, "bridge", "convert",
"--output", kubedir, "--transformation", fmt.Sprintf("docker/compose-bridge-kubernetes:%s", bridgeImageVersion))
"--output", kubedir, "--transformation", "docker/compose-bridge-kubernetes:"+bridgeImageVersion)
assert.NilError(t, res.Error)
assert.Equal(t, res.ExitCode, 0)
res = c.RunCmd(t, "diff", "-r", kubedir, "./fixtures/bridge/expected-kubernetes")
@@ -49,7 +48,7 @@ func TestConvertAndTransformList(t *testing.T) {
t.Run("helm charts", func(t *testing.T) {
helmDir := filepath.Join(tmpDir, "helm")
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/bridge/compose.yaml", "--project-name", projectName, "bridge", "convert",
"--output", helmDir, "--transformation", fmt.Sprintf("docker/compose-bridge-helm:%s", bridgeImageVersion))
"--output", helmDir, "--transformation", "docker/compose-bridge-helm:"+bridgeImageVersion)
assert.NilError(t, res.Error)
assert.Equal(t, res.ExitCode, 0)
res = c.RunCmd(t, "diff", "-r", helmDir, "./fixtures/bridge/expected-helm")
@@ -69,7 +68,7 @@ func TestConvertBuildOnlyService(t *testing.T) {
outDir := t.TempDir()
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/bridge-build-only/compose.yaml", "--project-name", "bridge-build-only", "bridge", "convert",
"--output", outDir, "--transformation", fmt.Sprintf("docker/compose-bridge-kubernetes:%s", bridgeImageVersion))
"--output", outDir, "--transformation", "docker/compose-bridge-kubernetes:"+bridgeImageVersion)
assert.NilError(t, res.Error)
assert.Equal(t, res.ExitCode, 0)
+18 -16
View File
@@ -23,11 +23,13 @@ package e2e
// test-specific logic), and are named after the observable they assert.
import (
"errors"
"fmt"
"os"
"regexp"
"runtime"
"slices"
"strconv"
"strings"
"time"
@@ -67,7 +69,7 @@ func OutputContains(sub string) Check {
name: fmt.Sprintf("output contains %q", sub),
fn: func(ctx *CheckContext) error {
if !strings.Contains(ctx.result.Combined(), sub) {
return fmt.Errorf("not found in output")
return errors.New("not found in output")
}
return nil
},
@@ -82,7 +84,7 @@ func StdoutContains(sub string) Check {
name: fmt.Sprintf("stdout contains %q", sub),
fn: func(ctx *CheckContext) error {
if !strings.Contains(ctx.result.Stdout(), sub) {
return fmt.Errorf("not found in stdout")
return errors.New("not found in stdout")
}
return nil
},
@@ -97,7 +99,7 @@ func OutputMatches(pattern string) Check {
name: fmt.Sprintf("output matches %q", pattern),
fn: func(ctx *CheckContext) error {
if !re.MatchString(ctx.result.Stdout()) {
return fmt.Errorf("no match in stdout")
return errors.New("no match in stdout")
}
return nil
},
@@ -127,7 +129,7 @@ func StderrContains(sub string) Check {
name: fmt.Sprintf("stderr contains %q", sub),
fn: func(ctx *CheckContext) error {
if !strings.Contains(ctx.result.Stderr(), sub) {
return fmt.Errorf("not found in stderr")
return errors.New("not found in stderr")
}
return nil
},
@@ -140,7 +142,7 @@ func OutputNotContains(sub string) Check {
name: fmt.Sprintf("output does not contain %q", sub),
fn: func(ctx *CheckContext) error {
if strings.Contains(ctx.result.Combined(), sub) {
return fmt.Errorf("found in output")
return errors.New("found in output")
}
return nil
},
@@ -220,7 +222,7 @@ func ServiceState(service, state string) Check {
fn: func(ctx *CheckContext) error {
containers := ctx.curr.service(service)
if len(containers) == 0 {
return fmt.Errorf("service has no container")
return errors.New("service has no container")
}
for _, c := range containers {
if c.State != state {
@@ -264,7 +266,7 @@ func ReplicaNumbers(service string, numbers ...int) Check {
slices.Sort(actual)
var expected []string
for _, n := range numbers {
expected = append(expected, fmt.Sprint(n))
expected = append(expected, strconv.Itoa(n))
}
slices.Sort(expected)
if !slices.Equal(actual, expected) {
@@ -353,7 +355,7 @@ func ServiceHealthy(service string) Check {
fn: func(ctx *CheckContext) error {
containers := ctx.curr.service(service)
if len(containers) == 0 {
return fmt.Errorf("service has no container")
return errors.New("service has no container")
}
for _, c := range containers {
res := icmd.RunCmd(ctx.scenario.cli.NewDockerCmd(ctx.scenario.t,
@@ -378,7 +380,7 @@ func OneOffState(service, state string) Check {
fn: func(ctx *CheckContext) error {
containers := ctx.curr.oneOffs(service)
if len(containers) == 0 {
return fmt.Errorf("service has no one-off container")
return errors.New("service has no one-off container")
}
for _, c := range containers {
if c.State != state {
@@ -399,7 +401,7 @@ func OneOffsUntouched(service string) Check {
fn: func(ctx *CheckContext) error {
before, after := ctx.prev.oneOffs(service), ctx.curr.oneOffs(service)
if len(before) == 0 {
return fmt.Errorf("service had no one-off container before the step")
return errors.New("service had no one-off container before the step")
}
if !slices.Equal(containerIDs(before), containerIDs(after)) {
return fmt.Errorf("one-off containers changed: %v -> %v", containerIDs(before), containerIDs(after))
@@ -424,7 +426,7 @@ func OneOffsRemoved(service string) Check {
name: fmt.Sprintf("one-offs of service %q removed", service),
fn: func(ctx *CheckContext) error {
if len(ctx.prev.oneOffs(service)) == 0 {
return fmt.Errorf("service had no one-off container before the step")
return errors.New("service had no one-off container before the step")
}
var names []string
for _, c := range ctx.curr.oneOffs(service) {
@@ -464,7 +466,7 @@ func FileExists(path string) Check {
return err
}
if info.Size() == 0 {
return fmt.Errorf("file is empty")
return errors.New("file is empty")
}
return nil
},
@@ -496,7 +498,7 @@ func FileAbsent(path string) Check {
name: fmt.Sprintf("file %q is absent", path),
fn: func(ctx *CheckContext) error {
if _, err := os.Stat(path); err == nil {
return fmt.Errorf("file still exists")
return errors.New("file still exists")
} else if !os.IsNotExist(err) {
return err
}
@@ -512,7 +514,7 @@ func LabelSet(service, key string) Check {
fn: func(ctx *CheckContext) error {
containers := ctx.curr.service(service)
if len(containers) == 0 {
return fmt.Errorf("service has no container")
return errors.New("service has no container")
}
for _, c := range containers {
if c.Labels[key] == "" {
@@ -555,7 +557,7 @@ func LabelUnchanged(service, key string) Check {
fn: func(ctx *CheckContext) error {
before, after := ctx.prev.service(service), ctx.curr.service(service)
if len(before) == 0 || len(after) == 0 {
return fmt.Errorf("service has no container to compare")
return errors.New("service has no container to compare")
}
if before[0].Labels[key] != after[0].Labels[key] {
return fmt.Errorf("label changed: %q -> %q", before[0].Labels[key], after[0].Labels[key])
@@ -573,7 +575,7 @@ func RunsOnPlatform(service, platform string) Check {
fn: func(ctx *CheckContext) error {
containers := ctx.curr.service(service)
if len(containers) == 0 {
return fmt.Errorf("service has no container")
return errors.New("service has no container")
}
res := icmd.RunCmd(ctx.scenario.cli.NewDockerCmd(ctx.scenario.t, "inspect", "--format",
"{{.ImageManifestDescriptor.Platform.OS}}/{{.ImageManifestDescriptor.Platform.Architecture}}",
+1 -1
View File
@@ -282,7 +282,7 @@ func (c *CLI) BaseEnvironment() []string {
_, filename, _, _ := runtime.Caller(0)
root := filepath.Join(filepath.Dir(filename), "..", "..")
coverdir = filepath.Join(root, coverdir)
env = append(env, fmt.Sprintf("GOCOVERDIR=%s", coverdir))
env = append(env, "GOCOVERDIR="+coverdir)
}
return env
}
+2 -1
View File
@@ -21,6 +21,7 @@ package e2e
import (
"bytes"
"crypto/rand"
"encoding/hex"
"fmt"
"os"
"path/filepath"
@@ -203,7 +204,7 @@ func doTest(t *testing.T, svcName string) {
waitForFlush := func() {
b := make([]byte, 32)
_, _ = rand.Read(b)
sentinelVal := fmt.Sprintf("%x", b)
sentinelVal := hex.EncodeToString(b)
writeDataFile("wait.txt", sentinelVal)
poll.WaitOn(t, checkFileContents("/app/data/wait.txt", sentinelVal))
}
+3 -2
View File
@@ -19,6 +19,7 @@ package remote
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"os"
@@ -49,7 +50,7 @@ const (
func validatePathInBase(base, unsafePath string) error {
// Reject paths with path separators regardless of OS
if strings.ContainsAny(unsafePath, "\\/") {
return fmt.Errorf("invalid OCI artifact")
return errors.New("invalid OCI artifact")
}
// Join the base with the untrusted path
@@ -64,7 +65,7 @@ func validatePathInBase(base, unsafePath string) error {
// Check if the target directory is the same as base directory
if cleanTargetDir != cleanBase {
return fmt.Errorf("invalid OCI artifact")
return errors.New("invalid OCI artifact")
}
return nil
+1 -1
View File
@@ -120,7 +120,7 @@ func absPatterns(absRoot string, patterns []string) []string {
}
absPattern := pPath
if isExclusion {
absPattern = fmt.Sprintf("!%s", pPath)
absPattern = "!" + pPath
}
absPatterns = append(absPatterns, absPattern)
}
+1 -2
View File
@@ -18,7 +18,6 @@ package watch
import (
"expvar"
"fmt"
"os"
"path/filepath"
"strconv"
@@ -30,7 +29,7 @@ type FileEvent string
func NewFileEvent(p string) FileEvent {
if !filepath.IsAbs(p) {
panic(fmt.Sprintf("NewFileEvent only accepts absolute paths. Actual: %s", p))
panic("NewFileEvent only accepts absolute paths. Actual: " + p)
}
return FileEvent(p)
}
+2 -1
View File
@@ -17,6 +17,7 @@
package watch
import (
"errors"
"fmt"
"os"
"path/filepath"
@@ -25,7 +26,7 @@ import (
func greatestExistingAncestor(path string) (string, error) {
if path == string(filepath.Separator) ||
path == fmt.Sprintf("%s%s", filepath.VolumeName(path), string(filepath.Separator)) {
return "", fmt.Errorf("cannot watch root directory")
return "", errors.New("cannot watch root directory")
}
_, err := os.Stat(path)
+2 -1
View File
@@ -19,6 +19,7 @@
package watch
import (
"errors"
"fmt"
"io/fs"
"os"
@@ -301,7 +302,7 @@ func newWatcher(paths []string) (Notify, error) {
fsw, err := fsnotify.NewWatcher()
if err != nil {
if strings.Contains(err.Error(), "too many open files") && runtime.GOOS == "linux" {
return nil, fmt.Errorf("hit OS limits creating a watcher.\n" +
return nil, errors.New("hit OS limits creating a watcher.\n" +
"Run 'sysctl fs.inotify.max_user_instances' to check your inotify limits.\n" +
"To raise them, run 'sudo sysctl fs.inotify.max_user_instances=1024'")
}
+6 -6
View File
@@ -57,7 +57,7 @@ func TestDontWatchEachFile(t *testing.T) {
}
for i := range 100 {
f.WriteFile(f.JoinPath(initialDir, fmt.Sprintf("%d", i)), "initial data")
f.WriteFile(f.JoinPath(initialDir, strconv.Itoa(i)), "initial data")
}
f.watch(watched)
@@ -80,7 +80,7 @@ func TestDontWatchEachFile(t *testing.T) {
}
for i := range 100 {
f.WriteFile(f.JoinPath(inplaceDir, fmt.Sprintf("%d", i)), "inplace data")
f.WriteFile(f.JoinPath(inplaceDir, strconv.Itoa(i)), "inplace data")
}
f.fsync()
@@ -99,7 +99,7 @@ func TestDontWatchEachFile(t *testing.T) {
}
for i := range 100 {
f.WriteFile(f.JoinPath(stagedDir, fmt.Sprintf("%d", i)), "staged data")
f.WriteFile(f.JoinPath(stagedDir, strconv.Itoa(i)), "staged data")
}
if err := os.Rename(staged, f.JoinPath(watched, "staged")); err != nil {
@@ -115,7 +115,7 @@ func TestDontWatchEachFile(t *testing.T) {
n, err := inotifyNodes()
assert.NilError(t, err)
if n > 10 {
t.Fatalf("watching more than 10 files: %d", n)
t.Fatal("watching more than 10 files:", n)
}
}
@@ -147,14 +147,14 @@ func TestDontRecurseWhenWatchingParentsOfNonExistentFiles(t *testing.T) {
excludedDir := f.JoinPath(watched, "excluded")
for i := range 10 {
f.WriteFile(f.JoinPath(excludedDir, fmt.Sprintf("%d", i), "data.txt"), "initial data")
f.WriteFile(f.JoinPath(excludedDir, strconv.Itoa(i), "data.txt"), "initial data")
}
f.fsync()
n, err := inotifyNodes()
assert.NilError(t, err)
if n > 5 {
t.Fatalf("watching more than 5 files: %d", n)
t.Fatal("watching more than 5 files:", n)
}
}