Skip to content

Make vgi-news lint-clean at vgi-lint-check 0.26.0 (strict profile) #9

Make vgi-news lint-clean at vgi-lint-check 0.26.0 (strict profile)

Make vgi-news lint-clean at vgi-lint-check 0.26.0 (strict profile) #9

Workflow file for this run

# Copyright 2026 Query Farm LLC - https://query.farm
#
# Unit tests (pytest), lint, and the sqllogictest extension suite
# (test/sql/*.test) run against the vgi-news worker through the real signed
# `vgi` DuckDB community extension via a prebuilt standalone `haybarn-unittest`.
# The SQL E2E redirects every provider at a local mock news API — no keys, no
# cost, no live egress. See ci/README.md for the design.
name: CI
on:
push:
branches: [main]
paths-ignore: ['README.md']
pull_request:
branches: [main]
paths-ignore: ['README.md']
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
name: Python ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
python-version: ["3.13"]
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v8.2.0
- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}
- name: Install dependencies
run: uv sync --frozen --all-extras
# The `live` marker (real GDELT over the network) is excluded by default
# via the pyproject addopts.
- name: Run tests
run: uv run --no-sync pytest -q
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v8.2.0
- name: Install dependencies
run: uv sync --frozen --all-extras
- name: Check formatting
run: uv run --no-sync ruff format --check .
- name: Check linting
run: uv run --no-sync ruff check .
- name: Type check (mypy)
run: uv run --no-sync mypy vgi_news/ news_worker.py
# Run pydoclint isolated via uvx: it depends on `docstring-parser-fork`,
# which shares the `docstring_parser` import namespace with the plain
# `docstring-parser` pulled in transitively by vgi-rpc. Co-installing both
# in one env is an install-order-dependent collision (the plain package can
# win and break pydoclint's imports), so give pydoclint its own env.
- name: Docstring lint (pydoclint)
run: uvx pydoclint --config pyproject.toml vgi_news/ news_worker.py
# Metadata-quality gate: build the worker, then run vgi-lint against the live
# catalog (the action force-installs the signed `vgi` community extension and
# launches the worker at LOCATION). Kept a separate job so it's visible.
metadata-quality:
name: Metadata quality (vgi-lint)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v8.2.0
- name: Set up Python 3.13
run: uv python install 3.13
- name: Install the worker
run: uv sync --frozen --all-extras
- name: vgi-lint
uses: Query-farm/vgi-lint-check@v1
with:
location: "uv run news_worker.py"
fail-on: info
# Resolve the latest published haybarn release once, so the whole matrix tests
# the same version (and we never hardcode/pin it).
resolve-haybarn:
name: Resolve haybarn release
runs-on: ubuntu-latest
outputs:
release: ${{ steps.r.outputs.release }}
steps:
- id: r
run: |
REL=$(gh release view --repo Query-farm-haybarn/haybarn --json tagName --jq .tagName)
echo "release=$REL" >> "$GITHUB_OUTPUT"
echo "Latest haybarn release: $REL"
env:
GH_TOKEN: ${{ github.token }}
integration:
name: SQL E2E (${{ matrix.transport }}) on ${{ matrix.os }}
needs: resolve-haybarn
strategy:
fail-fast: false
matrix:
# Run the SAME sqllogictest suite over every VGI transport. The vgi
# extension picks the transport from the ATTACH LOCATION string that
# run-integration.sh builds per $TRANSPORT (the mock news server stays up
# for all three; the exported VGI_NEWS_*_BASE_URL vars route every
# worker — DuckDB-spawned or booted out-of-band by the script — at it):
# subprocess : `.venv/bin/python news_worker.py` (stdio)
# http : `http://127.0.0.1:<port>` (worker booted with --http)
# unix : `unix://<sock>` (worker booted with --unix)
os: [ubuntu-latest, macos-latest]
transport: [subprocess, http, unix]
include:
- { os: ubuntu-latest, asset: haybarn_unittest-linux-amd64.zip }
- { os: macos-latest, asset: haybarn_unittest-osx-arm64.zip }
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v8.2.0
- name: Set up Python 3.13
run: uv python install 3.13
- name: Install the worker (from the lockfile, with the http extra)
# The `http` extra pulls in waitress so the worker can serve `--http`.
# Harmless for the subprocess/unix legs; required for the http leg.
run: uv sync --frozen --python 3.13 --extra http
- name: Download haybarn-unittest
run: |
gh release download "$HAYBARN_RELEASE" \
--repo Query-farm-haybarn/haybarn \
--pattern '${{ matrix.asset }}' \
--output haybarn-unittest.zip --clobber
mkdir -p hb && unzip -o -q haybarn-unittest.zip -d hb
env:
GH_TOKEN: ${{ github.token }}
HAYBARN_RELEASE: ${{ needs.resolve-haybarn.outputs.release }}
- name: Resolve runner + worker paths
run: |
# Absolute paths: run-integration.sh cd's into a staging dir before
# invoking the runner, so relative paths would not resolve. The worker
# runs from the synced .venv (deps resolved from PyPI via the lockfile);
# plain `.venv/bin/python` ignores the PEP 723 header. run-integration.sh
# starts the mock news API and redirects both providers at it (for all
# transports). WORKER_CMD is the stdio command: used directly as the
# subprocess LOCATION, and to boot the http/unix server out-of-band.
UNITTEST="$PWD/$(find hb -name 'haybarn-unittest' -type f | head -1)"
chmod +x "$UNITTEST"
echo "HAYBARN_UNITTEST=$UNITTEST" >> "$GITHUB_ENV"
echo "WORKER_CMD=$PWD/.venv/bin/python $PWD/news_worker.py" >> "$GITHUB_ENV"
- name: Run extension integration suite (${{ matrix.transport }})
run: ci/run-integration.sh
env:
TRANSPORT: ${{ matrix.transport }}