github.com/khulnasoft/cli@v0.0.0-20240402070845-01bcad7beefa/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/docker/api/types/image"
    10  	registrytypes "github.com/docker/docker/api/types/registry"
    11  	"github.com/docker/docker/pkg/jsonmessage"
    12  	"github.com/docker/docker/registry"
    13  	"github.com/khulnasoft/cli/cli"
    14  	"github.com/khulnasoft/cli/cli/command"
    15  	"github.com/khulnasoft/cli/cli/command/completion"
    16  	"github.com/khulnasoft/cli/cli/streams"
    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  }