Repository: compose-spec/compose-go
Pull request #764 (2025-04-02 13:29:48)

prefer `provider` over `external` to avoid confusion

ndeloof: FYI @mikesir87

Patch:
diff --git a/loader/validate.go b/loader/validate.go
index 90d64ea..0d95325 100644
--- a/loader/validate.go
+++ b/loader/validate.go
@@ -29,7 +29,7 @@ import (
 // checkConsistency validate a compose model is consistent
 func checkConsistency(project *types.Project) error { //nolint:gocyclo
 	for name, s := range project.Services {
-		if s.Build == nil && s.Image == "" && s.External == nil {
+		if s.Build == nil && s.Image == "" && s.Provider == nil {
 			return fmt.Errorf("service %q has neither an image nor a build context specified: %w", s.Name, errdefs.ErrInvalid)
 		}
 
diff --git a/schema/compose-spec.json b/schema/compose-spec.json
index 0e622c7..d77b09a 100644
--- a/schema/compose-spec.json
+++ b/schema/compose-spec.json
@@ -259,7 +259,7 @@
             }
           ]
         },
-        "external": {
+        "provider": {
           "type": "object",
           "properties": {
             "type": {"type": "string"},
diff --git a/types/derived.gen.go b/types/derived.gen.go
index 9e32e90..e540c53 100644
--- a/types/derived.gen.go
+++ b/types/derived.gen.go
@@ -355,11 +355,11 @@ func deriveDeepCopyService(dst, src *ServiceConfig) {
 		}
 		copy(dst.Entrypoint, src.Entrypoint)
 	}
-	if src.External == nil {
-		dst.External = nil
+	if src.Provider == nil {
+		dst.Provider = nil
 	} else {
-		dst.External = new(ExternalServiceConfig)
-		deriveDeepCopy_13(dst.External, src.External)
+		dst.Provider = new(ServiceProviderConfig)
+		deriveDeepCopy_13(dst.Provider, src.Provider)
 	}
 	if src.Environment != nil {
 		dst.Environment = make(map[string]*string, len(src.Environment))
@@ -1226,7 +1226,7 @@ func deriveDeepCopy_12(dst, src []DeviceMapping) {
 }
 
 // deriveDeepCopy_13 recursively copies the contents of src into dst.
-func deriveDeepCopy_13(dst, src *ExternalServiceConfig) {
+func deriveDeepCopy_13(dst, src *ServiceProviderConfig) {
 	dst.Type = src.Type
 	if src.Options != nil {
 		dst.Options = make(map[string]string, len(src.Options))
diff --git a/types/types.go b/types/types.go
index 189b5e7..0144b70 100644
--- a/types/types.go
+++ b/types/types.go
@@ -76,7 +76,7 @@ type ServiceConfig struct {
 	//
 	// Set to `[]` or an empty string to clear the entrypoint from the image.
 	Entrypoint      ShellCommand                     `yaml:"entrypoint,omitempty" json:"entrypoint"` // NOTE: we can NOT omitempty for JSON! see ShellCommand type for details.
-	External        *ExternalServiceConfig           `yaml:"external,omitempty" json:"external,omitempty"`
+	Provider        *ServiceProviderConfig           `yaml:"provider,omitempty" json:"provider,omitempty"`
 	Environment     MappingWithEquals                `yaml:"environment,omitempty" json:"environment,omitempty"`
 	EnvFiles        []EnvFile                        `yaml:"env_file,omitempty" json:"env_file,omitempty"`
 	Expose          StringOrNumberList               `yaml:"expose,omitempty" json:"expose,omitempty"`
@@ -142,7 +142,7 @@ type ServiceConfig struct {
 	Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
 }
 
-type ExternalServiceConfig struct {
+type ServiceProviderConfig struct {
 	Type       string     `yaml:"type,omitempty" json:"driver,omitempty"`
 	Options    Options    `yaml:"options,omitempty" json:"options,omitempty"`
 	Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`


Test patch:
diff --git a/loader/loader_test.go b/loader/loader_test.go
index d28cc5f..d51095f 100644
--- a/loader/loader_test.go
+++ b/loader/loader_test.go
@@ -3761,18 +3761,18 @@ services:
 	assert.Equal(t, *p.Services["test"].Secrets[0].Mode, types.FileMode(0o440))
 }
 
-func TestExternalService(t *testing.T) {
+func TestServiceProvider(t *testing.T) {
 	p, err := loadYAML(`
-name: external-service
+name: service-provider
 services:
   test:
-    external:
+    provider:
       type: foo
       options:
         bar: zot
 `)
 	assert.NilError(t, err)
-	assert.DeepEqual(t, p.Services["test"].External, &types.ExternalServiceConfig{
+	assert.DeepEqual(t, p.Services["test"].Provider, &types.ServiceProviderConfig{
 		Type:    "foo",
 		Options: map[string]string{"bar": "zot"},
 	})