@@ -2,6 +2,15 @@ name: Install Swift
2
2
description : Install Swift Release
3
3
4
4
inputs :
5
+ source :
6
+ description : " Where to source the Swift installer. Specify either 'swift.org' or 'custom' (Github release)"
7
+ required : true
8
+ default : ' swift.org'
9
+ type : choice
10
+ options :
11
+ - swift.org
12
+ - custom
13
+
5
14
# for swift.org toolchains:
6
15
branch :
7
16
description : ' Branch for swift.org builds. Only specifiy when using official Swift toolchains from swift.org'
@@ -36,238 +45,82 @@ inputs:
36
45
37
46
runs :
38
47
using : ' composite'
39
-
40
48
steps :
41
- - name : Validate inputs
42
- id : validation
43
- shell : bash
44
- run : |
45
- if [[ -n "${{ inputs.github-repo }}" && -n "${{ inputs.release-tag-name }}" && -n "${{ inputs.release-asset-name }}" ]]; then
46
- if [[ "${{ runner.os }}" == "Linux" && "${{ inputs.release-asset-name }}" != *.tar.gz ]]; then
47
- echo >&2 "::error::inputs Invalid action inputs: release-asset-name has to be a '*.tar.gz' file on Linux platforms."
48
- exit 1
49
- elif [[ "${{ runner.os }}" == "macOS" && "${{ inputs.release-asset-name }}" != *.pkg ]]; then
50
- echo >&2 "::error::inputs Invalid action inputs: release-asset-name has to be a '*.pkg' file on MacOS platforms."
51
- exit 1
52
- elif [[ "${{ runner.os }}" == "Windows" && "${{ inputs.release-asset-name }}" != *.exe ]]; then
53
- echo >&2 "::error::inputs Invalid action inputs: release-asset-name has to be a '*.exe' file on Windows platforms."
54
- exit 1
55
- fi
56
- echo "use_custom_url=1" >> $GITHUB_OUTPUT
57
- elif [[ -n "${{ inputs.branch }}" && -n "${{ inputs.tag }}" ]]; then
58
- echo "use_custom_url=0" >> $GITHUB_OUTPUT
59
- else
60
- echo >&2 "::error::inputs Invalid action inputs"
61
- echo >&2 "::error:: for a custom Swift toolchain, specify github-repo, release-tag-name and release-asset-name"
62
- echo >&2 "::error:: for the official swift.org toolchain, specify only branch and tag"
63
- exit 1
64
- fi
65
-
66
49
- name : Fetch installer from GitHub release
67
- if : steps.validation.outputs.use_custom_url == 1
68
- shell : bash
50
+ if : inputs.source == 'custom'
69
51
env :
70
52
GH_TOKEN : ${{ inputs.github-token }}
71
53
run : |
72
- gh release download "${{ inputs.release-tag-name }}" \
73
- --repo "${{ inputs.github-repo }}" \
74
- --pattern "${{ inputs.release-asset-name }}"
54
+ gh release download "${{ inputs.release-tag-name }}" --skip-existing --repo "${{ inputs.github-repo }}" --pattern "${{ inputs.release-asset-name }}" --output $([IO.Path]::Combine(${env:Temp}, "installer.exe"))
55
+ shell : pwsh
75
56
76
- - name : Install Swift ${{ inputs.tag }}
77
- if : runner.os == 'Windows'
57
+ - name : Fetch installer from swift.org
58
+ if : runner.os == 'Windows' && inputs.source == 'swift.org'
78
59
run : |
79
- function Update-EnvironmentVariables {
80
- foreach ($level in "Machine", "User") {
81
- [Environment]::GetEnvironmentVariables($level).GetEnumerator() | % {
82
- # For Path variables, append the new values, if they're not already in there
83
- if ($_.Name -Match 'Path$') {
84
- $_.Value = ($((Get-Content "Env:$($_.Name)") + ";$($_.Value)") -Split ';' | Select -Unique) -Join ';'
85
- }
86
- $_
87
- } | Set-Content -Path { "Env:$($_.Name)" }
88
- }
89
- }
90
-
91
- function Invoke-Download {
92
- Param
93
- (
94
- [Parameter(Mandatory)]
95
- [String] $URL,
96
- [Alias("Destination")]
97
- [Int] $Retries = 20,
98
- [Int] $RetryInterval = 30
99
- )
100
-
101
- $InvalidCharacters = [IO.Path]::GetInvalidFileNameChars() -Join ''
102
- $RE = "[{0}]" -f [RegEx]::Escape($InvalidCharacters)
103
- $FileName = [IO.Path]::GetFileName($URL) -Replace $RE
104
-
105
- if ([String]::IsNullOrEmpty($FileName)) {
106
- $FileName = [System.IO.Path]::GetRandomFileName()
107
- }
108
- $Path = Join-Path -Path "${env:Temp}" -ChildPath $FileName
109
-
110
- Write-Host "Downloading package from $URL to $Path..."
111
-
112
- $StartTime = Get-Date
113
- do {
114
- try {
115
- $AttemptStartTime = Get-Date
116
- (New-Object System.Net.WebClient).DownloadFile($URL, $Path)
117
- $AttemptDuration = [math]::Round(($(Get-Date) - $AttemptStartTime).TotalSeconds, 2)
118
- Write-Host "Package downloaded in $AttemptDuration seconds"
119
- break
120
- } catch {
121
- $AttemptDuration = [math]::Round(($(Get-Date) - $AttemptStartTime).TotalSeconds, 2)
122
- Write-Warning "Package download failed after $AttemptDuration seconds"
123
- Write-Warning $_.Exception.Message
124
- }
125
-
126
- if ($Retries -eq 1) {
127
- $Duration = [math]::Round(($(Get-Date) - $StartTime).TotalSeconds, 2)
128
- throw "Package download failed after $Duration seconds"
129
- }
130
-
131
- Write-Warning "Waiting $RetryInterval seconds before retrying (retries remaining: $($Retries - 1))..."
132
- Start-Sleep -Seconds $RetryInterval
133
- } while (--$Retries -gt 0)
134
-
135
- return $Path
60
+ $URL = if ("${{ inputs.build_arch }}" -eq "amd64") {
61
+ "https://download.swift.org/${{ inputs.branch }}/windows10/swift-${{ inputs.tag }}/swift-${{ inputs.tag }}-windows10.exe"
62
+ } else {
63
+ "https://download.swift.org/${{ inputs.branch }}/windows10-${{ inputs.build_arch }}/swift-${{ inputs.tag }}/swift-${{ inputs.tag }}-windows10-${{ inputs.build_arch }}.exe"
136
64
}
137
65
138
- function Verify-Checksum {
139
- Param
140
- (
141
- [Parameter(Mandatory)]
142
- [String] $Actual,
143
- [Parameter(Mandatory)]
144
- [String] $Expected
145
- )
66
+ $Path = [IO.Path]::Combine(${env:Temp}, "installer.exe")
146
67
147
- Write-Verbose "Performing Checksum Verification"
148
- if ($Actual -eq $Expected) {
149
- Write-Verbose "Checksum verification passed"
150
- } else {
151
- throw "Checksum verification failure (Actual: $Actual vs Expected: $Expected)"
152
- }
68
+ Write-Host "Downloading package from $URL to $Path..."
69
+ try {
70
+ (New-Object System.Net.WebClient).DownloadFile($URL, $Path)
71
+ } catch {
72
+ Write-Host "::error::Package download failed: $($_.Exception.Message)"
153
73
}
74
+ shell : pwsh
154
75
155
- function Invoke-Installer {
156
- Param
157
- (
158
- [Parameter(Mandatory, ParameterSetName = "URL")]
159
- [String] $URL,
160
- [Parameter(Mandatory, ParameterSetName = "LocalPath")]
161
- [String] $LocalPath,
162
- [ValidateSet("MSI", "EXE")]
163
- [String] $Type,
164
- [String[]] $InstallArgs = $null, # Use default for installer format
165
- [String[]] $ExtraInstallArgs = @(),
166
- [String] $ExpectedSHA256
167
- )
168
-
169
- if ($PSCmdlet.ParameterSetName -eq "LocalPath") {
170
- if (-not (Test-Path -Path $LocalPath)) {
171
- throw "LocalPath parameter is specified, but the file does not exist"
172
- }
173
- $FilePath = $LocalPath
174
- } else {
175
- $FileName = [System.IO.Path]::GetFileName($URL)
176
- $FilePath = Invoke-Download -URL $URL
177
- }
178
-
179
- if ($ExpectedSHA256) {
180
- $Hash = (Get-FileHash -Path $FilePath -Algorithm SH256).Hash
181
- Verify-Checksum -Actual $Hash -Expected $ExpectedSHA256
182
- }
183
-
184
- if (-not $Type) {
185
- $Type = ([System.IO.Path]::GetExtension($FilePath)).Replace(".", "").ToUpper()
186
- }
187
-
188
- switch ($Type) {
189
- "EXE" {
190
- if (-not $InstallArgs) { $InstallArgs = @() }
191
- $InstallArgs += $ExtraInstallArgs
192
- }
193
- "MSI" {
194
- if (-not $InstallArgs) {
195
- Write-Host "Using default MSI arguments: /i, /qn, /norestart"
196
- $InstallArgs = @("/i", $FilePath, "/qn", "/norestart")
197
- }
198
-
199
- $InstallArgs += $ExtraInstallArgs
200
- $FilePath = "msiexec.exe"
201
- }
76
+ - name : Install Swift ${{ inputs.tag }}
77
+ if : runner.os == 'Windows'
78
+ run : |
79
+ $Installer = [IO.Path]::Combine(${env:Temp}, "installer.exe")
80
+ $Arguments = "/quiet ${{ inputs.installer-args }}".Split(" ", [StringSplitOptions]"RemoveEmptyEntries")
81
+
82
+ Write-Host "::debug::Installer Arguments: $($Arguments -join ' ')"
83
+ try {
84
+ $Process = Start-Process -FilePath $Installer -ArgumentList $Arguments -Wait -PassThru -Verb RunAs
85
+ switch ($Process.ExitCode) {
86
+ 0 { Write-Host "::debug::Installation successful" }
87
+ 3010 { Write-Host "::notice::Installation successful; reboot required"}
202
88
default {
203
- throw "Unknown installer type (${Type}), please specify via `-Type` parameter"
89
+ Write-Host "::error::Installation process returned unexpected exit code: $_"
90
+ exit $_
204
91
}
205
92
}
206
-
207
- $InstallArgs += "${{ inputs.installer-args }}".Split(" ", [StringSplitOptions]"RemoveEmptyEntries")
208
-
209
- $StartTime = Get-Date
210
- Write-Host "Installer args: $($InstallArgs -join ' ')"
211
- Write-Host "Starting Install..."
212
- try {
213
- $Process = Start-Process -FilePath $FilePath -ArgumentList $InstallArgs -Wait -PassThru -Verb RunAs
214
- $ExitCode = $Process.ExitCode
215
- $Duration = [math]::Round(($(Get-Date) - $StartTime).TotalSeconds, 2)
216
- switch ($ExitCode) {
217
- 0 { Write-Host "Installation successful in $Duration seconds" }
218
- 3010 { Write-Host "Installation successful in $Duration seconds; reboot required"}
219
- default {
220
- Write-Host "Installation process returned unexpected exit code: $ExitCode"
221
- Write-Host "Time elapsed: $Duration seconds"
222
- exit $ExitCode
223
- }
224
- }
225
- } catch {
226
- $Duration = [math]::Round(($(Get-Date) - $StartTime).TotalSeconds, 2)
227
- Write-Host "Installation failed after $Duration seconds: $_"
228
- exit 1
229
- }
93
+ } catch {
94
+ Write-Host "::error::Installation failed: $($_.Exception.Message)"
95
+ exit 1
230
96
}
231
97
232
- if ("${{ steps.validation.outputs.use_custom_url }}" -eq "1 ") {
233
- Invoke-Installer -LocalPath "${{ inputs.release-asset-name }}" -InstallArgs ("/quiet")
234
- } else {
235
- if ("${{ inputs.build_arch }}" -eq "amd64 ") {
236
- Invoke-Installer -URL "https://download.swift.org/${{ inputs.branch }}/windows10/swift-${{ inputs.tag }}/swift-${{ inputs.tag }}-windows10.exe" -InstallArgs ("/quiet")
237
- } else {
238
- 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")
239
- }
98
+ foreach ($level in "Machine", "User ") {
99
+ [Environment]::GetEnvironmentVariables($level).GetEnumerator() | ForEach-Object {
100
+ # For Path variables, append the new values, if they're not already in there
101
+ if ($_.Name -eq "Path ") {
102
+ $_.Value = ("${env:Path};$($_.Value)" -Split ';' | Select -Unique) -Join ';'
103
+ }
104
+ $_
105
+ } | Set-Content -Path { "Env:$($_.Name)" }
240
106
}
241
- Update-EnvironmentVariables
242
107
243
108
# Reset Path and environment
244
- echo "$env:Path" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8
245
- Get-ChildItem Env: | % { echo "$($_.Name)=$($_.Value)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append }
109
+ Write-Output "$env:Path" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8
110
+ Get-ChildItem Env: | ForEach-Object { echo "$($_.Name)=$($_.Value)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append }
246
111
shell : pwsh
247
112
248
113
- name : Check Swift version
249
114
if : runner.os == 'Windows'
250
115
id : swift-version
251
- shell : pwsh
252
116
run : |
253
- $SwiftVersionOutput=$(swift --version)
254
- if ("$SwiftVersionOutput" -match "[\d]+(\.[\d]+){0,2}") {
255
- $SwiftSemVer=$Matches[0]
256
-
257
- # Ensure we have at least MAJOR.MINOR or [System.Version] won't parse.
258
- if (-Not ($SwiftSemVer -like "*.*")) {
259
- $SwiftSemVer += ".0"
260
- }
261
-
262
- $SwiftVersion=[System.Version]($SwiftSemVer)
263
-
264
- # If the toolchain is newer than 5.9 we don't need to ensure compatibility with VS2022.
265
- if ($SwiftVersion -gt [System.Version]"5.9") {
266
- "is_newer_than_5_9='true'" | Out-File $env:GITHUB_OUTPUT -Append -Encoding utf8
267
- } else {
268
- "is_newer_than_5_9='false'" | Out-File $env:GITHUB_OUTPUT -Append -Encoding utf8
269
- }
117
+ $Output = swift --version
118
+ $Match = ([regex]"\d+.\d+(.\d+)?").Match($Output)
119
+ if ($Match.Success) {
120
+ $SwiftVersion = [System.Version]($Match.Groups[0].Value)
121
+ Write-Output is_newer_than_5_9=$($SwiftVersion -gt [System.Version]"5.9") | Out-File $env:GITHUB_OUTPUT -Append -Encoding UTF8
270
122
}
123
+ shell : pwsh
271
124
272
125
- name : VS2022 Compatibility Setup
273
126
if : runner.os == 'Windows' && steps.swift-version.outputs.is_newer_than_5_9 == 'false'
@@ -291,10 +144,11 @@ runs:
291
144
if : runner.os == 'Linux'
292
145
run : |
293
146
source /etc/os-release
147
+ echo ${ID} ${VERSION_ID}
294
148
case ${ID} in
295
149
ubuntu)
296
150
case ${VERSION_ID} in
297
- 16.04|18.04|20.04|22.04)
151
+ 16.04|18.04|20.04|22.04|24.04 )
298
152
if [[ "${{ steps.validation.outputs.use_custom_url }}" == "1" ]]; then
299
153
mv "${{ inputs.release-asset-name }}" swift-toolchain.tar.gz
300
154
else
@@ -304,7 +158,7 @@ runs:
304
158
rm -f swift-toolchain.tar.gz
305
159
;;
306
160
*)
307
- echo "::error file=/etc/os-release,title=Unsupported::unsupported ${OS } release (${VERSION_ID})"
161
+ echo "::error file=/etc/os-release,title=Unsupported::unsupported ${ID } release (${VERSION_ID})"
308
162
exit 1
309
163
esac
310
164
;;
0 commit comments