feat: standards, shared CI and release tooling for NAPALM drivers
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:
commit
db6b2e4ea7
37 files changed
+2894
No files matched your search
@@ -0,0 +1,88 @@
|
||||
"""A driver repository on disk that meets the standard, to break one rule at a time."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
import textwrap
|
||||
from collections.abc import Callable
|
||||
|
||||
import pytest
|
||||
|
||||
PYPROJECT = """\
|
||||
[build-system]
|
||||
requires = ["setuptools>=68"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "napalm-example"
|
||||
version = "1.2.0"
|
||||
description = "NAPALM driver for Example devices"
|
||||
readme = "README.md"
|
||||
license = "Apache-2.0"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"napalm>=5.0",
|
||||
"napalm-device-types>=4.21",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Repository = "https://git.netork.io/NAPALM/napalm-example"
|
||||
Issues = "https://git.netork.io/NAPALM/napalm-example/issues"
|
||||
|
||||
[project.entry-points."napalm.drivers"]
|
||||
example = "napalm_example:ExampleDriver"
|
||||
|
||||
[tool.mypy]
|
||||
strict = true
|
||||
|
||||
[tool.coverage.run]
|
||||
source = ["napalm_example"]
|
||||
|
||||
[tool.coverage.report]
|
||||
fail_under = 80
|
||||
"""
|
||||
|
||||
CHANGELOG = """\
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.2.0] - 2026-10-22
|
||||
|
||||
### Added
|
||||
- Interfaces.
|
||||
|
||||
## [1.1.0] - 2026-10-01
|
||||
|
||||
### Fixed
|
||||
- Facts.
|
||||
"""
|
||||
|
||||
RepoFactory = Callable[..., pathlib.Path]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def make_repo(tmp_path: pathlib.Path) -> RepoFactory:
|
||||
"""Write a conforming repo; ``files`` overrides or (with None) removes a path."""
|
||||
|
||||
def make(files: dict[str, str | None] | None = None) -> pathlib.Path:
|
||||
layout: dict[str, str | None] = {
|
||||
"pyproject.toml": PYPROJECT,
|
||||
"README.md": "# napalm-example\n\nA driver.\n",
|
||||
"CHANGELOG.md": CHANGELOG,
|
||||
"LICENSE": "Apache License\nVersion 2.0, January 2004\n",
|
||||
"napalm_example/__init__.py": "",
|
||||
"napalm_example/py.typed": "",
|
||||
".gitea/workflows/ci.yml": "name: CI\n",
|
||||
"tests/test_driver.py": "def test_nothing():\n pass\n",
|
||||
}
|
||||
layout.update(files or {})
|
||||
for rel, content in layout.items():
|
||||
if content is None:
|
||||
continue
|
||||
path = tmp_path / rel
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(textwrap.dedent(content))
|
||||
return tmp_path
|
||||
|
||||
return make
|
||||
Reference in new issue
Block a user