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))
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)
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)])
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)