mirror of
https://github.com/goreleaser/goreleaser.git
synced 2025-03-23 21:19:17 +02:00
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>
97 lines
2.4 KiB
Go
97 lines
2.4 KiB
Go
package docker
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"os/exec"
|
|
"sync"
|
|
|
|
"github.com/caarlos0/log"
|
|
"github.com/goreleaser/goreleaser/internal/gio"
|
|
"github.com/goreleaser/goreleaser/internal/logext"
|
|
"github.com/goreleaser/goreleaser/pkg/context"
|
|
)
|
|
|
|
var (
|
|
manifesters = map[string]manifester{}
|
|
imagers = map[string]imager{}
|
|
lock sync.Mutex
|
|
)
|
|
|
|
func registerManifester(use string, impl manifester) {
|
|
lock.Lock()
|
|
defer lock.Unlock()
|
|
manifesters[use] = impl
|
|
}
|
|
|
|
func registerImager(use string, impl imager) {
|
|
lock.Lock()
|
|
defer lock.Unlock()
|
|
imagers[use] = impl
|
|
}
|
|
|
|
// imager is something that can build and push docker images.
|
|
type imager interface {
|
|
Build(ctx *context.Context, root string, images, flags []string) error
|
|
Push(ctx *context.Context, image string, flags []string) (digest string, err error)
|
|
}
|
|
|
|
// manifester is something that can create and push docker manifests.
|
|
type manifester interface {
|
|
Create(ctx *context.Context, manifest string, images, flags []string) error
|
|
Push(ctx *context.Context, manifest string, flags []string) error
|
|
}
|
|
|
|
// nolint: unparam
|
|
func runCommand(ctx *context.Context, dir, binary string, args ...string) error {
|
|
fields := log.Fields{
|
|
"cmd": append([]string{binary}, args[0]),
|
|
"cwd": dir,
|
|
}
|
|
|
|
/* #nosec */
|
|
cmd := exec.CommandContext(ctx, binary, args...)
|
|
cmd.Dir = dir
|
|
cmd.Env = ctx.Env.Strings()
|
|
|
|
var b bytes.Buffer
|
|
w := gio.Safe(&b)
|
|
cmd.Stderr = io.MultiWriter(logext.NewWriter(fields, logext.Error), w)
|
|
cmd.Stdout = io.MultiWriter(logext.NewWriter(fields, logext.Info), w)
|
|
|
|
log.WithFields(fields).WithField("args", args[1:]).Debug("running")
|
|
if err := cmd.Run(); err != nil {
|
|
return fmt.Errorf("%w: %s", err, b.String())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func runCommandWithOutput(ctx *context.Context, dir, binary string, args ...string) ([]byte, error) {
|
|
fields := log.Fields{
|
|
"cmd": append([]string{binary}, args[0]),
|
|
"cwd": dir,
|
|
}
|
|
|
|
/* #nosec */
|
|
cmd := exec.CommandContext(ctx, binary, args...)
|
|
cmd.Dir = dir
|
|
cmd.Env = ctx.Env.Strings()
|
|
|
|
var b bytes.Buffer
|
|
w := gio.Safe(&b)
|
|
cmd.Stderr = io.MultiWriter(logext.NewWriter(fields, logext.Error), w)
|
|
|
|
log.WithFields(fields).WithField("args", args[1:]).Debug("running")
|
|
out, err := cmd.Output()
|
|
if out != nil {
|
|
// regardless of command success, always print stdout for backward-compatibility with runCommand()
|
|
_, _ = io.MultiWriter(logext.NewWriter(fields, logext.Error), w).Write(out)
|
|
}
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%w: %s", err, b.String())
|
|
}
|
|
|
|
return out, nil
|
|
}
|