...

Source file src/edge-infra.dev/pkg/tools/hack/cmd/push/push.go

Documentation: edge-infra.dev/pkg/tools/hack/cmd/push

     1  package push
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/google/go-containerregistry/pkg/crane"
     8  
     9  	"edge-infra.dev/hack/build/ci"
    10  	"edge-infra.dev/pkg/lib/cli/rags"
    11  	"edge-infra.dev/pkg/lib/cli/sink"
    12  	"edge-infra.dev/pkg/tools/hack/bazelx"
    13  	"edge-infra.dev/pkg/tools/hack/containers"
    14  )
    15  
    16  func New(name string) *sink.Command {
    17  	var (
    18  		repo                  string
    19  		tags                  []string
    20  		insecure, relTags, rc bool
    21  		bzlx                  = &bazelx.Bazelx{}
    22  	)
    23  
    24  	return &sink.Command{
    25  		Use:        fmt.Sprintf("%s [flags] <bazel expressions ...> [-- bazel flags]", name),
    26  		Short:      "Push OCI build artifacts to registries using Bazel",
    27  		Extensions: []sink.Extension{bzlx},
    28  		Flags: []*rags.Rag{
    29  			{
    30  				Name:  "repo",
    31  				Short: "r",
    32  				Usage: "Override the default destination repository",
    33  				Value: &rags.String{Var: &repo},
    34  			},
    35  			{
    36  				Name:  "tag",
    37  				Short: "t",
    38  				Usage: "One or more tags to apply to pushed containers. Multiple flags can be provided as comma separated strings or multiple instances of the flag.",
    39  				Value: &rags.StringSet{Var: &tags},
    40  			},
    41  			// TODO: This is needed for initial pass because rules_docker doesn't
    42  			// support multiple tags on a push target. Once we are on rules_oci completely,
    43  			// we should use stamping to create remote_tags file with multiple tags in it,
    44  			// instead of achieving release tags by wrapping with this tool.
    45  			{
    46  				Name:  "release-tags",
    47  				Usage: "Tag pushed containers with build information",
    48  				Value: &rags.Bool{Var: &relTags},
    49  			},
    50  			{
    51  				Name:  "rc",
    52  				Usage: "Whether or not this build is a release candidate",
    53  				Value: &rags.Bool{Var: &rc, Default: true},
    54  			},
    55  			// TODO: This is rules_docker specific and should be removed as part of the
    56  			// migration. Make sure HTTP flows are supported in rules_oci. Looks like
    57  			// only consumer is Edge IAM.
    58  			{
    59  				Name:  "insecure-repository",
    60  				Usage: "Allow HTTP repositories. Only valid for rules_docker push rules",
    61  				Value: &rags.Bool{Var: &insecure},
    62  			},
    63  		},
    64  		Exec: func(_ context.Context, r sink.Run) error {
    65  			if len(r.Args()) == 0 {
    66  				return fmt.Errorf("one or more Bazel expressions required")
    67  			}
    68  
    69  			log := r.Log
    70  
    71  			pushes, err := containers.QueryPushes(r.Args()...)
    72  			if err != nil {
    73  				return err
    74  			}
    75  			if len(pushes) == 0 {
    76  				return fmt.Errorf("no container_push targets found")
    77  			}
    78  			log.Info("container_push targets to execute", "targets", pushes)
    79  
    80  			opts := []containers.Option{}
    81  			if repo != "" {
    82  				opts = append(opts, containers.ToRepository(repo))
    83  			}
    84  			if insecure {
    85  				opts = append(opts, containers.Insecure)
    86  			}
    87  
    88  			refs, err := containers.Push(bzlx.Bazel, pushes, opts...)
    89  			if err != nil {
    90  				return err
    91  			}
    92  			log.Info("successfully pushed", "refs", refs)
    93  
    94  			if relTags {
    95  				rt, err := containerTags(rc)
    96  				if err != nil {
    97  					return err
    98  				}
    99  				tags = append(tags, rt...)
   100  			}
   101  
   102  			// If no tags, we are done.
   103  			if len(tags) == 0 {
   104  				return nil
   105  			}
   106  
   107  			// TODO: once rules_docker is entirely gone, we can just provide the
   108  			// tags as flags to the individual container_push binaries instead
   109  			for _, r := range refs {
   110  				for _, t := range tags {
   111  					if err := crane.Tag(r.String(), t); err != nil {
   112  						return fmt.Errorf("failed to tag %s with %s: %w", r, t, err)
   113  					}
   114  				}
   115  				log.Info("tagged", "ref", r, "tags", tags)
   116  			}
   117  
   118  			return nil
   119  		},
   120  	}
   121  }
   122  
   123  func containerTags(rc bool) ([]string, error) {
   124  	version, branch, err := ci.BuildInfo(rc, ci.RepoRoot)
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  
   129  	// get the tags we will apply to each container
   130  	return version.ContainerTags(branch)
   131  }
   132  

View as plain text