|  | #!/usr/bin/env vpython3 | 
|  |  | 
|  | # Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. | 
|  | # | 
|  | # Use of this source code is governed by a BSD-style license | 
|  | # that can be found in the LICENSE file in the root of the source | 
|  | # tree. An additional intellectual property rights grant can be found | 
|  | # in the file PATENTS.  All contributing project authors may | 
|  | # be found in the AUTHORS file in the root of the source tree. | 
|  |  | 
|  | """Script to auto-update the WebRTC source version in call/version.cc""" | 
|  |  | 
|  | import argparse | 
|  | import datetime | 
|  | import logging | 
|  | import os | 
|  | import re | 
|  | import subprocess | 
|  | import sys | 
|  |  | 
|  |  | 
|  | UPDATE_BRANCH_NAME = 'webrtc_version_update' | 
|  | SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) | 
|  | CHECKOUT_SRC_DIR = os.path.realpath( | 
|  | os.path.join(SCRIPT_DIR, os.pardir, os.pardir)) | 
|  |  | 
|  | NOTIFY_EMAIL = 'webrtc-trooper@webrtc.org' | 
|  |  | 
|  |  | 
|  | def _remove_previous_update_branch(): | 
|  | active_branch, branches = _get_branches() | 
|  | if active_branch == UPDATE_BRANCH_NAME: | 
|  | active_branch = 'main' | 
|  | if UPDATE_BRANCH_NAME in branches: | 
|  | logging.info('Removing previous update branch (%s)', | 
|  | UPDATE_BRANCH_NAME) | 
|  | subprocess.check_call(['git', 'checkout', active_branch]) | 
|  | subprocess.check_call(['git', 'branch', '-D', UPDATE_BRANCH_NAME]) | 
|  | logging.info('No branch to remove') | 
|  |  | 
|  |  | 
|  | def _get_last_author(): | 
|  | """Returns a string with the author of the last commit.""" | 
|  | author = subprocess.check_output( | 
|  | ['git', 'log', '-1', '--pretty=format:"%an"'], | 
|  | universal_newlines=True).splitlines() | 
|  | return author | 
|  |  | 
|  |  | 
|  | def _get_branches(): | 
|  | """Returns a tuple (active, branches). | 
|  |  | 
|  | 'active' is a string with name of the currently active branch, while | 
|  | 'branches' is the list of all branches. | 
|  | """ | 
|  | lines = subprocess.check_output(['git', 'branch'], | 
|  | universal_newlines=True).splitlines() | 
|  | branches = [] | 
|  | active = '' | 
|  | for line in lines: | 
|  | if '*' in line: | 
|  | # The assumption is that the first char will always be the '*'. | 
|  | active = line[1:].strip() | 
|  | branches.append(active) | 
|  | else: | 
|  | branch = line.strip() | 
|  | if branch: | 
|  | branches.append(branch) | 
|  | return active, branches | 
|  |  | 
|  |  | 
|  | def _create_update_branch(): | 
|  | logging.info('Creating update branch: %s', UPDATE_BRANCH_NAME) | 
|  | subprocess.check_call(['git', 'checkout', '-b', UPDATE_BRANCH_NAME]) | 
|  |  | 
|  |  | 
|  | def _update_webrtc_version(filename): | 
|  | with open(filename, 'rb') as file: | 
|  | content = file.read().decode('utf-8') | 
|  | date = datetime.datetime.utcnow() | 
|  | # pylint: disable=line-too-long | 
|  | new_content = re.sub( | 
|  | r'WebRTC source stamp [0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}', | 
|  | r'WebRTC source stamp %02d-%02d-%02dT%02d:%02d:%02d' % | 
|  | (date.year, date.month, date.day, date.hour, date.minute, date.second), | 
|  | content, | 
|  | flags=re.MULTILINE) | 
|  | # pylint: enable=line-too-long | 
|  | with open(filename, 'wb') as file: | 
|  | file.write(new_content.encode('utf-8')) | 
|  |  | 
|  |  | 
|  | def _is_tree_clean(): | 
|  | stdout = subprocess.check_output(['git', 'status', '--porcelain'], | 
|  | universal_newlines=True) | 
|  | if len(stdout) == 0: | 
|  | return True | 
|  | return False | 
|  |  | 
|  |  | 
|  | def _local_commit(): | 
|  | logging.info('Committing changes locally.') | 
|  | date = datetime.datetime.utcnow() | 
|  |  | 
|  | msg = ('Update WebRTC code version (%02d-%02d-%02dT%02d:%02d:%02d).' | 
|  | '\n\nBug: None') | 
|  | msg = msg % (date.year, date.month, date.day, date.hour, date.minute, | 
|  | date.second) | 
|  | subprocess.check_call(['git', 'add', '--update', '.']) | 
|  | subprocess.check_call(['git', 'commit', '-m', msg]) | 
|  |  | 
|  |  | 
|  | def _upload_cl(commit_queue_mode): | 
|  | """Upload the committed changes as a changelist to Gerrit. | 
|  |  | 
|  | commit_queue_mode: | 
|  | - 2: Submit to commit queue. | 
|  | - 1: Run trybots but do not submit to CQ. | 
|  | - 0: Skip CQ, upload only. | 
|  | """ | 
|  | cmd = [ | 
|  | 'git', 'cl', 'upload', '--force', '--bypass-hooks', | 
|  | '--bypass-watchlist' | 
|  | ] | 
|  | if commit_queue_mode >= 2: | 
|  | logging.info('Sending the CL to the CQ...') | 
|  | cmd.extend(['-o', 'label=Bot-Commit+1']) | 
|  | cmd.extend(['-o', 'label=Commit-Queue+2']) | 
|  | cmd.extend(['--send-mail', '--cc', NOTIFY_EMAIL]) | 
|  | elif commit_queue_mode >= 1: | 
|  | logging.info('Starting CQ dry run...') | 
|  | cmd.extend(['-o', 'label=Commit-Queue+1']) | 
|  | subprocess.check_call(cmd) | 
|  |  | 
|  |  | 
|  | def main(): | 
|  | logging.basicConfig(level=logging.INFO) | 
|  | parser = argparse.ArgumentParser() | 
|  | parser.add_argument('--clean', | 
|  | action='store_true', | 
|  | default=False, | 
|  | help='Removes any previous local update branch.') | 
|  | opts = parser.parse_args() | 
|  |  | 
|  | if opts.clean: | 
|  | _remove_previous_update_branch() | 
|  |  | 
|  | if _get_last_author() == 'webrtc-version-updater': | 
|  | logging.info('Last commit is a version change, skipping CL.') | 
|  | return 0 | 
|  |  | 
|  | version_filename = os.path.join(CHECKOUT_SRC_DIR, 'call', 'version.cc') | 
|  | _create_update_branch() | 
|  | _update_webrtc_version(version_filename) | 
|  | if _is_tree_clean(): | 
|  | logging.info('No WebRTC version change detected, skipping CL.') | 
|  | else: | 
|  | _local_commit() | 
|  | logging.info('Uploading CL...') | 
|  | _upload_cl(2) | 
|  | return 0 | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | sys.exit(main()) |