+import com.atlassian.plugin.PluginAccessor
+import com.atlassian.sal.api.component.ComponentLocator
+import com.atlassian.stash.commit.CommitService
+import com.atlassian.stash.internal.branch.LatestChangesetMetadataProvider
+import com.atlassian.stash.internal.branch.list.aheadbehind.AheadBehindRefMetadataProvider
+import com.atlassian.stash.repository.*
+import com.atlassian.stash.scm.ScmService
+import com.atlassian.stash.scm.git.GitCommandBuilderFactory
+import com.atlassian.stash.util.Page
+import com.atlassian.stash.util.PageProvider
+import com.atlassian.stash.util.PageRequest
+import com.atlassian.stash.util.PagedIterable
+import com.onresolve.scriptrunner.runner.ScriptRunnerImpl
+import com.onresolve.scriptrunner.runner.customisers.WithPlugin
+import groovy.transform.Canonical
+import groovy.util.logging.Log4j
+@Log4j(category = "com.onresolve.examples")
+@WithPlugin("com.atlassian.stash.stash-branch-utils")
+class AheadBehindReport extends Script {
+ def scmService = ComponentLocator.getComponent(ScmService)
+ def repositoryService = ComponentLocator.getComponent(RepositoryService)
+ def repositoryMetadataService = ComponentLocator.getComponent(RepositoryMetadataService)
+ def pluginAccessor = ComponentLocator.getComponent(PluginAccessor)
+ def gitCommandBuilderFactory = pluginAccessor.getEnabledPluginModule(ScriptRunnerImpl.PLUGIN_KEY + ":gitCmdBuilderFactory").getModule() as GitCommandBuilderFactory
+ Modify these three lines
+ // this is what you are comparing your branches to, to see if they are ahead/behind
+ def baseRefName = "master"
+ def repository = repositoryService.getBySlug(projectKey, repoSlug)
+ def baseRef = repositoryMetadataService.resolveRef(repository, baseRefName)
+ def builder = new RepositoryBranchesRequest.Builder().repository(repository).build()
+ def branches = new PagedIterable<Branch>(new PageProvider<Branch>() {
+ Page<Branch> get(PageRequest pageRequest) {
+ repositoryMetadataService.getBranches(builder, pageRequest)
+ }, PageRequest.MAX_PAGE_LIMIT).findAll {
+ it.displayId != baseRefName
+ def refs = branches as Set<Ref>
+ def latestChangesetMetadataProvider = new LatestChangesetMetadataProvider(scmService)
+ def latestChangesetData = latestChangesetMetadataProvider.getMetadata(new RefMetadataContextImpl(baseRef, refs, repository))
+ def aheadBehindRefMetadataProvider = new AheadBehindRefMetadataProvider(ComponentLocator.getComponent(CommitService))
+ def metadata = aheadBehindRefMetadataProvider.getMetadata(new RefMetadataContextImpl(baseRef, refs, repository))
+ def mergedBranches = metadata.findAll { ref, aheadBehindCount ->
+ aheadBehindCount.ahead == 0 && aheadBehindCount.behind > 0
+ mergedBranches.keySet().each { ref ->
+ log.warn("delete: ${ref.displayId}, last modified: ${latestChangesetData[ref].authorTimestamp.format("dd/MMM/yy")}")
+ // uncomment this line to remove the branch
+ // gitCommandBuilderFactory.builder(repository).branch().delete(ref.displayId).build().call()
+ // look for branches without a pull request for which the last commit was greater than six weeks ago
+ Calendar cal = Calendar.getInstance()
+ cal.add(Calendar.DAY_OF_YEAR, -42)
+ metadata.findAll { ref, aheadBehindCount ->
+ aheadBehindCount.ahead > 0 &&
+ aheadBehindCount.behind > 0 &&
+ latestChangesetData[ref].authorTimestamp < cal.getTime()
+ latestChangesetData[it.key].authorTimestamp
+ }.each { ref, aheadBehindCount ->
+ log.warn("Old branch: ${ref.displayId}, behind: ${latestChangesetData[ref].authorTimestamp.format("dd/MMM/yy")}")
+class RefMetadataContextImpl implements RefMetadataContext {