1#!/usr/bin/env vpython3 2 3# Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. 4# 5# Use of this source code is governed by a BSD-style license 6# that can be found in the LICENSE file in the root of the source 7# tree. An additional intellectual property rights grant can be found 8# in the file PATENTS. All contributing project authors may 9# be found in the AUTHORS file in the root of the source tree. 10 11"""Script to auto-update the WebRTC source version in call/version.cc""" 12 13import argparse 14import datetime 15import logging 16import os 17import re 18import subprocess 19import sys 20 21 22def FindSrcDirPath(): 23 """Returns the abs path to the src/ dir of the project.""" 24 src_dir = os.path.dirname(os.path.abspath(__file__)) 25 while os.path.basename(src_dir) != 'src': 26 src_dir = os.path.normpath(os.path.join(src_dir, os.pardir)) 27 return src_dir 28 29 30UPDATE_BRANCH_NAME = 'webrtc_version_update' 31CHECKOUT_SRC_DIR = FindSrcDirPath() 32 33NOTIFY_EMAIL = '[email protected]' 34 35 36def _RemovePreviousUpdateBranch(): 37 active_branch, branches = _GetBranches() 38 if active_branch == UPDATE_BRANCH_NAME: 39 active_branch = 'main' 40 if UPDATE_BRANCH_NAME in branches: 41 logging.info('Removing previous update branch (%s)', UPDATE_BRANCH_NAME) 42 subprocess.check_call(['git', 'checkout', active_branch]) 43 subprocess.check_call(['git', 'branch', '-D', UPDATE_BRANCH_NAME]) 44 logging.info('No branch to remove') 45 46 47def _GetLastAuthor(): 48 """Returns a string with the author of the last commit.""" 49 author = subprocess.check_output( 50 ['git', 'log', '-1', '--pretty=format:"%an"'], 51 universal_newlines=True).splitlines() 52 return author 53 54 55def _GetBranches(): 56 """Returns a tuple (active, branches). 57 58 'active' is a string with name of the currently active branch, while 59 'branches' is the list of all branches. 60 """ 61 lines = subprocess.check_output(['git', 'branch'], 62 universal_newlines=True).splitlines() 63 branches = [] 64 active = '' 65 for line in lines: 66 if '*' in line: 67 # The assumption is that the first char will always be the '*'. 68 active = line[1:].strip() 69 branches.append(active) 70 else: 71 branch = line.strip() 72 if branch: 73 branches.append(branch) 74 return active, branches 75 76 77def _CreateUpdateBranch(): 78 logging.info('Creating update branch: %s', UPDATE_BRANCH_NAME) 79 subprocess.check_call(['git', 'checkout', '-b', UPDATE_BRANCH_NAME]) 80 81 82def _UpdateWebRTCVersion(filename): 83 with open(filename, 'rb') as f: 84 content = f.read().decode('utf-8') 85 d = datetime.datetime.utcnow() 86 # pylint: disable=line-too-long 87 new_content = re.sub( 88 r'WebRTC source stamp [0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}', 89 r'WebRTC source stamp %02d-%02d-%02dT%02d:%02d:%02d' % 90 (d.year, d.month, d.day, d.hour, d.minute, d.second), 91 content, 92 flags=re.MULTILINE) 93 # pylint: enable=line-too-long 94 with open(filename, 'wb') as f: 95 f.write(new_content.encode('utf-8')) 96 97 98def _IsTreeClean(): 99 stdout = subprocess.check_output(['git', 'status', '--porcelain'], 100 universal_newlines=True) 101 if len(stdout) == 0: 102 return True 103 return False 104 105 106def _LocalCommit(): 107 logging.info('Committing changes locally.') 108 d = datetime.datetime.utcnow() 109 110 commit_msg = ('Update WebRTC code version (%02d-%02d-%02dT%02d:%02d:%02d).' 111 '\n\nBug: None') 112 commit_msg = commit_msg % (d.year, d.month, d.day, d.hour, d.minute, d.second) 113 subprocess.check_call(['git', 'add', '--update', '.']) 114 subprocess.check_call(['git', 'commit', '-m', commit_msg]) 115 116 117def _UploadCL(commit_queue_mode): 118 """Upload the committed changes as a changelist to Gerrit. 119 120 commit_queue_mode: 121 - 2: Submit to commit queue. 122 - 1: Run trybots but do not submit to CQ. 123 - 0: Skip CQ, upload only. 124 """ 125 cmd = [ 126 'git', 'cl', 'upload', '--force', '--bypass-hooks', '--bypass-watchlist' 127 ] 128 if commit_queue_mode >= 2: 129 logging.info('Sending the CL to the CQ...') 130 cmd.extend(['-o', 'label=Bot-Commit+1']) 131 cmd.extend(['-o', 'label=Commit-Queue+2']) 132 cmd.extend(['--send-mail', '--cc', NOTIFY_EMAIL]) 133 elif commit_queue_mode >= 1: 134 logging.info('Starting CQ dry run...') 135 cmd.extend(['-o', 'label=Commit-Queue+1']) 136 subprocess.check_call(cmd) 137 138 139def main(): 140 logging.basicConfig(level=logging.INFO) 141 p = argparse.ArgumentParser() 142 p.add_argument('--clean', 143 action='store_true', 144 default=False, 145 help='Removes any previous local update branch.') 146 opts = p.parse_args() 147 148 if opts.clean: 149 _RemovePreviousUpdateBranch() 150 151 if _GetLastAuthor() == 'webrtc-version-updater': 152 logging.info('Last commit is a version change, skipping CL.') 153 return 0 154 155 version_filename = os.path.join(CHECKOUT_SRC_DIR, 'call', 'version.cc') 156 _CreateUpdateBranch() 157 _UpdateWebRTCVersion(version_filename) 158 if _IsTreeClean(): 159 logging.info('No WebRTC version change detected, skipping CL.') 160 else: 161 _LocalCommit() 162 logging.info('Uploading CL...') 163 _UploadCL(2) 164 return 0 165 166 167if __name__ == '__main__': 168 sys.exit(main()) 169