Compare commits

..
4 Commits
Author SHA1 Message Date
devx-ci-bot 40dd578d89 release: v0.19.0
Post-merge / detect-type (push) Successful in 37s
Post-merge / release (push) Has been skipped
Post-merge / validate-commit-msg (push) Has been skipped
Post-merge / sync-wiki (push) Has been skipped
Post-merge / vikunja (push) Has been skipped
Post-merge / configure-repo (push) Has been skipped
Publish Release / publish (push) Successful in 48s
Post-merge / badges (push) Successful in 48s
2026-06-26 19:03:14 +00:00
emil 7ea9b4a96b DEVX-64: feat: add skip_ref_prefixes config to check_agent_docs
Post-merge / detect-type (push) Successful in 38s
Post-merge / validate-commit-msg (push) Successful in 45s
Post-merge / sync-wiki (push) Successful in 51s
Post-merge / release (push) Successful in 57s
Post-merge / badges (push) Successful in 59s
Post-merge / configure-repo (push) Successful in 1m1s
Post-merge / vikunja (push) Successful in 1m22s
2026-06-26 19:01:39 +00:00
gitea-actions-bot 08ceaf484f chore: update badge URLs to commit c003531a [skip ci] 2026-06-26 20:52:05 +02:00
gitea-actions-bot fb6b0fda1d chore: update badge URLs to commit c5811a72 [skip ci] 2026-06-26 18:50:24 +00:00
6 changed files with 44 additions and 21 deletions
+6
View File
@@ -2,6 +2,12 @@
All notable changes to this project will be documented in this file.
## [0.19.0] - 2026-06-26
### Features
- Add skip_ref_prefixes config to check_agent_docs
## [0.18.0] - 2026-06-26
### Features
+6 -6
View File
@@ -16,12 +16,12 @@ quality badges.
[![CI](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions/workflows/ci.yml/badge.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![License: GPL-3.0](https://img.shields.io/badge/license-GPL--3.0-blue)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/src/branch/master/LICENSE)
[![Coverage](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/0a0adc8dce9a146068a35ade3e9f301c3a5e8cca/coverage.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Tests](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/0a0adc8dce9a146068a35ade3e9f301c3a5e8cca/tests.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Docs](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/0a0adc8dce9a146068a35ade3e9f301c3a5e8cca/docs.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki)
[![Code Quality](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/0a0adc8dce9a146068a35ade3e9f301c3a5e8cca/quality.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Version](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/0a0adc8dce9a146068a35ade3e9f301c3a5e8cca/version.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/releases)
[![Python](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/0a0adc8dce9a146068a35ade3e9f301c3a5e8cca/python.svg)](https://www.python.org/downloads/)
[![Coverage](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/c003531a580f4f888dd60d5c8d3f16b04b6443a4/coverage.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Tests](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/c003531a580f4f888dd60d5c8d3f16b04b6443a4/tests.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Docs](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/c003531a580f4f888dd60d5c8d3f16b04b6443a4/docs.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki)
[![Code Quality](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/c003531a580f4f888dd60d5c8d3f16b04b6443a4/quality.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Version](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/c003531a580f4f888dd60d5c8d3f16b04b6443a4/version.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/releases)
[![Python](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/c003531a580f4f888dd60d5c8d3f16b04b6443a4/python.svg)](https://www.python.org/downloads/)
## Why devx?
+6 -6
View File
@@ -12,12 +12,12 @@ project to be reusable across all oblachno-oss repositories.
[![CI](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions/workflows/ci.yml/badge.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![License: GPL-3.0](https://img.shields.io/badge/license-GPL--3.0-blue)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/src/branch/master/LICENSE)
[![Coverage](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/0a0adc8dce9a146068a35ade3e9f301c3a5e8cca/coverage.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Tests](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/0a0adc8dce9a146068a35ade3e9f301c3a5e8cca/tests.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Docs](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/0a0adc8dce9a146068a35ade3e9f301c3a5e8cca/docs.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki)
[![Code Quality](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/0a0adc8dce9a146068a35ade3e9f301c3a5e8cca/quality.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Version](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/0a0adc8dce9a146068a35ade3e9f301c3a5e8cca/version.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/releases)
[![Python](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/0a0adc8dce9a146068a35ade3e9f301c3a5e8cca/python.svg)](https://www.python.org/downloads/)
[![Coverage](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/c003531a580f4f888dd60d5c8d3f16b04b6443a4/coverage.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Tests](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/c003531a580f4f888dd60d5c8d3f16b04b6443a4/tests.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Docs](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/c003531a580f4f888dd60d5c8d3f16b04b6443a4/docs.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki)
[![Code Quality](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/c003531a580f4f888dd60d5c8d3f16b04b6443a4/quality.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Version](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/c003531a580f4f888dd60d5c8d3f16b04b6443a4/version.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/releases)
[![Python](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/c003531a580f4f888dd60d5c8d3f16b04b6443a4/python.svg)](https://www.python.org/downloads/)
## Overview
+1 -1
View File
@@ -1,3 +1,3 @@
"""devx — reusable development and CI/CD tools for oblachno-oss projects."""
__version__ = "0.18.0"
__version__ = "0.19.0"
+8
View File
@@ -117,6 +117,7 @@ def _check_file(
legitimate_indicators: list[str],
repo_path_prefixes: list[str],
min_path_ref_length: int,
skip_ref_prefixes: list[str],
) -> list[str]:
"""Check a single file for stale references."""
issues: list[str] = []
@@ -147,6 +148,9 @@ def _check_file(
# Only check references that look like repo paths
if not any(ref.startswith(prefix) for prefix in repo_path_prefixes):
continue
# Skip references matching configured skip prefixes (e.g. aspirational test files)
if any(ref.startswith(prefix) for prefix in skip_ref_prefixes):
continue
candidate = repo_root / ref
if not candidate.exists():
issues.append(f"{rel_path}:{lineno}: references non-existent file '{ref}'")
@@ -179,6 +183,9 @@ def cli() -> None:
min_len_raw = cfg.get("min_path_ref_length")
min_path_ref_length: int = int(min_len_raw) if isinstance(min_len_raw, int) else MIN_PATH_REF_LENGTH_DEFAULT
skip_prefixes_raw = cfg.get("skip_ref_prefixes", [])
skip_ref_prefixes: list[str] = [str(d) for d in skip_prefixes_raw] if isinstance(skip_prefixes_raw, list) else []
deleted_files: set[str] = set()
deleted_raw = cfg.get("deleted_files", [])
if isinstance(deleted_raw, list):
@@ -209,6 +216,7 @@ def cli() -> None:
legitimate_indicators,
repo_path_prefixes,
min_path_ref_length,
skip_ref_prefixes,
)
all_issues.extend(issues)
+17 -8
View File
@@ -89,7 +89,7 @@ class TestCheckFile:
doc.parent.mkdir(parents=True)
doc.write_text("See scripts/old.py for details.\n")
issues = _check_file(
doc, tmp_path, {"scripts/old.py"}, [], [], DEFAULT_REPO_PATH_PREFIXES, MIN_PATH_REF_LENGTH_DEFAULT
doc, tmp_path, {"scripts/old.py"}, [], [], DEFAULT_REPO_PATH_PREFIXES, MIN_PATH_REF_LENGTH_DEFAULT, []
)
assert any("deleted file" in i for i in issues)
@@ -97,7 +97,7 @@ class TestCheckFile:
doc = tmp_path / "docs" / "guide.md"
doc.parent.mkdir(parents=True)
doc.write_text("See scripts/nonexistent.py for details.\n")
issues = _check_file(doc, tmp_path, set(), [], [], DEFAULT_REPO_PATH_PREFIXES, MIN_PATH_REF_LENGTH_DEFAULT)
issues = _check_file(doc, tmp_path, set(), [], [], DEFAULT_REPO_PATH_PREFIXES, MIN_PATH_REF_LENGTH_DEFAULT, [])
assert any("non-existent file" in i for i in issues)
def test_does_not_flag_existing_file(self, tmp_path: Path) -> None:
@@ -106,7 +106,7 @@ class TestCheckFile:
doc = tmp_path / "docs" / "guide.md"
doc.parent.mkdir(parents=True)
doc.write_text("See scripts/exists.py for details.\n")
issues = _check_file(doc, tmp_path, set(), [], [], DEFAULT_REPO_PATH_PREFIXES, MIN_PATH_REF_LENGTH_DEFAULT)
issues = _check_file(doc, tmp_path, set(), [], [], DEFAULT_REPO_PATH_PREFIXES, MIN_PATH_REF_LENGTH_DEFAULT, [])
assert issues == []
def test_detects_deprecated_pattern(self, tmp_path: Path) -> None:
@@ -115,7 +115,7 @@ class TestCheckFile:
doc.write_text("Use ansible/envs/prod/secrets.yml for config.\n")
patterns = [re.compile(r"ansible/envs/[^/]+/secrets\.yml")]
issues = _check_file(
doc, tmp_path, set(), patterns, [], DEFAULT_REPO_PATH_PREFIXES, MIN_PATH_REF_LENGTH_DEFAULT
doc, tmp_path, set(), patterns, [], DEFAULT_REPO_PATH_PREFIXES, MIN_PATH_REF_LENGTH_DEFAULT, []
)
assert any("deprecated pattern" in i for i in issues)
@@ -129,7 +129,7 @@ class TestCheckFile:
doc.write_text("The legacy ansible/envs/prod/secrets.yml is deprecated.\n")
patterns = [re.compile(r"ansible/envs/[^/]+/secrets\.yml")]
issues = _check_file(
doc, tmp_path, set(), patterns, ["deprecated"], DEFAULT_REPO_PATH_PREFIXES, MIN_PATH_REF_LENGTH_DEFAULT
doc, tmp_path, set(), patterns, ["deprecated"], DEFAULT_REPO_PATH_PREFIXES, MIN_PATH_REF_LENGTH_DEFAULT, []
)
assert issues == []
@@ -137,14 +137,14 @@ class TestCheckFile:
doc = tmp_path / "docs" / "guide.md"
doc.parent.mkdir(parents=True)
doc.write_bytes(b"\xff\xfe\x00\x00")
issues = _check_file(doc, tmp_path, set(), [], [], DEFAULT_REPO_PATH_PREFIXES, MIN_PATH_REF_LENGTH_DEFAULT)
issues = _check_file(doc, tmp_path, set(), [], [], DEFAULT_REPO_PATH_PREFIXES, MIN_PATH_REF_LENGTH_DEFAULT, [])
assert issues == []
def test_skips_short_ref(self, tmp_path: Path) -> None:
doc = tmp_path / "docs" / "guide.md"
doc.parent.mkdir(parents=True)
doc.write_text("See a.py for details.\n")
issues = _check_file(doc, tmp_path, set(), [], [], DEFAULT_REPO_PATH_PREFIXES, 5)
issues = _check_file(doc, tmp_path, set(), [], [], DEFAULT_REPO_PATH_PREFIXES, 5, [])
# "a.py" is only 4 chars, below min_path_ref_length
assert issues == []
@@ -152,10 +152,19 @@ class TestCheckFile:
doc = tmp_path / "docs" / "guide.md"
doc.parent.mkdir(parents=True)
doc.write_text("See vendor/some/long/path.py for details.\n")
issues = _check_file(doc, tmp_path, set(), [], [], DEFAULT_REPO_PATH_PREFIXES, MIN_PATH_REF_LENGTH_DEFAULT)
issues = _check_file(doc, tmp_path, set(), [], [], DEFAULT_REPO_PATH_PREFIXES, MIN_PATH_REF_LENGTH_DEFAULT, [])
# "vendor/" is not in repo_path_prefixes
assert issues == []
def test_skip_ref_prefixes_skips_nonexistent(self, tmp_path: Path) -> None:
doc = tmp_path / "docs" / "guide.md"
doc.parent.mkdir(parents=True)
doc.write_text("See scripts/test_foo.py for details.\n")
issues = _check_file(
doc, tmp_path, set(), [], [], DEFAULT_REPO_PATH_PREFIXES, MIN_PATH_REF_LENGTH_DEFAULT, ["scripts/test_"]
)
assert issues == []
class TestCli:
def test_passes_when_no_issues(self, tmp_path: Path) -> None: