3

I want a mercurial hook that will run JSLint/PyChecker/etc on all files that are modified. However, I do not have control over all hg clients, and want this to run on push to the master repository (which I have control), so a pretxnchangegroup hook on the master seems best.

How can I get a list of all changesets that are in the changegroup that is going to be committed?

I have seem other solutions that use a precommit hook, but these will not work for me because the clients may already have a commit that fails JSLint. In this case, they should be able to fix the errors in a new commit, and be able to push (both the bad and new commits) to the server successfully. The server just needs to check the most recent changeset on each branch, of every file that was modified in the changegroup.

Geoffrey Zheng
  • 6,562
  • 2
  • 38
  • 47
Knio
  • 6,638
  • 3
  • 29
  • 29

3 Answers3

4

You're right that you want a pretxnchangegroup hook, but you don't want to check all the new revisions -- because people will fix the errors you reject in subsequent changesets but if you're checking all changesets their work will never be accepted!

Instead either just check all files in all the heads, or use the hg status --rev x:y syntax to get a list of the changed files between the revision you already have and the tip revision you're receiving, and check only those files only in the tip revision.

If you really want the list of all revisions you'd use a revset ( hg help revsets ) new in version 1.6, but you really only want to check the results, not all the revisions that get you there.

Ry4an Brase
  • 78,112
  • 7
  • 148
  • 169
  • Right- I only want to check the heads, but I want to check the head of each file that was modified in the changeset, because a file may have been modified, but not in the head. Using `hg status --rev x:y`, how do I find `x` and `y`? the hook only seems to tell me `y`. Also, this seems to output every change between those dates? This includes commits by other people, not just the commits in the changegroup – Knio Sep 01 '10 at 19:53
  • X would be the last change set you do already had in that branch (be it named branch or anonymous branch). You could get that from a local clone created pre-changegroup and the union operator on the revsets feature. Honestly, though you should do what everyone does and just check all the .py files in each `hg heads` on changegreoup. It's not too inefficient. Either code the code the heads is good or bad, and code in the interstitial changesets is either still present in a head for checking or was removed/fixed and is thus no concern. – Ry4an Brase Sep 02 '10 at 10:48
  • We have about 1000 js/py files and running the script on every file for every head would be way too slow – Knio Sep 02 '10 at 19:04
3

I just wrote a pretxnchangegroup hook that does exactly this. If you want all files that have changed in the current changegroup, you can get the union of the output of these two commands:

hg status --rev $HG_NODE:

(note the trailing colon)

and

hg status --change $HG_NODE

When pushing between two repositories on the same machine, the first command seems to be sufficient, but when pushing to a remote repository, the first command would miss files changed in the first changeset in the changegroup, which is where the second command comes in.

According to http://www.selenic.com/mercurial/hgrc.5.html, "ID of the first new changeset is in $HG_NODE."

Marc
  • 767
  • 6
  • 18
  • This is still not quite a complete solution. `--rev` simply compares `$HG_NODE` to `HEAD` (or the working directory) and lists all files that are have changed, and does *not* included changes in revisions that happened in between. Consider the following: *User makes a commit in default which breaks the build – Knio Mar 16 '11 at 09:44
  • Consider the following: 1 User makes a new branch `bar` off of default (rev `f00`) 2 User checkes out `default` again and makes a commit in `default` which breaks file `one.py` (rev `f01`) 3 user checks out `bar` again, and makes an innocent commit in file `two.py` (rev `f02`) `hg status --rev $HG_NODE && `hg status --change $HG_NODE` now only reports the changes made in `f00`, and the difference between `f00` and `f02`. Since `one.py` is the same in both, it is not reported and `default` is broken – Knio Mar 16 '11 at 09:51
  • Also: this commenting system is frustrating – Knio Mar 16 '11 at 09:54
  • I'm not sure I understand what you're saying -- are you saying that pushing changes in bar to a central server will succeed, when the errors in default should prevent this? If so, this is by design - if I'm working in bar, why should random changes in default hinder my pushes? When someone pushes default, the script will catch these errors. – Marc Mar 24 '11 at 08:35
  • Wow - I see what you mean about the comment system. I couldn't figure out how to insert advanced formatting characters like newlines... But I apologize if I've misunderstood your complaint about this system. What did I miss? – Marc Mar 24 '11 at 08:37
  • When you push to the central repository, it pushes *all* of your commits, not just the ones in `bar`. So you can break `default` in `f01`, and push a broken head to `default` without this script noticing. Ideally it should not be possible for any head in the central repository to be broken. – Knio Mar 24 '11 at 09:56
0

Does my answer to this help at all? https://stackoverflow.com/a/8615156/1025457

It is the skeleton of a pretxnchangegroup hook that iterates over the nodes in the changegroup

Community
  • 1
  • 1
Truan
  • 379
  • 2
  • 10