Stash merge-check hook for deploying changed code

I am trying to write a merge-check hook that will take the list of changed files from a pull request and run a system command on them, effectively for deployment. I only want to deal with the changed files as the repositories I will be dealing with have thousands of files in a single directory. I would just write a bash script, but need the configurability the Stash UI provides.

I've got a demo hook running with atlas-run, so I've got the very basics going. I know that, were I on the command line, I could run 'git diff --name-only master..pullrequest_branch' for a list of changed files, which I can copy into a temp directory with 'git cat-file', 'git show', etc. Right now my bottle neck is just getting access to the repository.

First of all, should I be using system calls for the above actions, or can I get this information using the built in git libraries?

Second, how do I get that information from my repository? Using the git library, I can probably use the hook's context directly, but if I am running the system calls, how do I get the directory from which I need to run these commands?

7 answers

1 accepted

Accepted Answer
1 vote

Hi Benjamin,

If you're writing a merge-check my advice would be to stick to the Stash API where possible. For normal operations like comparing revisions and getting the file contents we have already handled all the plumbing for you.

Jason has got some useful advice here. You will probably be interested in the HistoryService.getChanges() method, which is basically your 'git diff' command.

https://answers.atlassian.com/questions/171295/stash-pre-receive-hook-plugin-accessing-committed-contents

And I link to my plugin which does some/most of what you want here:

https://bitbucket.org/atlassianlabs/stash-filesize-hook-plugin/src/master/src/main/java/com/atlassian/stash/plugin/filesize/FilesizeHook.java?at=master

I know there's a fair amount of Java noise in there. :( I use cat-file to get the file size, but we have a ContentService.streamFile if you're just looking to do a 'git show'.

If you just want the repository directory you can get it from:

https://developer.atlassian.com/static/javadoc/stash/latest/api/reference/com/atlassian/stash/server/ApplicationPropertiesService.html#getRepositoryDir(com.atlassian.stash.repository.Repository)

You'll then need to fork out to Git and parse the results yourself. As mentioned above, if you can navigate our Java API I would recommend sticking with what we have as it should (hopefully) make your life a little easier.

Let me know if you have any more specific questions or need help with your plugin/hook.

Cheers,

Charles

Right now I'm thinking the simplest solution is to get the repository directory and then fork to a script to do the actual heavy lifting. There is just too much Java noise to sift through for what I need, and I know exactly what git commands I need to run to get what I want.

I'm trying to call the getRepositoryDir() function you linked above, but get an error:

cannot find symbol
symbol  : method getRepositoryDir(com.atlassian.stash.repository.Repository)

I have added

import com.atlassian.stash.server.*

to the top of my java file and I am just calling the function like so:

System.out.println("repo " + getRepositoryDir(context.getRepository()));

Any idea why I am getting that error?

I just realized that getRepositoryDir is a class function, so that is problem one. I tried creating an ApplicationPropertiesService, but get an error saying that the class is abstract and cannot be instantiated, and if I try to call ApplicationPropertiesService.getRepositoryDir(), I get an error saying that it cannot be referenced from a static context.

Is there an ApplicationPropertiesService object somewhere else that I should be calling this function on?

I added an ApplicationPropertiesService argument to my plugin constructor and it is now magically working. I'm not totally sure how it know to pass things into the constructor, but I'll just accept it and move on for now.

I decided to try a bit harder to use the API and made some progress, but it seems that the version of HistoryService's getChangesetBetween() that you are using is deprecated. I'm trying to update it to use a newer version, but am getting errors in my import lines. I made a new question for this problem here: https://answers.atlassian.com/questions/209860/cannot-find-symbol-class-changesetsbetweenrequest

Putting exported Stash services in the constructor will autowire them using Spring. Not sure that necessarily helps explain how it works, but it's a long story. That's how all the Atlassian plugins work though.

Charles

Just realized that merge-check might not be the best choice. This deployment hook could potentially fire before other possibly blocking checks. The problem of doing a post-receive hook is that finding the list of changed files might be more challenging. If anyone has a solution to that, I'm all ears.

For my purposes, I can log the last successful deployment in a file outside of stash and use that as a reference to get the changed files, so that problem is solved. Now I just need the original question solved: how do I access files in the current repository?

Hi again,

If you're deploying something I _definitely_ wouldn't do this as part of a merge check. They fire every time a user views a pull request page.

You should be able to do the deploy as part of post-receive hook and/or just listen specfiically for PullRequestMergedEvent which has a list of RefChange objects which you can then diff as you would in the merge-check. Does that make sense?

Cheers,

Charles

Hi Ben,

Was your last comment "how do I access files in the current repository" answered in some part from my response below? Specifically you can use the ContentService to get access to the file stream and HistoryService to do the diff.

Charles

One last thing - I'm just wondering if this could be done as part of a normal build operation? Normally the Stash team (and Atlassian in general) would do deployments from a Bamboo plan when a branch (ie master) has changed. Bamboo 5.0 even has a new deployments feature.

This may not be possible in your scenario, depending on what configuration in Stash you're providing and how critical it is to the build scripts to know what changed in any given merge (that may be available to the plan, I'm not 100% sure).

</sales-pitch> :)

Charles

I think what you have provided will get me going. It has been a few years since I've done anything in Java, so I'm still just trying to wade through all this stuff. Thanks for the pointers. I'll let you know if I have more questions.

Suggest an answer

Log in or Sign up to answer
Community showcase
Published Aug 21, 2018 in Bitbucket

Branch Management with Bitbucket

As a project manager, I have discovered that different developers want to bring their previous branching method with them when they join the team. Some developers are used to performing individual wo...

2,378 views 9 12
Read article

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