github.com/ahmet2mir/goreleaser@v0.180.3-0.20210927151101-8e5ee5a9b8c5/internal/pipe/docker/manifest.go (about) 1 package docker 2 3 import ( 4 "fmt" 5 "sort" 6 "strings" 7 8 "github.com/apex/log" 9 "github.com/goreleaser/goreleaser/internal/artifact" 10 "github.com/goreleaser/goreleaser/internal/ids" 11 "github.com/goreleaser/goreleaser/internal/pipe" 12 "github.com/goreleaser/goreleaser/internal/semerrgroup" 13 "github.com/goreleaser/goreleaser/internal/tmpl" 14 "github.com/goreleaser/goreleaser/pkg/config" 15 "github.com/goreleaser/goreleaser/pkg/context" 16 ) 17 18 // ManifestPipe is beta implementation of for the docker manifest feature, 19 // allowing to publish multi-arch docker images. 20 type ManifestPipe struct{} 21 22 func (ManifestPipe) String() string { return "docker manifests" } 23 func (ManifestPipe) Skip(ctx *context.Context) bool { return len(ctx.Config.DockerManifests) == 0 } 24 25 // Default sets the pipe defaults. 26 func (ManifestPipe) Default(ctx *context.Context) error { 27 ids := ids.New("docker_manifests") 28 for i := range ctx.Config.DockerManifests { 29 manifest := &ctx.Config.DockerManifests[i] 30 if manifest.ID != "" { 31 ids.Inc(manifest.ID) 32 } 33 if manifest.Use == "" { 34 manifest.Use = useDocker 35 } 36 if err := validateManifester(manifest.Use); err != nil { 37 return err 38 } 39 } 40 return ids.Validate() 41 } 42 43 // Publish the docker manifests. 44 func (ManifestPipe) Publish(ctx *context.Context) error { 45 g := semerrgroup.NewSkipAware(semerrgroup.New(1)) 46 for _, manifest := range ctx.Config.DockerManifests { 47 manifest := manifest 48 g.Go(func() error { 49 if strings.TrimSpace(manifest.SkipPush) == "true" { 50 return pipe.Skip("docker_manifest.skip_push is set") 51 } 52 53 if strings.TrimSpace(manifest.SkipPush) == "auto" && ctx.Semver.Prerelease != "" { 54 return pipe.Skip("prerelease detected with 'auto' push, skipping docker manifest") 55 } 56 57 name, err := manifestName(ctx, manifest) 58 if err != nil { 59 return err 60 } 61 62 images, err := manifestImages(ctx, manifest) 63 if err != nil { 64 return err 65 } 66 67 manifester := manifesters[manifest.Use] 68 69 log.WithField("manifest", name).WithField("images", images).Info("creating docker manifest") 70 if err := manifester.Create(ctx, name, images, manifest.CreateFlags); err != nil { 71 return err 72 } 73 art := &artifact.Artifact{ 74 Type: artifact.DockerManifest, 75 Name: name, 76 Path: name, 77 Extra: map[string]interface{}{}, 78 } 79 if manifest.ID != "" { 80 art.Extra["ID"] = manifest.ID 81 } 82 ctx.Artifacts.Add(art) 83 84 log.WithField("manifest", name).Info("pushing docker manifest") 85 return manifester.Push(ctx, name, manifest.PushFlags) 86 }) 87 } 88 return g.Wait() 89 } 90 91 func validateManifester(use string) error { 92 valid := make([]string, 0, len(manifesters)) 93 for k := range manifesters { 94 valid = append(valid, k) 95 } 96 for _, s := range valid { 97 if s == use { 98 return nil 99 } 100 } 101 sort.Strings(valid) 102 return fmt.Errorf("docker manifest: invalid use: %s, valid options are %v", use, valid) 103 } 104 105 func manifestName(ctx *context.Context, manifest config.DockerManifest) (string, error) { 106 name, err := tmpl.New(ctx).Apply(manifest.NameTemplate) 107 if err != nil { 108 return name, err 109 } 110 if strings.TrimSpace(name) == "" { 111 return name, pipe.Skip("manifest name is empty") 112 } 113 return name, nil 114 } 115 116 func manifestImages(ctx *context.Context, manifest config.DockerManifest) ([]string, error) { 117 imgs := make([]string, 0, len(manifest.ImageTemplates)) 118 for _, img := range manifest.ImageTemplates { 119 str, err := tmpl.New(ctx).Apply(img) 120 if err != nil { 121 return []string{}, err 122 } 123 imgs = append(imgs, str) 124 } 125 if strings.TrimSpace(strings.Join(manifest.ImageTemplates, "")) == "" { 126 return imgs, pipe.Skip("manifest has no images") 127 } 128 return imgs, nil 129 }