From bcb6076bc67279ac451d5d0d3449bbc89c4830d6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20H=C3=B6ppner?= <jonas.hoeppner@garz-fricke.com>
Date: Fri, 6 May 2022 14:23:25 +0200
Subject: [PATCH] CI: Add check if integration branch is on top of target
 branch before reusing it

The integration branch was reused even if there where new commits on the
target branch, which could lead into reverting some changes.
This adds a check, if the existing integration branch is directly based
on the target branch and deletes it if not.
---
 .gitlab-ci.yml                               |  1 +
 check_if_integration_branch_is_up_to_date.py |  2 +-
 common.py                                    | 10 +++-
 deploy_gitlab_ci.py                          |  3 +-
 update_submodule.py                          | 51 +++++++++++++-------
 5 files changed, 46 insertions(+), 21 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index ce94903..2046a68 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -116,6 +116,7 @@ yamllint:
       --manifest-project=${MANIFEST_PROJECT}
       --submodule=.gitlab-ci
       --revision=${CI_COMMIT_SHA}
+      --verbose
       ${MERGE}
       ${INTEGRATE_INTO}
 
diff --git a/check_if_integration_branch_is_up_to_date.py b/check_if_integration_branch_is_up_to_date.py
index 460f331..42c2605 100755
--- a/check_if_integration_branch_is_up_to_date.py
+++ b/check_if_integration_branch_is_up_to_date.py
@@ -53,7 +53,7 @@ def check_if_integration_branch_is_up_to_date(
 
     # Loop over the commits until the integration_branch head id is found
     return common.is_commit_parent_of_project_commit(
-        manifest_project, integration_branch.commit["id"], integration_base_id
+        manifest_project, integration_branch.commit["id"], integration_base_id, limit=10
     )
 
 
diff --git a/common.py b/common.py
index 599ae3b..6e45da0 100755
--- a/common.py
+++ b/common.py
@@ -266,7 +266,9 @@ def get_repository_file_obj(project: Project, filename, ref=None):
     return fileobj
 
 
-def is_commit_parent_of_project_commit(project: Project, project_commit, commit):
+def is_commit_parent_of_project_commit(
+    project: Project, project_commit, commit, limit=None
+):
     """Walks through the commits of project, starting with project_commit
     and compares its sha with the given commit.
     Both commits are specified as sha
@@ -280,7 +282,13 @@ def is_commit_parent_of_project_commit(project: Project, project_commit, commit)
 
     # Loop over the parent commits until commit is found
     parent_id = project_commit
+    count = 0
     while True:
+        count = count + 1
+        if limit is not None and count >= limit:
+            logging.debug("Check %d commits and did not found a match.", count)
+            return False
+
         try:
             parent = project.commits.get(parent_id, retry_transient_errors=True)
         except GitlabGetError as e:
diff --git a/deploy_gitlab_ci.py b/deploy_gitlab_ci.py
index 127630c..2e52073 100755
--- a/deploy_gitlab_ci.py
+++ b/deploy_gitlab_ci.py
@@ -185,7 +185,7 @@ def main():
     project_integration = {}
     # Update submodule in all 'child' project
     for p in args.projects:
-        logging.debug("Integrate into: %s", p)
+        print("Create integration commit is: %s", p)
 
         res = integrate_submodule_into(
             gitlab, p, args.submodule, args.revision, args.branch
@@ -195,6 +195,7 @@ def main():
         if res["commit"] is not None:
             project_integration[p] = res
 
+    print("Create integration commit in: %s", args.project)
     # Update submodule in manifest project
     manifest_project = integrate_submodule_into(
         gitlab,
diff --git a/update_submodule.py b/update_submodule.py
index 1103d91..6c3f760 100755
--- a/update_submodule.py
+++ b/update_submodule.py
@@ -282,25 +282,40 @@ def update_submodule_and_include_ref(
             pass
 
         if existing_branch:
-            (
-                _,
-                integration_branch_submodule_rev,
-            ) = get_submodule_project_path_and_revision(
-                project, submodule_name, integration_branch_name
-            )
-            logging.debug(
-                "Revision in integration branch '%s', new_revision '%s'",
-                integration_branch_submodule_rev,
-                new_revision,
-            )
-
-            if integration_branch_submodule_rev == new_revision:
-                print(
-                    "Submodule is already at %s on branch %s"
-                    % (new_revision, integration_branch_name)
+            # Check if the integration branch is on top of the integration
+            # base or if it is outdated
+            integration_base_branch = project.branches.get(branch)
+            integration_base_id = integration_base_branch.commit["id"]
+            logging.debug("Head of %s points to %s", branch, integration_base_id)
+
+            # Loop over the commits until the integration_branch head id is found
+            if not common.is_commit_parent_of_project_commit(
+                project, existing_branch.commit["id"], integration_base_id, limit=5
+            ):
+                logging.debug("Integration branch is outdated, delete it.")
+                project.branches.delete(existing_branch.name)
+                existing_branch = None
+            else:
+                # Check the submodule revision on the integration branch
+                (
+                    _,
+                    integration_branch_submodule_rev,
+                ) = get_submodule_project_path_and_revision(
+                    project, submodule_name, integration_branch_name
                 )
-                integration_commit = existing_branch.commit["id"]
-                submodule_update_needed = False
+                logging.debug(
+                    "Revision in integration branch '%s', new_revision '%s'",
+                    integration_branch_submodule_rev,
+                    new_revision,
+                )
+
+                if integration_branch_submodule_rev == new_revision:
+                    print(
+                        "Submodule is already at %s on branch %s"
+                        % (new_revision, integration_branch_name)
+                    )
+                    integration_commit = existing_branch.commit["id"]
+                    submodule_update_needed = False
 
     # Clone the project, we need to do changes
     if submodule_update_needed or force_clone:
-- 
GitLab