Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/actions/locate-vcvarsall-and-setup-env/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: 'Locate vcvarsall and Setup Environment'
description: 'Locates vcvarsall.bat, sets up the environment, and handles PATH updates.'
inputs:
architecture:
description: 'Target architecture (x64 or x86)'
required: true
default: 'x64'
outputs:
vcvarsall_path:
description: "Path to vcvarsall.bat"
value: ${{ steps.find-vcvarsall.outputs.vcvarsall_path }}
runs:
using: "composite"
steps:
- name: Find vcvarsall.bat
id: find-vcvarsall
shell: python # Use Python shell
run: |
import os
import subprocess

vswhere_path = os.path.join(os.environ["ProgramFiles(x86)"], "Microsoft Visual Studio", "Installer", "vswhere.exe")

try:
process = subprocess.run([vswhere_path, "-latest", "-property", "installationPath"], capture_output=True, text=True, check=True)
vs_install_path = process.stdout.strip()
vcvarsall_path = os.path.join(vs_install_path, "VC", "Auxiliary", "Build", "vcvarsall.bat")

if os.path.exists(vcvarsall_path):
print(f"vcvarsall found at: {vcvarsall_path}")
# Use GITHUB_OUTPUT environment variable
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
f.write(f"vcvarsall_path={vcvarsall_path}\n")
else:
print(f"vcvarsall.bat not found at expected path: {vcvarsall_path}")
# Use 'exit(1)' for Python to properly signal failure to GitHub Actions
exit(1)


except subprocess.CalledProcessError as e:
print(f"Error running vswhere.exe: {e}")
print(f"vswhere output: {e.stdout}")
print(f"vswhere stderr: {e.stderr}")
exit(1) # Exit with a non-zero code on error
except FileNotFoundError:
print(f"vswhere.exe not found at: {vswhere_path}")
exit(1)


- name: Setup Environment
shell: cmd
run: |
REM Get initial environment variables
set > initial_env.txt

REM Call vcvarsall.bat using the output from the previous step
call "${{ steps.find-vcvarsall.outputs.vcvarsall_path }}" ${{ inputs.architecture }}

REM Get environment variables after calling vcvarsall.bat
set > final_env.txt

REM Call the Python script to update the GitHub Actions environment
python ${{ github.action_path }}\update_environment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@echo off
setlocal

set vswherepath="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
set vcvarsall_arch=%1
if "%vcvarsall_arch%" == "x86" (
set vcvarsall_arch=x86
) else (
set vcvarsall_arch=x64
)

for /f "usebackq delims=" %%i in (`%vswherepath% -latest -property installationPath`) do (
if exist "%%i\VC\Auxiliary\Build\vcvars%vcvarsall_arch%.bat" (
set "vcvarsall=%%i\VC\Auxiliary\Build\vcvars%vcvarsall_arch%.bat"
)
)

echo "Get initial environment variables"
set > initial_env.txt

echo "Call vcvarsall.bat"
call "%vcvarsall%"

echo "Get environment variables after calling vcvarsall.bat"
set > final_env.txt

echo "Call the Python script to update the GitHub Actions environment"
python "%~dp0\update_environment.py"

endlocal
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import os
import re


def read_env_file(filepath):
env_vars = {}
with open(filepath) as f:
for line in f:
match = re.match(r"^(.*?)=(.*)$", line.strip())
if match:
env_vars[match.group(1).upper()] = match.group(2)
return env_vars


initial_env = read_env_file("initial_env.txt")
final_env = read_env_file("final_env.txt")

for key, value in final_env.items():
if key not in initial_env or initial_env[key] != value:
if key.startswith("_"):
continue
if key.upper() == "PATH":
new_paths = value.split(";")
initial_paths = initial_env.get("PATH", "").split(";")
added_paths = [p for p in new_paths if p not in initial_paths and p]

if added_paths:
print("Adding paths")
with open(os.environ["GITHUB_PATH"], "a") as f:
for path in added_paths:
print(f"Adding PATH: {path}")
f.write(path + os.linesep)
else:
# Use GITHUB_ENV
with open(os.environ["GITHUB_ENV"], "a") as f:
print(f"Setting {key}={value}\n")
f.write(f"{key}={value}\n")
122 changes: 119 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# .github/workflows/build.yml
name: Build Actions Check

on:
Expand All @@ -9,8 +8,8 @@ on:
workflow_dispatch:

