github.com/thajeztah/cli@v0.0.0-20240223162942-dc6bfac81a8b/cli/command/image/push.go (about) 1 package image 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 8 "github.com/distribution/reference" 9 "github.com/docker/cli/cli" 10 "github.com/docker/cli/cli/command" 11 "github.com/docker/cli/cli/command/completion" 12 "github.com/docker/cli/cli/streams" 13 "github.com/docker/docker/api/types/image" 14 registrytypes "github.com/docker/docker/api/types/registry" 15 "github.com/docker/docker/pkg/jsonmessage" 16 "github.com/docker/docker/registry" 17 "github.com/pkg/errors" 18 "github.com/spf13/cobra" 19 ) 20 21 type pushOptions struct { 22 all bool 23 remote string 24 untrusted bool 25 quiet bool 26 } 27 28 // NewPushCommand creates a new `docker push` command 29 func NewPushCommand(dockerCli command.Cli) *cobra.Command { 30 var opts pushOptions 31 32 cmd := &cobra.Command{ 33 Use: "push [OPTIONS] NAME[:TAG]", 34 Short: "Upload an image to a registry", 35 Args: cli.ExactArgs(1), 36 RunE: func(cmd *cobra.Command, args []string) error { 37 opts.remote = args[0] 38 return RunPush(cmd.Context(), dockerCli, opts) 39 }, 40 Annotations: map[string]string{ 41 "category-top": "6", 42 "aliases": "docker image push, docker push", 43 }, 44 ValidArgsFunction: completion.ImageNames(dockerCli), 45 } 46 47 flags := cmd.Flags() 48 flags.BoolVarP(&opts.all, "all-tags", "a", false, "Push all tags of an image to the repository") 49 flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress verbose output") 50 command.AddTrustSigningFlags(flags, &opts.untrusted, dockerCli.ContentTrustEnabled()) 51 52 return cmd 53 } 54 55 // RunPush performs a push against the engine based on the specified options 56 func RunPush(ctx context.Context, dockerCli command.Cli, opts pushOptions) error { 57 ref, err := reference.ParseNormalizedNamed(opts.remote) 58 switch { 59 case err != nil: 60 return err 61 case opts.all && !reference.IsNameOnly(ref): 62 return errors.New("tag can't be used with --all-tags/-a") 63 case !opts.all && reference.IsNameOnly(ref): 64 ref = reference.TagNameOnly(ref) 65 if tagged, ok := ref.(reference.Tagged); ok && !opts.quiet { 66 _, _ = fmt.Fprintf(dockerCli.Out(), "Using default tag: %s\n", tagged.Tag()) 67 } 68 } 69 70 // Resolve the Repository name from fqn to RepositoryInfo 71 repoInfo, err := registry.ParseRepositoryInfo(ref) 72 if err != nil { 73 return err 74 } 75 76 // Resolve the Auth config relevant for this server 77 authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index) 78 encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig) 79 if err != nil { 80 return err 81 } 82 requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "push") 83 options := image.PushOptions{ 84 All: opts.all, 85 RegistryAuth: encodedAuth, 86 PrivilegeFunc: requestPrivilege, 87 } 88 89 responseBody, err := dockerCli.Client().ImagePush(ctx, reference.FamiliarString(ref), options) 90 if err != nil { 91 return err 92 } 93 94 defer responseBody.Close() 95 if !opts.untrusted { 96 // TODO PushTrustedReference currently doesn't respect `--quiet` 97 return PushTrustedReference(dockerCli, repoInfo, ref, authConfig, responseBody) 98 } 99 100 if opts.quiet { 101 err = jsonmessage.DisplayJSONMessagesToStream(responseBody, streams.NewOut(io.Discard), nil) 102 if err == nil { 103 fmt.Fprintln(dockerCli.Out(), ref.String()) 104 } 105 return err 106 } 107 return jsonmessage.DisplayJSONMessagesToStream(responseBody, dockerCli.Out(), nil) 108 }