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,71 @@
|
||||
"""The Gitea release that goes with a tag (STANDARDS.md §9)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from napalm_standard.release import NotFound, publish
|
||||
|
||||
CHANGELOG = "# Changelog\n\n## [1.2.0] - 2026-10-22\n\n- Interfaces.\n\n## [1.1.0] - x\n\n- y\n"
|
||||
|
||||
|
||||
class FakeApi:
|
||||
def __init__(self, existing: dict[str, Any] | None = None) -> None:
|
||||
self.existing = existing
|
||||
self.calls: list[tuple[str, str, dict[str, Any] | None]] = []
|
||||
|
||||
def __call__(self, method: str, path: str, payload: dict[str, Any] | None = None) -> Any:
|
||||
self.calls.append((method, path, payload))
|
||||
if method == "GET":
|
||||
if self.existing is None:
|
||||
raise NotFound(path)
|
||||
return self.existing
|
||||
return {"id": 7, **(payload or {})}
|
||||
|
||||
|
||||
def test_a_missing_release_is_created_from_the_changelog() -> None:
|
||||
api = FakeApi()
|
||||
|
||||
publish("v1.2.0", "napalm-example", CHANGELOG, api)
|
||||
|
||||
assert api.calls[0][:2] == ("GET", "/releases/tags/v1.2.0")
|
||||
method, path, payload = api.calls[1]
|
||||
assert (method, path) == ("POST", "/releases")
|
||||
assert payload == {
|
||||
"tag_name": "v1.2.0",
|
||||
"name": "napalm-example 1.2.0",
|
||||
"body": "- Interfaces.",
|
||||
"draft": False,
|
||||
"prerelease": False,
|
||||
}
|
||||
|
||||
|
||||
def test_an_existing_release_is_updated_not_duplicated() -> None:
|
||||
api = FakeApi(existing={"id": 3})
|
||||
|
||||
publish("v1.2.0", "napalm-example", CHANGELOG, api)
|
||||
|
||||
assert [c[:2] for c in api.calls] == [
|
||||
("GET", "/releases/tags/v1.2.0"),
|
||||
("PATCH", "/releases/3"),
|
||||
]
|
||||
|
||||
|
||||
def test_a_version_without_a_changelog_section_is_refused() -> None:
|
||||
api = FakeApi()
|
||||
|
||||
with pytest.raises(ValueError, match="1.3.0"):
|
||||
publish("v1.3.0", "napalm-example", CHANGELOG, api)
|
||||
|
||||
assert api.calls == []
|
||||
|
||||
|
||||
def test_the_payload_is_json_serialisable() -> None:
|
||||
api = FakeApi()
|
||||
|
||||
publish("v1.2.0", "napalm-example", CHANGELOG, api)
|
||||
|
||||
json.dumps(api.calls[1][2])
|
||||
Reference in new issue
Block a user