Skip to content

Commit

Permalink
feat: SAVE IMAGE --without-earthly-labels (#4084)
Browse files Browse the repository at this point in the history
This commit adds the `--without-earthly-labels` for the SAVE IMAGE
instruction to not modify the digest of the final artifact if none of
its contents changes. Enabled `--allow-without-earthly-labels` feature.

Certain custom registries may require strict checking of the image
contents, so this option disables build information.

---------

Co-authored-by: Alex Couture-Beil <[email protected]>
  • Loading branch information
3manuek and alexcb committed May 6, 2024
1 parent e640ac4 commit eafa608
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 13 deletions.
11 changes: 6 additions & 5 deletions ast/commandflag/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,12 @@ type SaveArtifactOpts struct {
}

type SaveImageOpts struct {
Push bool `long:"push" description:"Push the image to the remote registry provided that the build succeeds and also that earthly is invoked in push mode"`
CacheHint bool `long:"cache-hint" description:"Instruct Earthly that the current target should be saved entirely as part of the remote cache"`
Insecure bool `long:"insecure" description:"Use unencrypted connection for the push"`
NoManifestList bool `long:"no-manifest-list" description:"Do not include a manifest list (specifying the platform) in the creation of the image"`
CacheFrom []string `long:"cache-from" description:"Declare additional cache import as a Docker tag"`
Push bool `long:"push" description:"Push the image to the remote registry provided that the build succeeds and also that earthly is invoked in push mode"`
CacheHint bool `long:"cache-hint" description:"Instruct Earthly that the current target should be saved entirely as part of the remote cache"`
Insecure bool `long:"insecure" description:"Use unencrypted connection for the push"`
NoManifestList bool `long:"no-manifest-list" description:"Do not include a manifest list (specifying the platform) in the creation of the image"`
CacheFrom []string `long:"cache-from" description:"Declare additional cache import as a Docker tag"`
WithoutEarthlyLabels bool `long:"without-earthly-labels" description:"Disable build information dev.earthly labels to reduce the chance of changing images digests."`
}

type BuildOpts struct {
Expand Down
23 changes: 15 additions & 8 deletions earthfile2llb/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -1171,14 +1171,21 @@ func (i *Interpreter) handleSaveImage(ctx context.Context, cmd spec.Command) err
return nil
}

labels := map[string]string{
"dev.earthly.version": version.Version,
"dev.earthly.git-sha": version.GitSha,
"dev.earthly.built-by": version.BuiltBy,
}
err = i.converter.Label(ctx, labels)
if err != nil {
return i.wrapError(err, cmd.SourceLocation, "failed to create dev.earthly.* labels during SAVE IMAGE")
if opts.WithoutEarthlyLabels {
if !i.converter.ftrs.AllowWithoutEarthlyLabels {
return i.errorf(cmd.SourceLocation, "the SAVE IMAGE --without-earthly-labels flag must be enabled with the VERSION --allow-without-earthly-labels feature flag.")
}
// deliberately don't add any labels (i.e. do nothing here)
} else {
labels := map[string]string{
"dev.earthly.version": version.Version,
"dev.earthly.git-sha": version.GitSha,
"dev.earthly.built-by": version.BuiltBy,
}
err = i.converter.Label(ctx, labels)
if err != nil {
return i.wrapError(err, cmd.SourceLocation, "failed to create dev.earthly.* labels during SAVE IMAGE")
}
}

err = i.converter.SaveImage(ctx, imageNames, opts.Push, opts.Insecure, opts.CacheHint, opts.CacheFrom, opts.NoManifestList)
Expand Down
1 change: 1 addition & 0 deletions features/features.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ type Features struct {
WildcardCopy bool `long:"wildcard-copy" description:"allow for the expansion of wildcard (glob) paths for COPY commands"`
RawOutput bool `long:"raw-output" description:"allow for --raw-output on RUN commands"`
GitAuthorEmailNameArgs bool `long:"git-author-email-name-args" description:"includes EARTHLY_GIT_AUTHOR_EMAIL and EARTHLY_GIT_AUTHOR_NAME builtin ARGs"`
AllowWithoutEarthlyLabels bool `long:"allow-without-earthly-labels" description:"Allow the usage of --without-earthly-labels in SAVE IMAGE"`
DockerCache bool `long:"docker-cache" description:"enable the WITH DOCKER --cache-id option"`

// version numbers
Expand Down
1 change: 1 addition & 0 deletions tests/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ ga-no-qemu-group11:

ga-no-qemu-group12:
BUILD --pass-args ./warn-if-not-logged-in+test
BUILD --pass-args ./with-docker-validate-labels+all


ga-no-qemu-slow:
Expand Down
31 changes: 31 additions & 0 deletions tests/with-docker-validate-labels/Earthfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Test for --without-earthly-labels feature
VERSION --allow-without-earthly-labels 0.8

ARG --global DIND_IMAGE="earthly/dind:ubuntu-23.04-docker-25.0.2-1"

all:
BUILD +test-without-labels
BUILD +test-with-labels

myimage-without-labels:
FROM alpine
COPY file /
SAVE IMAGE --without-earthly-labels myimage:test

myimage-with-labels:
FROM alpine
COPY file /
SAVE IMAGE myimage:test

test-without-labels:
FROM $DIND_IMAGE
WITH DOCKER --load=+myimage-without-labels
RUN docker inspect myimage:test | jq -r '.[].Config.Labels' | grep -q null
END

test-with-labels:
FROM $DIND_IMAGE
WITH DOCKER --load=+myimage-with-labels
# We just test that fields aren't null.
RUN docker inspect myimage:test | jq -e '.[].Config.Labels' > /dev/null
END
1 change: 1 addition & 0 deletions tests/with-docker-validate-labels/file
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Almost empty file

0 comments on commit eafa608

Please sign in to comment.