155 lines
4.6 KiB
Python
155 lines
4.6 KiB
Python
|
#!/usr/bin/env python3
|
||
|
# Copyright 2021 The Chromium Authors. All rights reserved.
|
||
|
# Use of this source code is governed by a BSD-style license that can be
|
||
|
# found in the LICENSE file.
|
||
|
# based on an almost identical script by: jyrki@google.com (Jyrki Alakuijala)
|
||
|
"""Updates the commit message used in the auto-roller.
|
||
|
|
||
|
Merges several small commit logs into a single more useful commit message.
|
||
|
|
||
|
Usage:
|
||
|
update_commit_message.py --old-revision=<sha1>
|
||
|
"""
|
||
|
|
||
|
import argparse
|
||
|
import logging
|
||
|
import os
|
||
|
import platform
|
||
|
import re
|
||
|
import shutil
|
||
|
import subprocess
|
||
|
import sys
|
||
|
import tempfile
|
||
|
|
||
|
GCLIENT_LINE = r'([^:]+): ([^@]+)@(.*)'
|
||
|
CHANGE_TEMPLATE = '* %s: %s.git/+log/%s..%s'
|
||
|
EXIT_SUCCESS = 0
|
||
|
EXIT_FAILURE = 1
|
||
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||
|
GCLIENT = """\
|
||
|
solutions = [{
|
||
|
'name': '.',
|
||
|
'url': 'https://chromium.googlesource.com/vulkan-deps.git',
|
||
|
'deps_file': 'DEPS',
|
||
|
'managed': False,
|
||
|
}]
|
||
|
"""
|
||
|
INSERT_NEEDLE = 'If this roll has caused a breakage'
|
||
|
|
||
|
|
||
|
def run(cmd, args):
|
||
|
exe = ('%s.bat' % cmd) if platform.system() == 'Windows' else cmd
|
||
|
cmd_args = [exe] + list(args)
|
||
|
return subprocess.check_output(cmd_args).decode('ascii').strip()
|
||
|
|
||
|
|
||
|
def git(*args):
|
||
|
return run('git', args)
|
||
|
|
||
|
|
||
|
def gclient(*args):
|
||
|
return run('gclient', args)
|
||
|
|
||
|
|
||
|
def parse_revinfo(output):
|
||
|
expr = re.compile(GCLIENT_LINE)
|
||
|
config = dict()
|
||
|
urls = dict()
|
||
|
for line in output.split('\n'):
|
||
|
match = expr.match(line.strip())
|
||
|
if match:
|
||
|
dep = match.group(1)
|
||
|
urls[dep] = match.group(2)
|
||
|
config[dep] = match.group(3)
|
||
|
return config, urls
|
||
|
|
||
|
|
||
|
def _local_commit_amend(commit_msg, dry_run):
|
||
|
logging.info('Amending changes to local commit.')
|
||
|
old_commit_msg = git('log', '-1', '--pretty=%B')
|
||
|
logging.debug('Existing commit message:\n%s\n', old_commit_msg)
|
||
|
insert_index = old_commit_msg.rfind(INSERT_NEEDLE)
|
||
|
if insert_index == -1:
|
||
|
logging.exception('"%s" not found in commit message.' % INSERT_NEEDLE)
|
||
|
|
||
|
new_commit_msg = old_commit_msg[:insert_index] + commit_msg + '\n\n' + old_commit_msg[insert_index:]
|
||
|
logging.debug('New commit message:\n%s\n', new_commit_msg)
|
||
|
if not dry_run:
|
||
|
with tempfile.NamedTemporaryFile(delete=False, mode="w") as ntf:
|
||
|
ntf.write(new_commit_msg)
|
||
|
ntf.close()
|
||
|
git('commit', '--amend', '--no-edit', '--file=%s' % ntf.name)
|
||
|
os.unlink(ntf.name)
|
||
|
|
||
|
|
||
|
def main(raw_args):
|
||
|
parser = argparse.ArgumentParser()
|
||
|
parser.add_argument('--old-revision', help='Old git revision in the roll.', required=True)
|
||
|
parser.add_argument(
|
||
|
'--dry-run',
|
||
|
help='Test out functionality without making changes.',
|
||
|
action='store_true',
|
||
|
default=False)
|
||
|
parser.add_argument(
|
||
|
'-v', '--verbose', help='Verbose debug logging.', action='store_true', default=False)
|
||
|
args = parser.parse_args(raw_args)
|
||
|
|
||
|
if args.verbose:
|
||
|
logging.basicConfig(level=logging.DEBUG)
|
||
|
else:
|
||
|
logging.basicConfig(level=logging.INFO)
|
||
|
|
||
|
cwd = os.getcwd()
|
||
|
|
||
|
os.chdir(SCRIPT_DIR)
|
||
|
old_deps_content = git('show', '%s:DEPS' % args.old_revision)
|
||
|
|
||
|
with tempfile.TemporaryDirectory() as tempdir:
|
||
|
os.chdir(tempdir)
|
||
|
|
||
|
# Add the gclientfile.
|
||
|
with open(os.path.join(tempdir, '.gclient'), 'w') as gcfile:
|
||
|
gcfile.write(GCLIENT)
|
||
|
gcfile.close()
|
||
|
|
||
|
# Get the current config.
|
||
|
shutil.copyfile(os.path.join(SCRIPT_DIR, 'DEPS'), os.path.join(tempdir, 'DEPS'))
|
||
|
gclient_head_output = gclient('revinfo')
|
||
|
|
||
|
# Get the prior config.
|
||
|
with open('DEPS', 'w') as deps:
|
||
|
deps.write(old_deps_content)
|
||
|
deps.close()
|
||
|
gclient_old_output = gclient('revinfo')
|
||
|
os.chdir(SCRIPT_DIR)
|
||
|
|
||
|
head_config, urls = parse_revinfo(gclient_head_output)
|
||
|
old_config, _ = parse_revinfo(gclient_old_output)
|
||
|
|
||
|
changed_deps = []
|
||
|
|
||
|
for dep, new_sha1 in head_config.items():
|
||
|
if dep in old_config:
|
||
|
old_sha1 = old_config[dep]
|
||
|
if new_sha1 != old_sha1:
|
||
|
dep_short = dep.replace('\\', '/').split('/')[0]
|
||
|
repo = urls[dep]
|
||
|
logging.debug('Found change: %s to %s' % (dep, new_sha1))
|
||
|
changed_deps.append(CHANGE_TEMPLATE %
|
||
|
(dep_short, repo, old_sha1[:10], new_sha1[:10]))
|
||
|
|
||
|
if not changed_deps:
|
||
|
print('No changed dependencies, early exit.')
|
||
|
return EXIT_SUCCESS
|
||
|
|
||
|
commit_msg = 'Changed dependencies:\n%s' % '\n'.join(sorted(changed_deps))
|
||
|
|
||
|
os.chdir(cwd)
|
||
|
_local_commit_amend(commit_msg, args.dry_run)
|
||
|
|
||
|
return EXIT_SUCCESS
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
sys.exit(main(sys.argv[1:]))
|