|
#Requires -PSEdition Core |
|
|
|
<# |
|
.SYNOPSIS |
|
Retrieves distinct commits and associated work items for a build pipeline... with support for monorepos! |
|
|
|
See the blog post at https://tiberriver256.github.io/DevOps/azure-devops-pipelines-related-work-items-monorepo for more information. |
|
|
|
.DESCRIPTION |
|
This script retrieves the distinct commits and associated work items for a build pipeline. It requires the following parameters: |
|
- BuildId: The ID of the build. If not provided, it uses the value of the environment variable BUILD_BUILDID. |
|
- CollectionUri: The URI of the collection. If not provided, it uses the value of the environment variable SYSTEM_COLLECTIONURI. |
|
- ProjectId: The ID of the project. If not provided, it uses the value of the environment variable SYSTEM_TEAMPROJECTID. |
|
- AuthorizationHeader: The authorization header. If not provided, it uses the value of the environment variable SYSTEM_ACCESSTOKEN. |
|
|
|
.PARAMETER BuildId |
|
The ID of the build. |
|
|
|
.PARAMETER CollectionUri |
|
The URI of the collection. |
|
|
|
.PARAMETER ProjectId |
|
The ID of the project. |
|
|
|
.PARAMETER AuthorizationHeader |
|
The authorization header. |
|
|
|
.OUTPUTS |
|
Returns a PSCustomObject with the following properties: |
|
- DistinctCommits: An array of distinct commits. |
|
- AssociatedWorkItems: An array of associated work items. |
|
|
|
.EXAMPLE |
|
Get-BuildPipelineScopedChanges -BuildId 12345 -CollectionUri "https://dev.azure.com/myorg/" -ProjectId "be77c668-1e13-4360-aa08-264b1d5f64c6" -AuthorizationHeader "Bearer <access_token>" |
|
|
|
Retrieves the distinct commits and associated work items for the build with ID 12345 in the project "be77c668-1e13-4360-aa08-264b1d5f64c6" in the Azure DevOps organization "myorg" using the specified access token. |
|
#> |
|
|
|
[CmdletBinding()] |
|
param ( |
|
[Parameter()] |
|
[int] |
|
$BuildId = $ENV:BUILD_BUILDID, |
|
|
|
[Parameter()] |
|
[Uri] |
|
$CollectionUri = $ENV:SYSTEM_COLLECTIONURI, |
|
|
|
[Parameter()] |
|
[Guid] |
|
$ProjectId = $ENV:SYSTEM_TEAMPROJECTID, |
|
|
|
[Parameter()] |
|
$AuthorizationHeader = "Bearer $ENV:SYSTEM_ACCESSTOKEN" |
|
) |
|
|
|
function EnsureModuleInstalled ( $name ) { |
|
$module = Get-InstalledModule -Name $name |
|
if ($null -eq $module) { |
|
Install-Module -Name $name -Scope CurrentUser -AllowClobber |
|
} |
|
} |
|
|
|
EnsureModuleInstalled "powershell-yaml" |
|
|
|
$Headers = @{ |
|
Authorization = $AuthorizationHeader |
|
} |
|
|
|
$BuildUri = "$CollectionUri$ProjectId/_apis/build/builds/$BuildId" |
|
$ChangesUri = "$CollectionUri$ProjectId/_apis/build/builds/$BuildId/changes" |
|
|
|
$Build = Invoke-RestMethod -Uri $BuildUri -Headers $Headers |
|
$RepositoryId = $Build.repository.id |
|
$CommitId = $Build.sourceVersion |
|
$BuildDefinitionId = $Build.definition.id |
|
$BuildDefinitionRevision = $Build.definition.revision |
|
|
|
$BuildDefinitionUri = "$CollectionUri$ProjectId/_apis/build/definitions/$($BuildDefinitionId)?revision=$BuildDefinitionRevision" |
|
$BuildDefinition = Invoke-RestMethod -Uri $BuildDefinitionUri -Headers $Headers |
|
$YamlFilePath = $BuildDefinition.process.yamlFilename |
|
$YamlFileUri = "$CollectionUri$ProjectId/_apis/git/repositories/$RepositoryId/items?path=$YamlFilePath&download=true&versionDescriptor.version=$CommitId&versionDescriptor.versionType=commit" |
|
$YamlFile = Invoke-RestMethod -Uri $YamlFileUri -Headers $Headers | ConvertFrom-Yaml |
|
$TriggerPaths = $YamlFile.trigger.paths.include | ForEach-Object { $_ -replace "\*", "" } |
|
|
|
$IsMonoRepo = $TriggerPaths.Count -ge 1 -and $TriggerPaths[0] -ne "/" |
|
|
|
|
|
$Changes = Invoke-RestMethod -Uri $ChangesUri -Headers $Headers |
|
|
|
$LatestChangeTimeStamp = $Changes.value[0].timestamp |
|
$OldestChangeTimeStamp = $Changes.value[-1].timestamp |
|
|
|
$CommitsFilteredByTriggerPaths = @() |
|
$BaseCommitsUri = "$CollectionUri$ProjectId/_apis/git/repositories/$RepositoryId/commits?searchCriteria.fromDate=$OldestChangeTimeStamp&searchCriteria.toDate=$LatestChangeTimeStamp&searchCriteria.includeWorkItems=true" |
|
|
|
if ($IsMonoRepo) { |
|
foreach ($Path in $TriggerPaths) { |
|
$CommitsUri = "$BaseCommitsUri&searchCriteria.itemPath=$Path" |
|
$Commits = Invoke-RestMethod -Uri $CommitsUri -Headers $Headers |
|
$CommitsFilteredByTriggerPaths += $Commits.value |
|
} |
|
} |
|
else { |
|
$Commits = Invoke-RestMethod -Uri $BaseCommitsUri -Headers $Headers |
|
$CommitsFilteredByTriggerPaths = $Commits.value |
|
} |
|
|
|
$DistinctCommits = @($CommitsFilteredByTriggerPaths | |
|
Group-Object -Property commitId | |
|
ForEach-Object { $_.Group[0] }) |
|
|
|
$DistinctWorkItemUrls = $DistinctCommits.workItems.url | Get-Unique |
|
|
|
$AssociatedWorkItems = @($DistinctWorkItemUrls | ForEach-Object { |
|
Invoke-RestMethod -Uri $_ -Headers $Headers |
|
}) |
|
|
|
return [PSCustomObject]@{ |
|
DistinctCommits = $DistinctCommits |
|
AssociatedWorkItems = $AssociatedWorkItems |
|
} |