mercurial pre-push hook parameter to obtain the remote repo path - mercurial

I'm trying to implement a mercurial pre-push hook which checks the target repo path and adds the appropriate id by ssh-add. The not so nice solution would be checking the command line parameters and if the path isn't forced, then reading the default from the hgrc file but is there a cleaner way to just obtain the remote path?
I printed the kwargs passed into the hook method but there isn't any which seem to hold what I need. I also tried googling but the info available is next to nothing and this appears to be a bit like a black art really. So, any reference to a decent documentation and/or examples would be appreciated too.
Cheers,

Looking in hg help config, it seems like you can use the 'prechangegroup' hook and the HG_URL environment variable:
"prechangegroup"
Run before a changegroup is added via push, pull or unbundle. Exit
status 0 allows the changegroup to proceed. Non-zero status will cause
the push, pull or unbundle to fail. URL from which changes will come is
in "$HG_URL".

You should be able to use the 'pre-changegroup' and 'pre-push' hook (mind the dash). Which supplies the command line arguments as $HG_ARGS.
If the $HG_ARGS is a valid url you can use that url. If nothing is supplied use the ui object that is given as a keyword argument to the hook.
Use the following to retreive the default path from the configuration: ui.config('paths', 'default')
As you can also write other named urls/paths in the configuration file you should also be able to verify the $HG_ARGS if it doesn't contain a valid url a a keyword to the ui.config paths object

Related

How to set up mercurial hooks in Kallithea

I've been at it for a while now and I can't seem to get it working.
As per Kallithea documentation:
To add another custom hook simply fill in the first textbox with <name>.<hook_type> and the second with the hook path. Example hooks can be found in kallithea.lib.hooks.
So my first attempt was to add a new method to hooks.py. Basically to test out the hook I want to prevent ALL push to the repo. So I'll use pretxnchangegroup and return non 0 non false value as Mercurial documentation states
A hook that executes successfully must exit with a status of zero if external, or return boolean “false” if in-process. Failure is indicated with a non-zero exit status from an external hook, or an in-process hook returning boolean “true”. If an in-process hook raises an exception, the hook is considered to have failed.
So I did this:
def myhook(ui, repo, **kwargs):
return True
And I added the hook to the GUI in Kallithea hook options:
pretxnchangegroup <=> python:kallithea.lib.hooks.myhook
This however failed because for some reason the method can't be found
abort: pretxnchangegroup hook is invalid ("kallithea.lib.hooks.myhook" is not defined)
So I tried putting it in another file ( in the same 'lib' folder where hooks.py is ). Created a file called canpush.py and added the same method there. I changed the hook path to target the new file name:
pretxnchangegroup <=> python:kallithea.lib.hooks.myhook
However the hook does not trigger, and I can push to my repo without a problem. I plan to change the actual hook implementation in the future, push will be allowed, but first I need to get any hook functional with Kallithea.
What am I doing wrong here ?
Also, if someone knows how to use hgrc settings from individual repo within Kallithea an example would be great. Original question here.
Answering my own question, but just to keep it as reference.
As it turned out the setup was fine, but in an act of desperation I decided to restart kallithea daemon ( which was nowhere in the documentation ), basically thinking 'what could go wrong' - and that did the trick!
I guess during the startup process things get compiled / cached and the hook definition methods are found and functional ( If someone has a better explanation as to what happens on kallithea restart please share it )
So bare in mind, after every change to the hooks files kallithea daemon must be restarted in order for hooks to have any effect.
sudo service kallithea restart
Something else that wasn't clear to me from reading the kallithea documentation is that the hooks are mercurial hooks, they're not really some kallithea/rhodecode API, it's mercurial all the way.
This means that the best source of documentation on how to write one is something like http://hgbook.red-bean.com/read/handling-repository-events-with-hooks.html

How to get the working directory of the command from an hg hook?

