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  }