github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/mungegithub/mungers/nag-flake-issues.go (about)

     1  /*
     2  Copyright 2015 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 mungers
    18  
    19  import (
    20  	"time"
    21  
    22  	"github.com/google/go-github/github"
    23  	"k8s.io/kubernetes/pkg/util/sets"
    24  	"k8s.io/test-infra/mungegithub/features"
    25  	mgh "k8s.io/test-infra/mungegithub/github"
    26  	c "k8s.io/test-infra/mungegithub/mungers/matchers/comment"
    27  	"k8s.io/test-infra/mungegithub/mungers/mungerutil"
    28  	"k8s.io/test-infra/mungegithub/options"
    29  )
    30  
    31  const (
    32  	flakeNagNotifyName = "FLAKE-PING"
    33  	// defaultTimePeriod is priority/P1 (to get a human to prioritize)
    34  	defaultTimePeriod = 4 * 24 * time.Hour
    35  )
    36  
    37  var (
    38  	// Only include priorities that you care about. Others won't be pinged
    39  	timePeriods = map[string]time.Duration{
    40  		"priority/P0": 2 * 24 * time.Hour,
    41  		"priority/P1": 8 * 24 * time.Hour,
    42  		"priority/P2": time.Duration(1<<63 - 1),
    43  		"priority/P3": time.Duration(1<<63 - 1),
    44  	}
    45  )
    46  
    47  // NagFlakeIssues pings assignees on flaky-test issues
    48  type NagFlakeIssues struct {
    49  	botName string
    50  }
    51  
    52  var _ Munger = &NagFlakeIssues{}
    53  
    54  func init() {
    55  	n := &NagFlakeIssues{}
    56  	RegisterMungerOrDie(n)
    57  	RegisterStaleIssueComments(n)
    58  }
    59  
    60  // Name is the name usable in --pr-mungers
    61  func (NagFlakeIssues) Name() string { return "nag-flake-issues" }
    62  
    63  // RequiredFeatures is a slice of 'features' that must be provided
    64  func (NagFlakeIssues) RequiredFeatures() []string { return []string{} }
    65  
    66  // Initialize will initialize the munger
    67  func (n *NagFlakeIssues) Initialize(config *mgh.Config, features *features.Features) error {
    68  	n.botName = config.BotName
    69  	return nil
    70  }
    71  
    72  // EachLoop is called at the start of every munge loop
    73  func (NagFlakeIssues) EachLoop() error { return nil }
    74  
    75  // RegisterOptions registers options for this munger; returns any that require a restart when changed.
    76  func (NagFlakeIssues) RegisterOptions(opts *options.Options) sets.String { return nil }
    77  
    78  // findTimePeriod returns how often we should ping based on priority
    79  func findTimePeriod(labels []github.Label) time.Duration {
    80  	priorities := mgh.GetLabelsWithPrefix(labels, "priority/")
    81  	if len(priorities) == 0 {
    82  		return defaultTimePeriod
    83  	}
    84  	// If we have multiple priority labels (shouldn't happen), use the first one
    85  	period, ok := timePeriods[priorities[0]]
    86  	if !ok {
    87  		return defaultTimePeriod
    88  	}
    89  	return period
    90  }
    91  
    92  // Munge is the workhorse the will actually make updates to the PR
    93  func (n *NagFlakeIssues) Munge(obj *mgh.MungeObject) {
    94  	if obj.IsPR() || !obj.HasLabel("kind/flake") {
    95  		return
    96  	}
    97  
    98  	issueComments, ok := obj.ListComments()
    99  	if !ok {
   100  		return
   101  	}
   102  	comments := c.FromIssueComments(issueComments)
   103  
   104  	// Use the pinger to notify assignees:
   105  	// - Set time period based on configuration (at the top of this file)
   106  	// - Mention list of assignees as an argument
   107  	// - Start the ping timer after the last HumanActor comment
   108  
   109  	// How often should we ping
   110  	period := findTimePeriod(obj.Issue.Labels)
   111  
   112  	// Who are we pinging
   113  	who := mungerutil.GetIssueUsers(obj.Issue).Assignees.Mention().Join()
   114  	if who == "" {
   115  		return
   116  	}
   117  
   118  	// When does the pinger start
   119  	startDate := c.LastComment(comments, c.HumanActor(n.botName), obj.Issue.CreatedAt)
   120  
   121  	// Get a notification if it's time to ping.
   122  	notif := c.NewPinger(flakeNagNotifyName, n.botName).
   123  		SetDescription("This flaky-test issue would love to have more attention.").
   124  		SetTimePeriod(period).PingNotification(
   125  		comments,
   126  		who,
   127  		startDate,
   128  	)
   129  	if notif != nil {
   130  		obj.WriteComment(notif.String())
   131  	}
   132  }
   133  
   134  // StaleIssueComments returns a slice of stale issue comments.
   135  func (n *NagFlakeIssues) StaleIssueComments(obj *mgh.MungeObject, issueComments []*github.IssueComment) []*github.IssueComment {
   136  	comments := c.FromIssueComments(issueComments)
   137  	// Remove all pings written before the last human actor comment
   138  	filtered := c.FilterComments(comments, c.And([]c.Matcher{
   139  		c.MungerNotificationName(flakeNagNotifyName, n.botName),
   140  		c.CreatedBefore(*c.LastComment(comments, c.HumanActor(n.botName), &time.Time{})),
   141  	}))
   142  	issueCommentsFiltered := []*github.IssueComment{}
   143  	for _, comment := range filtered {
   144  		issueCommentsFiltered = append(issueCommentsFiltered, comment.Source.(*github.IssueComment))
   145  	}
   146  	return issueCommentsFiltered
   147  }