diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go index 301246a88..bd774c645 100644 --- a/cmd/soong_ui/main.go +++ b/cmd/soong_ui/main.go @@ -94,7 +94,7 @@ var commands = []command{ }, { flag: "--upload-metrics-only", description: "upload metrics without building anything", - config: uploadOnlyConfig, + config: build.UploadOnlyConfig, stdio: stdio, // Upload-only mode mostly skips to the metrics-uploading phase of soong_ui. // However, this invocation marks the true "end of the build", and thus we @@ -451,14 +451,6 @@ func dumpVarConfig(ctx build.Context, args ...string) build.Config { return build.NewConfig(ctx) } -// uploadOnlyConfig explicitly requires no arguments. -func uploadOnlyConfig(ctx build.Context, args ...string) build.Config { - if len(args) > 0 { - fmt.Printf("--upload-only does not require arguments.") - } - return build.UploadOnlyConfig(ctx) -} - func buildActionConfig(ctx build.Context, args ...string) build.Config { flags := flag.NewFlagSet("build-mode", flag.ContinueOnError) flags.SetOutput(ctx.Writer) @@ -710,7 +702,7 @@ func updateTotalRealTime(ctx build.Context, config build.Config, args []string) } met := ctx.ContextImpl.Metrics - err = met.UpdateTotalRealTime(data) + err = met.UpdateTotalRealTimeAndNonZeroExit(data, config.BazelExitCode()) if err != nil { ctx.Fatal(err) } diff --git a/ui/build/config.go b/ui/build/config.go index 2dda52a01..8ec96800f 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -89,7 +89,8 @@ type configImpl struct { skipMetricsUpload bool buildStartedTime int64 // For metrics-upload-only - manually specify a build-started time buildFromTextStub bool - ensureAllowlistIntegrity bool // For CI builds - make sure modules are mixed-built + ensureAllowlistIntegrity bool // For CI builds - make sure modules are mixed-built + bazelExitCode int32 // For b-runs - necessary for updating NonZeroExit // From the product config katiArgs []string @@ -298,11 +299,12 @@ func defaultBazelProdMode(cfg *configImpl) bool { return true } -func UploadOnlyConfig(ctx Context, _ ...string) Config { +func UploadOnlyConfig(ctx Context, args ...string) Config { ret := &configImpl{ environ: OsEnvironment(), sandboxConfig: &SandboxConfig{}, } + ret.parseArgs(ctx, args) srcDir := absPath(ctx, ".") bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG") if err := loadEnvConfig(ctx, ret, bc); err != nil { @@ -883,6 +885,14 @@ func (c *configImpl) parseArgs(ctx Context, args []string) { } } else if arg == "--ensure-allowlist-integrity" { c.ensureAllowlistIntegrity = true + } else if strings.HasPrefix(arg, "--bazel-exit-code=") { + bazelExitCodeStr := strings.TrimPrefix(arg, "--bazel-exit-code=") + val, err := strconv.Atoi(bazelExitCodeStr) + if err == nil { + c.bazelExitCode = int32(val) + } else { + ctx.Fatalf("Error parsing bazel-exit-code", err) + } } else if len(arg) > 0 && arg[0] == '-' { parseArgNum := func(def int) int { if len(arg) > 2 { @@ -1723,6 +1733,10 @@ func (c *configImpl) BuildStartedTimeOrDefault(defaultTime time.Time) time.Time return time.UnixMilli(c.buildStartedTime) } +func (c *configImpl) BazelExitCode() int32 { + return c.bazelExitCode +} + func GetMetricsUploader(topDir string, env *Environment) string { if p, ok := env.Get("METRICS_UPLOADER"); ok { metricsUploader := filepath.Join(topDir, p) diff --git a/ui/build/upload.go b/ui/build/upload.go index 1e6d94aad..ee4a5b345 100644 --- a/ui/build/upload.go +++ b/ui/build/upload.go @@ -141,7 +141,7 @@ func parsePhaseTiming(line string) bazel_metrics_proto.PhaseTiming { // This method takes a file created by bazel's --analyze-profile mode and // writes bazel metrics data to the provided filepath. // TODO(b/279987768) - move this outside of upload.go -func processBazelMetrics(bazelProfileFile string, bazelMetricsFile string, ctx Context) { +func processBazelMetrics(bazelProfileFile string, bazelMetricsFile string, ctx Context, config Config) { if bazelProfileFile == "" { return } @@ -179,6 +179,7 @@ func processBazelMetrics(bazelProfileFile string, bazelMetricsFile string, ctx C return } bazelProto := readBazelProto(bazelProfileFile) + bazelProto.ExitCode = proto.Int32(config.bazelExitCode) shared.Save(&bazelProto, bazelMetricsFile) } @@ -192,7 +193,7 @@ func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted t defer ctx.EndTrace() uploader := config.MetricsUploaderApp() - processBazelMetrics(bazelProfileFile, bazelMetricsFile, ctx) + processBazelMetrics(bazelProfileFile, bazelMetricsFile, ctx, config) if uploader == "" { // If the uploader path was not specified, no metrics shall be uploaded. diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go index 82d11ed30..a282e2030 100644 --- a/ui/metrics/metrics.go +++ b/ui/metrics/metrics.go @@ -228,7 +228,7 @@ func (m *Metrics) SetBuildDateTime(buildTimestamp time.Time) { m.metrics.BuildDateTimestamp = proto.Int64(buildTimestamp.UnixNano() / int64(time.Second)) } -func (m *Metrics) UpdateTotalRealTime(data []byte) error { +func (m *Metrics) UpdateTotalRealTimeAndNonZeroExit(data []byte, bazelExitCode int32) error { if err := proto.Unmarshal(data, &m.metrics); err != nil { return fmt.Errorf("Failed to unmarshal proto", err) } @@ -236,6 +236,9 @@ func (m *Metrics) UpdateTotalRealTime(data []byte) error { endTime := uint64(time.Now().UnixNano()) *m.metrics.Total.RealTime = *proto.Uint64(endTime - startTime) + + bazelError := bazelExitCode != 0 + m.metrics.NonZeroExit = proto.Bool(bazelError) return nil }