Skip to content

Commit

Permalink
Auto-skip: further support for shell-out (#3496)
Browse files Browse the repository at this point in the history
Allows targets that use shell-out features to be auto-skipped unless the
target name is to be dynamically resolved using the result of a
shell-out command.

---------

Co-authored-by: Alex Couture-Beil <[email protected]>
  • Loading branch information
mikejholly and alexcb authored Nov 16, 2023
1 parent 42a37be commit 2e58c8c
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 11 deletions.
34 changes: 23 additions & 11 deletions inputgraph/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,16 @@ func (l *loader) handleCopy(ctx context.Context, cmd spec.Command) error {
return nil
}

func hasShellExpr(s string) bool {
return strings.Contains(s, "$(") && strings.Contains(s, ")")
}

func (l *loader) handleCopySrc(ctx context.Context, src string, isDir bool) error {

if hasShellExpr(src) {
return errors.Errorf("dynamic COPY source %q cannot be resolved", src)
}

var (
classical bool
artifactSrc domain.Artifact
Expand Down Expand Up @@ -218,18 +226,16 @@ func (l *loader) expandDirs(dirs ...string) ([]string, error) {
if err != nil {
return nil, errors.Wrap(err, "failed to read dir")
}
children := []string{}
for _, entry := range entries {
next := filepath.Join(dir, entry.Name())
if entry.IsDir() {
found, err := l.expandDirs(next)
if err != nil {
return nil, err
}
ret = append(ret, found...)
} else {
ret = append(ret, next)
}
child := filepath.Join(dir, entry.Name())
children = append(children, child)
}
found, err := l.expandDirs(children...)
if err != nil {
return nil, err
}
ret = append(ret, found...)
} else {
ret = append(ret, dir)
}
Expand All @@ -241,7 +247,7 @@ func (l *loader) expandArgs(ctx context.Context, args []string) ([]string, error
ret := []string{}
for _, arg := range args {
expanded, err := l.varCollection.Expand(arg, func(cmd string) (string, error) {
return "", errors.New("shell-out is not supported")
return arg, nil // Return the original expression so it can be referenced later.
})
if err != nil {
return nil, err
Expand Down Expand Up @@ -498,6 +504,12 @@ func (l *loader) forTarget(ctx context.Context, target domain.Target, args []str
}

func (l *loader) loadTargetFromString(ctx context.Context, targetName string, args []string, passArgs bool) error {
// If the target name contains a variable that hasn't been expanded, we
// won't be able to explore the rest of the graph and generate a valid hash.
if hasShellExpr(targetName) {
return errors.Errorf("dynamic target %q cannot be resolved", targetName)
}

relTarget, err := domain.ParseTarget(targetName)
if err != nil {
return errors.Wrapf(err, "parse target name %s", targetName)
Expand Down
16 changes: 16 additions & 0 deletions tests/autoskip/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ test-all:
BUILD +test-try-catch
BUILD +test-push
BUILD +test-no-cache
BUILD +test-shell-out

test-files:
RUN echo hello > my-file
Expand Down Expand Up @@ -147,6 +148,21 @@ test-push:
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=simple.earth --target=+simple --should_fail=true --extra_args="--push" --output_contains="push cannot be used"
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=simple.earth --target=+simple --should_fail=true --extra_args="--push" --output_does_not_contain="target .* has already been run; exiting"

test-shell-out:
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=shell-out.earth --target=+shell-out
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=shell-out.earth --target=+shell-out --output_contains="target .* has already been run; exiting"

DO --pass-args +RUN_EARTHLY_ARGS --earthfile=shell-out.earth --target=+shell-out-target --output_contains="dynamic target"
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=shell-out.earth --target=+shell-out-target --output_does_not_contain="target .* has already been run; exiting"

DO --pass-args +RUN_EARTHLY_ARGS --earthfile=shell-out.earth --target=+shell-out-target-2 --output_contains="dynamic target"
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=shell-out.earth --target=+shell-out-target-2 --output_does_not_contain="target .* has already been run; exiting"

RUN echo "foo" > my-file

DO --pass-args +RUN_EARTHLY_ARGS --earthfile=shell-out.earth --target=+shell-out-copy --output_contains="dynamic COPY source"
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=shell-out.earth --target=+shell-out-copy --output_does_not_contain="target .* has already been run; exiting"

RUN_EARTHLY_ARGS:
COMMAND
ARG earthfile
Expand Down
25 changes: 25 additions & 0 deletions tests/autoskip/shell-out.earth
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
VERSION 0.7

PROJECT testorg/testproj

FROM alpine:3.18

shell-out:
ARG result=$(echo "hi")
RUN echo $result

foo:
RUN echo "hello from foo"

shell-out-target:
ARG target=$(echo "+foo")
BUILD $target

shell-out-target-2:
ARG name="+foo"
ARG target=$(echo $name)
BUILD $target

shell-out-copy:
ARG file=$(echo "my-file")
COPY $file .

0 comments on commit 2e58c8c

Please sign in to comment.