Files
christianmanivong 9390accb43
CI / test (3.11) (pull_request) Successful in 26s
CI / test (3.12) (pull_request) Successful in 25s
CI / test (3.13) (pull_request) Successful in 24s
fix(ci): longer download timeout and retries for pip and uv
Several jobs on the NAPALM runner failed on ReadTimeoutError from
files.pythonhosted.org on 2026-10-22, none of them on the code.
2026-10-23 08:31:32 +02:00

213 lines
7.5 KiB
YAML

# The CI every NAPALM driver runs (STANDARDS.md §7). A driver repo calls it from
# its own .gitea/workflows/ci.yml — see template/.gitea/workflows/ci.yml.
#
# Every job that installs builds its own venv in the workspace: jobs on one
# runner share /opt/hostedtoolcache, and two `pip install -e .` into the same
# site-packages break each other (netOrk REPOSITORY_GUIDELINES §10).
#
# upload-artifact/download-artifact stay on v3: v4 refuses to run on Gitea
# ("not currently supported on GHES").
name: driver
on:
workflow_call:
inputs:
standard-ref:
description: "Version of napalm-standard to check with; keep it equal to the @ref of this workflow"
type: string
default: "main"
pre-install:
description: "pip specs installed before the package (until its dependencies are on PyPI)"
type: string
default: ""
python-versions:
description: "JSON list of the Python versions the tests run on"
type: string
default: '["3.10", "3.11", "3.12", "3.13"]'
pypi-url:
description: "Upload target; https://test.pypi.org/legacy/ for a dry run"
type: string
default: "https://upload.pypi.org/legacy/"
secrets:
PYPI_TOKEN:
required: false
env:
# The runner's downloads from PyPI time out now and then (2026-10-22 evening:
# ReadTimeoutError on files.pythonhosted.org in several jobs). Wait longer and retry.
PIP_DEFAULT_TIMEOUT: "60"
PIP_RETRIES: "10"
UV_HTTP_TIMEOUT: "60"
STANDARD: "napalm-standard @ git+https://git.netork.io/NAPALM/driver-standard.git@${{ inputs.standard-ref }}"
jobs:
standard:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install napalm-standard
run: |
python -m venv .venv
echo "$PWD/.venv/bin" >> "$GITHUB_PATH"
.venv/bin/pip install -q "$STANDARD"
- name: Conformance
run: |
if [ "$GITHUB_REF_TYPE" = "tag" ]; then
napalm-standard check --tag "$GITHUB_REF_NAME"
else
napalm-standard check
fi
- name: Quality ratchet
run: napalm-standard ratchet
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: ruff
run: |
python -m venv .venv
.venv/bin/pip install -q ruff
.venv/bin/ruff format --check .
.venv/bin/ruff check .
types:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install
run: |
python -m venv .venv
echo "$PWD/.venv/bin" >> "$GITHUB_PATH"
.venv/bin/pip install -q "$STANDARD" mypy
if [ -n "${{ inputs.pre-install }}" ]; then .venv/bin/pip install -q ${{ inputs.pre-install }}; fi
.venv/bin/pip install -q -e ".[dev]"
- name: mypy
run: mypy "$(napalm-standard package)"
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ${{ fromJSON(inputs.python-versions) }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install
run: |
python -m venv .venv
echo "$PWD/.venv/bin" >> "$GITHUB_PATH"
if [ -n "${{ inputs.pre-install }}" ]; then .venv/bin/pip install -q ${{ inputs.pre-install }}; fi
.venv/bin/pip install -q -e ".[dev]" pytest pytest-cov
- name: pytest
# --cov takes its source from [tool.coverage.run], the floor from fail_under.
run: python -m pytest -q --tb=short --cov --cov-report=term-missing
lowest:
# The floors in pyproject.toml are a promise: install exactly them and run the tests.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Install the lowest versions the package allows
run: |
python -m venv .venv
echo "$PWD/.venv/bin" >> "$GITHUB_PATH"
.venv/bin/pip install -q uv
if [ -n "${{ inputs.pre-install }}" ]; then .venv/bin/uv pip install --python .venv/bin/python -q ${{ inputs.pre-install }}; fi
.venv/bin/uv pip install --python .venv/bin/python -q --resolution lowest-direct -e ".[dev]" pytest
- name: pytest
run: python -m pytest -q --tb=short -p no:cacheprovider
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install
# Two venvs: the tools, and the package alone. Auditing the tools' venv
# reported the runner's own pip instead of anything the package brings.
run: |
python -m venv .tools
.tools/bin/pip install -q --upgrade pip
.tools/bin/pip install -q "$STANDARD" bandit pip-audit
python -m venv .audit
.audit/bin/pip install -q --upgrade pip
if [ -n "${{ inputs.pre-install }}" ]; then .audit/bin/pip install -q ${{ inputs.pre-install }}; fi
.audit/bin/pip install -q .
- name: bandit
run: .tools/bin/bandit -q -r "$(.tools/bin/napalm-standard package)"
- name: pip-audit
# What a user gets today from the package's ranges. Packages installed from
# a URL (the package itself, a git pre-install) are not on PyPI's index yet.
run: |
.audit/bin/pip freeze --all | grep -vE ' @ |^-e ' > audit-requirements.txt
cat audit-requirements.txt
.tools/bin/pip-audit -r audit-requirements.txt --no-deps --disable-pip --progress-spinner off
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Build wheel and sdist
run: |
python -m venv .venv
.venv/bin/pip install -q build twine
.venv/bin/python -m build
.venv/bin/twine check --strict dist/*
- uses: actions/upload-artifact@v3
with:
name: dist
path: dist/*
publish:
# Only a release tag publishes, and only when everything above passed.
if: github.ref_type == 'tag' && startsWith(github.ref_name, 'v')
needs: [standard, lint, types, test, lowest, security, build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- uses: actions/download-artifact@v3
with:
name: dist
path: dist
- name: Upload to PyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
TWINE_REPOSITORY_URL: ${{ inputs.pypi-url }}
run: |
if [ -z "$TWINE_PASSWORD" ]; then echo "no PYPI_TOKEN secret in this repo"; exit 1; fi
python -m venv .venv
.venv/bin/pip install -q twine "$STANDARD"
.venv/bin/twine upload --non-interactive dist/*
- name: Gitea release
env:
GITEA_URL: ${{ github.server_url }}
GITEA_REPOSITORY: ${{ github.repository }}
GITEA_TOKEN: ${{ github.token }}
run: .venv/bin/napalm-standard release "$GITHUB_REF_NAME"