Files
imccyu 1276a8e13a ci: split pull-request CI into Linux, Windows, and Python workflows (#6898)
* ci: run native Windows PR jobs in a separate workflow

GitHub re-runs failed jobs only after a whole run finishes, so slow Windows jobs blocked re-running failed Linux jobs. CI Windows now owns the native Windows jobs and the Windows x64 Python runtime target, with its own required 'windows checks passed' verdict.

Refs #6893

* ci: run Python PR jobs in a separate workflow

Python rarely fails while the Windows lanes run long, so the Python SDK suite and the Linux/Windows x64 runtime matrix move into CI Python. The three pull-request workflows can now be re-run without waiting for each other, and branch protection gains "python checks passed" beside the existing verdicts.

Refs #6893

* docs: record the three PR verdicts in the failover runbook

* test: pin the shared environment across the PR workflows

* test: read the python SDK lane from CI Python

* test(sdk): parse session JSONL frames in the keyless smoke

Node 24.19 returned only the first frame of a concatenated zstd log, so the single JSON.parse saw just the header; 24.22 returns every frame and the JSONL body broke the parse. Read frames explicitly and select the main session by its header so both versions agree.
2026-10-22 04:09:35 +00:00

88 lines
3.3 KiB
YAML

name: CI Python
# Python pull-request lanes run in their own workflow so a slow runtime build
# does not keep the CI run in progress: GitHub re-runs failed jobs only after
# every job of a run finishes, so each workflow can be re-run without waiting
# for the others. Branch protection requires this workflow's "python checks
# passed" verdict beside CI's "all checks passed" and CI Windows' "windows
# checks passed".
on:
pull_request:
permissions:
contents: read
env:
PRIMARY_NODE_VERSION: '24'
# 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'
# Cancel a superseded pull-request run on a new push, as in ci.yml.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
python-sdk:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
name: python 3.10 / keyless SDK
steps:
- uses: actions/checkout@v7.0.1
- uses: actions/setup-python@v6.3.0
with:
python-version: '3.10'
cache: pip
- name: Install uv
run: python -m pip install uv==0.11.23
- uses: actions/setup-node@v7.0.0
with:
node-version: 24
- name: Test production blame scoring
run: uv run --python 3.10 --with-requirements .github/review-ownership/requirements.txt python -m unittest discover -s .github/review-ownership -p 'test_*.py'
- name: Run complete keyless Python suite
run: uv run --python 3.10 --group test --project python/sdk pytest
# The reusable builder owns each published executable, wheel, clean-install,
# keyless black-box, and trusted real-API path. Linux and Windows x64 block
# pull requests; Linux ARM64 and both macOS architectures run in
# ci-master.yml.
python-runtime:
if: github.event_name == 'pull_request'
needs: python-sdk
name: python runtime / release-shaped matrix
uses: ./.github/workflows/build-exe-for-python-sdk.yml
with:
targets: node24-linux-x64,node24-win-x64
ci: true
secrets:
DEEPSEEK_API_KEY_EXTERNAL: ${{ secrets.DEEPSEEK_API_KEY_EXTERNAL }}
# Stable required check for the Python lanes, with the same semantics as
# ci.yml's "all checks passed": every blocking job in THIS workflow is
# listed in `needs`. The bookkeeping job follows the Linux failover switch
# like the other verdicts.
python-checks-passed:
name: python checks passed
runs-on: >-
${{ vars.DSH_CI_FAILOVER_LINUX == 'blacksmith' && 'blacksmith-4vcpu-ubuntu-2404'
|| vars.DSH_CI_FAILOVER_LINUX == 'selfhosted'
&& github.event.pull_request.user.login != 'dependabot[bot]'
&& fromJSON('["self-hosted", "linux", "x64", "vm-backup"]')
|| 'ubuntu-latest' }}
needs: [python-sdk, python-runtime]
if: ${{ !cancelled() && github.event_name == 'pull_request' }}
steps:
- name: Fail if any needed job did not succeed
if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped')
run: |
echo "::error::Needed job results: ${{ join(needs.*.result, ', ') }}"
exit 1
- name: Python checks passed
run: echo "All needed jobs succeeded (${{ join(needs.*.result, ', ') }})"