Mercurial Hook - 在提交前更改提交消息

时间:2012-04-29 23:47:10

标签: python mercurial mercurial-hook

编辑制作此基本挂钩以防止分支名称&提交消息bugID不匹配。 https://gist.github.com/2583189

基本上,如果分支名称类似于bug_123或feature_123,那么钩子应该在提交消息的末尾附加“BugID:xyz”。但是我在查找如何执行此操作时遇到了问题,因为大多数pretxncommit的例子都不想改变变更集描述。

这是我到目前为止所拥有的。它使用正确的消息更新.hg / commit.save,但此消息永远不会传递给提交。然而,它显示在下一次提交的默认消息框(tortoisehg)中。也许pretxncommit不是正确的钩子?

我可以使用precommit钩子,读取commit.save和repo ['tip']。branch()文件并更改 那,如果是这样,我将从哪里获取分支名称?

#
# Fogbugz automaticically add BugID:123 to commit messages based on branch names.
# Your branch name must be in the format feature_123_description or bug_123_description
#

import re
import mercurial, sys, os

_branch_regex = re.compile('(feature|bug|case|bugid|fogbugz)_(\d+)')
_commit_regex = re.compile(r'\b(?P<case>(review|case|bug[zs]?(\s| )*(id)?:?)s?(\s| )*([#:; ]| )+)((([ ,:;#]|and)*)(?P<bugid>\d+))+',re.I)

def pretxncommithook(ui, repo, **kwargs):
    ui.write('hook pretxncommithook running from fogbugz.py\n')
    """
    Checks a single commit message for adherence to commit message rules.

    To use add the following to your project .hg/hgrc for each
    project you want to check, or to your user hgrc to apply to all projects.

    [hooks]
    pretxncommit.fogbugz = python:fogbugz.pretxncommithook
    """
    hg_commit_message = repo['tip'].description()
    commit_has_bugid = _commit_regex.match(hg_commit_message) is not None

    match = _branch_regex.match(repo['tip'].branch())
    if match:
        hg_commit_message = hg_commit_message + ' BugID:'+ match.groups()[1]
            #hg_commit_message needs to be escaped for characters like >
        os.system('echo ' + hg_commit_message + ' > .hg/commit.save')

稍微不相关的说明,如果来自Fogbugz / Kiln团队的任何人看到这个......请更新您的软件以阅读分支名称,我不应该在每个该死的提交上放置一个BugID:x。首先,它浪费了我的时间。其次,如果案例ID输入不正确,它将不会显示在bug上,而不会有很多混乱。许多开发人员使用每个bug /功能系统的分支。这是我工作的公司政策。 Fogbugz很糟糕。

2 个答案:

答案 0 :(得分:6)

我认为这里的问题是pretxncommit挂钩是在你无法真正改变任何东西的地方执行的。此时你也无法真正获得提交消息,因为它没有设置在任何可访问的上下文对象上。

repo['tip'].description()没有引用正在提交的更改日志,而是引用已提交的旧提示,即repo[None],但是由于某些挖掘源显示它与持久化的上下文对象不同,所以改变它没有意义。

我能找到的唯一方法就是使用一个早期的钩子 - 比如precommit - 并且像这样monkeypatch存储库的commitctx方法:

def precommit_hook(repo, **kwargs):

    # keep a copy of repo.commitctx
    commitctx = repo.commitctx

    def updatectx(ctx, error):

        # check if `ctx.branch()` matches ...

        # update commit text
        ctx._text += " ... additional text"

        # call original
        return commitctx(ctx, error)

    # monkeypatch the commit method
    repo.commitctx = updatectx

这样,cou就可以在提交之前访问上下文对象。

答案 1 :(得分:5)

mata的答案很聪明,但如果你愿意编写自己的扩展(really easy,实际上有一种内置的方法可以做到这一点,不过只是编写你想写的钩子功能)

执行此操作的“正确”方法是在reposetup中对存储库进行子类化,如mercurial.extensions.wrapfunction的文档字符串所示(因为事实证明wrapfunction不是正确的方法做回购:

Wrapping methods of the repository object is not recommended since
it conflicts with extensions that extend the repository by
subclassing. All extensions that need to extend methods of
localrepository should use this subclassing trick: namely,
reposetup() should look like

  def reposetup(ui, repo):
      class myrepo(repo.__class__):
          def whatever(self, *args, **kwargs):
              [...extension stuff...]
              super(myrepo, self).whatever(*args, **kwargs)
              [...extension stuff...]

      repo.__class__ = myrepo

例如,您的扩展程序看起来像这样(剥离):

#!/usr/bin/python
import re
import mercurial, sys, os

_branch_regex = re.compile('(feature|bug|case|bugid|fogbugz)_(\d+)')
_commit_regex = re.compile(r'\b(?P<case>(review|case|bug[zs]?(\s| )*(id)?:?)s?(\s| )*([#:; ]| )+)((([ ,:;#]|and)*)(?P<bugid>\d+))+',re.I)

#One of mercurial's callbacks for extensions. This is where you
# you want to subclass repo to add your functionality.
def reposetup(ui, repo):

    #Create a derived class that actually does what you want.
    class myrepo(repo.__class__):
        def commitctx(self, ctx, *args, **kwargs):
            match = _branch_regex.match(ctx.branch())
            if match:
                ctx._text += ' BugID:'+ match.groups()[1]

    #Make sure to actually use the new subclass.
    repo.__class__ = myrepo

### Finish off the extensions stuff

# We aren't adding any commands to hg.
cmdtables = {}

#List of known compatible versions of hg.
testedwith = '2.7.1'

我测试了这个并且它工作正常。您可以通过将扩展名保存在python文件中来使用该扩展名,例如/some-path/fogbugz.py,并将其添加到hgrc中的extensions组下:

[extensions]
fogbugz = /some-path/fogbugz.py