--- a/hgext/releasenotes.py Sat Oct 05 10:29:34 2019 -0400
+++ b/hgext/releasenotes.py Sun Oct 06 09:45:02 2019 -0400
@@ -28,15 +28,14 @@
scmutil,
util,
)
-from mercurial.utils import (
- stringutil,
-)
+from mercurial.utils import stringutil
cmdtable = {}
command = registrar.command(cmdtable)
try:
import fuzzywuzzy.fuzz as fuzz
+
fuzz.token_set_ratio
except ImportError:
fuzz = None
@@ -60,6 +59,7 @@
BULLET_SECTION = _('Other Changes')
+
class parsedreleasenotes(object):
def __init__(self):
self.sections = {}
@@ -103,19 +103,25 @@
This is used to combine multiple sources of release notes together.
"""
if not fuzz:
- ui.warn(_("module 'fuzzywuzzy' not found, merging of similar "
- "releasenotes is disabled\n"))
+ ui.warn(
+ _(
+ "module 'fuzzywuzzy' not found, merging of similar "
+ "releasenotes is disabled\n"
+ )
+ )
for section in other:
- existingnotes = (
- converttitled(self.titledforsection(section)) +
- convertnontitled(self.nontitledforsection(section)))
+ existingnotes = converttitled(
+ self.titledforsection(section)
+ ) + convertnontitled(self.nontitledforsection(section))
for title, paragraphs in other.titledforsection(section):
if self.hastitledinsection(section, title):
# TODO prompt for resolution if different and running in
# interactive mode.
- ui.write(_('%s already exists in %s section; ignoring\n') %
- (title, section))
+ ui.write(
+ _('%s already exists in %s section; ignoring\n')
+ % (title, section)
+ )
continue
incoming_str = converttitled([(title, paragraphs)])[0]
@@ -146,6 +152,7 @@
self.addnontitleditem(section, paragraphs)
+
class releasenotessections(object):
def __init__(self, ui, repo=None):
if repo:
@@ -170,6 +177,7 @@
return None
+
def converttitled(titledparagraphs):
"""
Convert titled paragraphs to strings
@@ -182,6 +190,7 @@
string_list.append(' '.join(lines))
return string_list
+
def convertnontitled(nontitledparagraphs):
"""
Convert non-titled bullets to strings
@@ -194,6 +203,7 @@
string_list.append(' '.join(lines))
return string_list
+
def getissuenum(incoming_str):
"""
Returns issue number from the incoming string if it exists
@@ -203,6 +213,7 @@
issue = issue.group()
return issue
+
def findissue(ui, existing, issue):
"""
Returns true if issue number already exists in notes.
@@ -213,6 +224,7 @@
else:
return False
+
def similar(ui, existing, incoming_str):
"""
Returns true if similar note found in existing notes.
@@ -220,14 +232,17 @@
if len(incoming_str.split()) > 10:
merge = similaritycheck(incoming_str, existing)
if not merge:
- ui.write(_('"%s" already exists in notes file; ignoring\n')
- % incoming_str)
+ ui.write(
+ _('"%s" already exists in notes file; ignoring\n')
+ % incoming_str
+ )
return True
else:
return False
else:
return False
+
def similaritycheck(incoming_str, existingnotes):
"""
Returns false when note fragment can be merged to existing notes.
@@ -244,6 +259,7 @@
break
return merge
+
def getcustomadmonitions(repo):
ctx = repo['.']
p = config.config()
@@ -253,13 +269,15 @@
data = ctx[f].data()
p.parse(f, data, sections, remap, read)
else:
- raise error.Abort(_(".hgreleasenotes file \'%s\' not found") %
- repo.pathto(f))
+ raise error.Abort(
+ _(".hgreleasenotes file \'%s\' not found") % repo.pathto(f)
+ )
if '.hgreleasenotes' in ctx:
read('.hgreleasenotes')
return p['sections']
+
def checkadmonitions(ui, repo, directives, revs):
"""
Checks the commit messages for admonitions and their validity.
@@ -280,10 +298,13 @@
if admonition.group(1) in directives:
continue
else:
- ui.write(_("Invalid admonition '%s' present in changeset %s"
- "\n") % (admonition.group(1), ctx.hex()[:12]))
- sim = lambda x: difflib.SequenceMatcher(None,
- admonition.group(1), x).ratio()
+ ui.write(
+ _("Invalid admonition '%s' present in changeset %s" "\n")
+ % (admonition.group(1), ctx.hex()[:12])
+ )
+ sim = lambda x: difflib.SequenceMatcher(
+ None, admonition.group(1), x
+ ).ratio()
similar = [s for s in directives if sim(s) > 0.6]
if len(similar) == 1:
@@ -292,18 +313,21 @@
ss = ", ".join(sorted(similar))
ui.write(_("(did you mean one of %s?)\n") % ss)
+
def _getadmonitionlist(ui, sections):
for section in sections:
ui.write("%s: %s\n" % (section[0], section[1]))
+
def parsenotesfromrevisions(repo, directives, revs):
notes = parsedreleasenotes()
for rev in revs:
ctx = repo[rev]
- blocks, pruned = minirst.parse(ctx.description(),
- admonitions=directives)
+ blocks, pruned = minirst.parse(
+ ctx.description(), admonitions=directives
+ )
for i, block in enumerate(blocks):
if block['type'] != 'admonition':
@@ -313,8 +337,13 @@
title = block['lines'][0].strip() if block['lines'] else None
if i + 1 == len(blocks):
- raise error.Abort(_('changeset %s: release notes directive %s '
- 'lacks content') % (ctx, directive))
+ raise error.Abort(
+ _(
+ 'changeset %s: release notes directive %s '
+ 'lacks content'
+ )
+ % (ctx, directive)
+ )
# Now search ahead and find all paragraphs attached to this
# admonition.
@@ -330,8 +359,13 @@
break
if pblock['type'] != 'paragraph':
- repo.ui.warn(_('changeset %s: unexpected block in release '
- 'notes directive %s\n') % (ctx, directive))
+ repo.ui.warn(
+ _(
+ 'changeset %s: unexpected block in release '
+ 'notes directive %s\n'
+ )
+ % (ctx, directive)
+ )
if pblock['indent'] > 0:
paragraphs.append(pblock['lines'])
@@ -340,8 +374,10 @@
# TODO consider using title as paragraph for more concise notes.
if not paragraphs:
- repo.ui.warn(_("error parsing releasenotes for revision: "
- "'%s'\n") % node.hex(ctx.node()))
+ repo.ui.warn(
+ _("error parsing releasenotes for revision: " "'%s'\n")
+ % node.hex(ctx.node())
+ )
if title:
notes.addtitleditem(directive, title, paragraphs)
else:
@@ -349,6 +385,7 @@
return notes
+
def parsereleasenotesfile(sections, text):
"""Parse text content containing generated release notes."""
notes = parsedreleasenotes()
@@ -375,7 +412,7 @@
else:
lines = [[l[1:].strip() for l in block['lines']]]
- for block in blocks[i + 1:]:
+ for block in blocks[i + 1 :]:
if block['type'] in ('bullet', 'section'):
break
if block['type'] == 'paragraph':
@@ -383,8 +420,10 @@
notefragment.append(lines)
continue
elif block['type'] != 'paragraph':
- raise error.Abort(_('unexpected block type in release notes: '
- '%s') % block['type'])
+ raise error.Abort(
+ _('unexpected block type in release notes: ' '%s')
+ % block['type']
+ )
if title:
notefragment.append(block['lines'])
@@ -402,8 +441,9 @@
if block['underline'] == '=': # main section
name = sections.sectionfromtitle(title)
if not name:
- raise error.Abort(_('unknown release notes section: %s') %
- title)
+ raise error.Abort(
+ _('unknown release notes section: %s') % title
+ )
currentsection = name
bullet_points = gatherparagraphsbullets(i)
@@ -424,6 +464,7 @@
return notes
+
def serializenotes(sections, notes):
"""Serialize release notes from parsed fragments and notes.
@@ -449,8 +490,9 @@
for i, para in enumerate(paragraphs):
if i:
lines.append('')
- lines.extend(stringutil.wrap(' '.join(para),
- width=78).splitlines())
+ lines.extend(
+ stringutil.wrap(' '.join(para), width=78).splitlines()
+ )
lines.append('')
@@ -468,17 +510,25 @@
lines.append('')
for paragraphs in nontitled:
- lines.extend(stringutil.wrap(' '.join(paragraphs[0]),
- width=78,
- initindent='* ',
- hangindent=' ').splitlines())
+ lines.extend(
+ stringutil.wrap(
+ ' '.join(paragraphs[0]),
+ width=78,
+ initindent='* ',
+ hangindent=' ',
+ ).splitlines()
+ )
for para in paragraphs[1:]:
lines.append('')
- lines.extend(stringutil.wrap(' '.join(para),
- width=78,
- initindent=' ',
- hangindent=' ').splitlines())
+ lines.extend(
+ stringutil.wrap(
+ ' '.join(para),
+ width=78,
+ initindent=' ',
+ hangindent=' ',
+ ).splitlines()
+ )
lines.append('')
@@ -487,14 +537,29 @@
return '\n'.join(lines)
-@command('releasenotes',
- [('r', 'rev', '', _('revisions to process for release notes'), _('REV')),
- ('c', 'check', False, _('checks for validity of admonitions (if any)'),
- _('REV')),
- ('l', 'list', False, _('list the available admonitions with their title'),
- None)],
+
+@command(
+ 'releasenotes',
+ [
+ ('r', 'rev', '', _('revisions to process for release notes'), _('REV')),
+ (
+ 'c',
+ 'check',
+ False,
+ _('checks for validity of admonitions (if any)'),
+ _('REV'),
+ ),
+ (
+ 'l',
+ 'list',
+ False,
+ _('list the available admonitions with their title'),
+ None,
+ ),
+ ],
_('hg releasenotes [-r REV] [-c] FILE'),
- helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
+ helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
+)
def releasenotes(ui, repo, file_=None, **opts):
"""parse release notes from commit messages into an output file
@@ -616,6 +681,7 @@
with open(file_, 'wb') as fh:
fh.write(serializenotes(sections, notes))
+
@command('debugparsereleasenotes', norepo=True)
def debugparsereleasenotes(ui, path, repo=None):
"""parse release notes and print resulting data structure"""