mirror of
https://dev.azure.com/effectory/Survey%20Software/_git/Cloud%20Engineering
synced 2026-02-27 10:45:02 +01:00
241 lines
12 KiB
PowerShell
241 lines
12 KiB
PowerShell
|
|
<#
|
|
.SYNOPSIS
|
|
Analyzes Azure DevOps repositories to identify which have 'test' and 'accept' branches and their last activity.
|
|
|
|
.DESCRIPTION
|
|
This script retrieves all repositories from an Azure DevOps project and analyzes each one to determine:
|
|
- Basic repository information (ID, name, default branch, status, URL)
|
|
- Last commit activity on the default branch
|
|
- Whether a 'test' branch exists and its last commit activity
|
|
- Whether an 'accept' branch exists and its last commit activity
|
|
|
|
This is commonly used in development workflows where 'test' and 'accept' branches represent
|
|
specific deployment environments or approval stages in the development pipeline.
|
|
|
|
.PARAMETER Token
|
|
The Azure DevOps Personal Access Token (PAT) used for authentication. This token must have
|
|
'Code (Read)' permissions to access repository and commit information.
|
|
|
|
.PARAMETER Organization
|
|
The Azure DevOps organization name. Defaults to "effectory" if not specified.
|
|
|
|
.PARAMETER Project
|
|
The Azure DevOps project name. Defaults to "Survey Software" if not specified.
|
|
|
|
.EXAMPLE
|
|
.\RepositoriesWithTestAccept.ps1 -Token "your-personal-access-token"
|
|
|
|
Analyzes repositories using the default organization and project settings.
|
|
|
|
.EXAMPLE
|
|
.\RepositoriesWithTestAccept.ps1 -Token "your-pat-token" -Organization "myorg" -Project "MyProject"
|
|
|
|
Analyzes repositories for a specific organization and project.
|
|
|
|
.OUTPUTS
|
|
Creates a timestamped CSV file in the current directory with the format: "yyyy-MM-dd HHmm repositories with test and accept.csv"
|
|
The CSV contains the following columns:
|
|
- Id: Repository unique identifier
|
|
- Name: Repository name
|
|
- DefaultBranch: Repository default branch (e.g., main, master)
|
|
- IsDisabled: Boolean indicating if the repository is disabled
|
|
- WebUrl: Repository web URL in Azure DevOps
|
|
- LastDefaultChange: Date of last commit on the default branch
|
|
- HasTest: Boolean indicating if a 'test' branch exists (True/False)
|
|
- LastTestChange: Date of last commit on the 'test' branch (empty if branch doesn't exist)
|
|
- HasAccept: Boolean indicating if an 'accept' branch exists (True/False)
|
|
- LastAcceptChange: Date of last commit on the 'accept' branch (empty if branch doesn't exist)
|
|
|
|
.NOTES
|
|
Author: Cloud Engineering Team
|
|
Created: 2025
|
|
Requires: PowerShell 5.1 or later, Azure CLI installed and authenticated
|
|
Dependencies: Azure CLI (az) for repository listing, Azure DevOps REST API for commit information
|
|
|
|
Prerequisites:
|
|
- Install Azure CLI: https://docs.microsoft.com/en-us/cli/azure/install-azure-cli
|
|
- Authenticate: az login
|
|
- Azure DevOps Personal Access Token with Code (Read) permissions
|
|
|
|
The script uses both Azure CLI commands and REST API calls:
|
|
- Azure CLI for listing repositories
|
|
- REST API for checking branch existence and commit history
|
|
|
|
Branch Analysis:
|
|
- 'test' branch: Often used for testing environment deployments
|
|
- 'accept' branch: Often used for acceptance testing or staging environments
|
|
- Default branch: Usually 'main' or 'master', represents the primary development branch
|
|
|
|
Error Handling:
|
|
- If a branch doesn't exist, the API call will fail and the branch is marked as non-existent
|
|
- Disabled repositories are processed but branch analysis is skipped
|
|
- Network or authentication errors are handled gracefully
|
|
|
|
.LINK
|
|
https://docs.microsoft.com/en-us/rest/api/azure/devops/git/commits/get-commits
|
|
#>
|
|
|
|
param(
|
|
[Parameter(Mandatory = $true, HelpMessage = "Azure DevOps Personal Access Token with Code (Read) permissions")]
|
|
[string]$Token,
|
|
|
|
[Parameter(Mandatory = $false, HelpMessage = "Azure DevOps organization name")]
|
|
[string]$Organization = "effectory",
|
|
|
|
[Parameter(Mandatory = $false, HelpMessage = "Azure DevOps project name")]
|
|
[string]$Project = "Survey Software"
|
|
)
|
|
|
|
# Define a class to structure repository information with branch analysis
|
|
class Repository {
|
|
[string] $Id = "" # Repository unique identifier
|
|
[string] $Name = "" # Repository display name
|
|
[string] $DefaultBranch = "" # Repository default branch (e.g., main, master)
|
|
[string] $IsDisabled = "" # Whether the repository is disabled (True/False)
|
|
[string] $WebUrl = "" # Repository web URL in Azure DevOps
|
|
[string] $LastDefaultChange = "" # Date of last commit on default branch
|
|
[string] $HasTest = "" # Whether 'test' branch exists (True/False)
|
|
[string] $LastTestChange = "" # Date of last commit on 'test' branch
|
|
[string] $HasAccept = "" # Whether 'accept' branch exists (True/False)
|
|
[string] $LastAcceptChange = "" # Date of last commit on 'accept' branch
|
|
}
|
|
|
|
# Initialize variables for API calls
|
|
[string] $url = ""
|
|
[string] $repositoryId = ""
|
|
[string] $branchName = ""
|
|
|
|
# Generate timestamped filename for the output CSV
|
|
[string] $date = Get-Date -Format "yyyy-MM-dd HHmm"
|
|
$fileName = ".\$date repositories with test and accept.csv"
|
|
|
|
# Prepare authentication for Azure DevOps REST API calls
|
|
# Personal Access Token must be base64 encoded with a colon prefix
|
|
$encodedToken = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($Token)"))
|
|
$head = @{ Authorization =" Basic $encodedToken" }
|
|
|
|
# URL-encode the project name for API calls
|
|
$projectEncoded = $Project -replace " ", "%20"
|
|
|
|
# Display script execution banner
|
|
Write-Host "========================================================================================================================================================================"
|
|
Write-Host "Analyzing repositories for 'test' and 'accept' branches"
|
|
Write-Host "Organization: $Organization, Project: $Project"
|
|
Write-Host "Output file: $fileName"
|
|
Write-Host "========================================================================================================================================================================"
|
|
|
|
# Retrieve all repositories from the Azure DevOps project
|
|
Write-Host "Fetching repositories from project '$Project'..." -ForegroundColor Yellow
|
|
$repos = az repos list --organization "https://dev.azure.com/$Organization/" --project "$Project" | ConvertFrom-Json | Select-Object
|
|
Write-Host "Found $($repos.Count) repositories" -ForegroundColor Green
|
|
|
|
# Initialize array to store repository analysis results
|
|
[Repository[]]$Result = @()
|
|
|
|
# Process each repository to analyze branch structure and activity
|
|
foreach ($repo in $repos)
|
|
{
|
|
Write-Host "Analyzing repository: $($repo.name)" -ForegroundColor Cyan
|
|
|
|
# Create new repository object and populate basic information
|
|
[Repository] $repository = [Repository]::new()
|
|
$repository.Id = $repo.id
|
|
$repository.Name = $repo.name
|
|
$repository.DefaultBranch = $repo.defaultBranch
|
|
$repository.IsDisabled = $repo.isDisabled
|
|
$repository.WebUrl = $repo.webUrl
|
|
|
|
# Only analyze branches for active repositories
|
|
if ($true -ne $repo.isDisabled)
|
|
{
|
|
$repositoryId = $repo.id
|
|
|
|
# Analyze default branch activity
|
|
$branchName = $repo.defaultBranch
|
|
$branchName = $branchName.Replace("refs/heads/", "")
|
|
Write-Host " Checking default branch: $branchName" -ForegroundColor Gray
|
|
|
|
try {
|
|
$url="https://dev.azure.com/$Organization/$projectEncoded/_apis/git/repositories/$repositoryId/commits?searchCriteria.itemVersion.version=$branchName&searchCriteria.`$top=1&api-version=6.0"
|
|
$response = Invoke-RestMethod -Uri $url -Method GET -Headers $head
|
|
$repository.LastDefaultChange = $response.value[0].committer.date
|
|
Write-Host " Last commit: $(Get-Date $response.value[0].committer.date -Format 'yyyy-MM-dd HH:mm')" -ForegroundColor Gray
|
|
}
|
|
catch {
|
|
Write-Host " No commits found or branch inaccessible" -ForegroundColor Yellow
|
|
$repository.LastDefaultChange = ""
|
|
}
|
|
|
|
# Check for 'test' branch existence and activity
|
|
Write-Host " Checking for 'test' branch..." -ForegroundColor Gray
|
|
try {
|
|
$branchName = "test"
|
|
$url="https://dev.azure.com/$Organization/$projectEncoded/_apis/git/repositories/$repositoryId/commits?searchCriteria.itemVersion.version=$branchName&searchCriteria.`$top=1&api-version=6.0"
|
|
$response = Invoke-RestMethod -Uri $url -Method GET -Headers $head
|
|
$repository.HasTest = "True"
|
|
$repository.LastTestChange = $response.value[0].committer.date
|
|
Write-Host " 'test' branch found - Last commit: $(Get-Date $response.value[0].committer.date -Format 'yyyy-MM-dd HH:mm')" -ForegroundColor Green
|
|
}
|
|
catch {
|
|
$repository.HasTest = "False"
|
|
$repository.LastTestChange = ""
|
|
Write-Host " 'test' branch not found" -ForegroundColor Yellow
|
|
}
|
|
|
|
# Check for 'accept' branch existence and activity
|
|
Write-Host " Checking for 'accept' branch..." -ForegroundColor Gray
|
|
try {
|
|
$branchName = "accept"
|
|
$url="https://dev.azure.com/$Organization/$projectEncoded/_apis/git/repositories/$repositoryId/commits?searchCriteria.itemVersion.version=$branchName&searchCriteria.`$top=1&api-version=6.0"
|
|
$response = Invoke-RestMethod -Uri $url -Method GET -Headers $head
|
|
$repository.HasAccept = "True"
|
|
$repository.LastAcceptChange = $response.value[0].committer.date
|
|
Write-Host " 'accept' branch found - Last commit: $(Get-Date $response.value[0].committer.date -Format 'yyyy-MM-dd HH:mm')" -ForegroundColor Green
|
|
}
|
|
catch {
|
|
$repository.HasAccept = "False"
|
|
$repository.LastAcceptChange = ""
|
|
Write-Host " 'accept' branch not found" -ForegroundColor Yellow
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Write-Host " Repository is disabled - skipping branch analysis" -ForegroundColor Yellow
|
|
# Set default values for disabled repositories
|
|
$repository.LastDefaultChange = ""
|
|
$repository.HasTest = "N/A"
|
|
$repository.LastTestChange = ""
|
|
$repository.HasAccept = "N/A"
|
|
$repository.LastAcceptChange = ""
|
|
}
|
|
|
|
# Add repository to results array
|
|
$Result += $repository
|
|
}
|
|
|
|
# Export results to CSV file
|
|
$Result | Export-Csv -Path $fileName -NoTypeInformation
|
|
|
|
# Calculate and display summary statistics
|
|
$totalRepos = $Result.Count
|
|
$activeRepos = ($Result | Where-Object { $_.IsDisabled -ne "True" }).Count
|
|
$disabledRepos = ($Result | Where-Object { $_.IsDisabled -eq "True" }).Count
|
|
$reposWithTest = ($Result | Where-Object { $_.HasTest -eq "True" }).Count
|
|
$reposWithAccept = ($Result | Where-Object { $_.HasAccept -eq "True" }).Count
|
|
$reposWithBoth = ($Result | Where-Object { $_.HasTest -eq "True" -and $_.HasAccept -eq "True" }).Count
|
|
|
|
# Display completion summary
|
|
Write-Host "========================================================================================================================================================================"
|
|
Write-Host "Branch analysis completed successfully!" -ForegroundColor Green
|
|
Write-Host ""
|
|
Write-Host "SUMMARY STATISTICS:" -ForegroundColor Cyan
|
|
Write-Host "Total repositories: $totalRepos" -ForegroundColor Yellow
|
|
Write-Host "Active repositories: $activeRepos" -ForegroundColor Yellow
|
|
Write-Host "Disabled repositories: $disabledRepos" -ForegroundColor Yellow
|
|
Write-Host "Repositories with 'test' branch: $reposWithTest" -ForegroundColor Yellow
|
|
Write-Host "Repositories with 'accept' branch: $reposWithAccept" -ForegroundColor Yellow
|
|
Write-Host "Repositories with both 'test' and 'accept' branches: $reposWithBoth" -ForegroundColor Yellow
|
|
Write-Host ""
|
|
Write-Host "Output file: $fileName" -ForegroundColor Yellow
|
|
Write-Host "========================================================================================================================================================================" |