github.com/amane3/goreleaser@v0.182.0/internal/pipe/docker/manifest.go (about)

     1  package docker
     2  
     3  import (
     4  	"fmt"
     5  	"os/exec"
     6  	"strings"
     7  
     8  	"github.com/amane3/goreleaser/internal/artifact"
     9  	"github.com/amane3/goreleaser/internal/pipe"
    10  	"github.com/amane3/goreleaser/internal/semerrgroup"
    11  	"github.com/amane3/goreleaser/internal/tmpl"
    12  	"github.com/amane3/goreleaser/pkg/config"
    13  	"github.com/amane3/goreleaser/pkg/context"
    14  	"github.com/apex/log"
    15  )
    16  
    17  // ManifestPipe is beta implementation of for the docker manifest feature,
    18  // allowing to publish multi-arch docker images.
    19  type ManifestPipe struct{}
    20  
    21  func (ManifestPipe) String() string {
    22  	return "docker manifests"
    23  }
    24  
    25  // Publish the docker manifests.
    26  func (ManifestPipe) Publish(ctx *context.Context) error {
    27  	if ctx.SkipPublish {
    28  		return pipe.ErrSkipPublishEnabled
    29  	}
    30  	var g = semerrgroup.NewSkipAware(semerrgroup.New(ctx.Parallelism))
    31  	for _, manifest := range ctx.Config.DockerManifests {
    32  		manifest := manifest
    33  		g.Go(func() error {
    34  			name, err := manifestName(ctx, manifest)
    35  			if err != nil {
    36  				return err
    37  			}
    38  			images, err := manifestImages(ctx, manifest)
    39  			if err != nil {
    40  				return err
    41  			}
    42  			if err := dockerManifestCreate(ctx, name, images, manifest.CreateFlags); err != nil {
    43  				return err
    44  			}
    45  			ctx.Artifacts.Add(&artifact.Artifact{
    46  				Type: artifact.DockerManifest,
    47  				Name: name,
    48  				Path: name,
    49  			})
    50  			return dockerManifestPush(ctx, name, manifest.PushFlags)
    51  		})
    52  	}
    53  	return g.Wait()
    54  }
    55  
    56  func manifestName(ctx *context.Context, manifest config.DockerManifest) (string, error) {
    57  	name, err := tmpl.New(ctx).Apply(manifest.NameTemplate)
    58  	if err != nil {
    59  		return name, err
    60  	}
    61  	if strings.TrimSpace(name) == "" {
    62  		return name, pipe.Skip("manifest name is empty")
    63  	}
    64  	return name, nil
    65  }
    66  
    67  func manifestImages(ctx *context.Context, manifest config.DockerManifest) ([]string, error) {
    68  	var imgs = make([]string, 0, len(manifest.ImageTemplates))
    69  	for _, img := range manifest.ImageTemplates {
    70  		str, err := tmpl.New(ctx).Apply(img)
    71  		if err != nil {
    72  			return []string{}, err
    73  		}
    74  		imgs = append(imgs, str)
    75  	}
    76  	if strings.TrimSpace(strings.Join(manifest.ImageTemplates, "")) == "" {
    77  		return imgs, pipe.Skip("manifest has no images")
    78  	}
    79  	return imgs, nil
    80  }
    81  
    82  func dockerManifestCreate(ctx *context.Context, manifest string, images, flags []string) error {
    83  	log.WithField("manifest", manifest).Info("creating docker manifest")
    84  	var args = []string{"manifest", "create", manifest}
    85  	for _, img := range images {
    86  		args = append(args, "--amend", img)
    87  	}
    88  	args = append(args, flags...)
    89  	/* #nosec */
    90  	var cmd = exec.CommandContext(ctx, "docker", args...)
    91  	log.WithField("cmd", cmd.Args).WithField("cwd", cmd.Dir).Debug("running")
    92  	out, err := cmd.CombinedOutput()
    93  	if err != nil {
    94  		return fmt.Errorf("failed to create docker manifest: %s: \n%s: %w", manifest, string(out), err)
    95  	}
    96  	log.Debugf("docker manifest output: \n%s", string(out))
    97  	return nil
    98  }
    99  
   100  func dockerManifestPush(ctx *context.Context, manifest string, flags []string) error {
   101  	log.WithField("manifest", manifest).Info("pushing docker manifest")
   102  	var args = []string{"manifest", "push", manifest}
   103  	args = append(args, flags...)
   104  	/* #nosec */
   105  	var cmd = exec.CommandContext(ctx, "docker", args...)
   106  	log.WithField("cmd", cmd.Args).WithField("cwd", cmd.Dir).Debug("running")
   107  	out, err := cmd.CombinedOutput()
   108  	if err != nil {
   109  		return fmt.Errorf("failed to push docker manifest: %s: \n%s: %w", manifest, string(out), err)
   110  	}
   111  	log.Debugf("docker manifest output: \n%s", string(out))
   112  	return nil
   113  }