diff --git a/cli/compose/template/template.go b/cli/compose/template/template.go index 14ba09de3599..3bedc79b4504 100644 --- a/cli/compose/template/template.go +++ b/cli/compose/template/template.go @@ -72,6 +72,11 @@ func SubstituteWith(template string, mapping Mapping, pattern *regexp.Regexp, su func substituteWith(template string, mapping Mapping, pattern regexper, subsFuncs ...SubstituteFunc) (string, error) { var err error result := pattern.ReplaceAllStringFunc(template, func(substring string) string { + if err != nil { + // A previous substitution failed; don't continue, so that the + // error is not overwritten by later (successful) substitutions. + return "" + } matches := pattern.FindStringSubmatch(substring) groups := matchGroups(matches, defaultPattern) if escaped := groups["escaped"]; escaped != "" { @@ -89,12 +94,9 @@ func substituteWith(template string, mapping Mapping, pattern regexper, subsFunc } for _, f := range subsFuncs { - var ( - value string - applied bool - ) - value, applied, err = f(substitution, mapping) - if err != nil { + value, applied, subErr := f(substitution, mapping) + if subErr != nil { + err = subErr return "" } if !applied { diff --git a/cli/compose/template/template_test.go b/cli/compose/template/template_test.go index 0b2d463ebbe8..c87ff88df46c 100644 --- a/cli/compose/template/template_test.go +++ b/cli/compose/template/template_test.go @@ -132,6 +132,24 @@ func TestMandatoryVariableErrors(t *testing.T) { } } +func TestMandatoryVariableErrorsWithOtherVariables(t *testing.T) { + testCases := []string{ + "${UNSET_VAR:?Mandatory Variable Unset} ${FOO}", + "${UNSET_VAR:?Mandatory Variable Unset} $FOO", + "${UNSET_VAR:?Mandatory Variable Unset} ${missing:-def}", + "${UNSET_VAR?Mandatory Variable Unset}/${FOO?err}", + "${FOO} ${UNSET_VAR:?Mandatory Variable Unset} ${FOO}", + } + + for _, template := range testCases { + t.Run(template, func(t *testing.T) { + _, err := Substitute(template, defaultMapping) + assert.Check(t, is.ErrorContains(err, "required variable UNSET_VAR is missing a value: Mandatory Variable Unset")) + assert.Check(t, is.ErrorType(err, &InvalidTemplateError{})) + }) + } +} + func TestDefaultsForMandatoryVariables(t *testing.T) { testCases := []struct { template string