--- a/hgext/mqext/__init__.py
+++ b/hgext/mqext/__init__.py
@@ -70,17 +70,17 @@ Alternatively, if you only want a subset
the -Q option to all relevant commands in your ~/.hgrc::
[defaults]
qnew = -Q
qdelete = -Q
qimport = -Q
'''
-testedwith = '3.2 3.3 3.3 3.4 3.5'
+testedwith = '3.4 3.5 3.6 3.7'
import os
import re
import json
import urllib2
from mercurial.i18n import _
from mercurial.node import short
@@ -101,18 +101,24 @@ except:
try:
# hg 1.9+
from mercurial.scmutil import canonpath
except:
from mercurial.util import canonpath
buglink = 'https://bugzilla.mozilla.org/enter_bug.cgi?product=Developer%20Services&component=General'
+cmdtable = {}
+command = cmdutil.command(cmdtable)
+
bugzilla_jsonrpc_url = "https://bugzilla.mozilla.org/jsonrpc.cgi"
+@command('qshow', [
+ ('', 'stat', None, 'output diffstat-style summary of changes')],
+ ('hg qshow [patch]'))
def qshow(ui, repo, patchspec=None, **opts):
'''display a patch
If no patch is given, the top of the applied stack is shown.'''
q = repo.mq
patchf = None
if patchspec is None:
@@ -246,16 +252,22 @@ def patch_changes(ui, repo, patchfile=No
break
left -= 1
yield repo[ctx.rev()]
fileRe = re.compile(r"^\+\+\+ (?:b/)?([^\s]*)", re.MULTILINE)
suckerRe = re.compile(r"[^s-]r=(\w+)")
supersuckerRe = re.compile(r"sr=(\w+)")
+@command('reviewers', [
+ ('f', 'file', [], 'see reviewers for FILE', 'FILE'),
+ ('r', 'rev', [], 'see reviewers for revisions', 'REVS'),
+ ('l', 'limit', 200, 'how many revisions back to scan', 'LIMIT'),
+ ('', 'brief', False, 'shorter output')],
+ _('hg reviewers [-f FILE1 -f FILE2...] [-r REVS] [-l LIMIT] [PATCH]'))
def reviewers(ui, repo, patchfile=None, **opts):
'''Suggest a reviewer for a patch
Scan through the last LIMIT commits to find candidate reviewers for a
patch (or set of files).
The patch may be given as a file or a URL. If no patch is specified,
the changes in the working directory will be used. If there are no
@@ -358,16 +370,22 @@ def fetch_bugs(url, ui, bugs):
bs = list(bugs)
parts = [ bs[i:len(bugs):nparts] for i in range(0,nparts) ]
return reduce(lambda bs,p: bs + fetch_bugs(url, ui, p), parts, [])
raise util.Abort("Failed to retrieve bugs, last buginfo=%r" % (buginfo,))
return buginfo['result']['bugs']
+@command('components', [
+ ('f', 'file', [], 'see components for FILE', 'FILE'),
+ ('r', 'rev', [], 'see reviewers for revisions', 'REVS'),
+ ('l', 'limit', 25, 'how many revisions back to scan', 'LIMIT'),
+ ('', 'brief', False, 'shorter output')],
+ _('hg components [-f FILE1 -f FILE2...] [-r REVS] [-l LIMIT] [PATCH]'))
def bzcomponents(ui, repo, patchfile=None, **opts):
'''Suggest a bugzilla product and component for a patch
Scan through the last LIMIT commits to find bug product/components that
touch the same files.
The patch may be given as a file or a URL. If no patch is specified,
the changes in the working directory will be used. If there are no
@@ -410,16 +428,20 @@ def bzcomponents(ui, repo, patchfile=Non
ui.write("Potential components:\n")
if len(components) == 0:
ui.write(" none found in range (try higher --limit?)\n")
else:
for (comp, count) in components.most_common(5):
ui.write(" %s: %d\n" % (comp, count))
+@command('bugs', [
+ ('f', 'file', [], 'see bugs for FILE', 'FILE'),
+ ('l', 'limit', 100, 'how many revisions back to scan', 'LIMIT')],
+ _('hg bugs [-f FILE1 -f FILE2...] [-l LIMIT] [PATCH]'))
def bzbugs(ui, repo, patchfile=None, **opts):
'''List the bugs that have modified the files in a patch
Scan through the last LIMIT commits to find bugs that touch the same files.
The patch may be given as a file or a URL. If no patch is specified,
the changes in the working directory will be used. If there are no
changes, the topmost applied patch in your mq repository will be used.
@@ -435,16 +457,20 @@ def bzbugs(ui, repo, patchfile=None, **o
bugs.add(m.group(2))
if bugs:
for bug in bugs:
ui.write("bug %s\n" % bug)
else:
ui.write("No bugs found\n")
+@command('qtouched', [
+ ('a', 'applied', None, 'only consider applied patches'),
+ ('p', 'patch', '', 'restrict to given patch')],
+ _('hg touched [-a] [-p PATCH] [FILE]'))
def touched(ui, repo, sourcefile=None, **opts):
'''Show what files are touched by what patches
If no file is given, print out a series of lines containing a
patch and a file changed by that patch, for all files changed by
all patches. This is mainly intended for easy grepping.
If a file is given, print out the list of patches that touch that file.'''
@@ -467,16 +493,17 @@ def touched(ui, repo, sourcefile=None, *
if sourcefile is None:
ui.write(patchname + "\t" + filename + "\n")
elif sourcefile == filename:
ui.write(patchname + "\n")
qparent_re = re.compile('^qparent: (\S+)$', re.M)
top_re = re.compile('^top: (\S+)$', re.M)
+@command('qrevert', [], _('hg qrevert REV'))
def qrevert(ui, repo, rev, **opts):
'''
Revert to a past mq state. This updates both the main checkout as well as
the patch directory, and leaves either or both at a non-head revision.
'''
q = repo.mq
if not q or not q.qrepo():
raise util.Abort(_("No revisioned patch queue found"))
@@ -681,16 +708,22 @@ def qdelete_wrapper(orig, self, repo, *p
if mqcommit and mqmessage:
mqmessage = substitute_mqmessage(mqmessage, repo,
{ 'a': 'DELETE',
'P': '%d patches - %s' % (len(patches), " ".join(patchnames)),
'[]': patchnames })
commands.commit(r.ui, r, message=mqmessage)
+@command('urls', [
+ ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
+ ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
+ ('u', 'user', [], _('revisions committed by user'), _('USER')),
+ ] + commands.logopts,
+ _('hg urls [-l LIMIT] [NAME]'))
def urls(ui, repo, *paths, **opts):
'''Display a list of urls for the last several commits.
These are merely heuristic guesses and are intended for pasting into
bugs after landing. If that makes no sense to you, then you are probably
not the intended audience. It's mainly a Mozilla thing.
Note that this will display the URL for your default repo, which may very
well be something local. So you may need to give your outbound repo as
@@ -753,68 +786,16 @@ def qcrecord_wrapper(orig, self, repo, p
if ret:
return ret
if mqcommit and mqmessage:
mqmessage = substitute_mqmessage(mqmessage, repo, { 'p': patchfn,
'a': 'NEW' })
commands.commit(r.ui, r, message=mqmessage)
-cmdtable = {
- 'qshow': (qshow,
- [('', 'stat', None, 'output diffstat-style summary of changes'),
- ],
- ('hg qshow [patch]')),
-
- 'reviewers':
- (reviewers,
- [('f', 'file', [], 'see reviewers for FILE', 'FILE'),
- ('r', 'rev', [], 'see reviewers for revisions', 'REVS'),
- ('l', 'limit', 200, 'how many revisions back to scan', 'LIMIT'),
- ('', 'brief', False, 'shorter output'),
- ],
- ('hg reviewers [-f FILE1 -f FILE2...] [-r REVS] [-l LIMIT] [PATCH]')),
-
- 'bugs':
- (bzbugs,
- [('f', 'file', [], 'see bugs for FILE', 'FILE'),
- ('l', 'limit', 100, 'how many revisions back to scan', 'LIMIT')
- ],
- ('hg bugs [-f FILE1 -f FILE2...] [-l LIMIT] [PATCH]')),
-
- 'components':
- (bzcomponents,
- [('f', 'file', [], 'see components for FILE', 'FILE'),
- ('r', 'rev', [], 'see reviewers for revisions', 'REVS'),
- ('l', 'limit', 25, 'how many revisions back to scan', 'LIMIT'),
- ('', 'brief', False, 'shorter output'),
- ],
- ('hg components [-f FILE1 -f FILE2...] [-r REVS] [-l LIMIT] [PATCH]')),
-
- 'qtouched':
- (touched,
- [('a', 'applied', None, 'only consider applied patches'),
- ('p', 'patch', '', 'restrict to given patch')
- ],
- ('hg touched [-a] [-p PATCH] [FILE]')),
-
- 'urls':
- (urls,
- [('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
- ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
- ('u', 'user', [], _('revisions committed by user'), _('USER')),
- ] + commands.logopts,
- ('hg urls [-l LIMIT] [NAME]')),
-
- 'qrevert':
- (qrevert,
- [],
- ('hg qrevert REV')),
-}
-
def uisetup(ui):
try:
mq = extensions.find('mq')
if mq is None:
ui.warn("mqext extension is mostly disabled when mq is disabled")
return
except KeyError:
ui.warn("mqext extension is mostly disabled when mq is not installed")