Triggering Bitbucket Server Pull Request builds

The following code can be used within Jenkins job triggered every few minutes.

It will get a list of currently open pull requests. Then get build data for every last commit in pull request. If the commit is not build then trigger Jenkins job.

# -*- coding: utf-8 -*-
import requests, re, os, json, datetime, time
from requests.auth import HTTPBasicAuth
JENKINS_URL   = os.environ['JENKINS_URL']
STASH_URL     = os.environ['STASH_URL']
JOB_NAME      = 'JOB_NAME'
JENKINS_TRIG  = JENKINS_URL+"/job/"+JOB_NAME+"/buildWithParameters"
CREDENTIALS   = os.environ['CREDENTIALS'].split(':') # ex user:password
STASH_PRLIST  = STASH_URL + "/rest/api/1.0/projects/PROJECT/repos/REPO/pull-requests"
STASH_PRLIST += r"?limit=20&withAttributes=false&withProperties=false"
STASH_BUILDS  = STASH_URL + "/rest/build-status/1.0/commits/"
JOB_TOKEN     = r"POOLINGISBAD"
userAuth      = HTTPBasicAuth(CREDENTIALS[0], CREDENTIALS[1])
pull_requests = []
trigger       = []
 
print('Fetching list of open Pull Requests', 
      STASH_PRLIST, 
      datetime.datetime.utcnow().isoformat(),
      'UTC')
 
def getPullRequestsList():
    isLastPage    = False
    nextPageStart = 0
    while not isLastPage:
        spage = '' if nextPageStart is 0 else '&start='+str(nextPageStart)
        r     = requests.get(STASH_PRLIST + spage, auth=userAuth, timeout=10)
        if r.status_code is not requests.codes.ok:
            raise Exception('Failed to fetch list of open PRs', 
                            [r.status_code, r.text])
        data          = json.loads(r.text)
        isLastPage    = data['isLastPage']
        nextPageStart = data.get('nextPageStart', 0)
	pull_requests.extend(data['values'])
    return pull_requests
 
def checkAndTriggerIfRequired():
    for PR in getPullRequestsList():
        PR_commit = PR['fromRef']['latestCommit']
        PR_title  = PR['title']
        PR_id     = PR['id']
        r         = requests.get(STASH_BUILDS + PR_commit, auth=userAuth, timeout=10)
        PR_data   = json.loads(r.text)
        PR_val    = PR_data['values']
        PR_lastState = 'NULL' if len(PR_val) is 0 else PR_val[0]['state']
        PR_doTrigger = 'trigger' if PR_lastState is 'NULL' else 'skip'
 
        print('\u2022 {:<4} {:} {:<10} {:<7} {:}'.format(PR_id,
                                                         PR_commit,
                                                         PR_lastState,
                                                         PR_doTrigger,
                                                         PR_title))
        if PR_doTrigger is 'trigger': trigger.append([PR_id, PR_title])
 
    if len(trigger) is 0:
        print('Nothing to trigger.')
        return 0
 
	print()
    for trig in trigger:
        URL = JENKINS_TRIG+'?token='+JOB_TOKEN+'&ID='+str(trig[0])
        print('\u2022 Triggering:', trig[1], URL)
        r = requests.put(URL, auth=userAuth)
        if r.status_code is not requests.codes.ok:
            raise Exception('Failed to trigger Jenkins job', [r.status_code, r.text])
    return 0
 
exitcode = checkAndTriggerIfRequired()
print('Let Jenkins process, start the build and notify Stash')
print('Doing nothing for mandatory period of 10 seconds')
time.sleep(10)
exit(exitcode)