Skip to content

Bitbucket Pull Request Dashboard

This example demonstrates how to create a dashboard component that displays the information of all open Pull Requests from Bitbucket repositories associated with a Jira project.

Populated PR Dashboard

High-Level Overview

We're going to create a dashboard that receives events from Bitbucket whenever a Pull Request is created, updated, merged, or declined. The dashboard will display the information of all open Pull Requests from Bitbucket repositories associated with a Jira project.

To achieve this we'll use:

  • Webhooks from the Bitbucket repository to get data into our dashboard.
  • Some Webhook Transforms to convert the native Bitbucket Webhook events into the structure we want to display.
  • A Data List to store and manage the Pull Request data.
  • A Dynamic Table to display the Pull Request data inside the Jira project.

Youtube Video



Getting data from Bitbucket

The dashboard we're creating needs to receive and store two events from Bitbucket:

  1. Whenever a Pull Request is Created or Updated.
  2. Whenever a Pull Request is Merged or Declined.

Creating Webhook Transforms

Before we set up the Webhooks in Bitbucket, we need to create the Webhook Transforms that will convert the Bitbucket Webhook events into the structure we want to display in the dashboard.

We need to do this first so that we know the Webhook Transform URL's to use when setting up the Webhooks in Bitbucket.

Pull Request Created or Updated

The first Webhook Transform we'll create is for whenever a Pull Request is Created or Updated.

Because the payload sent from Bitbucket is the same for both events, and App Maker's Data List functionality automatically handles both "create" and "update" operations, we can just create a single Webhook Transform for both.

TIP

Feel free to copy/paste the JSON below for your own use-cases, and then modify the source and target values as needed.

Just make sure to replace the resourceKey with a project key that matches the project you want to display the data in.

json
{
	"action": "set",
	"resourceType": "site",
	"title": "bitbucket-pr-updated",
	"transformTarget": "list",
	"transformData": {
		"fieldMaps": [
			{
				"source": "'add'",
				"target": "action"
			},
			{
				"source": "'project'",
				"target": "resourceType"
			},
			{
				"source": "'AMT'",
				"target": "resourceKey"
			},
			{
				"source": "'bitbucket-prs'",
				"target": "title"
			},
			{
				"source": "'id'",
				"target": "listItemKey"
			},
			{
				"source": "body.pullrequest.id",
				"target": "listItem.id"
			},
			{
				"source": "body.pullrequest.title",
				"target": "listItem.title"
			},
			{
				"source": "body.pullrequest.author.display_name",
				"target": "listItem.author"
			},
			{
				"source": "body.pullrequest.state",
				"target": "listItem.status"
			},
			{
				"source": "body.pullrequest.links.html.href",
				"target": "listItem.link"
			},
			{
				"source": "body.pullrequest.comment_count",
				"target": "listItem.commentCount"
			},
			{
				"source": "body.pullrequest.task_count",
				"target": "listItem.taskCount"
			},
			{
				"source": "body.repository.full_name",
				"target": "listItem.repoName"
			},
						{
				"source": "body.repository.links.html.href",
				"target": "listItem.repoLink"
			}
		]
	}
}

Above we create a Webhook Transform that:

  • Is scoped to the site resource type.
  • Has a title of bitbucket-pr-updated.
  • Has a transformTarget of list, so that we know we want to store the data in a List, rather than in a single Custom Data object.
    • This is important because we want to store multiple Pull Requests in the same List, and then display each of them separately in a table.

What that Webhook Transform does is defined inside the transformData.fieldMaps list:

  • We set the action field to 'add', so that the List knows to add a new item each time this transform runs.
  • We set the resourceType field to 'project', so that the list being operated on is scoped to a project.
  • We set the resourceKey field to 'AMT', so that the list being operated on is scoped to the project with the key 'AMT'.
  • We set the title field to 'bitbucket-prs', so that we can specify exactly which list within that scope we want to operate on.
  • We set the listItemKey field to 'id', so that the List knows which field in each list item to use as the unique identifier.
  • Finally, we map a whole heap of fields from the Bitbucket Webhook payload to the fields we want to store in the List.
    • Note that up to this point, the fields we've mapped are all static values, indicated by the single quotes around the source value.

How this works:

Once created, App Maker will return a Webhook Transform URL that we can use when setting up the Webhook for the created/updated event in Bitbucket.

So what will happen is that whenever a Pull Request is created or updated, the Webhook Transform will add a new item to the specified list with all the relevant information from the Bitbucket Webhook payload.

Because the id field is used as the unique identifier, if the same Pull Request is updated multiple times, the List will only store the latest version of the Pull Request.


Pull Request Merged or Declined

The second Webhook Transform we'll create is for whenever a Pull Request is Merged or Declined.

Whenever either of these events happen, we want to remove the Pull Request from the List of open Pull Requests.

json
{
	"action": "set",
	"resourceType": "site",
	"title": "bitbucket-pr-closed",
	"transformTarget": "list",
	"transformData": {
		"fieldMaps": [
			{
				"source": "'remove'",
				"target": "action"
			},
			{
				"source": "'project'",
				"target": "resourceType"
			},
			{
				"source": "'AMT'",
				"target": "resourceKey"
			},
			{
				"source": "'bitbucket-prs'",
				"target": "title"
			},
			{
				"source": "'id'",
				"target": "listItemKey"
			},
			{
				"source": "body.pullrequest.id",
				"target": "listItem.id"
			}
		]
	}
}

