Repository navigation
[CI]: Bump the actions group with 4 updates #470
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Comprehensive CI | |
| on: | |
| pull_request: | |
| branches: [ '*' ] | |
| push: | |
| branches: [ '*' ] | |
| jobs: | |
| code-quality: | |
| name: Code Quality | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Set up Python | |
| uses: actions/setup-python@v7 | |
| with: | |
| python-version: '3.10' | |
| - name: Cache dependencies | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.cache/pip | |
| key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pip- | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e ".[dev]" | |
| - name: Run pre-commit hooks | |
| run: | | |
| pre-commit run --all-files --show-diff-on-failure | |
| - name: Compile-check examples and tests | |
| run: | | |
| python -m compileall -q examples tests | |
| # webview/lib holds binaries built from interop/, and nothing rebuilds them | |
| # automatically - buildozer and the backends consume the committed artifact. | |
| # Editing the Java source without rebuilding therefore changes nothing at | |
| # runtime, silently, which is easy to do and hard to notice in review. | |
| # | |
| # It fires for comment-only edits, since those shift the line numbers | |
| # compiled into the jar. That is deliberate: Java stack traces in logcat | |
| # cite them, and a jar whose line table has drifted from the source sends | |
| # you to the wrong line. | |
| - name: Set up JDK | |
| uses: actions/setup-java@v6 | |
| with: | |
| distribution: temurin | |
| # Pinned, along with android-31 below, because the check compares the | |
| # compiled classes byte for byte. | |
| java-version: '17' | |
| - name: Check the Android jar matches interop/android | |
| run: | | |
| set -euo pipefail | |
| platform="$ANDROID_HOME/platforms/android-31/android.jar" | |
| if [ ! -f "$platform" ]; then | |
| "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" 'platforms;android-31' > /dev/null | |
| fi | |
| rm -rf /tmp/jar-rebuilt /tmp/jar-committed | |
| mkdir -p /tmp/jar-rebuilt /tmp/jar-committed | |
| javac -g --release 11 -classpath "$platform" -d /tmp/jar-rebuilt \ | |
| interop/android/lib/src/main/java/com/pywebview/*.java | |
| unzip -q webview/lib/pywebview-android.jar -d /tmp/jar-committed | |
| if diff -r /tmp/jar-rebuilt/com /tmp/jar-committed/com; then | |
| echo "webview/lib/pywebview-android.jar matches interop/android." | |
| exit 0 | |
| fi | |
| echo "::error::webview/lib/pywebview-android.jar does not match interop/android." | |
| echo "The APK bundles the committed jar, so a Java change has no effect until it is rebuilt:" | |
| echo | |
| echo " cd interop/android" | |
| echo " javac -g --release 11 \\" | |
| echo " -classpath \$ANDROID_HOME/platforms/android-31/android.jar \\" | |
| echo " -d /tmp/jar lib/src/main/java/com/pywebview/*.java" | |
| echo " (cd /tmp/jar && jar cf \"\$GITHUB_WORKSPACE/webview/lib/pywebview-android.jar\" com)" | |
| echo | |
| echo "Built here with $(javac -version 2>&1) against android-31." | |
| exit 1 | |
| type-check: | |
| name: Type Check | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| # Advisory: the package ships py.typed, but the core modules still carry a | |
| # backlog of annotation errors. The job reports them without blocking so the | |
| # count can be ratcheted down; make it required once it reaches zero. | |
| continue-on-error: true | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Set up Python | |
| uses: actions/setup-python@v7 | |
| with: | |
| python-version: '3.12' | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e "." | |
| pip install mypy | |
| - name: Run mypy | |
| run: | | |
| mypy webview | |
| tests: | |
| name: ${{ matrix.name }} | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 20 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Ubuntu Qt Backend | |
| - name: "Ubuntu Qt" | |
| os: ubuntu-22.04 | |
| python-version: '3.10' | |
| gui: qt | |
| display: ":99" | |
| qt_platform: "offscreen" | |
| log_level: "error" | |
| # Ubuntu GTK Backend | |
| - name: "Ubuntu GTK" | |
| os: ubuntu-22.04 | |
| python-version: '3.11' | |
| gui: gtk | |
| display: ":99" | |
| log_level: "error" | |
| # Windows EdgeChromium | |
| - name: "Windows EdgeChromium" | |
| os: windows-latest | |
| python-version: '3.12' | |
| gui: edgechromium | |
| log_level: "error" | |
| # Windows CEF | |
| # - name: "Windows CEF" | |
| # os: windows-latest | |
| # python-version: '3.12' | |
| # gui: cef | |
| # log_level: "error" | |
| # macOS | |
| - name: "macOS" | |
| os: macos-latest | |
| python-version: '3.13' | |
| log_level: "error" | |
| env: | |
| PYWEBVIEW_GUI: ${{ matrix.gui }} | |
| PYWEBVIEW_LOG: ${{ matrix.log_level }} | |
| DISPLAY: ${{ matrix.display }} | |
| QT_QPA_PLATFORM: ${{ matrix.qt_platform }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v7 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Cache dependencies | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.cache/pip | |
| key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ matrix.gui }}-${{ hashFiles('**/pyproject.toml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ matrix.gui }}- | |
| ${{ runner.os }}-pip-${{ matrix.python-version }}- | |
| ${{ runner.os }}-pip- | |
| # Ubuntu Qt specific setup | |
| - name: Install Qt dependencies (Ubuntu Qt) | |
| if: matrix.gui == 'qt' | |
| run: | | |
| sudo apt-get update -q --allow-releaseinfo-change | |
| sudo apt-get install --no-install-recommends -y \ | |
| xvfb \ | |
| python3-pyqt5 \ | |
| python3-pyqt5.qtwebkit \ | |
| libqt5webkit5-dev \ | |
| - name: Start Xvfb (Ubuntu Qt) | |
| if: matrix.gui == 'qt' | |
| run: | | |
| sudo /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid \ | |
| --make-pidfile --background --exec /usr/bin/Xvfb -- :99 \ | |
| -screen 0 1920x1200x24 -ac +extension GLX +render -noreset | |
| sleep 3 | |
| # Ubuntu GTK specific setup | |
| - name: Install GTK dependencies (Ubuntu GTK) | |
| if: matrix.gui == 'gtk' | |
| run: | | |
| sudo apt-get update -q --allow-releaseinfo-change | |
| sudo apt-get install --no-install-recommends -y \ | |
| xvfb \ | |
| gir1.2-gtk-3.0 \ | |
| gir1.2-webkit2-4.0 \ | |
| python3-gi \ | |
| python3-gi-cairo \ | |
| python3-pep8 \ | |
| pyflakes3 \ | |
| python3-pytest \ | |
| libgirepository1.0-dev | |
| - name: Start Xvfb (Ubuntu GTK) | |
| if: matrix.gui == 'gtk' | |
| run: | | |
| sudo /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid \ | |
| --make-pidfile --background --exec /usr/bin/Xvfb -- :99 \ | |
| -screen 0 1920x1200x24 -ac +extension GLX +render -noreset | |
| sleep 3 | |
| # Windows specific setup | |
| - name: Cache WebView2 Runtime (Windows) | |
| if: runner.os == 'Windows' | |
| uses: actions/cache@v6 | |
| with: | |
| path: 'C:\Program Files\Microsoft\Edge WebView2 Runtime' | |
| key: ${{ runner.os }}-webview2-runtime | |
| - name: Install WebView2 Runtime (Windows) | |
| if: runner.os == 'Windows' | |
| run: | | |
| choco install webview2-runtime --ignore-checksums -y | |
| # Install Python dependencies | |
| - name: Install base dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e "." | |
| pip install pytest pytest-timeout | |
| - name: Install Qt dependencies (Ubuntu Qt) | |
| if: matrix.gui == 'qt' | |
| run: | | |
| python -m pip install --upgrade setuptools==70.0.0 | |
| pip install -e ".[qt5]" | |
| - name: Install GTK dependencies (Ubuntu GTK) | |
| if: matrix.gui == 'gtk' | |
| run: | | |
| python -m pip install --upgrade setuptools==70.0.0 | |
| pip install -e ".[gtk]" | |
| - name: Install CEF dependencies (Windows CEF) | |
| if: matrix.gui == 'cef' | |
| run: | | |
| pip install -e ".[cef]" | |
| - name: Install macOS dependencies (macOS) | |
| if: runner.os == 'macOS' | |
| run: | | |
| pip install -e "." | |
| pip install pillow | |
| - name: Run tests | |
| run: | | |
| cd tests | |
| python run.py | |
| - name: Stop Xvfb (Linux) | |
| if: matrix.gui == 'qt' || matrix.gui == 'gtk' | |
| run: | | |
| sudo killall Xvfb || true | |
| - name: Upload screenshots (macOS) | |
| if: runner.os == 'macOS' && failure() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: macos-screenshots | |
| path: /tmp/screenshots | |
| security: | |
| name: Security Scan | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Set up Python | |
| uses: actions/setup-python@v7 | |
| with: | |
| python-version: '3.12' | |
| - name: Audit dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install pip-audit | |
| pip-audit --strict --desc=auto . | |
| tests-winui3: | |
| name: Windows WinUI3 | |
| runs-on: windows-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Set up Python | |
| uses: actions/setup-python@v7 | |
| with: | |
| python-version: '3.10' | |
| - name: Install WebView2 Runtime | |
| run: | | |
| choco install webview2-runtime -y | |
| - name: Install Windows App Runtime | |
| shell: pwsh | |
| run: | | |
| # Must match the Windows App SDK version the installed pywinrt/winui3 | |
| # wheels (pyproject.toml's `winui3` extra, currently pywinrt 3.2.x) | |
| # were built against — see https://github.com/pywinrt/pywinrt/blob/main/CHANGELOG.md. | |
| # A mismatched runtime makes the app's ON_NO_MATCH_SHOW_UI bootstrap | |
| # try to show an (invisible, on a CI runner) install prompt and hang | |
| # instead of raising, so pin this to the exact version, not latest. | |
| $installer = Join-Path $env:RUNNER_TEMP 'WindowsAppRuntimeInstall.exe' | |
| Invoke-WebRequest -Uri 'https://aka.ms/windowsappsdk/1.7/1.7.250513003/windowsappruntimeinstall-x64.exe' -OutFile $installer | |
| $proc = Start-Process -FilePath $installer -ArgumentList '--quiet' -Wait -PassThru | |
| if ($proc.ExitCode -ne 0) { | |
| throw "WindowsAppRuntimeInstall.exe failed with exit code $($proc.ExitCode)" | |
| } | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e ".[winui3]" | |
| pip install pytest pytest-timeout | |
| - name: Run WinUI3 tests | |
| shell: pwsh | |
| env: | |
| PYWEBVIEW_GUI: winui3 | |
| run: | | |
| cd tests | |
| ./run.ps1 | |
| tests-android: | |
| name: Android | |
| runs-on: ubuntu-22.04 | |
| # A cold python-for-android build (SDK + NDK download, then CPython built | |
| # from source) does not fit in the 20-30 minutes the other jobs get. This is | |
| # per-job, so it does not affect them. GitHub-hosted runners cap at 360. | |
| timeout-minutes: 180 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Set up Python | |
| uses: actions/setup-python@v7 | |
| with: | |
| python-version: '3.11' | |
| - name: Set up JDK | |
| uses: actions/setup-java@v6 | |
| with: | |
| distribution: temurin | |
| java-version: '17' | |
| - name: Enable KVM for the emulator | |
| run: | | |
| echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules | |
| sudo udevadm control --reload-rules | |
| sudo udevadm trigger --name-match=kvm | |
| # One fixed key, deliberately not keyed on buildozer.spec. The expensive and | |
| # slow-moving part of this cache is the Android SDK, the NDK and the | |
| # cross-built CPython, none of which depend much on the spec; the pip | |
| # requirements that do are pure Python and cheap to reinstall into a | |
| # restored dist. Keying on the spec instead produced a new ~3GB entry on | |
| # every requirements edit, and three of those exhaust the repository's 10GB | |
| # cache budget and start evicting the pip caches the other jobs rely on. | |
| # | |
| # Restore and save are split so the save can be conditional: it runs only | |
| # when the build succeeded and the exact key was not already present, so a | |
| # broken build cannot claim the key (entries are immutable) and a good one | |
| # is written exactly once. Bump the version suffix to force a rebuild of | |
| # the toolchain. | |
| - name: Restore buildozer global and project build dirs | |
| id: buildozer-cache | |
| uses: actions/cache/restore@v6 | |
| with: | |
| path: | | |
| ~/.buildozer | |
| tests/android/.buildozer | |
| key: ${{ runner.os }}-buildozer-v1 | |
| restore-keys: | | |
| ${{ runner.os }}-buildozer- | |
| # python-for-android builds CPython and its extension modules from source | |
| # on the runner, so it needs a full autotools toolchain. Most of this is | |
| # not present on a stock ubuntu-22.04 image. | |
| - name: Install build toolchain | |
| run: | | |
| sudo apt-get update -q --allow-releaseinfo-change | |
| sudo apt-get install --no-install-recommends -y \ | |
| autoconf \ | |
| automake \ | |
| libtool \ | |
| pkg-config \ | |
| cmake \ | |
| zlib1g-dev \ | |
| libncurses-dev \ | |
| libffi-dev \ | |
| libssl-dev | |
| - name: Install buildozer | |
| run: | | |
| python -m pip install --upgrade pip | |
| # buildozer is pinned because this job depends on specifics of its | |
| # behaviour: that APP_ANDROID_ARCHS overrides the spec, and that --arch | |
| # cannot be passed through to p4a. It depends on pexpect (needed for | |
| # android.accept_sdk_license) and pins cython<3.0 itself, so neither | |
| # wants naming here. | |
| pip install 'buildozer==1.6.0' | |
| - name: Build APK | |
| # Capped below the job budget so a genuinely stuck build still leaves time | |
| # for the cache to be saved and the logs to be collected. | |
| timeout-minutes: 150 | |
| env: | |
| # Overrides [app] android.archs, which keeps all three ABIs for real | |
| # devices. buildozer builds one python-for-android dist per ABI, so | |
| # building only the one the emulator uses cuts the build to a third. | |
| # (buildozer derives its own --arch flags from the spec, so passing | |
| # --arch through to p4a would add a fourth rather than replace them; | |
| # this env override is the supported route - see specparser.py's | |
| # _override_config_from_envs.) | |
| APP_ANDROID_ARCHS: x86_64 | |
| run: | | |
| cd tests/android | |
| buildozer -v android debug | |
| - name: Save buildozer cache | |
| if: success() && steps.buildozer-cache.outputs.cache-hit != 'true' | |
| uses: actions/cache/save@v6 | |
| with: | |
| path: | | |
| ~/.buildozer | |
| tests/android/.buildozer | |
| key: ${{ runner.os }}-buildozer-v1 | |
| - name: Run tests on emulator | |
| uses: reactivecircus/android-emulator-runner@v2 | |
| with: | |
| api-level: 30 | |
| arch: x86_64 | |
| target: default | |
| disable-animations: true | |
| emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none | |
| working-directory: tests/android | |
| script: ./ci_check.sh | |
| - name: Publish test results to the run summary | |
| if: always() | |
| run: cat tests/android/summary.md >> "$GITHUB_STEP_SUMMARY" || true | |
| - name: Upload logcat | |
| if: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| # Attempt number in the name: artifacts are immutable per run, so on a | |
| # re-run the upload is rejected and downloads silently return the first | |
| # attempt's log - which makes re-runs useless for judging a flaky | |
| # failure. | |
| name: android-logcat-${{ github.run_attempt }} | |
| path: | | |
| tests/android/logcat.txt | |
| tests/android/summary.md | |
| if-no-files-found: warn |