Home | History | Annotate | Download | only in bin
      1 #!/usr/bin/env python
      2 
      3 # Copyright 2017 Google Inc.
      4 #
      5 # Use of this source code is governed by a BSD-style license that can be
      6 # found in the LICENSE file.
      7 
      8 
      9 """Submit one or more try jobs."""
     10 
     11 
     12 import argparse
     13 import json
     14 import os
     15 import re
     16 import subprocess
     17 import sys
     18 import tempfile
     19 
     20 
     21 BUCKET_SKIA_PRIMARY = 'skia.primary'
     22 BUCKET_SKIA_INTERNAL = 'skia.internal'
     23 CHECKOUT_ROOT = os.path.realpath(os.path.join(
     24     os.path.dirname(os.path.abspath(__file__)), os.pardir))
     25 INFRA_BOTS = os.path.join(CHECKOUT_ROOT, 'infra', 'bots')
     26 JOBS_JSON = os.path.join(INFRA_BOTS, 'jobs.json')
     27 REPO_INTERNAL = 'https://skia.googlesource.com/internal_test.git'
     28 TMP_DIR = os.path.join(tempfile.gettempdir(), 'sktry')
     29 
     30 sys.path.insert(0, INFRA_BOTS)
     31 
     32 import update_meta_config
     33 import utils
     34 
     35 
     36 def get_jobs(repo):
     37   """Obtain the list of jobs from the given repo."""
     38   # Maintain a copy of the repo in the temp dir.
     39   if not os.path.isdir(TMP_DIR):
     40     os.mkdir(TMP_DIR)
     41   with utils.chdir(TMP_DIR):
     42     dirname = repo.split('/')[-1]
     43     if not os.path.isdir(dirname):
     44       subprocess.check_call([
     45           utils.GIT, 'clone', '--mirror', repo, dirname])
     46     with utils.chdir(dirname):
     47       subprocess.check_call([utils.GIT, 'remote', 'update'])
     48       jobs = json.loads(subprocess.check_output([
     49           utils.GIT, 'show', 'master:infra/bots/jobs.json']))
     50       return (BUCKET_SKIA_INTERNAL, jobs)
     51 
     52 
     53 def main():
     54   # Parse arguments.
     55   d = 'Helper script for triggering try jobs defined in %s.' % JOBS_JSON
     56   parser = argparse.ArgumentParser(description=d)
     57   parser.add_argument('--list', action='store_true', default=False,
     58                       help='Just list the jobs; do not trigger anything.')
     59   parser.add_argument('--internal', action='store_true', default=False,
     60                       help=('If set, include internal jobs. You must have '
     61                             'permission to view internal repos.'))
     62   parser.add_argument('job', nargs='?', default=None,
     63                       help='Job name or regular expression to match job names.')
     64   args = parser.parse_args()
     65 
     66   # Load and filter the list of jobs.
     67   jobs = []
     68   with open(JOBS_JSON) as f:
     69     jobs.append((BUCKET_SKIA_PRIMARY, json.load(f)))
     70   if args.internal:
     71     jobs.append(get_jobs(REPO_INTERNAL))
     72   jobs.extend(update_meta_config.CQ_INCLUDE_CHROMIUM_TRYBOTS)
     73   if args.job:
     74     filtered_jobs = []
     75     for bucket, job_list in jobs:
     76       filtered = [j for j in job_list if re.search(args.job, j)]
     77       if len(filtered) > 0:
     78         filtered_jobs.append((bucket, filtered))
     79     jobs = filtered_jobs
     80 
     81   # Display the list of jobs.
     82   if len(jobs) == 0:
     83     print 'Found no jobs matching "%s"' % repr(args.job)
     84     sys.exit(1)
     85   count = 0
     86   for bucket, job_list in jobs:
     87     count += len(job_list)
     88   print 'Found %d jobs:' % count
     89   for bucket, job_list in jobs:
     90     print '  %s:' % bucket
     91     for j in job_list:
     92       print '    %s' % j
     93   if args.list:
     94     return
     95 
     96   if count > 1:
     97     # Prompt before triggering jobs.
     98     resp = raw_input('\nDo you want to trigger these jobs? (y/n or i for '
     99                      'interactive): ')
    100     print ''
    101     if resp != 'y' and resp != 'i':
    102       sys.exit(1)
    103     if resp == 'i':
    104       filtered_jobs = []
    105       for bucket, job_list in jobs:
    106         new_job_list = []
    107         for j in job_list:
    108           incl = raw_input(('Trigger %s? (y/n): ' % j))
    109           if incl == 'y':
    110             new_job_list.append(j)
    111         if len(new_job_list) > 0:
    112           filtered_jobs.append((bucket, new_job_list))
    113       jobs = filtered_jobs
    114 
    115   # Trigger the try jobs.
    116   for bucket, job_list in jobs:
    117     cmd = ['git', 'cl', 'try', '-B', bucket]
    118     for j in job_list:
    119       cmd.extend(['-b', j])
    120     try:
    121       subprocess.check_call(cmd)
    122     except subprocess.CalledProcessError:
    123       # Output from the command will fall through, so just exit here rather than
    124       # printing a stack trace.
    125       sys.exit(1)
    126 
    127 
    128 if __name__ == '__main__':
    129   main()
    130