-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Expand file tree
/
Copy pathupdate.ps1
More file actions
351 lines (270 loc) · 10.8 KB
/
update.ps1
File metadata and controls
351 lines (270 loc) · 10.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
<#
.Synopsis
Update Cmder vendored dependencies
.DESCRIPTION
This script updates dependencies to the latest version in vendor/sources.json file.
You will need to make this script executable by setting your Powershell Execution Policy to Remote signed
Then unblock the script for execution with UnblockFile .\build.ps1
.EXAMPLE
.\build.ps1
Updates the dependency sources in the default location, the vendor/sources.json file.
.EXAMPLE
.\build -verbose
Updates the dependency sources and see what's going on.
.EXAMPLE
.\build.ps1 -SourcesPath '~/custom/vendors.json'
Specify the path to update dependency sources file at.
.NOTES
AUTHORS
David Refoua <David@Refoua.me>
Part of the Cmder project.
.LINK
http://cmder.app/ - Project Home
#>
[CmdletBinding(SupportsShouldProcess = $true)]
Param(
# CmdletBinding will give us;
# -verbose switch to turn on logging and
# -whatif switch to not actually make changes
# Path to the vendor configuration source file
[string]$sourcesPath = "$PSScriptRoot\..\vendor\sources.json",
# Include pre-release versions (RC, beta, alpha, etc.)
# By default, only stable releases are considered
[switch]$IncludePrerelease = $false
)
# Get the root directory of the cmder project.
$cmder_root = Resolve-Path "$PSScriptRoot\.."
# Dot source util functions into this scope
. "$PSScriptRoot\utils.ps1"
$ErrorActionPreference = "Stop"
# Attempts to match the current link with the new link, returning the count of matching characters.
function Match-Filenames {
param (
$url,
$downloadUrl,
$fromEnd
)
$filename = [System.IO.Path]::GetFileName($url)
$filenameDownload = [System.IO.Path]::GetFileName($downloadUrl)
$position = 0
if ([String]::IsNullOrEmpty($filename) -or [String]::IsNullOrEmpty($filenameDownload)) {
throw "Either one or both filenames are empty!"
}
if ($fromEnd) {
$arr = $filename -split ""
[array]::Reverse($arr)
$filename = $arr -join ''
$arr = $filenameDownload -split ""
[array]::Reverse($arr)
$filenameDownload = $arr -join ''
}
while ($filename.Substring($position, 1) -eq $filenameDownload.Substring($position, 1)) {
$position++
if ( ($position -ge $filename.Length) -or ($position -ge $filenameDownload.Length) ) {
break
}
}
return $position
}
# Checks if a release is a pre-release based on GitHub API flag and version tag keywords
# Pre-release keywords include: -rc (release candidate), -beta, -alpha, -preview, -pre
function Test-IsPrerelease {
param (
[Parameter(Mandatory = $true)]
$release
)
# Check if marked as pre-release by GitHub
if ($release.prerelease -eq $true) {
return $true
}
# Check for common pre-release keywords in tag name
# This catches versions like v2.50.0-rc, v1.0.0-beta, v1.0.0-alpha, etc.
$prereleaseKeywords = @('-rc', '-beta', '-alpha', '-preview', '-pre')
foreach ($keyword in $prereleaseKeywords) {
if ($release.tag_name -ilike "*$keyword*") {
return $true
}
}
return $false
}
# Uses the GitHub api in order to fetch the current download links for the latest releases of the repo.
function Fetch-DownloadUrl {
param (
[Parameter(Mandatory = $true)]
$urlStr,
[Parameter(Mandatory = $false)]
[bool]$includePrerelease = $false
)
$url = [uri] $urlStr
if ((-not $url) -or ($null -eq $url) -or ($url -eq '')) {
throw "Failed to parse url: $urlStr"
}
if (-not ("http", "https" -contains $url.Scheme)) {
throw "unknown source scheme: $($url.Scheme)"
}
if (-not ($url.Host -ilike "*github.com")) {
throw "unknown source domain: $($url.Host)"
}
$p = $url.Segments.Split([Environment]::NewLine)
$headers = @{}
if ($env:GITHUB_TOKEN) {
$headers["Authorization"] = "token $($env:GITHUB_TOKEN)"
}
# Api server for GitHub
$urlHost = "api.github.com"
# Path for releases end-point
$urlPath = [IO.Path]::Combine('repos', $p[1], $p[2], 'releases').Trim('/')
$apiUrl = [uri] (New-Object System.UriBuilder -ArgumentList $url.Scheme, $urlHost, -1, $urlPath).Uri
$info = Invoke-RestMethod -Uri $apiUrl -Headers $headers
$downloadLinks = (New-Object System.Collections.Generic.List[System.Object])
$charCount = 0
if (-not ($info -is [array])) {
throw "The response received from API server is invalid"
}
:loop foreach ($i in $info) {
# Skip pre-release versions unless explicitly included
# Pre-releases include RC (Release Candidate), beta, alpha, and other test versions
if (-not $includePrerelease -and (Test-IsPrerelease $i)) {
Write-Verbose "Skipping pre-release version: $($i.tag_name)"
continue
}
if (-not ($i.assets -is [array])) {
continue
}
foreach ($a in $i.assets) {
if ([String]::IsNullOrEmpty($a.browser_download_url)) {
continue
}
# Skip some download links as we're not interested in them
if ( $a.browser_download_url -ilike "*_symbols*" ) {
continue
}
$score = Match-Filenames $url $a.browser_download_url
# Skip links that don't match or are less similar
if ( ($score -eq 0) -or ($score -lt $charCount) ) {
continue
}
# If we reach the same download link as we have
if ( $score -eq [System.IO.Path]::GetFileName($url).Length ) {
}
$charCount = $score
$downloadLinks.Add($a.browser_download_url)
}
# If at least one download link was found, don't continue with older releases
if ( $downloadLinks.Length -gt 0 ) {
break :loop
}
}
# Special case for archive downloads of repository
if (($null -eq $downloadLinks) -or (-not $downloadLinks)) {
if ((($p | ForEach-Object { $_.Trim('/') }) -contains "archive")) {
# Find the first release that matches our pre-release filtering criteria
$selectedRelease = $null
foreach ($release in $info) {
# Apply the same filtering logic
if (-not $includePrerelease -and (Test-IsPrerelease $release)) {
continue
}
# Use the first release that passes the filter
$selectedRelease = $release
break
}
if ($selectedRelease -and $selectedRelease.tag_name) {
for ($i = 0; $i -lt $p.Length; $i++) {
if ($p[$i].Trim('/') -eq "archive") {
$p[$i + 1] = $selectedRelease.tag_name + ".zip"
$downloadLinks = $url.Scheme + "://" + $url.Host + ($p -join '')
return $downloadLinks
}
}
}
}
return ''
}
$temp = $downloadLinks | Where-Object { (Match-Filenames $url $_) -eq $charCount }
$downloadLinks = (New-Object System.Collections.Generic.List[System.Object])
$charCount = 0
foreach ($l in $temp) {
$score = Match-Filenames $url $l true
if ( ($score -eq 0) -or ($score -lt $charCount) ) {
continue
}
$charCount = $score
}
$downloadLinks = $temp | Where-Object { (Match-Filenames $url $_ true) -eq $charCount }
if (($null -eq $downloadLinks) -or (-not $downloadLinks)) {
throw "No suitable download links matched for the url!"
}
if (-not($downloadLinks -is [String])) {
throw "Found multiple matches for the same url:`n" + $downloadLinks
}
return $downloadLinks
}
$count = 0
$hasBreakingChanges = $false
$updateDetails = @()
# Read the current sources content
$sources = Get-Content $sourcesPath | Out-String | ConvertFrom-Json
foreach ($s in $sources) {
Write-Verbose "Updating sources link for $($s.name)..."
Write-Verbose "Old Link: $($s.url)"
$downloadUrl = Fetch-DownloadUrl $s.url -includePrerelease $IncludePrerelease
if (($null -eq $downloadUrl) -or ($downloadUrl -eq '')) {
Write-Verbose "No new links were found"
continue
}
Write-Verbose "Link: $downloadUrl"
$url = [uri] $downloadUrl
$version = ''
if (($url.Segments[-3] -eq "download/") -and ($url.Segments[-2].StartsWith("v"))) {
$version = $url.Segments[-2].TrimStart('v').TrimEnd('/')
}
if (($url.Segments[-2] -eq "archive/")) {
$version = [System.IO.Path]::GetFileNameWithoutExtension($url.Segments[-1].TrimStart('v').TrimEnd('/'))
}
if ($version -eq '') {
throw "Unable to extract version from url string"
}
Write-Verbose "Version: $version"
if ( $s.version -ne $version ) {
# if ( ([System.Version] $s.version) -gt ([System.Version] $version) ) {
# throw "The current version $($s.version) is already newer than the found version $version!"
# }
$count++
# Analyze version change type using shared function
$result = Get-VersionChangeType -OldVersion $s.version -NewVersion $version
$changeType = $result.ChangeType
# Determine if this is a breaking change
if ($changeType -eq "downgrade" -or $changeType -eq "major") {
$hasBreakingChanges = $true
} elseif ($changeType -eq "unknown") {
# If version parsing failed, treat as potentially breaking
$hasBreakingChanges = $true
Write-Verbose "Could not parse version as semantic version for dependency '$($s.name)' (old: '$($s.version)', new: '$version'), treating as potentially breaking"
}
$updateDetails += @{
name = $s.name
oldVersion = $s.version
newVersion = $version
changeType = $changeType
}
}
$s.url = $downloadUrl
$s.version = $version
}
$sources | ConvertTo-Json | Set-Content $sourcesPath
if ($count -eq 0) {
Write-Host -ForegroundColor yellow "No new releases were found."
return
}
# Export update details for GitHub Actions
if ($Env:GITHUB_ACTIONS -eq 'true') {
$updateDetailsJson = $updateDetails | ConvertTo-Json -Compress
Write-Output "UPDATE_DETAILS=$updateDetailsJson" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
Write-Output "HAS_BREAKING_CHANGES=$hasBreakingChanges" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
Write-Output "::notice title=Task Complete::Successfully updated $count dependencies."
}
if ($Env:APPVEYOR -eq 'True') {
Add-AppveyorMessage -Message "Successfully updated $count dependencies." -Category Information
}
Write-Host -ForegroundColor green "Successfully updated $count dependencies."