diff --git a/external_updater.py b/external_updater.py index 0ee2e86c879fcad591893d5c1e4223bbeb768c7d..bc464ac3439b3e025b67eab9c6746ef87cf76e24 100644 --- a/external_updater.py +++ b/external_updater.py @@ -26,9 +26,10 @@ import time from google.protobuf import text_format # pylint: disable=import-error -import fileutils from git_updater import GitUpdater from github_archive_updater import GithubArchiveUpdater +import fileutils +import git_utils import updater_utils @@ -79,6 +80,11 @@ def has_new_version(updater): return updater.get_current_version() != updater.get_latest_version() +def _message_for_calledprocesserror(error): + return '\n'.join([error.stdout.decode('utf-8'), + error.stderr.decode('utf-8')]) + + def check_update(proj_path): """Checks updates for a project. Prints result on console. @@ -104,11 +110,8 @@ def check_update(proj_path): err)) return (updater, str(err)) except subprocess.CalledProcessError as err: - msg = 'stdout: {}\nstderr: {}.'.format( - err.stdout, - err.stderr) - print('{} {}.'.format(color_string('Failed.', 'ERROR'), - msg)) + msg = _message_for_calledprocesserror(err) + print('{}\n{}'.format(msg, color_string('Failed.', 'ERROR'))) return (updater, msg) @@ -157,12 +160,42 @@ def check(args): def update(args): """Handler for update command.""" + try: + _do_update(args) + except subprocess.CalledProcessError as err: + msg = _message_for_calledprocesserror(err) + print('{}\n{}'.format(msg, color_string('Failed to upgrade.', 'ERROR'))) + + +TMP_BRANCH_NAME = 'tmp_auto_upgrade' + +def _do_update(args): updater, err = check_update(args.path) if updater is None: return - if has_new_version(updater) or args.force: - updater.update() + if not has_new_version(updater) and not args.force: + return + + full_path = fileutils.get_absolute_project_path(args.path) + if args.branch_and_commit: + git_utils.checkout(full_path, args.remote_name + '/master') + try: + git_utils.delete_branch(full_path, TMP_BRANCH_NAME) + except subprocess.CalledProcessError as err: + # Still continue if the branch doesn't exist. + pass + git_utils.start_branch(full_path, TMP_BRANCH_NAME) + + updater.update() + + if args.branch_and_commit: + msg = 'Upgrade {} to {}\n\nTest: None'.format( + args.path, updater.get_latest_version()) + git_utils.commit(full_path, msg) + + if args.push_change: + git_utils.push(full_path, args.remote_name) def parse_args(): @@ -201,6 +234,15 @@ def parse_args(): '--force', help='Run update even if there\'s no new version.', action='store_true') + update_parser.add_argument( + '--branch_and_commit', action='store_true', + help='Starts a new branch and commit changes.') + update_parser.add_argument( + '--push_change', action='store_true', + help='Pushes change to Gerrit.') + update_parser.add_argument( + '--remote_name', default='aosp', required=False, + help='Upstream remote name.') update_parser.set_defaults(func=update) return parser.parse_args() diff --git a/git_updater.py b/git_updater.py index 81ef922e46dc16a0975c94a299a25fdb6128a272..81ee93d5d6575140bc3790dd4b4eaf9421b1d5f7 100644 --- a/git_updater.py +++ b/git_updater.py @@ -135,7 +135,8 @@ class GitUpdater(): print('{} is {} commits behind of {}.'.format( self.merge_from, len(commits), upstream_branch)) - self._write_metadata(self.proj_path) print("Running `git merge {merge_branch}`..." .format(merge_branch=self.merge_from)) git_utils.merge(self.proj_path, self.merge_from) + self._write_metadata(self.proj_path) + git_utils.add_file(self.proj_path, 'METADATA') diff --git a/git_utils.py b/git_utils.py index 67f45008296269ea89d57b8776469807ea6df6f3..7b78b21362e619b7bcc8a766ca1d1dbb6bf64a32 100644 --- a/git_utils.py +++ b/git_utils.py @@ -18,9 +18,10 @@ import re import subprocess -def _run(cmd, cwd): +def _run(cmd, cwd, redirect=True): """Runs a command with stdout and stderr redirected.""" - return subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + out = subprocess.PIPE if redirect else None + return subprocess.run(cmd, stdout=out, stderr=out, check=True, cwd=cwd) @@ -117,4 +118,41 @@ def is_commit(commit): def merge(proj_path, branch): """Merges a branch.""" - _run(['git', 'merge', branch], cwd=proj_path) + try: + out = _run(['git', 'merge', branch, '--no-commit'], + cwd=proj_path) + except subprocess.CalledProcessError: + # Merge failed. Error is already written to console. + subprocess.run(['git', 'merge', '--abort'], cwd=proj_path) + raise + + +def add_file(proj_path, file_name): + """Stages a file.""" + _run(['git', 'add', file_name], cwd=proj_path) + + +def delete_branch(proj_path, branch_name): + """Force delete a branch.""" + _run(['git', 'branch', '-D', branch_name], cwd=proj_path) + + +def start_branch(proj_path, branch_name): + """Starts a new repo branch.""" + _run(['repo', 'start', branch_name], cwd=proj_path) + + +def commit(proj_path, message): + """Commits changes.""" + _run(['git', 'commit', '-m', message], cwd=proj_path) + + +def checkout(proj_path, branch_name): + """Checkouts a branch.""" + _run(['git', 'checkout', branch_name], cwd=proj_path) + + +def push(proj_path, remote_name): + """Pushes change to remote.""" + return _run(['git', 'push', remote_name, 'HEAD:refs/for/master'], + cwd=proj_path, redirect=False)