github.com/zppinho/prow@v0.0.0-20240510014325-1738badeb017/pkg/gerrit/adapter/trigger.go (about) 1 /* 2 Copyright 2019 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package adapter 18 19 import ( 20 "strings" 21 "time" 22 23 "github.com/andygrunwald/go-gerrit" 24 "github.com/sirupsen/logrus" 25 "k8s.io/apimachinery/pkg/util/sets" 26 27 "sigs.k8s.io/prow/pkg/config" 28 "sigs.k8s.io/prow/pkg/gerrit/client" 29 "sigs.k8s.io/prow/pkg/pjutil" 30 ) 31 32 // presubmitContexts returns the set of failing and all job names contained in the reports. 33 func presubmitContexts(failed sets.Set[string], presubmits []config.Presubmit, logger logrus.FieldLogger) (sets.Set[string], sets.Set[string]) { 34 allContexts := sets.Set[string]{} 35 for _, presubmit := range presubmits { 36 allContexts.Insert(presubmit.Name) // TODO(fejta): context, not name 37 } 38 failedContexts := allContexts.Intersection(failed) 39 return failedContexts, allContexts 40 } 41 42 // currentMessages returns messages on the current revision after the specified time. 43 func currentMessages(change gerrit.ChangeInfo, since time.Time) []gerrit.ChangeMessageInfo { 44 var messages []gerrit.ChangeMessageInfo 45 want := change.Revisions[change.CurrentRevision].Number 46 for _, have := range change.Messages { 47 if have.RevisionNumber != want { 48 continue 49 } 50 if !have.Date.Time.After(since) { 51 continue 52 } 53 messages = append(messages, have) 54 } 55 return messages 56 } 57 58 func indicatesChangeFromDraftToActiveState(s string) bool { 59 return strings.HasSuffix(s, client.ReadyForReviewMessageFixed) || 60 strings.HasSuffix(s, client.ReadyForReviewMessageCustomizable) 61 } 62 63 // messageFilter returns filter that matches all /test all, /test foo, /retest comments since lastUpdate. 64 // 65 // The behavior of each message matches the behavior of pjutil.PresubmitFilter. 66 func messageFilter(messages []gerrit.ChangeMessageInfo, failingContexts, allContexts sets.Set[string], triggerTimes map[string]time.Time, logger logrus.FieldLogger) pjutil.Filter { 67 var filters []pjutil.Filter 68 contextGetter := func() (sets.Set[string], sets.Set[string], error) { 69 return failingContexts, allContexts, nil 70 } 71 for _, message := range messages { 72 // Use the PresubmitFilter before possibly adding the /test-all filter to ensure explicitly requested presubmits are forced to run. 73 filter, err := pjutil.PresubmitFilter(false, contextGetter, message.Message, logger) 74 if err != nil { 75 logger.WithError(err).WithField("message", message).Warn("failed to create presubmit filter") 76 continue 77 } 78 filters = append(filters, &timeAnnotationFilter{ 79 Filter: filter, 80 eventTime: message.Date.Time, 81 triggerTimes: triggerTimes, 82 }) 83 // If the Gerrit Change changed from draft to active state, trigger all 84 // presubmit Prow jobs. 85 if indicatesChangeFromDraftToActiveState(message.Message) { 86 filters = append(filters, &timeAnnotationFilter{ 87 Filter: pjutil.NewTestAllFilter(), 88 eventTime: message.Date.Time, 89 triggerTimes: triggerTimes, 90 }) 91 continue 92 } 93 } 94 95 return pjutil.NewAggregateFilter(filters) 96 } 97 98 // timeAnnotationFilter is a wrapper around a pjutil.Filter that records the eventTime in 99 // the triggerTimes map when the Filter returns a true 'shouldRun' value. 100 type timeAnnotationFilter struct { 101 pjutil.Filter // Delegate filter. Only override/wrap ShouldRun() for time annotation, use Name() directly. 102 eventTime time.Time // The time of the event. If the filter matches, use this time for annotation. 103 triggerTimes map[string]time.Time // This map is referenced by all timeAnnotationFilters for a single processing iteration. 104 } 105 106 func (taf *timeAnnotationFilter) ShouldRun(p config.Presubmit) (shouldRun bool, forcedToRun bool, defaultBehavior bool) { 107 shouldRun, forced, def := taf.Filter.ShouldRun(p) 108 if shouldRun { 109 taf.triggerTimes[p.Name] = taf.eventTime 110 } 111 return shouldRun, forced, def 112 }