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