From 5e3ffb237385bc1dbdff739521b14fb5c25d30ee Mon Sep 17 00:00:00 2001
From: Emanuele Aina <emanuele.aina@collabora.com>
Date: Sat, 13 Mar 2021 23:48:22 +0100
Subject: [PATCH] pkg-merge-upstream-to-downstream: Streamline the loop

Refactor the code to reduce the amount of state carried across loop
iterations and to reduce the nesting of conditionals, so that it's
hopefully easier to understand and modify.

Signed-off-by: Emanuele Aina <emanuele.aina@collabora.com>
---
 .../apertis-pkg-merge-upstream-to-downstreams | 67 +++++++++++--------
 1 file changed, 39 insertions(+), 28 deletions(-)

diff --git a/package-source-builder/overlay/usr/bin/apertis-pkg-merge-upstream-to-downstreams b/package-source-builder/overlay/usr/bin/apertis-pkg-merge-upstream-to-downstreams
index 1428651..862c5e1 100755
--- a/package-source-builder/overlay/usr/bin/apertis-pkg-merge-upstream-to-downstreams
+++ b/package-source-builder/overlay/usr/bin/apertis-pkg-merge-upstream-to-downstreams
@@ -12,6 +12,7 @@ from sh.contrib import git
 from sh import apertis_pkg_merge_updates
 import re
 from pathlib import Path
+from functools import partial
 
 def parse_ref(ref: str) -> str:
     return git('rev-parse', '-q', '--verify', ref + '^{commit}', _ok_code=[0, 1]).strip('\n')
@@ -74,41 +75,51 @@ def main():
   local_suffix = args.local_suffix
 
   for upstream_branch in existing_upstream_branches(upstream):
-   # Mapping of downstream reference to proposed updates
-   known_refs = {}
    for downstream in downstreams:
     downstream_branch = get_matching_downstream_branch(downstream, upstream_branch)
 
-    # Skip branch not set
     if not downstream_branch:
-        continue
+      print(f"No branch for downstream {downstream}, skipping")
+      continue
 
     print(f"Looking at {downstream_branch} <- {upstream_branch}")
-    git.checkout(downstream_branch)
-    ref = git("rev-parse", "HEAD").rstrip()
-    known = known_refs.get(ref)
-
-    if known == None:
-      print("New target, doing merge")
-      proposed_branch = f"proposed-updates/{upstream_branch}/{ref[0:8]}"
-      git.checkout("-B", proposed_branch)
-      apertis_pkg_merge_updates(f"--downstream={downstream_branch}", f"--upstream={upstream_branch}", f"--local-version-suffix={local_suffix}", _fg=True)
-      o = git('diff', '--quiet', f"HEAD..{downstream_branch}", _ok_code=[0,1])
-      if o.exit_code == 1:
-        print("Merge done, pushing")
-        push_merge_request(args.project_url, proposed_branch, upstream_branch, downstream_branch)
-        known_refs[ref] = proposed_branch
-      else:
-        print("No merge required, skipping")
-        known_refs[ref] = ""
-    else:
-      if known == "":
-        print("Known target ref, Nothing required, skipping")
-        continue
 
-      # Check out known pre-pushed merge, and push that as an MR to the target
-      print("Known target, pushing merge request")
-      push_merge_request(args.project_url, known, upstream_branch, downstream_branch)
+    if git("merge-base", "--is-ancestor", upstream_branch, downstream_branch, _ok_code=[0,1]).exit_code == 0:
+      print(f"Upstream branch {upstream_branch} already merged into {downstream_branch}, no merge required")
+      continue
+
+    ref = git("rev-parse", downstream_branch).rstrip()
+    proposed_branch = f"proposed-updates/{upstream_branch}/{ref[0:8]}"
+
+    push_this_merge_request = partial(push_merge_request, args.project_url, proposed_branch, upstream_branch, downstream_branch)
+
+    # check if we have a proposed branch from a previous iteration
+    if git("rev-parse", "--verify", proposed_branch, _ok_code=[0, 128]).strip():
+      # handle the case where two downstreams are at the same commit and have
+      # the same upstream, so they should share the proposed branch
+      # for instance, if both v2021 and v2020 are at rev badf00d and are based
+      # on buster:
+      # 1. process v2021 and create proposed-updates/debian/buster/badf00d,
+      #    submit a MR from proposed-updates/debian/buster/badf00d
+      #    to apertis/v2021
+      # 1. process v2020 and re-use proposed-updates/debian/buster/badf00d to
+      #    submit a MR from proposed-updates/debian/buster/badf00d
+      #    to apertis/v2020
+      print(f"Reusing branch {proposed_branch} to be merged into {downstream_branch}")
+      push_this_merge_request()
+      continue
+
+    print(f"Attempt merging {upstream_branch} into {downstream_branch} via {proposed_branch}")
+    git("checkout", "--force", "-B", "tmp", downstream_branch)
+    apertis_pkg_merge_updates(f"--downstream={downstream_branch}", f"--upstream={upstream_branch}", f"--local-version-suffix={local_suffix}", _fg=True)
+    o = git('diff', '--quiet', f"HEAD..{downstream_branch}", _ok_code=[0,1])
+    if o.exit_code == 0:
+      print(f"No merge required for {downstream_branch}, skipping ")
+      continue
+
+    print("Merge done, pushing {proposed_branch} to update the existing MR")
+    git("branch", "--force", proposed_branch, "HEAD")
+    push_this_merge_request()
 
 if __name__ == '__main__':
   main()
-- 
GitLab