Skip to content

Commit db4a0d5

Browse files
authored
fix(entry-point): rename hatch entry point 'decorators' to 'reqstool' + add e2e tests (#75)
* fix(entry-point): rename hatch entry point from 'decorators' to 'reqstool' The entry point key must match the hook name used in pyproject.toml ([tool.hatch.build.hooks.reqstool]). The previous 'decorators' key caused 'Unknown build hook: reqstool' errors for all users following the README. Also: - Fix addopts: remove broken '-m not slow or not integration' filter - Drop unused 'flaky'/'slow' markers; add 'integration' and 'e2e' markers - Add tests/integration/ and tests/e2e/ directory structure - Add e2e test: runs hatchling directly in an isolated venv to verify the build hook generates annotations.yml and bundles reqstool_config.yml - Fix CI: correct cov package name, add --junitxml, build wheel before tests * test: verify annotations.yml content contains expected REQ/SVC ids * style: apply black formatting to e2e test * fix: remove unused sys import * fix(ci): remove pull_request_target trigger from semantic PR check * fix(tests): move tarfile assertions inside with block
1 parent c734ceb commit db4a0d5

File tree

8 files changed

+80
-8
lines changed

8 files changed

+80
-8
lines changed

.github/workflows/build.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@ jobs:
2828
python-version: "3.13"
2929
- name: Install dependencies
3030
run: pip install hatch
31-
- name: Run unit and integrations tests
32-
run: hatch run dev:pytest --cov=reqstool-python-decorators --cov-report=xml --cov-report=html
31+
- name: Build wheel (used by e2e tests via PIP_FIND_LINKS)
32+
run: hatch build --target wheel
33+
- name: Run tests
34+
run: hatch run dev:pytest --junitxml=build/junit.xml --cov=reqstool_python_hatch_plugin --cov-report=xml:build/coverage.xml
3335
- name: Build project
3436
run: hatch build
3537
# Upload artifacts for later use

.github/workflows/check-semantic-pr.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ name: Check Semantic PR
22
on:
33
pull_request:
44
types: [opened, edited, synchronize, reopened]
5-
pull_request_target:
6-
types: [opened, edited, synchronize, reopened]
75

86
jobs:
97
check:

pyproject.toml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Source = "https://github.com/reqstool/reqstool-python-hatch-plugin.git"
2727
Documentation = "https://github.com/reqstool/reqstool-python-hatch-plugin.git"
2828

2929
[project.entry-points.hatch]
30-
decorators = "reqstool_python_hatch_plugin.hooks"
30+
reqstool = "reqstool_python_hatch_plugin.hooks"
3131

3232
[tool.hatch.version]
3333
source = "vcs"
@@ -52,15 +52,13 @@ addopts = [
5252
"-s",
5353
"--import-mode=importlib",
5454
"--log-cli-level=DEBUG",
55-
'-m not slow or not integration',
5655
]
5756
pythonpath = [".", "src", "tests"]
5857
testpaths = ["tests"]
5958
norecursedirs = ["tests/fixtures"]
6059
markers = [
61-
"flaky: tests that can randomly fail through no change to the code",
62-
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
6360
"integration: tests that require external resources",
61+
"e2e: end-to-end tests that run the full pipeline locally",
6462
]
6563

6664
[tool.black]

tests/e2e/__init__.py

Whitespace-only changes.

tests/e2e/reqstool_python_hatch_plugin/__init__.py

Whitespace-only changes.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Copyright © LFV
2+
import shutil
3+
import subprocess
4+
import tarfile
5+
import tempfile
6+
import venv
7+
from pathlib import Path
8+
9+
import pytest
10+
11+
FIXTURE_DIR = Path(__file__).parents[2] / "fixtures" / "test_project"
12+
DIST_DIR = Path(__file__).parents[3] / "dist"
13+
14+
# The hatch plugin appends reqstool_config.yml to the tar.gz and generates
15+
# annotations.yml on disk. requirements.yml and software_verification_cases.yml
16+
# are included via the sdist include config (docs/reqstool/**).
17+
EXPECTED_IN_TARBALL = [
18+
"reqstool_config.yml",
19+
"requirements.yml",
20+
"software_verification_cases.yml",
21+
]
22+
23+
24+
@pytest.mark.e2e
25+
def test_hatch_build_sdist_contains_reqstool_artifacts():
26+
"""hatch build (sdist) triggers the reqstool hook and bundles all artifacts.
27+
28+
Runs hatchling directly inside an isolated venv that has the local plugin wheel
29+
pre-installed, bypassing hatch's own build-env management (which can't resolve
30+
@ file:// hook dependencies reliably across pip/uv versions).
31+
"""
32+
wheels = sorted(DIST_DIR.glob("reqstool_python_hatch_plugin-*.whl"))
33+
if not wheels:
34+
pytest.skip("No local wheel found — run `hatch build --target wheel` first")
35+
36+
with tempfile.TemporaryDirectory() as tmpdir:
37+
tmp_project = Path(tmpdir) / "test_project"
38+
shutil.copytree(FIXTURE_DIR, tmp_project, ignore=shutil.ignore_patterns("dist", "build", "__pycache__"))
39+
40+
# Build an isolated venv with hatchling + the local plugin wheel.
41+
# We call hatchling directly so we fully control what's installed.
42+
venv_dir = Path(tmpdir) / "build-venv"
43+
venv.create(str(venv_dir), with_pip=True)
44+
python = str(venv_dir / "bin" / "python")
45+
46+
subprocess.run(
47+
[python, "-m", "pip", "install", "--quiet", "hatchling", str(wheels[-1])],
48+
check=True,
49+
)
50+
51+
result = subprocess.run(
52+
[python, "-m", "hatchling", "build", "--target", "sdist"],
53+
cwd=tmp_project,
54+
capture_output=True,
55+
text=True,
56+
)
57+
assert result.returncode == 0, f"hatchling build failed:\n{result.stderr}"
58+
59+
tarballs = sorted((tmp_project / "dist").glob("mypackage-*.tar.gz"))
60+
assert tarballs, "No tarball found in dist/"
61+
62+
with tarfile.open(tarballs[-1]) as tf:
63+
names = tf.getnames()
64+
for expected in EXPECTED_IN_TARBALL:
65+
assert any(
66+
expected in n for n in names
67+
), f"{expected!r} missing from {tarballs[-1].name};\ngot: {names}"
68+
69+
# annotations.yml is generated on disk (not bundled in the tarball)
70+
annotations_file = tmp_project / "build" / "reqstool" / "annotations.yml"
71+
assert annotations_file.exists(), f"annotations.yml not generated at {annotations_file}"
72+
annotations_content = annotations_file.read_text()
73+
assert "REQ_001" in annotations_content, "annotations.yml missing REQ_001"
74+
assert "SVC_001" in annotations_content, "annotations.yml missing SVC_001"

tests/integration/__init__.py

Whitespace-only changes.

tests/integration/reqstool_python_hatch_plugin/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)