cli/bpbuild/cmd.go (115 lines of code) (raw):

package bpbuild import ( "fmt" "os" "time" "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/cli/util" "github.com/fatih/color" "github.com/spf13/cobra" "github.com/spf13/viper" ) var avgTimeFlags struct { projectId string repoName string buildFilePath string buildStepID string lookUpStart string lookUpStartTime time.Time lookUpEnd string lookUpEndTime time.Time } const defaultBuildFilePath = "build/int.cloudbuild.yaml" func init() { viper.AutomaticEnv() Cmd.AddCommand(avgTimeCmd) avgTimeCmd.Flags().StringVar(&avgTimeFlags.buildFilePath, "build-file", defaultBuildFilePath, "Path to file containing CloudBuild configs.") avgTimeCmd.Flags().StringVar(&avgTimeFlags.buildStepID, "step", "", "ID of build step to compute avg.") avgTimeCmd.Flags().StringVar(&avgTimeFlags.lookUpStart, "start-time", "", "Time to start computing build step avg in form MM-DD-YYYY. Defaults to one month ago.") avgTimeCmd.Flags().StringVar(&avgTimeFlags.lookUpEnd, "end-time", "", "Time to stop computing build step avg in form MM-DD-YYYY. Defaults to current date.") avgTimeCmd.Flags().StringVar(&avgTimeFlags.projectId, "project-id", "cloud-foundation-cicd", "Project ID where builds are executed.") avgTimeCmd.Flags().StringVar(&avgTimeFlags.repoName, "repo", "", "Name of repo that triggered the builds. Defaults to extracting from git config.") } var Cmd = &cobra.Command{ Use: "builds", Short: "Blueprint builds", Long: `Blueprint builds CLI is used to get information about blueprint builds.`, Args: cobra.NoArgs, } var avgTimeCmd = &cobra.Command{ Use: "avgtime", Short: "average time for build step", Long: `Compute average time for a given build step across build executions from a given start-time to end-time.`, Args: cobra.NoArgs, RunE: calcAvgTime, } func calcAvgTime(cmd *cobra.Command, args []string) error { // set any computed defaults if err := setAvgTimeFlagDefaults(); err != nil { return err } // build filters filterExpr := successBuildsBtwFilterExpr(avgTimeFlags.lookUpStartTime, avgTimeFlags.lookUpEndTime) cFilters := []clientBuildFilter{ filterRealBuilds, filterGHRepoBuilds(avgTimeFlags.repoName), } // get builds and compute avg builds, err := getCBBuildsWithFilter(avgTimeFlags.projectId, filterExpr, cFilters) if err != nil { return fmt.Errorf("error retrieving builds: %w", err) } durations, err := findBuildStageDurations(avgTimeFlags.buildStepID, builds) if err != nil { return err } if len(durations) < 1 { return fmt.Errorf("error no successful build stage %s found", avgTimeFlags.buildStepID) } avgTime := durationAvg(durations) // todo(bharathkkb): Add JSON output fmt.Printf("Discovered %d samples for %s stage between %s and %s\n", len(durations), avgTimeFlags.buildStepID, avgTimeFlags.lookUpStart, avgTimeFlags.lookUpEnd) color.Green("Computed average time: %s", avgTime) return nil } // setAvgTimeFlagDefaults sets computed defaults for any missing flags. // An error is thrown if a default cannot be computed. func setAvgTimeFlagDefaults() error { // if no explicit repo name specified via flag, try to auto discover if avgTimeFlags.repoName == "" { Log.Info("No repo specified, attempting to detect repo name from current dir") path, err := os.Getwd() if err != nil { return fmt.Errorf("error getting working dir: %w", err) } r, err := getRepoName(path) if err != nil { return fmt.Errorf("error finding repo name: %w", err) } if r == "" { return fmt.Errorf("unable to detect repo name, please specify a name using --repo") } avgTimeFlags.repoName = r Log.Info("Found repo", "default", avgTimeFlags.repoName) } // if no explicit build step specified via flag, prompt user with possible options from CloudBuild configs. if avgTimeFlags.buildStepID == "" { Log.Info("No build ID specified, attempting to find and prompt for build step ID from build file.") buildFile, err := getBuildFromFile(avgTimeFlags.buildFilePath) if err != nil { return fmt.Errorf("error finding build file: %w", err) } steps := getBuildStepIDs(buildFile) avgTimeFlags.buildStepID = util.PromptSelect("Select build step to compute average", steps) } // if no explicit start time, default to starting computation from one month ago. if avgTimeFlags.lookUpStart == "" { avgTimeFlags.lookUpStart = time.Now().AddDate(0, -1, 0).Format("01-02-2006") Log.Info("No start time specified.", "default", avgTimeFlags.lookUpStart) } startTime, err := getTimeFromStr(avgTimeFlags.lookUpStart) if err != nil { return fmt.Errorf("error converting %s to time: %w", avgTimeFlags.lookUpStart, err) } avgTimeFlags.lookUpStartTime = startTime // if no explicit end time, default to ending computation to now. if avgTimeFlags.lookUpEnd == "" { avgTimeFlags.lookUpEnd = time.Now().Format("01-02-2006") Log.Info("No end time specified.", "default", avgTimeFlags.lookUpEnd) } endTime, err := getTimeFromStr(avgTimeFlags.lookUpEnd) if err != nil { return fmt.Errorf("error converting %s to time: %w", avgTimeFlags.lookUpEnd, err) } avgTimeFlags.lookUpEndTime = endTime return nil }