Successful jenkins build remains "In Progress" in Bitbucket - and how to workaround

Posted in development, ci on January 13, 2021 by Adrian Wyssmann ‐ 3 min read

It may happen that even so successful jenkins build remains "In Progress" in Bitbucket.

At my employer we use Jenkins as build server and Bitbucket as git repository server. They can be integrated so that a push of the code triggers the ci pipeline, which ultimately returns the status of the build which is “In Progress”, “Failed” or “Successful”. Usually that works fine, but we - as well as others - have discovered that this does not always work and builds which were successful still are reported as “In Progress”.

Jenkins build finished successfully
Merge impossible due to 'build in progress'

This will hinder developers to merge their PR if the merge check “Minimum successful builds” is active.

Until this issue is properly fixed you may need to work-around it. Following Updating build status for commits (atlassian.com) this can be done via the REST API but first we need to get the key of the build in question, using the commit id from the pr which triggered the build (see screenshot above)

$ curl -u xxxx:xxxxx -k -H "Content-Type: application/json" -X GET https://git.intra/rest/build-status/1.0/commits/b3040bd64c950c5e6d885612adb4f00a7d15e3bc
{
    "size": 1,
    "limit": 25,
    "isLastPage": true,
    "values": [
        {
            "state": "INPROGRESS",
            "key": "e8be793d8147a7c679298b2c38f25322",
            "name": "Playground » test-ci-pipeline » papanito/build-status-demo #1",
            "url": "https://jenkins.intra/job/Playground/job/test-ci-pipeline/job/papanito%252Fbuild-status-demo/1/",
            "description": "The build is in progress...",
            "dateAdded": 1610377634403
        }
    ],
    "start": 0
}

Using the information above, we need to send a json-payload with the correct state for example:

{
    "state": "SUCCESSFUL",
    "key": "e8be793d8147a7c679298b2c38f25322",
    "name": "Playground » test-ci-pipeline » papanito/build-status-demo #1",
    "url": "https://jenkins.intra/job/Playground/job/test-ci-pipeline/job/papanito%252Fbuild-status-demo/1/",
    "description": "Changed by Adrian Wyssmann manually"
}

Then run this

curl -u xxxxx:xxxxxx -k -H "Content-Type: application/json" -X POST https://git.intra/rest/build-status/1.0/commits/b3040bd64c950c5e6d885612adb4f00a7d15e3bc -d @payload.json
Merge is now possible as build is reported as 'Successful'

Sure this manual process so it makes sense to automate the whole procedure. Well as at my employeer we mostly work on Windows machines, I’ve made a small powershell script.

<# 
 .Synopsis
  Updates build status to "SUCCESSFUL"

 .Description
  Build status of Jenkins build in Bitbucket may stay "In Progress" even so it succeeded, thus blocking merge of PR.
  This script takes a commit-id and updates all builds which are "In Progress" to "Successful"


 .Example
  .\Bitbucket.Pass.Build.ps1 -CommitID 52f43d788fb552135d2d852869d9c67d3d2b4297
#>
Param(
    [Parameter(
        Mandatory=$true,
        ValueFromPipeline=$true,
        HelpMessage="Commit id for which the build status has to be corrected"
        )]
    [ValidatePattern("[0-9a-zA-Z]{5,40}")]
    [string] $CommitID,
    [Parameter(
        Mandatory=$false,
        ValueFromPipeline=$true,
        HelpMessage='Bearer token used to access bitbucket rest api, uses $env:BITBUCKET_TOKEN per default'
        )]
    [string] $Token = $env:BITBUCKET_TOKEN
)

$baseUrl = "https://bitbucket.intra"
$urlRestApi = "$baseUrl/rest/build-status/1.0/commits"

# get credentials if not set
if (!$Token) {
    Write-Host "Please provide a bearer token via -Token or \$env:BITBUCKET_TOKEN"
    Exit
}

$headers = @{}
$headers.Add("Authorization","Bearer $Token")

$urlQuery = "$urlRestApi/$CommitID"
Write-Host "Get $urlQuery"
$Response = Invoke-WebRequest -Uri "$urlQuery" -Headers $headers -ContentType "application/json" -Method 'GET' | ConvertFrom-Json

$Response  | ConvertTo-Json

$statusToFix = "INPROGRESS"
$statusToSet = "SUCCESSFUL"

foreach ($data in $Response.values) {

    if ($data.state -eq $statusToFix) {
        $key = $data.key
        $name = $data.name
        $url = $data.url
        Write-Host "Fix the status of the following build: ${key}"
        $name = $name.Replace("??", "»")

        $json = @"
{
    "state": "$statusToSet",
    "key": "$key",
    "name": "$name",
    "url": "$url",
    "description": "Changed manually"
} 
"@
        Write-Host "Write $urlQuery"
        Write-Host $json
        Invoke-WebRequest -Uri "$urlQuery" -Headers $headers -ContentType "application/json" -Method 'POST' -Body $json
    }
}