|
name: CI |
|
|
|
on: |
|
push: |
|
branches: [ '**' ] |
|
pull_request: |
|
branches: [ '**' ] |
|
|
|
jobs: |
|
build: |
|
runs-on: ubuntu-latest |
|
strategy: |
|
matrix: |
|
python-version: ['3.13', '3.14'] |
|
|
|
steps: |
|
- name: Checkout |
|
uses: actions/checkout@v4 |
|
|
|
- name: Set up uv (Python ${{ matrix.python-version }}) |
|
uses: astral-sh/setup-uv@v10.0.1 |
|
with: |
|
enable-cache: true |
|
python-version: ${{ matrix.python-version }} |
|
|
|
- name: Install dependencies |
|
run: uv sync --locked --group dev |
|
|
|
- name: Lint (Ruff) |
|
run: uv run ruff check . |
|
|
|
- name: Format check (Black) |
|
run: uv run black --check src examples tests |
|
|
|
- name: Type check (MyPy) |
|
run: uv run mypy |
|
|
|
# The Inbox and e2e apps each own a top-level ``app`` package, so |
|
# they're checked from their own directories rather than whole-tree. |
|
- name: Type check the Inbox example (strict) |
|
working-directory: examples/inbox |
|
env: |
|
MYPYPATH: ../inbox-extension/src |
|
run: uv run --project ../.. mypy --strict app |
|
|
|
- name: Type check the e2e suite (strict) |
|
working-directory: examples/e2e-suite |
|
run: uv run --project ../.. mypy --strict app |
|
|
|
- name: Rules of hooks (pn lint) |
|
run: uv run pn lint src/pythonnative examples |
|
|
|
# Produces the sdist and wheel through the setuptools backend. Note |
|
# this builds but does not install them, so the previous non-editable |
|
# install smoke test is not replaced. |
|
- name: Build package |
|
run: uv build |
|
|
|
- name: Run tests |
|
run: uv run pytest -q |
|
|
|
browser: |
|
runs-on: ubuntu-latest |
|
steps: |
|
- uses: actions/checkout@v4 |
|
- uses: astral-sh/setup-uv@v10.0.1 |
|
with: |
|
python-version: '3.13' |
|
- run: uv sync --locked --group dev |
|
- run: uv run python scripts/run-browser-tests.py |
|
|
|
# The Swift half of the rendering core: decoders, component managers, |
|
# gestures, and module promises run under XCTest on a simulator. |
|
native-ios: |
|
runs-on: macos-15 |
|
env: |
|
DEVELOPER_DIR: /Applications/Xcode_26.3.app/Contents/Developer |
|
steps: |
|
- name: Checkout |
|
uses: actions/checkout@v4 |
|
|
|
# Runner images ship different simulator sets, and xcodebuild |
|
# silently falls back to "My Mac" (where UIKit doesn't exist) when |
|
# a named destination is missing, so resolve an available iPhone |
|
# simulator by UDID instead of hardcoding a model name. |
|
- name: Run PythonNativeKit tests |
|
working-directory: src/pythonnative/native/ios |
|
run: | |
|
set -o pipefail |
|
UDID="$(xcrun simctl list devices available -j | python3 -c ' |
|
import json, sys |
|
data = json.load(sys.stdin)["devices"] |
|
phones = [ |
|
d for runtime, devices in sorted(data.items()) if "iOS" in runtime |
|
for d in devices if d.get("isAvailable") and d["name"].startswith("iPhone") |
|
] |
|
if not phones: |
|
sys.exit("no available iPhone simulator on this runner") |
|
print(phones[-1]["udid"]) |
|
')" |
|
echo "Using simulator $UDID" |
|
xcodebuild test \ |
|
-project Tests/NativeTests.xcodeproj \ |
|
-scheme NativeTests \ |
|
-parallel-testing-enabled NO \ |
|
-destination "platform=iOS Simulator,id=$UDID" \ |
|
-derivedDataPath "$RUNNER_TEMP/pnkit" \ |
|
-resultBundlePath "$RUNNER_TEMP/pnkit-results.xcresult" |
|
|
|
- name: Upload native test results |
|
if: failure() |
|
uses: actions/upload-artifact@v4 |
|
with: |
|
name: native-ios-results |
|
path: ${{ runner.temp }}/pnkit-results.xcresult |
|
|
|
# JUnit covers contracts; Robolectric exercises native widget lifecycles. |
|
native-android: |
|
runs-on: ubuntu-latest |
|
steps: |
|
- name: Checkout |
|
uses: actions/checkout@v4 |
|
|
|
- name: Set up Java 17 |
|
uses: actions/setup-java@v4 |
|
with: |
|
distribution: 'temurin' |
|
java-version: '17' |
|
|
|
- name: Set up Gradle |
|
uses: gradle/actions/setup-gradle@v4 |
|
|
|
- name: Run pythonnative module tests |
|
working-directory: src/pythonnative/native/android |
|
run: ../../templates/android_template/gradlew testDebugUnitTest --no-daemon |