add .github\workflows\actionlint.yml #11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ============================================================ | |
| # .github/workflows/ci-org.yml (Continuous Integration) | |
| # ============================================================ | |
| # WHY-FILE: Validate repository hygiene and documentation builds. | |
| # REQ: Any check that can be run locally MUST be available locally via pre-commit. | |
| # REQ: CI MUST NOT introduce arbitrary rules that are not reproducible locally. | |
| # OBS: CI validates only; it never edits files or deploys docs. | |
| # OBS: Optional tools (ruff, pyright, deptry, pytest, mkdocs) run only if configured. | |
| name: CI | |
| # WHY: Validate docs and repo metadata on PRs and pushes. | |
| # OBS: This workflow validates only; it never deploys. | |
| on: | |
| push: | |
| branches: [main] # WHY: Run when pushing to main branch. | |
| pull_request: | |
| branches: [main] # WHY: Run on pull requests targeting main branch. | |
| workflow_dispatch: # WHY: Allow manual triggering from Actions tab. | |
| workflow_call: # WHY: Allow calling from other repos in this org. | |
| permissions: # WHY: Use least privileges required. | |
| contents: read | |
| env: | |
| PYTHONUNBUFFERED: "1" # WHY: Real-time logging. | |
| PYTHONIOENCODING: "utf-8" # WHY: Ensure UTF-8 encoding for international characters. | |
| jobs: | |
| ci: | |
| name: CI checks | |
| runs-on: ubuntu-latest # WHY: Linux environment matches most production deployments. | |
| timeout-minutes: 30 # WHY: Prevent hanging jobs. If over, it is likely stuck. | |
| steps: | |
| # ============================================================ | |
| # ASSEMBLE: Get code and set up environment | |
| # ============================================================ | |
| - name: A1) Checkout repository code | |
| # WHY: Needed to access files for all subsequent checks. | |
| uses: actions/checkout@v6 | |
| - name: A2) Run pre-commit (all files) | |
| # WHY: Single source of truth for locally runnable quality gates. | |
| # OBS: Fails if hooks would modify files; does not commit changes. | |
| id: precommit | |
| uses: pre-commit/action@v3.0.1 | |
| with: | |
| extra_args: --all-files | |
| - name: A2f) If pre-commit failed, show local fix instructions | |
| if: failure() | |
| run: | | |
| echo "## Pre-commit failed" >> "$GITHUB_STEP_SUMMARY" | |
| echo "Run pre-commit locally and commit the resulting changes." >> "$GITHUB_STEP_SUMMARY" | |
| - name: A3) Install uv (with caching) | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: "uv.lock" # WHY: Only re-cache when dependencies change. | |
| - name: A4) Install Python 3.14 | |
| run: uv python install 3.14 | |
| - name: A5) Sync to install all dependencies | |
| run: uv sync --extra dev --extra docs --upgrade | |
| # ============================================================ | |
| # BASELINE CHECKS: Validate project metadata and code quality | |
| # ============================================================ | |
| - name: B1) Validate pyproject.toml structure | |
| run: uvx validate-pyproject | |
| - name: B2) Ruff format check (if configured) | |
| # OBS: Skipped if [tool.ruff] is not present in pyproject.toml. | |
| run: | | |
| if grep -q "\[tool\.ruff\]" pyproject.toml; then | |
| uv run ruff format --check --diff . | |
| else | |
| echo "No ruff config found; skipping format check." | |
| fi | |
| - name: B3) Ruff lint check (if configured) | |
| # OBS: Skipped if [tool.ruff] is not present in pyproject.toml. | |
| run: | | |
| if grep -q "\[tool\.ruff\]" pyproject.toml; then | |
| uv run ruff check . | |
| else | |
| echo "No ruff config found; skipping lint check." | |
| fi | |
| - name: B4) Pyright type check (if configured) | |
| # OBS: Skipped if [tool.pyright] is not present in pyproject.toml. | |
| run: | | |
| if grep -q "\[tool\.pyright\]" pyproject.toml; then | |
| uv run pyright | |
| else | |
| echo "No pyright config found; skipping type check." | |
| fi | |
| - name: B5) Deptry dependency check (if configured) | |
| # OBS: Skipped if [tool.deptry] is not present in pyproject.toml. | |
| run: | | |
| if grep -q "\[tool\.deptry\]" pyproject.toml; then | |
| uvx deptry . | |
| else | |
| echo "No deptry config found; skipping dependency check." | |
| fi | |
| # ============================================================ | |
| # COVERAGE AND TESTS: Verify functionality | |
| # ============================================================ | |
| - name: C1) Run pytest with coverage (if tests exist) | |
| # OBS: Skipped if no test files found under tests/. | |
| run: | | |
| if [ -d "tests" ] && [ -n "$(find tests -name 'test_*.py' -o -name '*_test.py' 2>/dev/null)" ]; then | |
| uv run pytest --cov-report=xml | |
| else | |
| echo "No tests found; skipping pytest." | |
| echo "## No Tests Found" >> "$GITHUB_STEP_SUMMARY" | |
| echo '<?xml version="1.0" ?><coverage></coverage>' > coverage.xml | |
| fi | |
| - name: C2) Add coverage to job summary (if available) | |
| if: always() | |
| run: | | |
| echo "## Test Coverage Report" >> "$GITHUB_STEP_SUMMARY" | |
| if [ -f ".coverage" ]; then | |
| echo '```' >> "$GITHUB_STEP_SUMMARY" | |
| uv run coverage report >> "$GITHUB_STEP_SUMMARY" | |
| echo '```' >> "$GITHUB_STEP_SUMMARY" | |
| else | |
| echo "No coverage data available." >> "$GITHUB_STEP_SUMMARY" | |
| fi | |
| - name: C3) Upload coverage artifact (if available) | |
| if: always() && hashFiles('coverage.xml') != '' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: coverage-report | |
| path: coverage.xml | |
| retention-days: 30 | |
| # ============================================================ | |
| # DEPLOY PRE-CHECKS: Validate docs build before any deployment | |
| # ============================================================ | |
| - name: D1) Build docs with Zensical (if zensical.toml present) | |
| run: | | |
| if [ -f "zensical.toml" ]; then | |
| uv run zensical build | |
| else | |
| echo "No zensical.toml found; skipping Zensical build." | |
| fi |