Skip to content

Commit 17be5ca

Browse files
authored
action: simplify the action logic
1. Split the Download and Install phase 2. Add an explicit option to select the "ParameterSet" for the toolchain source. 3. Inline the (now) single use functions. There is no need to have the ceremony around the function definition and invocation. 4. Specialise the install rules for the particular type of installer shipped for the Swift toolchain. It is unlikely to go to a MSI based installer. 5. Update Ubuntu version support for 24.04 6. Clean up some of the test rules, updating to 2025-02-24-a. This work prepares the composite action to integrate actions/cache to use the tool cache to amortize the cost of the download of the installer. This becomes more important as the installer size increases.
1 parent 1510050 commit 17be5ca

File tree

2 files changed

+69
-214
lines changed

2 files changed

+69
-214
lines changed

.github/workflows/test-install.yml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
uses: ./
3030
with:
3131
branch: development
32-
tag: DEVELOPMENT-SNAPSHOT-2023-05-20-a
32+
tag: DEVELOPMENT-SNAPSHOT-2025-02-24-a
3333

3434
- name: Check Swift version
3535
run: swift --version
@@ -43,7 +43,9 @@ jobs:
4343
run: sudo apt-get update && sudo apt-get install -y ninja-build
4444

4545
- name: Smoke test
46-
run: cmake -GNinja -S .github/smoke-test -B .cmake-build && cmake --build .cmake-build
46+
run: |
47+
cmake -B build -G Ninja -S .github/smoke-test
48+
cmake --build build
4749
4850
windows-installer-args:
4951
name: Test installer arguments on Windows
@@ -57,14 +59,13 @@ jobs:
5759
uses: ./
5860
with:
5961
branch: development
60-
tag: DEVELOPMENT-SNAPSHOT-2024-08-07-a # This installer version supports the argument below
61-
installer-args: OptionsInstallIde=0
62+
tag: DEVELOPMENT-SNAPSHOT-2025-02-24-a
63+
installer-args: OptionsInstallIDE=0
6264

6365
- name: Assert that we find swiftc.exe
64-
run: where.exe swiftc.exe
66+
run: Get-Command swiftc.exe
6567

6668
- name: Assert that we don't find sourcekit-lsp.exe
6769
shell: pwsh
6870
run: |
69-
where.exe sourcekit-lsp.exe
70-
if ($LastExitCode -eq 0) { exit 1 }
71+
-not (Get-Command sourcekit-lsp.exe -ErrorAction SilentlyContinue)

action.yml

Lines changed: 61 additions & 207 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@ name: Install Swift
22
description: Install Swift Release
33

44
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+
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

3746
runs:
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

Comments
 (0)