findmissing: Determine base tag dynamically

We use the base tag of a given branch primarily to determine
the number of commits in that branch. So far, that means that
stable release candidates include all commits in the stable release,
not only the commits in the release candidates.

We can work around that by determining the base tag dynamically
and use the most recent tag for release candidates instead of using
the branch base tag. This reduces the number of release candidate patches
significantly and speeds up the code working on release candidates
(specifically the getopen script).

Test show that this patch reduces the 'git log' runtime for release
candidate branches significantly. At the same time, the time needed to
calculate the base tag increases, and the time needed for subject
matches decreases. Overall, the time needed for calculating the base tag,
getting the list of commits in a branch, and searching for subject
matches in that branch is reduced by more than 50% for a typical run
of the 'getopen' tool. This plus the previous patch reduce patches robot
runtime by approximately 15%.

BUG=b:177099511
TEST=Run getopen tool

Change-Id: I8b168210890e5be735609aaa5a71d4d709dc0ad1
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/dev-util/+/2651796
Reviewed-by: Curtis Malainey <cujomalainey@chromium.org>
Commit-Queue: Guenter Roeck <groeck@chromium.org>
Tested-by: Guenter Roeck <groeck@chromium.org>
diff --git a/contrib/findmissing/git_interface.py b/contrib/findmissing/git_interface.py
index 96152be..3f1c1f0 100755
--- a/contrib/findmissing/git_interface.py
+++ b/contrib/findmissing/git_interface.py
@@ -173,7 +173,6 @@
         if not branch:
             branch = self.metadata.branches[0]
         self.branch = branch
-        self.merge_base = self.metadata.tag_template % branch
         self.branchname = self.metadata.get_kernel_branch(branch)
         self.path = common.get_kernel_absolute_path(self.metadata.path)
         self.status = 'unknown'
@@ -185,6 +184,19 @@
         current_branch_cmd = ['symbolic-ref', '-q', '--short', 'HEAD']
         self.current_branch = self.__git_check_output(current_branch_cmd).rstrip()
 
+    def __base_tag(self):
+        """Return base tag for selected branch
+
+        The base tag is derived from the tag template in metadata or,
+        if the tag template is empty, from the most recent tag in the
+        selected branch.
+        """
+        if self.metadata.tag_template:
+            return self.metadata.tag_template % self.branch
+        # Pick base tag from most recent tag in branch (self.branchname)
+        cmd = ['describe', '--abbrev=0', self.branchname]
+        return self.__git_check_output(cmd).rstrip()
+
     def __git_command(self, command):
         return ['git', '-C', self.path] + command
 
@@ -231,7 +243,6 @@
         """
         if branch and branch != self.branch:
             self.branch = branch
-            self.merge_base = self.metadata.tag_template % branch
             self.branchname = self.metadata.get_kernel_branch(branch)
             self.status = 'unknown'
 
@@ -256,7 +267,7 @@
         commit_list = self.commit_list[self.kernel]
         if self.branch not in commit_list:
             cmd = ['log', '--no-merges', '--format=%s',
-                   '%s..%s' % (self.merge_base, self.branchname)]
+                   '%s..%s' % (self.__base_tag(), self.branchname)]
             subjects = self.__git_check_output(cmd)
             commit_list[self.branch] = subjects.splitlines()