Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@ modules/
common/ # cli.py, properties.py, utils.py — shared helpers
setup/ # properties.py — creates properties.yml (no-op if it exists), called by setup.sh/setup.ps1; templates/properties/*.yml — tier fragments
tasks/
__init__.py # Wires the invoke Collection (debug, ruff, setup, tests) plus top-level aliases (fix, test)
combos.py # Top-level aliases: fix, test
debug.py # debug.env — print cwd + sorted env vars
ruff.py # ruff.fix, ruff.format
setup.py # setup.properties — creates/stamps properties.yml
tests.py # tests.actionlint, tests.pylint, tests.pytest, tests.rufflint, tests.yamllint
__init__.py # Wires the invoke Collection: common/ and tests/ (registered at their original top-level names — debug, ruff, setup, tests, plus bare fix/test — not nested under common.*/tests.* prefixes)
common/
main.py # Top-level aliases: fix, test (was combos.py)
debug.py # debug.env — print cwd + sorted env vars
ruff.py # ruff.fix, ruff.format
setup.py # setup.properties — creates/stamps properties.yml
tests/ # One file per check (actionlint.py, pylint.py, pytest.py, rufflint.py, yamllint.py) — still one flat tests.* namespace: tests.actionlint, tests.pylint, tests.pytest, tests.rufflint, tests.yamllint
.github/
copilot-instructions.md # What this repo is, for GitHub Copilot
workflows/
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ docstring-code-line-length = "dynamic"
[tool.pytest.ini_options]
testpaths = ["tests"]
norecursedirs = ["tmp", ".venv", ".ruff_cache", "__pycache__"]
markers = [
"setup: modules/setup/ (properties.yml bootstrap) — tests/setup/",
"style: Markdown/doc style checks — tests/style/",
]

[tool.pylint.main]
py-version = "3.14"
Expand Down
26 changes: 14 additions & 12 deletions tasks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,23 @@
if str(_REPO_ROOT) not in sys.path:
sys.path.insert(0, str(_REPO_ROOT))

from . import ( # noqa: E402 # pylint: disable=wrong-import-position
combos,
debug,
ruff,
setup,
tests,
)
from .common import debug, ruff, setup # noqa: E402 # pylint: disable=wrong-import-position
from .common import main as common_main # noqa: E402 # pylint: disable=wrong-import-position
from .tests import namespace as tests_namespace # noqa: E402 # pylint: disable=wrong-import-position

namespace = Collection()
namespace.configure({"auto_dash_names": False})
namespace = Collection(auto_dash_names=False)

# `common/` and `tests/` are the only two subpackages here — `tasks/` in this base template is
# deliberately as small as possible (debug/ruff/setup + the fix/test aliases, plus the tests
# themselves), everything project-specific (repo/template sync, AI-agent tooling, versioning)
# lives downstream in template_ai_python instead. Both stay registered at their original
# top-level names (`debug.*`, `ruff.*`, `setup.*`, `tests.*`, plus bare `fix`/`test`) rather than
# nested under `common.*`/`tests.*` prefixes that don't exist — every repo that clones this
# template inherits that exact CLI surface.
namespace.add_collection(debug, name="debug")
namespace.add_collection(ruff, name="ruff")
namespace.add_collection(setup, name="setup")
namespace.add_collection(tests, name="tests")
namespace.add_collection(tests_namespace, name="tests")

namespace.add_task(combos.fix, name="fix")
namespace.add_task(combos.test, name="test")
namespace.add_task(common_main.fix, name="fix")
namespace.add_task(common_main.test, name="test")
20 changes: 0 additions & 20 deletions tasks/combos.py

This file was deleted.

Empty file added tasks/common/__init__.py
Empty file.
File renamed without changes.
21 changes: 21 additions & 0 deletions tasks/common/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from invoke import task

from ..tests import actionlint, pylint, pytest, rufflint, yamllint
from . import ruff


@task
def fix(context):
"""Run All Automated Fixes"""
ruff.fix(context)
ruff.format(context)


@task
def test(context):
"""Run All Tests"""
actionlint(context)
pylint(context)
pytest(context)
rufflint(context)
yamllint(context)
File renamed without changes.
File renamed without changes.
53 changes: 0 additions & 53 deletions tasks/tests.py

This file was deleted.

21 changes: 21 additions & 0 deletions tasks/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""`tests` collection — one file per check (was a single flat `tasks/tests.py`), still registered
as one flat `tests.*` namespace (`tests.actionlint`, `tests.pytest`, etc.) so nothing that calls
these tasks needs to change. Re-exports each task function at package level too, so
`tasks/common/main.py`'s `test` task can keep calling `actionlint(context)` etc. exactly like it
did when this was one file.
"""

from invoke import Collection

from .actionlint import actionlint
from .pylint import pylint
from .pytest import run_pytest as pytest
from .rufflint import rufflint
from .yamllint import yamllint

namespace = Collection(auto_dash_names=False)
namespace.add_task(actionlint, name="actionlint")
namespace.add_task(pylint, name="pylint")
namespace.add_task(pytest, name="pytest")
namespace.add_task(rufflint, name="rufflint")
namespace.add_task(yamllint, name="yamllint")
10 changes: 10 additions & 0 deletions tasks/tests/actionlint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from invoke import task


@task
def actionlint(context):
"""Run Action Lint"""
print("\n------------")
print("Action Lint")
print("------------\n")
context.run("actionlint")
10 changes: 10 additions & 0 deletions tasks/tests/pylint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from invoke import task


@task
def pylint(context):
"""Run PyLint on Entire Repo"""
print("\n------------")
print("Pylint Lint")
print("------------\n")
context.run("pylint --verbose --rcfile=pyproject.toml .")
10 changes: 10 additions & 0 deletions tasks/tests/pytest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from invoke import task


@task(name="pytest")
def run_pytest(context, scope=None):
"""Run Pytest Unit Test Suite (pass scope=<marker-expr> to run a subset, e.g. scope=setup or scope="not style")"""
print("\n------------")
print("Pytest")
print("------------\n")
context.run(f'pytest -m "{scope}"' if scope else "pytest")
10 changes: 10 additions & 0 deletions tasks/tests/rufflint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from invoke import task


@task
def rufflint(context):
"""Run Ruff Linter on Entire Repo"""
print("\n------------")
print("Ruff Lint")
print("------------\n")
context.run("ruff check .")
17 changes: 17 additions & 0 deletions tasks/tests/yamllint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from invoke import task


@task
def yamllint(context):
"""Run Yaml Linter on Entire Repo"""
print("\n------------")
print("Yaml Lint")
print("------------\n")
context.run(
"""
yamllint --list-files -c .yamllint . &&
echo '------------' &&
echo -e &&
yamllint -f parsable -c .yamllint .
"""
)
Empty file added tests/setup/__init__.py
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

from modules.setup import properties as setup_props

pytestmark = pytest.mark.setup


def _template_lines() -> list[str]:
return setup_props._build_initial_content().splitlines(keepends=True) # pylint: disable=protected-access
Expand Down
Empty file added tests/style/__init__.py
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@

from pathlib import Path

REPO_ROOT = Path(__file__).resolve().parents[1]
import pytest

pytestmark = pytest.mark.style

REPO_ROOT = Path(__file__).resolve().parents[2]
INSTRUCTIONS_DIR = REPO_ROOT / ".github" / "instructions"


Expand Down