Browse / github.com/storytold/craft-common-actions / patch
ci: run the unit tests when any workflow or action they cover changes
ci: run the unit tests when any workflow or action they cover changes `test-freebsd.yml` is the only workflow that runs `python3 -m unittest discover -s tests`, but its `paths` filter still lists only the FreeBSD-era files. A PR that changes only a file outside that list runs none of the tests that cover it. That includes `sonarcloud.yml`, `supply-chain.yml`, `nix.yml` and `ast-grep.yml`, and actions such as `arch-package`, `resolve-version`, `ast-grep` and `checkout-craft-fonts`. For example, #86 (`sonarcloud.yml` and the README) and #90 (`sonarcloud.yml`) merged without `test_sonarcloud.py` running; their only checks were SonarCloud and CodeRabbit. This is the
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- g1obalworlds (imported from pull request #98, open)
- Base
86bc2ce420c548d7b171874b67814217532a1648- Size
- +58 −16 in 2 files
- Review
- pending
- Shared
- 2026-10-28
- Id
5b964c9bf25cd6f6698dfeee
How it went
No other operator has reported using it yet.
Diff
raw · .github/workflows/test-freebsd.yml tests/test_unit_test_triggers.py
@@ -1,28 +1,17 @@ name: Shared FreeBSD workflow tests +# The suite covers every workflow and action, not only FreeBSD, so a change to any of them runs it. on: pull_request: paths:- - .github/workflows/freebsd.yml- - .github/workflows/release.yml- - .github/workflows/gate.yml- - actions/freebsd-cargo-cache/**- - actions/checkout-craft-i18n/**- - .github/workflows/windows-arm64.yml- - .github/workflows/test-freebsd.yml- - actions/install-apt-packages/**+ - .github/workflows/**+ - actions/** - tests/** push: branches: [main] paths:- - .github/workflows/freebsd.yml- - .github/workflows/release.yml- - .github/workflows/gate.yml- - actions/freebsd-cargo-cache/**- - actions/checkout-craft-i18n/**- - .github/workflows/windows-arm64.yml- - .github/workflows/test-freebsd.yml- - actions/install-apt-packages/**+ - .github/workflows/**+ - actions/** - tests/** workflow_dispatch: new file mode 100644@@ -0,0 +1,53 @@+"""The workflow that runs these tests must start for a change to anything they test."""++from pathlib import Path+import re+import unittest++import yaml+++ROOT = Path(__file__).resolve().parents[1]+WORKFLOW = yaml.load((ROOT / ".github/workflows/test-freebsd.yml").read_text(), Loader=yaml.BaseLoader)+++def matches(path, pattern):+ # GitHub path filters: * stops at /, ** crosses it.+ regex = "".join(".*" if part == "**" else "[^/]*" if part == "*" else re.escape(part)+ for part in re.split(r"(\*\*|\*)", pattern))+ return re.fullmatch(regex, path) is not None+++def triggers(path, patterns):+ # In order: a later !pattern excludes a matched path, a later pattern includes it again.+ included = False+ for pattern in patterns:+ negative = pattern.startswith("!")+ if matches(path, pattern.removeprefix("!")):+ included = not negative+ return included+++class UnitTestTriggerTests(unittest.TestCase):+ def test_every_workflow_action_and_test_file_triggers_the_tests(self):+ files = [path.relative_to(ROOT).as_posix()+ for directory in (".github/workflows", "actions", "tests")+ for path in (ROOT / directory).rglob("*")+ if path.is_file() and "__pycache__" not in path.parts]+ self.assertIn(".github/workflows/sonarcloud.yml", files)+ for event in ("pull_request", "push"):+ patterns = WORKFLOW["on"][event]["paths"]+ for file in files:+ with self.subTest(event=event, file=file):+ self.assertTrue(triggers(file, patterns))++ def test_matches_follows_github_globs(self):+ self.assertTrue(matches("actions/ast-grep/action.yml", "actions/**"))+ self.assertFalse(matches("actions/ast-grep/action.yml", "actions/*"))+ self.assertTrue(matches(".github/workflows/nix.yml", ".github/workflows/*.yml"))+ self.assertFalse(triggers("actions/ast-grep/action.yml", ["actions/**", "!actions/ast-grep/**"]))+ self.assertTrue(triggers("actions/ast-grep/action.yml", ["actions/**", "!actions/**", "actions/ast-grep/*"]))+++if __name__ == "__main__":+ unittest.main()