github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/prow/config/jobs.go (about)

     1  /*
     2  Copyright 2017 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 config
    18  
    19  import (
    20  	"regexp"
    21  	"time"
    22  
    23  	"k8s.io/test-infra/prow/kube"
    24  )
    25  
    26  // Presubmit is the job-specific trigger info.
    27  type Presubmit struct {
    28  	// eg kubernetes-pull-build-test-e2e-gce
    29  	Name string `json:"name"`
    30  	// Run for every PR, or only when a comment triggers it.
    31  	AlwaysRun bool `json:"always_run"`
    32  	// Run if the PR modifies a file that matches this regex.
    33  	RunIfChanged string `json:"run_if_changed"`
    34  	// Context line for GitHub status.
    35  	Context string `json:"context"`
    36  	// eg @k8s-bot e2e test this
    37  	Trigger string `json:"trigger"`
    38  	// Valid rerun command to give users. Must match Trigger.
    39  	RerunCommand string `json:"rerun_command"`
    40  	// Whether or not to skip commenting and setting status on GitHub.
    41  	SkipReport bool `json:"skip_report"`
    42  	// Maximum number of this job running concurrently, 0 implies no limit.
    43  	MaxConcurrency int `json:"max_concurrency"`
    44  	// Agent that will take care of running this job.
    45  	Agent string `json:"agent"`
    46  	// Kubernetes pod spec.
    47  	Spec *kube.PodSpec `json:"spec,omitempty"`
    48  	// Run these jobs after successfully running this one.
    49  	RunAfterSuccess []Presubmit `json:"run_after_success"`
    50  
    51  	Brancher
    52  
    53  	// We'll set these when we load it.
    54  	re        *regexp.Regexp // from Trigger.
    55  	reChanges *regexp.Regexp // from RunIfChanged
    56  }
    57  
    58  // Postsubmit runs on push events.
    59  type Postsubmit struct {
    60  	Name string `json:"name"`
    61  	// Agent that will take care of running this job.
    62  	Agent string `json:"agent"`
    63  	// Kubernetes pod spec.
    64  	Spec *kube.PodSpec `json:"spec,omitempty"`
    65  	// Maximum number of this job running concurrently, 0 implies no limit.
    66  	MaxConcurrency int `json:"max_concurrency"`
    67  
    68  	Brancher
    69  	// Run these jobs after successfully running this one.
    70  	RunAfterSuccess []Postsubmit `json:"run_after_success"`
    71  }
    72  
    73  // Periodic runs on a timer.
    74  type Periodic struct {
    75  	Name string `json:"name"`
    76  	// Agent that will take care of running this job.
    77  	Agent string `json:"agent"`
    78  	// Kubernetes pod spec.
    79  	Spec *kube.PodSpec `json:"spec,omitempty"`
    80  	// Interval to wait between two runs of the job.
    81  	Interval string   `json:"interval"`
    82  	Tags     []string `json:"tags,omitempty"`
    83  	// Run these jobs after successfully running this one.
    84  	RunAfterSuccess []Periodic `json:"run_after_success"`
    85  
    86  	interval time.Duration
    87  }
    88  
    89  func (p *Periodic) SetInterval(d time.Duration) {
    90  	p.interval = d
    91  }
    92  
    93  func (p *Periodic) GetInterval() time.Duration {
    94  	return p.interval
    95  }
    96  
    97  // Brancher is for shared code between jobs that only run against certain
    98  // branches. An empty brancher runs against all branches.
    99  type Brancher struct {
   100  	// Do not run against these branches. Default is no branches.
   101  	SkipBranches []string `json:"skip_branches"`
   102  	// Only run against these branches. Default is all branches.
   103  	Branches []string `json:"branches"`
   104  }
   105  
   106  func (br Brancher) RunsAgainstAllBranch() bool {
   107  	return len(br.SkipBranches) == 0 && len(br.Branches) == 0
   108  }
   109  
   110  func (br Brancher) RunsAgainstBranch(branch string) bool {
   111  	if br.RunsAgainstAllBranch() {
   112  		return true
   113  	}
   114  
   115  	// Favor SkipBranches over Branches
   116  	for _, s := range br.SkipBranches {
   117  		if s == branch {
   118  			return false
   119  		}
   120  	}
   121  	if len(br.Branches) == 0 {
   122  		return true
   123  	}
   124  	for _, b := range br.Branches {
   125  		if b == branch {
   126  			return true
   127  		}
   128  	}
   129  	return false
   130  }
   131  
   132  func (ps Presubmit) RunsAgainstChanges(changes []string) bool {
   133  	for _, change := range changes {
   134  		if ps.reChanges.MatchString(change) {
   135  			return true
   136  		}
   137  	}
   138  	return false
   139  }
   140  
   141  func matching(j Presubmit, body string, testAll bool) (out []Presubmit) {
   142  	if j.re.MatchString(body) || (testAll && j.AlwaysRun) {
   143  		out = append(out, j)
   144  	}
   145  
   146  	for _, child := range j.RunAfterSuccess {
   147  		out = append(out, matching(child, body, testAll)...)
   148  	}
   149  
   150  	return
   151  }
   152  
   153  func (c *Config) MatchingPresubmits(fullRepoName, body string, testAll *regexp.Regexp) []Presubmit {
   154  	var result []Presubmit
   155  	ott := testAll.MatchString(body)
   156  	if jobs, ok := c.Presubmits[fullRepoName]; ok {
   157  		for _, job := range jobs {
   158  			result = append(result, matching(job, body, ott)...)
   159  		}
   160  	}
   161  	return result
   162  }
   163  
   164  // RetestPresubmits returns all presubmits that should be run given a /retest command.
   165  // This is the set of all presubmits intersected with ((alwaysRun + runContexts) - skipContexts)
   166  func (c *Config) RetestPresubmits(fullRepoName string, skipContexts, runContexts map[string]bool) []Presubmit {
   167  	var result []Presubmit
   168  	if jobs, ok := c.Presubmits[fullRepoName]; ok {
   169  		for _, job := range jobs {
   170  			if (job.AlwaysRun || runContexts[job.Context]) && !skipContexts[job.Context] {
   171  				result = append(result, job)
   172  			}
   173  		}
   174  	}
   175  	return result
   176  }
   177  
   178  // GetPresubmit returns the presubmit job for the provided repo and job name.
   179  func (c *Config) GetPresubmit(repo, jobName string) *Presubmit {
   180  	presubmits := c.AllPresubmits([]string{repo})
   181  	for i := range presubmits {
   182  		ps := presubmits[i]
   183  		if ps.Name == jobName {
   184  			return &ps
   185  		}
   186  	}
   187  	return nil
   188  }
   189  
   190  func (c *Config) SetPresubmits(jobs map[string][]Presubmit) error {
   191  	nj := map[string][]Presubmit{}
   192  	for k, v := range jobs {
   193  		nj[k] = make([]Presubmit, len(v))
   194  		copy(nj[k], v)
   195  		for i := range v {
   196  			re, err := regexp.Compile(v[i].Trigger)
   197  			if err != nil {
   198  				return err
   199  			}
   200  			nj[k][i].re = re
   201  		}
   202  	}
   203  	c.Presubmits = nj
   204  	return nil
   205  }
   206  
   207  // AllPresubmits returns all prow presubmit jobs in repos.
   208  // if repos is empty, return all presubmits.
   209  func (c *Config) AllPresubmits(repos []string) []Presubmit {
   210  	var res []Presubmit
   211  	var listPres func(ps []Presubmit) []Presubmit
   212  	listPres = func(ps []Presubmit) []Presubmit {
   213  		var res []Presubmit
   214  		for _, p := range ps {
   215  			res = append(res, p)
   216  			res = append(res, listPres(p.RunAfterSuccess)...)
   217  		}
   218  		return res
   219  	}
   220  
   221  	for repo, v := range c.Presubmits {
   222  		if len(repos) == 0 {
   223  			res = append(res, listPres(v)...)
   224  		} else {
   225  			for _, r := range repos {
   226  				if r == repo {
   227  					res = append(res, listPres(v)...)
   228  					break
   229  				}
   230  			}
   231  		}
   232  	}
   233  
   234  	return res
   235  }
   236  
   237  // AllPostsubmits returns all prow postsubmit jobs in repos.
   238  // if repos is empty, return all postsubmits.
   239  func (c *Config) AllPostsubmits(repos []string) []Postsubmit {
   240  	var res []Postsubmit
   241  	var listPost func(ps []Postsubmit) []Postsubmit
   242  	listPost = func(ps []Postsubmit) []Postsubmit {
   243  		var res []Postsubmit
   244  		for _, p := range ps {
   245  			res = append(res, p)
   246  			res = append(res, listPost(p.RunAfterSuccess)...)
   247  		}
   248  		return res
   249  	}
   250  
   251  	for repo, v := range c.Postsubmits {
   252  		if len(repos) == 0 {
   253  			res = append(res, listPost(v)...)
   254  		} else {
   255  			for _, r := range repos {
   256  				if r == repo {
   257  					res = append(res, listPost(v)...)
   258  					break
   259  				}
   260  			}
   261  		}
   262  	}
   263  
   264  	return res
   265  }
   266  
   267  // AllPostsubmits returns all prow periodic jobs.
   268  func (c *Config) AllPeriodics() []Periodic {
   269  	var listPeriodic func(ps []Periodic) []Periodic
   270  	listPeriodic = func(ps []Periodic) []Periodic {
   271  		var res []Periodic
   272  		for _, p := range ps {
   273  			res = append(res, p)
   274  			res = append(res, listPeriodic(p.RunAfterSuccess)...)
   275  		}
   276  		return res
   277  	}
   278  
   279  	return listPeriodic(c.Periodics)
   280  }