Repository: compose-spec/compose-go
Pull request #186 (2021-09-16 08:33:44)

release process
replace https://github.com/compose-spec/compose-go/pull/185


sample run : https://github.com/ndeloof/compose-go/releases/tag/v1.2.3


Patch:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..fa2cb92
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,13 @@
+name: Release
+on:
+  push:
+    tags:
+      - "v1*"
+
+jobs:
+  release:
+    runs-on: ubuntu-latest      
+    steps:
+      - uses: ncipollo/release-action@v1
+        with:
+          token: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
diff --git a/loader/loader.go b/loader/loader.go
index dd093b8..32a10f0 100644
--- a/loader/loader.go
+++ b/loader/loader.go
@@ -514,9 +514,7 @@ func loadServiceWithExtends(filename, name string, servicesDict map[string]inter
 // LoadService produces a single ServiceConfig from a compose file Dict
 // the serviceDict is not validated if directly used. Use Load() to enable validation
 func LoadService(name string, serviceDict map[string]interface{}, workingDir string, lookupEnv template.Mapping, resolvePaths bool) (*types.ServiceConfig, error) {
-	serviceConfig := &types.ServiceConfig{
-		Scale: 1,
-	}
+	serviceConfig := &types.ServiceConfig{}
 	if err := Transform(serviceDict, serviceConfig); err != nil {
 		return nil, err
 	}
@@ -1007,13 +1005,10 @@ var transformSize TransformerFunc = func(value interface{}) (interface{}, error)
 	switch value := value.(type) {
 	case int:
 		return int64(value), nil
-	case int64, types.UnitBytes:
-		return value, nil
 	case string:
 		return units.RAMInBytes(value)
-	default:
-		return value, errors.Errorf("invalid type for size %T", value)
 	}
+	panic(errors.Errorf("invalid type for size %T", value))
 }
 
 var transformStringToDuration TransformerFunc = func(value interface{}) (interface{}, error) {
diff --git a/loader/merge.go b/loader/merge.go
index 0c7a6dd..07ccdb0 100644
--- a/loader/merge.go
+++ b/loader/merge.go
@@ -108,10 +108,10 @@ func _merge(baseService *types.ServiceConfig, overrideService *types.ServiceConf
 	if err := mergo.Merge(baseService, overrideService, mergo.WithAppendSlice, mergo.WithOverride, mergo.WithTransformers(serviceSpecials)); err != nil {
 		return nil, err
 	}
-	if overrideService.Command != nil {
+	if len(overrideService.Command) > 0 {
 		baseService.Command = overrideService.Command
 	}
-	if overrideService.Entrypoint != nil {
+	if len(overrideService.Entrypoint) > 0 {
 		baseService.Entrypoint = overrideService.Entrypoint
 	}
 	return baseService, nil
diff --git a/loader/normalize.go b/loader/normalize.go
index 3f465b3..30e9d20 100644
--- a/loader/normalize.go
+++ b/loader/normalize.go
@@ -84,22 +84,17 @@ func normalize(project *types.Project, resolvePaths bool) error {
 		}
 		s.Environment = s.Environment.Resolve(fn)
 
-		err := relocateLogDriver(&s)
+		err := relocateLogDriver(s)
 		if err != nil {
 			return err
 		}
 
-		err = relocateLogOpt(&s)
+		err = relocateLogOpt(s)
 		if err != nil {
 			return err
 		}
 
-		err = relocateDockerfile(&s)
-		if err != nil {
-			return err
-		}
-
-		err = relocateScale(&s)
+		err = relocateDockerfile(s)
 		if err != nil {
 			return err
 		}
@@ -112,21 +107,6 @@ func normalize(project *types.Project, resolvePaths bool) error {
 	return nil
 }
 
-func relocateScale(s *types.ServiceConfig) error {
-	scale := uint64(s.Scale)
-	if scale != 1 {
-		logrus.Warn("`scale` is deprecated. Use the `deploy.replicas` element")
-		if s.Deploy == nil {
-			s.Deploy = &types.DeployConfig{}
-		}
-		if s.Deploy.Replicas != nil && *s.Deploy.Replicas != scale {
-			return errors.Wrap(errdefs.ErrInvalid, "can't use both 'scale' (deprecated) and 'deploy.replicas'")
-		}
-		s.Deploy.Replicas = &scale
-	}
-	return nil
-}
-
 func absComposeFiles(composeFiles []string) ([]string, error) {
 	absComposeFiles := make([]string, len(composeFiles))
 	for i, composeFile := range composeFiles {
@@ -213,7 +193,7 @@ func relocateExternalName(project *types.Project) error {
 	return nil
 }
 
-func relocateLogOpt(s *types.ServiceConfig) error {
+func relocateLogOpt(s types.ServiceConfig) error {
 	if len(s.LogOpt) != 0 {
 		logrus.Warn("`log_opts` is deprecated. Use the `logging` element")
 		if s.Logging == nil {
@@ -230,7 +210,7 @@ func relocateLogOpt(s *types.ServiceConfig) error {
 	return nil
 }
 
-func relocateLogDriver(s *types.ServiceConfig) error {
+func relocateLogDriver(s types.ServiceConfig) error {
 	if s.LogDriver != "" {
 		logrus.Warn("`log_driver` is deprecated. Use the `logging` element")
 		if s.Logging == nil {
@@ -245,7 +225,7 @@ func relocateLogDriver(s *types.ServiceConfig) error {
 	return nil
 }
 
-func relocateDockerfile(s *types.ServiceConfig) error {
+func relocateDockerfile(s types.ServiceConfig) error {
 	if s.Dockerfile != "" {
 		logrus.Warn("`dockerfile` is deprecated. Use the `build` element")
 		if s.Build == nil {
diff --git a/types/types.go b/types/types.go
index 23bae0e..f4d5886 100644
--- a/types/types.go
+++ b/types/types.go
@@ -152,7 +152,7 @@ type ServiceConfig struct {
 	ReadOnly        bool                             `mapstructure:"read_only" yaml:"read_only,omitempty" json:"read_only,omitempty"`
 	Restart         string                           `yaml:",omitempty" json:"restart,omitempty"`
 	Runtime         string                           `yaml:",omitempty" json:"runtime,omitempty"`
-	Scale           int                              `yaml:"-" json:"-"`
+	Scale           int                              `yaml:",omitempty" json:"scale,omitempty"`
 	Secrets         []ServiceSecretConfig            `yaml:",omitempty" json:"secrets,omitempty"`
 	SecurityOpt     []string                         `mapstructure:"security_opt" yaml:"security_opt,omitempty" json:"security_opt,omitempty"`
 	ShmSize         UnitBytes                        `mapstructure:"shm_size" yaml:"shm_size,omitempty" json:"shm_size,omitempty"`


Test patch:
diff --git a/compatibility/allowlist_test.go b/compatibility/allowlist_test.go
index f5951da..592d3e9 100644
--- a/compatibility/allowlist_test.go
+++ b/compatibility/allowlist_test.go
@@ -33,7 +33,6 @@ func TestAllowList(t *testing.T) {
 				"services.network_mode",
 				"services.privileged",
 				"services.networks",
-				"services.scale",
 			},
 		},
 	}
diff --git a/loader/full-struct_test.go b/loader/full-struct_test.go
index 751a553..a4e0e14 100644
--- a/loader/full-struct_test.go
+++ b/loader/full-struct_test.go
@@ -358,7 +358,6 @@ func services(workingDir, homeDir string) []types.ServiceConfig {
 			Privileged: true,
 			ReadOnly:   true,
 			Restart:    types.RestartPolicyAlways,
-			Scale:      1,
 			Secrets: []types.ServiceSecretConfig{
 				{
 					Source: "secret1",
diff --git a/loader/loader_test.go b/loader/loader_test.go
index cea5117..9d2e52f 100644
--- a/loader/loader_test.go
+++ b/loader/loader_test.go
@@ -202,7 +202,6 @@ var sampleConfig = types.Config{
 			Networks: map[string]*types.ServiceNetworkConfig{
 				"with_me": nil,
 			},
-			Scale: 1,
 		},
 		{
 			Name:        "bar",
@@ -211,7 +210,6 @@ var sampleConfig = types.Config{
 			Networks: map[string]*types.ServiceNetworkConfig{
 				"with_ipam": nil,
 			},
-			Scale: 1,
 		},
 	},
 	Networks: map[string]types.NetworkConfig{
@@ -691,7 +689,6 @@ networks:
 				},
 				Privileged: true,
 				ReadOnly:   true,
-				Scale:      1,
 				ShmSize:    types.UnitBytes(2 * 1024 * 1024 * 1024),
 				StdinOpen:  true,
 				Tty:        true,
@@ -1443,7 +1440,6 @@ networks:
 			{
 				Name:  "hello-world",
 				Image: "redis:alpine",
-				Scale: 1,
 				Networks: map[string]*types.ServiceNetworkConfig{
 					"network1": nil,
 					"network3": nil,
@@ -1606,7 +1602,6 @@ secrets:
 						Source: "config",
 					},
 				},
-				Scale: 1,
 				Secrets: []types.ServiceSecretConfig{
 					{
 						Source: "secret",
@@ -1672,7 +1667,6 @@ secrets:
 						Source: "config",
 					},
 				},
-				Scale: 1,
 				Secrets: []types.ServiceSecretConfig{
 					{
 						Source: "secret",
@@ -1747,7 +1741,6 @@ func TestLoadWithExtends(t *testing.T) {
 			},
 			Environment: types.MappingWithEquals{},
 			Networks:    map[string]*types.ServiceNetworkConfig{"default": nil},
-			Scale:       1,
 		},
 	}
 	assert.Check(t, is.DeepEqual(expServices, actual.Services))
diff --git a/loader/merge_test.go b/loader/merge_test.go
index 42f5f38..035eeba 100644
--- a/loader/merge_test.go
+++ b/loader/merge_test.go
@@ -215,7 +215,6 @@ func TestLoadLogging(t *testing.T) {
 						Name:        "foo",
 						Logging:     tc.expected,
 						Environment: types.MappingWithEquals{},
-						Scale:       1,
 					},
 				},
 				Networks:   types.Networks{},
@@ -371,7 +370,6 @@ func TestLoadMultipleServicePorts(t *testing.T) {
 						Name:        "foo",
 						Ports:       tc.expected,
 						Environment: types.MappingWithEquals{},
-						Scale:       1,
 					},
 				},
 				Networks:   types.Networks{},
@@ -497,7 +495,6 @@ func TestLoadMultipleSecretsConfig(t *testing.T) {
 						Name:        "foo",
 						Secrets:     tc.expected,
 						Environment: types.MappingWithEquals{},
-						Scale:       1,
 					},
 				},
 				Networks:   types.Networks{},
@@ -623,7 +620,6 @@ func TestLoadMultipleConfigobjsConfig(t *testing.T) {
 						Name:        "foo",
 						Configs:     tc.expected,
 						Environment: types.MappingWithEquals{},
-						Scale:       1,
 					},
 				},
 				Networks:   types.Networks{},
@@ -739,7 +735,6 @@ func TestLoadMultipleUlimits(t *testing.T) {
 						Name:        "foo",
 						Ulimits:     tc.expected,
 						Environment: types.MappingWithEquals{},
-						Scale:       1,
 					},
 				},
 				Networks:   types.Networks{},
@@ -858,7 +853,6 @@ func TestLoadMultipleServiceNetworks(t *testing.T) {
 						Name:        "foo",
 						Networks:    tc.expected,
 						Environment: types.MappingWithEquals{},
-						Scale:       1,
 					},
 				},
 				Networks:   types.Networks{},
@@ -875,9 +869,7 @@ func TestLoadMultipleConfigs(t *testing.T) {
 	base := map[string]interface{}{
 		"services": map[string]interface{}{
 			"foo": map[string]interface{}{
-				"image":      "foo",
-				"entrypoint": "echo",
-				"command":    "hellow world",
+				"image": "foo",
 				"build": map[string]interface{}{
 					"context":    ".",
 					"dockerfile": "bar.Dockerfile",
@@ -902,9 +894,7 @@ func TestLoadMultipleConfigs(t *testing.T) {
 	override := map[string]interface{}{
 		"services": map[string]interface{}{
 			"foo": map[string]interface{}{
-				"image":      "baz",
-				"entrypoint": "ping",
-				"command":    "localhost",
+				"image": "baz",
 				"build": map[string]interface{}{
 					"dockerfile": "foo.Dockerfile",
 					"args": []interface{}{
@@ -950,13 +940,10 @@ func TestLoadMultipleConfigs(t *testing.T) {
 				Name:        "bar",
 				Image:       "bar",
 				Environment: types.MappingWithEquals{},
-				Scale:       1,
 			},
 			{
-				Name:       "foo",
-				Image:      "baz",
-				Entrypoint: types.ShellCommand{"ping"},
-				Command:    types.ShellCommand{"localhost"},
+				Name:  "foo",
+				Image: "baz",
 				Build: &types.BuildConfig{
 					Context:    ".",
 					Dockerfile: "foo.Dockerfile",
@@ -988,7 +975,6 @@ func TestLoadMultipleConfigs(t *testing.T) {
 				},
 				CapAdd:      []string{"NET_ADMIN", "SYS_ADMIN"},
 				Environment: types.MappingWithEquals{},
-				Scale:       1,
 			}},
 		Networks:   types.Networks{},
 		Volumes:    types.Volumes{},
@@ -1052,7 +1038,6 @@ func TestLoadMultipleNetworks(t *testing.T) {
 				Name:        "foo",
 				Image:       "baz",
 				Environment: types.MappingWithEquals{},
-				Scale:       1,
 			}},
 		Networks: map[string]types.NetworkConfig{
 			"hostnet": {
diff --git a/loader/normalize_test.go b/loader/normalize_test.go
index dcc5858..2f500e6 100644
--- a/loader/normalize_test.go
+++ b/loader/normalize_test.go
@@ -54,7 +54,6 @@ func TestNormalizeNetworkNames(t *testing.T) {
 						"ZOT": nil,
 					},
 				},
-				Scale: 1,
 			},
 		},
 	}
diff --git a/loader/with-version-struct_test.go b/loader/with-version-struct_test.go
index cefb4d1..1ff23f9 100644
--- a/loader/with-version-struct_test.go
+++ b/loader/with-version-struct_test.go
@@ -42,7 +42,6 @@ func withVersionServices(workingDir, homeDir string) []types.ServiceConfig {
 				"default": nil,
 			},
 			VolumesFrom: []string{"other"},
-			Scale:       1,
 		},
 		{
 			Name: "other",
@@ -53,7 +52,6 @@ func withVersionServices(workingDir, homeDir string) []types.ServiceConfig {
 			Volumes: []types.ServiceVolumeConfig{
 				{Target: "/data", Type: "volume", Volume: &types.ServiceVolumeVolume{}},
 			},
-			Scale: 1,
 		},
 	}
 }