github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/prow/gerrit/reporter/reporter.go (about) 1 /* 2 Copyright 2018 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 reporter implements a reporter interface for gerrit 18 package reporter 19 20 import ( 21 "fmt" 22 23 "github.com/sirupsen/logrus" 24 "k8s.io/apimachinery/pkg/labels" 25 26 "k8s.io/test-infra/prow/apis/prowjobs/v1" 27 pjlister "k8s.io/test-infra/prow/client/listers/prowjobs/v1" 28 "k8s.io/test-infra/prow/gerrit/client" 29 "k8s.io/test-infra/prow/kube" 30 ) 31 32 type gerritClient interface { 33 SetReview(instance, id, revision, message string, labels map[string]string) error 34 } 35 36 // Client is a gerrit reporter client 37 type Client struct { 38 gc gerritClient 39 lister pjlister.ProwJobLister 40 } 41 42 // NewReporter returns a reporter client 43 func NewReporter(cookiefilePath string, projects map[string][]string, lister pjlister.ProwJobLister) (*Client, error) { 44 gc, err := client.NewClient(projects) 45 if err != nil { 46 return nil, err 47 } 48 gc.Start(cookiefilePath) 49 return &Client{ 50 gc: gc, 51 lister: lister, 52 }, nil 53 } 54 55 // GetName returns the name of the reporter 56 func (c *Client) GetName() string { 57 return "gerrit-reporter" 58 } 59 60 // ShouldReport returns if this prowjob should be reported by the gerrit reporter 61 func (c *Client) ShouldReport(pj *v1.ProwJob) bool { 62 63 if pj.Status.State == v1.TriggeredState || pj.Status.State == v1.PendingState { 64 // not done yet 65 logrus.WithField("prowjob", pj.ObjectMeta.Name).Info("PJ not finished") 66 return false 67 } 68 69 // has gerrit metadata (scheduled by gerrit adapter) 70 if pj.ObjectMeta.Annotations[client.GerritID] == "" || 71 pj.ObjectMeta.Annotations[client.GerritInstance] == "" || 72 pj.ObjectMeta.Labels[client.GerritRevision] == "" { 73 logrus.WithField("prowjob", pj.ObjectMeta.Name).Info("Not a gerrit job") 74 return false 75 } 76 77 // Only report when all jobs of the same type on the same revision finished 78 selector := labels.Set{ 79 client.GerritRevision: pj.ObjectMeta.Labels[client.GerritRevision], 80 kube.ProwJobTypeLabel: pj.ObjectMeta.Labels[kube.ProwJobTypeLabel], 81 } 82 pjs, err := c.lister.List(selector.AsSelector()) 83 if err != nil { 84 logrus.WithError(err).Errorf("Cannot list prowjob with selector %v", selector) 85 return false 86 } 87 88 for _, pj := range pjs { 89 if pj.Status.State == v1.TriggeredState || pj.Status.State == v1.PendingState { 90 // other jobs are still running on this revision, skip report 91 logrus.WithField("prowjob", pj.ObjectMeta.Name).Info("Other jobs are still running on this revision") 92 return false 93 } 94 } 95 96 return true 97 } 98 99 // Report will send the current prowjob status as a gerrit review 100 func (c *Client) Report(pj *v1.ProwJob) error { 101 // If you are hitting here, which means the entire patchset has been finished :-) 102 103 clientGerritRevision := client.GerritRevision 104 clientGerritID := client.GerritID 105 clientGerritInstance := client.GerritInstance 106 pjTypeLabel := kube.ProwJobTypeLabel 107 108 // list all prowjobs in the patchset matching pj's type (pre- or post-submit) 109 selector := labels.Set{ 110 clientGerritRevision: pj.ObjectMeta.Labels[clientGerritRevision], 111 pjTypeLabel: pj.ObjectMeta.Labels[pjTypeLabel], 112 } 113 pjsOnRevision, err := c.lister.List(selector.AsSelector()) 114 if err != nil { 115 logrus.WithError(err).Errorf("Cannot list prowjob with selector %v", selector) 116 return err 117 } 118 119 // generate an aggregated report: 120 total := len(pjsOnRevision) 121 success := 0 122 message := "" 123 124 for _, pjOnRevision := range pjsOnRevision { 125 if pjOnRevision.Status.PrevReportStates[c.GetName()] == pjOnRevision.Status.State { 126 logrus.Infof("Revision %s has been reported already", pj.ObjectMeta.Labels[clientGerritRevision]) 127 return nil 128 } 129 130 if pjOnRevision.Status.State == v1.SuccessState { 131 success++ 132 } 133 134 message = fmt.Sprintf("%s\nJob %s finished with %s -- URL: %s", message, pjOnRevision.Spec.Job, pjOnRevision.Status.State, pjOnRevision.Status.URL) 135 } 136 137 message = fmt.Sprintf("%d out of %d jobs passed!\n%s", success, total, message) 138 139 // report back 140 gerritID := pj.ObjectMeta.Annotations[clientGerritID] 141 gerritInstance := pj.ObjectMeta.Annotations[clientGerritInstance] 142 gerritRevision := pj.ObjectMeta.Labels[clientGerritRevision] 143 reportLabel := client.CodeReview 144 if val, ok := pj.ObjectMeta.Labels[client.GerritReportLabel]; ok { 145 reportLabel = val 146 } 147 148 vote := client.LBTM 149 if success == total { 150 vote = client.LGTM 151 } 152 labels := map[string]string{reportLabel: vote} 153 154 logrus.Infof("Reporting to instance %s on id %s with message %s", gerritInstance, gerritID, message) 155 if err := c.gc.SetReview(gerritInstance, gerritID, gerritRevision, message, labels); err != nil { 156 logrus.WithError(err).Errorf("fail to set review with %s label on change ID %s", reportLabel, gerritID) 157 158 // possibly don't have label permissions, try without labels 159 message = fmt.Sprintf("[NOTICE]: Prow Bot cannot access %s label!\n%s", reportLabel, message) 160 if err := c.gc.SetReview(gerritInstance, gerritID, gerritRevision, message, nil); err != nil { 161 logrus.WithError(err).Errorf("fail to set plain review on change ID %s", gerritID) 162 return err 163 } 164 } 165 logrus.Infof("Review Complete") 166 167 return nil 168 }