jobs:
build:
name: Build & Lint JavaScript Actions
linux-ci:
name: Linux CI
runs-on: ubuntu-latest

steps:
Expand All @@ -34,3 +33,120 @@ jobs:

- name: Run Unit Tests with Jest
run: npm test

- name: Test setup-cmake action (Linux)
uses: ./build/setup-cmake
with:
cmake-version: '4.0.0'
cmake-hash: '8482e754bf5bf45349ba2f2184999f81f8754ed3d281e1708f1f9a3b2fcd05c3aa5368e6247930495722ffc5982aadbe489630c5716241ab1702c3cf866483cf'
add-to-path: 'true'
disable-terrapin: 'true'

windows-ci-no-downloader:
name: Windows CI (No Downloader Tool)
runs-on: windows-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Setup Node.js 20
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install Dependencies
# npm ci should work fine on Windows
run: npm ci

- name: Lint Source Code
# Assumes your lint script (ESLint) works cross-platform
run: npm run lint

- name: Build Actions using esbuild
# Assumes your build script (esbuild) works cross-platform
# This builds the JS code (e.g., dist/index.js) needed by the action
run: npm run build

- name: Run Unit Tests with Jest
# Assumes your Jest tests work cross-platform
run: npm test

- name: Test setup-cmake action (Windows)
uses: ./build/setup-cmake
with:
cmake-version: '4.0.0'
cmake-hash: '704fc67b9efa1d65e68a516b439ce3f65f1d6388dc0794002a342d4b59cd3ea63619e674d0343a08c03e9831b053bcbb3ae7635ac42f7796b8d440deeb81b7f6'
add-to-path: 'true'
disable-terrapin: 'true'

- name: Verify CMake Installation (Windows)
run: cmake --version

windows-ci:
name: Windows CI
runs-on: windows-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Setup Node.js 20
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install Dependencies
# npm ci should work fine on Windows
run: npm ci

- name: Lint Source Code
# Assumes your lint script (ESLint) works cross-platform
run: npm run lint

- name: Build Actions using esbuild
# Assumes your build script (esbuild) works cross-platform
# This builds the JS code (e.g., dist/index.js) needed by the action
run: npm run build

- name: Run Unit Tests with Jest
# Assumes your Jest tests work cross-platform
run: npm test

- name: Locate vcvarsall and Setup Env
uses: ./.github/actions/locate-vcvarsall-and-setup-env
with:
architecture: x64

- name: Compile terrapin_tool.exe
shell: cmd # Use cmd shell, often better set up for cl.exe
run: |
echo "Navigating to C++ source directory..."
cd "${{ github.workspace }}\test\cpp"
IF %ERRORLEVEL% NEQ 0 (
echo "Error: Failed to change directory to test\cpp"
exit /B 1
)

echo "Compiling main.cpp..."
cl.exe /nologo /EHsc /std:c++20 /MD /W4 /DUNICODE /D_UNICODE main.cpp /Fe:terrapin_tool.exe winhttp.lib bcrypt.lib shell32.lib
IF %ERRORLEVEL% NEQ 0 (
echo "Error: C++ compilation failed."
exit /B 1
)

echo "Compilation successful. Listing directory contents:"
dir terrapin_tool.exe

- name: Test setup-cmake action (Windows)
uses: ./build/setup-cmake
with:
cmake-version: '4.0.0'
cmake-hash: '704fc67b9efa1d65e68a516b439ce3f65f1d6388dc0794002a342d4b59cd3ea63619e674d0343a08c03e9831b053bcbb3ae7635ac42f7796b8d440deeb81b7f6'
add-to-path: 'true'
terrapin-tool-path: ${{ github.workspace }}/test/cpp/terrapin_tool.exe

- name: Verify CMake Installation (Windows)
run: cmake --version
61 changes: 61 additions & 0 deletions actions/setup-cmake/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# ./actions/setup-cmake/README.md

# Setup CMake Action

This action downloads, verifies (if hash provided), extracts, caches, and optionally adds a specific version of CMake to the system's PATH.

## Features

