hgext/releasenotes.py
changeset 33881 6a49c74b1e8f
parent 33784 589fda7895da
child 33940 2a37459aedf2
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())