Skip to content

Instantly share code, notes, and snippets.

@GFoley83
Created November 26, 2024 23:57
Show Gist options
  • Save GFoley83/19491dacf591806036a796c4280bc2c6 to your computer and use it in GitHub Desktop.
Save GFoley83/19491dacf591806036a796c4280bc2c6 to your computer and use it in GitHub Desktop.
Delete all branches X number of commits behind master
# Define variables
$organization = ""
$project = ""
$repositoryName = ""
$masterBranch = "master"
$devBranch = "develop"
$maxCommitsBehind = 500
$apiKey = $env:AZURE_DEVOPS_API_KEY
# Validate API Key
if (-not $apiKey) {
Write-Error "Azure DevOps API Key is not set in the environment variable 'AZURE_DEVOPS_API_KEY'."
exit 1
}
# Azure DevOps API base URL
$repositoryApiUrl = "https://dev.azure.com/$organization/$project/_apis/git/repositories?api-version=6.0"
# Set API headers
$headers = @{
"Authorization" = "Basic " + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$apiKey"))
"Content-Type" = "application/json"
}
# Fetch repositories and validate existence
Write-Host "Validating repository existence..." -ForegroundColor Yellow
$repositoriesResponse = Invoke-RestMethod -Uri $repositoryApiUrl -Headers $headers -Method Get
# Match the repository by name
$repository = $repositoriesResponse.value | Where-Object { $_.name -ieq $repositoryName }
if (-not $repository) {
Write-Error "Repository with name '$repositoryName' does not exist in the project '$project'."
exit 1
}
Write-Host "Repository '$repositoryName' found." -ForegroundColor Green
# Extract repository ID (GUID) for subsequent API calls
$repositoryId = $repository.id
Write-Host "Using Repository ID: $repositoryId" -ForegroundColor Cyan
# Azure DevOps repository-specific API base URL
$baseApiUrl = "https://dev.azure.com/$organization/$project/_apis/git/repositories/$repositoryId"
# Fetch all branches
Write-Host "Fetching all branches in repository '$repositoryName'..." -ForegroundColor Yellow
$branchesUrl = "$baseApiUrl/refs?filter=heads/&api-version=6.0"
$branchesResponse = Invoke-RestMethod -Uri $branchesUrl -Headers $headers -Method Get
$branches = $branchesResponse.value
if (-not $branches) {
Write-Error "No branches found in the repository '$repositoryName'."
exit 1
}
# Process each branch
foreach ($branch in $branches) {
$branchName = $branch.name -replace "^refs/heads/", "" # Remove refs/heads/ prefix
if ($branchName -eq $masterBranch -or $branchName -eq $devBranch) {
Write-Host "Skipping $branchName branch..." -ForegroundColor Yellow
continue
}
# Compare commits between the branch and master using diffs/commits API
$compareUrl = "$baseApiUrl/diffs/commits?baseVersionType=branch&baseVersion=$masterBranch&targetVersionType=branch&targetVersion=$branchName&api-version=6.0"
try {
$compareResponse = Invoke-RestMethod -Uri $compareUrl -Headers $headers -Method Get
} catch {
Write-Warning "Unable to compare commits for branch: $branchName. Skipping..."
continue
}
if (-not $compareResponse.behindCount) {
Write-Warning "No commit comparison data for branch: $branchName. Skipping..."
continue
}
$commitsBehind = $compareResponse.behindCount
if ($commitsBehind -gt $maxCommitsBehind) {
# Prepare the delete request
$deleteBranchUrl = "$baseApiUrl/refs/?api-version=6.0"
# Get the current commit ID of the branch (oldObjectId)
$oldObjectId = $branch.objectId
# Prepare the request body as a JSON array
$body = ConvertTo-Json @(
@{
name = "refs/heads/$branchName";
oldObjectId = $oldObjectId;
newObjectId = "0000000000000000000000000000000000000000";
}
) -Depth 10
# Debug the request body
# Write-Host "Request Body JSON: $body" -ForegroundColor Yellow
try {
# Send the POST request to delete the branch
$deleteResponse = Invoke-RestMethod -Uri $deleteBranchUrl -Headers $headers -Method Post -Body $body -ContentType "application/json" -UseBasicParsing
Write-Host "Branch $branchName is $commitsBehind commits behind master. Deleted successfully." -ForegroundColor Red
} catch {
Write-Warning "Failed to delete branch: $branchName."
Write-Warning "Error details: $($_.Exception.Message)"
if ($_.Exception.Response -and $_.Exception.Response.Content) {
$reader = [System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream())
$responseContent = $reader.ReadToEnd()
Write-Warning "Response content: $responseContent"
}
}
} else {
Write-Host "Branch $branchName is only $commitsBehind commits behind master. Skipping..." -ForegroundColor Green
}
}
Write-Host "Branch cleanup complete." -ForegroundColor Green
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment