A repository hook get a "refChanges" argument. With the help of "historyService" it is possible to list the changes involved in the push. Each change is a com.atlassian.stash.content.Changeset, which provides very basic informion about that change. It provides access to the author and the parents, but not to the committer and the actual change.
How do I get access to the committer and the actual change of a given change/commit from inside a pre receive repository hook?
What is the correct documentation I should read?
(I already found ScmService and GitCommandBuilderSupport. They look kind of promising, but I could not find out how to use them.)
Community moderators have prevented the ability to post new answers.
Hi Michael,
Apologies, I didn't read your question properly (at all apparently). You want the _Git_ committer, which is definitely stored but just not available. As you've hinted at you will unfortunately have to use one of the low-level Builders to retrieve that information by calling revList() and manually:
// Injected into the constructor private GitCommandBuilderFactory gitBuilderFactory; ... gitBuilderFactory.builder(repository).revList().build() .format("TODO") // Add your flags here .build(new MyCommandOutputHandler() { // TODO Parse the lines }).call();
And follow the types in your IDE is probably the best bet at that point. If you have access to the Stash source I would recommend looking at com.atlassian.stash.scm.git.common.ChangesetReader.
The fact that we don't parse the commits is baked into the very low levels of Stash I'm afraid and there isn't any configuration. You will have to parse the output of 'git rev-list' manually yourself. :(
I might see if this something we can make easier, but I can't promise anything.
Regarding the files themselves, you can use HistoryService.getDetailedChangeset() quite happily after figuring out which specific changesets you are interested in. This is a plugin that I wrote that checks the file size of a push, which might be useful?
https://bitbucket.org/atlassianlabs/stash-filesize-hook-plugin/src/b520fe77a2a5a2596d559f3358607721bcf6398a/src/main/java/com/atlassian/stash/plugin/filesize/FilesizeHook.java?at=master
Cheers,
Charles
Could you give an example for a suitable output handler? (I tried to find an example in the source by myself, but it is a pain without IDE support.)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Michael,
You will want to look in the :
plugins/scm-git/src/main/java/com/atlassian/stash/internal/scm/git/command/revlist folder for the relevant code.
How important is the commiter (and not just author) to your plugin by the way?
Charles
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Well in many cases author and commiter are the same, therefore it is fine to just check the author. But in case they are different usually the committer is the more important one, as the author only wrote the change, whereas the committer added it to the branch and is therefore responsible for that change. - I was a bit surprised to see the one available and the other missing. (Especially as they are treated equally at the lower layers.)
The plugin should make sure that all commits contain correct names and email addresses, i.e. there should be a matching entry in crowd.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks Michael, I was just curious.
Let me know if you get stuck on the OutputHandler.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
This really gets nasty... I probably need something like that:
private Person getCommitter(Changeset changeset) { return gitBuilderFactory.builder(changeset.getRepository()).revList() .format("%cn%x02%ce").limit(1).rev(changeset.getId()) .build(new CommitterHandler()).call(); } class MyPerson implements Person { private String name; private String email; public MyPerson(String name, String email) { this.name = name; this.email = email; } @Override public String getEmailAddress() { return email; } @Override public String getName() { return name; } } class CommitterHandler implements CommandOutputHandler<Person> { private Person committer; @Override public void process(InputStream output) throws ProcessException { BufferedReader reader = new BufferedReader(new InputStreamReader( output)); try { String line = reader.readLine(); if (line == null) { return; } if (!line.startsWith("commit")) { throw new IllegalStateException( "[" + line + "]: Unexpected output; expected a 'commit' object"); } line = reader.readLine(); if (line == null) { throw new IllegalStateException("Unexpected end of output; no changeset details were present"); } String[] pieces = StringUtils.splitPreserveAllTokens(line, '\u0002'); if (pieces.length != 2) { throw new IllegalStateException("Unexpected number of pieces found."); } committer=new MyPerson(pieces[0],pieces[1]); } catch (IOException e) { throw new IllegalStateException("read error."); } } @Override @Nullable public Person getOutput() { return committer; } @Override public void complete() throws ProcessException {} @Override public void setWatchdog(Watchdog watchdog) {} }
This reimplements much of the existing stash code. A better API would really be great.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
BTW, why do I need to explicitly use <component-import> for GitCommandBuilderFactory, but don't need this for HistoryService?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Positive. Have you imported the component?
<component-import key="gitCommandBuilderFactory" interface="com.atlassian.stash.scm.git.GitCommandBuilderFactory"/>
I'm actually not sure what the best way to find a comprehensive list of components.
Any stateless interfaces in our API javadocs are probably a fairly good bet.
https://developer.atlassian.com/stash/docs/latest/reference/java-api.html
https://developer.atlassian.com/static/javadoc/stash/latest/scm-git-api/reference/com/atlassian/stash/scm/git/GitCommandBuilderFactory.html
In the case of the Git plugin, if you have the source look at plugins/scm-git/src/main/resources/META-INF/pring/atlassian-plugins-components.xml and anything that is exported as osgi:service. In other cases it's normally in the relevant atlassian-plugin.xml as:
<component class="..." public="true" />
I know that isn't ideal, and I'll talk to the team internally to see if there is a better way to discover them.
Charles
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Oh, I see.
Why do I need to explicitly use <component-import> for GitCommandBuilderFactory, but don't need this for HistoryService?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
(oops, just rewrote my comment in the same minute you added your answer.)
BTW, why do I need to explicitly use <component-import> for GitCommandBuilderFactory, but don't need this for HistoryService?
With the component properly imported my plugin seems to work fine. Does the above code make sense to you? Do you have any ideas for improvements?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Basically anything that's exported to OSGI via the webapp doesn't need to be imported. In Stash's case that's anything in the API/SPI modules.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Michael,
EDIT: Please IGNORE this comment - it doesn't answer the question at all...
I'm sorry but we don't store anything about who made the push yet, there really isn't any way to retrieve that information from Git. We are definitely going to add this functionality, but I couldn't say when.
At the moment the only option would be to write a post-receive hook and store that information yourself.
You might be interested in the following:
https://jira.atlassian.com/browse/STASH-2715
https://jira.atlassian.com/browse/STASH-2852
Cheers,
Charles
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.