feat: standards, shared CI and release tooling for NAPALM drivers
CI / test (3.11) (push) Successful in 34s
CI / test (3.12) (push) Successful in 30s
CI / test (3.13) (push) Successful in 37s

STANDARDS.md binds every repository in the NAPALM org: one default branch,
Conventional Commits, the device-types contract, test-driven development,
clean-code limits, a quality ratchet for existing code, packaging rules and
releases by tag to PyPI.

napalm-standard holds what a tool can check: the conformance check (with
release rules on a tag), the quality ratchet (ported from netOrk's
quality_ratchet.py), and the Gitea release from the CHANGELOG section.
.gitea/workflows/driver.yml is the CI every driver calls; template/ is a new
driver's starting point and passes the check as it is.
This commit is contained in:
christianmanivong committed 2026-10-22 19:01:14 +02:00
commit db6b2e4ea7
37 files changed
+2894

No files matched your search

+32
View File
@@ -0,0 +1,32 @@
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12", "3.13"]
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"
.venv/bin/pip install -q -e ".[dev]"
- name: Lint
run: |
ruff format --check .
ruff check .
- name: Types
run: mypy napalm_standard
- name: Tests
run: pytest -q --tb=short
+200
View File
@@ -0,0 +1,200 @@
# 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:
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
run: |
python -m venv .venv
echo "$PWD/.venv/bin" >> "$GITHUB_PATH"
.venv/bin/pip install -q "$STANDARD" bandit pip-audit
if [ -n "${{ inputs.pre-install }}" ]; then .venv/bin/pip install -q ${{ inputs.pre-install }}; fi
.venv/bin/pip install -q .
- name: bandit
run: bandit -q -r "$(napalm-standard package)"
- name: pip-audit
# The installed set: what a user gets today from the package's ranges.
# A package not on PyPI yet (the driver itself, a git pre-install) is skipped with a note.
run: pip-audit --skip-editable --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"