You can now vote for scripts to help people know if they're useful or not. Login or create an account to vote!

1

Check PR reviewers on leave

Overview

Check if a PR reviewer is on leave.

Example

As a developer, I am ready to create a Pull Request and I must select at least one reviewer. I want to know if a potential reviewer is on leave.

Good to Know

  • This script must be configured as a Custom listener for the PullRequestOpenedEvent event by someone with at least global administrator permission.
  • If a reviewer is on leave, the PR will not be blocked. This script will just add a comment to notify the PR creator.
  • The script connects to BambooHR to check reviewer status. BambooHR's API_TOKEN should be used as 'username' with basic authentication, while the password can be any string. For more info see https://documentation.bamboohr.com/docs/getting-started#authentication

Requirements

  • Bitbucket Bitbucket (6.0 - 7.17)
  • ScriptRunner for Bitbucket ScriptRunner for Bitbucket (6.18.0)
    
/** * Please note: This is an example for a small/medium size company and makes 2 API calls to BambooHR. It follows these steps: * 1) Fetch the complete employee directory https://documentation.bamboohr.com/reference#get-employee. * 2) Fetch all employees on leave https://documentation.bamboohr.com/reference#get-employee (this does not include the employees' work email addresses). * 3) Combine the above to create a list of employees (including work email addresses) who are on leave. * 4) Compare the above with the PR reviewers' email addresses. * * * Since this strategy will fetch all your company employees, you might want to consider using * cache, or go for a different approach. For example, run the 'time_off/whos_out' call first, * then call https://documentation.bamboohr.com/reference#get-employee to retrieve each worker's email address by their employee id. * This will trigger a lot more API calls, but might be easier to cache. */ import com.atlassian.bitbucket.comment.AddCommentRequest import com.atlassian.bitbucket.comment.CommentService import com.atlassian.bitbucket.comment.Commentable import com.atlassian.bitbucket.user.UserService import com.atlassian.bitbucket.user.SecurityService import com.atlassian.sal.api.component.ComponentLocator import groovyx.net.http.ContentType import groovyx.net.http.RESTClient import groovyx.net.http.HttpResponseDecorator import java.time.format.DateTimeFormatter import java.time.LocalDate /** * Replace the url with your organisation's BambooHR REST API. * If you can access BambooHR at https://mycompany.bamboohr.com, then your companyDomain is "mycompany". */ final String BASE_URL = 'https://api.bamboohr.com/api/gateway.php//v1/' /** * Replace this token. To create one, follow these steps: * - Log in BambooHR, click your account > API Keys > Add New Key. * - Fill in 'API Key Name' and click 'Generate Key'. * - Copy the 'API key' and paste it here. */ final API_KEY = '' /** * The username of the BitBucket account that will add the PR comment. */ final String BB_USER_ID = '' /** * The projects and repositories where this script will be applied to. * Consists of comma separated [Project / Repository] pairs. * By convention, each entry will be in a / format where: * - is the Key of the Project, see 'Key' column in Projects screen. * - is the URL-friendly name of the repository. * * Both values can be found in your browser URL when you navigate to a repository page, as the url will look like: * "http:///bitbucket/projects//repos//browse" * */ final def PROJECT_REPOS = ['PROJECT_Y/rep_0', 'PROJECT_X/rep_1', 'PROJECT_X/rep_2', 'PROJECT_Z/rep_3'] def matchingRepo def matchingProj PROJECT_REPOS.each { projRepoPair -> def splitStr = projRepoPair.split('/') def proj = splitStr[0] def repo = splitStr[1] if (proj == event.pullRequest.toRef.repository.project.key && repo == event.pullRequest.toRef.repository.slug ) { matchingRepo = repo matchingProj = proj } } if (!matchingProj || !matchingRepo) { return } if (!event.pullRequest.reviewers) { return } def restClient = new RESTClient(BASE_URL) restClient.auth.basic(API_KEY, 'x') class Employee { int employeeID String displayName String email } Map getEmployees(RESTClient restClient) { def result = [:] restClient.handler.failure = { HttpResponseDecorator response -> handleFailedResponse(response) } restClient.handler.success = { response, Map data -> result = data.employees.collect { Map employee -> [(employee.id as int): new Employee( employeeID: employee.id as int, displayName: employee.displayName as String, email: employee.workEmail as String )] }.collectEntries() } restClient.get( path: 'employees/directory', contentType: ContentType.JSON ) result as Map } List getPeopleOnHolidays(RESTClient restClient) { def employees = getEmployees(restClient) List idsOfEmployeesOnHoliday def formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd') def todaysDate = LocalDate.now().format(formatter) restClient.handler.failure = { HttpResponseDecorator response -> handleFailedResponse(response) } restClient.handler.success = { response, data -> idsOfEmployeesOnHoliday = data.collect { Map employee -> employee['employeeId'] as Integer } } restClient.get( path: 'time_off/whos_out', contentType: ContentType.JSON, query: [end: todaysDate] ) idsOfEmployeesOnHoliday.collect { employees[it] } } def handleFailedResponse(HttpResponseDecorator response) { log.error("There was a problem calling BambooHR API ${response.statusLine}") throw new IllegalStateException("${response.statusLine} ${response.headers['X-BambooHR-Error-Message']}") } def peopleOnHolidays = getPeopleOnHolidays(restClient) def reviewersOnHoliday = event.pullRequest.reviewers.findAll { reviewer -> peopleOnHolidays.find { it.email.equalsIgnoreCase(reviewer.user.emailAddress as String) } } if (reviewersOnHoliday) { def holidayBotUser = ComponentLocator.getComponent(UserService).getUserByName(BB_USER_ID) def securityService = ComponentLocator.getComponent(SecurityService) securityService.impersonating(holidayBotUser, 'adding holiday comment').call { def commentService = ComponentLocator.getComponent(CommentService) def reviewersOnHolidayMentions = reviewersOnHoliday.collect { "@${it.user.name}" }.join(' ') def commentText = ":palm_tree: Hey @${event.pullRequest.author.user.name} it looks like you added the following users as reviewers, but they are on leave: ${reviewersOnHolidayMentions} :coconut:" commentService.addComment(new AddCommentRequest.Builder(event.pullRequest as Commentable, commentText).build()) } }
Discovered an issue? Report it here

Suggested for you