Snippets

Adaptavist Ahead Behind Report Stash

Created by Jamie Echlin
package examples.stash

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
     */
    def projectKey = "SR"
    def repoSlug = "sr"

    // this is what you are comparing your branches to, to see if they are ahead/behind
    def baseRefName = "master"

    @Override
    Object run() {

        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>() {
            @Override
            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()
        }.sort {
            latestChangesetData[it.key].authorTimestamp
        }.each { ref, aheadBehindCount ->
            log.warn("Old branch: ${ref.displayId}, behind: ${latestChangesetData[ref].authorTimestamp.format("dd/MMM/yy")}")
        }
    }
}

@Canonical
class RefMetadataContextImpl implements RefMetadataContext {
    Ref baseRef
    Set<Ref> refs
    Repository repository
}

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.