aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2011-05-03 01:07:23 -0400
committerRuss Cox <rsc@golang.org>2011-05-03 01:07:23 -0400
commit5ce9a8d4fc067cab461e54c2b2e7c47ea4b9a9ef (patch)
treeedc4c10f897c3fc2d0f5662550c075bef2517363
parent5a8ae387e2f22e1c255d96b052b868281ca83761 (diff)
downloadgo-5ce9a8d4fc067cab461e54c2b2e7c47ea4b9a9ef.tar.gz
go-5ce9a8d4fc067cab461e54c2b2e7c47ea4b9a9ef.zip
create release-branch.r57
-rw-r--r--lib/codereview/codereview.py140
1 files changed, 127 insertions, 13 deletions
diff --git a/lib/codereview/codereview.py b/lib/codereview/codereview.py
index bfa69fcc08..36d7df199f 100644
--- a/lib/codereview/codereview.py
+++ b/lib/codereview/codereview.py
@@ -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.