├── .github ├── smoke-test │ ├── CMakeLists.txt │ └── Library.swift └── workflows │ └── test-install.yml ├── .gitignore ├── LICENSE ├── README.md └── action.yml /.github/smoke-test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.25) 2 | project(gha_setup_swift LANGUAGES Swift) 3 | add_library(Library Library.swift) 4 | -------------------------------------------------------------------------------- /.github/smoke-test/Library.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func fortyTwo() -> Int { 42 } 4 | -------------------------------------------------------------------------------- /.github/workflows/test-install.yml: -------------------------------------------------------------------------------- 1 | name: Test install 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | workflow_dispatch: 11 | 12 | jobs: 13 | install-swift: 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | os: [macos-latest, windows-latest, ubuntu-latest] 18 | 19 | name: Test Swift toolchain install on ${{ matrix.os }} 20 | runs-on: ${{ matrix.os }} 21 | 22 | steps: 23 | - uses: actions/checkout@v3 24 | 25 | - uses: compnerd/gha-setup-vsdevenv@main 26 | if: ${{ runner.os == 'windows' }} 27 | 28 | - name: Install Swift 29 | uses: ./ 30 | with: 31 | branch: development 32 | tag: DEVELOPMENT-SNAPSHOT-2025-02-24-a 33 | 34 | - name: Check Swift version 35 | run: swift --version 36 | 37 | - name: Install pre-requisites for smoke test 38 | if: ${{ runner.os == 'macOS' }} 39 | run: brew install ninja 40 | 41 | - name: Install pre-requisites for smoke test 42 | if: ${{ runner.os == 'Linux' }} 43 | run: sudo apt-get update && sudo apt-get install -y ninja-build 44 | 45 | - name: Smoke test 46 | run: | 47 | cmake -B build -G Ninja -S .github/smoke-test 48 | cmake --build build 49 | 50 | windows-installer-args: 51 | name: Test installer arguments on Windows 52 | runs-on: windows-latest 53 | 54 | steps: 55 | - uses: actions/checkout@v3 56 | - uses: compnerd/gha-setup-vsdevenv@main 57 | 58 | - name: Install Swift without the IDE component 59 | uses: ./ 60 | with: 61 | branch: development 62 | tag: DEVELOPMENT-SNAPSHOT-2025-02-24-a 63 | installer-args: OptionsInstallIDE=0 64 | 65 | - name: Assert that we find swiftc.exe 66 | run: Get-Command swiftc.exe 67 | 68 | - name: Assert that we don't find sourcekit-lsp.exe 69 | shell: pwsh 70 | run: | 71 | -not (Get-Command sourcekit-lsp.exe -ErrorAction SilentlyContinue) 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | xcuserdata/ 5 | DerivedData/ 6 | .swiftpm/configuration/registries.json 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | .netrc 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, Saleem Abdulrasool 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gha-setup-swift 2 | Setup Swift (on Windows) on GitHub Actions Builders 3 | 4 | Automates installation of the Swift toolchain for Windows hosts on GitHub Actions runners. 5 | 6 | ## Usage 7 | 8 | > [!NOTE] 9 | > Windows requires Swift 5.4.2+ 10 | 11 | * Sample workflow using official Swift releases 12 | 13 | ```yaml 14 | on: [pull_request] 15 | 16 | jobs: 17 | windows: 18 | runs-on: windows-latest 19 | steps: 20 | - uses: compnerd/gha-setup-swift@main 21 | with: 22 | branch: swift-5.5-release 23 | tag: 5.5-RELEASE 24 | 25 | - uses: actions/checkout@v2 26 | - run: swift build 27 | - run: swift test 28 | ``` 29 | 30 | * Sample workflow using a custom Swift toolchain from a Github repository 31 | 32 | ```yaml 33 | on: [pull_request] 34 | 35 | jobs: 36 | windows: 37 | runs-on: windows-latest 38 | steps: 39 | - uses: compnerd/gha-setup-swift@main 40 | with: 41 | release-tag-name: "20230530.2" 42 | github-repo: mycompany/swift-toolchain-build 43 | release-asset-name: installer-amd64.exe 44 | 45 | - uses: actions/checkout@v2 46 | - run: swift build 47 | - run: swift test 48 | ``` 49 | 50 | ### Parameters 51 | 52 | #### When using official Swift releases: 53 | - `branch`: (**Note:** this is not a git branch name) the Swift "version" to be installed. This may be either a pre-release branch (e.g. `swift-5.5-branch`), a release branch (e.g. `swift-5.5-release`) or the development branch (`swift-development`). 54 | - `tag`: (**Note:** this is not a git tag name) the actual build tag to install, minus the “`swift-`” prefix. May indicate a release snapshot (e.g. `5.5-DEVELOPMENT-SNAPSHOT-2021-09-18-a`), development snapshot (e.g. `DEVELOPMENT-SNAPSHOT-2021-09-28-a`), or a release (e.g. `5.5-RELEASE`). 55 | 56 | #### When using Swift builds from a Github repository release: 57 | - `github-repo`: Github repo in "owner/repo" format 58 | 59 | - `release-tag-name`: Release tag name, can be found in `github.com///releases` 60 | 61 | - `release-asset-name`: Asset name for the Swift installer executable in the release 62 | 63 | - `github-token`: Optional Github token for fetching a release from a private repository 64 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: Install Swift 2 | description: Install Swift Release 3 | 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 | 14 | # for swift.org toolchains: 15 | branch: 16 | description: 'Branch for swift.org builds. Only specifiy when using official Swift toolchains from swift.org' 17 | required: false 18 | tag: 19 | description: 'Tag for swift.org builds. Only specifiy when using official Swift toolchains from swift.org' 20 | required: false 21 | build_arch: 22 | description: 'Build architecture (amd64 or arm64). Only specifiy when using official Swift toolchains from swift.org' 23 | default: 'amd64' 24 | required: true 25 | 26 | # for custom toolchains: 27 | github-repo: 28 | description: 'Github repo in "owner/repo" format. Only specify when using custom toolchains from Github releases.' 29 | required: false 30 | release-tag-name: 31 | description: 'Release tag name. Only specify when using custom toolchains from Github releases.' 32 | required: false 33 | release-asset-name: 34 | description: 'Asset name for the Swift installer executable in the release. Only specify when using custom toolchains from Github releases.' 35 | required: false 36 | github-token: 37 | description: 'Optional Github token for fetching a release. Only specify when using custom toolchains from non-public Github releases.' 38 | required: false 39 | 40 | # common 41 | installer-args: 42 | description: 'Additional arguments to pass to the installer, space-delimited (double quotes are not supported)' 43 | required: false 44 | default: '' 45 | 46 | runs: 47 | using: 'composite' 48 | steps: 49 | - name: Fetch installer from GitHub release 50 | if: inputs.source == 'custom' 51 | env: 52 | GH_TOKEN: ${{ inputs.github-token }} 53 | run: | 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 56 | 57 | - name: Fetch installer from swift.org 58 | if: runner.os == 'Windows' && inputs.source == 'swift.org' 59 | run: | 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" 64 | } 65 | 66 | $Path = [IO.Path]::Combine(${env:Temp}, "installer.exe") 67 | 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)" 73 | } 74 | shell: pwsh 75 | 76 | - name: Install Swift ${{ inputs.tag }} 77 | id: install-swift 78 | if: runner.os == 'Windows' 79 | run: | 80 | $Installer = [IO.Path]::Combine(${env:Temp}, "installer.exe") 81 | $Arguments = "/quiet /lv*x ${env:Temp}/install.log ${{ inputs.installer-args }}".Split(" ", [StringSplitOptions]"RemoveEmptyEntries") 82 | 83 | Write-Host "::debug::Installer Arguments: $($Arguments -join ' ')" 84 | try { 85 | $Process = Start-Process -FilePath $Installer -ArgumentList $Arguments -Wait -PassThru -Verb RunAs 86 | switch ($Process.ExitCode) { 87 | 0 { Write-Host "::debug::Installation successful" } 88 | 3010 { Write-Host "::notice::Installation successful; reboot required"} 89 | default { 90 | Write-Host "::error::Installation process returned unexpected exit code: $_" 91 | exit $_ 92 | } 93 | } 94 | } catch { 95 | Write-Host "::error::Installation failed: $($_.Exception.Message)" 96 | exit 1 97 | } 98 | 99 | foreach ($level in "Machine", "User") { 100 | [Environment]::GetEnvironmentVariables($level).GetEnumerator() | ForEach-Object { 101 | # For Path variables, append the new values, if they're not already in there 102 | if ($_.Name -eq "Path") { 103 | $_.Value = ("${env:Path};$($_.Value)" -Split ';' | Select -Unique) -Join ';' 104 | } 105 | $_ 106 | } | Set-Content -Path { "Env:$($_.Name)" } 107 | } 108 | 109 | # Reset Path and environment 110 | Write-Output "$env:Path" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 111 | Get-ChildItem Env: | ForEach-Object { echo "$($_.Name)=$($_.Value)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append } 112 | shell: pwsh 113 | 114 | - name: Upload Error Logs 115 | if: runner.os == 'Windows' && failure() && steps.install-swift.outcome == 'failure' 116 | uses: actions/upload-artifact@v4 117 | with: 118 | name: installer-logs 119 | path: ${env:Temp}/install*.log* 120 | 121 | - name: Check Swift version 122 | if: runner.os == 'Windows' 123 | id: swift-version 124 | run: | 125 | $Output = swift --version 126 | $Match = ([regex]"\d+.\d+(.\d+)?").Match($Output) 127 | if ($Match.Success) { 128 | $SwiftVersion = [System.Version]($Match.Groups[0].Value) 129 | Write-Output is_newer_than_5_9=$($SwiftVersion -gt [System.Version]"5.9") | Out-File $env:GITHUB_OUTPUT -Append -Encoding UTF8 130 | } 131 | shell: pwsh 132 | 133 | - name: VS2022 Compatibility Setup 134 | if: runner.os == 'Windows' && steps.swift-version.outputs.is_newer_than_5_9 == 'false' 135 | uses: compnerd/gha-setup-vsdevenv@f1ba60d553a3216ce1b89abe0201213536bc7557 # v6 136 | 137 | - name: VS2022 Compatibility Installation 138 | if: runner.os == 'Windows' && steps.swift-version.outputs.is_newer_than_5_9 == 'false' 139 | run: | 140 | Copy-Item "$env:SDKROOT\usr\share\ucrt.modulemap" -destination "$env:UniversalCRTSdkDir\Include\$env:UCRTVersion\ucrt\module.modulemap" 141 | if (Test-Path -Path "$env:SDKROOT\usr\share\vcruntime.modulemap") { 142 | Copy-Item "$env:SDKROOT\usr\share\vcruntime.modulemap" -destination "$env:VCToolsInstallDir\include\module.modulemap" 143 | Copy-Item "$env:SDKROOT\usr\share\vcruntime.apinotes" -destination "$env:VCToolsInstallDir\include\vcruntime.apinotes" 144 | } else { 145 | Copy-Item "$env:SDKROOT\usr\share\visualc.modulemap" -destination "$env:VCToolsInstallDir\include\module.modulemap" 146 | Copy-Item "$env:SDKROOT\usr\share\visualc.apinotes" -destination "$env:VCToolsInstallDir\include\visualc.apinotes" 147 | } 148 | Copy-Item "$env:SDKROOT\usr\share\winsdk.modulemap" -destination "$env:UniversalCRTSdkDir\Include\$env:UCRTVersion\um\module.modulemap" 149 | shell: pwsh 150 | 151 | - name: Install Swift ${{ inputs.tag }} 152 | if: runner.os == 'Linux' 153 | run: | 154 | source /etc/os-release 155 | echo ${ID} ${VERSION_ID} 156 | case ${ID} in 157 | ubuntu) 158 | case ${VERSION_ID} in 159 | 16.04|18.04|20.04|22.04|24.04) 160 | if [[ "${{ steps.validation.outputs.use_custom_url }}" == "1" ]]; then 161 | mv "${{ inputs.release-asset-name }}" swift-toolchain.tar.gz 162 | else 163 | 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 164 | fi 165 | tar zxf swift-toolchain.tar.gz -C ${HOME} 166 | rm -f swift-toolchain.tar.gz 167 | ;; 168 | *) 169 | echo "::error file=/etc/os-release,title=Unsupported::unsupported ${ID} release (${VERSION_ID})" 170 | exit 1 171 | esac 172 | ;; 173 | *) 174 | echo ::error unknown Linux distribution 175 | exit 1 176 | esac 177 | 178 | echo "${HOME}/usr/bin" >> $GITHUB_PATH 179 | shell: bash 180 | 181 | - name: Install Swift ${{ inputs.tag }} 182 | if: runner.os == 'macOS' 183 | run: | 184 | if [[ "${{ steps.validation.outputs.use_custom_url }}" == "1" ]]; then 185 | mv "${{ inputs.release-asset-name }}" swift-${{ inputs.tag }}-osx.pkg 186 | else 187 | curl -sOL https://download.swift.org/${{ inputs.branch }}/xcode/swift-${{ inputs.tag }}/swift-${{ inputs.tag }}-osx.pkg 188 | fi 189 | xattr -dr com.apple.quarantine swift-${{ inputs.tag }}-osx.pkg 190 | installer -pkg swift-${{ inputs.tag }}-osx.pkg -target CurrentUserHomeDirectory 191 | rm -f swift-${{ inputs.tag }}-osx.pkg 192 | 193 | echo "TOOLCHAINS=$(plutil -extract 'CFBundleIdentifier' xml1 ${HOME}/Library/Developer/Toolchains/swift-${{ inputs.tag }}.xctoolchain/Info.plist | xmllint --xpath '//plist/string/text()' -)" >> $GITHUB_ENV 194 | shell: bash 195 | --------------------------------------------------------------------------------