Skip to content

cli: force UTF-8 stdio on startup + use platform-native fake path in … #423

cli: force UTF-8 stdio on startup + use platform-native fake path in …

cli: force UTF-8 stdio on startup + use platform-native fake path in … #423

Workflow file for this run

name: Run Tests
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
workflow_dispatch:
permissions:
contents: read
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
precheck:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v6
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: '3.12'
- name: Install uv
uses: astral-sh/setup-uv@v8.0.0
with:
enable-cache: true
cache-dependency-glob: "uv.lock"
- name: Setup venv and install pip dependencies
run: |
uv venv --python "3.12" \
&& uv sync --all-extras --all-groups --no-cache \
&& uv pip install pip \
&& echo "/home/linuxbrew/.linuxbrew/bin" >> "$GITHUB_PATH" \
&& if [ -d /nix/var/nix/profiles/default/bin ]; then echo "/nix/var/nix/profiles/default/bin" >> "$GITHUB_PATH"; fi
- name: Run pre-commit checks
run: uv run prek run --all-files
discover-standard-tests:
needs: precheck
runs-on: ubuntu-latest
timeout-minutes: 20
outputs:
test-files: ${{ steps.set-matrix.outputs.test-files }}
steps:
- uses: actions/checkout@v6
- name: Discover standard test files
id: set-matrix
run: |
json_array="["
first=true
for test_file in $(find tests -maxdepth 1 -name 'test_*.py' -type f | sort); do
if [ "$first" = true ]; then
first=false
else
json_array+=","
fi
test_name=$(basename "$test_file" .py | sed 's/^test_//')
json_array+="{\"path\":\"$test_file\",\"name\":\"$test_name\"}"
done
json_array+="]"
echo "test-files=$json_array" >> "$GITHUB_OUTPUT"
echo "$json_array"
build:
name: ${{ matrix.target.os }} py${{ matrix.target.python_version }} ${{ matrix.test.name }}
needs: [precheck, discover-standard-tests]
runs-on: ${{ matrix.target.os }}
timeout-minutes: 20
if: ${{ needs.discover-standard-tests.outputs.test-files != '[]' }}
# Windows support is best-effort: the core library (Binary /
# BinProvider / Scoop / pip / uv / etc.) works on Windows, but a
# handful of tests still carry POSIX-only assertions (hardcoded
# ``/tmp`` paths, ``.CMD`` vs no-suffix shim names, CRX extraction
# that needs a bundled ``unzipper`` npm dep, etc.). Mark the
# Windows leg as ``experimental`` so CI still surfaces its status
# without blocking merge on leftover per-test Windows fixups.
continue-on-error: ${{ matrix.target.experimental || false }}
# Use git-bash on Windows runners so the (mostly POSIX) setup scripts
# below keep working without duplicating them in PowerShell.
defaults:
run:
shell: bash
strategy:
fail-fast: false
max-parallel: 20
matrix:
target:
- os: ubuntu-latest
python_version: '3.11'
- os: ubuntu-latest
python_version: '3.14'
- os: macOS-latest
python_version: '3.13'
- os: windows-latest
python_version: '3.13'
experimental: true
test: ${{ fromJson(needs.discover-standard-tests.outputs.test-files) }}
steps:
- uses: actions/checkout@v6
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.target.python_version }}
- name: Install uv
uses: astral-sh/setup-uv@v8.0.0
with:
enable-cache: true
cache-dependency-glob: "uv.lock"
- name: Setup pnpm
uses: pnpm/action-setup@v5.0.0
with:
version: 10.19.0
- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: '22'
- name: Setup Yarn (classic + Berry)
# Uses ``ln -sf`` / Unix prefix dirs — not applicable to the Windows
# runner and not needed for the Windows test matrix anyway.
if: runner.os != 'Windows'
run: |
npm install -g yarn@1.22.22
if [ "$(uname -s)" = "Darwin" ]; then
YARN_BERRY_PREFIX="/opt/homebrew/opt/yarn-berry"
YARN_BERRY_ALIAS="/opt/homebrew/bin/yarn-berry"
elif [ -d /home/linuxbrew/.linuxbrew/opt ]; then
YARN_BERRY_PREFIX="/home/linuxbrew/.linuxbrew/opt/yarn-berry"
YARN_BERRY_ALIAS="/home/linuxbrew/.linuxbrew/bin/yarn-berry"
else
YARN_BERRY_PREFIX="/usr/local/yarn-berry"
YARN_BERRY_ALIAS="/usr/local/bin/yarn-berry"
fi
YARN_BERRY_ALIAS_DIR="$(dirname "$YARN_BERRY_ALIAS")"
mkdir -p "$YARN_BERRY_ALIAS_DIR"
export PATH="$YARN_BERRY_ALIAS_DIR:$PATH"
echo "$YARN_BERRY_ALIAS_DIR" >> "$GITHUB_PATH"
npm install --prefix "$YARN_BERRY_PREFIX" @yarnpkg/cli-dist@4.13.0
ln -sf "$YARN_BERRY_PREFIX/node_modules/.bin/yarn" "$YARN_BERRY_ALIAS"
"$YARN_BERRY_ALIAS" --version | grep -q '^4\.'
command -v yarn
yarn --version
command -v yarn-berry
yarn-berry --version
yarn --version | grep -q '^1\.' || { echo "ERROR: yarn is not 1.x"; exit 1; }
- name: Setup Yarn (classic + Berry, Windows)
# Windows equivalent of the Unix setup: classic yarn via ``npm -g``,
# then Berry via ``npm --prefix`` + a ``.cmd`` wrapper at a stable
# ``yarn-berry.cmd`` PATH entry (git-bash has no ``ln -sf``).
if: runner.os == 'Windows'
run: |
npm install -g yarn@1.22.22
YARN_BERRY_PREFIX="$USERPROFILE/yarn-berry"
YARN_BERRY_ALIAS_DIR="$USERPROFILE/yarn-berry-bin"
mkdir -p "$YARN_BERRY_ALIAS_DIR"
# GITHUB_PATH is interpreted by runner as \-prefixed lines on Windows.
echo "$YARN_BERRY_ALIAS_DIR" >> "$GITHUB_PATH"
npm install --prefix "$YARN_BERRY_PREFIX" @yarnpkg/cli-dist@4.13.0
# Emit a one-line ``yarn-berry.cmd`` that forwards to npm-installed
# ``yarn.cmd``. Use ``%*`` to pass through all args.
cat > "$YARN_BERRY_ALIAS_DIR/yarn-berry.cmd" <<EOF
@echo off

