Repository: compose-spec/compose-go
Pull request #92 (2020-12-14 09:39:07)

Check service has either a Build section or Image set
Detect invalid image definition for service (no build, no image) as we load compose file

see https://github.com/docker/compose-cli/issues/1055


Patch:
diff --git a/go.sum b/go.sum
index 5dd98c9..1316385 100644
--- a/go.sum
+++ b/go.sum
@@ -7,8 +7,7 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw
 github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo=
-github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
 github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
@@ -16,8 +15,7 @@ github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
 github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
 github.com/mattn/go-shellwords v1.0.10 h1:Y7Xqm8piKOO3v10Thp7Z36h4FYFjt5xB//6XvOrs2Gw=
 github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
-github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
-github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks=
 github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -53,6 +51,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
 gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
diff --git a/loader/validate.go b/loader/validate.go
index 0d6fdbe..18abb43 100644
--- a/loader/validate.go
+++ b/loader/validate.go
@@ -27,6 +27,10 @@ import (
 // checkConsistency validate a compose model is consistent
 func checkConsistency(project *types.Project) error {
 	for _, s := range project.Services {
+		if s.Build == nil && s.Image == "" {
+			return errors.Wrapf(errdefs.ErrInvalid, "service %q has neither an image nor a build context specified", s.Name)
+		}
+
 		for network := range s.Networks {
 			if _, ok := project.Networks[network]; !ok {
 				return errors.Wrap(errdefs.ErrInvalid, fmt.Sprintf("service %q refers to undefined network %s", s.Name, network))


Test patch:
diff --git a/loader/validate_test.go b/loader/validate_test.go
index e63d3ef..1eed167 100644
--- a/loader/validate_test.go
+++ b/loader/validate_test.go
@@ -27,7 +27,8 @@ func TestValidateAnonymousVolume(t *testing.T) {
 	project := &types.Project{
 		Services: types.Services([]types.ServiceConfig{
 			{
-				Name: "myservice",
+				Name:  "myservice",
+				Image: "my/service",
 				Volumes: []types.ServiceVolumeConfig{
 					{
 						Type:   types.VolumeTypeVolume,
@@ -45,7 +46,8 @@ func TestValidateNamedVolume(t *testing.T) {
 	project := &types.Project{
 		Services: types.Services([]types.ServiceConfig{
 			{
-				Name: "myservice",
+				Name:  "myservice",
+				Image: "my/service",
 				Volumes: []types.ServiceVolumeConfig{
 					{
 						Type:   types.VolumeTypeVolume,
@@ -66,5 +68,16 @@ func TestValidateNamedVolume(t *testing.T) {
 	})
 	err = checkConsistency(project)
 	assert.NilError(t, err)
+}
 
+func TestValidateNoBuildNoImage(t *testing.T) {
+	project := &types.Project{
+		Services: types.Services([]types.ServiceConfig{
+			{
+				Name: "myservice",
+			},
+		}),
+	}
+	err := checkConsistency(project)
+	assert.Error(t, err, `service "myservice" has neither an image nor a build context specified: invalid compose project`)
 }