comparison hgext/releasenotes.py @ 33881:6a49c74b1e8f

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
author Rishabh Madan <rishabhmadan96@gmail.com>
date Sun, 13 Aug 2017 19:58:45 +0530
parents 589fda7895da
children 2a37459aedf2
comparison
equal deleted inserted replaced
33880:edf503e5dfd4 33881:6a49c74b1e8f
11 process simpler by automating it. 11 process simpler by automating it.
12 """ 12 """
13 13
14 from __future__ import absolute_import 14 from __future__ import absolute_import
15 15
16 import difflib
16 import errno 17 import errno
17 import re 18 import re
18 import sys 19 import sys
19 import textwrap 20 import textwrap
20 21
240 241
241 if '.hgreleasenotes' in ctx: 242 if '.hgreleasenotes' in ctx:
242 read('.hgreleasenotes') 243 read('.hgreleasenotes')
243 return p['sections'] 244 return p['sections']
244 245
246 def checkadmonitions(ui, repo, directives, revs):
247 """
248 Checks the commit messages for admonitions and their validity.
249
250 .. abcd::
251
252 First paragraph under this admonition
253
254 For this commit message, using `hg releasenotes -r . --check`
255 returns: Invalid admonition 'abcd' present in changeset 3ea92981e103
256
257 As admonition 'abcd' is neither present in default nor custom admonitions
258 """
259 for rev in revs:
260 ctx = repo[rev]
261 admonition = re.search(RE_DIRECTIVE, ctx.description())
262 if admonition:
263 if admonition.group(1) in directives:
264 continue
265 else:
266 ui.write(_("Invalid admonition '%s' present in changeset %s"
267 "\n") % (admonition.group(1), ctx.hex()[:12]))
268 sim = lambda x: difflib.SequenceMatcher(None,
269 admonition.group(1), x).ratio()
270
271 similar = [s for s in directives if sim(s) > 0.6]
272 if len(similar) == 1:
273 ui.write(_("(did you mean %s?)\n") % similar[0])
274 elif similar:
275 ss = ", ".join(sorted(similar))
276 ui.write(_("(did you mean one of %s?)\n") % ss)
277
245 def parsenotesfromrevisions(repo, directives, revs): 278 def parsenotesfromrevisions(repo, directives, revs):
246 notes = parsedreleasenotes() 279 notes = parsedreleasenotes()
247 280
248 for rev in revs: 281 for rev in revs:
249 ctx = repo[rev] 282 ctx = repo[rev]
430 lines.append('') 463 lines.append('')
431 464
432 return '\n'.join(lines) 465 return '\n'.join(lines)
433 466
434 @command('releasenotes', 467 @command('releasenotes',
435 [('r', 'rev', '', _('revisions to process for release notes'), _('REV'))], 468 [('r', 'rev', '', _('revisions to process for release notes'), _('REV')),
436 _('[-r REV] FILE')) 469 ('c', 'check', False, _('checks for validity of admonitions (if any)'),
437 def releasenotes(ui, repo, file_, rev=None): 470 _('REV'))],
471 _('hg releasenotes [-r REV] [-c] FILE'))
472 def releasenotes(ui, repo, file_=None, **opts):
438 """parse release notes from commit messages into an output file 473 """parse release notes from commit messages into an output file
439 474
440 Given an output file and set of revisions, this command will parse commit 475 Given an output file and set of revisions, this command will parse commit
441 messages for release notes then add them to the output file. 476 messages for release notes then add them to the output file.
442 477
509 this command and changes should not be lost when running this command on 544 this command and changes should not be lost when running this command on
510 that file. A particular use case for this is to tweak the wording of a 545 that file. A particular use case for this is to tweak the wording of a
511 release note after it has been added to the release notes file. 546 release note after it has been added to the release notes file.
512 """ 547 """
513 sections = releasenotessections(ui, repo) 548 sections = releasenotessections(ui, repo)
549 rev = opts.get('rev')
514 550
515 revs = scmutil.revrange(repo, [rev or 'not public()']) 551 revs = scmutil.revrange(repo, [rev or 'not public()'])
552 if opts.get('check'):
553 return checkadmonitions(ui, repo, sections.names(), revs)
554
516 incoming = parsenotesfromrevisions(repo, sections.names(), revs) 555 incoming = parsenotesfromrevisions(repo, sections.names(), revs)
517 556
518 try: 557 try:
519 with open(file_, 'rb') as fh: 558 with open(file_, 'rb') as fh:
520 notes = parsereleasenotesfile(sections, fh.read()) 559 notes = parsereleasenotesfile(sections, fh.read())