-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathaction.yml
332 lines (295 loc) · 13.9 KB
/
action.yml
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
name: Install Swift
description: Install Swift Release
inputs:
# for swift.org toolchains:
branch:
description: 'Branch for swift.org builds. Only specifiy when using official Swift toolchains from swift.org'
required: false
tag:
description: 'Tag for swift.org builds. Only specifiy when using official Swift toolchains from swift.org'
required: false
build_arch:
description: 'Build architecture (amd64 or arm64). Only specifiy when using official Swift toolchains from swift.org'
default: 'amd64'
required: true
# for custom toolchains:
github-repo:
description: 'Github repo in "owner/repo" format. Only specify when using custom toolchains from Github releases.'
required: false
release-tag-name:
description: 'Release tag name. Only specify when using custom toolchains from Github releases.'
required: false
release-asset-name:
description: 'Asset name for the Swift installer executable in the release. Only specify when using custom toolchains from Github releases.'
required: false
github-token:
description: 'Optional Github token for fetching a release. Only specify when using custom toolchains from non-public Github releases.'
required: false
# common
installer-args:
description: 'Additional arguments to pass to the installer, space-delimited (double quotes are not supported)'
required: false
default: ''
runs:
using: 'composite'
steps:
- name: Validate inputs
id: validation
shell: bash
run: |
if [[ -n "${{ inputs.github-repo }}" && -n "${{ inputs.release-tag-name }}" && -n "${{ inputs.release-asset-name }}" ]]; then
if [[ "${{ runner.os }}" == "Linux" && "${{ inputs.release-asset-name }}" != *.tar.gz ]]; then
echo >&2 "::error::inputs Invalid action inputs: release-asset-name has to be a '*.tar.gz' file on Linux platforms."
exit 1
elif [[ "${{ runner.os }}" == "macOS" && "${{ inputs.release-asset-name }}" != *.pkg ]]; then
echo >&2 "::error::inputs Invalid action inputs: release-asset-name has to be a '*.pkg' file on MacOS platforms."
exit 1
elif [[ "${{ runner.os }}" == "Windows" && "${{ inputs.release-asset-name }}" != *.exe ]]; then
echo >&2 "::error::inputs Invalid action inputs: release-asset-name has to be a '*.exe' file on Windows platforms."
exit 1
fi
echo "use_custom_url=1" >> $GITHUB_OUTPUT
elif [[ -n "${{ inputs.branch }}" && -n "${{ inputs.tag }}" ]]; then
echo "use_custom_url=0" >> $GITHUB_OUTPUT
else
echo >&2 "::error::inputs Invalid action inputs"
echo >&2 "::error:: for a custom Swift toolchain, specify github-repo, release-tag-name and release-asset-name"
echo >&2 "::error:: for the official swift.org toolchain, specify only branch and tag"
exit 1
fi
- name: Fetch installer from GitHub release
if: steps.validation.outputs.use_custom_url == 1
shell: bash
env:
GH_TOKEN: ${{ inputs.github-token }}
run: |
gh release download "${{ inputs.release-tag-name }}" \
--repo "${{ inputs.github-repo }}" \
--pattern "${{ inputs.release-asset-name }}"
- name: Install Swift ${{ inputs.tag }}
if: runner.os == 'Windows'
run: |
function Update-EnvironmentVariables {
foreach ($level in "Machine", "User") {
[Environment]::GetEnvironmentVariables($level).GetEnumerator() | % {
# For Path variables, append the new values, if they're not already in there
if ($_.Name -Match 'Path$') {
$_.Value = ($((Get-Content "Env:$($_.Name)") + ";$($_.Value)") -Split ';' | Select -Unique) -Join ';'
}
$_
} | Set-Content -Path { "Env:$($_.Name)" }
}
}
function Invoke-Download {
Param
(
[Parameter(Mandatory)]
[String] $URL,
[Alias("Destination")]
[Int] $Retries = 20,
[Int] $RetryInterval = 30
)
$InvalidCharacters = [IO.Path]::GetInvalidFileNameChars() -Join ''
$RE = "[{0}]" -f [RegEx]::Escape($InvalidCharacters)
$FileName = [IO.Path]::GetFileName($URL) -Replace $RE
if ([String]::IsNullOrEmpty($FileName)) {
$FileName = [System.IO.Path]::GetRandomFileName()
}
$Path = Join-Path -Path "${env:Temp}" -ChildPath $FileName
Write-Host "Downloading package from $URL to $Path..."
$StartTime = Get-Date
do {
try {
$AttemptStartTime = Get-Date
(New-Object System.Net.WebClient).DownloadFile($URL, $Path)
$AttemptDuration = [math]::Round(($(Get-Date) - $AttemptStartTime).TotalSeconds, 2)
Write-Host "Package downloaded in $AttemptDuration seconds"
break
} catch {
$AttemptDuration = [math]::Round(($(Get-Date) - $AttemptStartTime).TotalSeconds, 2)
Write-Warning "Package download failed after $AttemptDuration seconds"
Write-Warning $_.Exception.Message
}
if ($Retries -eq 1) {
$Duration = [math]::Round(($(Get-Date) - $StartTime).TotalSeconds, 2)
throw "Package download failed after $Duration seconds"
}
Write-Warning "Waiting $RetryInterval seconds before retrying (retries remaining: $($Retries - 1))..."
Start-Sleep -Seconds $RetryInterval
} while (--$Retries -gt 0)
return $Path
}
function Verify-Checksum {
Param
(
[Parameter(Mandatory)]
[String] $Actual,
[Parameter(Mandatory)]
[String] $Expected
)
Write-Verbose "Performing Checksum Verification"
if ($Actual -eq $Expected) {
Write-Verbose "Checksum verification passed"
} else {
throw "Checksum verification failure (Actual: $Actual vs Expected: $Expected)"
}
}
function Invoke-Installer {
Param
(
[Parameter(Mandatory, ParameterSetName = "URL")]
[String] $URL,
[Parameter(Mandatory, ParameterSetName = "LocalPath")]
[String] $LocalPath,
[ValidateSet("MSI", "EXE")]
[String] $Type,
[String[]] $InstallArgs = $null, # Use default for installer format
[String[]] $ExtraInstallArgs = @(),
[String] $ExpectedSHA256
)
if ($PSCmdlet.ParameterSetName -eq "LocalPath") {
if (-not (Test-Path -Path $LocalPath)) {
throw "LocalPath parameter is specified, but the file does not exist"
}
$FilePath = $LocalPath
} else {
$FileName = [System.IO.Path]::GetFileName($URL)
$FilePath = Invoke-Download -URL $URL
}
if ($ExpectedSHA256) {
$Hash = (Get-FileHash -Path $FilePath -Algorithm SH256).Hash
Verify-Checksum -Actual $Hash -Expected $ExpectedSHA256
}
if (-not $Type) {
$Type = ([System.IO.Path]::GetExtension($FilePath)).Replace(".", "").ToUpper()
}
switch ($Type) {
"EXE" {
if (-not $InstallArgs) { $InstallArgs = @() }
$InstallArgs += $ExtraInstallArgs
}
"MSI" {
if (-not $InstallArgs) {
Write-Host "Using default MSI arguments: /i, /qn, /norestart"
$InstallArgs = @("/i", $FilePath, "/qn", "/norestart")
}
$InstallArgs += $ExtraInstallArgs
$FilePath = "msiexec.exe"
}
default {
throw "Unknown installer type (${Type}), please specify via `-Type` parameter"
}
}
$InstallArgs += "${{ inputs.installer-args }}".Split(" ", [StringSplitOptions]"RemoveEmptyEntries")
$StartTime = Get-Date
Write-Host "Installer args: $($InstallArgs -join ' ')"
Write-Host "Starting Install..."
try {
$Process = Start-Process -FilePath $FilePath -ArgumentList $InstallArgs -Wait -PassThru -Verb RunAs
$ExitCode = $Process.ExitCode
$Duration = [math]::Round(($(Get-Date) - $StartTime).TotalSeconds, 2)
switch ($ExitCode) {
0 { Write-Host "Installation successful in $Duration seconds" }
3010 { Write-Host "Installation successful in $Duration seconds; reboot required"}
default {
Write-Host "Installation process returned unexpected exit code: $ExitCode"
Write-Host "Time elapsed: $Duration seconds"
exit $ExitCode
}
}
} catch {
$Duration = [math]::Round(($(Get-Date) - $StartTime).TotalSeconds, 2)
Write-Host "Installation failed after $Duration seconds: $_"
exit 1
}
}
if ("${{ steps.validation.outputs.use_custom_url }}" -eq "1") {
Invoke-Installer -LocalPath "${{ inputs.release-asset-name }}" -InstallArgs ("/quiet")
} else {
if ("${{ inputs.build_arch }}" -eq "amd64") {
Invoke-Installer -URL "https://download.swift.org/${{ inputs.branch }}/windows10/swift-${{ inputs.tag }}/swift-${{ inputs.tag }}-windows10.exe" -InstallArgs ("/quiet")
} else {
Invoke-Installer -URL "https://download.swift.org/${{ inputs.branch }}/windows10-${{ inputs.build_arch }}/swift-${{ inputs.tag }}/swift-${{ inputs.tag }}-windows10-${{ inputs.build_arch }}.exe" -InstallArgs ("/quiet")
}
}
Update-EnvironmentVariables
# Reset Path and environment
echo "$env:Path" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8
Get-ChildItem Env: | % { echo "$($_.Name)=$($_.Value)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append }
shell: pwsh
- name: Check Swift version
if: runner.os == 'Windows'
id: swift-version
shell: pwsh
run: |
$SwiftVersionOutput=$(swift --version)
if ("$SwiftVersionOutput" -match "[\d]+(\.[\d]+){0,2}") {
$SwiftSemVer=$Matches[0]
# Ensure we have at least MAJOR.MINOR or [System.Version] won't parse.
if (-Not ($SwiftSemVer -like "*.*")) {
$SwiftSemVer += ".0"
}
$SwiftVersion=[System.Version]($SwiftSemVer)
# If the toolchain is newer than 5.9 we don't need to ensure compatibility with VS2022.
if ($SwiftVersion -gt [System.Version]"5.9") {
"is_newer_than_5_9='true'" | Out-File $env:GITHUB_OUTPUT -Append -Encoding utf8
} else {
"is_newer_than_5_9='false'" | Out-File $env:GITHUB_OUTPUT -Append -Encoding utf8
}
}
- name: VS2022 Compatibility Setup
if: runner.os == 'Windows' && steps.swift-version.outputs.is_newer_than_5_9 == 'false'
uses: compnerd/gha-setup-vsdevenv@f1ba60d553a3216ce1b89abe0201213536bc7557 # v6
- name: VS2022 Compatibility Installation
if: runner.os == 'Windows' && steps.swift-version.outputs.is_newer_than_5_9 == 'false'
run: |
Copy-Item "$env:SDKROOT\usr\share\ucrt.modulemap" -destination "$env:UniversalCRTSdkDir\Include\$env:UCRTVersion\ucrt\module.modulemap"
if (Test-Path -Path "$env:SDKROOT\usr\share\vcruntime.modulemap") {
Copy-Item "$env:SDKROOT\usr\share\vcruntime.modulemap" -destination "$env:VCToolsInstallDir\include\module.modulemap"
Copy-Item "$env:SDKROOT\usr\share\vcruntime.apinotes" -destination "$env:VCToolsInstallDir\include\vcruntime.apinotes"
} else {
Copy-Item "$env:SDKROOT\usr\share\visualc.modulemap" -destination "$env:VCToolsInstallDir\include\module.modulemap"
Copy-Item "$env:SDKROOT\usr\share\visualc.apinotes" -destination "$env:VCToolsInstallDir\include\visualc.apinotes"
}
Copy-Item "$env:SDKROOT\usr\share\winsdk.modulemap" -destination "$env:UniversalCRTSdkDir\Include\$env:UCRTVersion\um\module.modulemap"
shell: pwsh
- name: Install Swift ${{ inputs.tag }}
if: runner.os == 'Linux'
run: |
source /etc/os-release
case ${ID} in
ubuntu)
case ${VERSION_ID} in
16.04|18.04|20.04|22.04)
if [[ "${{ steps.validation.outputs.use_custom_url }}" == "1" ]]; then
mv "${{ inputs.release-asset-name }}" swift-toolchain.tar.gz
else
curl -sL https://download.swift.org/${{ inputs.branch }}/ubuntu${VERSION_ID/./}/swift-${{ inputs.tag }}/swift-${{ inputs.tag }}-ubuntu${VERSION_ID}.tar.gz -o swift-toolchain.tar.gz
fi
tar zxf swift-toolchain.tar.gz -C ${HOME}
rm -f swift-toolchain.tar.gz
;;
*)
echo "::error file=/etc/os-release,title=Unsupported::unsupported ${OS} release (${VERSION_ID})"
exit 1
esac
;;
*)
echo ::error unknown Linux distribution
exit 1
esac
echo "${HOME}/usr/bin" >> $GITHUB_PATH
shell: bash
- name: Install Swift ${{ inputs.tag }}
if: runner.os == 'macOS'
run: |
if [[ "${{ steps.validation.outputs.use_custom_url }}" == "1" ]]; then
mv "${{ inputs.release-asset-name }}" swift-${{ inputs.tag }}-osx.pkg
else
curl -sOL https://download.swift.org/${{ inputs.branch }}/xcode/swift-${{ inputs.tag }}/swift-${{ inputs.tag }}-osx.pkg
fi
xattr -dr com.apple.quarantine swift-${{ inputs.tag }}-osx.pkg
installer -pkg swift-${{ inputs.tag }}-osx.pkg -target CurrentUserHomeDirectory
rm -f swift-${{ inputs.tag }}-osx.pkg
echo "TOOLCHAINS=$(plutil -extract 'CFBundleIdentifier' xml1 ${HOME}/Library/Developer/Toolchains/swift-${{ inputs.tag }}.xctoolchain/Info.plist | xmllint --xpath '//plist/string/text()' -)" >> $GITHUB_ENV
shell: bash