go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/led/ledcli/get_build.go (about)

     1  // Copyright 2020 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package ledcli
    16  
    17  import (
    18  	"context"
    19  	"net/http"
    20  	"strconv"
    21  	"strings"
    22  
    23  	"github.com/maruel/subcommands"
    24  
    25  	"go.chromium.org/luci/auth"
    26  	"go.chromium.org/luci/common/errors"
    27  	"go.chromium.org/luci/common/flag/stringmapflag"
    28  	"go.chromium.org/luci/led/job"
    29  	"go.chromium.org/luci/led/ledcmd"
    30  )
    31  
    32  func getBuildCmd(opts cmdBaseOptions) *subcommands.Command {
    33  	return &subcommands.Command{
    34  		UsageLine: "get-build <buildbucket_build_id>",
    35  		ShortDesc: "obtain a JobDefinition from a buildbucket build",
    36  		LongDesc: `Obtains the build's definition from buildbucket and produces a JobDefinition.
    37  
    38  buildbucket_build_id can be specified with "b" prefix like b8962624445013664976,
    39  which is useful when copying it from ci.chromium.org URL.`,
    40  
    41  		CommandRun: func() subcommands.CommandRun {
    42  			ret := &cmdGetBuild{}
    43  			ret.initFlags(opts)
    44  			return ret
    45  		},
    46  	}
    47  }
    48  
    49  type cmdGetBuild struct {
    50  	cmdBase
    51  
    52  	bbHost               string
    53  	pinBotID             bool
    54  	priorityDiff         int
    55  	realBuild            bool
    56  	experiments          stringmapflag.Value
    57  	processedExperiments map[string]bool
    58  
    59  	buildID int64
    60  }
    61  
    62  func (c *cmdGetBuild) initFlags(opts cmdBaseOptions) {
    63  	c.Flags.StringVar(&c.bbHost, "B", "cr-buildbucket.appspot.com",
    64  		"The buildbucket hostname to grab the definition from.")
    65  
    66  	c.Flags.BoolVar(&c.pinBotID, "pin-bot-id", false,
    67  		"Pin the bot id in the generated job Definition's dimensions.")
    68  
    69  	c.Flags.IntVar(&c.priorityDiff, "adjust-priority", 10,
    70  		"Increase or decrease the priority of the generated job. Note: priority works like Unix 'niceness'; Higher values indicate lower priority.")
    71  
    72  	c.Flags.BoolVar(&c.realBuild, "real-build", false,
    73  		"Get a synthesized build using the provided build as template, instead the provided build itself.")
    74  
    75  	c.Flags.Var(&c.experiments, "experiment",
    76  		"Note: only works in real-build mode.\n"+
    77  			"(repeatable) enable or disable an experiment. This takes a parameter of `experiment_name=true|false` and "+
    78  			"adds/removes the corresponding experiment. Already enabled experiments are left as is unless they "+
    79  			"are explicitly disabled.")
    80  
    81  	c.cmdBase.initFlags(opts)
    82  }
    83  
    84  func (c *cmdGetBuild) jobInput() bool                  { return false }
    85  func (c *cmdGetBuild) positionalRange() (min, max int) { return 1, 1 }
    86  
    87  func (c *cmdGetBuild) validateFlags(ctx context.Context, positionals []string, env subcommands.Env) (err error) {
    88  	if err := pingHost(c.bbHost); err != nil {
    89  		return errors.Annotate(err, "buildbucket host").Err()
    90  	}
    91  
    92  	buildIDStr := positionals[0]
    93  	if strings.HasPrefix(buildIDStr, "b") {
    94  		// Milo URL structure prefixes buildbucket builds id with "b".
    95  		buildIDStr = positionals[0][1:]
    96  	}
    97  	if c.buildID, err = strconv.ParseInt(buildIDStr, 10, 64); err != nil {
    98  		return errors.Annotate(err, "bad <buildbucket_build_id>").Err()
    99  	}
   100  	if !c.realBuild && len(c.experiments) > 0 {
   101  		return errors.Reason("setting experiments only works in real-build mode.").Err()
   102  	}
   103  	if c.processedExperiments, err = processExperiments(c.experiments); err != nil {
   104  		return err
   105  	}
   106  	return nil
   107  }
   108  
   109  func (c *cmdGetBuild) execute(ctx context.Context, authClient *http.Client, _ auth.Options, inJob *job.Definition) (out any, err error) {
   110  	return ledcmd.GetBuild(ctx, authClient, ledcmd.GetBuildOpts{
   111  		BuildbucketHost: c.bbHost,
   112  		BuildID:         c.buildID,
   113  		PinBotID:        c.pinBotID,
   114  		PriorityDiff:    c.priorityDiff,
   115  		KitchenSupport:  c.kitchenSupport,
   116  		RealBuild:       c.realBuild,
   117  		Experiments:     c.processedExperiments,
   118  	})
   119  }
   120  
   121  func (c *cmdGetBuild) Run(a subcommands.Application, args []string, env subcommands.Env) int {
   122  	return c.doContextExecute(a, c, args, env)
   123  }