diff --git a/builder.go b/builder.go index 51ce5dfd..0fd07efd 100644 --- a/builder.go +++ b/builder.go @@ -317,6 +317,18 @@ func NewStages(node *parser.Node, b *Builder) (Stages, error) { } inheritedArgs := argInstructionsInStages[from] thisStageArgs := slices.Clone(inheritedArgs) + filteredUserArgs := make(map[string]string) + for k, v := range b.UserArgs { + for _, a := range b.GlobalAllowedArgs { + if a == k { + filteredUserArgs[k] = v + } + } + } + userArgs := envMapAsSlice(filteredUserArgs) + userArgs = mergeEnv(envMapAsSlice(b.BuiltinArgDefaults), userArgs) + userArgs = mergeEnv(envMapAsSlice(builtinArgDefaults), userArgs) + userArgs = mergeEnv(envMapAsSlice(b.HeadingArgs), userArgs) for _, child := range s.Node.Children { if !strings.EqualFold(child.Value, command.Arg) { continue @@ -329,7 +341,12 @@ func NewStages(node *parser.Node, b *Builder) (Stages, error) { } next := child.Next for next != nil { - thisStageArgs = append(thisStageArgs, next.Value) + processedValue, err := ProcessWord(next.Value, userArgs) + if err != nil { + return fmt.Errorf("processing ARG %q", next.Value) + } + thisStageArgs = append(thisStageArgs, processedValue) + userArgs = mergeEnv(userArgs, []string{processedValue}) next = next.Next } } diff --git a/builder_test.go b/builder_test.go index 8b770ac0..f7bfcc71 100644 --- a/builder_test.go +++ b/builder_test.go @@ -546,6 +546,12 @@ func TestMultiStageArgScope(t *testing.T) { if !builderHasArgument(stages[0].Builder, "SECRET=secretthings") { t.Fatalf("expected SECRET=secretthings to be contained in first stage arguments list: %v", stages[0].Builder.Arguments()) } + if !builderHasArgument(stages[0].Builder, "QUOTED=words with quotes") { + t.Fatalf(`expected QUOTED="words with quotes" to be present in first stage arguments list: %v`, stages[0].Builder.Arguments()) + } + if !builderHasArgument(stages[0].Builder, "REQUOTED=words with quotes") { + t.Fatalf(`expected REQUOTED="words with quotes" to be present in first stage arguments list: %v`, stages[0].Builder.Arguments()) + } secondStageArguments := stages[1].Builder.Arguments() secretInSecondStage := false @@ -591,6 +597,12 @@ func TestMultiStageArgScope(t *testing.T) { if !unusedInThirdStage { t.Fatalf("expected UNUSED to be present in third stage") } + if !builderHasArgument(stages[2].Builder, "QUOTED=words with quotes") { + t.Fatalf(`expected QUOTED=words with quotes to be present in third stage arguments list: %v`, thirdStageArguments) + } + if !builderHasArgument(stages[2].Builder, "REQUOTED=words with quotes") { + t.Fatalf(`expected REQUOTED=words with quotes to be present in third stage arguments list: %v`, thirdStageArguments) + } } func TestRun(t *testing.T) { diff --git a/dockerclient/testdata/multistage/Dockerfile.arg-scope b/dockerclient/testdata/multistage/Dockerfile.arg-scope index 2e39f8bd..ad031e23 100644 --- a/dockerclient/testdata/multistage/Dockerfile.arg-scope +++ b/dockerclient/testdata/multistage/Dockerfile.arg-scope @@ -2,6 +2,8 @@ FROM mirror.gcr.io/alpine ARG SECRET ARG UNUSED ARG INHERITED=set +ARG QUOTED="words with quotes" +ARG REQUOTED=$QUOTED RUN echo "$SECRET" FROM mirror.gcr.io/alpine @@ -12,3 +14,5 @@ RUN echo "$SECRET" FROM 0 RUN echo "$SECRET" +ARG QUOTED +ARG REQUOTED