Coverage for tests / integration / test_actionlint_integration.py: 90%
49 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
1"""Integration tests for actionlint tool."""
3from __future__ import annotations
5import subprocess
6from pathlib import Path
8import pytest
9from assertpy import assert_that
10from loguru import logger
12from lintro.plugins import ToolRegistry
14logger.remove()
15logger.add(lambda msg: print(msg, end=""), level="INFO")
18def actionlint_available() -> bool:
19 """Return True if the `actionlint` binary is available on PATH.
21 Returns:
22 bool: True when `actionlint -version` succeeds, False otherwise.
23 """
24 try:
25 proc = subprocess.run(
26 ["actionlint", "-version"],
27 capture_output=True,
28 text=True,
29 )
30 return proc.returncode == 0
31 except FileNotFoundError:
32 return False
35@pytest.mark.actionlint
36def test_actionlint_available() -> None:
37 """Skip the suite if actionlint is not present locally.
39 Ensures local runs behave like CI (which always has actionlint in Docker),
40 but do not fail when developers don't have actionlint installed.
41 """
42 if not actionlint_available():
43 pytest.skip("actionlint not available")
46SAMPLE_BAD = Path("test_samples/tools/config/github_actions/actionlint_violations.yml")
49@pytest.mark.actionlint
50def test_actionlint_reports_violations(tmp_path: Path) -> None:
51 """Assert that Lintro detects violations reported by actionlint.
53 Args:
54 tmp_path: Temporary directory provided by pytest.
55 """
56 if not actionlint_available():
57 pytest.skip("actionlint not available")
58 wf_dir = tmp_path / ".github" / "workflows"
59 wf_dir.mkdir(parents=True, exist_ok=True)
60 wf = wf_dir / "workflow_bad.yml"
61 wf.write_text(SAMPLE_BAD.read_text())
62 proc = subprocess.run(["actionlint", str(wf)], capture_output=True, text=True)
63 direct_out = proc.stdout + proc.stderr
64 logger.info(f"[LOG] actionlint stdout+stderr:\n{direct_out}")
66 assert_that(proc.returncode).is_not_equal_to(0)
67 tool = ToolRegistry.get("actionlint")
68 assert_that(tool).is_not_none()
69 result = tool.check([str(tmp_path)], {})
70 logger.info(f"[LOG] lintro actionlint issues: {result.issues_count}")
71 assert_that(result.issues_count > 0).is_true()
72 assert_that(result.success).is_false()
75@pytest.mark.actionlint
76def test_actionlint_no_files(tmp_path: Path) -> None:
77 """Assert that Lintro succeeds when no workflow files are present.
79 Args:
80 tmp_path: Temporary directory provided by pytest.
81 """
82 if not actionlint_available():
83 pytest.skip("actionlint not available")
84 empty = tmp_path / "empty"
85 empty.mkdir()
86 tool = ToolRegistry.get("actionlint")
87 assert_that(tool).is_not_none()
88 result = tool.check([str(empty)], {})
89 assert_that(result.success).is_true()
90 assert_that(result.issues_count).is_equal_to(0)