git-mr-update: add checks for mr ref
authorFrantisek Hrbata <frantisek@hrbata.com>
Tue, 8 Dec 2020 16:56:11 +0000 (17:56 +0100)
committerFrantisek Hrbata <frantisek@hrbata.com>
Tue, 8 Dec 2020 16:56:11 +0000 (17:56 +0100)
Also extend the current checks for other refs.

Signed-off-by: Frantisek Hrbata <frantisek@hrbata.com>
git-mr-update

index f2a0971cacec3abb4624cc36e69779384b3f26e9..9b8a06d5adb2feacedf50c26158deb576f8eb171 100755 (executable)
@@ -41,7 +41,7 @@ if user in admins:
 if newrev == mrlib.rev_zero:
     sys.exit("You cannot delete ref '{}'.".format(refname))
 
-match = re.match("^refs/mrs/([0-9a-f]{40})/([^/]+)/(head|tags|mbox)$", refname)
+match = re.match("^refs/mrs/([0-9a-f]{40})/([^/]+)/(head|tags|mbox|mr)$", refname)
 if not match:
     sys.exit("You cannot push ref '{}'.".format(refname))
 
@@ -52,8 +52,8 @@ ref_type = match.group(3)
 if ref_user != user:
     sys.exit("User '{}' in ref '{}' does not match user '{}' on server.".format(ref_user, refname, user))
 
-if ref_type not in ["head", "tags", "mbox"]:
-    sys.exit("Invalid ref type '{}' in '{}'. Allowed types are 'head', 'tags' or 'mbox'.".format(ref_type, refname))
+if ref_type not in ["head", "tags", "mbox", "mr"]:
+    sys.exit("Invalid ref type '{}' in '{}'. Allowed types are 'head', 'tags', 'mr' or 'mbox'.".format(ref_type, refname))
 
 if oldrev != mrlib.rev_zero:
     rv, out, err = mrlib.run(["git", "merge-base", "--is-ancestor", oldrev, newrev], die=False)
@@ -74,6 +74,59 @@ if ref_type == "head":
     if out:
         sys.exit("MR head '{}' already exists as '{}'.".format(ref_mr, out))
 
+elif ref_type == "mr":
+    if oldrev != mrlib.rev_zero:
+        sys.exit("You are not allowed to update 'mr' ref '{}'.".format(refname))
+
+    rv, out, err = mrlib.run(["git", "for-each-ref", "--format=%(refname)",
+        "refs/mrs/{}/*/head".format(ref_mr)])
+    if not out:
+        sys.exit("No MR '{}' exists on server.".format(ref_mr))
+
+    match = re.match("^refs/mrs/{}/([^/]+)/head$".format(ref_mr), out)
+    mr_owner = match.group(1)
+
+    if user != mr_owner:
+        sys.exit("Only MR owner '{}' can push 'mr' ref.".format(mr_owner))
+
+    rv, out, err = mrlib.run(["git", "show", "{}:tags".format(newrev)])
+    tags = mrlib.load_user_tags(out, ref_mr, user)
+    mr_tags = mrlib.get_commit_tags(tags, ref_mr, mrlib.rev_zero)
+    if not mr_tags:
+        sys.exit("No MR tags found.")
+
+    for t in ["M", "B", "A", "C", "CC", "AN", "AE", "AT"]:
+        if t not in mr_tags:
+            sys.exit("Tag '{}' is required.".format(t))
+
+    author = mrlib.get_tag_value(mr_tags, "A")
+    if author != user:
+        sys.exit("A tag '{}' does not match user '{}'.".format(author, user))
+
+    mr = mrlib.get_tag_value(mr_tags, "M")
+    if mr != ref_mr:
+        sys.exit("M tag '{}' does not MR '{}'.".format(mr, ref_mr))
+
+    base = mrlib.get_tag_value(mr_tags, "B")
+    rv, out, err = mrlib.run(["git", "merge-base", "--is-ancestor", base, mr], die=False)
+    if rv:
+        sys.exit("B '{}' is not ancestor of M '{}'.".format(base, mr))
+
+    fmt = "--format=format:%H"
+    rv, out, err = mrlib.run(["git", "log", fmt, "{}..{}".format(base, mr)])
+    commits = list()
+    for commit in out.split("\n"):
+        commits.insert(0, commit)
+
+    mrcommits = mrlib.get_tag_value(mr_tags, "C")
+    if not mrcommits:
+        sys.exit("No MR commits found.")
+
+    mrcommits = mrcommits.split()
+
+    if commits != mrcommits:
+        sys.exit("Commits in repo do not match commits in C tag.")
+
 elif ref_type == "tags":
     rv, out, err = mrlib.run(["git", "for-each-ref", "--format=%(refname)",
         "refs/mrs/{}/*/head".format(ref_mr)])
@@ -84,16 +137,29 @@ elif ref_type == "tags":
     mr_owner = match.group(1)
 
     rv, out, err = mrlib.run(["git", "show", "{}:tags".format(newrev)])
-    tags = mrlib.load_user_tags(out)
+    tags = mrlib.load_user_tags(out, ref_mr, user)
 
     mr_tags = mrlib.get_commit_tags(tags, ref_mr, mrlib.rev_zero)
     if not mr_tags:
         sys.exit()
 
-    if user != mr_owner:
-        sys.exit("MR tags can be set by owners and admins only.")
+    for t in ["M", "B", "A", "C", "CC", "AN", "AE", "AT"]:
+        if t in mr_tags:
+            sys.exit("Tag '{}' is reserved and cannot be set.".format(t))
+
+    if user == mr_owner:
+        sys.exit()
+
+    for t in ["S", "D"]:
+        if t in mr_tags:
+            sys.exit("Tag '{}' can be set only by MR owner.".format(t))
 
 elif ref_type == "mbox":
+    rv, out, err = mrlib.run(["git", "for-each-ref", "--format=%(refname)",
+        "refs/mrs/{}/*/head".format(ref_mr)])
+    if not out:
+        sys.exit("No MR '{}' exists on server.".format(ref_mr))
+
     stdin = "{}\n".format(newrev)
     if oldrev != mrlib.rev_zero:
         stdin += "^{}\n".format(oldrev)