pnpm run build ran every step in one serial chain, including the two noEmit aggregate programs (tests, scripts, benchmarks, website) that no artifact step consumes, so the Host aggregate check alone delayed tsdown by about 66 s. - build:src (scripts/build.ts --scope src) builds every artifact in the existing order and writes the client build record; it replaces the removed --artifacts-only flag and the libraries CLI mode. - build:test (--scope test) type-checks only the Host and Client aggregate programs with tsc -p, concurrently, without compiling references or checking prerequisites. - build runs both as one dependency graph through run-gates' new runAggregate: each aggregate check starts once its face's packages are compiled, and Client compilation stays after the Host bundle that writes the Typert /remote declarations. DSH_GATE_CONCURRENCY=1 serializes it; DSH_GATE_FAIL_FAST=1 stops the remaining steps at the first failure. Passing steps print one PASS line (DSH_GATE_VERBOSE=1 shows their output). - PR artifact builds (e2e, release, preview, Node 22 compatibility) and the Python builder (--build-src) use build:src; dev:web and dev:desktop use build:src. test:*, bench, typecheck and the required consumer/Windows lanes keep the complete build. - lint, lint:fix, doc-typecheck and the Typert contracts gate prepare with host-libraries (Host package compilation + Host bundle) instead of build:lib:host; their own checks never read the aggregate root or the Desktop bundle. Parallel and serial build produce byte-identical lib/, Web dist and client build record; a test-only type error fails build and build:test while build:src passes. Refs #5852
513 lines
22 KiB
YAML
513 lines
22 KiB
YAML
name: Build single-exe
|
|
|
|
# Native builds for the release targets; see
|
|
# .agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md.
|
|
# A full target run retains one SDK wheel and five runtime wheels; subset
|
|
# dispatch retains the SDK wheel and selected runtime wheels. Bare executables
|
|
# and source closures are test inputs. Run manually or call it from the Python
|
|
# release workflow. There is no `pull_request` trigger: a label trigger would
|
|
# list gray skipped checks on every unrelated PR label event. Checkout uses the
|
|
# triggering ref, so dispatch needs no separate ref input.
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
targets:
|
|
description: Comma-separated pkg targets to build; empty builds all five.
|
|
type: string
|
|
required: false
|
|
default: ''
|
|
release:
|
|
description: Run as the native builder for the Python release workflow.
|
|
type: boolean
|
|
required: false
|
|
default: false
|
|
ci:
|
|
description: Run Python runtime CI validation for the selected targets.
|
|
type: boolean
|
|
required: false
|
|
default: false
|
|
secrets:
|
|
DEEPSEEK_API_KEY_EXTERNAL:
|
|
description: Real DeepSeek API key for trusted installed-wheel pull-request tests.
|
|
required: false
|
|
workflow_dispatch:
|
|
inputs:
|
|
targets:
|
|
description: >-
|
|
Comma-separated pkg targets to build. Any subset of:
|
|
node24-linux-x64, node24-linux-arm64, node24-macos-arm64,
|
|
node24-macos-x64, node24-win-x64. Empty builds all five.
|
|
type: string
|
|
required: false
|
|
default: ''
|
|
|
|
concurrency:
|
|
# Keep the called workflow distinct from its caller's concurrency group;
|
|
# github.workflow identifies the caller inside a reusable workflow and keeps
|
|
# an ordinary CI run from cancelling a full release validation on the same ref.
|
|
group: build-single-exe-${{ github.workflow }}-${{ github.ref }}
|
|
# Release-owned builds are part of an intentional publication transaction.
|
|
cancel-in-progress: ${{ !inputs.release }}
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
env:
|
|
# CI runs must never report to the production telemetry endpoint baked
|
|
# into apps/cli/cordis.yml (AppCLIEntry disables the row when set).
|
|
DSH_TELEMETRY_DISABLED: '1'
|
|
|
|
jobs:
|
|
# Job-level conditions cannot inspect `matrix`, so validate target names and
|
|
# construct the matrix before the dependent jobs.
|
|
plan:
|
|
name: plan targets
|
|
if: inputs.ci || inputs.release || github.event_name == 'workflow_dispatch'
|
|
runs-on: >-
|
|
${{ inputs.ci && !inputs.release && vars.DSH_CI_FAILOVER_LINUX == 'blacksmith'
|
|
&& 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }}
|
|
timeout-minutes: 5
|
|
outputs:
|
|
matrix: ${{ steps.plan.outputs.matrix }}
|
|
version: ${{ steps.version.outputs.version }}
|
|
repository-version: ${{ steps.version.outputs.repository-version }}
|
|
steps:
|
|
- uses: actions/[email protected]
|
|
|
|
- name: Resolve repository version
|
|
id: version
|
|
run: |
|
|
set -euo pipefail
|
|
python3 - <<'PY' >> "$GITHUB_OUTPUT"
|
|
import runpy
|
|
|
|
release = runpy.run_path("scripts/build-python-release.py")
|
|
repository_version = release["repository_version"]()
|
|
wheel_version = release["pep440_version"](repository_version)
|
|
print(f"repository-version={repository_version}")
|
|
print(f"version={wheel_version}")
|
|
PY
|
|
|
|
- name: Compute matrix from targets input
|
|
id: plan
|
|
env:
|
|
# Blank dispatch inputs build all targets.
|
|
TARGETS: ${{ inputs.targets || 'node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-macos-x64,node24-win-x64' }}
|
|
run: |
|
|
set -euo pipefail
|
|
matrix='[]'
|
|
IFS=',' read -r -a targets <<< "$TARGETS"
|
|
for raw in "${targets[@]}"; do
|
|
t="$(echo "$raw" | xargs)" # trim surrounding whitespace
|
|
[ -z "$t" ] && continue
|
|
# Native-only: hosted arm64 Linux uses ubuntu-24.04-arm, while
|
|
# macos-latest is Apple Silicon; macos-15-intel is native x64.
|
|
case "$t" in
|
|
node24-linux-x64) runner=ubuntu-latest ;;
|
|
node24-linux-arm64) runner=ubuntu-24.04-arm ;;
|
|
node24-macos-arm64) runner=macos-latest ;;
|
|
node24-macos-x64) runner=macos-15-intel ;;
|
|
node24-win-x64) runner=windows-2025 ;;
|
|
*)
|
|
echo "::error::Unknown target '$t'. Supported: node24-linux-x64, node24-linux-arm64, node24-macos-arm64, node24-macos-x64, node24-win-x64."
|
|
exit 1
|
|
;;
|
|
esac
|
|
matrix="$(jq -c --arg target "$t" --arg runner "$runner" '. + [{target: $target, runner: $runner}]' <<< "$matrix")"
|
|
done
|
|
if [ "$matrix" = '[]' ]; then
|
|
echo "::error::The targets input selected nothing to build."
|
|
exit 1
|
|
fi
|
|
echo "Matrix: $matrix"
|
|
echo "matrix=$matrix" >> "$GITHUB_OUTPUT"
|
|
|
|
sdk-wheel:
|
|
needs: plan
|
|
name: deepseek_harness_sdk-${{ needs.plan.outputs.version }}-py3-none-any.whl
|
|
runs-on: >-
|
|
${{ inputs.ci && !inputs.release && vars.DSH_CI_FAILOVER_LINUX == 'blacksmith'
|
|
&& 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }}
|
|
timeout-minutes: 5
|
|
steps:
|
|
- uses: actions/[email protected]
|
|
|
|
- uses: actions/[email protected]
|
|
with:
|
|
python-version: '3.10'
|
|
|
|
- name: Install Python build tooling
|
|
run: python -m pip install uv==0.11.23
|
|
|
|
- name: Build release-shaped SDK wheel
|
|
run: >-
|
|
python scripts/build-python-release.py
|
|
--package sdk
|
|
--output-dir dist-python
|
|
|
|
- uses: actions/[email protected]
|
|
with:
|
|
name: deepseek_harness_sdk-${{ needs.plan.outputs.version }}-py3-none-any.whl
|
|
path: dist-python/deepseek_harness_sdk-${{ needs.plan.outputs.version }}-py3-none-any.whl
|
|
if-no-files-found: error
|
|
retention-days: 7
|
|
|
|
# Blacksmith x64 CI builds use 2 vCPU for compilation, bundling, and wheel smokes.
|
|
# Release macOS builds use larger GitHub runners; ordinary CI and direct
|
|
# builder dispatches retain the standard native target matrix.
|
|
build:
|
|
needs: [plan, sdk-wheel]
|
|
name: ${{ matrix.target }}
|
|
runs-on: >-
|
|
${{ inputs.release && matrix.target == 'node24-macos-x64' && 'macos-15-large'
|
|
|| inputs.release && matrix.target == 'node24-macos-arm64' && 'macos-15-xlarge'
|
|
|| inputs.ci && !inputs.release && matrix.target == 'node24-linux-x64'
|
|
&& vars.DSH_CI_FAILOVER_LINUX == 'blacksmith' && 'blacksmith-2vcpu-ubuntu-2404'
|
|
|| inputs.ci && !inputs.release && matrix.target == 'node24-win-x64'
|
|
&& vars.DSH_CI_FAILOVER_WINDOWS == 'blacksmith' && 'blacksmith-2vcpu-windows-2025'
|
|
|| matrix.runner }}
|
|
timeout-minutes: 45
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include: ${{ fromJSON(needs.plan.outputs.matrix) }}
|
|
steps:
|
|
- uses: actions/[email protected]
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- uses: pnpm/[email protected]
|
|
with:
|
|
dest: ${{ runner.temp }}/setup-pnpm-js-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}
|
|
|
|
- name: Enable Windows Developer Mode (symlink support)
|
|
if: runner.os == 'Windows'
|
|
shell: pwsh
|
|
run: >-
|
|
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock"
|
|
/t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"
|
|
|
|
# setup-node's built-in pnpm store cache keys on platform AND arch, so
|
|
# the Linux architectures sharing runner.os stay on separate caches.
|
|
- uses: actions/[email protected]
|
|
with:
|
|
node-version: 24
|
|
cache: pnpm
|
|
|
|
- uses: actions/[email protected]
|
|
with:
|
|
python-version: '3.10'
|
|
|
|
- name: Install Python build tooling
|
|
run: python -m pip install uv==0.11.23
|
|
|
|
# Cache pkg's target Node binary; lockfile changes roll the
|
|
# exact key while the restore prefix can seed its replacement.
|
|
- uses: actions/[email protected]
|
|
with:
|
|
path: ~/.pkg-cache
|
|
key: pkg-fetch-${{ matrix.target }}-${{ hashFiles('pnpm-lock.yaml') }}
|
|
restore-keys: |
|
|
pkg-fetch-${{ matrix.target }}-
|
|
|
|
- name: Install (immutable)
|
|
# node-gyp fetches Node headers from nodejs.org during install; that
|
|
# endpoint stalls intermittently (observed 10 s connect timeouts).
|
|
# Bounded retries mirror the wine lane's transfer policy without a
|
|
# mirror, since these installs also resolve native addons.
|
|
shell: bash
|
|
run: |
|
|
for attempt in 1 2 3; do
|
|
if pnpm install --frozen-lockfile; then exit 0; fi
|
|
[ "$attempt" -lt 3 ] && sleep 10
|
|
done
|
|
exit 1
|
|
|
|
- name: Rebuild Linux node-pty against manylinux 2.28
|
|
if: runner.os == 'Linux'
|
|
env:
|
|
RUNNER_ARCH: ${{ runner.arch }}
|
|
run: |
|
|
set -euo pipefail
|
|
case "$RUNNER_ARCH" in
|
|
X64) image=quay.io/pypa/manylinux_2_28_x86_64 ;;
|
|
ARM64) image=quay.io/pypa/manylinux_2_28_aarch64 ;;
|
|
*) echo "::error::Unsupported Linux runner architecture $RUNNER_ARCH"; exit 1 ;;
|
|
esac
|
|
addon_dir="$(realpath packages/subprocess/subprocess-local/node_modules/node-pty)"
|
|
pnpm_setup_root="$(realpath "$(dirname "$(dirname "$PNPM_HOME")")")"
|
|
# Verification installs would install node-gyp inside the package and package it into the exe.
|
|
(cd "$addon_dir" && npm_config_build_from_source=true pnpm --config.verifyDepsBeforeRun=false run install)
|
|
addon="$addon_dir/build/Release/pty.node"
|
|
[ -f "$addon_dir/build/Makefile" ] || {
|
|
echo "::error::node-pty install did not generate $addon_dir/build/Makefile"
|
|
exit 1
|
|
}
|
|
docker run --rm \
|
|
--user "$(id -u):$(id -g)" \
|
|
-v "$PWD:$PWD" \
|
|
-v "$HOME/.cache/node-gyp:$HOME/.cache/node-gyp:ro" \
|
|
-v "$pnpm_setup_root:$pnpm_setup_root:ro" \
|
|
-w "$addon_dir" \
|
|
"$image" \
|
|
bash -euxo pipefail -c \
|
|
'rm -rf build/Release && make -C build -j2 BUILDTYPE=Release'
|
|
[ -f "$addon" ] || { echo "::error::$addon missing after manylinux rebuild"; exit 1; }
|
|
readelf --version-info "$addon" | tee node-pty-glibc-versions.txt
|
|
maximum="$(sed -n 's/.*Name: GLIBC_\([0-9.]*\).*/\1/p' node-pty-glibc-versions.txt | sort -V | tail -1)"
|
|
[ -n "$maximum" ] || { echo "::error::No GLIBC requirements found in $addon"; exit 1; }
|
|
dpkg --compare-versions "$maximum" le 2.28 || {
|
|
echo "::error::node-pty addon requires GLIBC_$maximum but wheel claims manylinux_2_28"
|
|
exit 1
|
|
}
|
|
|
|
- name: Build single-exe
|
|
env:
|
|
DSH_BUILD_CLIENT_PROFILE: official
|
|
run: >-
|
|
pnpm exec tsx scripts/build-exe-for-python-sdk.ts --targets=${{ matrix.target }}
|
|
${{ inputs.ci && github.event_name == 'pull_request' && '--build-src' || '' }}
|
|
|
|
- name: Resolve platform outputs (POSIX)
|
|
id: runtime-posix
|
|
if: runner.os != 'Windows'
|
|
env:
|
|
TARGET: ${{ matrix.target }}
|
|
VERSION: ${{ needs.plan.outputs.version }}
|
|
run: |
|
|
set -euo pipefail
|
|
platform="${TARGET#node24-}"
|
|
exe="$PWD/dist-exe/deepseek-harness-sdk-runtime-$platform"
|
|
case "$platform" in
|
|
linux-x64) wheel=deepseek_harness_runtime_bin-$VERSION-py3-none-manylinux_2_28_x86_64.whl ;;
|
|
linux-arm64) wheel=deepseek_harness_runtime_bin-$VERSION-py3-none-manylinux_2_28_aarch64.whl ;;
|
|
macos-arm64) wheel=deepseek_harness_runtime_bin-$VERSION-py3-none-macosx_14_0_arm64.whl ;;
|
|
macos-x64) wheel=deepseek_harness_runtime_bin-$VERSION-py3-none-macosx_14_0_x86_64.whl ;;
|
|
*) echo "::error::Unsupported runtime platform $platform"; exit 1 ;;
|
|
esac
|
|
[ -x "$exe" ] || { echo "::error::$exe missing or not executable"; exit 1; }
|
|
echo "platform=$platform" >> "$GITHUB_OUTPUT"
|
|
echo "exe=$exe" >> "$GITHUB_OUTPUT"
|
|
echo "wheel=$wheel" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Resolve platform outputs (Windows)
|
|
id: runtime-windows
|
|
if: runner.os == 'Windows'
|
|
shell: pwsh
|
|
env:
|
|
TARGET: ${{ matrix.target }}
|
|
VERSION: ${{ needs.plan.outputs.version }}
|
|
run: |
|
|
if ($env:TARGET -ne 'node24-win-x64') { throw "Unsupported runtime target $env:TARGET" }
|
|
$platform = 'win-x64'
|
|
$exe = Join-Path $PWD 'dist-exe\deepseek-harness-sdk-runtime-win-x64.exe'
|
|
$wheel = "deepseek_harness_runtime_bin-$env:VERSION-py3-none-win_amd64.whl"
|
|
if (-not (Test-Path -LiteralPath $exe -PathType Leaf)) { throw "Runtime executable is missing at $exe" }
|
|
"platform=$platform" >> $env:GITHUB_OUTPUT
|
|
"exe=$exe" >> $env:GITHUB_OUTPUT
|
|
"wheel=$wheel" >> $env:GITHUB_OUTPUT
|
|
|
|
- name: Build release-shaped runtime wheel
|
|
run: >-
|
|
python scripts/build-python-release.py
|
|
--package runtime
|
|
--platform "${{ steps.runtime-posix.outputs.platform || steps.runtime-windows.outputs.platform }}"
|
|
--runtime-exe "${{ steps.runtime-posix.outputs.exe || steps.runtime-windows.outputs.exe }}"
|
|
--output-dir dist-python
|
|
|
|
- uses: actions/[email protected]
|
|
with:
|
|
name: deepseek_harness_sdk-${{ needs.plan.outputs.version }}-py3-none-any.whl
|
|
path: dist-python
|
|
|
|
- name: Install local SDK and runtime wheels into a clean venv (POSIX)
|
|
id: smoke-venv-posix
|
|
if: runner.os != 'Windows'
|
|
env:
|
|
RUNTIME_WHEEL: ${{ steps.runtime-posix.outputs.wheel }}
|
|
SDK_WHEEL: deepseek_harness_sdk-${{ needs.plan.outputs.version }}-py3-none-any.whl
|
|
run: |
|
|
set -euo pipefail
|
|
venv="$(python -c 'import tempfile; print(tempfile.mkdtemp(prefix="dsh-sdk-smoke-"))')"
|
|
python -m venv "$venv"
|
|
smoke_python="$venv/bin/python"
|
|
"$smoke_python" -m pip install \
|
|
"dist-python/$SDK_WHEEL" \
|
|
"dist-python/$RUNTIME_WHEEL"
|
|
echo "python=$smoke_python" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Install local SDK and runtime wheels into a clean venv (Windows)
|
|
id: smoke-venv-windows
|
|
if: runner.os == 'Windows'
|
|
shell: pwsh
|
|
env:
|
|
RUNTIME_WHEEL: ${{ steps.runtime-windows.outputs.wheel }}
|
|
SDK_WHEEL: deepseek_harness_sdk-${{ needs.plan.outputs.version }}-py3-none-any.whl
|
|
run: |
|
|
$venv = (& python -c 'import tempfile; print(tempfile.mkdtemp(prefix="dsh-sdk-smoke-"))').Trim()
|
|
python -m venv $venv
|
|
$smokePython = Join-Path $venv 'Scripts\python.exe'
|
|
& $smokePython -m pip install "dist-python/$env:SDK_WHEEL" "dist-python/$env:RUNTIME_WHEEL"
|
|
if ($LASTEXITCODE -ne 0) { throw "Wheel installation failed with exit code $LASTEXITCODE" }
|
|
"python=$smokePython" >> $env:GITHUB_OUTPUT
|
|
|
|
- name: Run installed-wheel keyless black-box tests (POSIX)
|
|
if: runner.os != 'Windows'
|
|
run: |
|
|
set -euo pipefail
|
|
blackbox_root="$(python -c 'import tempfile; print(tempfile.mkdtemp(prefix="dsh-sdk-blackbox-"))')"
|
|
cd "$blackbox_root"
|
|
env -u PYTHONPATH -u DSH_RUNTIME_MODE \
|
|
"${{ steps.smoke-venv-posix.outputs.python }}" \
|
|
"$GITHUB_WORKSPACE/scripts/smoke-python-runtime.py" \
|
|
--scenario all \
|
|
--installed-wheel
|
|
|
|
- name: Run installed-wheel keyless black-box tests (Windows)
|
|
if: runner.os == 'Windows'
|
|
shell: pwsh
|
|
run: |
|
|
$blackboxRoot = (& python -c 'import tempfile; print(tempfile.mkdtemp(prefix="dsh-sdk-blackbox-"))').Trim()
|
|
Remove-Item Env:PYTHONPATH -ErrorAction SilentlyContinue
|
|
Remove-Item Env:DSH_RUNTIME_MODE -ErrorAction SilentlyContinue
|
|
Push-Location $blackboxRoot
|
|
try {
|
|
& "${{ steps.smoke-venv-windows.outputs.python }}" "$env:GITHUB_WORKSPACE\scripts\smoke-python-runtime.py" --scenario all --installed-wheel
|
|
if ($LASTEXITCODE -ne 0) { throw "Installed-wheel black-box failed with exit code $LASTEXITCODE" }
|
|
} finally {
|
|
Pop-Location
|
|
}
|
|
|
|
- name: Preflight installed-wheel real API test (POSIX)
|
|
if: >-
|
|
inputs.ci
|
|
&& runner.os != 'Windows'
|
|
&& (github.event_name != 'pull_request'
|
|
|| !(github.event.pull_request.head.repo.fork
|
|
|| github.event.pull_request.user.login == 'dependabot[bot]'))
|
|
env:
|
|
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY_EXTERNAL }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [ -z "${DEEPSEEK_API_KEY:-}" ]; then
|
|
echo "::error::DEEPSEEK_API_KEY_EXTERNAL is empty; the installed-wheel real API test cannot self-skip."
|
|
exit 1
|
|
fi
|
|
|
|
- name: Preflight installed-wheel real API test (Windows)
|
|
if: >-
|
|
inputs.ci
|
|
&& runner.os == 'Windows'
|
|
&& (github.event_name != 'pull_request'
|
|
|| !(github.event.pull_request.head.repo.fork
|
|
|| github.event.pull_request.user.login == 'dependabot[bot]'))
|
|
shell: pwsh
|
|
env:
|
|
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY_EXTERNAL }}
|
|
run: |
|
|
if ([string]::IsNullOrWhiteSpace($env:DEEPSEEK_API_KEY)) {
|
|
throw 'DEEPSEEK_API_KEY_EXTERNAL is empty; the installed-wheel real API test cannot self-skip.'
|
|
}
|
|
|
|
- name: Run installed-wheel real API black-box test (POSIX)
|
|
if: >-
|
|
inputs.ci
|
|
&& runner.os != 'Windows'
|
|
&& (github.event_name != 'pull_request'
|
|
|| !(github.event.pull_request.head.repo.fork
|
|
|| github.event.pull_request.user.login == 'dependabot[bot]'))
|
|
env:
|
|
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY_EXTERNAL }}
|
|
DEEPSEEK_BASE_URL: https://api.deepseek.com/anthropic
|
|
run: |
|
|
set -euo pipefail
|
|
blackbox_root="$(python -c 'import tempfile; print(tempfile.mkdtemp(prefix="dsh-sdk-blackbox-live-"))')"
|
|
cd "$blackbox_root"
|
|
env -u PYTHONPATH -u DSH_RUNTIME_MODE \
|
|
"${{ steps.smoke-venv-posix.outputs.python }}" \
|
|
"$GITHUB_WORKSPACE/scripts/smoke-python-runtime.py" \
|
|
--scenario sdk-live \
|
|
--installed-wheel
|
|
|
|
- name: Run installed-wheel real API black-box test (Windows)
|
|
if: >-
|
|
inputs.ci
|
|
&& runner.os == 'Windows'
|
|
&& (github.event_name != 'pull_request'
|
|
|| !(github.event.pull_request.head.repo.fork
|
|
|| github.event.pull_request.user.login == 'dependabot[bot]'))
|
|
shell: pwsh
|
|
env:
|
|
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY_EXTERNAL }}
|
|
DEEPSEEK_BASE_URL: https://api.deepseek.com/anthropic
|
|
run: |
|
|
$blackboxRoot = (& python -c 'import tempfile; print(tempfile.mkdtemp(prefix="dsh-sdk-blackbox-live-"))').Trim()
|
|
Remove-Item Env:PYTHONPATH -ErrorAction SilentlyContinue
|
|
Remove-Item Env:DSH_RUNTIME_MODE -ErrorAction SilentlyContinue
|
|
Push-Location $blackboxRoot
|
|
try {
|
|
& "${{ steps.smoke-venv-windows.outputs.python }}" "$env:GITHUB_WORKSPACE\scripts\smoke-python-runtime.py" --scenario sdk-live --installed-wheel
|
|
if ($LASTEXITCODE -ne 0) { throw "Installed-wheel live API smoke failed with exit code $LASTEXITCODE" }
|
|
} finally {
|
|
Pop-Location
|
|
}
|
|
|
|
- name: Check Linux GLIBC requirements
|
|
if: runner.os == 'Linux'
|
|
run: |
|
|
set -euo pipefail
|
|
readelf --version-info "${{ steps.runtime-posix.outputs.exe }}" | tee glibc-versions.txt
|
|
maximum="$(sed -n 's/.*Name: GLIBC_\([0-9.]*\).*/\1/p' glibc-versions.txt | sort -V | tail -1)"
|
|
[ -n "$maximum" ] || { echo "::error::No GLIBC requirements found"; exit 1; }
|
|
dpkg --compare-versions "$maximum" le 2.28 || {
|
|
echo "::error::Executable requires GLIBC_$maximum but wheel claims manylinux_2_28"
|
|
exit 1
|
|
}
|
|
|
|
- name: Check macOS payload architecture and deployment target
|
|
if: runner.os == 'macOS'
|
|
env:
|
|
EXE: ${{ steps.runtime-posix.outputs.exe }}
|
|
PLATFORM: ${{ steps.runtime-posix.outputs.platform }}
|
|
run: |
|
|
set -euo pipefail
|
|
case "$PLATFORM" in
|
|
macos-arm64) macho_arch=arm64 ;;
|
|
macos-x64) macho_arch=x86_64 ;;
|
|
*) echo "::error::Unsupported macOS platform $PLATFORM"; exit 1 ;;
|
|
esac
|
|
for payload in "$EXE" "$EXE-rg" "$EXE-spawn-helper"; do
|
|
lipo "$payload" -verify_arch "$macho_arch"
|
|
done
|
|
python3 scripts/check-macos-deployment-target.py \
|
|
--platform "$PLATFORM" "$EXE" "$EXE-rg" "$EXE-spawn-helper"
|
|
|
|
- name: Run wheel in a manylinux 2.28 container
|
|
if: runner.os == 'Linux'
|
|
env:
|
|
RUNNER_ARCH: ${{ runner.arch }}
|
|
RUNTIME_WHEEL: ${{ steps.runtime-posix.outputs.wheel }}
|
|
SDK_WHEEL: deepseek_harness_sdk-${{ needs.plan.outputs.version }}-py3-none-any.whl
|
|
run: |
|
|
set -euo pipefail
|
|
case "$RUNNER_ARCH" in
|
|
X64) image=quay.io/pypa/manylinux_2_28_x86_64 ;;
|
|
ARM64) image=quay.io/pypa/manylinux_2_28_aarch64 ;;
|
|
*) echo "::error::Unsupported Linux runner architecture $RUNNER_ARCH"; exit 1 ;;
|
|
esac
|
|
docker run --rm -e RUNTIME_WHEEL -e SDK_WHEEL -e DSH_TELEMETRY_DISABLED -v "$PWD:/work" -w /work "$image" bash -euxo pipefail -c '
|
|
/opt/python/cp310-cp310/bin/python -m venv /tmp/dsh-sdk
|
|
/tmp/dsh-sdk/bin/python -m pip install "/work/dist-python/$SDK_WHEEL" "/work/dist-python/$RUNTIME_WHEEL"
|
|
mkdir -p /tmp/dsh-sdk-manylinux-smoke
|
|
cd /tmp/dsh-sdk-manylinux-smoke
|
|
env -u PYTHONPATH -u DSH_RUNTIME_MODE /tmp/dsh-sdk/bin/python /work/scripts/smoke-python-runtime.py --scenario sdk-default --installed-wheel
|
|
env -u PYTHONPATH -u DSH_RUNTIME_MODE /tmp/dsh-sdk/bin/python /work/scripts/smoke-python-runtime.py --scenario sdk-mcp --installed-wheel
|
|
'
|
|
|
|
- uses: actions/[email protected]
|
|
with:
|
|
name: ${{ steps.runtime-posix.outputs.wheel || steps.runtime-windows.outputs.wheel }}
|
|
path: dist-python/${{ steps.runtime-posix.outputs.wheel || steps.runtime-windows.outputs.wheel }}
|
|
if-no-files-found: error
|
|
retention-days: 7
|