I'm working on a commit hook for Mercurial and running into problems with relative paths.
Say my hook wants to look at the contents of the files being committed and warn if any contain the phrase "xyzzy". However, the user has decided to call commit from a subfolder and pass in the name of the file as a pattern...
C:\clone\subdir> hg commit file.txt -m 'test'
My hook is called with C:\clone as the working directory, but HG_PATS contains simply file.txt with no subdir\ prefix. How can I get the working directory of the hg command itself? I can't find a way to do this in docs.
The only way I can figure out how to get it is look up the process tree to find the first hg.exe and get its working directory. But that's not exactly portable to other OS's. (And I know I could write an extension, but would really like to avoid that.)
If you use the pretxncommit hook then you are given $HG_NODE which is the commit id, but the commit hasn't been finalized at that point so you can still return 1 to cancel it.
Then you could use
hg log -r $HG_NODE --template '{files}'
to get the list of files in the commit, and it gives you the full path relative to the repo root.
It's not exactly what you were after but it might get you close enough to let you do the content examination you want.
Thanks for the answers and comments, but after some more research I determined there's no clean way to do what I want from an external hook. I did implement the CWD hack I mentioned in my question. Not a ton of code, but quite nasty, and on Windows it requires undocumented access to external process CWD via tlist.exe. It works, but..yuck.
The right way to do this appears to be to write an in-process hook (example library at hghooklib). Usual versioning caveats apply as with writing any extension, though I think for our hooks the interface to hg is simple enough that we'll be ok.
(In my question I mentioned I didn't want to write an extension, but I was thinking of a full extension like hgeol. A hook-only extension with a single function entry point feels more constrained and simple, which is what I want at this point.)

Mercurial: how to add a hook on pull

I've searched awhile for this and haven't seen anything. Which could mean, it's not supposed to be done or it just can't be done.
I looked at a list of hooks for mercurial and I could not seem to find (or get one working) that executed a script after you give the hg pull command.
Thank you
From the hgrc docs section on "hooks" -
"incoming"
Run after a changeset has been pulled, pushed, or unbundled into the
local repository. The ID of the newly arrived changeset is in
"$HG_NODE". URL that was source of changes came is in "$HG_URL".
or...
"post-<command>"
Run after successful invocations of the associated command. The contents
of the command line are passed as "$HG_ARGS" and the result code in
"$HG_RESULT". Parsed command line arguments are passed as "$HG_PATS" and
"$HG_OPTS". These contain string representations of the python data
internally passed to <command>. "$HG_OPTS" is a dictionary of options
(with unspecified options set to their defaults). "$HG_PATS" is a list
of arguments. Hook failure is ignored.
(The documentation also goes into detail about what the config should actually look like and how hook scripts are called.)

Mercurial hook to test that username is valid when pushing to repository

I have a "central" repository that I want to ensure that no one pushes changes in to with a wrong user name.
But I can not figure out how to make a hook that tests the user name against a positive list. I have found in the Mercurial API a ctx.user() call that seems to be what I want to test my positive list against.
Also the hook could be a precommit hook that is distributed as part of the repository clone or it could be a hook on the central repository as a pre-incoming or something like that.
Any help or pointers would be greatly appreciated.
I have posted two functional examples on Bitbucket. Both examples are for searching a commit message for some specifically formatted text (like an issue tracked case ID), but could be easily modified to check a user against a list of valid users.
The first example is actually a Mercurial extension that wraps the 'commit' command. If it fails to find the appropriate text (or valid user in your case), it will prevent the commit from occurring at all. You can enable this in your .hgrc file by adding these lines:
[extensions]
someName = path/to/script/commit-msg-check.py
The second example uses a in-process pretxncommit hook, which runs between when the commit has been made, but before it becomes permanent. If this check fails it will automatically roll back the commit. You can enable this in your .hgrc file by adding these lines (assuming you kept the same file/function names):
[hooks]
pretxncommit.example = python:commit-msg-check-hook.CheckForIssueRecord
You can execute any Python code you like inside of these hooks, so user validation could be done in many ways.
Thanks for the examples dls.
In the end I decided to run it as a pretxnchangegroup hook and then use the hg log and grep to test the author field of the commits:
[hooks]
pretxnchangegroup.usercheck = hg log --template '{author}\n' -r \
$HG_NODE: | grep -qe 'user1\|user2\|etc'
It does of course not provide a very good feedback other than usercheck failed. But I think it is good enough for now.

How to use a relative pathname to a Mercurial hook

I have a script that is in the top level of my working copy and would like to use it as a Mercurial hook. If I use an absolute pathname to the hook then everything is fine, but I want a relative pathname so the whole thing can be easily moved around, used in other working copies and other developers can copy the hgrc as is.
/space/project/.hg/hgrc contains
[hooks]
update = genid
The genid script is at /space/project/genid
The hook is invoked just fine if I am in /space/project but if my current directory is /space/project/src/tools then 'hg update' will give an error as the hook cannot be found.
Python hooks cannot use a relative path. Script hooks can like this:
[hooks]
update = ./genid
In certain cases, environment variables are expanded in mercurial configuration. So you can check out if you can use a environment variable.
[hooks]
update = $MercurialHooks/genid
See Faq (12) in https://www.mercurial-scm.org/wiki/TipsAndTricks
I had the same problem and couldnt resolve it. The workaround was easy though! I versioned the file in the repo and just copied it to my .hg folder! Not ideal but it isnt that likely to change and other repo users can still get a copy of the file