Above we create a Webhook Transform that:

  • Is scoped to the site resource type.
  • Has a title of bitbucket-pr-closed.
  • Has a transformTarget of list.

What that Webhook Transform does is defined inside the transformData.fieldMaps list:

  • We set the action field to 'remove', so that the List knows to remove an item from the list each time this transform runs.
  • We set the resourceType field to 'project', so that the list being operated on is scoped to a project.
  • We set the resourceKey field to 'AMT', so that the list being operated on is scoped to the project with the key 'AMT'.
  • We set the title field to 'bitbucket-prs', so that we can specify exactly which list within that scope we want to operate on.
  • We set the listItemKey field to 'id', so that the List knows which field in each list item to use as the unique identifier.
  • Finally, we specify the exact field in the Bitbucket Webhook payload that represents the Pull Request ID, so that the List knows which item to remove.

How this works:

Once created, App Maker will return a Webhook Transform URL that we can use when setting up the Webhook for the merged/declined event in Bitbucket.

So what will happen is that whenever a Pull Request is merged or declined, the Webhook Transform will find the item in the specified list with an id property matching the PR, and remove it from the List of open Pull Requests.

Setting up Webhooks in Bitbucket

Now that we have our Webhook Transforms set up, and we have URL's for each of them, we can go ahead and set up the Webhooks in Bitbucket. This example doesn't cover how to set up Webhooks in Bitbucket in detail, but you can find the official Bitbucket documentation here.

Bitbucket Webhooks

You will need to create two separate Webhooks, one that fires on PR's being created or updated, and one that fires on PR's being merged or declined.

When setting up the Webhooks, you will need to provide the URL's for the respective Webhook Transforms you created earlier.

Creating the dashboard in Jira

At this stage you should now have Webhooks set up in Bitbucket that send data to the Webhook Transforms in App Maker. These Webhook transforms will store and manage the data in a List within App Maker that we can then display in the UI.

The last step of the process is creating the dashboard in Jira that displays the list of all the open PR's for users to be able to access.

json
{
	"action": "set",
	"resourceType": "project",
	"resourceKey": "AMT",
	"title": "pr-table",
	"module": "jira:projectPage",
	"componentData": {
		"type": "TabPanel",
		"tabTitle": "Bitbucket Pull Requests",
		"children": [
			{
				"type": "FullPageSection",
				"title": "Bitbucket Pull Requests",
				"children": [
					{
						"type": "ParagraphMedium",
						"content": "This table displays all the open Pull Requests from Bitbucket for this Project"
					},
					{
						"type": "DynamicTable",
						"columnHeaders": [
							{
								"type": "TableHeader",
								"title": "PR Title",
								"valuePath": "title",
								"linkPath": "link"
							},
							{
								"type": "TableHeader",
								"title": "Repo",
								"valuePath": "repoName",
								"linkPath": "repoLink"
							},
							{
								"type": "TableHeader",
								"title": "Author",
								"valuePath": "author"
							},
							{
								"type": "TableHeader",
								"title": "Status",
								"valuePath": "status",
								"fieldType": "lozenge",
								"appearanceMap": {
									"discovery": [
										"Open",
										"open",
										"OPEN"
									],
									"success": [
										"Closed",
										"closed"
									]
								}
							},
							{
								"type": "TableHeader",
								"title": "Comment Count",
								"valuePath": "commentCount"
							},
							{
								"type": "TableHeader",
								"title": "Task Count",
								"valuePath": "taskCount"
							}
						],
						"tableRows": "{{list: lists.project.bitbucket-prs}}"
					}
				]
			}
		]
	}
}

The UI Update above will create the following:

  • A new Custom App.
  • Scoped to the same project as the Data List storing the PR data (AMT).
  • With a title of pr-table.
  • And displaying in the jira:projectPage module.
    • This module creates a new full-page tab in the project sidebar.

Inside that Custom App we add:

  • A TabPanel component (required as the top-level component in most modules).
    • With a title of Bitbucket Pull Requests.
  • A FullPageSection component.
    • With a title of Bitbucket Pull Requests.
  • A ParagraphMedium component with some introductory text.
  • And a DynamicTable component.
    • With a list of columnHeaders that define the columns in the table.
    • And a tableRows property that specifies we want to use the list we created earlier as the data for the table (lists.project.bitbucket-prs).

Final Steps:

Go ahead and create that Custom App in your Jira project (making sure that you use a Project key that matches the one you used in the Webhook Transforms).

Then open up Jira and navigate to the project you created the Custom App in. You should see an option in the sidebar called "Custom Apps", and if you open that, a tab labelled Bitbucket Pull Requests.

Empty PR Dashboard

BUT... you won't see any data in the table yet, because we haven't actually created any Pull Requests in Bitbucket, and App Maker can only see data that was sent to it AFTER the Webhook Transforms were created.

To resolve this, simply head over to Bitbucket and create a PR (or push code to an existing one) and you should see the data appear in the table.