Skip to content

Delete Leased Builds

This is used for deleting leased builds in an Azure DevOps Project. It is useful for when trying to delete a pipeline that has leased builds preventing the deletion.

import requests 
import base64

# Example https://dev.azure.com/{org}/{project}
project_url = "https://dev.azure.com/{org}/{project}"
pat = "your_pat_here"
encoded_pat = base64.b64encode(f":{pat}".encode()).decode()
# Example https://dev.azure.com/{org}/{project}/_build?definitionId=17
build_definition_ids = [17] 

base_api_url = f"{project_url}/_apis/build" 
request_headers = { "Authorization": f"Basic {encoded_pat}" } 

def getBuildByDefinition(definition_id): 
    params = { "definitions": definition_id, "statusFilter": "completed", "api-version": "6.1-preview.7" } 
    response = requests.get(f"{base_api_url}/builds", headers=request_headers, params=params, verify=True) 
    response.raise_for_status() 
    return response.json()["value"] 

def getBuildLeases(build_id): 
    params = { "api-version": "6.1-preview.1" } 
    response = requests.get(f"{base_api_url}/builds/{build_id}/leases", headers=request_headers, params=params, verify=True) 
    response.raise_for_status() 
    return response.json()["value"] 

def deleteBuildLease(lease_id): 
    params = { "api-version": "6.1-preview.1" } 
    response = requests.delete(f"{base_api_url}/retention/leases?ids={lease_id}", headers=request_headers, params=params, verify=True) 
    response.raise_for_status() 
    return response.status_code == 204 

for definition_id in build_definition_ids: 
    builds = getBuildByDefinition(definition_id) 
    for build in builds: 
        build_id = build["id"] 

        if build["retainedByRelease"] == True: 
            leases = getBuildLeases(build_id) 
            for lease in leases: 
                lease_id = lease["leaseId"] 
                if lease["protectPipeline"] == True: 
                    delete_result = deleteBuildLease(lease_id) 
                    print(f"Lease {lease_id} of build {build_id} delete status => {delete_result}") 
        else: 
            print(f"Build {build_id} is not retained by release")