* Downloads a specific CMake version (e.g., `4.0.0`) or the `"latest"` available release.
* Supports Windows, Linux, and macOS runners.
* Supports common architectures like `x86_64` (x64) and `aarch64` (arm64), using `universal` for modern macOS builds.
* Verifies the download using a provided SHA512 hash **(optional)**.
* Integrates with the GitHub Actions tool cache (`@actions/tool-cache`) for efficiency across workflow runs.
* Optionally uses the `TerrapinRetrievalTool` for downloads (primarily for Windows environments where it's available *and* a hash is provided).
* Optionally adds the CMake `bin` directory to the `PATH` environment variable (default: true).
* Outputs the root installation path and the path to the `bin` directory.

## Inputs

* `cmake-version`: **(Required)** The CMake version to download (e.g., `4.0.0`) or the string `"latest"`.
* `cmake-hash`: (**Optional**) The expected SHA512 hash (hex) of the CMake archive for the target platform/architecture.
* If provided, the download integrity will be verified using this hash. Terrapin (if enabled/available) will also use this hash.
* **If omitted, hash verification is skipped, and the Terrapin tool will not be used.**
* **⚠️ SECURITY WARNING:** Omitting the hash significantly increases the risk of supply chain attacks, as the integrity of the downloaded CMake artifact will not be checked. It is **strongly recommended** to provide a hash whenever possible, especially for production workflows. Pinning to a specific `cmake-version` and providing its corresponding hash is the most secure approach.
* `terrapin-tool-path`: (**Optional**) Path to the `TerrapinRetrievalTool.exe` executable. Defaults to `C:/local/Terrapin/TerrapinRetrievalTool.exe`. Only used on Windows if `disable-terrapin` is `false`, the tool exists, **and `cmake-hash` is provided**.
* `disable-terrapin`: (**Optional**) Boolean. Set to `'true'` to force direct download via `@actions/tool-cache` instead of attempting to use Terrapin. Defaults to `'false'`.
* `add-to-path`: (**Optional**) Boolean. Indicates whether to add the CMake `bin` directory to the `PATH` environment variable. Defaults to `'true'`. Set to `'false'` if you only need to download/cache CMake or want to manage the PATH manually in subsequent steps.

## Outputs

* `cmake-root`: The absolute path to the root directory of the cached CMake installation (e.g., `/_work/_tool/cmake/4.0.0/x64/cmake-4.0.0-linux-x86_64`). Useful for referencing CMake modules or other files within the installation.
* `cmake-path`: The absolute path to the directory containing the CMake executables (e.g., `/_work/_tool/cmake/4.0.0/x64/cmake-4.0.0-linux-x86_64/bin`). This path is added to the system `PATH` environment variable only if the `add-to-path` input is `true` (the default).

## Example Usage

### Recommended: Pin Version with Hash (Adds to PATH)

```yaml
name: Build with Pinned CMake

on: [push]

jobs:
build:
runs-on: ubuntu-latest # Or windows-latest, macos-latest

steps:
- uses: actions/checkout@v4

- name: Setup CMake 4.0.0 (Secure, Adds to PATH)
uses: microsoft/onnxruntime-github-actions/actions/setup-cmake@main
with:
cmake-version: '4.0.0'
cmake-hash: 'example_linux_x64_sha512_hash_here_replace_me'
# add-to-path: 'true' # This is the default

- name: Verify CMake and Build
run: |
cmake --version # Should work as it's in PATH
cmake -B build .
cmake --build build
38 changes: 38 additions & 0 deletions actions/setup-cmake/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: 'Setup CMake'
description: 'Downloads, verifies (if hash provided), extracts, caches, and optionally adds a specific version of CMake to the PATH.' # Updated description

inputs:
cmake-version:
description: 'The CMake version to download (e.g., 3.28.3) or "latest".'
required: true
cmake-hash:
description: >
Optional. The expected SHA512 hash of the CMake archive for the target platform.
If provided, the download integrity will be verified.
If omitted, hash verification is skipped, and Terrapin tool (if available) will not be used.
Omitting the hash increases security risks (supply chain attacks).
required: false
terrapin-tool-path:
description: 'Path to the TerrapinRetrievalTool.exe executable (if used).'
required: false
default: 'C:/local/Terrapin/TerrapinRetrievalTool.exe'
disable-terrapin:
description: 'Set to true to bypass Terrapin and download directly.'
required: false
default: 'false'
add-to-path:
description: 'If true, add the CMake bin directory to the PATH environment variable.'
required: false
default: 'true'

outputs:
cmake-root:
description: 'The root directory path of the cached CMake installation.'
cmake-path:
description: >
The path to the directory containing the CMake executables (e.g., /path/to/cmake/bin).
This path is added to the system PATH only if `add-to-path` is true.

runs:
using: 'node20'
main: 'dist/index.js'
Loading