Skip to content

Document every argument and method: Args sections from the tool schemas #28

Document every argument and method: Args sections from the tool schemas

Document every argument and method: Args sections from the tool schemas #28

Workflow file for this run

name: wheels
# Build one py3-none wheel per platform by bundling the official binary from
# the browser repo's GitHub release (the same asset the README tells users to
# download). No compilation happens here — all four wheels build on one
# Ubuntu runner; native runners are only needed to *test* them.
#
# Modeled on zignal's python.yml (matrix -> build -> test-the-wheel ->
# publish), minus everything a C extension needs: no per-Python builds,
# no cross-compilation, no auditwheel/delocate.
#
# Triggers:
# - pull_request / push to main: build + test against the browser
# `nightly` release, no publish.
# - release published: build + test the browser release named by the tag
# and publish to PyPI. A release tag on this repo is the browser release
# tag it ships (e.g. 0.4.0), optionally followed by `-N` (or `.postN`) for
# a Python-only re-release of that same browser version: `0.4.0-1` bundles
# browser 0.4.0 and publishes as the PEP 440 post-release `0.4.0.post1`.
# Plain `X.Y.Z` releases here are created automatically by the browser
# repo's release workflow (its `update-python-package` job) whenever it
# builds a version tag, so a browser release flows to PyPI with no
# polling — the publish still stops at the pypi environment's
# required-reviewer gate.
# - workflow_dispatch: pick any browser tag, an optional post-release
# number and the publish target manually.
on:
pull_request:
push:
branches: [main]
release:
types: [published]
workflow_dispatch:
inputs:
release:
description: "browser release tag to bundle (nightly or a version tag)"
default: "nightly"
post:
description: "post-release number (publishes <release>.post<N>; leave empty for none)"
default: ""
publish:
description: "where to publish"
type: choice
options: [none, testpypi, pypi]
default: none
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
BROWSER_REPO: lightpanda-io/browser
jobs:
# Map the triggering event to the browser tag to bundle, the wheel version
# and the publish target, so the downstream jobs don't each re-derive them.
params:
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
release_tag: ${{ steps.resolve.outputs.release_tag }}
wheel_version: ${{ steps.resolve.outputs.wheel_version }}
publish: ${{ steps.resolve.outputs.publish }}
steps:
- name: Resolve browser tag, wheel version and publish target
id: resolve
run: |
case "${{ github.event_name }}" in
release)
tag="${{ github.event.release.tag_name }}"
publish=pypi
;;
workflow_dispatch)
tag="${{ inputs.release }}"
[ -n "${{ inputs.post }}" ] && tag="$tag-${{ inputs.post }}"
publish="${{ inputs.publish }}"
;;
*)
tag=nightly
publish=none
;;
esac
# Split the tag into the browser release to bundle and the wheel
# version. `X.Y.Z` ships browser X.Y.Z as version X.Y.Z; `X.Y.Z-N`
# (Debian style) or `X.Y.Z.postN` ships the same browser X.Y.Z as
# the PEP 440 post-release X.Y.Z.postN — a Python-only re-release.
# A nightly build keeps pyproject's dev version (empty wheel_version).
tag="${tag#v}"
case "$tag" in
nightly) browser=nightly; version= ;;
*-[0-9]*) browser="${tag%-*}"; version="${tag%-*}.post${tag##*-}" ;;
*.post[0-9]*) browser="${tag%.post*}"; version="$tag" ;;
*) browser="$tag"; version="$tag" ;;
esac
if [ "$browser" != nightly ] && ! echo "$browser" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error::'$tag' is not a browser release tag (X.Y.Z, optionally followed by -N or .postN)"
exit 1
fi
if [ -n "$version" ] && ! echo "$version" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(\.post[0-9]+)?$'; then
echo "::error::'$tag' does not map to a PEP 440 version (got '$version')"
exit 1
fi
# Never let a nightly build reach PyPI, whatever dispatched it.
if [ "$publish" = pypi ] && [ "$browser" = nightly ]; then
echo "::error::refusing to publish a nightly build to PyPI (pick a version tag)"
exit 1
fi
{
echo "release_tag=$browser"
echo "wheel_version=$version"
echo "publish=$publish"
} >> "$GITHUB_OUTPUT"
cat "$GITHUB_OUTPUT"
build:
needs: params
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
matrix:
include:
- asset: lightpanda-x86_64-linux
plat: manylinux_2_35_x86_64
- asset: lightpanda-aarch64-linux
plat: manylinux_2_35_aarch64
- asset: lightpanda-aarch64-macos
plat: macosx_14_0_arm64
- asset: lightpanda-x86_64-macos
plat: macosx_13_0_x86_64
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- name: Download the release binary
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release download "${{ needs.params.outputs.release_tag }}" -R "$BROWSER_REPO" \
-p "${{ matrix.asset }}" -O lightpanda-bin
chmod +x lightpanda-bin
ls -la lightpanda-bin
# The tool schemas are platform-independent; fetch the one binary
# this runner can execute to regenerate the methods from.
if [ "${{ matrix.asset }}" = lightpanda-x86_64-linux ]; then
cp lightpanda-bin lightpanda-gen
else
gh release download "${{ needs.params.outputs.release_tag }}" -R "$BROWSER_REPO" \
-p lightpanda-x86_64-linux -O lightpanda-gen
chmod +x lightpanda-gen
fi
- name: Regenerate tool methods from the bundled binary
env:
LIGHTPANDA_BIN: ${{ github.workspace }}/lightpanda-gen
run: |
# The wheel always ships methods matching the binary it bundles.
uv run --no-project python scripts/generate_methods.py
# PRs and pushes build against nightly: fail on drift so the committed
# file (what IDEs and the docs see) keeps up with the browser's tools.
case "${{ github.event_name }}" in
pull_request|push)
git diff --exit-code -- lightpanda/_methods.py || {
echo "::error::lightpanda/_methods.py is out of date: run scripts/generate_methods.py and commit the result"
exit 1
}
;;
esac
- name: Set wheel version from tag
if: needs.params.outputs.wheel_version != ''
run: |
# Already normalized by the params job (X.Y.Z or X.Y.Z.postN), so the
# wheel filename and the PyPI listing match the tag as written here.
sed -i 's/^version = .*/version = "${{ needs.params.outputs.wheel_version }}"/' pyproject.toml
grep '^version' pyproject.toml
- name: Build wheel
env:
LIGHTPANDA_BIN: ${{ github.workspace }}/lightpanda-bin
LIGHTPANDA_PLAT: ${{ matrix.plat }}
run: uv build --wheel
- uses: actions/upload-artifact@v4
with:
name: wheel-${{ matrix.plat }}
path: dist/*.whl
test:
needs: build
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-latest
plat: manylinux_2_35_x86_64
- runner: ubuntu-24.04-arm
plat: manylinux_2_35_aarch64
- runner: macos-14
plat: macosx_14_0_arm64
- runner: macos-15-intel
plat: macosx_13_0_x86_64
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- uses: actions/download-artifact@v4
with:
name: wheel-${{ matrix.plat }}
path: dist
- name: Install the wheel into a clean venv
run: |
uv venv wheel-env
# playwright (connect_over_cdp) and selenium (webdriver.Remote) are
# only clients of the bundled browser here: no browser or driver
# download is needed.
uv pip install --python wheel-env dist/*.whl pytest pytest-asyncio playwright selenium
- name: Run the test suite against the installed wheel
run: |
# Resolve the *bundled* binary and pin the tests to it; run from
# outside the checkout so the source tree can't shadow the install
# (-I likewise keeps the cwd off sys.path for this resolution).
# pyproject.toml comes along for its [tool.pytest.ini_options]
# (asyncio_mode) — without it the async tests are silently skipped.
BIN=$(./wheel-env/bin/python -I -c "from lightpanda.client import find_binary; print(find_binary())")
echo "bundled binary: $BIN"
mkdir -p /tmp/wheeltest && cp -r tests pyproject.toml /tmp/wheeltest/
cd /tmp/wheeltest
LIGHTPANDA_BIN="$BIN" "$GITHUB_WORKSPACE"/wheel-env/bin/python -m pytest tests -q
- name: CLI smoke
run: ./wheel-env/bin/lightpanda version
publish:
needs: [params, test]
if: needs.params.outputs.publish != 'none'
runs-on: ubuntu-latest
timeout-minutes: 10
environment: ${{ needs.params.outputs.publish }}
permissions:
id-token: write # PyPI trusted publishing
steps:
- uses: astral-sh/setup-uv@v5
- uses: actions/download-artifact@v4
with:
pattern: wheel-*
merge-multiple: true
path: dist
- name: Publish
run: |
if [ "${{ needs.params.outputs.publish }}" = "testpypi" ]; then
uv publish --publish-url https://test.pypi.org/legacy/ dist/*.whl
else
uv publish dist/*.whl
fi