# HG changeset patch # User Rishabh Madan # Date 2017-08-13 14:28:45 # Node ID 6a49c74b1e8f4a1949cfd44562c83b2160ff942d # Parent edf503e5dfd408f900f3bad0a6923573813e276b releasenotes: add check flag for use of admonitions and its validity While using releasenotes extension, we will be using admonitions in commit messages. The check (-c) flag will look for an admonition within the message. If it exists, it will verify if it is stated under default or custom admonition. The check fails if the admonition is not present in any of them. It also suggests similar admonitions in case the admonition is invalid. Differential Revision: https://phab.mercurial-scm.org/D368 diff --git a/hgext/releasenotes.py b/hgext/releasenotes.py --- a/hgext/releasenotes.py +++ b/hgext/releasenotes.py @@ -13,6 +13,7 @@ process simpler by automating it. from __future__ import absolute_import +import difflib import errno import re import sys @@ -242,6 +243,38 @@ def getcustomadmonitions(repo): read('.hgreleasenotes') return p['sections'] +def checkadmonitions(ui, repo, directives, revs): + """ + Checks the commit messages for admonitions and their validity. + + .. abcd:: + + First paragraph under this admonition + + For this commit message, using `hg releasenotes -r . --check` + returns: Invalid admonition 'abcd' present in changeset 3ea92981e103 + + As admonition 'abcd' is neither present in default nor custom admonitions + """ + for rev in revs: + ctx = repo[rev] + admonition = re.search(RE_DIRECTIVE, ctx.description()) + if admonition: + 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() + + similar = [s for s in directives if sim(s) > 0.6] + if len(similar) == 1: + ui.write(_("(did you mean %s?)\n") % similar[0]) + elif similar: + ss = ", ".join(sorted(similar)) + ui.write(_("(did you mean one of %s?)\n") % ss) + def parsenotesfromrevisions(repo, directives, revs): notes = parsedreleasenotes() @@ -432,9 +465,11 @@ def serializenotes(sections, notes): return '\n'.join(lines) @command('releasenotes', - [('r', 'rev', '', _('revisions to process for release notes'), _('REV'))], - _('[-r REV] FILE')) -def releasenotes(ui, repo, file_, rev=None): + [('r', 'rev', '', _('revisions to process for release notes'), _('REV')), + ('c', 'check', False, _('checks for validity of admonitions (if any)'), + _('REV'))], + _('hg releasenotes [-r REV] [-c] FILE')) +def releasenotes(ui, repo, file_=None, **opts): """parse release notes from commit messages into an output file Given an output file and set of revisions, this command will parse commit @@ -511,8 +546,12 @@ def releasenotes(ui, repo, file_, rev=No release note after it has been added to the release notes file. """ sections = releasenotessections(ui, repo) + rev = opts.get('rev') revs = scmutil.revrange(repo, [rev or 'not public()']) + if opts.get('check'): + return checkadmonitions(ui, repo, sections.names(), revs) + incoming = parsenotesfromrevisions(repo, sections.names(), revs) try: diff --git a/tests/test-releasenotes-formatting.t b/tests/test-releasenotes-formatting.t --- a/tests/test-releasenotes-formatting.t +++ b/tests/test-releasenotes-formatting.t @@ -378,3 +378,32 @@ Overriding default sections (For eg. by * Adds a new feature. + $ cd .. + +Testing output for the --check (-c) flag + + $ hg init check-flag + $ cd check-flag + + $ touch a + $ hg -q commit -A -l - << EOF + > .. asf:: + > + > First paragraph under this admonition. + > EOF + +Suggest similar admonition in place of the invalid one. + + $ hg releasenotes -r . -c + Invalid admonition 'asf' present in changeset 4026fe9e1c20 + + $ touch b + $ hg -q commit -A -l - << EOF + > .. fixes:: + > + > First paragraph under this admonition. + > EOF + + $ hg releasenotes -r . -c + Invalid admonition 'fixes' present in changeset 0e7130d2705c + (did you mean fix?)