|
| 1 | +param( |
| 2 | + [string]$TaskName, |
| 3 | + [string]$Version, |
| 4 | + [switch]$ShowRelease |
| 5 | +) |
| 6 | + |
| 7 | +<# |
| 8 | +.SYNOPSIS |
| 9 | + List all unique versions of an Azure Pipelines task and show the commit link for each version, or search for a particular version. |
| 10 | +.DESCRIPTION |
| 11 | + This script scans the git history of a task's task.json file and outputs all unique versions found, sorted in version order. |
| 12 | + It provides clickable commit links if a remote is set, or commit hashes otherwise. |
| 13 | + You can choose to see all versions or search for a particular version. |
| 14 | + Output is shown as a table for easy reading. |
| 15 | +.PARAMETER TaskName |
| 16 | + The name of the task (e.g., CopyFilesV2) |
| 17 | +.EXAMPLE |
| 18 | + pwsh ./Find-FirstTaskVersionCommit.ps1 |
| 19 | +#> |
| 20 | +function Show-ErrorAndExit($msg) { |
| 21 | + Write-Host "[ERROR] $msg" -ForegroundColor Red |
| 22 | + exit 1 |
| 23 | +} |
| 24 | + |
| 25 | +# Only prompt for parameters if not provided |
| 26 | +if (-not $TaskName) { |
| 27 | + Write-Host "" # Add spacing |
| 28 | + Write-Host "View (A)ll versions of a task, or (S)earch for a particular version" -ForegroundColor Cyan |
| 29 | + $action = Read-Host 'Enter "A" for all, or "S" for search' |
| 30 | + if ($action -notin @('A', 'a', 'S', 's')) { |
| 31 | + Show-ErrorAndExit "Invalid action. Please enter 'A' for all versions or 'S' for search." |
| 32 | + } |
| 33 | + $TaskName = Read-Host 'Enter the task name (e.g CopyFilesV2)' |
| 34 | + if($TaskName -eq '') { |
| 35 | + Show-ErrorAndExit "Task name cannot be empty. Please provide a valid task name." |
| 36 | + } |
| 37 | + $searchMode = $action -eq 's' |
| 38 | + if ($searchMode) { |
| 39 | + Write-Host "" # Add spacing |
| 40 | + $Major = Read-Host 'Enter the Major version number' |
| 41 | + $Minor = Read-Host 'Enter the Minor version number' |
| 42 | + $Patch = Read-Host 'Enter the Patch version number' |
| 43 | + $showReleaseInput = Read-Host 'Do you want to show the release tag? (Y/N)' |
| 44 | + if ($showReleaseInput -match '^(y|yes)$') { |
| 45 | + $ShowRelease = $true |
| 46 | + } else { |
| 47 | + $ShowRelease = $false |
| 48 | + } |
| 49 | + } |
| 50 | +} else { |
| 51 | + $searchMode = $false |
| 52 | + if ($Version) { |
| 53 | + $searchMode = $true |
| 54 | + $versionParts = $Version -split '\.' |
| 55 | + if ($versionParts.Length -eq 3) { |
| 56 | + $Major = $versionParts[0] |
| 57 | + $Minor = $versionParts[1] |
| 58 | + $Patch = $versionParts[2] |
| 59 | + } else { |
| 60 | + Show-ErrorAndExit "Version must be in the format Major.Minor.Patch (e.g., 2.252.0)" |
| 61 | + } |
| 62 | + } |
| 63 | +} |
| 64 | + |
| 65 | +$TaskJsonPath = "../../Tasks/${TaskName}/task.json" |
| 66 | +if (-not (Test-Path $TaskJsonPath)) { |
| 67 | + Show-ErrorAndExit "Task not found: $TaskName. Please check the task name and try again." |
| 68 | +} |
| 69 | + |
| 70 | +# Try to get the remote URL for link generation |
| 71 | +$remoteUrl = git remote get-url origin 2>$null |
| 72 | +if ($remoteUrl) { |
| 73 | + if ($remoteUrl -like 'git@*') { |
| 74 | + $remoteUrl = $remoteUrl -replace ':', '/' -replace 'git@', 'https://' |
| 75 | + $remoteUrl = $remoteUrl -replace '.git$', '' |
| 76 | + } elseif ($remoteUrl -like 'http*') { |
| 77 | + $remoteUrl = $remoteUrl -replace '.git$', '' |
| 78 | + } |
| 79 | +} |
| 80 | + |
| 81 | +$commits = git log --format="%H" -- $TaskJsonPath |
| 82 | +if (-not $commits) { |
| 83 | + Show-ErrorAndExit "No git history found for $TaskJsonPath. Please ensure Task exists" |
| 84 | +} |
| 85 | + |
| 86 | +$versions = @{} |
| 87 | +foreach ($commit in $commits) { |
| 88 | + $content = git show "${commit}:$TaskJsonPath" 2>$null |
| 89 | + if ($content) { |
| 90 | + try { |
| 91 | + $json = $content | ConvertFrom-Json |
| 92 | + $ver = "$($json.version.Major).$($json.version.Minor).$($json.version.Patch)" |
| 93 | + if (-not $versions.ContainsKey($ver)) { |
| 94 | + $commitInfo = git show -s --format="%an" $commit |
| 95 | + $commitDateRaw = git show -s --format="%ad" --date=iso $commit |
| 96 | + $commitDate = (Get-Date $commitDateRaw).ToString('dd-MM-yyyy') |
| 97 | + $commitUrl = $remoteUrl ? "$remoteUrl/commit/$commit" : $commit |
| 98 | + $versions[$ver] = [PSCustomObject]@{ |
| 99 | + Version = $ver |
| 100 | + LinkOrCommit = $commitUrl |
| 101 | + Date = $commitDate |
| 102 | + Author = $commitInfo |
| 103 | + CommitHash = $commit |
| 104 | + } |
| 105 | + } |
| 106 | + } catch { |
| 107 | + Write-Host "[WARN] Could not parse JSON for commit $commit. Skipping." -ForegroundColor DarkYellow |
| 108 | + } |
| 109 | + } |
| 110 | +} |
| 111 | + |
| 112 | +# Function to get the release tag(s) for a given commit |
| 113 | +function Get-ReleaseTagsForCommit($commitHash) { |
| 114 | + $tags = git tag --contains $commitHash 2>$null |
| 115 | + if ($tags) { |
| 116 | + $sortedTags = $tags | Sort-Object { [int]$_ } -ErrorAction SilentlyContinue |
| 117 | + return $sortedTags[0] |
| 118 | + } else { |
| 119 | + return $null |
| 120 | + } |
| 121 | +} |
| 122 | + |
| 123 | +if ($versions.Count -eq 0) { |
| 124 | + Show-ErrorAndExit "No valid versions found for ${TaskName}." |
| 125 | +} |
| 126 | + |
| 127 | +# Build $table in commit order (latest first, no need to sort) |
| 128 | +$table = @() |
| 129 | +foreach ($commit in $commits) { |
| 130 | + $ver = $null |
| 131 | + if ($versions.ContainsKey($commit)) { |
| 132 | + # Should never happen, but skip if duplicate |
| 133 | + continue |
| 134 | + } |
| 135 | + # Find the version for this commit |
| 136 | + foreach ($v in $versions.Keys) { |
| 137 | + if ($versions[$v].LinkOrCommit -like "*${commit}") { |
| 138 | + $ver = $v |
| 139 | + break |
| 140 | + } |
| 141 | + } |
| 142 | + if ($ver) { |
| 143 | + $row = $versions[$ver].PSObject.Copy() |
| 144 | + # If LinkOrCommit is a URL, make it a clickable hyperlink with text as the full commit hash |
| 145 | + if ($row.LinkOrCommit -match '^https?://') { |
| 146 | + $commitHash = $row.LinkOrCommit -replace '^.*\/([^\/]+)$', '$1' |
| 147 | + $row.LinkOrCommit = "`e]8;;$($row.LinkOrCommit)`e\$commitHash`e]8;;`e\" |
| 148 | + } |
| 149 | + $table += $row |
| 150 | + } |
| 151 | +} |
| 152 | + |
| 153 | +# If user provided a version, check if it ever existed |
| 154 | +if ($searchMode) { |
| 155 | + # Enforce all parameters for search |
| 156 | + if (-not $Major -or -not $Minor -or -not $Patch) { |
| 157 | + Show-ErrorAndExit "All parameters (Major, Minor, Patch) are required for search. Please provide valid values." |
| 158 | + } |
| 159 | + |
| 160 | + # If Major, Minor, and Patch are provided, search for that specific version |
| 161 | + if ($Major -and $Minor -and $Patch) { |
| 162 | + Write-Host "" # Add spacing |
| 163 | + Write-Host "[INFO] Searching for version $Major.$Minor.$Patch..." -ForegroundColor Yellow |
| 164 | + Write-Host "" # Add spacing |
| 165 | + $inputVersion = "$Major.$Minor.$Patch" |
| 166 | + if ($versions.ContainsKey($inputVersion)) { |
| 167 | + $row = $versions[$inputVersion].PSObject.Copy() |
| 168 | + # If LinkOrCommit is a URL, make it a clickable hyperlink with text as the full commit hash |
| 169 | + if ($row.LinkOrCommit -match '^https?://') { |
| 170 | + $commitHash = $row.LinkOrCommit -replace '^.*\/([^\/]+)$', '$1' |
| 171 | + $row.LinkOrCommit = "`e]8;;$($row.LinkOrCommit)`e\$commitHash`e]8;;`e\" |
| 172 | + } |
| 173 | + Write-Host "[SUCCESS] Version $inputVersion existed." -ForegroundColor Green |
| 174 | + Write-Host "" # Add spacing |
| 175 | + $row | Format-Table Version, LinkOrCommit, Date, Author |
| 176 | + if ($ShowRelease) { |
| 177 | + $commitHash = $row.CommitHash |
| 178 | + $releaseTag = Get-ReleaseTagsForCommit $commitHash |
| 179 | + if ($releaseTag) { |
| 180 | + if ($remoteUrl) { |
| 181 | + $releaseUrl = "$remoteUrl/releases/tag/$releaseTag" |
| 182 | + Write-Host "This version is part of release: $releaseTag" -ForegroundColor Green |
| 183 | + Write-Host "Release link: $releaseUrl" -ForegroundColor Cyan |
| 184 | + } else { |
| 185 | + Write-Host "This version is part of release: $releaseTag" -ForegroundColor Green |
| 186 | + } |
| 187 | + } else { |
| 188 | + Write-Host "No release tag found for this version." -ForegroundColor Yellow |
| 189 | + } |
| 190 | + } |
| 191 | + } else { |
| 192 | + Write-Host "Version $inputVersion does not exist for ${TaskName}." -ForegroundColor Red |
| 193 | + Write-Host "" # Add spacing |
| 194 | + Write-Host "[INFO] Valid versions for ${TaskName}:" -ForegroundColor Cyan |
| 195 | + $table | Format-Table Version, LinkOrCommit, Date, Author |
| 196 | + } |
| 197 | + } |
| 198 | +} |
| 199 | +# If no search mode, just show all unique versions |
| 200 | +else |
| 201 | +{ |
| 202 | + Write-Host "" # Add spacing |
| 203 | + Write-Host "[INFO] All unique versions found for ${TaskName} (latest first):" -ForegroundColor Cyan |
| 204 | + $table | Format-Table Version, LinkOrCommit, Date, Author |
| 205 | +} |
0 commit comments