Mercurial Hook – изменить сообщение фиксации фиксации

Edit Сделал этот базовый крючок, чтобы предотвратить несоответствие идентификатора ветки и комманды. https://gist.github.com/2583189

Таким образом, в основном идея заключается в том, что hook должен добавить «BugID: xyz» в конец сообщений фиксации, если имя ветки похоже на bug_123 или feature_123. Однако у меня возникают проблемы с поиском, как это сделать, так как большинство примеров pretxncommit не хотят мутировать описание набора изменений.

Это то, что у меня есть до сих пор. Он обновляет .hg / commit.save с правильным сообщением, но это сообщение никогда не передается коммиту. Однако он отображается в окне сообщения по умолчанию (черепаховый) следующего коммита. Возможно, 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 на каждую проклятую фиксацию. Прежде всего, я трачу свое время. Во-вторых, если идентификатор случая неверно напечатан, он не будет отображаться на ошибке без большого шума. Многие разработчики используют ветку для каждой системы ошибок / функций. Это политика компании, в которой я работаю. Fogbugz сосет.

Я думаю, что проблема в том, что крюк pretxncommit выполняется в точке, где вы больше ничего не можете изменить. И вы действительно не можете получить сообщение commit в этой точке, потому что оно не установлено ни в каком контекстном объекте.

repo['tip'].description() не относится к фиксированному списку изменений, но к уже сделанному ранее кончику, который будет repo[None] , но поскольку некоторые копания в источнике показали, что это не тот же объект контекста, который является сохранялся, поэтому нет смысла менять его.

единственный способ, которым я мог бы найти, – использовать ранний крючок – как precommit – и commitctx метод 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 может получить доступ к объекту контекста непосредственно перед его совершением.

Ответ mata очень умный, но на самом деле есть встроенный способ сделать это, если вы хотите написать собственное расширение (это очень просто , немного больше, чем просто написать функциональность hook, которую вы хотели написать в любом случае).

«Правильный» способ сделать это – подклассифицировать репозиторий в reposetup , как показано в docstring функции 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 и добавив его в группу extensions в hgrc:

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