Check failure on line 184 in .github/workflows/tests.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/tests.yml

Invalid workflow file

You have an error in your yaml syntax on line 184
"$YARN_BERRY_PREFIX\\node_modules\\.bin\\yarn.cmd" %*
EOF
export PATH="$YARN_BERRY_ALIAS_DIR:$PATH"
command -v yarn-berry
yarn-berry --version | grep -q '^4\.'
yarn --version | grep -q '^1\.'
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Setup Deno
uses: denoland/setup-deno@v2
with:
deno-version: v2.x
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version: '1.25'
- name: Install Nix
# Nix has no Windows build.
if: runner.os != 'Windows'
uses: DeterminateSystems/nix-installer-action@v22
- name: Setup venv and install pip dependencies
run: |
export PNPM_HOME="${RUNNER_TEMP}/pnpm"
uv venv --python "${{ matrix.target.python_version }}"
# ``ansible`` has no Windows build, and ``pyinfra`` pulls it in
# transitively, so on Windows we install the base extras only.
if [ "${{ runner.os }}" = "Windows" ]; then
uv sync
else
uv sync --all-extras
fi
uv pip install pip
mkdir -p "$PNPM_HOME"
echo "$PNPM_HOME" >> "$GITHUB_PATH"
if [ "${{ runner.os }}" != "Windows" ]; then
echo "/home/linuxbrew/.linuxbrew/bin" >> "$GITHUB_PATH"
if [ -d /nix/var/nix/profiles/default/bin ]; then echo "/nix/var/nix/profiles/default/bin" >> "$GITHUB_PATH"; fi
fi
- name: Environment diagnostic
run: |
echo "=== OS ==="; uname -a
# Activate the uv-managed venv so ``.venv/bin`` (where
# ``uv sync --all-extras`` installs pyinfra / ansible / pip /
# etc.) is on PATH, matching what ``uv run pytest`` sees. On
# Windows the executable scripts go into ``.venv/Scripts`` instead.
if [ -d .venv/bin ]; then
export PATH="$PWD/.venv/bin:$PATH"
echo "=== venv === $PWD/.venv"
fi
if [ -d .venv/Scripts ]; then
export PATH="$PWD/.venv/Scripts:$PATH"
echo "=== venv === $PWD/.venv (Windows layout)"
fi
echo "=== PATH ==="; echo "$PATH" | tr ':' '\n'
for bin in python pip uv node npm pnpm yarn bun deno go gem cargo rustc brew apt-get dpkg docker nix nix-env ansible ansible-playbook pyinfra scoop sh bash; do
path=$(command -v "$bin" 2>/dev/null || true)
if [ -z "$path" ]; then
echo "=== $bin === (not installed)"
continue
fi
case "$bin" in
# go uses the ``version`` subcommand, not a ``--version`` flag
go) ver=$("$bin" version 2>/dev/null | head -1 || true) ;;
# some tools print corepack/network noise to stderr during the
# first version probe; capture stdout only.
pnpm|yarn|bun|deno|brew)
ver=$("$bin" --version 2>/dev/null | head -1 || true) ;;
*) ver=$("$bin" --version 2>&1 | head -1 || true) ;;
esac
echo "=== $bin === $path :: $ver"
done
- name: Run standard test file
run: |
export PNPM_HOME="${RUNNER_TEMP}/pnpm"
export PATH="$PNPM_HOME:$PATH"
set +e
uv run pytest -vv --tb=long -m "not root_required and not docker_required" "${{ matrix.test.path }}"
status=$?
set -e
if [ "$status" -eq 0 ] || [ "$status" -eq 5 ]; then
exit 0
fi
exit "$status"
discover-live-tests:
needs: precheck
runs-on: ubuntu-latest
timeout-minutes: 20
outputs:
live-tests: ${{ steps.set-matrix.outputs.live-tests }}
steps:
- uses: actions/checkout@v6
- name: Discover live integration test files
id: set-matrix
run: |
json_array="["
first=true
for test_file in $(rg -l "def test_provider_direct_methods_exercise_real_lifecycle" tests/test_*.py | sort); do
test_name=$(basename "$test_file" .py | sed 's/^test_//')
needs_docker=false
if grep -q "@pytest.mark.docker_required" "$test_file"; then
needs_docker=true
fi
os_targets="ubuntu-latest macOS-latest"
if grep -q "@pytest.mark.docker_required" "$test_file" || grep -q "@pytest.mark.root_required" "$test_file" || grep -q 'skipif("darwin"' "$test_file"; then
os_targets="ubuntu-latest"
elif grep -q 'require_tool("brew")' "$test_file" && ! grep -q 'require_tool("apt-get")' "$test_file" && ! grep -q "operations.apt.packages" "$test_file" && ! grep -q "ansible.builtin.apt" "$test_file"; then
os_targets="macOS-latest"
fi
for os_target in $os_targets; do
os_name=$(printf '%s' "$os_target" | tr '[:upper:]' '[:lower:]' | sed 's/-latest//')
entry="{\"name\":\"${test_name}-${os_name}\",\"path\":\"$test_file\",\"os\":\"$os_target\",\"needs_docker\":$needs_docker}"
if [ "$first" = true ]; then first=false; else json_array+=","; fi
json_array+="$entry"
done
done
json_array+="]"
echo "live-tests=$json_array" >> "$GITHUB_OUTPUT"
echo "$json_array"
live-integration:
name: ${{ matrix.live.name }}
needs: [precheck, discover-live-tests]
runs-on: ${{ matrix.live.os }}
timeout-minutes: 20
if: ${{ needs.discover-live-tests.outputs.live-tests != '[]' }}
strategy:
fail-fast: false
max-parallel: 20
matrix:
live: ${{ fromJson(needs.discover-live-tests.outputs.live-tests) }}
steps:
- uses: actions/checkout@v6
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: '3.12'
- name: Install uv
uses: astral-sh/setup-uv@v8.0.0
with:
enable-cache: true
cache-dependency-glob: "uv.lock"
- name: Setup pnpm
uses: pnpm/action-setup@v5.0.0
with:
version: 10.19.0
- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: '22'
- name: Setup Yarn (classic + Berry)
run: |
npm install -g yarn@1.22.22
if [ "$(uname -s)" = "Darwin" ]; then
YARN_BERRY_PREFIX="/opt/homebrew/opt/yarn-berry"
YARN_BERRY_ALIAS="/opt/homebrew/bin/yarn-berry"
elif [ -d /home/linuxbrew/.linuxbrew/opt ]; then
YARN_BERRY_PREFIX="/home/linuxbrew/.linuxbrew/opt/yarn-berry"
YARN_BERRY_ALIAS="/home/linuxbrew/.linuxbrew/bin/yarn-berry"
else
YARN_BERRY_PREFIX="/usr/local/yarn-berry"
YARN_BERRY_ALIAS="/usr/local/bin/yarn-berry"
fi
YARN_BERRY_ALIAS_DIR="$(dirname "$YARN_BERRY_ALIAS")"
mkdir -p "$YARN_BERRY_ALIAS_DIR"
export PATH="$YARN_BERRY_ALIAS_DIR:$PATH"
echo "$YARN_BERRY_ALIAS_DIR" >> "$GITHUB_PATH"
npm install --prefix "$YARN_BERRY_PREFIX" @yarnpkg/cli-dist@4.13.0
ln -sf "$YARN_BERRY_PREFIX/node_modules/.bin/yarn" "$YARN_BERRY_ALIAS"
"$YARN_BERRY_ALIAS" --version | grep -q '^4\.'
command -v yarn
yarn --version
command -v yarn-berry
yarn-berry --version
yarn --version | grep -q '^1\.' || { echo "ERROR: yarn is not 1.x"; exit 1; }
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Setup Deno
uses: denoland/setup-deno@v2
with:
deno-version: v2.x
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version: '1.25'
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@v22
- name: Setup Docker
if: ${{ matrix.live.needs_docker }}
uses: docker/setup-docker-action@v5.0.0
env:
LIMA_START_ARGS: --vm-type=vz
with:
daemon-config: |
{
"debug": true
}
- name: Setup venv and install pip dependencies
run: |
export PNPM_HOME="${RUNNER_TEMP}/pnpm"
uv venv --python "3.12"
uv sync --all-extras
uv pip install pip
mkdir -p "$PNPM_HOME"
echo "$PNPM_HOME" >> "$GITHUB_PATH"
echo "/home/linuxbrew/.linuxbrew/bin" >> "$GITHUB_PATH"
echo "/nix/var/nix/profiles/default/bin" >> "$GITHUB_PATH"
- name: Inspect Docker
if: ${{ matrix.live.needs_docker }}
run: |
docker version \
&& docker info
- name: Run live package lifecycle test
run: |
export PNPM_HOME="${RUNNER_TEMP}/pnpm"
export PATH="$PNPM_HOME:$PATH:/nix/var/nix/profiles/default/bin:$PATH"
uv run pytest "${{ matrix.live.path }}" -k test_provider_direct_methods_exercise_real_lifecycle