Script Console

The Script Console is the place for running one-off ad hoc scripts, and for learning and experimenting with the Bitbucket API.

Either enter your script directly in the browser, or click the File tab, and type the path to a file. The file can be a fully-qualified path name to a .groovy file accessible to the server. If you provide a relative path name, the file is resolved relative to your script roots. By default there is one script root automatically created, which is <stash_home>/scripts/.

Read more about script roots and script plugins.

Samples

Take one of these samples, and use it as a starting point for your own situation.

List all Repository Sizes By Project

Let’s start with computing the sizes of all repositories, and summing them by project. We might wish to identify the projects that are using the most disk space on our Bitbucket instance.

This will just dump the results as JSON to the console when run:

import com.atlassian.bitbucket.project.ProjectService
import com.atlassian.bitbucket.repository.Repository
import com.atlassian.bitbucket.repository.RepositoryService
import com.atlassian.sal.api.component.ComponentLocator

import groovy.json.JsonBuilder

import static com.onresolve.scriptrunner.canned.bitbucket.util.BitbucketCannedScriptUtils.unlimitedPager

def repositoryService = ComponentLocator.getComponent(RepositoryService)
def projectService = ComponentLocator.getComponent(ProjectService)

def allProjects = projectService.findAll(unlimitedPager).values // <1>
def sizeByProject = allProjects.collect { project ->

    def repos = repositoryService.findByProjectKey(project.key, unlimitedPager).values // <2>
    def repoSizes = repos.collectEntries { Repository repo ->
        [(repo.name): repositoryService.getSize(repo)] // <3>
    }

    [
        project     : project.name,
        totalSize   : repoSizes.values().sum(),
        repositories: repoSizes
    ]
}

"<pre>" + new JsonBuilder(sizeByProject).toPrettyString() + "</pre>"

Line 14: Get all projects in this instance

Line 17: Get all repositories for each project

Line 19: Get the size of each repository

That’s not fantastically useful…​ let’s format these into a table so we can see the size for each repository, grouped by project:

You can replace the final return line with the following code:


static String humanReadableByteCount(long bytes) {
    int unit = 1000
    if (bytes < unit) {
        return bytes + " B"
    }
    int exp = (int) (Math.log(bytes) / Math.log(unit))
    String pre = "kMGTPE".charAt(exp - 1)
    String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre)
}

def writer = new StringWriter()
def builder = new MarkupBuilder(writer)
builder.table(class: "aui") {
    thead {
        tr {
            th("Project Name")
            th("Repository Name")
            th("Size")
        }
    }
    tbody {
        sizeByProject.each { dataRow ->
            tr {
                td {
                    b(dataRow.project)
                }
                td()
                td {
                    b(humanReadableByteCount(dataRow.totalSize ?: 0))
                }
            }
            dataRow.repositories.each { repoRow ->
                tr {
                    td()
                    td(repoRow.key)
                    td(humanReadableByteCount(repoRow.value ?: 0))
                }
            }
        }
    }
}

writer.toString()

On clicking Run you should see something like:

Enable Repository Hooks on Multiple Repositories

Manually enabling and configuring Bitbucket hooks across multiple repositories is a time-consuming and error-prone business. The following example enables and configures a hook across all the repositories in a project. In this case it enables the excellent Repository Mirror Plugin for Stash, which allows synchronization to a remote repository, which could be on Bitbucket or GitHub for instance.

This script assumes that for each repository in a Bitbucket project, there is a corresponding empty GitHub repository. It could easily be enhanced to create the remote repository if not present.

import com.atlassian.sal.api.component.ComponentLocator
import com.atlassian.bitbucket.hook.repository.RepositoryHookService
import com.atlassian.bitbucket.repository.RepositoryService
import com.atlassian.bitbucket.util.PageRequestImpl

def repositoryService = ComponentLocator.getComponent(RepositoryService)
def repositoryHookService = ComponentLocator.getComponent(RepositoryHookService)

def final String MIRROR_HOOK_KEY = "com.englishtown.bitbucket-hook-mirror:mirror-repository-hook"

repositoryService.findByProjectKey("TEST", new PageRequestImpl(0, 100)).values.each { repository ->
    repositoryHookService.findAll(repository, new PageRequestImpl(0, 100)).values.each { hook ->

        def settings = repositoryHookService.createSettingsBuilder()
            .add("mirrorRepoUrl0", "git@github.com:<orgname>/${repository.slug}") // <1>
            .add("username0", "<github-username>") // <2>
            .add("password0", "<github-password>") // <3>
            .build()
        repositoryHookService.enable(repository, MIRROR_HOOK_KEY, settings)
    }
}

