2017-09-12 04:31:00 +02:00
|
|
|
package docker
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2023-04-09 02:06:04 +02:00
|
|
|
"io/fs"
|
2023-09-01 16:16:16 +02:00
|
|
|
"net/http"
|
2017-09-12 12:54:43 +02:00
|
|
|
"os"
|
2017-09-12 04:31:00 +02:00
|
|
|
"path/filepath"
|
2021-06-27 22:55:00 +02:00
|
|
|
"sort"
|
2017-12-24 14:12:51 +02:00
|
|
|
"strings"
|
2023-09-01 16:16:16 +02:00
|
|
|
"time"
|
2017-09-12 04:31:00 +02:00
|
|
|
|
2022-06-22 02:11:15 +02:00
|
|
|
"github.com/caarlos0/log"
|
2017-12-18 03:11:17 +02:00
|
|
|
"github.com/goreleaser/goreleaser/internal/artifact"
|
2021-07-25 00:59:43 +02:00
|
|
|
"github.com/goreleaser/goreleaser/internal/gio"
|
2021-08-17 03:11:54 +02:00
|
|
|
"github.com/goreleaser/goreleaser/internal/ids"
|
2018-09-12 19:18:01 +02:00
|
|
|
"github.com/goreleaser/goreleaser/internal/pipe"
|
2018-07-10 06:38:00 +02:00
|
|
|
"github.com/goreleaser/goreleaser/internal/semerrgroup"
|
2023-09-16 22:01:20 +02:00
|
|
|
"github.com/goreleaser/goreleaser/internal/skips"
|
2018-07-09 06:05:18 +02:00
|
|
|
"github.com/goreleaser/goreleaser/internal/tmpl"
|
2018-08-15 04:50:20 +02:00
|
|
|
"github.com/goreleaser/goreleaser/pkg/config"
|
|
|
|
"github.com/goreleaser/goreleaser/pkg/context"
|
2017-09-12 04:31:00 +02:00
|
|
|
)
|
|
|
|
|
2021-06-26 21:36:31 +02:00
|
|
|
const (
|
|
|
|
dockerConfigExtra = "DockerConfig"
|
|
|
|
|
2022-10-05 14:42:05 +02:00
|
|
|
useBuildx = "buildx"
|
|
|
|
useDocker = "docker"
|
2021-06-26 21:36:31 +02:00
|
|
|
)
|
|
|
|
|
2020-05-26 05:48:10 +02:00
|
|
|
// Pipe for docker.
|
2017-09-12 04:31:00 +02:00
|
|
|
type Pipe struct{}
|
|
|
|
|
2023-09-16 22:01:20 +02:00
|
|
|
func (Pipe) String() string { return "docker images" }
|
|
|
|
|
|
|
|
func (Pipe) Skip(ctx *context.Context) bool {
|
|
|
|
return len(ctx.Config.Dockers) == 0 || skips.Any(ctx, skips.Docker)
|
|
|
|
}
|
2017-09-12 04:31:00 +02:00
|
|
|
|
2023-03-03 14:50:15 +02:00
|
|
|
func (Pipe) Dependencies(ctx *context.Context) []string {
|
|
|
|
var cmds []string
|
|
|
|
for _, s := range ctx.Config.Dockers {
|
|
|
|
switch s.Use {
|
|
|
|
case useDocker, useBuildx:
|
|
|
|
cmds = append(cmds, "docker")
|
|
|
|
// TODO: how to check if buildx is installed
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return cmds
|
|
|
|
}
|
|
|
|
|
2020-05-26 05:48:10 +02:00
|
|
|
// Default sets the pipe defaults.
|
2017-12-02 23:53:19 +02:00
|
|
|
func (Pipe) Default(ctx *context.Context) error {
|
2021-08-17 03:11:54 +02:00
|
|
|
ids := ids.New("dockers")
|
2017-12-05 15:19:44 +02:00
|
|
|
for i := range ctx.Config.Dockers {
|
2021-04-19 14:31:57 +02:00
|
|
|
docker := &ctx.Config.Dockers[i]
|
2018-10-20 15:09:55 +02:00
|
|
|
|
2021-08-17 03:11:54 +02:00
|
|
|
if docker.ID != "" {
|
|
|
|
ids.Inc(docker.ID)
|
|
|
|
}
|
2017-12-17 22:10:38 +02:00
|
|
|
if docker.Goos == "" {
|
|
|
|
docker.Goos = "linux"
|
|
|
|
}
|
|
|
|
if docker.Goarch == "" {
|
|
|
|
docker.Goarch = "amd64"
|
2017-12-05 15:19:44 +02:00
|
|
|
}
|
2022-11-14 18:59:01 +02:00
|
|
|
if docker.Goarm == "" {
|
|
|
|
docker.Goarm = "6"
|
|
|
|
}
|
2022-04-12 03:43:22 +02:00
|
|
|
if docker.Goamd64 == "" {
|
2022-04-14 02:29:39 +02:00
|
|
|
docker.Goamd64 = "v1"
|
2022-04-12 03:43:22 +02:00
|
|
|
}
|
2020-11-25 00:41:40 +02:00
|
|
|
if docker.Dockerfile == "" {
|
|
|
|
docker.Dockerfile = "Dockerfile"
|
|
|
|
}
|
2021-06-26 21:36:31 +02:00
|
|
|
if docker.Use == "" {
|
|
|
|
docker.Use = useDocker
|
|
|
|
}
|
2021-06-27 22:55:00 +02:00
|
|
|
if err := validateImager(docker.Use); err != nil {
|
|
|
|
return err
|
2021-06-26 21:36:31 +02:00
|
|
|
}
|
2017-12-05 15:19:44 +02:00
|
|
|
}
|
2021-08-17 03:11:54 +02:00
|
|
|
return ids.Validate()
|
2017-12-02 23:53:19 +02:00
|
|
|
}
|
|
|
|
|
2021-06-27 22:55:00 +02:00
|
|
|
func validateImager(use string) error {
|
|
|
|
valid := make([]string, 0, len(imagers))
|
|
|
|
for k := range imagers {
|
|
|
|
valid = append(valid, k)
|
|
|
|
}
|
|
|
|
for _, s := range valid {
|
2021-06-26 21:36:31 +02:00
|
|
|
if s == use {
|
2021-06-27 22:55:00 +02:00
|
|
|
return nil
|
2021-06-26 21:36:31 +02:00
|
|
|
}
|
|
|
|
}
|
2021-06-27 22:55:00 +02:00
|
|
|
sort.Strings(valid)
|
|
|
|
return fmt.Errorf("docker: invalid use: %s, valid options are %v", use, valid)
|
2021-06-26 21:36:31 +02:00
|
|
|
}
|
|
|
|
|
2020-05-26 05:48:10 +02:00
|
|
|
// Publish the docker images.
|
2018-10-20 18:45:31 +02:00
|
|
|
func (Pipe) Publish(ctx *context.Context) error {
|
2022-06-23 13:49:33 +02:00
|
|
|
skips := pipe.SkipMemento{}
|
2021-04-19 14:31:57 +02:00
|
|
|
images := ctx.Artifacts.Filter(artifact.ByType(artifact.PublishableDockerImage)).List()
|
2018-10-20 18:45:31 +02:00
|
|
|
for _, image := range images {
|
|
|
|
if err := dockerPush(ctx, image); err != nil {
|
2022-06-23 13:49:33 +02:00
|
|
|
if pipe.IsSkip(err) {
|
|
|
|
skips.Remember(err)
|
|
|
|
continue
|
|
|
|
}
|
2018-10-20 18:45:31 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2022-06-23 13:49:33 +02:00
|
|
|
return skips.Evaluate()
|
2018-10-20 18:45:31 +02:00
|
|
|
}
|
|
|
|
|
2021-09-18 15:21:29 +02:00
|
|
|
// Run the pipe.
|
|
|
|
func (Pipe) Run(ctx *context.Context) error {
|
2021-04-19 14:31:57 +02:00
|
|
|
g := semerrgroup.NewSkipAware(semerrgroup.New(ctx.Parallelism))
|
2022-11-14 19:49:49 +02:00
|
|
|
for i, docker := range ctx.Config.Dockers {
|
|
|
|
i := i
|
2017-12-26 03:27:06 +02:00
|
|
|
docker := docker
|
|
|
|
g.Go(func() error {
|
2022-11-14 19:49:49 +02:00
|
|
|
log := log.WithField("index", i)
|
|
|
|
log.Debug("looking for artifacts matching")
|
2021-04-19 14:31:57 +02:00
|
|
|
filters := []artifact.Filter{
|
2019-12-27 16:55:03 +02:00
|
|
|
artifact.ByGoos(docker.Goos),
|
|
|
|
artifact.ByGoarch(docker.Goarch),
|
2021-01-07 21:21:12 +02:00
|
|
|
artifact.Or(
|
|
|
|
artifact.ByType(artifact.Binary),
|
|
|
|
artifact.ByType(artifact.LinuxPackage),
|
|
|
|
),
|
2019-12-27 16:55:03 +02:00
|
|
|
}
|
2022-04-12 03:43:22 +02:00
|
|
|
// TODO: properly test this
|
|
|
|
switch docker.Goarch {
|
|
|
|
case "amd64":
|
|
|
|
filters = append(filters, artifact.ByGoamd64(docker.Goamd64))
|
|
|
|
case "arm":
|
|
|
|
filters = append(filters, artifact.ByGoarm(docker.Goarm))
|
|
|
|
}
|
2021-01-07 21:21:12 +02:00
|
|
|
if len(docker.IDs) > 0 {
|
|
|
|
filters = append(filters, artifact.ByIDs(docker.IDs...))
|
2017-09-12 04:31:00 +02:00
|
|
|
}
|
2021-04-19 14:31:57 +02:00
|
|
|
artifacts := ctx.Artifacts.Filter(artifact.And(filters...))
|
2021-01-07 21:21:12 +02:00
|
|
|
log.WithField("artifacts", artifacts.Paths()).Debug("found artifacts")
|
|
|
|
return process(ctx, docker, artifacts.List())
|
2017-12-26 03:27:06 +02:00
|
|
|
})
|
2017-09-12 04:31:00 +02:00
|
|
|
}
|
2022-05-03 03:05:42 +02:00
|
|
|
if err := g.Wait(); err != nil {
|
2022-05-12 19:44:09 +02:00
|
|
|
if pipe.IsSkip(err) {
|
|
|
|
return err
|
|
|
|
}
|
2022-05-03 03:05:42 +02:00
|
|
|
return fmt.Errorf("docker build failed: %w\nLearn more at https://goreleaser.com/errors/docker-build\n", err) // nolint:revive
|
|
|
|
}
|
|
|
|
return nil
|
2017-09-12 04:31:00 +02:00
|
|
|
}
|
|
|
|
|
2021-01-07 21:21:12 +02:00
|
|
|
func process(ctx *context.Context, docker config.Docker, artifacts []*artifact.Artifact) error {
|
2022-12-01 03:47:53 +02:00
|
|
|
if len(artifacts) == 0 {
|
2023-09-07 20:35:32 +02:00
|
|
|
log.Warn("no binaries or packages found for the given platform - COPY/ADD may not work")
|
2022-12-01 03:47:53 +02:00
|
|
|
}
|
2023-03-03 02:01:33 +02:00
|
|
|
tmp, err := os.MkdirTemp("", "goreleaserdocker")
|
2018-08-20 23:58:56 +02:00
|
|
|
if err != nil {
|
2020-09-21 19:47:51 +02:00
|
|
|
return fmt.Errorf("failed to create temporary dir: %w", err)
|
2018-08-20 23:58:56 +02:00
|
|
|
}
|
2023-07-11 19:12:21 +02:00
|
|
|
defer os.RemoveAll(tmp)
|
2018-10-03 14:58:02 +02:00
|
|
|
|
2019-01-11 20:27:39 +02:00
|
|
|
images, err := processImageTemplates(ctx, docker)
|
2018-10-03 14:58:02 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2017-12-05 15:19:44 +02:00
|
|
|
}
|
2018-10-03 14:58:02 +02:00
|
|
|
|
2021-09-18 15:21:29 +02:00
|
|
|
if len(images) == 0 {
|
|
|
|
return pipe.Skip("no image templates found")
|
|
|
|
}
|
|
|
|
|
2021-07-04 03:52:59 +02:00
|
|
|
log := log.WithField("image", images[0])
|
|
|
|
log.Debug("tempdir: " + tmp)
|
|
|
|
|
2023-07-17 04:31:00 +02:00
|
|
|
if err := tmpl.New(ctx).ApplyAll(
|
|
|
|
&docker.Dockerfile,
|
|
|
|
); err != nil {
|
2022-10-05 16:11:01 +02:00
|
|
|
return err
|
|
|
|
}
|
2023-07-17 04:31:00 +02:00
|
|
|
if err := gio.Copy(
|
|
|
|
docker.Dockerfile,
|
|
|
|
filepath.Join(tmp, "Dockerfile"),
|
|
|
|
); err != nil {
|
2022-10-05 16:11:01 +02:00
|
|
|
return fmt.Errorf("failed to copy dockerfile: %w", err)
|
|
|
|
}
|
|
|
|
|
2017-09-26 00:10:04 +02:00
|
|
|
for _, file := range docker.Files {
|
2021-04-19 14:31:57 +02:00
|
|
|
if err := os.MkdirAll(filepath.Join(tmp, filepath.Dir(file)), 0o755); err != nil {
|
2021-07-25 00:59:43 +02:00
|
|
|
return fmt.Errorf("failed to copy extra file '%s': %w", file, err)
|
2018-12-16 15:11:01 +02:00
|
|
|
}
|
2021-07-25 00:59:43 +02:00
|
|
|
if err := gio.Copy(file, filepath.Join(tmp, file)); err != nil {
|
|
|
|
return fmt.Errorf("failed to copy extra file '%s': %w", file, err)
|
2017-09-26 00:10:04 +02:00
|
|
|
}
|
|
|
|
}
|
2021-01-07 21:21:12 +02:00
|
|
|
for _, art := range artifacts {
|
2023-08-03 14:19:07 +02:00
|
|
|
target := filepath.Join(tmp, art.Name)
|
|
|
|
if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {
|
|
|
|
return fmt.Errorf("failed to make dir for artifact: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := gio.Copy(art.Path, target); err != nil {
|
2021-07-25 00:59:43 +02:00
|
|
|
return fmt.Errorf("failed to copy artifact: %w", err)
|
2019-01-11 20:27:39 +02:00
|
|
|
}
|
2018-08-20 23:58:56 +02:00
|
|
|
}
|
2018-10-03 14:58:02 +02:00
|
|
|
|
2019-01-11 20:27:39 +02:00
|
|
|
buildFlags, err := processBuildFlagTemplates(ctx, docker)
|
2018-10-03 14:58:02 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-07-04 03:52:59 +02:00
|
|
|
log.Info("building docker image")
|
2021-06-27 22:55:00 +02:00
|
|
|
if err := imagers[docker.Use].Build(ctx, tmp, images, buildFlags); err != nil {
|
2023-04-13 18:56:56 +02:00
|
|
|
if isFileNotFoundError(err.Error()) {
|
2023-04-09 02:06:04 +02:00
|
|
|
var files []string
|
2023-06-16 04:51:07 +02:00
|
|
|
_ = filepath.Walk(tmp, func(_ string, info fs.FileInfo, _ error) error {
|
2023-04-09 02:06:04 +02:00
|
|
|
if info.IsDir() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
files = append(files, info.Name())
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return fmt.Errorf(`seems like you tried to copy a file that is not available in the build context.
|
|
|
|
|
|
|
|
Here's more information about the build context:
|
|
|
|
|
|
|
|
dir: %q
|
|
|
|
files in that dir:
|
|
|
|
%s
|
|
|
|
|
|
|
|
Previous error:
|
|
|
|
%w`, tmp, strings.Join(files, "\n "), err)
|
|
|
|
}
|
2023-11-02 23:35:36 +02:00
|
|
|
if isBuildxContextError(err.Error()) {
|
2023-11-04 03:01:17 +02:00
|
|
|
return fmt.Errorf("docker buildx is not set to default context - please switch with 'docker context use default'")
|
2023-11-02 23:35:36 +02:00
|
|
|
}
|
2017-09-12 04:31:00 +02:00
|
|
|
return err
|
|
|
|
}
|
2019-03-06 18:17:53 +02:00
|
|
|
|
2018-10-20 18:45:31 +02:00
|
|
|
for _, img := range images {
|
2019-08-12 22:44:48 +02:00
|
|
|
ctx.Artifacts.Add(&artifact.Artifact{
|
2018-10-20 18:45:31 +02:00
|
|
|
Type: artifact.PublishableDockerImage,
|
|
|
|
Name: img,
|
|
|
|
Path: img,
|
|
|
|
Goarch: docker.Goarch,
|
|
|
|
Goos: docker.Goos,
|
|
|
|
Goarm: docker.Goarm,
|
2021-06-26 21:36:31 +02:00
|
|
|
Extra: map[string]interface{}{
|
|
|
|
dockerConfigExtra: docker,
|
|
|
|
},
|
2018-10-20 18:45:31 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
return nil
|
2017-09-26 23:50:00 +02:00
|
|
|
}
|
|
|
|
|
2023-04-13 18:56:56 +02:00
|
|
|
func isFileNotFoundError(out string) bool {
|
|
|
|
if strings.Contains(out, `executable file not found in $PATH`) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return strings.Contains(out, "file not found") ||
|
2023-08-03 03:57:38 +02:00
|
|
|
strings.Contains(out, ": not found")
|
2023-04-13 18:56:56 +02:00
|
|
|
}
|
|
|
|
|
2023-11-02 23:35:36 +02:00
|
|
|
func isBuildxContextError(out string) bool {
|
2023-11-04 01:43:31 +02:00
|
|
|
return strings.Contains(out, "to switch to context")
|
2023-11-02 23:35:36 +02:00
|
|
|
}
|
|
|
|
|
2019-01-11 20:27:39 +02:00
|
|
|
func processImageTemplates(ctx *context.Context, docker config.Docker) ([]string, error) {
|
2018-10-03 14:58:02 +02:00
|
|
|
// nolint:prealloc
|
|
|
|
var images []string
|
2018-10-20 14:21:52 +02:00
|
|
|
for _, imageTemplate := range docker.ImageTemplates {
|
2019-01-11 20:27:39 +02:00
|
|
|
image, err := tmpl.New(ctx).Apply(imageTemplate)
|
2018-10-20 14:21:52 +02:00
|
|
|
if err != nil {
|
2020-09-21 19:47:51 +02:00
|
|
|
return nil, fmt.Errorf("failed to execute image template '%s': %w", imageTemplate, err)
|
2018-10-20 14:21:52 +02:00
|
|
|
}
|
2020-12-28 22:36:46 +02:00
|
|
|
if image == "" {
|
|
|
|
continue
|
|
|
|
}
|
2018-10-20 14:21:52 +02:00
|
|
|
|
|
|
|
images = append(images, image)
|
|
|
|
}
|
|
|
|
|
2018-10-03 14:58:02 +02:00
|
|
|
return images, nil
|
|
|
|
}
|
|
|
|
|
2019-01-11 20:27:39 +02:00
|
|
|
func processBuildFlagTemplates(ctx *context.Context, docker config.Docker) ([]string, error) {
|
2018-10-03 14:58:02 +02:00
|
|
|
// nolint:prealloc
|
|
|
|
var buildFlags []string
|
|
|
|
for _, buildFlagTemplate := range docker.BuildFlagTemplates {
|
2019-01-11 20:27:39 +02:00
|
|
|
buildFlag, err := tmpl.New(ctx).Apply(buildFlagTemplate)
|
2018-10-03 14:58:02 +02:00
|
|
|
if err != nil {
|
2020-09-21 19:47:51 +02:00
|
|
|
return nil, fmt.Errorf("failed to process build flag template '%s': %w", buildFlagTemplate, err)
|
2018-10-03 14:58:02 +02:00
|
|
|
}
|
|
|
|
buildFlags = append(buildFlags, buildFlag)
|
|
|
|
}
|
|
|
|
return buildFlags, nil
|
|
|
|
}
|
|
|
|
|
2019-08-12 22:44:48 +02:00
|
|
|
func dockerPush(ctx *context.Context, image *artifact.Artifact) error {
|
2021-12-21 04:43:35 +02:00
|
|
|
log.WithField("image", image.Name).Info("pushing")
|
2022-06-23 13:49:33 +02:00
|
|
|
|
2022-06-24 04:36:19 +02:00
|
|
|
docker, err := artifact.Extra[config.Docker](*image, dockerConfigExtra)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-05-12 06:51:02 +02:00
|
|
|
skip, err := tmpl.New(ctx).Apply(docker.SkipPush)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if strings.TrimSpace(skip) == "true" {
|
2022-06-23 13:49:33 +02:00
|
|
|
return pipe.Skip("docker.skip_push is set: " + image.Name)
|
|
|
|
}
|
2023-05-12 06:51:02 +02:00
|
|
|
if strings.TrimSpace(skip) == "auto" && ctx.Semver.Prerelease != "" {
|
2022-06-23 13:49:33 +02:00
|
|
|
return pipe.Skip("prerelease detected with 'auto' push, skipping docker publish: " + image.Name)
|
|
|
|
}
|
|
|
|
|
2023-09-01 16:16:16 +02:00
|
|
|
digest, err := doPush(ctx, imagers[docker.Use], image.Name, docker.PushFlags)
|
feat: add digest to artifacts info of published docker images (#3540)
Extract the digest (sha256) of docker images from the `docker push`
command for dockers published to the docker registry.
Outputting the digest is required to avoid a race condition when
referencing the image, where the image tag is being modified before the
reference is done.
See this [blog
post](https://github.com/goreleaser/goreleaser/issues/3496) for more
info.
This PR fixes https://github.com/goreleaser/goreleaser/issues/3496.
Note that the 'publish' pipe now must run before the 'metadata' pipe, so
that the information extracted during the 'publish' pipe would appear in
the metadata.
Previously, the published docker images metadata wasn't printed (because
of the order). It made sense because the content of the published image
was just a subset of the local one.
Now that it is printed to the metadata, it should have a different name
to avoid confusion.
As I mentioned, it wasn't printed before - so there shouldn't be any
backward-compatibility issues.
---
Local tests:
```
go test -v .
=== RUN TestVersion
=== RUN TestVersion/only_version
=== RUN TestVersion/version_and_date
=== RUN TestVersion/version,_date,_built_by
=== RUN TestVersion/all_empty
=== RUN TestVersion/complete
--- PASS: TestVersion (0.00s)
--- PASS: TestVersion/only_version (0.00s)
--- PASS: TestVersion/version_and_date (0.00s)
--- PASS: TestVersion/version,_date,_built_by (0.00s)
--- PASS: TestVersion/all_empty (0.00s)
--- PASS: TestVersion/complete (0.00s)
PASS
ok github.com/goreleaser/goreleaser 0.764s
```
Output example:
```
{
"name": "gallegit/hello-world:latest",
"path": "gallegit/hello-world:latest",
"goos": "linux",
"goarch": "amd64",
"internal_type": 10,
"type": "Published Docker Image",
"extra": {
"digest": "sha256:c3f7dd196a046dc061236d3c6ae1e2946269e90da30b0a959240ca799750e632"
}
}
```
Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com>
Co-authored-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
2022-11-12 19:51:53 +02:00
|
|
|
if err != nil {
|
2021-06-26 21:36:31 +02:00
|
|
|
return err
|
2017-09-12 04:31:00 +02:00
|
|
|
}
|
2022-06-23 13:49:33 +02:00
|
|
|
|
2021-08-17 03:11:54 +02:00
|
|
|
art := &artifact.Artifact{
|
2019-09-03 18:27:16 +02:00
|
|
|
Type: artifact.DockerImage,
|
|
|
|
Name: image.Name,
|
|
|
|
Path: image.Path,
|
|
|
|
Goarch: image.Goarch,
|
|
|
|
Goos: image.Goos,
|
|
|
|
Goarm: image.Goarm,
|
2021-08-17 03:11:54 +02:00
|
|
|
Extra: map[string]interface{}{},
|
|
|
|
}
|
|
|
|
if docker.ID != "" {
|
2021-10-17 03:46:11 +02:00
|
|
|
art.Extra[artifact.ExtraID] = docker.ID
|
2021-08-17 03:11:54 +02:00
|
|
|
}
|
2022-11-15 13:31:21 +02:00
|
|
|
art.Extra[artifact.ExtraDigest] = digest
|
feat: add digest to artifacts info of published docker images (#3540)
Extract the digest (sha256) of docker images from the `docker push`
command for dockers published to the docker registry.
Outputting the digest is required to avoid a race condition when
referencing the image, where the image tag is being modified before the
reference is done.
See this [blog
post](https://github.com/goreleaser/goreleaser/issues/3496) for more
info.
This PR fixes https://github.com/goreleaser/goreleaser/issues/3496.
Note that the 'publish' pipe now must run before the 'metadata' pipe, so
that the information extracted during the 'publish' pipe would appear in
the metadata.
Previously, the published docker images metadata wasn't printed (because
of the order). It made sense because the content of the published image
was just a subset of the local one.
Now that it is printed to the metadata, it should have a different name
to avoid confusion.
As I mentioned, it wasn't printed before - so there shouldn't be any
backward-compatibility issues.
---
Local tests:
```
go test -v .
=== RUN TestVersion
=== RUN TestVersion/only_version
=== RUN TestVersion/version_and_date
=== RUN TestVersion/version,_date,_built_by
=== RUN TestVersion/all_empty
=== RUN TestVersion/complete
--- PASS: TestVersion (0.00s)
--- PASS: TestVersion/only_version (0.00s)
--- PASS: TestVersion/version_and_date (0.00s)
--- PASS: TestVersion/version,_date,_built_by (0.00s)
--- PASS: TestVersion/all_empty (0.00s)
--- PASS: TestVersion/complete (0.00s)
PASS
ok github.com/goreleaser/goreleaser 0.764s
```
Output example:
```
{
"name": "gallegit/hello-world:latest",
"path": "gallegit/hello-world:latest",
"goos": "linux",
"goarch": "amd64",
"internal_type": 10,
"type": "Published Docker Image",
"extra": {
"digest": "sha256:c3f7dd196a046dc061236d3c6ae1e2946269e90da30b0a959240ca799750e632"
}
}
```
Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com>
Co-authored-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
2022-11-12 19:51:53 +02:00
|
|
|
|
2021-08-17 03:11:54 +02:00
|
|
|
ctx.Artifacts.Add(art)
|
2017-09-12 04:31:00 +02:00
|
|
|
return nil
|
|
|
|
}
|
2023-09-01 16:16:16 +02:00
|
|
|
|
|
|
|
func doPush(ctx *context.Context, img imager, name string, flags []string) (string, error) {
|
|
|
|
var try int
|
|
|
|
for try < 10 {
|
|
|
|
digest, err := img.Push(ctx, name, flags)
|
|
|
|
if err == nil {
|
|
|
|
return digest, nil
|
|
|
|
}
|
|
|
|
if isRetryable(err) {
|
|
|
|
log.WithField("try", try).
|
|
|
|
WithField("image", name).
|
|
|
|
WithError(err).
|
|
|
|
Warnf("failed to push image, will retry")
|
|
|
|
time.Sleep(time.Duration(try*10) * time.Second)
|
|
|
|
try++
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return "", fmt.Errorf("failed to push %s after %d tries: %w", name, try, err)
|
|
|
|
}
|
|
|
|
return "", nil // will never happen
|
|
|
|
}
|
|
|
|
|
|
|
|
func isRetryable(err error) bool {
|
|
|
|
for _, code := range []int{
|
|
|
|
http.StatusInternalServerError,
|
|
|
|
// http.StatusNotImplemented,
|
|
|
|
http.StatusBadGateway,
|
|
|
|
http.StatusServiceUnavailable,
|
|
|
|
http.StatusGatewayTimeout,
|
|
|
|
// http.StatusHTTPVersionNotSupported,
|
|
|
|
http.StatusVariantAlsoNegotiates,
|
|
|
|
// http.StatusInsufficientStorage,
|
|
|
|
// http.StatusLoopDetected,
|
|
|
|
http.StatusNotExtended,
|
|
|
|
// http.StatusNetworkAuthenticationRequired,
|
|
|
|
} {
|
|
|
|
if strings.Contains(
|
|
|
|
err.Error(),
|
|
|
|
fmt.Sprintf(
|
|
|
|
"received unexpected HTTP status: %d %s",
|
|
|
|
code,
|
|
|
|
http.StatusText(code),
|
|
|
|
),
|
|
|
|
) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|