Skip to content

Commit

Permalink
Support Let/Set in autoskip (#4007)
Browse files Browse the repository at this point in the history
  • Loading branch information
idodod authored Apr 10, 2024
1 parent 385b84d commit 35e384f
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ All notable changes to [Earthly](https://github.com/earthly/earthly) will be doc
### Fixed

- Make `LET`/`SET` commands block parallel commands such as `BUILD` until the former are processed, similar to the behavior of `ARG`. [#3997](https://github.com/earthly/earthly/issues/3997)
- `LET`/`SET` commands were not properly handled with the use of Auto-skip. [#3996](https://github.com/earthly/earthly/issues/3996)

## v0.8.7 - 2024-04-03

Expand Down
61 changes: 61 additions & 0 deletions inputgraph/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,10 @@ func (l *loader) handleCommand(ctx context.Context, cmd spec.Command) error {
return l.handleCopy(ctx, cmd)
case command.Arg:
return l.handleArg(ctx, cmd, false)
case command.Let:
return l.handleLet(ctx, cmd)
case command.Set:
return l.handleSet(ctx, cmd)
case command.FromDockerfile:
return l.handleFromDockerfile(ctx, cmd)
case command.Import:
Expand Down Expand Up @@ -454,6 +458,63 @@ func (l *loader) handleArg(ctx context.Context, cmd spec.Command, isBase bool) e
return nil
}

func (l *loader) handleLet(ctx context.Context, cmd spec.Command) error {
var opts commandflag.LetOpts
argsCpy := flagutil.GetArgsCopy(cmd)
args, err := flagutil.ParseArgsCleaned("LET", &opts, argsCpy)
if err != nil {
return wrapError(err, cmd.SourceLocation, "failed to parse LET args")
}
// performing minimal validation to avoid index out of bound (full validation occurs in the interpreter)
if len(args) != 3 {
return newError(cmd.SourceLocation, "failed to parse LET args")
}
key := args[0]
baseVal := args[2]
val, err := l.expandArgs(ctx, baseVal)
if err != nil {
return wrapError(err, cmd.SourceLocation, "failed to expand LET value %q", baseVal)
}

l.hasher.HashString(fmt.Sprintf("LET %s=%s", key, val))

_, _, err = l.varCollection.DeclareVar(key, variables.WithValue(val))
if err != nil {
return wrapError(err, cmd.SourceLocation, "failed to declare variable")
}
return nil
}

func (l *loader) handleSet(ctx context.Context, cmd spec.Command) error {
var opts commandflag.SetOpts
argsCpy := flagutil.GetArgsCopy(cmd)
args, err := flagutil.ParseArgsCleaned("SET", &opts, argsCpy)
if err != nil {
return wrapError(err, cmd.SourceLocation, "failed to parse SET args")
}
// performing minimal validation to avoid index out of bound (full validation occurs in the interpreter)
if len(args) != 3 {
return newError(cmd.SourceLocation, "failed to parse SET args")
}

key := args[0]
baseVal := args[2]
val, err := l.expandArgs(ctx, baseVal)
if err != nil {
return wrapError(err, cmd.SourceLocation, "failed to expand SET value %q", baseVal)
}

l.hasher.HashString(fmt.Sprintf("SET %s=%s", key, val))

err = l.varCollection.UpdateVar(key, val, nil)
if err != nil {
if err != nil {
return wrapError(err, cmd.SourceLocation, "failed to declare variable")
}
}
return nil
}

func (l *loader) handleWith(ctx context.Context, with spec.WithStatement) error {
if with.Command.Name != command.Docker {
return newError(with.Command.SourceLocation, "expected WITH DOCKER")
Expand Down
42 changes: 41 additions & 1 deletion tests/autoskip/Earthfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION --pass-args --use-function-keyword 0.7
VERSION 0.8

FROM --pass-args ..+base

Expand Down Expand Up @@ -34,6 +34,10 @@ test-all:
BUILD +test-flag-conflict
BUILD +test-init-failure
BUILD +test-arg-change
BUILD +test-expand-let
BUILD +test-copy-target-let
BUILD +test-expand-set
BUILD +test-copy-target-set

test-files:
RUN echo hello > my-file
Expand Down Expand Up @@ -166,6 +170,42 @@ test-arg-matrix:
DO --pass-args +RUN_EARTHLY_ARGS --target=+arg-matrix --output_contains="Hello Sam. From Todd"
DO --pass-args +RUN_EARTHLY_ARGS --target=+arg-matrix --output_contains="Target .* has already been run. Skipping."

test-expand-let:
COPY glob/hello.txt .
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-let.earth --target=+basic --output_contains="COPY hello.txt"
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-let.earth --target=+basic --output_contains="Target .* has already been run. Skipping."

DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-let.earth --target=+dynamic-build --output_contains="dynamic target ok"
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-let.earth --target=+dynamic-build --output_contains="Target .* has already been run. Skipping."

DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-let.earth --target=+dynamic-arg --output_contains="hello bar"
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-let.earth --target=+dynamic-arg --output_contains="Target .* has already been run. Skipping."

test-copy-target-let:
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-let.earth --target=+copy-target-dynamic --output_contains="+copy-target-dynamic | goodbye"
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-let.earth --target=+copy-target-dynamic --output_contains="Target .* has already been run. Skipping."

DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-let.earth --target=+copy-target-dynamic-2 --output_contains="+copy-target-dynamic-2 | foobar"
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-let.earth --target=+copy-target-dynamic-2 --output_contains="Target .* has already been run. Skipping."

test-expand-set:
COPY glob/hello.txt .
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-set.earth --target=+basic --output_contains="COPY hello.txt"
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-set.earth --target=+basic --output_contains="Target .* has already been run. Skipping."

DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-set.earth --target=+dynamic-build --output_contains="dynamic target ok"
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-set.earth --target=+dynamic-build --output_contains="Target .* has already been run. Skipping."

DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-set.earth --target=+dynamic-arg --output_contains="hello bar"
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-set.earth --target=+dynamic-arg --output_contains="Target .* has already been run. Skipping."

test-copy-target-set:
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-set.earth --target=+copy-target-dynamic --output_contains="+copy-target-dynamic | goodbye"
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-set.earth --target=+copy-target-dynamic --output_contains="Target .* has already been run. Skipping."

DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-set.earth --target=+copy-target-dynamic-2 --output_contains="+copy-target-dynamic-2 | foobar"
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=expand-set.earth --target=+copy-target-dynamic-2 --output_contains="Target .* has already been run. Skipping."

test-try-catch:
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=try-catch.earth --target=+basic --output_contains="Artifact +basic/hello.txt output as hello.txt"
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=try-catch.earth --target=+basic --output_contains="Target .* has already been run. Skipping."
Expand Down
41 changes: 41 additions & 0 deletions tests/autoskip/expand-let.earth
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
VERSION 0.8

PROJECT earthly-technologies/core

FROM alpine

foo:
RUN echo "dynamic target ok"

basic:
LET ext=txt
COPY hello.$ext /tmp
RUN ls -l /tmp

dynamic-build:
LET target=+foo
BUILD $target

dynamic-arg:
LET foo=bar
ARG baz=$foo
RUN echo "hello $baz"

copy-target:
ARG foo
RUN echo $foo > x
SAVE ARTIFACT x

copy-target-2:
RUN echo "foobar" > x
SAVE ARTIFACT x

copy-target-dynamic:
LET name="+copy-target"
COPY ($name/x --foo=goodbye) .
RUN cat x

copy-target-dynamic-2:
LET name="+copy-target-2"
COPY $name/x .
RUN cat x
46 changes: 46 additions & 0 deletions tests/autoskip/expand-set.earth
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
VERSION 0.8

PROJECT earthly-technologies/core

FROM alpine

foo:
RUN echo "dynamic target ok"

basic:
LET ext=""
SET ext=txt
COPY hello.$ext /tmp
RUN ls -l /tmp

dynamic-build:
LET target=""
SET target=+foo
BUILD $target

dynamic-arg:
LET foo=""
SET foo=bar
ARG baz=$foo
RUN echo "hello $baz"

copy-target:
ARG foo
RUN echo $foo > x
SAVE ARTIFACT x

copy-target-2:
RUN echo "foobar" > x
SAVE ARTIFACT x

copy-target-dynamic:
LET name=""
SET name="+copy-target"
COPY ($name/x --foo=goodbye) .
RUN cat x

copy-target-dynamic-2:
LET name=""
SET name="+copy-target-2"
COPY $name/x .
RUN cat x
7 changes: 4 additions & 3 deletions tests/wildcard-copy.earth
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,10 @@ wildcard-multi-with-flags:
RUN test -f somedir1/somefile1

wildcard-if-exists:
#COPY --if-exists ./wildcard/*+test/non-existing .
#DO +TEST --EXPECTED_COUNT=0
#RUN ! test -e non-existing
COPY --if-exists ./wildcard/*+test/non-existing .
DO +TEST --EXPECTED_COUNT=0
RUN ! test -e non-existing

COPY --if-exists ./wildcard/f*+test/helloworld* .
DO +TEST --EXPECTED_COUNT=1

Expand Down

0 comments on commit 35e384f

Please sign in to comment.