Skip to content

CI fix

CI fix #23

Workflow file for this run

name: Build and release
on:
push:
branches:
- main
tags:
- 'v*.*.*'
pull_request:
workflow_dispatch:
inputs:
make_release:
description: "Also publish a GitHub release from this manual run"
type: boolean
default: true
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
# Pinned python-build-standalone release bundled into every published package,
# so releases are self-contained and ABI-stable regardless of the runner's
# ambient Python. See https://github.com/astral-sh/python-build-standalone
PBS_RELEASE: "20260623"
PBS_PYTHON_VERSION: "3.14.6"
jobs:
build:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- name: Linux x86_64
os: ubuntu-22.04
package: linux-x86_64
mads_asset: "*Linux-x86_64.tar.gz"
pbs_triple: x86_64-unknown-linux-gnu
- name: Linux aarch64
os: ubuntu-22.04-arm
package: linux-aarch64
mads_asset: "*Linux-aarch64.tar.gz"
pbs_triple: aarch64-unknown-linux-gnu
- name: macOS arm64
os: macos-15
package: macos-arm64
mads_asset: "*Darwin-universal.sh"
cmake_osx_architectures: "arm64"
pbs_triple: aarch64-apple-darwin
- name: macOS x86_64
os: macos-14
package: macos-x86_64
mads_asset: "*Darwin-universal.sh"
cmake_osx_architectures: "x86_64"
pbs_triple: x86_64-apple-darwin
- name: Windows x86_64
os: windows-2022
package: windows-x86_64
mads_asset: "*Windows-AMD64.exe"
pbs_triple: x86_64-pc-windows-msvc
steps:
- name: Check out sources
uses: actions/checkout@v6
# Used only for the stdlib JSON heredocs in the "Install MADS" steps below.
# The interpreter shipped to users is the bundled one downloaded later.
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.x'
- name: Install Linux build dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y \
clang \
cmake \
extra-cmake-modules \
ninja-build \
python3 python3-dev \
pkg-config
- name: Set up MSVC
if: runner.os == 'Windows'
uses: ilammy/msvc-dev-cmd@v1
with:
arch: amd64
- name: Install MADS on Linux
if: runner.os == 'Linux'
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
mkdir -p "$RUNNER_TEMP/mads-release" "$RUNNER_TEMP/mads"
curl -fsSL \
-H "Authorization: Bearer $GH_TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
-H "User-Agent: mads-chat-ci" \
"https://api.github.com/repos/pbosetti/MADS/releases/latest" \
-o "$RUNNER_TEMP/mads-release/latest.json"
asset_url="$(
python3 - "$RUNNER_TEMP/mads-release/latest.json" "${{ matrix.mads_asset }}" <<'PY'
import fnmatch
import json
import sys
with open(sys.argv[1], encoding="utf-8") as handle:
release = json.load(handle)
for asset in release["assets"]:
if fnmatch.fnmatch(asset["name"], sys.argv[2]):
print(asset["url"])
break
else:
raise SystemExit(f"No MADS release asset matches {sys.argv[2]}")
PY
)"
curl -fL \
-H "Accept: application/octet-stream" \
-H "Authorization: Bearer $GH_TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
-H "User-Agent: mads-chat-ci" \
"$asset_url" \
-o "$RUNNER_TEMP/mads-release/mads.tar.gz"
archive="$RUNNER_TEMP/mads-release/mads.tar.gz"
tar -xzf "$archive" -C "$RUNNER_TEMP/mads"
agent_header="$(find "$RUNNER_TEMP/mads" -type f -path '*/include/agent.hpp' -print -quit)"
if [ -z "$agent_header" ]; then
echo "Could not find MADS headers after extracting $archive" >&2
exit 1
fi
mads_root="${agent_header%/include/agent.hpp}"
test -f "$mads_root/lib/libMadsCore.so"
echo "MADS_ROOT=$mads_root" >> "$GITHUB_ENV"
echo "$mads_root/bin" >> "$GITHUB_PATH"
- name: Install MADS on macOS
if: runner.os == 'macOS'
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
mkdir -p "$RUNNER_TEMP/mads-release" "$RUNNER_TEMP/mads"
curl -fsSL \
-H "Authorization: Bearer $GH_TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
-H "User-Agent: mads-chat-ci" \
"https://api.github.com/repos/pbosetti/MADS/releases/latest" \
-o "$RUNNER_TEMP/mads-release/latest.json"
asset_url="$(
python3 - "$RUNNER_TEMP/mads-release/latest.json" "${{ matrix.mads_asset }}" <<'PY'
import fnmatch
import json
import sys
with open(sys.argv[1], encoding="utf-8") as handle:
release = json.load(handle)
for asset in release["assets"]:
if fnmatch.fnmatch(asset["name"], sys.argv[2]):
print(asset["url"])
break
else:
raise SystemExit(f"No MADS release asset matches {sys.argv[2]}")
PY
)"
installer="$RUNNER_TEMP/mads-release/mads.sh"
curl -fL \
-H "Accept: application/octet-stream" \
-H "Authorization: Bearer $GH_TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
-H "User-Agent: mads-chat-ci" \
"$asset_url" \
-o "$installer"
sh "$installer" --skip-license --prefix="$RUNNER_TEMP/mads" --exclude-subdir
agent_header="$(find "$RUNNER_TEMP/mads" -type f -path '*/include/agent.hpp' -print -quit)"
if [ -z "$agent_header" ]; then
echo "Could not find MADS headers after running $installer" >&2
exit 1
fi
mads_root="${agent_header%/include/agent.hpp}"
test -f "$mads_root/lib/libMadsCore.dylib"
echo "MADS_ROOT=$mads_root" >> "$GITHUB_ENV"
echo "$mads_root/bin" >> "$GITHUB_PATH"
- name: Install MADS on Windows
if: runner.os == 'Windows'
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
New-Item -ItemType Directory -Force "$env:RUNNER_TEMP\mads-release", "$env:RUNNER_TEMP\mads" | Out-Null
$headers = @{
Authorization = "Bearer $env:GH_TOKEN"
Accept = "application/vnd.github+json"
"X-GitHub-Api-Version" = "2022-11-28"
"User-Agent" = "mads-chat-ci"
}
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/pbosetti/MADS/releases/latest" -Headers $headers
$asset = $release.assets |
Where-Object { $_.name -like "${{ matrix.mads_asset }}" } |
Select-Object -First 1
if (-not $asset) {
throw "No MADS release asset matches ${{ matrix.mads_asset }}"
}
$installer = "$env:RUNNER_TEMP\mads-release\mads.exe"
$downloadHeaders = @{
Authorization = "Bearer $env:GH_TOKEN"
Accept = "application/octet-stream"
"X-GitHub-Api-Version" = "2022-11-28"
"User-Agent" = "mads-chat-ci"
}
Invoke-WebRequest -Uri $asset.url -Headers $downloadHeaders -OutFile $installer
$installRoot = "$env:RUNNER_TEMP\mads"
$process = Start-Process `
-FilePath $installer `
-ArgumentList "/VERYSILENT", "/SUPPRESSMSGBOXES", "/NORESTART", "/SP-", "/CURRENTUSER", "/DIR=$installRoot" `
-Wait `
-PassThru
if ($process.ExitCode -ne 0) {
throw "MADS installer failed with exit code $($process.ExitCode)"
}
$agentHeader = Get-ChildItem $installRoot -Recurse -Filter agent.hpp |
Where-Object { $_.FullName -match '\\include\\agent\.hpp$' } |
Select-Object -First 1
if (-not $agentHeader) {
throw "Could not find MADS headers after running $installer"
}
$madsRoot = Split-Path (Split-Path $agentHeader.FullName -Parent) -Parent
$madsImportLibrary = Join-Path $madsRoot "lib\MadsCore.lib"
if (-not (Test-Path $madsImportLibrary)) {
throw "Could not find $madsImportLibrary"
}
"MADS_ROOT=$madsRoot" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
"$madsRoot\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Download bundled CPython
shell: bash
run: |
set -euo pipefail
case "${{ matrix.pbs_triple }}" in
*windows*) py=python.exe ;;
*) py=bin/python3 ;;
esac
url="https://github.com/astral-sh/python-build-standalone/releases/download/${PBS_RELEASE}/cpython-${PBS_PYTHON_VERSION}+${PBS_RELEASE}-${{ matrix.pbs_triple }}-install_only_stripped.tar.gz"
# $RUNNER_TEMP is a native path (e.g. "D:\a\_temp" on Windows). MSYS
# tar/curl in Git Bash need a POSIX path ("/d/a/_temp"), so normalise
# with cygpath where available (Windows); on Linux/macOS it's a no-op.
dest="$RUNNER_TEMP/pbs"
if command -v cygpath >/dev/null 2>&1; then
dest="$(cygpath -u "$RUNNER_TEMP")/pbs"
fi
mkdir -p "$dest"
# Pipe straight into tar (no -f): a "D:" archive path would otherwise
# be parsed as a remote host:path spec. Works the same with bsdtar.
curl -fsSL "$url" | tar -xz -C "$dest"
# Populate the bundled interpreter's own site-packages.
"$dest/python/$py" -m pip install --upgrade pip
"$dest/python/$py" -m pip install numpy
# Export PBS_DIR in a form CMake/pwsh understand: a mixed Windows path
# with forward slashes ("D:/a/_temp/pbs/python") on Windows, the plain
# POSIX path elsewhere.
bundle="$dest/python"
if command -v cygpath >/dev/null 2>&1; then
bundle="$(cygpath -m "$dest/python")"
fi
echo "PBS_DIR=$bundle" >> "$GITHUB_ENV"
- name: Configure
if: runner.os != 'Windows'
env:
CC: clang
CXX: clang++
CMAKE_OSX_ARCHITECTURES: ${{ matrix.cmake_osx_architectures }}
run: |
extra_args=()
if [ -n "${CMAKE_OSX_ARCHITECTURES:-}" ]; then
extra_args+=("-DCMAKE_OSX_ARCHITECTURES=$CMAKE_OSX_ARCHITECTURES")
fi
cmake -S . -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="$PWD/package" \
-DMADS_ROOT="$MADS_ROOT" \
-DPYTHON_AGENT_BUNDLE_PYTHON=ON \
-DPYTHON_BUNDLE_DIR="$PBS_DIR" \
"${extra_args[@]}"
- name: Configure
if: runner.os == 'Windows'
shell: pwsh
run: |
cmake -S . -B build -G Ninja `
-DCMAKE_BUILD_TYPE=Release `
"-DCMAKE_INSTALL_PREFIX=$env:GITHUB_WORKSPACE\package" `
"-DMADS_ROOT=$env:MADS_ROOT" `
-DPYTHON_AGENT_BUNDLE_PYTHON=ON `
"-DPYTHON_BUNDLE_DIR=$env:PBS_DIR"
- name: Build
run: cmake --build build --config Release --parallel
- name: Package
run: cmake --build build --config Release --target package --parallel
- name: Upload package
uses: actions/upload-artifact@v7
with:
name: mads-chat-${{ matrix.package }}
path: build/*.zip
if-no-files-found: error
release:
name: Create GitHub release
if: >-
startsWith(github.ref, 'refs/tags/') ||
(github.event_name == 'workflow_dispatch' && inputs.make_release)
needs: build
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- name: Download packages
uses: actions/download-artifact@v4
with:
pattern: mads-chat-*
path: dist
merge-multiple: true
- name: Create release
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
if [ "$GITHUB_REF_TYPE" = "tag" ]; then
release_tag="$GITHUB_REF_NAME"
release_title="$GITHUB_REF_NAME"
extra_args=(--verify-tag)
else
safe_ref="$(printf '%s' "$GITHUB_REF_NAME" | tr -c '[:alnum:]._-' '-')"
short_sha="${GITHUB_SHA::7}"
release_tag="${safe_ref}-${short_sha}"
release_title="${GITHUB_REF_NAME} ${short_sha}"
extra_args=(--target "$GITHUB_SHA")
fi
gh release create "$release_tag" dist/*.zip \
--repo "$GITHUB_REPOSITORY" \
--title "$release_title" \
--generate-notes \
"${extra_args[@]}"