diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000000..13566b81b01 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/compose.iml b/.idea/compose.iml new file mode 100644 index 00000000000..5e764c4f0b9 --- /dev/null +++ b/.idea/compose.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/golinter.xml b/.idea/golinter.xml new file mode 100644 index 00000000000..1ccf3ec6d93 --- /dev/null +++ b/.idea/golinter.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000000..2efec7ef046 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000000..35eb1ddfbbc --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/cmd/compose/ps.go b/cmd/compose/ps.go index 2528fccacfb..e79a8bcef89 100644 --- a/cmd/compose/ps.go +++ b/cmd/compose/ps.go @@ -81,7 +81,7 @@ func psCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *Backend ValidArgsFunction: completeServiceNames(dockerCli, p), } flags := psCmd.Flags() - flags.StringVar(&opts.Format, "format", "table", cliflags.FormatHelp) + flags.StringVar(&opts.Format, "format", "", cliflags.FormatHelp) flags.StringVar(&opts.Filter, "filter", "", "Filter services by a property (supported filters: status)") flags.StringArrayVar(&opts.Status, "status", []string{}, "Filter services by status. Values: [paused | restarting | removing | running | dead | created | exited]") flags.BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs") @@ -152,9 +152,14 @@ func runPs(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOp return nil } - if opts.Format == "" { + if len(opts.Format) == 0 { opts.Format = dockerCli.ConfigFile().PsFormat } + if len(opts.Format) == 0 { + opts.Format = "table" + } else if opts.Quiet { + _, _ = dockerCli.Err().Write([]byte("WARNING: Ignoring custom format, because both --format and --quiet are set.\n")) + } containerCtx := cliformatter.Context{ Output: dockerCli.Out(), diff --git a/cmd/compose/ps_format_test.go b/cmd/compose/ps_format_test.go new file mode 100644 index 00000000000..dd5f8b68b19 --- /dev/null +++ b/cmd/compose/ps_format_test.go @@ -0,0 +1,47 @@ +/* + 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 ( + "testing" + + "github.com/docker/cli/cli/config/configfile" + "github.com/docker/cli/cli/streams" + "go.uber.org/mock/gomock" + "gotest.tools/v3/assert" + + "github.com/docker/compose/v5/pkg/mocks" +) + +func TestPsCommandDefaultFormat(t *testing.T) { + // Test that the format flag has empty string as default + projectOpts := &ProjectOptions{} + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + cli := mocks.NewMockCli(mockCtrl) + cli.EXPECT().ConfigFile().Return(configfile.New("test")).AnyTimes() + cli.EXPECT().Out().Return(&streams.Out{}).AnyTimes() + cli.EXPECT().Err().Return(&streams.Out{}).AnyTimes() + + backendOptions := &BackendOptions{} + cmd := psCommand(projectOpts, cli, backendOptions) + + // Check default value of format flag + formatFlag := cmd.Flags().Lookup("format") + assert.Equal(t, formatFlag.DefValue, "") +} diff --git a/pkg/compose/publish.go b/pkg/compose/publish.go index fb466607559..4ec67a63263 100644 --- a/pkg/compose/publish.go +++ b/pkg/compose/publish.go @@ -251,6 +251,9 @@ func processFile(ctx context.Context, file string, project *types.Project, extFi } for name, service := range base.Services { for i, envFile := range service.EnvFiles { + if !envFile.Required { + continue + } hash := fmt.Sprintf("%x.env", sha256.Sum256([]byte(envFile.Path))) envFiles[envFile.Path] = hash f, err = transform.ReplaceEnvFile(f, name, i, hash) @@ -351,8 +354,11 @@ func (s *composeService) checkEnvironmentVariables(project *types.Project, optio errorList := map[string][]string{} for _, service := range project.Services { - if len(service.EnvFiles) > 0 { - errorList[service.Name] = append(errorList[service.Name], fmt.Sprintf("service %q has env_file declared.", service.Name)) + for _, envFile := range service.EnvFiles { + if envFile.Required { + errorList[service.Name] = append(errorList[service.Name], fmt.Sprintf("service %q has env_file declared.", service.Name)) + break + } } } @@ -438,6 +444,9 @@ func (s *composeService) checkForSensitiveData(project *types.Project) ([]secret for _, service := range project.Services { // Check env files for _, envFile := range service.EnvFiles { + if !envFile.Required { + continue + } findings, err := scan.ScanFile(envFile.Path) if err != nil { return nil, fmt.Errorf("failed to scan env file %s: %w", envFile.Path, err) diff --git a/pkg/compose/publish_test.go b/pkg/compose/publish_test.go index 8f91f663e69..b3ba8c77875 100644 --- a/pkg/compose/publish_test.go +++ b/pkg/compose/publish_test.go @@ -18,6 +18,7 @@ package compose import ( "slices" + "strings" "testing" "github.com/compose-spec/compose-go/v2/loader" @@ -100,3 +101,69 @@ services: return !slices.Contains([]string{".Data", ".Digest", ".Size"}, path.String()) }, cmp.Ignore())) } + +func Test_createLayers_withRequiredFalse(t *testing.T) { + project, err := loader.LoadWithContext(t.Context(), types.ConfigDetails{ + WorkingDir: "testdata/publish/", + Environment: types.Mapping{}, + ConfigFiles: []types.ConfigFile{ + { + Filename: "testdata/publish/compose-required-false.yaml", + }, + }, + }) + assert.NilError(t, err) + project.ComposeFiles = []string{"testdata/publish/compose-required-false.yaml"} + + service := &composeService{} + layers, err := service.createLayers(t.Context(), project, api.PublishOptions{ + WithEnvironment: true, + }) + assert.NilError(t, err) + + assert.Equal(t, len(layers), 2) + + assert.Equal(t, layers[0].Annotations["com.docker.compose.file"], "compose-required-false.yaml") + + assert.Equal(t, layers[1].MediaType, "application/vnd.docker.compose.envfile") + + envFileHash := layers[1].Annotations["com.docker.compose.envfile"] + assert.Assert(t, len(envFileHash) > 0) + assert.Assert(t, envFileHash != "missing.env") +} + +func Test_checkEnvironmentVariables_withRequiredFalse(t *testing.T) { + project := &types.Project{ + Services: types.Services{ + "test": { + Name: "test", + EnvFiles: []types.EnvFile{ + { + Path: "missing.env", + Required: false, + }, + { + Path: "existing.env", + Required: true, + }, + }, + }, + "test2": { + Name: "test2", + EnvFiles: []types.EnvFile{ + { + Path: "optional.env", + Required: false, + }, + }, + }, + }, + } + + service := &composeService{} + + err := service.checkEnvironmentVariables(project, api.PublishOptions{}) + assert.Assert(t, err != nil) + assert.Assert(t, strings.Contains(err.Error(), `service "test" has env_file declared.`)) + assert.Assert(t, !strings.Contains(err.Error(), `service "test2"`)) +} diff --git a/pkg/compose/testdata/publish/compose-required-false.yaml b/pkg/compose/testdata/publish/compose-required-false.yaml new file mode 100644 index 00000000000..64b94e38942 --- /dev/null +++ b/pkg/compose/testdata/publish/compose-required-false.yaml @@ -0,0 +1,9 @@ +name: test-required-false +services: + test: + image: test + env_file: + - path: missing.env + required: false + - path: existing.env + required: true diff --git a/pkg/compose/testdata/publish/existing.env b/pkg/compose/testdata/publish/existing.env new file mode 100644 index 00000000000..bda5e6e581f --- /dev/null +++ b/pkg/compose/testdata/publish/existing.env @@ -0,0 +1 @@ +EXISTING_VAR=value