diff -r 57875cf423c9 -r 2372284d9457 hgext/releasenotes.py --- 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"""