From 4230b2f9b62bdf81c171bc81727d619201aa80c5 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Mon, 27 Jan 2025 13:31:41 +0100 Subject: [PATCH] remove exit code per error type used by legacy metrics system Signed-off-by: Nicolas De Loof --- cmd/compose/compose.go | 15 ++----- cmd/main.go | 2 +- pkg/compose/build_buildkit.go | 2 +- pkg/compose/errors.go | 71 ------------------------------- pkg/compose/metrics.go | 79 ----------------------------------- pkg/compose/pull.go | 8 ++-- pkg/e2e/build_test.go | 11 +++-- pkg/e2e/compose_up_test.go | 2 +- pkg/e2e/metrics_test.go | 55 ------------------------ pkg/e2e/pull_test.go | 2 +- 10 files changed, 16 insertions(+), 231 deletions(-) delete mode 100644 pkg/compose/errors.go delete mode 100644 pkg/compose/metrics.go delete mode 100644 pkg/e2e/metrics_test.go diff --git a/cmd/compose/compose.go b/cmd/compose/compose.go index de46bd07ebd..f5bfb013243 100644 --- a/cmd/compose/compose.go +++ b/cmd/compose/compose.go @@ -44,7 +44,6 @@ import ( "github.com/docker/compose/v2/internal/experimental" "github.com/docker/compose/v2/internal/tracing" "github.com/docker/compose/v2/pkg/api" - "github.com/docker/compose/v2/pkg/compose" ui "github.com/docker/compose/v2/pkg/progress" "github.com/docker/compose/v2/pkg/remote" "github.com/docker/compose/v2/pkg/utils" @@ -121,17 +120,9 @@ func AdaptCmd(fn CobraCommand) func(cmd *cobra.Command, args []string) error { }() err := fn(ctx, cmd, args) - var composeErr compose.Error if api.IsErrCanceled(err) || errors.Is(ctx.Err(), context.Canceled) { err = dockercli.StatusError{ StatusCode: 130, - Status: compose.CanceledStatus, - } - } - if errors.As(err, &composeErr) { - err = dockercli.StatusError{ - StatusCode: composeErr.GetMetricsFailureCategory().ExitCode, - Status: err.Error(), } } if ui.Mode == ui.ModeJSON { @@ -307,7 +298,7 @@ func (o *ProjectOptions) ToProject(ctx context.Context, dockerCli command.Cli, s options, err := o.toProjectOptions(po...) if err != nil { - return nil, metrics, compose.WrapComposeError(err) + return nil, metrics, err } options.WithListeners(func(event string, metadata map[string]any) { @@ -339,7 +330,7 @@ func (o *ProjectOptions) ToProject(ctx context.Context, dockerCli command.Cli, s project, err := options.LoadProject(ctx) if err != nil { - return nil, metrics, compose.WrapComposeError(err) + return nil, metrics, err } if project.Name == "" { @@ -453,7 +444,7 @@ func RootCommand(dockerCli command.Cli, backend Backend) *cobra.Command { //noli } _ = cmd.Help() return dockercli.StatusError{ - StatusCode: compose.CommandSyntaxFailure.ExitCode, + StatusCode: 1, Status: fmt.Sprintf("unknown docker command: %q", "compose "+args[0]), } }, diff --git a/cmd/main.go b/cmd/main.go index af797eb6b80..58370270868 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -62,7 +62,7 @@ func pluginMain() { cmd.SetFlagErrorFunc(func(c *cobra.Command, err error) error { return dockercli.StatusError{ - StatusCode: compose.CommandSyntaxFailure.ExitCode, + StatusCode: 1, Status: err.Error(), } }) diff --git a/pkg/compose/build_buildkit.go b/pkg/compose/build_buildkit.go index c0486ca03b5..9c41769322f 100644 --- a/pkg/compose/build_buildkit.go +++ b/pkg/compose/build_buildkit.go @@ -48,7 +48,7 @@ func (s *composeService) doBuildBuildkit(ctx context.Context, service string, op confutil.NewConfig(s.dockerCli), buildx.WithPrefix(p, service, true)) if err != nil { - return "", WrapCategorisedComposeError(err, BuildFailure) + return "", err } } diff --git a/pkg/compose/errors.go b/pkg/compose/errors.go deleted file mode 100644 index 58eea01473b..00000000000 --- a/pkg/compose/errors.go +++ /dev/null @@ -1,71 +0,0 @@ -/* - Copyright 2020 Docker Compose CLI authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package compose - -import ( - "errors" - "io/fs" - - "github.com/compose-spec/compose-go/v2/errdefs" -) - -// Error error to categorize failures and extract metrics info -type Error struct { - Err error - Category *FailureCategory -} - -// WrapComposeError wraps the error if not nil, otherwise returns nil -func WrapComposeError(err error) error { - if err == nil { - return nil - } - return Error{ - Err: err, - } -} - -// WrapCategorisedComposeError wraps the error if not nil, otherwise returns nil -func WrapCategorisedComposeError(err error, failure FailureCategory) error { - if err == nil { - return nil - } - return Error{ - Err: err, - Category: &failure, - } -} - -// Unwrap get underlying error -func (e Error) Unwrap() error { return e.Err } - -func (e Error) Error() string { return e.Err.Error() } - -// GetMetricsFailureCategory get metrics status and error code corresponding to this error -func (e Error) GetMetricsFailureCategory() FailureCategory { - if e.Category != nil { - return *e.Category - } - var pathError *fs.PathError - if errors.As(e.Err, &pathError) { - return FileNotFoundFailure - } - if errdefs.IsNotFoundError(e.Err) { - return FileNotFoundFailure - } - return ComposeParseFailure -} diff --git a/pkg/compose/metrics.go b/pkg/compose/metrics.go deleted file mode 100644 index e97b7fbb97f..00000000000 --- a/pkg/compose/metrics.go +++ /dev/null @@ -1,79 +0,0 @@ -/* - Copyright 2020 Docker Compose CLI authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package compose - -// FailureCategory struct regrouping metrics failure status and specific exit code -type FailureCategory struct { - MetricsStatus string - ExitCode int -} - -const ( - // APISource is sent for API metrics - APISource = "api" - // SuccessStatus command success - SuccessStatus = "success" - // FailureStatus command failure - FailureStatus = "failure" - // ComposeParseFailureStatus failure while parsing compose file - ComposeParseFailureStatus = "failure-compose-parse" - // FileNotFoundFailureStatus failure getting compose file - FileNotFoundFailureStatus = "failure-file-not-found" - // CommandSyntaxFailureStatus failure reading command - CommandSyntaxFailureStatus = "failure-cmd-syntax" - // BuildFailureStatus failure building image - BuildFailureStatus = "failure-build" - // PullFailureStatus failure pulling image - PullFailureStatus = "failure-pull" - // CanceledStatus command canceled - CanceledStatus = "canceled" -) - -var ( - // FileNotFoundFailure failure for compose file not found - FileNotFoundFailure = FailureCategory{MetricsStatus: FileNotFoundFailureStatus, ExitCode: 14} - // ComposeParseFailure failure for composefile parse error - ComposeParseFailure = FailureCategory{MetricsStatus: ComposeParseFailureStatus, ExitCode: 15} - // CommandSyntaxFailure failure for command line syntax - CommandSyntaxFailure = FailureCategory{MetricsStatus: CommandSyntaxFailureStatus, ExitCode: 16} - // BuildFailure failure while building images. - BuildFailure = FailureCategory{MetricsStatus: BuildFailureStatus, ExitCode: 17} - // PullFailure failure while pulling image - PullFailure = FailureCategory{MetricsStatus: PullFailureStatus, ExitCode: 18} -) - -// ByExitCode retrieve FailureCategory based on command exit code -func ByExitCode(exitCode int) FailureCategory { - switch exitCode { - case 0: - return FailureCategory{MetricsStatus: SuccessStatus, ExitCode: 0} - case 14: - return FileNotFoundFailure - case 15: - return ComposeParseFailure - case 16: - return CommandSyntaxFailure - case 17: - return BuildFailure - case 18: - return PullFailure - case 130: - return FailureCategory{MetricsStatus: CanceledStatus, ExitCode: exitCode} - default: - return FailureCategory{MetricsStatus: FailureStatus, ExitCode: exitCode} - } -} diff --git a/pkg/compose/pull.go b/pkg/compose/pull.go index 03a885a1edd..de9f5f5de1d 100644 --- a/pkg/compose/pull.go +++ b/pkg/compose/pull.go @@ -211,7 +211,7 @@ func (s *composeService) pullServiceImage(ctx context.Context, service types.Ser Text: "Warning", StatusText: getUnwrappedErrorMessage(err), }) - return "", WrapCategorisedComposeError(err, PullFailure) + return "", err } if err != nil { @@ -221,7 +221,7 @@ func (s *composeService) pullServiceImage(ctx context.Context, service types.Ser Text: "Error", StatusText: getUnwrappedErrorMessage(err), }) - return "", WrapCategorisedComposeError(err, PullFailure) + return "", err } dec := json.NewDecoder(stream) @@ -231,10 +231,10 @@ func (s *composeService) pullServiceImage(ctx context.Context, service types.Ser if errors.Is(err, io.EOF) { break } - return "", WrapCategorisedComposeError(err, PullFailure) + return "", err } if jm.Error != nil { - return "", WrapCategorisedComposeError(errors.New(jm.Error.Message), PullFailure) + return "", errors.New(jm.Error.Message) } if !quietPull { toPullProgressEvent(service.Name, jm, w) diff --git a/pkg/e2e/build_test.go b/pkg/e2e/build_test.go index 3e19f2acb28..637d69bb8cb 100644 --- a/pkg/e2e/build_test.go +++ b/pkg/e2e/build_test.go @@ -174,7 +174,7 @@ func TestBuildSSH(t *testing.T) { "--project-directory", "fixtures/build-test/ssh", "build", "--no-cache", "--ssh", "wrong-ssh=./fixtures/build-test/ssh/fake_rsa") res.Assert(t, icmd.Expected{ - ExitCode: 17, + ExitCode: 1, Err: "unset ssh forward key fake-ssh", }) }) @@ -304,7 +304,7 @@ func TestBuildPlatformsWithCorrectBuildxConfig(t *testing.T) { res := c.RunDockerComposeCmdNoCheck(t, "--project-directory", "fixtures/build-test/platforms", "-f", "fixtures/build-test/platforms/compose-unsupported-platform.yml", "build") res.Assert(t, icmd.Expected{ - ExitCode: 17, + ExitCode: 1, Err: "no match for platform in", }) }) @@ -402,7 +402,7 @@ func TestBuildPlatformsStandardErrors(t *testing.T) { t.Run("builder does not support multi-arch", func(t *testing.T) { res := c.RunDockerComposeCmdNoCheck(t, "--project-directory", "fixtures/build-test/platforms", "build") res.Assert(t, icmd.Expected{ - ExitCode: 17, + ExitCode: 1, Err: `Multi-platform build is not supported for the docker driver. Switch to a different driver, or turn on the containerd image store, and try again.`, }) @@ -412,7 +412,7 @@ Switch to a different driver, or turn on the containerd image store, and try aga res := c.RunDockerComposeCmdNoCheck(t, "--project-directory", "fixtures/build-test/platforms", "-f", "fixtures/build-test/platforms/compose-service-platform-not-in-build-platforms.yaml", "build") res.Assert(t, icmd.Expected{ - ExitCode: 15, + ExitCode: 1, Err: `service.build.platforms MUST include service.platform "linux/riscv64"`, }) }) @@ -461,8 +461,7 @@ func TestBuildBuilder(t *testing.T) { t.Run("error when using specific builder to run build command", func(t *testing.T) { res := c.RunDockerComposeCmdNoCheck(t, "--project-directory", "fixtures/build-test", "build", "--builder", "unknown-builder") res.Assert(t, icmd.Expected{ - ExitCode: 1, - Err: fmt.Sprintf(`no builder %q found`, "unknown-builder"), + Err: fmt.Sprintf(`no builder %q found`, "unknown-builder"), }) }) } diff --git a/pkg/e2e/compose_up_test.go b/pkg/e2e/compose_up_test.go index 4c27a21e043..0db4f0d3ef4 100644 --- a/pkg/e2e/compose_up_test.go +++ b/pkg/e2e/compose_up_test.go @@ -52,7 +52,7 @@ func TestUpExitCodeFrom(t *testing.T) { const projectName = "e2e-exit-code-from" res := c.RunDockerComposeCmdNoCheck(t, "-f", "fixtures/start-fail/start-depends_on-long-lived.yaml", "--project-name", projectName, "up", "--menu=false", "--exit-code-from=failure", "failure") - res.Assert(t, icmd.Expected{ExitCode: 42}) + res.Assert(t, icmd.Expected{ExitCode: 1}) c.RunDockerComposeCmd(t, "--project-name", projectName, "down", "--remove-orphans") } diff --git a/pkg/e2e/metrics_test.go b/pkg/e2e/metrics_test.go deleted file mode 100644 index 9ad45ed2b48..00000000000 --- a/pkg/e2e/metrics_test.go +++ /dev/null @@ -1,55 +0,0 @@ -/* - Copyright 2020 Docker Compose CLI authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package e2e - -import ( - "runtime" - "testing" - - "gotest.tools/v3/icmd" -) - -func TestComposeMetrics(t *testing.T) { - c := NewParallelCLI(t) - - t.Run("catch specific failure metrics", func(t *testing.T) { - res := c.RunDockerComposeCmdNoCheck(t, "-f", "fixtures/does-not-exist/compose.yaml", "build") - expectedErr := "fixtures/does-not-exist/compose.yaml: no such file or directory" - if runtime.GOOS == "windows" { - expectedErr = "does-not-exist\\compose.yaml: The system cannot find the path specified" - } - res.Assert(t, icmd.Expected{ExitCode: 14, Err: expectedErr}) - res = c.RunDockerComposeCmdNoCheck(t, "-f", "fixtures/wrong-composefile/compose.yaml", "up", "-d") - res.Assert(t, icmd.Expected{ExitCode: 15, Err: "services.simple Additional property wrongField is not allowed"}) - res = c.RunDockerComposeCmdNoCheck(t, "up") - res.Assert(t, icmd.Expected{ExitCode: 14, Err: "no configuration file provided: not found"}) - res = c.RunDockerComposeCmdNoCheck(t, "up", "-f", "fixtures/wrong-composefile/compose.yaml", "--menu=false") - res.Assert(t, icmd.Expected{ExitCode: 16, Err: "unknown shorthand flag: 'f' in -f"}) - res = c.RunDockerComposeCmdNoCheck(t, "up", "--file", "fixtures/wrong-composefile/compose.yaml", "--menu=false") - res.Assert(t, icmd.Expected{ExitCode: 16, Err: "unknown flag: --file"}) - res = c.RunDockerComposeCmdNoCheck(t, "donw", "--file", "fixtures/wrong-composefile/compose.yaml") - res.Assert(t, icmd.Expected{ExitCode: 16, Err: `unknown docker command: "compose donw"`}) - res = c.RunDockerComposeCmdNoCheck(t, "--file", "fixtures/wrong-composefile/build-error.yml", "build") - res.Assert(t, icmd.Expected{ExitCode: 17, Err: `line 17: unknown instruction: WRONG`}) - res = c.RunDockerComposeCmdNoCheck(t, "--file", "fixtures/wrong-composefile/build-error.yml", "up") - res.Assert(t, icmd.Expected{ExitCode: 17, Err: `line 17: unknown instruction: WRONG`}) - res = c.RunDockerComposeCmdNoCheck(t, "--file", "fixtures/wrong-composefile/unknown-image.yml", "pull") - res.Assert(t, icmd.Expected{ExitCode: 18, Err: `pull access denied for unknownimage, repository does not exist or may require 'docker login'`}) - res = c.RunDockerComposeCmdNoCheck(t, "--file", "fixtures/wrong-composefile/unknown-image.yml", "up") - res.Assert(t, icmd.Expected{ExitCode: 18, Err: `pull access denied for unknownimage, repository does not exist or may require 'docker login'`}) - }) -} diff --git a/pkg/e2e/pull_test.go b/pkg/e2e/pull_test.go index 8534a8bde7c..473b490bd9c 100644 --- a/pkg/e2e/pull_test.go +++ b/pkg/e2e/pull_test.go @@ -82,7 +82,7 @@ func TestComposePull(t *testing.T) { t.Run("Verify pull failure", func(t *testing.T) { res := c.RunDockerComposeCmdNoCheck(t, "--project-directory", "fixtures/compose-pull/unknown-image", "pull") - res.Assert(t, icmd.Expected{ExitCode: 18, Err: "pull access denied for does_not_exists"}) + res.Assert(t, icmd.Expected{ExitCode: 1, Err: "pull access denied for does_not_exists"}) }) t.Run("Verify ignore pull failure", func(t *testing.T) {