Skip to content

Commit 42c1cc8

Browse files
committed
do not interpolate service.environment
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
1 parent a0d3b94 commit 42c1cc8

File tree

15 files changed

+130
-87
lines changed

15 files changed

+130
-87
lines changed

cli/options_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,9 @@ func TestProjectName(t *testing.T) {
167167
})
168168

169169
t.Run("by COMPOSE_PROJECT_NAME", func(t *testing.T) {
170-
err := os.Setenv("COMPOSE_PROJECT_NAME", "my_project_from_env")
170+
err := os.Setenv(consts.ComposeProjectName, "my_project_from_env")
171171
assert.NilError(t, err)
172-
defer os.Unsetenv("COMPOSE_PROJECT_NAME")
172+
defer os.Unsetenv(consts.ComposeProjectName)
173173
opts, err := NewProjectOptions([]string{"testdata/simple/compose.yaml"}, WithOsEnv)
174174
assert.NilError(t, err)
175175
p, err := ProjectFromOptions(context.TODO(), opts)

dotenv/godotenv.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ func ReadFile(filename string, lookupFn LookupFn) (map[string]string, error) {
167167
return ParseWithLookup(file, lookupFn)
168168
}
169169

170-
func expandVariables(value string, envMap map[string]string, lookupFn LookupFn) (string, error) {
170+
func ExpandVariables(value string, envMap map[string]string, lookupFn LookupFn) (string, error) {
171171
retVal, err := template.Substitute(value, func(k string) (string, bool) {
172172
if v, ok := lookupFn(k); ok {
173173
return v, true

dotenv/godotenv_var_expansion_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func TestExpandIfEmptyOrUnset(t *testing.T) {
4343

4444
for _, expected := range templateResults {
4545
t.Run(expected.name, func(t *testing.T) {
46-
result, err := expandVariables(expected.input, envMap, notFoundLookup)
46+
result, err := ExpandVariables(expected.input, envMap, notFoundLookup)
4747
require.NoError(t, err)
4848
assert.Equal(t, expected.result, result)
4949
})
@@ -75,7 +75,7 @@ func TestExpandIfUnset(t *testing.T) {
7575

7676
for _, expected := range templateResults {
7777
t.Run(expected.name, func(t *testing.T) {
78-
result, err := expandVariables(expected.input, envMap, notFoundLookup)
78+
result, err := ExpandVariables(expected.input, envMap, notFoundLookup)
7979
require.NoError(t, err)
8080
assert.Equal(t, expected.result, result)
8181
})
@@ -111,7 +111,7 @@ func TestErrorIfEmptyOrUnset(t *testing.T) {
111111

112112
for _, expected := range templateResults {
113113
t.Run(expected.name, func(t *testing.T) {
114-
result, err := expandVariables(expected.input, envMap, notFoundLookup)
114+
result, err := ExpandVariables(expected.input, envMap, notFoundLookup)
115115
assert.Equal(t, expected.err, err)
116116
assert.Equal(t, expected.result, result)
117117
})
@@ -147,7 +147,7 @@ func TestErrorIfUnset(t *testing.T) {
147147

148148
for _, expected := range templateResults {
149149
t.Run(expected.name, func(t *testing.T) {
150-
result, err := expandVariables(expected.input, envMap, notFoundLookup)
150+
result, err := ExpandVariables(expected.input, envMap, notFoundLookup)
151151
assert.Equal(t, expected.err, err)
152152
assert.Equal(t, expected.result, result)
153153
})

dotenv/parser.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ func (p *parser) extractVarValue(src string, envMap map[string]string, lookupFn
157157
// Remove inline comments on unquoted lines
158158
value, _, _ = strings.Cut(value, " #")
159159
value = strings.TrimRightFunc(value, unicode.IsSpace)
160-
retVal, err := expandVariables(value, envMap, lookupFn)
160+
retVal, err := ExpandVariables(value, envMap, lookupFn)
161161
return retVal, rest, err
162162
}
163163

@@ -194,7 +194,7 @@ func (p *parser) extractVarValue(src string, envMap map[string]string, lookupFn
194194
if quote == prefixDoubleQuote {
195195
// expand standard shell escape sequences & then interpolate
196196
// variables on the result
197-
retVal, err := expandVariables(expandEscapes(value), envMap, lookupFn)
197+
retVal, err := ExpandVariables(expandEscapes(value), envMap, lookupFn)
198198
if err != nil {
199199
return "", "", err
200200
}

interpolation/interpolation.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ type Options struct {
3333
TypeCastMapping map[tree.Path]Cast
3434
// Substitution function to use
3535
Substitute func(string, template.Mapping) (string, error)
36+
// Exclude do not run interpolation on matching paths
37+
Exclude []tree.Path
38+
}
39+
40+
func (opts *Options) Clone() *Options {
41+
return &Options{
42+
Substitute: opts.Substitute,
43+
LookupValue: opts.LookupValue,
44+
TypeCastMapping: opts.TypeCastMapping,
45+
Exclude: opts.Exclude,
46+
}
3647
}
3748

3849
// LookupValue is a function which maps from variable names to values.
@@ -70,6 +81,11 @@ func Interpolate(config map[string]interface{}, opts Options) (map[string]interf
7081
}
7182

7283
func recursiveInterpolate(value interface{}, path tree.Path, opts Options) (interface{}, error) {
84+
for _, pattern := range opts.Exclude {
85+
if path.Matches(pattern) {
86+
return value, nil
87+
}
88+
}
7389
switch value := value.(type) {
7490
case string:
7591
newValue, err := opts.Substitute(value, template.Mapping(opts.LookupValue))
@@ -127,8 +143,8 @@ func newPathError(path tree.Path, err error) error {
127143
}
128144
}
129145

130-
func (o Options) getCasterForPath(path tree.Path) (Cast, bool) {
131-
for pattern, caster := range o.TypeCastMapping {
146+
func (opts Options) getCasterForPath(path tree.Path) (Cast, bool) {
147+
for pattern, caster := range opts.TypeCastMapping {
132148
if path.Matches(pattern) {
133149
return caster, true
134150
}

loader/environment.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ func resolveServicesEnvironment(dict map[string]any, environment types.Mapping)
4040
if !ok {
4141
continue
4242
}
43+
if _, ok := serviceConfig[types.LoaderEnvironment]; !ok && environment != nil {
44+
serviceConfig[types.LoaderEnvironment] = map[string]string(environment)
45+
}
46+
services[service] = serviceConfig
47+
4348
serviceEnv, ok := serviceConfig["environment"].([]any)
4449
if !ok {
4550
continue
@@ -58,7 +63,6 @@ func resolveServicesEnvironment(dict map[string]any, environment types.Mapping)
5863
}
5964
}
6065
serviceConfig["environment"] = envs
61-
services[service] = serviceConfig
6266
}
6367
dict["services"] = services
6468
}

loader/include.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
"strings"
2626

2727
"github.com/compose-spec/compose-go/v2/dotenv"
28-
interp "github.com/compose-spec/compose-go/v2/interpolation"
2928
"github.com/compose-spec/compose-go/v2/types"
3029
)
3130

@@ -142,11 +141,8 @@ func ApplyInclude(ctx context.Context, workingDir string, environment types.Mapp
142141
ConfigFiles: types.ToConfigFiles(r.Path),
143142
Environment: environment.Clone().Merge(envFromFile),
144143
}
145-
loadOptions.Interpolate = &interp.Options{
146-
Substitute: options.Interpolate.Substitute,
147-
LookupValue: config.LookupEnv,
148-
TypeCastMapping: options.Interpolate.TypeCastMapping,
149-
}
144+
loadOptions.Interpolate = options.Interpolate.Clone()
145+
loadOptions.Interpolate.LookupValue = config.LookupEnv
150146
imported, err := loadYamlModel(ctx, config, loadOptions, &cycleTracker{}, included)
151147
if err != nil {
152148
return err

loader/loader.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ func (o *Options) clone() *Options {
179179
SkipConsistencyCheck: o.SkipConsistencyCheck,
180180
SkipExtends: o.SkipExtends,
181181
SkipInclude: o.SkipInclude,
182+
SkipResolveEnvironment: o.SkipResolveEnvironment,
182183
Interpolate: o.Interpolate,
183184
discardEnvFiles: o.discardEnvFiles,
184185
projectName: o.projectName,
@@ -362,6 +363,9 @@ func toOptions(configDetails *types.ConfigDetails, options []func(*Options)) *Op
362363
op(opts)
363364
}
364365
opts.ResourceLoaders = append(opts.ResourceLoaders, localResourceLoader{configDetails.WorkingDir})
366+
if opts.SkipResolveEnvironment {
367+
opts.Interpolate.Exclude = append(opts.Interpolate.Exclude, "services.*.environment")
368+
}
365369
return opts
366370
}
367371

@@ -724,8 +728,10 @@ func processExtensions(dict map[string]any, p tree.Path, extensions map[string]a
724728
}
725729
}
726730
if !skip && strings.HasPrefix(key, "x-") {
727-
extras[key] = value
728-
delete(dict, key)
731+
if key != types.LoaderEnvironment {
732+
extras[key] = value
733+
delete(dict, key)
734+
}
729735
continue
730736
}
731737
switch v := value.(type) {

0 commit comments

Comments
 (0)