Line 15: Change orgname to your github organization or username

Line 16: Enter github username

Line 17: Enter github password

Delete all the Repositories in a Project

Bitbucket won’t let you delete a project if there are any repositories in it. Deleting them one by one is painful.

This script will delete all the repositories for any given project. Make sure you modify to include the correct project key.

Be sure this is what you want to do, there is no undo button.

import com.atlassian.sal.api.component.ComponentLocator
import com.atlassian.bitbucket.repository.Repository
import com.atlassian.bitbucket.repository.RepositoryService
import com.atlassian.bitbucket.util.Page
import com.atlassian.bitbucket.util.PageProvider
import com.atlassian.bitbucket.util.PageRequest
import com.atlassian.bitbucket.util.PagedIterable

def repositoryService = ComponentLocator.getComponent(RepositoryService)

def final projectKey = "AAA" /// delete repositories of this project

new PagedIterable<Repository>(new PageProvider<Repository>() {
    @Override
    Page<Repository> get(PageRequest pageRequest) {
        repositoryService.findByProjectKey(projectKey, pageRequest) as Page<Repository>
    }
}, 10).collect().each { Repository repository ->
    log.debug("Delete repository: ${repository.name}")
    repositoryService.delete(repository)
}

Bulk Project Permissions Update

After using Bitbucket for a while you may decide that you want to modify all projects to:

  • change the default access level

  • make them publicly accessible to non logged-in users

  • add a group with write permissions

  • remove a user or group from all projects

See default project / repository permissions listeners for a way to set default project / repository settings on creation.

The following snippet, will iterate over all of your projects, but not actually do anything. What follows after is a list of snippets whereby you can make changes similar to the examples.

import com.atlassian.sal.api.component.ComponentLocator
import com.atlassian.bitbucket.project.Project
import com.atlassian.bitbucket.project.ProjectService
import com.atlassian.bitbucket.project.ProjectUpdateRequest
import com.atlassian.bitbucket.permission.Permission
import com.atlassian.bitbucket.permission.PermissionAdminService
import com.atlassian.bitbucket.user.UserService
import com.atlassian.bitbucket.permission.SetPermissionRequest
import com.atlassian.bitbucket.util.Page
import com.atlassian.bitbucket.util.PageProvider
import com.atlassian.bitbucket.util.PageRequest
import com.atlassian.bitbucket.util.PagedIterable

def projectService = ComponentLocator.getComponent(ProjectService)
def permissionAdminService = ComponentLocator.getComponent(PermissionAdminService)
def userService = ComponentLocator.getComponent(UserService)

new PagedIterable<Project>(new PageProvider<Project>() {
    @Override
    Page<Project> get(PageRequest pageRequest) {
        projectService.findAll(pageRequest) as Page<Project>
    }
}, 10).each { project ->
    log.debug("Update project ${project.key}")

}

To use these snippets, add them to the code that iterates each project, immediately after the log.debug line, and before the closing }.

To enable public access to non-logged in users, add this:

    projectService.update(
        new ProjectUpdateRequest.Builder(project)
            .publiclyAccessible(true)
            .build()
    )

To grant a default permission to the project:

    permissionAdminService.revokeAllProjectPermission(
        Permission.PROJECT_WRITE, project) // <1>

    permissionAdminService.grantAllProjectPermission(
        Permission.PROJECT_READ, project)

Line 2: if you need to revoke previously given WRITE privileges

Add a group to all projects with a particular permission:

    def setPermissionRequest = new SetPermissionRequest.Builder()
        .projectPermission(Permission.PROJECT_WRITE, project) // <1>
        .group("project-creators") // <2>
        .build()

    permissionAdminService.setPermission(setPermissionRequest)

Line 2: PROJECT_READ and PROJECT_ADMIN does what you expect

Line 3: Set the name of the group to add

Remove a group from all projects:

    permissionAdminService.revokeAllProjectPermissions(project, "authorised-devs")

Remove a user from all projects:

    permissionAdminService.revokeAllProjectPermissions(
        project, userService.getUserByName("anuser")
    )

Further Examples

On this page