codereview: add release branch support

Note that if you are working on the upcoming release
branch you have to point your extension path to a
copy of lib/codereview/codereview.py that won't change
as the repository flips between release-branch and default branch.
This warning should only apply to this one branch and only to rsc,
but you never know.

R=adg
CC=golang-dev
https://golang.org/cl/4446076
This commit is contained in:
Russ Cox 2011-05-03 10:39:11 -04:00
parent 86e6a44112
commit 35a37f1735

View file

@ -112,6 +112,7 @@ defaultcc = None
contributors = {}
missing_codereview = None
real_rollback = None
releaseBranch = None
#######################################################################
# RE: UNICODE STRING HANDLING
@ -1049,7 +1050,7 @@ def change(ui, repo, *pats, **opts):
if missing_codereview:
return missing_codereview
dirty = {}
if len(pats) > 0 and GoodCLName(pats[0]):
name = pats[0]
@ -1062,6 +1063,8 @@ def change(ui, repo, *pats, **opts):
if not cl.local and (opts["stdin"] or not opts["stdout"]):
return "cannot change non-local CL " + name
else:
if repo[None].branch() != "default":
return "cannot run hg change outside default branch"
name = "new"
cl = CL("new")
dirty[cl] = True
@ -1154,7 +1157,9 @@ def clpatch(ui, repo, clname, **opts):
Submitting an imported patch will keep the original author's
name as the Author: line but add your own name to a Committer: line.
"""
return clpatch_or_undo(ui, repo, clname, opts)
if repo[None].branch() != "default":
return "cannot run hg clpatch outside default branch"
return clpatch_or_undo(ui, repo, clname, opts, mode="clpatch")
def undo(ui, repo, clname, **opts):
"""undo the effect of a CL
@ -1163,7 +1168,66 @@ def undo(ui, repo, clname, **opts):
After creating the CL, opens the CL text for editing so that
you can add the reason for the undo to the description.
"""
return clpatch_or_undo(ui, repo, clname, opts, undo=True)
if repo[None].branch() != "default":
return "cannot run hg undo outside default branch"
return clpatch_or_undo(ui, repo, clname, opts, mode="undo")
def release_apply(ui, repo, clname, **opts):
"""apply a CL to the release branch
Creates a new CL copying a previously committed change
from the main branch to the release branch.
The current client must either be clean or already be in
the release branch.
The release branch must be created by starting with a
clean client, disabling the code review plugin, and running:
hg update weekly.YYYY-MM-DD
hg branch release-branch.rNN
hg commit -m 'create release-branch.rNN'
hg push --new-branch
Then re-enable the code review plugin.
People can test the release branch by running
hg update release-branch.rNN
in a clean client. To return to the normal tree,
hg update default
Move changes since the weekly into the release branch
using hg release-apply followed by the usual code review
process and hg submit.
When it comes time to tag the release, record the
final long-form tag of the release-branch.rNN
in the *default* branch's .hgtags file. That is, run
hg update default
and then edit .hgtags as you would for a weekly.
"""
c = repo[None]
if not releaseBranch:
return "no active release branches"
if c.branch() != releaseBranch:
if c.modified() or c.added() or c.removed():
raise util.Abort("uncommitted local changes - cannot switch branches")
err = hg.clean(repo, releaseBranch)
if err:
return err
try:
err = clpatch_or_undo(ui, repo, clname, opts, mode="backport")
if err:
raise util.Abort(err)
except Exception, e:
hg.clean(repo, "default")
raise e
return None
def rev2clname(rev):
# Extract CL name from revision description.
@ -1185,15 +1249,24 @@ undoFooter = """
»»»
"""
backportHeader = """[%s] %s
««« CL %s / %s
"""
backportFooter = """
»»»
"""
# Implementation of clpatch/undo.
def clpatch_or_undo(ui, repo, clname, opts, undo=False):
def clpatch_or_undo(ui, repo, clname, opts, mode):
if missing_codereview:
return missing_codereview
if undo:
if mode == "undo" or mode == "backport":
if hgversion < '1.4':
# Don't have cmdutil.match (see implementation of sync command).
return "hg is too old to run hg undo - update to 1.4 or newer"
return "hg is too old to run hg %s - update to 1.4 or newer" % mode
# Find revision in Mercurial repository.
# Assume CL number is 7+ decimal digits.
@ -1227,8 +1300,19 @@ def clpatch_or_undo(ui, repo, clname, opts, undo=False):
# Create fresh CL and start with patch that would reverse the change.
vers = short(rev.node())
cl = CL("new")
cl.desc = (undoHeader % (clname, vers)) + rev.description() + undoFooter
patch = RunShell(["hg", "diff", "--git", "-r", vers + ":" + short(rev.parents()[0].node())])
desc = rev.description()
if mode == "undo":
cl.desc = (undoHeader % (clname, vers)) + desc + undoFooter
else:
cl.desc = (backportHeader % (releaseBranch, line1(desc), clname, vers)) + desc + undoFooter
v1 = vers
v0 = short(rev.parents()[0].node())
if mode == "undo":
arg = v1 + ":" + v0
else:
vers = v0
arg = v0 + ":" + v1
patch = RunShell(["hg", "diff", "--git", "-r", arg])
else: # clpatch
cl, vers, patch, err = DownloadCL(ui, repo, clname)
@ -1249,10 +1333,10 @@ def clpatch_or_undo(ui, repo, clname, opts, undo=False):
if id != vers:
patch, err = portPatch(repo, patch, vers, id)
if err != "":
return "codereview issue %s is out of date: %s" % (clname, err)
return "codereview issue %s is out of date: %s (%s->%s)" % (clname, err, vers, id)
argv = ["hgpatch"]
if opts["no_incoming"]:
if opts["no_incoming"] or mode == "backport":
argv += ["--checksync=false"]
try:
cmd = subprocess.Popen(argv, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None, close_fds=sys.platform != "win32")
@ -1271,7 +1355,7 @@ def clpatch_or_undo(ui, repo, clname, opts, undo=False):
if extra:
ui.warn("warning: these files were listed in the patch but not changed:\n\t" + "\n\t".join(extra) + "\n")
cl.Flush(ui, repo)
if undo:
if mode == "undo":
err = EditCL(ui, repo, cl)
if err != "":
return "CL created, but error editing: " + err
@ -1506,7 +1590,7 @@ def reposetup(ui, repo):
def CheckContributor(ui, repo, user=None):
set_status("checking CONTRIBUTORS file")
_, userline = FindContributor(ui, repo, user, warn=False)
user, userline = FindContributor(ui, repo, user, warn=False)
if not userline:
raise util.Abort("cannot find %s in CONTRIBUTORS" % (user,))
return userline
@ -1524,7 +1608,7 @@ def FindContributor(ui, repo, user=None, warn=True):
if user not in contributors:
if warn:
ui.warn("warning: cannot find %s in CONTRIBUTORS\n" % (user,))
return None, None
return user, None
user, email = contributors[user]
return email, "%s <%s>" % (user, email)
@ -1650,6 +1734,14 @@ def submit(ui, repo, *pats, **opts):
if not cl.copied_from:
EditDesc(cl.name, closed=True, private=cl.private)
cl.Delete(ui, repo)
c = repo[None]
if c.branch() == releaseBranch and not c.modified() and not c.added() and not c.removed():
ui.write("switching from %s to default branch.\n" % releaseBranch)
err = hg.clean(repo, "default")
if err:
return err
return None
def sync(ui, repo, **opts):
"""synchronize with remote repository
@ -1822,6 +1914,15 @@ cmdtable = {
] + commands.walkopts,
"[-r reviewer] [--cc cc] [change# | file ...]"
),
"^release-apply": (
release_apply,
[
('', 'ignore_hgpatch_failure', None, 'create CL metadata even if hgpatch fails'),
('', 'no_incoming', None, 'disable check for incoming changes'),
],
"change#"
),
# TODO: release-start, release-tag, weekly-tag
"^submit": (
submit,
review_opts + [
@ -2263,6 +2364,19 @@ def RietveldSetup(ui, repo):
upload_options.email = "test@example.com"
rpc = None
global releaseBranch
tags = repo.branchtags().keys()
if 'release-branch.r100' in tags:
# NOTE(rsc): This tags.sort is going to get the wrong
# answer when comparing release-branch.r99 with
# release-branch.r100. If we do ten releases a year
# that gives us 4 years before we have to worry about this.
raise util.Abort('tags.sort needs to be fixed for release-branch.r100')
tags.sort()
for t in tags:
if t.startswith('release-branch.'):
releaseBranch = t
#######################################################################
# http://codereview.appspot.com/static/upload.py, heavily edited.