From c4e323a44346bdbf7d68bd0a8d4d21d2a0e81e99 Mon Sep 17 00:00:00 2001 From: Evan Wilde Date: Tue, 18 Aug 2026 15:38:49 -0700 Subject: [PATCH] Add install cmake action Adding an action to install a specific version of CMake. The version is verified against a hash before being unpacked and installed. --- .github/actions/install-cmake/action.yml | 50 +++++++++ .../actions/install-cmake/install-cmake.sh | 102 ++++++++++++++++++ .github/actions/install-cmake/readme.md | 47 ++++++++ 3 files changed, 199 insertions(+) create mode 100644 .github/actions/install-cmake/action.yml create mode 100755 .github/actions/install-cmake/install-cmake.sh create mode 100644 .github/actions/install-cmake/readme.md diff --git a/.github/actions/install-cmake/action.yml b/.github/actions/install-cmake/action.yml new file mode 100644 index 00000000..01cc3004 --- /dev/null +++ b/.github/actions/install-cmake/action.yml @@ -0,0 +1,50 @@ +name: 'Install CMake' +description: 'Download and install CMake' + +inputs: + cmake-version: + description: "CMake version (e.g. '3.30.2')" + required: true + hash: + description: "Expected SHA-256 hash of the target archive (Required)." + required: true + install_dir: + description: "Location where to install CMake" + required: false + default: "" + +outputs: + cmake-dir: + description: "Directory containing the CMake binaries" + value: ${{ steps.install.outputs.cmake-dir }} + cmake: + description: "Path to the installed CMake binary" + value: ${{ steps.install.outputs.cmake-path }} + ctest: + description: "Path to the installed CTest binary" + value: ${{ steps.install.outputs.ctest-path }} + +runs: + using: "composite" + steps: + - name: Run CMake Installer + id: install + shell: bash + env: + CMAKE_VERSION: ${{ inputs.cmake-version }} + CMAKE_SHA256: ${{ inputs.hash }} + CMAKE_INSTALL_DIR: ${{ inputs.install_dir }} + RAW_ACTION_PATH: ${{ github.action_path }} + run: | + # Resolve path whether running on the host runner or inside a Docker container + SCRIPT_PATH="${RAW_ACTION_PATH}/install-cmake.sh" + if [ ! -f "${SCRIPT_PATH}" ]; then + CONTAINER_PATH="$(echo "${RAW_ACTION_PATH}" | sed 's|^/home/runner/work|/__w|')" + if [ -f "${CONTAINER_PATH}/install-cmake.sh" ]; then + SCRIPT_PATH="${CONTAINER_PATH}/install-cmake.sh" + elif [ -f "${GITHUB_WORKSPACE}/.github/actions/install-cmake/install-cmake.sh" ]; then + SCRIPT_PATH="${GITHUB_WORKSPACE}/.github/actions/install-cmake/install-cmake.sh" + fi + fi + + bash "${SCRIPT_PATH}" diff --git a/.github/actions/install-cmake/install-cmake.sh b/.github/actions/install-cmake/install-cmake.sh new file mode 100755 index 00000000..5d0a1df8 --- /dev/null +++ b/.github/actions/install-cmake/install-cmake.sh @@ -0,0 +1,102 @@ +#!/bin/bash +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift.org open source project +## +## Copyright (c) YEARS Apple Inc. and the Swift project authors +## Licensed under Apache License v2.0 with Runtime Library Exception +## +## See https://swift.org/LICENSE.txt for license information +## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +## +##===----------------------------------------------------------------------===## +set -euo pipefail + +VERSION="${CMAKE_VERSION:?CMAKE_VERSION is required}" +EXPECTED_SHA="${CMAKE_SHA256:?CMAKE_SHA256 is required}" +OS="${RUNNER_OS:?RUNNER_OS is required}" +ARCH="${RUNNER_ARCH:?RUNNER_ARCH is required}" +TEMP_DIR="${RUNNER_TEMP:?RUNNER_TEMP is required}" + +# Normalize hash to lowercase and strip whitespace +EXPECTED_SHA=$(echo "${EXPECTED_SHA}" | tr '[:upper:]' '[:lower:]' | xargs) + +# 1. Determine destination directory (fallback to $RUNNER_TEMP/cmake- if unset/empty) +DEST_DIR="${CMAKE_INSTALL_DIR:-}" +if [ -z "${DEST_DIR}" ]; then + DEST_DIR="${TEMP_DIR}/cmake-${VERSION}" +fi + +# 2. Determine archive filename, binary subpath, and binary extension +BIN_EXT="" +case "${OS}" in + Linux) + case "${ARCH}" in + X64) ARCH_NAME="x86_64" ;; + ARM64) ARCH_NAME="aarch64" ;; + *) echo "::error::Unsupported Linux architecture: ${ARCH}"; exit 1 ;; + esac + ARCHIVE="cmake-${VERSION}-linux-${ARCH_NAME}.tar.gz" + BIN_SUBPATH="bin" + ;; + macOS) + ARCHIVE="cmake-${VERSION}-macos-universal.tar.gz" + BIN_SUBPATH="CMake.app/Contents/bin" + ;; + Windows) + case "${ARCH}" in + X64) ARCH_NAME="x86_64" ;; + ARM64) ARCH_NAME="arm64" ;; + *) echo "::error::Unsupported Windows architecture: ${ARCH}"; exit 1 ;; + esac + ARCHIVE="cmake-${VERSION}-windows-${ARCH_NAME}.zip" + BIN_SUBPATH="bin" + BIN_EXT=".exe" + ;; + *) + echo "::error::Unsupported OS: ${OS}" + exit 1 + ;; +esac + +ARCHIVE_URL="https://github.com/Kitware/CMake/releases/download/v${VERSION}/${ARCHIVE}" +ARCHIVE_PATH="${TEMP_DIR}/${ARCHIVE}" + +# 3. Download +echo "==> Downloading ${ARCHIVE_URL}..." +curl -fsSL --retry 3 -o "${ARCHIVE_PATH}" "${ARCHIVE_URL}" + +# 4. Verify SHA-256 directly in one step +echo "==> Verifying SHA-256..." +CHECK_CMD=$(command -v sha256sum || echo "shasum -a 256") +echo "${EXPECTED_SHA} ${ARCHIVE_PATH}" | ${CHECK_CMD} -c - + +# 5. Extract into destination directory +echo "==> Extracting into ${DEST_DIR}..." +mkdir -p "${DEST_DIR}" + +if [[ "${ARCHIVE}" == *.tar.gz ]]; then + tar -xzf "${ARCHIVE_PATH}" -C "${DEST_DIR}" --strip-components=1 +elif [[ "${ARCHIVE}" == *.zip ]]; then + UNZIP_TEMP="${TEMP_DIR}/unzip_tmp" + mkdir -p "${UNZIP_TEMP}" + unzip -q -o "${ARCHIVE_PATH}" -d "${UNZIP_TEMP}" + TOP_DIR=$(find "${UNZIP_TEMP}" -mindepth 1 -maxdepth 1 -type d) + mv "${TOP_DIR}"/* "${DEST_DIR}/" + rm -rf "${UNZIP_TEMP}" +fi +rm -f "${ARCHIVE_PATH}" + +# 6. Set PATH and GITHUB_OUTPUT +CMAKE_BIN_DIR="${DEST_DIR}/${BIN_SUBPATH}" +echo "${CMAKE_BIN_DIR}" >> "${GITHUB_PATH}" + +if [ -n "${GITHUB_OUTPUT:-}" ]; then + { + echo "cmake-dir=${CMAKE_BIN_DIR}" + echo "cmake-path=${CMAKE_BIN_DIR}/cmake${BIN_EXT}" + echo "ctest-path=${CMAKE_BIN_DIR}/ctest${BIN_EXT}" + } >> "${GITHUB_OUTPUT}" +fi + +echo "==> CMake ${VERSION} successfully installed at ${CMAKE_BIN_DIR}" diff --git a/.github/actions/install-cmake/readme.md b/.github/actions/install-cmake/readme.md new file mode 100644 index 00000000..a5cb0a68 --- /dev/null +++ b/.github/actions/install-cmake/readme.md @@ -0,0 +1,47 @@ +# Install CMake + +Install an arbitrary version of CMake. + +Inputs: + - cmake-version: Version of CMake to install (e.g. 3.30.2) + - hash: sha256 of the downloaded artifact (.zip or .tar.gz) + - intall_dir: (optional) location where to install CMake + +Outputs: + - cmake-dir: Directory containing the CMake binaries + - cmake: Path to the installed CMake binary + - ctest: Path to the installed CTest binary + + +## Usage + +```yaml +... + +steps: + + ... + + - name: Install CMake + id: install-cmake + uses: swiftlang/github-workflows/.github/actions/install-cmake@ + with: + cmake-version: 4.0.3 + hash: 585ae9e013107bc8e7c7c9ce872cbdcbdff569e675b07ef57aacfb88c886faac + + - name: Run Build + shell: bash + env: + CMAKE: ${{ steps.install-cmake.outputs.cmake }} + run: | + "$CMAKE" -G Ninja -B build -S -DCMAKE_BUILD_TYPE=Release + + - name: Run Tests + shell: bash + env: + CTEST: ${{ steps.install-cmake.outputs.ctest }} + run: | + "$CTEST" --output-on-failure --test-timeout 150 --test-dir build -j + + ... +```