@@ -2,6 +2,15 @@ name: Install Swift
22description : Install Swift Release
33
44inputs :
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+
514 # for swift.org toolchains:
615 branch :
716 description : ' Branch for swift.org builds. Only specifiy when using official Swift toolchains from swift.org'
@@ -36,238 +45,82 @@ inputs:
3645
3746runs :
3847 using : ' composite'
39-
4048 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-
6649 - name : Fetch installer from GitHub release
67- if : steps.validation.outputs.use_custom_url == 1
68- shell : bash
50+ if : inputs.source == 'custom'
6951 env :
7052 GH_TOKEN : ${{ inputs.github-token }}
7153 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
7556
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'
7859 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"
13664 }
13765
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")
14667
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)"
15373 }
74+ shell : pwsh
15475
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"}
20288 default {
203- throw "Unknown installer type (${Type}), please specify via `-Type` parameter"
89+ Write-Host "::error::Installation process returned unexpected exit code: $_"
90+ exit $_
20491 }
20592 }
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
23096 }
23197
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)" }
240106 }
241- Update-EnvironmentVariables
242107
243108 # 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 }
246111 shell : pwsh
247112
248113 - name : Check Swift version
249114 if : runner.os == 'Windows'
250115 id : swift-version
251- shell : pwsh
252116 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
270122 }
123+ shell : pwsh
271124
272125 - name : VS2022 Compatibility Setup
273126 if : runner.os == 'Windows' && steps.swift-version.outputs.is_newer_than_5_9 == 'false'
@@ -291,10 +144,11 @@ runs:
291144 if : runner.os == 'Linux'
292145 run : |
293146 source /etc/os-release
147+ echo ${ID} ${VERSION_ID}
294148 case ${ID} in
295149 ubuntu)
296150 case ${VERSION_ID} in
297- 16.04|18.04|20.04|22.04)
151+ 16.04|18.04|20.04|22.04|24.04 )
298152 if [[ "${{ steps.validation.outputs.use_custom_url }}" == "1" ]]; then
299153 mv "${{ inputs.release-asset-name }}" swift-toolchain.tar.gz
300154 else
@@ -304,7 +158,7 @@ runs:
304158 rm -f swift-toolchain.tar.gz
305159 ;;
306160 *)
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})"
308162 exit 1
309163 esac
310164 ;;
0 commit comments