AL/Get-AppFromLastSuccessfulBuild.ps1
|
function Get-AppFromLastSuccessfulBuild { <# .SYNOPSIS Downloads the .app files from the last successful Azure DevOps build for a project. .DESCRIPTION Queries the Azure DevOps build API for the most recent successful build of the given project/repository, downloads the artifact ZIP, extracts it to a temporary directory, and returns FileInfo objects for each .app file (excluding test apps unless -IncludeTests is set). The ZIP is deleted after extraction; the extracted directory is registered in $script:ALTempDirectories so the caller can clean it up after copying the files. When -Inspect is set, the function returns an empty array immediately after confirming a successful build exists, without downloading anything. .PARAMETER ProjectName Short project name (resolved to a VSTS project via Get-ProjectName). .PARAMETER RepositoryName Repository name used to filter builds. When empty, the latest build across all repositories in the project is used. .PARAMETER BranchName Limit the build search to a specific branch (e.g. 'main'). .PARAMETER BuildNumber Limit the build search to a specific build number. .PARAMETER IncludeTests Include test apps (files whose path contains 'Tests') in the returned list. .PARAMETER OpenExplorer Open Windows Explorer at the extracted artifact folder after downloading. .PARAMETER Inspect Dry-run mode. Returns an empty array after confirming a successful build exists, without downloading or extracting the artifact. .OUTPUTS System.IO.FileInfo — one entry per .app file found in the artifact. .EXAMPLE Get-AppFromLastSuccessfulBuild -ProjectName 'MyApp' -RepositoryName 'BC' .EXAMPLE Get-AppFromLastSuccessfulBuild -ProjectName 'MyApp' -RepositoryName 'BC' -Inspect #> Param( [Parameter(Mandatory=$false)] [string]$ProjectName, [Parameter(Mandatory=$false)] [string]$RepositoryName = '', [Parameter(Mandatory=$false)] [switch]$OpenExplorer, [Parameter(Mandatory=$false)] [switch]$IncludeTests, [Parameter(Mandatory=$false)] [string]$BranchName = '', [Parameter(Mandatory=$false)] [string]$BuildNumber = '', [Parameter(Mandatory=$false)] [switch]$Inspect ) $VSTSProjectName = Get-ProjectName $ProjectName if ($RepositoryName -ne '') { $APIUrl = ('{0}{1}/_apis/build/builds?queryOrder=finishTimeDescending&resultFilter=succeeded&$top=1&repositoryId={2}&repositoryType=TfsGit' -f (Get-TFSCollectionURL), $VSTSProjectName, (Get-RepositoryId -ProjectName $VSTSProjectName -RepositoryName $RepositoryName)) } else { $APIUrl = ('{0}{1}/_apis/build/builds?queryOrder=finishTimeDescending&resultFilter=succeeded&$top=1' -f (Get-TFSCollectionURL), $VSTSProjectName) } if ($BranchName -ne '') { $APIUrl += '&branchName=refs/heads/{0}' -f $BranchName } if ($BuildNo -ne '') { $APIUrl += '&buildNumber={0}' -f $BuildNumber } $Build = Invoke-TFSAPI $APIUrl -SuppressError if($null -eq $Build){ return $null } else { if($Build.count -eq 0){ return $null } } Write-Host " (repo: $RepositoryName, build: $($Build.value.buildNumber))." -ForegroundColor Cyan if ($Inspect.IsPresent) { return ,@() } $Artifacts = Invoke-TFSAPI ('{0}{1}/_apis/build/builds/{2}/artifacts' -f (Get-TFSCollectionURL), $VSTSProjectName, $Build.value.id) $ArtifactPath = Join-Path (New-TempDirectory) ('{0}.zip' -f (Get-URLParameterValue -Url $Artifacts.value.resource.downloadUrl -ParameterName 'artifactName')) Invoke-TFSAPI ($Artifacts.value.resource.downloadUrl) -OutFile -OutFilePath $ArtifactPath $ExpandPath = (New-TempDirectory) Expand-Archive -Path $ArtifactPath -DestinationPath $ExpandPath $script:ALTempDirectories.Add($ExpandPath) $script:ALLastExtractPath = $ExpandPath if ($IncludeTests.IsPresent) { Get-ChildItem -Path $ExpandPath -Filter '*.app' -Recurse } else { Get-ChildItem -Path $ExpandPath -Filter '*.app' -Recurse | ? FullName -NotLike '*Tests*' } if ($OpenExplorer.IsPresent) { explorer (Split-Path (Get-ChildItem -Path $ExpandPath -Filter '*app' -Recurse).Item(0).FullName -Parent) } Remove-Item $ArtifactPath -Recurse } function Get-URLParameterValue { Param( [Parameter(Mandatory=$true)] [string]$Url, [Parameter(Mandatory=$true)] [string]$ParameterName ) $ParameterString = $Url.Substring($Url.IndexOf('?') + 1) $Parameters = $ParameterString.Split('&') $Parameter = $Parameters | where {$_ -like ('{0}*' -f $ParameterName)} $Parameter.Substring($Parameter.IndexOf('=') + 1) } Export-ModuleMember -Function Get-AppFromLastSuccessfulBuild |