go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/bisection/util/bqutil/bq_util.go (about) 1 // Copyright 2023 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 bqutil contains utility functions for BigQuery. 16 package bqutil 17 18 import ( 19 "context" 20 21 "google.golang.org/protobuf/types/known/fieldmaskpb" 22 "google.golang.org/protobuf/types/known/timestamppb" 23 24 "go.chromium.org/luci/bisection/model" 25 bqpb "go.chromium.org/luci/bisection/proto/bq" 26 pb "go.chromium.org/luci/bisection/proto/v1" 27 "go.chromium.org/luci/bisection/util/datastoreutil" 28 "go.chromium.org/luci/bisection/util/protoutil" 29 buildbucketpb "go.chromium.org/luci/buildbucket/proto" 30 "go.chromium.org/luci/common/errors" 31 "go.chromium.org/luci/common/proto/mask" 32 ) 33 34 // TestFailureAnalysisToBqRow returns a TestAnalysisRow for a TestFailureAnalysis. 35 // This is very similar to TestFailureAnalysisToPb in protoutil, but we intentionally 36 // keep them separate because they are for 2 different purposes. 37 // It gives us the flexibility to change one without affecting the others. 38 func TestFailureAnalysisToBqRow(ctx context.Context, tfa *model.TestFailureAnalysis) (*bqpb.TestAnalysisRow, error) { 39 // Make sure that the analysis has ended. 40 if !tfa.HasEnded() { 41 return nil, errors.Reason("analysis %d has not ended", tfa.ID).Err() 42 } 43 result := &bqpb.TestAnalysisRow{ 44 Project: tfa.Project, 45 AnalysisId: tfa.ID, 46 CreatedTime: timestamppb.New(tfa.CreateTime), 47 StartTime: timestamppb.New(tfa.StartTime), 48 EndTime: timestamppb.New(tfa.EndTime), 49 Status: tfa.Status, 50 RunStatus: tfa.RunStatus, 51 Builder: &buildbucketpb.BuilderID{ 52 Project: tfa.Project, 53 Bucket: tfa.Bucket, 54 Builder: tfa.Builder, 55 }, 56 SampleBbid: tfa.FailedBuildID, 57 } 58 59 // Get test bundle. 60 bundle, err := datastoreutil.GetTestFailureBundle(ctx, tfa) 61 if err != nil { 62 return nil, errors.Annotate(err, "get test failure bundle").Err() 63 } 64 tfFieldMask := fieldmaskpb.FieldMask{ 65 Paths: []string{"*"}, 66 } 67 tfMask, err := mask.FromFieldMask(&tfFieldMask, &pb.TestFailure{}, false, false) 68 if err != nil { 69 return nil, errors.Annotate(err, "from field mask").Err() 70 } 71 72 result.TestFailures = protoutil.TestFailureBundleToPb(ctx, bundle, tfMask) 73 primary := bundle.Primary() 74 result.StartFailureRate = float32(primary.StartPositionFailureRate) 75 result.EndFailureRate = float32(primary.EndPositionFailureRate) 76 result.StartGitilesCommit = &buildbucketpb.GitilesCommit{ 77 Host: primary.Ref.GetGitiles().GetHost(), 78 Project: primary.Ref.GetGitiles().GetProject(), 79 Ref: primary.Ref.GetGitiles().GetRef(), 80 Id: tfa.StartCommitHash, 81 Position: uint32(primary.RegressionStartPosition), 82 } 83 result.EndGitilesCommit = &buildbucketpb.GitilesCommit{ 84 Host: primary.Ref.GetGitiles().GetHost(), 85 Project: primary.Ref.GetGitiles().GetProject(), 86 Ref: primary.Ref.GetGitiles().GetRef(), 87 Id: tfa.EndCommitHash, 88 Position: uint32(primary.RegressionEndPosition), 89 } 90 91 nsa, err := datastoreutil.GetTestNthSectionForAnalysis(ctx, tfa) 92 if err != nil { 93 return nil, errors.Annotate(err, "get test nthsection for analysis").Err() 94 } 95 if nsa != nil { 96 nsaFieldMask := fieldmaskpb.FieldMask{ 97 Paths: []string{"*"}, 98 } 99 nsaMask, err := mask.FromFieldMask(&nsaFieldMask, &pb.TestNthSectionAnalysisResult{}, false, false) 100 if err != nil { 101 return nil, errors.Annotate(err, "from field mask").Err() 102 } 103 104 nsaResult, err := protoutil.NthSectionAnalysisToPb(ctx, tfa, nsa, primary.Ref, nsaMask) 105 if err != nil { 106 return nil, errors.Annotate(err, "nthsection analysis to pb").Err() 107 } 108 result.NthSectionResult = nsaResult 109 culprit, err := datastoreutil.GetVerifiedCulpritForTestAnalysis(ctx, tfa) 110 if err != nil { 111 return nil, errors.Annotate(err, "get verified culprit").Err() 112 } 113 if culprit != nil { 114 culpritFieldMask := fieldmaskpb.FieldMask{ 115 Paths: []string{"*"}, 116 } 117 culpritMask, err := mask.FromFieldMask(&culpritFieldMask, &pb.TestCulprit{}, false, false) 118 if err != nil { 119 return nil, errors.Annotate(err, "from field mask").Err() 120 } 121 122 culpritPb, err := protoutil.CulpritToPb(ctx, culprit, nsa, culpritMask) 123 if err != nil { 124 return nil, errors.Annotate(err, "culprit to pb").Err() 125 } 126 result.Culprit = culpritPb 127 } 128 } 129 return result, nil 130 }