d7e55629a0
This eases the workflow for developers who don't use git-cl to upload changes, but it doesn't remove the dependency on git-cl for triggering try jobs. Doing so would require using the Buildbucket API directly, which we're not well set up to do in Python. Eventually we'll be forced to either migrate this tool to Python 3 or rewrite in Go, and at that point we can use the API clients we already use from Go code to remove the dependency on Depot Tools. Change-Id: I749007a2150cfeb2442643db6f2a01a7a56c10a4 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/298748 Commit-Queue: Eric Boren <borenet@google.com> Reviewed-by: Mike Klein <mtklein@google.com>
177 lines
5.8 KiB
Python
Executable File
177 lines
5.8 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
# Copyright 2017 Google Inc.
|
|
#
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
|
|
"""Submit one or more try jobs."""
|
|
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import urllib2
|
|
|
|
|
|
BUCKET_SKIA_PRIMARY = 'skia/skia.primary'
|
|
BUCKET_SKIA_INTERNAL = 'skia-internal/skia.internal'
|
|
INFRA_BOTS = os.path.join('infra', 'bots')
|
|
TASKS_JSON = os.path.join(INFRA_BOTS, 'tasks.json')
|
|
REPO_INTERNAL = 'https://skia.googlesource.com/internal_test.git'
|
|
TMP_DIR = os.path.join(tempfile.gettempdir(), 'sktry')
|
|
|
|
SKIA_ROOT = os.path.realpath(os.path.join(
|
|
os.path.dirname(os.path.abspath(__file__)), os.pardir))
|
|
SKIA_INFRA_BOTS = os.path.join(SKIA_ROOT, INFRA_BOTS)
|
|
sys.path.insert(0, SKIA_INFRA_BOTS)
|
|
|
|
import utils
|
|
|
|
|
|
def find_repo_root():
|
|
"""Find the root directory of the current repository."""
|
|
cwd = os.getcwd()
|
|
while True:
|
|
if os.path.isdir(os.path.join(cwd, '.git')):
|
|
return cwd
|
|
next_cwd = os.path.dirname(cwd)
|
|
if next_cwd == cwd:
|
|
raise Exception('Failed to find repo root!')
|
|
cwd = next_cwd
|
|
|
|
|
|
def get_jobs(repo):
|
|
"""Obtain the list of jobs from the given repo."""
|
|
# Maintain a copy of the repo in the temp dir.
|
|
if not os.path.isdir(TMP_DIR):
|
|
os.mkdir(TMP_DIR)
|
|
with utils.chdir(TMP_DIR):
|
|
dirname = repo.split('/')[-1]
|
|
if not os.path.isdir(dirname):
|
|
subprocess.check_call([
|
|
utils.GIT, 'clone', '--mirror', repo, dirname])
|
|
with utils.chdir(dirname):
|
|
subprocess.check_call([utils.GIT, 'remote', 'update'])
|
|
jobs = json.loads(subprocess.check_output([
|
|
utils.GIT, 'show', 'master:%s' % JOBS_JSON]))
|
|
return (BUCKET_SKIA_INTERNAL, jobs)
|
|
|
|
|
|
def main():
|
|
# Parse arguments.
|
|
d = 'Helper script for triggering try jobs.'
|
|
parser = argparse.ArgumentParser(description=d)
|
|
parser.add_argument('--list', action='store_true', default=False,
|
|
help='Just list the jobs; do not trigger anything.')
|
|
parser.add_argument('--internal', action='store_true', default=False,
|
|
help=('If set, include internal jobs. You must have '
|
|
'permission to view internal repos.'))
|
|
parser.add_argument('job', nargs='?', default=None,
|
|
help='Job name or regular expression to match job names.')
|
|
args = parser.parse_args()
|
|
|
|
# First, find the Gerrit issue number. If the change was uploaded using Depot
|
|
# Tools, this configuration will be present in the git config.
|
|
branch = subprocess.check_output(['git', 'branch', '--show-current']).rstrip()
|
|
if not branch:
|
|
print 'Not on any branch; cannot trigger try jobs.'
|
|
sys.exit(1)
|
|
branch_issue_config = 'branch.%s.gerritissue' % branch
|
|
try:
|
|
issue = subprocess.check_output([
|
|
'git', 'config', '--local', branch_issue_config])
|
|
except subprocess.CalledProcessError:
|
|
# Not using Depot Tools. Find the Change-Id line in the most recent commit
|
|
# and obtain the issue number using that.
|
|
print '"git cl issue" not set; searching for Change-Id footer.'
|
|
msg = subprocess.check_output(['git', 'log', '-n1', branch])
|
|
m = re.search('Change-Id: (I[a-f0-9]+)', msg)
|
|
if not m:
|
|
print ('No gerrit issue found in `git config --local %s` and no Change-Id'
|
|
' found in most recent commit message.')
|
|
sys.exit(1)
|
|
url = 'https://skia-review.googlesource.com/changes/%s' % m.groups()[0]
|
|
resp = urllib2.urlopen(url).read()
|
|
issue = str(json.loads('\n'.join(resp.splitlines()[1:]))['_number'])
|
|
print 'Setting "git cl issue %s"' % issue
|
|
subprocess.check_call(['git', 'cl', 'issue', issue])
|
|
# Load and filter the list of jobs.
|
|
jobs = []
|
|
tasks_json = os.path.join(find_repo_root(), TASKS_JSON)
|
|
with open(tasks_json) as f:
|
|
tasks_cfg = json.load(f)
|
|
skia_primary_jobs = []
|
|
for k, v in tasks_cfg['jobs'].iteritems():
|
|
skia_primary_jobs.append(k)
|
|
skia_primary_jobs.sort()
|
|
|
|
# TODO(borenet): This assumes that the current repo is associated with the
|
|
# skia.primary bucket. This will work for most repos but it would be better to
|
|
# look up the correct bucket to use.
|
|
jobs.append((BUCKET_SKIA_PRIMARY, skia_primary_jobs))
|
|
if args.internal:
|
|
jobs.append(get_jobs(REPO_INTERNAL))
|
|
if args.job:
|
|
filtered_jobs = []
|
|
for bucket, job_list in jobs:
|
|
filtered = [j for j in job_list if re.search(args.job, j)]
|
|
if len(filtered) > 0:
|
|
filtered_jobs.append((bucket, filtered))
|
|
jobs = filtered_jobs
|
|
|
|
# Display the list of jobs.
|
|
if len(jobs) == 0:
|
|
print 'Found no jobs matching "%s"' % repr(args.job)
|
|
sys.exit(1)
|
|
count = 0
|
|
for bucket, job_list in jobs:
|
|
count += len(job_list)
|
|
print 'Found %d jobs:' % count
|
|
for bucket, job_list in jobs:
|
|
print ' %s:' % bucket
|
|
for j in job_list:
|
|
print ' %s' % j
|
|
if args.list:
|
|
return
|
|
|
|
if count > 1:
|
|
# Prompt before triggering jobs.
|
|
resp = raw_input('\nDo you want to trigger these jobs? (y/n or i for '
|
|
'interactive): ')
|
|
print ''
|
|
if resp != 'y' and resp != 'i':
|
|
sys.exit(1)
|
|
if resp == 'i':
|
|
filtered_jobs = []
|
|
for bucket, job_list in jobs:
|
|
new_job_list = []
|
|
for j in job_list:
|
|
incl = raw_input(('Trigger %s? (y/n): ' % j))
|
|
if incl == 'y':
|
|
new_job_list.append(j)
|
|
if len(new_job_list) > 0:
|
|
filtered_jobs.append((bucket, new_job_list))
|
|
jobs = filtered_jobs
|
|
|
|
# Trigger the try jobs.
|
|
for bucket, job_list in jobs:
|
|
cmd = ['git', 'cl', 'try', '-B', bucket]
|
|
for j in job_list:
|
|
cmd.extend(['-b', j])
|
|
try:
|
|
subprocess.check_call(cmd)
|
|
except subprocess.CalledProcessError:
|
|
# Output from the command will fall through, so just exit here rather than
|
|
# printing a stack trace.
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|