diff options
Diffstat (limited to 'util/update_release_branch.py')
-rwxr-xr-x | util/update_release_branch.py | 354 |
1 files changed, 233 insertions, 121 deletions
diff --git a/util/update_release_branch.py b/util/update_release_branch.py index 0a871724fe..939d572dc4 100755 --- a/util/update_release_branch.py +++ b/util/update_release_branch.py @@ -42,11 +42,11 @@ def git_commit_msg(cros_main, branch, head, merge_head, rel_paths, cmd): A String containing the git commit message with the exception of the Signed-Off-By field and Change-ID field. """ - relevant_commits_cmd, relevant_commits = get_relevant_commits( + relevant_commits_cmd, relevant_commits, relevant_hdr = get_relevant_commits( head, merge_head, "--oneline", rel_paths ) - _, relevant_bugs = get_relevant_commits(head, merge_head, "", rel_paths) + _, relevant_bugs, _ = get_relevant_commits(head, merge_head, "", rel_paths) relevant_bugs = set(re.findall("BUG=(.*)", relevant_bugs)) # Filter out "none" from set of bugs filtered = [] @@ -65,7 +65,7 @@ Merge remote-tracking branch {CROS_MAIN} into {BRANCH} Generated by: {COMMAND_LINE} -Relevant changes: +{RELEVANT_COMMITS_HEADER} {RELEVANT_COMMITS_CMD} @@ -93,6 +93,7 @@ Force-Relevant-Builds: all BRANCH=branch, RELEVANT_COMMITS_CMD=relevant_commits_cmd, RELEVANT_COMMITS=relevant_commits, + RELEVANT_COMMITS_HEADER=relevant_hdr, BUG_FIELD=bug_field, COMMAND_LINE=cmd, ) @@ -135,8 +136,10 @@ def get_relevant_commits(head, merge_head, fmt, relevant_paths): Returns: A tuple containing the arguments passed to the git log command and - stdout. + stdout, and the header for the message """ + if not relevant_paths: + return "", "", "" if fmt: cmd = [ "git", @@ -156,7 +159,129 @@ def get_relevant_commits(head, merge_head, fmt, relevant_paths): proc = subprocess.run( cmd, stdout=subprocess.PIPE, encoding="utf-8", check=True, shell=True ) - return "".join(proc.args), proc.stdout + return "".join(proc.args), proc.stdout, "Relevant changes:" + + +def merge_repo( + base, cros_main, cmd_checkout, strategy, cmd, prunelist, relevant_paths +): + """Merge changes from ToT into this repo's branch. + + For this repo, merge the changes from ToT to the branch set + in the merge command. + + Args: + base: String indicating the Source directory of repo. + cros_main: String indicating the origin branch name + cmd_checkout: String list containing the checkout command to use. + strategy: String list containing the merge strategy, + cmd: String containing the command line + prunelist: String list containing the files to remove. + relevant_paths: String containing all the relevant paths for this + particular baseboard or board. + """ + # Change directory to the repo being merged + print('Starting merge in "%s"' % base) + print('Checkout command: "%s"' % " ".join(cmd_checkout)) + os.chdir(base) + # Check if we are already in merge process + result = subprocess.run( + ["git", "rev-parse", "--quiet", "--verify", "MERGE_HEAD"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + check=False, + ) + + if result.returncode: + # Let's perform the merge + print("Updating remote...") + subprocess.run(["git", "remote", "update"], check=True) + subprocess.run(cmd_checkout, check=True) + cmd_merge = [ + "git", + "merge", + "--no-ff", + "--no-commit", + cros_main, + "-s", + ] + cmd_merge.extend(strategy) + print('Merge command: "%s"' % " ".join(cmd_merge)) + try: + subprocess.run(cmd_merge, check=True) + except subprocess.CalledProcessError: + # We've likely encountered a merge conflict due to new OWNERS file + # modifications. If we're removing the owners, we'll delete them. + if prunelist: + # Find the unmerged files + unmerged = ( + subprocess.run( + ["git", "diff", "--name-only", "--diff-filter=U"], + stdout=subprocess.PIPE, + encoding="utf-8", + check=True, + ) + .stdout.rstrip() + .split() + ) + + # Prune OWNERS files + for file in unmerged: + if file in prunelist: + subprocess.run(["git", "rm", file], check=False) + unmerged.remove(file) + + print("Removed non-root OWNERS files.") + if unmerged: + print( + "Unmerged files still exist! You need to manually resolve this." + ) + print("\n".join(unmerged)) + sys.exit(1) + else: + raise + else: + print( + "We have already started merge process.", + "Attempt to generate commit.", + ) + # Check whether any commit is needed. + changes = subprocess.run( + ["git", "status", "--porcelain"], + stdout=subprocess.PIPE, + encoding="utf-8", + check=True, + ).stdout.rstrip() + if not changes: + print("No changes have been found, skipping commit.") + return + + print("Generating commit message...") + branch = subprocess.run( + ["git", "rev-parse", "--abbrev-ref", "HEAD"], + stdout=subprocess.PIPE, + encoding="utf-8", + check=True, + ).stdout.rstrip() + head = subprocess.run( + ["git", "rev-parse", "--short", "HEAD"], + stdout=subprocess.PIPE, + encoding="utf-8", + check=True, + ).stdout.rstrip() + merge_head = subprocess.run( + ["git", "rev-parse", "--short", "MERGE_HEAD"], + stdout=subprocess.PIPE, + encoding="utf-8", + check=True, + ).stdout.rstrip() + + print("Typing as fast as I can...") + commit_msg = git_commit_msg( + cros_main, branch, head, merge_head, relevant_paths, cmd + ) + subprocess.run(["git", "commit", "--signoff", "-m", commit_msg], check=True) + subprocess.run(["git", "commit", "--amend"], check=True) def main(argv): @@ -186,7 +311,11 @@ def main(argv): parser.add_argument("--baseboard") parser.add_argument("--board") parser.add_argument( - "release_branch", help=("The name of the target release" " branch") + "release_branch", + help=( + "The name of the target release branch, " + "without the trailing '-main'." + ), ) parser.add_argument( "--remote_prefix", @@ -197,6 +326,11 @@ def main(argv): default="cros", ) parser.add_argument( + "--srcbase", + help=("The base directory where the src tree exists."), + default="/mnt/host/source/", + ) + parser.add_argument( "--relevant_paths_file", help=( "A path to a text file which includes other " @@ -213,7 +347,7 @@ def main(argv): parser.add_argument( "--strategy_option", "-X", - help=("The strategy option for the chosen merge " "strategy"), + help=("The strategy option for the chosen merge strategy"), ) parser.add_argument( "--remove_owners", @@ -221,6 +355,12 @@ def main(argv): action=("store_true"), help=("Remove non-root OWNERS level files if present"), ) + parser.add_argument( + "--zephyr", + "-z", + action=("store_true"), + help=("If set, treat the board as a Zephyr based program"), + ) opts = parser.parse_args(argv[1:]) @@ -228,17 +368,24 @@ def main(argv): board_dir = "" if opts.baseboard: + # If a zephyr board, no baseboard allowed + if opts.zephyr: + raise Exception("--baseboard not allowed for Zephyr boards") # Dereference symlinks so "git log" works as expected. baseboard_dir = os.path.relpath("baseboard/" + opts.baseboard) baseboard_dir = os.path.relpath(os.path.realpath(baseboard_dir)) boards = get_relevant_boards(opts.baseboard) elif opts.board: - board_dir = os.path.relpath("board/" + opts.board) + if opts.zephyr: + board_dir = os.path.relpath("zephyr/program/" + opts.board) + else: + board_dir = os.path.relpath("board/" + opts.board) board_dir = os.path.relpath(os.path.realpath(board_dir)) boards = [opts.board] else: - boards = [] + # With no board or baseboard, not sure whether this should proceed + raise Exception("no board or baseboard specified") print("Gathering relevant paths...") relevant_paths = [] @@ -247,10 +394,12 @@ def main(argv): elif opts.board: relevant_paths.append(board_dir) - for board in boards: - relevant_paths.append("board/" + board) + if not opts.zephyr: + for board in boards: + relevant_paths.append("board/" + board) # Check for the existence of a file that has other paths of interest. + # Also check for 'relevant-paths.txt' in the board directory if opts.relevant_paths_file and os.path.exists(opts.relevant_paths_file): with open(opts.relevant_paths_file, "r") as relevant_paths_file: for line in relevant_paths_file: @@ -260,17 +409,9 @@ def main(argv): relevant_paths.append("util/getversion.sh") relevant_paths = " ".join(relevant_paths) - # Check if we are already in merge process - result = subprocess.run( - ["git", "rev-parse", "--quiet", "--verify", "MERGE_HEAD"], - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - check=False, - ) - # Prune OWNERS files if desired + prunelist = [] if opts.remove_owners: - prunelist = [] for root, dirs, files in os.walk("."): for name in dirs: if "build" in name: @@ -291,112 +432,83 @@ def main(argv): for path in prunelist: print(" " + path) - if result.returncode: - # Let's perform the merge - print("Updating remote...") - subprocess.run(["git", "remote", "update"], check=True) - subprocess.run( - [ - "git", - "checkout", - "-B", - opts.release_branch, - opts.remote_prefix + "/" + opts.release_branch, - ], - check=True, - ) - print("Attempting git merge...") - if opts.merge_strategy == "recursive" and not opts.strategy_option: - opts.strategy_option = "theirs" - print( - 'Using "%s" merge strategy' % opts.merge_strategy, - ( - "with strategy option '%s'" % opts.strategy_option - if opts.strategy_option - else "" - ), - ) - cros_main = opts.remote_prefix + "/" + "main" - arglist = [ + # Create the merge and checkout commands to use. + cmd_checkout = [ + "git", + "checkout", + "-B", + opts.release_branch, + opts.remote_prefix + "/" + opts.release_branch, + ] + if opts.merge_strategy == "recursive" and not opts.strategy_option: + opts.strategy_option = "theirs" + print( + 'Using "%s" merge strategy' % opts.merge_strategy, + ( + "with strategy option '%s'" % opts.strategy_option + if opts.strategy_option + else "" + ), + ) + cros_main = opts.remote_prefix + "/" + "main" + strategy = [ + opts.merge_strategy, + ] + if opts.strategy_option: + strategy.append("-X" + opts.strategy_option) + cmd = " ".join(argv) + + # Merge each of the repos + merge_repo( + os.path.join(opts.srcbase, "src/platform/ec"), + cros_main, + cmd_checkout, + strategy, + cmd, + prunelist, + relevant_paths, + ) + if opts.zephyr: + # Strip off any trailing -main or -master from branch name + if opts.release_branch.endswith("-main"): + opts.release_branch = opts.release_branch[:-5] + if opts.release_branch.endswith("-master"): + opts.release_branch = opts.release_branch[:-7] + cmd_checkout = [ "git", - "merge", - "--no-ff", - "--no-commit", - cros_main, - "-s", - opts.merge_strategy, + "checkout", + "-B", + opts.release_branch, + opts.remote_prefix + "/" + opts.release_branch, ] - if opts.strategy_option: - arglist.append("-X" + opts.strategy_option) - try: - subprocess.run(arglist, check=True) - except: - # We've likely encountered a merge conflict due to new OWNERS file - # modifications. If we're removing the owners, we'll delete them. - if opts.remove_owners and prunelist: - # Find the unmerged files - unmerged = ( - subprocess.run( - ["git", "diff", "--name-only", "--diff-filter=U"], - stdout=subprocess.PIPE, - encoding="utf-8", - check=True, - ) - .stdout.rstrip() - .split() - ) - - # Prune OWNERS files - for file in unmerged: - if file in prunelist: - subprocess.run(["git", "rm", file], check=False) - unmerged.remove(file) - - print("Removed non-root OWNERS files.") - if unmerged: - print( - "Unmerged files still exist! You need to manually resolve this." - ) - print("\n".join(unmerged)) - sys.exit(1) - else: - raise - else: - print( - "We have already started merge process.", - "Attempt to generate commit.", + prunelist = [] + if opts.remove_owners: + # Remove the top level OWNERS file from the list + # to avoid any conflict with the modified branch file. + prunelist.append("OWNERS") + merge_repo( + os.path.join(opts.srcbase, "src/third_party/zephyr/main"), + cros_main, + cmd_checkout, + strategy, + cmd, + prunelist, + [], + ) + # cmsis repo has different remote + cros_main = opts.remote_prefix + "/" + "chromeos-main" + merge_repo( + os.path.join(opts.srcbase, "src/third_party/zephyr/cmsis"), + cros_main, + cmd_checkout, + strategy, + cmd, + prunelist, + [], ) - - print("Generating commit message...") - branch = subprocess.run( - ["git", "rev-parse", "--abbrev-ref", "HEAD"], - stdout=subprocess.PIPE, - encoding="utf-8", - check=True, - ).stdout.rstrip() - head = subprocess.run( - ["git", "rev-parse", "--short", "HEAD"], - stdout=subprocess.PIPE, - encoding="utf-8", - check=True, - ).stdout.rstrip() - merge_head = subprocess.run( - ["git", "rev-parse", "--short", "MERGE_HEAD"], - stdout=subprocess.PIPE, - encoding="utf-8", - check=True, - ).stdout.rstrip() - - cmd = " ".join(argv) - print("Typing as fast as I can...") - commit_msg = git_commit_msg( - cros_main, branch, head, merge_head, relevant_paths, cmd - ) - subprocess.run(["git", "commit", "--signoff", "-m", commit_msg], check=True) - subprocess.run(["git", "commit", "--amend"], check=True) print( ( - "Finished! **Please review the commit to see if it's to your " + "Finished! **Please review the commit(s) to see if they're to your " "liking.**" ) ) |