From 5ce9a8d4fc067cab461e54c2b2e7c47ea4b9a9ef Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 3 May 2011 01:07:23 -0400 Subject: create release-branch.r57 --- lib/codereview/codereview.py | 140 +++++++++++++++++++++++++++++++++++++++---- 1 file 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. -- cgit v1.2.3-54-g00ecf