diff --git a/.github/actions/setup-swift/action.yml b/.github/actions/setup-swift/action.yml new file mode 100644 index 0000000..8d1c534 --- /dev/null +++ b/.github/actions/setup-swift/action.yml @@ -0,0 +1,39 @@ +name: Setup Swift +description: Install and cache a verified Swift release using Swiftly. + +inputs: + swift-version: + description: Exact Swift release version to install + required: true + +runs: + using: composite + steps: + - name: Locate tool cache + id: tool-cache + shell: bash + env: + SWIFT_VERSION: ${{ inputs.swift-version }} + run: | + if [[ ! "$SWIFT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "::error::swift-version must be an exact release, e.g. 6.4.0." + exit 1 + fi + ARCH=$(printf '%s' "$RUNNER_ARCH" | tr '[:upper:]' '[:lower:]') + CACHE_PATH="$RUNNER_TOOL_CACHE/swift/$SWIFT_VERSION/$ARCH" + echo "path=$CACHE_PATH" >> "$GITHUB_OUTPUT" + + - name: Cache Swift toolchain + uses: actions/cache@v6 + with: + path: | + ${{ steps.tool-cache.outputs.path }} + ${{ steps.tool-cache.outputs.path }}.complete + key: swift-${{ runner.os }}-${{ runner.arch }}-${{ env.ImageOS }}-${{ env.ImageVersion }}-${{ inputs.swift-version }}-${{ hashFiles('.github/actions/setup-swift/**') }} + + - name: Install and select Swift + shell: bash + env: + SWIFT_VERSION: ${{ inputs.swift-version }} + SWIFT_CACHE_PATH: ${{ steps.tool-cache.outputs.path }} + run: bash "$GITHUB_ACTION_PATH/setup.sh" diff --git a/.github/actions/setup-swift/setup.sh b/.github/actions/setup-swift/setup.sh new file mode 100644 index 0000000..c900f11 --- /dev/null +++ b/.github/actions/setup-swift/setup.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +set -euo pipefail +: "${SWIFT_VERSION:?SWIFT_VERSION is required}" + +export SWIFTLY_HOME_DIR="$SWIFT_CACHE_PATH/home" +export SWIFTLY_BIN_DIR="$SWIFT_CACHE_PATH/bin" +export SWIFTLY_TOOLCHAINS_DIR="$SWIFT_CACHE_PATH/toolchains" + +# Keep Swiftly's version selection outside the checked-out repository. +mkdir -p "$SWIFT_CACHE_PATH" +cd "$SWIFT_CACHE_PATH" + +if [[ ! -f "$SWIFT_CACHE_PATH.complete" ]]; then + SWIFTLY_VERSION=1.1.4 + DOWNLOAD_DIR=$(mktemp -d "$RUNNER_TEMP/setup-swift.XXXXXX") + + case "$RUNNER_OS" in + Linux) + URL="https://download.swift.org/swiftly/linux" + URL="$URL/swiftly-$SWIFTLY_VERSION-$(uname -m).tar.gz" + curl --fail --silent --show-error --location "$URL" \ + --output "$DOWNLOAD_DIR/swiftly.tar.gz" + curl --fail --silent --show-error --location "$URL.sig" \ + --output "$DOWNLOAD_DIR/swiftly.tar.gz.sig" + curl --compressed --fail --silent --show-error --location \ + https://swift.org/keys/all-keys.asc \ + --output "$DOWNLOAD_DIR/swift-keys.asc" + # Swiftly's bootstrap signature must be checked before executing it. + gpg --batch --import "$DOWNLOAD_DIR/swift-keys.asc" + gpg --batch --verify "$DOWNLOAD_DIR/swiftly.tar.gz.sig" \ + "$DOWNLOAD_DIR/swiftly.tar.gz" + tar -xzf "$DOWNLOAD_DIR/swiftly.tar.gz" -C "$DOWNLOAD_DIR" + SWIFTLY="$DOWNLOAD_DIR/swiftly" + ;; + macOS) + URL="https://download.swift.org/swiftly/darwin" + curl --fail --silent --show-error --location \ + "$URL/swiftly-$SWIFTLY_VERSION.pkg" \ + --output "$DOWNLOAD_DIR/swiftly.pkg" + pkgutil --check-signature "$DOWNLOAD_DIR/swiftly.pkg" + pkgutil --expand "$DOWNLOAD_DIR/swiftly.pkg" "$DOWNLOAD_DIR/package" + mkdir -p "$DOWNLOAD_DIR/extracted" + tar -xf "$DOWNLOAD_DIR/package"/swiftly-*/Payload \ + -C "$DOWNLOAD_DIR/extracted" + SWIFTLY="$DOWNLOAD_DIR/extracted/bin/swiftly" + ;; + *) + echo "::error::Unsupported runner OS: $RUNNER_OS" + exit 1 + ;; + esac + + "$SWIFTLY" init --skip-install --quiet-shell-followup \ + --assume-yes --no-modify-profile + "$SWIFTLY_BIN_DIR/swiftly" install "$SWIFT_VERSION" --use --assume-yes \ + --post-install-file "$SWIFT_CACHE_PATH/post-install.sh" +fi + +# A restored toolchain still needs its system dependencies on a fresh runner. +if [[ -f "$SWIFT_CACHE_PATH/post-install.sh" ]]; then + if [[ "$RUNNER_OS" == Linux ]]; then + sudo apt-get update + fi + sudo bash "$SWIFT_CACHE_PATH/post-install.sh" +fi + +TOOLCHAIN=$("$SWIFTLY_BIN_DIR/swiftly" use --print-location) +SWIFT_BIN="$TOOLCHAIN/usr/bin" +VERSION_OUTPUT=$("$SWIFT_BIN/swift" --version) +printf '%s\n' "$VERSION_OUTPUT" +ACTUAL_VERSION=$(printf '%s\n' "$VERSION_OUTPUT" \ + | sed -nE 's/.*Swift version ([0-9]+\.[0-9]+(\.[0-9]+)?).*/\1/p') +if [[ "$ACTUAL_VERSION" =~ ^[0-9]+\.[0-9]+$ ]]; then + ACTUAL_VERSION="$ACTUAL_VERSION.0" +fi +if [[ "$ACTUAL_VERSION" != "$SWIFT_VERSION" ]]; then + echo "::error::Expected Swift $SWIFT_VERSION, got $ACTUAL_VERSION" + exit 1 +fi + +# Match the runner tool-cache convention: publish only complete installations. +touch "$SWIFT_CACHE_PATH.complete" +printf '%s\n' "$SWIFT_BIN" >> "$GITHUB_PATH" diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index fbebb64..1ac2892 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -23,9 +23,9 @@ jobs: uses: actions/checkout@v7 - name: Setup Swift - uses: swift-actions/setup-swift@v3 + uses: ./.github/actions/setup-swift with: - swift-version: "6.3.3" + swift-version: "6.4.0" - name: Install analysis tools run: brew bundle --file Brewfile-ci diff --git a/.github/workflows/build-binaries.yml b/.github/workflows/build-binaries.yml index 975d001..976e822 100644 --- a/.github/workflows/build-binaries.yml +++ b/.github/workflows/build-binaries.yml @@ -46,9 +46,9 @@ jobs: uses: actions/checkout@v7 - name: Setup Swift - uses: swift-actions/setup-swift@v3 + uses: ./.github/actions/setup-swift with: - swift-version: "6.3.3" + swift-version: "6.4.0" - name: Generate build metadata uses: ./.github/actions/generate-build-metadata @@ -123,15 +123,15 @@ jobs: uses: actions/checkout@v7 - name: Setup Swift - uses: swift-actions/setup-swift@v3 + uses: ./.github/actions/setup-swift with: - swift-version: "6.3.3" + swift-version: "6.4.0" - name: Install Static Linux SDK run: | swift sdk install \ - "https://download.swift.org/swift-6.3.3-release/static-sdk/swift-6.3.3-RELEASE/swift-6.3.3-RELEASE_static-linux-0.1.0.artifactbundle.tar.gz" \ - --checksum "87c3eaf908e67c0e13a84367119e12273cec1d2cd3d81f7d74bb36722d6b607b" + "https://download.swift.org/swift-6.4.0-release/static-sdk/swift-6.4.0-RELEASE/swift-6.4.0-RELEASE_static-linux-0.1.0.artifactbundle.tar.gz" \ + --checksum "47d2fd89eebfdf9eb4d536b6710414297f755c17926cdebc4742c08982b40a9e" - name: Generate build metadata uses: ./.github/actions/generate-build-metadata diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 199ed9a..5f0cb2f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,9 +23,9 @@ jobs: uses: actions/checkout@v7 - name: Setup Swift - uses: swift-actions/setup-swift@v3 + uses: ./.github/actions/setup-swift with: - swift-version: "6.3.3" + swift-version: "6.4.0" - name: Make Build run: make build diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 5c1c430..ae49f3f 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -23,9 +23,9 @@ jobs: uses: actions/checkout@v7 - name: Setup Swift - uses: swift-actions/setup-swift@v3 + uses: ./.github/actions/setup-swift with: - swift-version: "6.3.3" + swift-version: "6.4.0" - name: Install formatting tools run: brew bundle --file Brewfile-ci diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9dbc2e2..e475fe0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,9 +23,9 @@ jobs: uses: actions/checkout@v7 - name: Setup Swift - uses: swift-actions/setup-swift@v3 + uses: ./.github/actions/setup-swift with: - swift-version: "6.3.3" + swift-version: "6.4.0" - name: Make Test run: make test @@ -39,9 +39,9 @@ jobs: uses: actions/checkout@v7 - name: Setup Swift - uses: swift-actions/setup-swift@v3 + uses: ./.github/actions/setup-swift with: - swift-version: "6.3.3" + swift-version: "6.4.0" - name: Make Test run: make test diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 0000000..bbcd868 --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,5 @@ +extends: default + +rules: + line-length: + max: 200