Repository: compose-spec/compose-go
Pull request #71 (2020-08-31 07:09:01)

Bump github.com/google/go-cmp from 0.5.1 to 0.5.2
Bumps [github.com/google/go-cmp](https://github.com/google/go-cmp) from 0.5.1 to 0.5.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/google/go-cmp/releases">github.com/google/go-cmp's releases</a>.</em></p>
<blockquote>
<h2>v0.5.2</h2>
<p>Minor documentation changes:</p>
<p>(<a href="https://github-redirect.dependabot.com/google/go-cmp/issues/234">#234</a>) Suggest use of cmpopts.EquateErrors
(<a href="https://github-redirect.dependabot.com/google/go-cmp/issues/231">#231</a>) Fix Diff documentation</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/google/go-cmp/commit/d2fcc899bdc2d134b7c00e36137260db963e193c"><code>d2fcc89</code></a> Suggest use of cmpopts.EquateErrors (<a href="https://github-redirect.dependabot.com/google/go-cmp/issues/234">#234</a>)</li>
<li><a href="https://github.com/google/go-cmp/commit/db9de4321f4e5db7c6f996d170ebce7953f22f8e"><code>db9de43</code></a> Add testing for Go1.15 (<a href="https://github-redirect.dependabot.com/google/go-cmp/issues/232">#232</a>)</li>
<li><a href="https://github.com/google/go-cmp/commit/036ffc7f24c0d0eda6ce580168fdaec194a1561f"><code>036ffc7</code></a> Fix Diff documentation (<a href="https://github-redirect.dependabot.com/google/go-cmp/issues/231">#231</a>)</li>
<li>See full diff in <a href="https://github.com/google/go-cmp/compare/v0.5.1...v0.5.2">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=github.com/google/go-cmp&package-manager=go_modules&previous-version=0.5.1&new-version=0.5.2)](https://dependabot.com/compatibility-score/?dependency-name=github.com/google/go-cmp&package-manager=go_modules&previous-version=0.5.1&new-version=0.5.2)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
- `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme

Additionally, you can set the following in the `.dependabot/config.yml` file in this repo:
- Update frequency
- Out-of-range updates (receive only lockfile updates, if desired)
- Security updates (receive only security updates, if desired)



</details>


Patch:
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ad5395b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+### IDEs ###
+.idea/*
diff --git a/cli/options.go b/cli/options.go
index 5380268..3817109 100644
--- a/cli/options.go
+++ b/cli/options.go
@@ -38,6 +38,7 @@ type ProjectOptions struct {
 	WorkingDir  string
 	ConfigPaths []string
 	Environment map[string]string
+	loadOptions []func(*loader.Options)
 }
 
 type ProjectOptionsFn func(*ProjectOptions) error
@@ -83,6 +84,13 @@ func WithEnv(env []string) ProjectOptionsFn {
 	}
 }
 
+// WithDiscardEnvFiles sets discards the `env_file` section after resolving to
+// the `environment` section
+func WithDiscardEnvFile(o *ProjectOptions) error {
+	o.loadOptions = append(o.loadOptions, loader.WithDiscardEnvFiles)
+	return nil
+}
+
 // WithOsEnv imports environment variables from OS
 func WithOsEnv(o *ProjectOptions) error {
 	for k, v := range getAsEqualsMap(os.Environ()) {
@@ -163,11 +171,7 @@ func ProjectFromOptions(options *ProjectOptions) (*types.Project, error) {
 		return nil, err
 	}
 
-	return loader.Load(types.ConfigDetails{
-		ConfigFiles: configs,
-		WorkingDir:  workingDir,
-		Environment: options.Environment,
-	}, func(opts *loader.Options) {
+	var nameLoadOpt = func(opts *loader.Options) {
 		if options.Name != "" {
 			opts.Name = options.Name
 		} else if nameFromEnv, ok := os.LookupEnv(ComposeProjectName); ok {
@@ -176,7 +180,14 @@ func ProjectFromOptions(options *ProjectOptions) (*types.Project, error) {
 			opts.Name = regexp.MustCompile(`[^a-z0-9\\-_]+`).
 				ReplaceAllString(strings.ToLower(filepath.Base(absWorkingDir)), "")
 		}
-	})
+	}
+	options.loadOptions = append(options.loadOptions, nameLoadOpt)
+
+	return loader.Load(types.ConfigDetails{
+		ConfigFiles: configs,
+		WorkingDir:  workingDir,
+		Environment: options.Environment,
+	}, options.loadOptions...)
 }
 
 // getConfigPathsFromOptions retrieves the config files for project based on project options
diff --git a/go.mod b/go.mod
index 0304c8b..4958a4e 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ go 1.13
 require (
 	github.com/docker/go-connections v0.4.0
 	github.com/docker/go-units v0.4.0
-	github.com/google/go-cmp v0.5.1
+	github.com/google/go-cmp v0.5.2
 	github.com/imdario/mergo v0.3.11
 	github.com/joho/godotenv v1.3.0
 	github.com/mattn/go-shellwords v1.0.10
diff --git a/go.sum b/go.sum
index b2475a3..8211e16 100644
--- a/go.sum
+++ b/go.sum
@@ -14,6 +14,8 @@ github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
 github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
 github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
 github.com/imdario/mergo v0.3.10 h1:6q5mVkdH/vYmqngx7kZQTjJ5HRsx+ImorDIEQ+beJgc=
diff --git a/loader/loader.go b/loader/loader.go
index e1cab0b..c7ef137 100644
--- a/loader/loader.go
+++ b/loader/loader.go
@@ -349,6 +349,7 @@ func createTransformHook(additionalTransformers ...Transformer) mapstructure.Dec
 		reflect.TypeOf(types.ServiceVolumeConfig{}):              transformServiceVolumeConfig,
 		reflect.TypeOf(types.BuildConfig{}):                      transformBuildConfig,
 		reflect.TypeOf(types.Duration(0)):                        transformStringToDuration,
+		reflect.TypeOf(types.DependsOnConfig{}):                  transformDependsOnConfig,
 	}
 
 	for _, transformer := range additionalTransformers {
@@ -778,6 +779,25 @@ var transformBuildConfig TransformerFunc = func(data interface{}) (interface{},
 	}
 }
 
+var transformDependsOnConfig TransformerFunc = func(data interface{}) (interface{}, error) {
+	switch value := data.(type) {
+	case []interface{}:
+		transformed := map[string]interface{}{}
+		for _, serviceIntf := range value {
+			service, ok := serviceIntf.(string)
+			if !ok {
+				return data, errors.Errorf("invalid type %T for service depends_on element. Expected string.", value)
+			}
+			transformed[service] = map[string]interface{}{"condition": types.ServiceConditionStarted}
+		}
+		return transformed, nil
+	case map[string]interface{}:
+		return data, nil
+	default:
+		return data, errors.Errorf("invalid type %T for service depends_on", value)
+	}
+}
+
 var transformServiceVolumeConfig TransformerFunc = func(data interface{}) (interface{}, error) {
 	switch value := data.(type) {
 	case string:
diff --git a/types/types.go b/types/types.go
index 8b056c8..a645b1f 100644
--- a/types/types.go
+++ b/types/types.go
@@ -95,7 +95,7 @@ type ServiceConfig struct {
 	Configs         []ServiceConfigObjConfig         `yaml:",omitempty" json:"configs,omitempty"`
 	ContainerName   string                           `mapstructure:"container_name" yaml:"container_name,omitempty" json:"container_name,omitempty"`
 	CredentialSpec  *CredentialSpecConfig            `mapstructure:"credential_spec" yaml:"credential_spec,omitempty" json:"credential_spec,omitempty"`
-	DependsOn       []string                         `mapstructure:"depends_on" yaml:"depends_on,omitempty" json:"depends_on,omitempty"`
+	DependsOn       DependsOnConfig                  `mapstructure:"depends_on" yaml:"depends_on,omitempty" json:"depends_on,omitempty"`
 	Deploy          *DeployConfig                    `yaml:",omitempty" json:"deploy,omitempty"`
 	Devices         []string                         `yaml:",omitempty" json:"devices,omitempty"`
 	DNS             StringList                       `yaml:",omitempty" json:"dns,omitempty"`
@@ -165,7 +165,9 @@ type ServiceConfig struct {
 // GetDependencies retrieve all services this service depends on
 func (s ServiceConfig) GetDependencies() []string {
 	dependencies := make(set)
-	dependencies.append(s.DependsOn...)
+	for dependency := range s.DependsOn {
+		dependencies.append(dependency)
+	}
 	dependencies.append(s.Links...)
 	if strings.HasPrefix(s.NetworkMode, "service:") {
 		dependencies.append(s.NetworkMode[8:])
@@ -657,6 +659,23 @@ type FileObjectConfig struct {
 	Extensions     map[string]interface{} `yaml:",inline" json:"-"`
 }
 
+const (
+	// TypeServiceConditionHealthy is the type for waiting until a service is
+	// healthy.
+	ServiceConditionHealthy = "service_healthy"
+
+	// TypeServiceConditionHealthy is the type for waiting until a service has
+	// started.
+	ServiceConditionStarted = "service_started"
+)
+
+type DependsOnConfig map[string]ServiceDependency
+
+type ServiceDependency struct {
+	Condition  string                 `yaml:",omitempty" json:"condition,omitempty"`
+	Extensions map[string]interface{} `yaml:",inline" json:"-"`
+}
+
 // SecretConfig for a secret
 type SecretConfig FileObjectConfig
 


Test patch:
diff --git a/cli/options_test.go b/cli/options_test.go
index d83b16b..9459307 100644
--- a/cli/options_test.go
+++ b/cli/options_test.go
@@ -76,6 +76,20 @@ func TestProjectWithDotEnv(t *testing.T) {
 	assert.Equal(t, service.Ports[0].Published, uint32(8000))
 }
 
+func TestProjectWithDiscardEnvFile(t *testing.T) {
+	opts, err := NewProjectOptions([]string{
+		"testdata/env-file/compose-with-env-file.yaml",
+	}, WithDiscardEnvFile)
+
+	assert.NilError(t, err)
+	p, err := ProjectFromOptions(opts)
+	assert.NilError(t, err)
+	service, err := p.GetService("simple")
+	assert.NilError(t, err)
+	assert.Equal(t, *service.Environment["DEFAULT_PORT"], "8080")
+	assert.Assert(t, service.EnvFile == nil)
+}
+
 func TestEnvMap(t *testing.T) {
 	m := map[string]string{}
 	m["foo"] = "bar"
diff --git a/cli/testdata/env-file/compose-with-env-file.yaml b/cli/testdata/env-file/compose-with-env-file.yaml
new file mode 100644
index 0000000..5d51ba9
--- /dev/null
+++ b/cli/testdata/env-file/compose-with-env-file.yaml
@@ -0,0 +1,8 @@
+version: "3"
+services:
+  simple:
+    image: nginx
+    env_file:
+      - ./simple-env
+    ports:
+    - 8000:80
diff --git a/cli/testdata/env-file/simple-env b/cli/testdata/env-file/simple-env
new file mode 100644
index 0000000..e2ba368
--- /dev/null
+++ b/cli/testdata/env-file/simple-env
@@ -0,0 +1,1 @@
+DEFAULT_PORT=8080
\ No newline at end of file
diff --git a/loader/full-struct_test.go b/loader/full-struct_test.go
index 2dcdae3..088b933 100644
--- a/loader/full-struct_test.go
+++ b/loader/full-struct_test.go
@@ -74,7 +74,10 @@ func services(workingDir, homeDir string) []types.ServiceConfig {
 				},
 			},
 			ContainerName: "my-web-container",
-			DependsOn:     []string{"db", "redis"},
+			DependsOn: types.DependsOnConfig{
+				"db":    {Condition: types.ServiceConditionStarted},
+				"redis": {Condition: types.ServiceConditionStarted},
+			},
 			Deploy: &types.DeployConfig{
 				Mode:     "replicated",
 				Replicas: uint64Ptr(6),
@@ -587,8 +590,10 @@ func fullExampleYAML(workingDir, homeDir string) string {
       mode: 288
     container_name: my-web-container
     depends_on:
-    - db
-    - redis
+      db:
+        condition: service_started
+      redis:
+        condition: service_started
     deploy:
       mode: replicated
       replicas: 6
@@ -1083,10 +1088,14 @@ func fullExampleJSON(workingDir, homeDir string) string {
         }
       ],
       "container_name": "my-web-container",
-      "depends_on": [
-        "db",
-        "redis"
-      ],
+      "depends_on": {
+        "db": {
+          "condition": "service_started"
+        },
+        "redis": {
+          "condition": "service_started"
+        }
+      },
       "deploy": {
         "mode": "replicated",
         "replicas": 6,
diff --git a/types/config_test.go b/types/config_test.go
index 80b1efb..32ebc74 100644
--- a/types/config_test.go
+++ b/types/config_test.go
@@ -26,13 +26,21 @@ func Test_WithServices(t *testing.T) {
 	p := Project{
 		Services: append(Services{},
 			ServiceConfig{
-				Name:      "service_1",
-				DependsOn: []string{"service_3"},
+				Name: "service_1",
+				DependsOn: map[string]ServiceDependency{
+					"service_3": {
+						Condition: ServiceConditionStarted,
+					},
+				},
 			}, ServiceConfig{
 				Name: "service_2",
 			}, ServiceConfig{
-				Name:  "service_3",
-				Links: []string{"service_2"},
+				Name: "service_3",
+				DependsOn: map[string]ServiceDependency{
+					"service_2": {
+						Condition: ServiceConditionStarted,
+					},
+				},
 			}),
 	}
 	order := []string{}