go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/resultdb/internal/services/testmetadataupdator/update_test_metadata.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 testmetadataupdator 16 17 import ( 18 "context" 19 "time" 20 21 "google.golang.org/protobuf/proto" 22 23 "go.chromium.org/luci/common/errors" 24 "go.chromium.org/luci/common/logging" 25 "go.chromium.org/luci/resultdb/internal/invocations" 26 "go.chromium.org/luci/resultdb/internal/invocations/graph" 27 "go.chromium.org/luci/resultdb/internal/tasks/taskspb" 28 pb "go.chromium.org/luci/resultdb/proto/v1" 29 "go.chromium.org/luci/server" 30 "go.chromium.org/luci/server/span" 31 "go.chromium.org/luci/server/tq" 32 ) 33 34 // TestMetadataTask describes how to route update test metadata task. 35 var TestMetadataTask = tq.RegisterTaskClass(tq.TaskClass{ 36 ID: "update-test-metadata", 37 Prototype: &taskspb.UpdateTestMetadata{}, 38 Kind: tq.Transactional, 39 Queue: "testmetadataupdator", 40 RoutingPrefix: "/internal/tasks/testmetadataupdator", 41 }) 42 43 // InitServer initializes a testmetadataupdator server. 44 func InitServer(srv *server.Server) { 45 // init() below takes care of everything. 46 } 47 48 func init() { 49 TestMetadataTask.AttachHandler(func(ctx context.Context, msg proto.Message) error { 50 task := msg.(*taskspb.UpdateTestMetadata) 51 return updateTestMetadata(ctx, invocations.ID(task.InvocationId)) 52 }) 53 } 54 55 // updateTestMetadata update the TestMetadata table with test results in the given invocation 56 // and invocations that inherit its commit source information. 57 func updateTestMetadata(ctx context.Context, invID invocations.ID) error { 58 inv, err := invocations.Read(span.Single(ctx), invID) 59 if err != nil { 60 return err 61 } 62 if inv.State != pb.Invocation_FINALIZED { 63 return errors.Reason("Invocation is not finalized %s", invID).Err() 64 } 65 if inv.SourceSpec == nil { 66 logging.Infof(ctx, "Skipping metadata ingestion for invocation %s, sourceSpec not available.", inv.Name) 67 return nil 68 } 69 70 source := inv.SourceSpec.Sources 71 if inv.SourceSpec.Inherit { 72 // Invocation with inherited sources will be processed with its including invocation. 73 logging.Infof(ctx, "Skipping metadata ingestion for invocation %s, sources are inherited.", inv.Name) 74 return nil 75 } 76 if source == nil { 77 logging.Infof(ctx, "Skipping metadata ingestion for invocation %s, sources not available.", inv.Name) 78 return nil 79 } 80 if len(source.Changelists) > 0 || source.IsDirty { 81 logging.Infof(ctx, "Skipping metadata ingestion for invocation %s, invocation has applied gerrit changes or dirty sources", inv.Name) 82 return nil 83 } 84 85 invIDs, err := graph.FindInheritSourcesDescendants(ctx, invID) 86 if err != nil { 87 return errors.Annotate(err, "find descendants invocation %s", invID).Err() 88 } 89 90 updator := newUpdator(source, invIDs, time.Now()) 91 return updator.run(ctx) 92 } 93 94 // Schedule schedules tasks for all the finalized invocations. 95 func Schedule(ctx context.Context, invID invocations.ID) error { 96 return tq.AddTask(ctx, &tq.Task{ 97 Title: string(invID), 98 Payload: &taskspb.UpdateTestMetadata{InvocationId: string(invID)}, 99 }) 100 }