How to access individual change information (eg size) in a changeset in a Stash pre-receive hook

Hi

We would like to implement a pre-commit hook to prevent users from committing too large files as this may be an issue in the long term (and some of our users are used to do it in other VCS)

I have looked at the examples and they seem simple enough. Also looked at this other question https://answers.atlassian.com/questions/145729/how-to-access-the-commit-message-in-pre-receive-hook that explains how to get to the commit message but what we would like to access is the individual changes' metadata, like name and size.

Is this possible at all? Of course we would like to reject the push in case any of the changes/files is larger than what we allow.

Thanks

Daniel

2 answers

1 accepted

Accepted Answer
1 vote

Hi Daniel,

I couldn't help myself, I've put together an example plugin which should do the trick.

https://bitbucket.org/atlassianlabs/stash-filesize-hook-plugin

It's worth re-iterating that for each branch being pushed there are going to be _three_ git calls invoked on the server. This is not an entirely free operation and you may potentially see a small lag for each push. Testing it locally with some small commits seems very snappy, but I just want to warn you up-front.

Let me know if you have any trouble or thoughts.

Cheers,

Charles

Thanks a lot Charles

I will test it as soon as possible and report any issues

Daniel

Hi Daniel,

That's a tricky question. Getting the file names is relatively easy with the current API.

  1. Get a list of changesets from getChangesetsBetween as mentioned in that previous answer
  2. Use getDetailedChangesets() with the list of changesetIds
    1. Each DetailedChangeset will have a list of changes
    2. Each change will have a path and contentId

At this point things get a little complicated. Up until this point you've only had to use our high-level API, and more importantly you've only had to make two low-level Git calls (which is one too many really). With the information you have here you _could_ restrict commits based on a set of file extensions. So for example on a Java project you probably never want to allow '.jar' files, regardless of the size. For your use-case this might be enough.

If you want to work out the filesize then you'll need to start making manual Git calls (ie this but in Java). Unfortunaty we don't have a high-level, or even medium-level API on which you can retrieve the Git blob (ie file) sizes from. However with the current scm-git API (ie low-level) you _could_ do:

  1. Inject GitCommandBuilderFactory and build() from the current Repository
  2. Call command("cat-file").argument("--batch-check")
  3. Call inputHandler() with a new CommandInputHandler
  4. The method you're interested in is "process(OutputStream out)" which you will want to write out the list of new-line separated contentIds calculated from the detailedChangesets above
  5. Finally on the CommandBuilde from step 2 you want to call build() with a new CommandOutputHandler
  6. On process() read each line from the InputStream
    1. Each line will look like "e1e81eef05fad9a709e5498acf37b6de413109c7 blob 12117\n"
    2. The part you're interested in is the last section, which is the blob size
    3. This blob size is just the filesize on disk, it doesn't give you any indication of whether that file is text or not. Generally you care less about large text files, but if the file is binary then size is much more relevant.

I've skipped proper error handling and all that stuff. Sorry I don't have time right now to actually code this in an example plugin. It's actually a really good idea for a plugin and it would make a good example of how to use our scm API. This is the kind of thing we have to do regularly to implement our high-level APIs (like HistoryService).

There _may_ be a better way to do this, in which case I apologise in advance if I lead you astray. I hope this helps.

Charles

Thanks a lot Charles

I will try to implement something with the information you provide. In principle it seems clear enough.

Suggest an answer

Log in or Sign up to answer
Community showcase
Posted Tuesday in Featured Groups

Tuesday tips & tricks: What is the Atlassian Community?

It's officially Tuesday, which means it's officially time for another tip to help you better navigate this space we call the Atlassian Community. 😄 I got a great question from community member, Sa...

91 views 3 6
View post

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you