go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/analysis/pbutil/resultdb.go (about) 1 // Copyright 2022 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 pbutil contains methods for manipulating LUCI Analysis protos. 16 package pbutil 17 18 import ( 19 "go.chromium.org/luci/resultdb/pbutil" 20 rdbpb "go.chromium.org/luci/resultdb/proto/v1" 21 22 pb "go.chromium.org/luci/analysis/proto/v1" 23 ) 24 25 // TestResultIDFromResultDB returns a LUCI Analysis TestResultId corresponding 26 // to the supplied ResultDB test result name. 27 // The format of name should be: 28 // "invocations/{INVOCATION_ID}/tests/{URL_ESCAPED_TEST_ID}/results/{RESULT_ID}". 29 func TestResultIDFromResultDB(name string) *pb.TestResultId { 30 return &pb.TestResultId{System: "resultdb", Id: name} 31 } 32 33 // VariantFromResultDB returns a LUCI Analysis Variant corresponding to the 34 // supplied ResultDB Variant. 35 func VariantFromResultDB(v *rdbpb.Variant) *pb.Variant { 36 if v == nil { 37 // Variant is optional in ResultDB. 38 return &pb.Variant{Def: make(map[string]string)} 39 } 40 return &pb.Variant{Def: v.Def} 41 } 42 43 // VariantToResultDB returns a ResultDB Variant corresponding to the 44 // supplied LUCI Analysis Variant. 45 func VariantToResultDB(v *pb.Variant) *rdbpb.Variant { 46 if v == nil { 47 return &rdbpb.Variant{Def: make(map[string]string)} 48 } 49 return &rdbpb.Variant{Def: v.Def} 50 } 51 52 // VariantHash returns a hash of the variant. 53 func VariantHash(v *pb.Variant) string { 54 return pbutil.VariantHash(VariantToResultDB(v)) 55 } 56 57 // StringPairFromResultDB returns a LUCI Analysis StringPair corresponding to 58 // the supplied ResultDB StringPair. 59 func StringPairFromResultDB(v []*rdbpb.StringPair) []*pb.StringPair { 60 pairs := []*pb.StringPair{} 61 for _, pair := range v { 62 pairs = append(pairs, &pb.StringPair{Key: pair.Key, Value: pair.Value}) 63 } 64 return pairs 65 } 66 67 // FailureReasonFromResultDB returns a LUCI Analysis FailureReason 68 // corresponding to the supplied ResultDB FailureReason. 69 func FailureReasonFromResultDB(fr *rdbpb.FailureReason) *pb.FailureReason { 70 if fr == nil { 71 return nil 72 } 73 return &pb.FailureReason{ 74 PrimaryErrorMessage: fr.PrimaryErrorMessage, 75 } 76 } 77 78 // SkipReasonFromResultDB returns a LUCI Analysis SkipReason 79 // corresponding to the supplied ResultDB SkipReason. 80 func SkipReasonFromResultDB(sr rdbpb.SkipReason) pb.SkipReason { 81 switch sr { 82 case rdbpb.SkipReason_AUTOMATICALLY_DISABLED_FOR_FLAKINESS: 83 return pb.SkipReason_AUTOMATICALLY_DISABLED_FOR_FLAKINESS 84 default: 85 return pb.SkipReason_SKIP_REASON_UNSPECIFIED 86 } 87 } 88 89 // TestMetadataFromResultDB converts a ResultDB TestMetadata to a LUCI Analysis 90 // TestMetadata. 91 func TestMetadataFromResultDB(rdbTmd *rdbpb.TestMetadata) *pb.TestMetadata { 92 if rdbTmd == nil { 93 return nil 94 } 95 96 tmd := &pb.TestMetadata{ 97 Name: rdbTmd.Name, 98 } 99 loc := rdbTmd.GetLocation() 100 if loc != nil { 101 tmd.Location = &pb.TestLocation{ 102 Repo: loc.Repo, 103 FileName: loc.FileName, 104 Line: loc.Line, 105 } 106 } 107 108 bugComponent := rdbTmd.BugComponent 109 if bugComponent != nil && bugComponent.System != nil { 110 tmd.BugComponent = &pb.BugComponent{} 111 switch v := bugComponent.System.(type) { 112 case *rdbpb.BugComponent_IssueTracker: 113 tmd.BugComponent.System = &pb.BugComponent_IssueTracker{ 114 IssueTracker: &pb.IssueTrackerComponent{ 115 ComponentId: v.IssueTracker.ComponentId, 116 }, 117 } 118 case *rdbpb.BugComponent_Monorail: 119 tmd.BugComponent.System = &pb.BugComponent_Monorail{ 120 Monorail: &pb.MonorailComponent{ 121 Project: v.Monorail.Project, 122 Value: v.Monorail.Value, 123 }, 124 } 125 } 126 } 127 128 return tmd 129 } 130 131 // TestResultStatusFromResultDB returns the LUCI Analysis test result status 132 // corresponding to the given ResultDB test result status. 133 func TestResultStatusFromResultDB(s rdbpb.TestStatus) pb.TestResultStatus { 134 switch s { 135 case rdbpb.TestStatus_ABORT: 136 return pb.TestResultStatus_ABORT 137 case rdbpb.TestStatus_CRASH: 138 return pb.TestResultStatus_CRASH 139 case rdbpb.TestStatus_FAIL: 140 return pb.TestResultStatus_FAIL 141 case rdbpb.TestStatus_PASS: 142 return pb.TestResultStatus_PASS 143 case rdbpb.TestStatus_SKIP: 144 return pb.TestResultStatus_SKIP 145 default: 146 return pb.TestResultStatus_TEST_RESULT_STATUS_UNSPECIFIED 147 } 148 } 149 150 // TestVerdictStatusFromResultDB returns the LUCI Analysis test verdict status 151 // corresponding to the given ResultDB test variant status. 152 func TestVerdictStatusFromResultDB(s rdbpb.TestVariantStatus) pb.TestVerdictStatus { 153 switch s { 154 case rdbpb.TestVariantStatus_EXONERATED: 155 return pb.TestVerdictStatus_EXONERATED 156 case rdbpb.TestVariantStatus_EXPECTED: 157 return pb.TestVerdictStatus_EXPECTED 158 case rdbpb.TestVariantStatus_FLAKY: 159 return pb.TestVerdictStatus_FLAKY 160 case rdbpb.TestVariantStatus_UNEXPECTED: 161 return pb.TestVerdictStatus_UNEXPECTED 162 case rdbpb.TestVariantStatus_UNEXPECTEDLY_SKIPPED: 163 return pb.TestVerdictStatus_UNEXPECTEDLY_SKIPPED 164 default: 165 return pb.TestVerdictStatus_TEST_VERDICT_STATUS_UNSPECIFIED 166 } 167 } 168 169 // ExonerationReasonFromResultDB converts a ResultDB ExonerationReason to a 170 // LUCI Analysis ExonerationReason. 171 func ExonerationReasonFromResultDB(s rdbpb.ExonerationReason) pb.ExonerationReason { 172 switch s { 173 case rdbpb.ExonerationReason_NOT_CRITICAL: 174 return pb.ExonerationReason_NOT_CRITICAL 175 case rdbpb.ExonerationReason_OCCURS_ON_MAINLINE: 176 return pb.ExonerationReason_OCCURS_ON_MAINLINE 177 case rdbpb.ExonerationReason_OCCURS_ON_OTHER_CLS: 178 return pb.ExonerationReason_OCCURS_ON_OTHER_CLS 179 case rdbpb.ExonerationReason_UNEXPECTED_PASS: 180 return pb.ExonerationReason_UNEXPECTED_PASS 181 default: 182 return pb.ExonerationReason_EXONERATION_REASON_UNSPECIFIED 183 } 184 } 185 186 // GitilesCommitFromResultDB returns the LUCI Analysis gitiles commit 187 // corresponding to a ResultDB gitiles commit. 188 func GitilesCommitFromResultDB(c *rdbpb.GitilesCommit) *pb.GitilesCommit { 189 return &pb.GitilesCommit{ 190 Host: c.Host, 191 Project: c.Project, 192 Ref: c.Ref, 193 CommitHash: c.CommitHash, 194 Position: c.Position, 195 } 196 } 197 198 // ChangelistFromResultDB returns the LUCI Analysis gerrit changelist 199 // corresponding to a ResultDB gerrit changelist. 200 func ChangelistFromResultDB(cl *rdbpb.GerritChange) *pb.GerritChange { 201 return &pb.GerritChange{ 202 Host: cl.Host, 203 Project: cl.Project, 204 Change: cl.Change, 205 Patchset: cl.Patchset, 206 } 207 } 208 209 // SourcesFromResultDB returns the LUCI Analysis source description 210 // corresponding to a ResultDB source description. 211 func SourcesFromResultDB(s *rdbpb.Sources) *pb.Sources { 212 result := &pb.Sources{ 213 GitilesCommit: GitilesCommitFromResultDB(s.GitilesCommit), 214 IsDirty: s.IsDirty, 215 } 216 for _, cl := range s.Changelists { 217 result.Changelists = append(result.Changelists, ChangelistFromResultDB(cl)) 218 } 219 return result 220 } 221 222 // GitilesCommitToResultDB returns the ResultDB gitiles commit 223 // corresponding to a LUCI Analysis gitiles commit. 224 func GitilesCommitToResultDB(c *pb.GitilesCommit) *rdbpb.GitilesCommit { 225 if c == nil { 226 return nil 227 } 228 return &rdbpb.GitilesCommit{ 229 Host: c.Host, 230 Project: c.Project, 231 Ref: c.Ref, 232 CommitHash: c.CommitHash, 233 Position: c.Position, 234 } 235 } 236 237 // ChangelistToResultDB returns the ResultDB gerrit changelist 238 // corresponding to a LUCI Analysis gerrit changelist. 239 func ChangelistToResultDB(cl *pb.GerritChange) *rdbpb.GerritChange { 240 if cl == nil { 241 return nil 242 } 243 return &rdbpb.GerritChange{ 244 Host: cl.Host, 245 Project: cl.Project, 246 Change: cl.Change, 247 Patchset: cl.Patchset, 248 } 249 } 250 251 // SourcesToResultDB returns the ResultDB source description 252 // corresponding to a LUCI Analysis source description. 253 func SourcesToResultDB(s *pb.Sources) *rdbpb.Sources { 254 if s == nil { 255 return nil 256 } 257 result := &rdbpb.Sources{ 258 GitilesCommit: GitilesCommitToResultDB(s.GitilesCommit), 259 IsDirty: s.IsDirty, 260 } 261 for _, cl := range s.Changelists { 262 result.Changelists = append(result.Changelists, ChangelistToResultDB(cl)) 263 } 264 return result 265 } 266 267 // SourceRefToResultDB returns a ResultDB SourceRef corresponding to the 268 // supplied LUCI Analysis SourceRef. 269 func SourceRefToResultDB(v *pb.SourceRef) *rdbpb.SourceRef { 270 if v == nil { 271 return nil 272 } 273 // Assert system should be Gitiles 274 if _, ok := v.System.(*pb.SourceRef_Gitiles); !ok { 275 panic("system should be gitiles") 276 } 277 return &rdbpb.SourceRef{ 278 System: &rdbpb.SourceRef_Gitiles{ 279 Gitiles: &rdbpb.GitilesRef{ 280 Host: v.GetGitiles().Host, 281 Project: v.GetGitiles().Project, 282 Ref: v.GetGitiles().Ref, 283 }, 284 }, 285 } 286 } 287 288 // SourceRefFromSources extracts a SourceRef from given sources. 289 // 290 // panics if the sources object is not valid. 291 func SourceRefFromSources(sources *pb.Sources) *pb.SourceRef { 292 return &pb.SourceRef{ 293 System: &pb.SourceRef_Gitiles{ 294 Gitiles: &pb.GitilesRef{ 295 Host: sources.GitilesCommit.Host, 296 Project: sources.GitilesCommit.Project, 297 Ref: sources.GitilesCommit.Ref, 298 }, 299 }, 300 } 301 } 302 303 // SourceRefHash returns a short hash of the source ref. 304 func SourceRefHash(sourceRef *pb.SourceRef) []byte { 305 return pbutil.SourceRefHash(SourceRefToResultDB(sourceRef)) 306 } 307 308 // SourcePosition returns the position along the source 309 // ref tested by the given sources. 310 // 311 // panics if the sources object is not valid. 312 func SourcePosition(sources *pb.Sources) int64 { 313 return sources.GitilesCommit.Position 314 }