diff --git a/internal/artifact/artifact.go b/internal/artifact/artifact.go index abd4ee687..f7a4e980a 100644 --- a/internal/artifact/artifact.go +++ b/internal/artifact/artifact.go @@ -24,7 +24,9 @@ const ( Binary // LinuxPackage is a linux package generated by nfpm or snapcraft LinuxPackage - // DockerImage is a docker image + // PublishableDockerImage is a Docker image yet to be published + PublishableDockerImage + // DockerImage is a published Docker image DockerImage // Checksum is a checksums file Checksum @@ -37,13 +39,13 @@ func (t Type) String() string { case UploadableArchive: return "Archive" case UploadableBinary: - return "Binary" case Binary: return "Binary" case LinuxPackage: - return "LinuxPackage" + return "Linux Package" case DockerImage: - return "DockerImage" + case PublishableDockerImage: + return "Docker Image" case Checksum: return "Checksum" case Signature: diff --git a/internal/pipe/docker/docker.go b/internal/pipe/docker/docker.go index 9e0221213..104db751e 100644 --- a/internal/pipe/docker/docker.go +++ b/internal/pipe/docker/docker.go @@ -10,8 +10,6 @@ import ( "strings" "github.com/apex/log" - "github.com/pkg/errors" - "github.com/goreleaser/goreleaser/internal/artifact" "github.com/goreleaser/goreleaser/internal/deprecate" "github.com/goreleaser/goreleaser/internal/pipe" @@ -19,6 +17,7 @@ import ( "github.com/goreleaser/goreleaser/internal/tmpl" "github.com/goreleaser/goreleaser/pkg/config" "github.com/goreleaser/goreleaser/pkg/context" + "github.com/pkg/errors" ) // ErrNoDocker is shown when docker cannot be found in $PATH @@ -78,6 +77,17 @@ func (Pipe) Run(ctx *context.Context) error { return doRun(ctx) } +// Publish the docker images +func (Pipe) Publish(ctx *context.Context) error { + var images = ctx.Artifacts.Filter(artifact.ByType(artifact.PublishableDockerImage)).List() + for _, image := range images { + if err := dockerPush(ctx, image); err != nil { + return err + } + } + return nil +} + func missingImage(ctx *context.Context) bool { return ctx.Config.Dockers[0].Image == "" && len(ctx.Config.Dockers[0].ImageTemplates) == 0 } @@ -112,14 +122,14 @@ func doRun(ctx *context.Context) error { return g.Wait() } -func process(ctx *context.Context, docker config.Docker, artifact artifact.Artifact) error { +func process(ctx *context.Context, docker config.Docker, bin artifact.Artifact) error { tmp, err := ioutil.TempDir(ctx.Config.Dist, "goreleaserdocker") if err != nil { return errors.Wrap(err, "failed to create temporary dir") } log.Debug("tempdir: " + tmp) - images, err := processImageTemplates(ctx, docker, artifact) + images, err := processImageTemplates(ctx, docker, bin) if err != nil { return err } @@ -132,11 +142,11 @@ func process(ctx *context.Context, docker config.Docker, artifact artifact.Artif return errors.Wrapf(err, "failed to link extra file '%s'", file) } } - if err := os.Link(artifact.Path, filepath.Join(tmp, filepath.Base(artifact.Path))); err != nil { + if err := os.Link(bin.Path, filepath.Join(tmp, filepath.Base(bin.Path))); err != nil { return errors.Wrap(err, "failed to link binary") } - buildFlags, err := processBuildFlagTemplates(ctx, docker, artifact) + buildFlags, err := processBuildFlagTemplates(ctx, docker, bin) if err != nil { return err } @@ -149,7 +159,22 @@ func process(ctx *context.Context, docker config.Docker, artifact artifact.Artif return err } } - return publish(ctx, docker, images) + if docker.SkipPush { + // TODO: this should also be better handled + log.Warn(pipe.Skip("skip_push is set").Error()) + return nil + } + for _, img := range images { + ctx.Artifacts.Add(artifact.Artifact{ + Type: artifact.PublishableDockerImage, + Name: img, + Path: img, + Goarch: docker.Goarch, + Goos: docker.Goos, + Goarm: docker.Goarm, + }) + } + return nil } func processImageTemplates(ctx *context.Context, docker config.Docker, artifact artifact.Artifact) ([]string, error) { @@ -224,25 +249,6 @@ func link(src, dest string) error { }) } -func publish(ctx *context.Context, docker config.Docker, images []string) error { - if ctx.SkipPublish { - // TODO: this should be better handled - log.Warn(pipe.ErrSkipPublishEnabled.Error()) - return nil - } - if docker.SkipPush { - // TODO: this should also be better handled - log.Warn(pipe.Skip("skip_push is set").Error()) - return nil - } - for _, image := range images { - if err := dockerPush(ctx, docker, image); err != nil { - return err - } - } - return nil -} - func dockerBuild(ctx *context.Context, root, image string, flags []string) error { log.WithField("image", image).Info("building docker image") /* #nosec */ @@ -276,23 +282,17 @@ func dockerTag(ctx *context.Context, image, tag string) error { return nil } -func dockerPush(ctx *context.Context, docker config.Docker, image string) error { +func dockerPush(ctx *context.Context, image artifact.Artifact) error { log.WithField("image", image).Info("pushing docker image") /* #nosec */ - var cmd = exec.CommandContext(ctx, "docker", "push", image) + var cmd = exec.CommandContext(ctx, "docker", "push", image.Name) log.WithField("cmd", cmd.Args).Debug("running") out, err := cmd.CombinedOutput() if err != nil { return errors.Wrapf(err, "failed to push docker image: \n%s", string(out)) } log.Debugf("docker push output: \n%s", string(out)) - ctx.Artifacts.Add(artifact.Artifact{ - Type: artifact.DockerImage, - Name: image, - Path: image, - Goarch: docker.Goarch, - Goos: docker.Goos, - Goarm: docker.Goarm, - }) + image.Type = artifact.DockerImage + ctx.Artifacts.Add(image) return nil } diff --git a/internal/pipe/docker/docker_test.go b/internal/pipe/docker/docker_test.go index a240c6d0f..df18b8eb1 100644 --- a/internal/pipe/docker/docker_test.go +++ b/internal/pipe/docker/docker_test.go @@ -92,6 +92,7 @@ func TestRunPipe(t *testing.T) { expect []string assertImageLabels imageLabelFinder assertError errChecker + pubAssertError errChecker }{ "valid": { publish: true, @@ -147,7 +148,8 @@ func TestRunPipe(t *testing.T) { "label=org.label-schema.version=1.0.0", "label=org.label-schema.vcs-ref=a1b2c3d4", "label=org.label-schema.name=mybin"), - assertError: shouldNotErr, + assertError: shouldNotErr, + pubAssertError: shouldNotErr, }, "with deprecated image name & tag templates": { publish: true, @@ -173,7 +175,8 @@ func TestRunPipe(t *testing.T) { "goreleaser/test_run_pipe", "label=org.label-schema.version=1.0.0", ), - assertError: shouldNotErr, + assertError: shouldNotErr, + pubAssertError: shouldNotErr, }, "multiple images with same extra file": { publish: true, @@ -203,6 +206,7 @@ func TestRunPipe(t *testing.T) { }, assertImageLabels: noLabels, assertError: shouldNotErr, + pubAssertError: shouldNotErr, }, "multiple images with same dockerfile": { publish: true, @@ -229,7 +233,8 @@ func TestRunPipe(t *testing.T) { registry + "goreleaser/test_run_pipe:latest", registry + "goreleaser/test_run_pipe2:latest", }, - assertError: shouldNotErr, + assertError: shouldNotErr, + pubAssertError: shouldNotErr, }, "valid_skip_push": { publish: true, @@ -249,6 +254,7 @@ func TestRunPipe(t *testing.T) { }, assertImageLabels: noLabels, assertError: shouldNotErr, + pubAssertError: shouldNotErr, }, "valid_no_latest": { publish: true, @@ -267,6 +273,7 @@ func TestRunPipe(t *testing.T) { }, assertImageLabels: noLabels, assertError: shouldNotErr, + pubAssertError: shouldNotErr, }, "valid_dont_publish": { publish: false, @@ -285,6 +292,7 @@ func TestRunPipe(t *testing.T) { }, assertImageLabels: noLabels, assertError: shouldNotErr, + pubAssertError: shouldNotErr, }, "valid build args": { publish: false, @@ -306,6 +314,7 @@ func TestRunPipe(t *testing.T) { }, assertImageLabels: noLabels, assertError: shouldNotErr, + pubAssertError: shouldNotErr, }, "bad build args": { publish: false, @@ -432,6 +441,7 @@ func TestRunPipe(t *testing.T) { }, assertImageLabels: noLabels, assertError: shouldNotErr, + pubAssertError: shouldNotErr, }, "no_permissions": { publish: true, @@ -449,7 +459,8 @@ func TestRunPipe(t *testing.T) { "docker.io/nope:latest", }, assertImageLabels: noLabels, - assertError: shouldErr(`requested access to the resource is denied`), + assertError: shouldNotErr, + pubAssertError: shouldErr(`requested access to the resource is denied`), }, "dockerfile_doesnt_exist": { publish: true, @@ -524,7 +535,7 @@ func TestRunPipe(t *testing.T) { for name, docker := range table { t.Run(name, func(tt *testing.T) { - folder, err := ioutil.TempDir("", "archivetest") + folder, err := ioutil.TempDir("", "dockertest") require.NoError(tt, err) var dist = filepath.Join(folder, "dist") require.NoError(tt, os.Mkdir(dist, 0755)) @@ -567,7 +578,11 @@ func TestRunPipe(t *testing.T) { _ = exec.Command("docker", "rmi", img).Run() } - docker.assertError(tt, Pipe{}.Run(ctx)) + err = Pipe{}.Run(ctx) + docker.assertError(tt, err) + if err == nil { + docker.pubAssertError(tt, Pipe{}.Publish(ctx)) + } for _, d := range docker.dockers { if d.ImageTemplates == nil { diff --git a/internal/pipe/publish/publish.go b/internal/pipe/publish/publish.go index 6eed83093..38206e7ad 100644 --- a/internal/pipe/publish/publish.go +++ b/internal/pipe/publish/publish.go @@ -9,6 +9,7 @@ import ( "github.com/goreleaser/goreleaser/internal/pipe" "github.com/goreleaser/goreleaser/internal/pipe/artifactory" "github.com/goreleaser/goreleaser/internal/pipe/brew" + "github.com/goreleaser/goreleaser/internal/pipe/docker" "github.com/goreleaser/goreleaser/internal/pipe/put" "github.com/goreleaser/goreleaser/internal/pipe/release" "github.com/goreleaser/goreleaser/internal/pipe/s3" @@ -39,6 +40,7 @@ var publishers = []Publisher{ release.Pipe{}, brew.Pipe{}, scoop.Pipe{}, + docker.Pipe{}, } var bold = color.New(color.Bold)