BitBucket PostRepositoryHook plugin question

Hello,

I am a new-bee to BitBucket plugin development… I am trying to create a plugin that will call a SonarQube scan when a branch is merged into another branch (from a PR to a ‘master’ branch - after the PR has been merged); our workflow is that we maintain a ‘baseline’ scan on Master branch. This Master branch needs to be scanned by SonarQube sonar-scanner (currently calling from command line but I have a Maven configuration ready to go);

I am predicating my code on the example found here:

https://developer.atlassian.com/bitbucket/server/docs/latest/how-tos/hooks-merge-checks-guide.html

I suppose I just replace the code in the postUpdate method to call out to Maven? I have found some ways to do that thanks to Stack, but not sure if it is “how it is done” or just “how it can be done” - there’s a difference, I’m sure… what is the preferred way to do this?

example code

 public void postUpdate(@Nonnull PostRepositoryHookContext context, 
                           @Nonnull RepositoryHookRequest hookRequest) {
        Logger.info("[{}] {} updated [{}]",
                hookRequest.getRepository(),
                hookRequest.getTrigger().getId(),
                hookRequest.getRefChanges().stream()
                    .map(change -> change.getRef().getId())
                    .collect(Collectors.joining(", ")));
    }```


I appreciate your replies!

Hi @ratboyDC,

Welcome to Atlassian! I’m curious whether your code worked or didn’t? Or is the question mainly for best practice?

Cheers,
Anne

Hello,

It is a “what is the best way to do this?” as opposed to a “will this work?”

I have a discussion with an engineer at my current company who has done this in accordance with their internal S&P’s later today, so I’ll discuss it with her and get her advice on how they prefer it implemented.

Thanks!

Hi @ratboyDC,

There are two ways in which I think you can do this. If any change to master (adding or removing commits) needs to trigger a rescan then adding a RepositoryRefsChangedEvent listener should be enough. The event carries a collection of refs which have been updated so finding refs/heads/master there should allow you to trigger the rescan.

    @EventListener
    public void onRepositoryRefsChanged(RepositoryRefsChangedEvent event) throws Exception {
        if (!shouldScan(event.getRepository())) {
            return;
        }
        event.getRefChanges().stream()
                .filter(refChange -> Objects.equals(refChange.getRef().getId(), "refs/heads/master"))
                .findFirst()
                .ifPresent(refChange -> scanMaster());
    }

If you need finer control over when the scanning should happen, our PostRepositoryHook SPI should allow you to get the information you need.

It’s worth noting that this SPI will not tell you if branch A was merged into branch B. Our merge triggers refer to merges executed by the system (e.g.: for a pull request), but a user could merge two branches remotely and push the ref updates. It will however let you know if commits were added or removed to a specific ref, thus letting you decided if you need to re-scan master.

In your PostRepositoryHook implementation you can check if the repository should be scanned. If so, you’ll need to register a RepositoryHookCommitCallback using the RepositoryHookCommitFilter#ADDED_TO_ANY_REF filter and onCommitAdded check the ref ID to see if it’s master. Not sure if you also care about commits being removed from master in which case you’ll also need the RepositoryHookCommitFilter#REMOVED_FROM_ANY_REF filter and implement onCommitRemoved. Finally you can implement onEnd to trigger your scan.

Something like this:

    public class SonarScannerHookCommitCallback implements RepositoryHookCommitCallback {

        private boolean rescan;

        @Override
        public boolean onCommitAdded(@Nonnull CommitAddedDetails commitDetails) {
            if (Objects.equals(commitDetails.getRef().getId(), "refs/heads/master")) {
                rescan = true;

                //We already know we need to rescan so return false so we'll stop being fed commits
                //and end the git command execution early
                return false;
            }
            return true;
        }

        public void onEnd() {
            if (rescan) {
                //TODO: Trigger Sonar rescan
            }
        }
    }

Hope this answers your question!

Regards,
Juan Palacios

Hi, jpalacios - very much appreciate the reply. I’ll follow your instructions and crank something out in the next couple of days to see if I can get this functionality delivered to my architect.