8

编辑制作了这个基本钩子以防止分支名称和提交消息 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 输入错误,它不会出现在错误上,而不会引起很多混乱。许多开发人员使用每个错误/功能系统的分支。这是我工作的公司政策。雾虫很烂。

4

2 回答 2

6

i think the problem here is that the pretxncommit hook is executed at a point where you can't really change anything anymore. And you can't really get the commit message at that point either, because it's not set on any context object accessible.

repo['tip'].description() doesn't refer to the changelog being committed but to old tip already committed, that would be repo[None], but as some digging in the source revealed it's not the same context object that's being persisted, so it's no point in changing it.

the only way i could find would be to use an earlier hook - like precommit - and monkeypatch the commitctx method of the repository like this:

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

this way cou can access the context object just before it's committed.

于 2012-05-06T00:19:32.017 回答
5

mata 的回答很聪明,但是如果您愿意编写自己的扩展程序,实际上有一种内置的方法可以做到这一点(这真的很容易,只不过是编写您想要编写的钩子功能而已)。

执行此操作的“正确”方法是在 中对存储库进行子类化reposetup,如mercurial.extensions.wrapfunction(因为事实证明wrapfunction这不是对 repos 执行此操作的正确方法:

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,并将其添加到extensionshgrc 中的组下:

[extensions]
fogbugz = /some-path/fogbugz.py
于 2013-10-29T14:56:19.663 回答