Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/env python
      2 # Copyright 2014 The Chromium Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 """Rolls swarming_client.
      7 
      8 While it is currently hard coded for swarming_client/, it is potentially
      9 modifiable to allow different dependencies. Works only with git checkout and git
     10 dependencies.
     11 """
     12 
     13 import optparse
     14 import os
     15 import re
     16 import subprocess
     17 import sys
     18 
     19 SRC_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
     20 
     21 
     22 def is_pristine(root, merge_base='origin/master'):
     23   """Returns True is a git checkout is pristine."""
     24   cmd = ['git', 'diff', '--ignore-submodules', merge_base]
     25   return not (
     26       subprocess.check_output(cmd, cwd=root).strip() or
     27       subprocess.check_output(cmd + ['--cached'], cwd=root).strip())
     28 
     29 
     30 def roll(deps_dir, key, reviewer, bug):
     31   if not is_pristine(SRC_ROOT):
     32     print >> sys.stderr, 'Ensure %s is clean first.' % SRC_ROOT
     33     return 1
     34 
     35   full_dir = os.path.join(SRC_ROOT, deps_dir)
     36   head = subprocess.check_output(
     37       ['git', 'rev-parse', 'HEAD'], cwd=full_dir).strip()
     38   deps = os.path.join(SRC_ROOT, 'DEPS')
     39   with open(deps, 'rb') as f:
     40     deps_content = f.read()
     41 
     42   if not head in deps_content:
     43     print('Warning: %s is not checked out at the expected revision in DEPS' %
     44           deps_dir)
     45     # It happens if the user checked out a branch in the dependency by himself.
     46     # Fall back to reading the DEPS to figure out the original commit.
     47     for i in deps_content.splitlines():
     48       m = re.match(r'\s+"' + key + '": "([a-z0-9]{40})",', i)
     49       if m:
     50         head = m.group(1)
     51         break
     52     else:
     53       print >> sys.stderr, 'Expected to find commit %s for %s in DEPS' % (
     54           head, key)
     55       return 1
     56 
     57   print('Found old revision %s' % head)
     58 
     59   subprocess.check_call(['git', 'fetch', 'origin'], cwd=full_dir)
     60   master = subprocess.check_output(
     61       ['git', 'rev-parse', 'origin/master'], cwd=full_dir).strip()
     62   print('Found new revision %s' % master)
     63 
     64   if master == head:
     65     print('No revision to roll!')
     66     return 1
     67 
     68   commit_range = '%s..%s' % (head[:9], master[:9])
     69   logs = subprocess.check_output(
     70       ['git', 'log', commit_range, '--date=short', '--format=%ad %ae %s'],
     71       cwd=full_dir).strip()
     72   logs = logs.replace('@chromium.org', '')
     73   cmd = (
     74       'git log %s --date=short --format=\'%%ad %%ae %%s\' | '
     75       'sed \'s/@chromium\.org//\'') % commit_range
     76 
     77   msg = (
     78       'Roll %s/ to %s.\n'
     79       '\n'
     80       '$ %s\n'
     81       '%s\n\n'
     82       'R=%s\n'
     83       'BUG=%s') % (
     84           deps_dir,
     85           master,
     86           cmd,
     87           logs,
     88           reviewer,
     89           bug)
     90 
     91   print('Commit message:')
     92   print('\n'.join('    ' + i for i in msg.splitlines()))
     93   deps_content = deps_content.replace(head, master)
     94   with open(deps, 'wb') as f:
     95     f.write(deps_content)
     96   subprocess.check_call(['git', 'add', 'DEPS'], cwd=SRC_ROOT)
     97   subprocess.check_call(['git', 'commit', '-m', msg], cwd=SRC_ROOT)
     98   print('Run:')
     99   print('  git cl upl --send-mail')
    100   return 0
    101 
    102 
    103 def main():
    104   parser = optparse.OptionParser(description=sys.modules[__name__].__doc__)
    105   parser.add_option(
    106       '-r', '--reviewer', default='',
    107       help='To specify multiple reviewers, use comma separated list, e.g. '
    108            '-r joe,jack,john. Defaults to @chromium.org')
    109   parser.add_option('-b', '--bug', default='')
    110   options, args = parser.parse_args()
    111   if args:
    112     parser.error('Unknown argument %s' % args)
    113   if not options.reviewer:
    114     parser.error('Pass a reviewer right away with -r/--reviewer')
    115 
    116   reviewers = options.reviewer.split(',')
    117   for i, r in enumerate(reviewers):
    118     if not '@' in r:
    119       reviewers[i] = r + '@chromium.org'
    120 
    121   return roll(
    122       'tools/swarming_client',
    123       'swarming_revision',
    124       ','.join(reviewers),
    125       options.bug)
    126 
    127 
    128 if __name__ == '__main__':
    129   sys.exit(main())
    130