From fdbce98be601c31ef2ad6cc7e426ae7e53ffa4e0 Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Thu, 30 Oct 2025 10:02:17 -0400 Subject: [PATCH] CICD now is aligned with pre-commit. Signed-off-by: Cliff Hill --- .gitea/workflows/cicd.yml | 178 ++++++++------------------------------ .pre-commit-config.yaml | 30 +++---- Dockerfile.cicd | 10 ++- backend/pyproject.toml | 1 + 4 files changed, 63 insertions(+), 156 deletions(-) diff --git a/.gitea/workflows/cicd.yml b/.gitea/workflows/cicd.yml index 69eea32..dfceee8 100644 --- a/.gitea/workflows/cicd.yml +++ b/.gitea/workflows/cicd.yml @@ -96,23 +96,12 @@ jobs: steps: - name: Login to Gitea Container Registry run: echo "${{ secrets.PACKAGE_ACCESS_TOKEN }}" | docker login dogar.darkhelm.org -u ${{ github.actor }} --password-stdin - - name: Check trailing whitespace + - name: Check trailing whitespace with pre-commit run: | docker pull dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} docker run --rm dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} bash -c " cd /workspace && - if find . -type f \( -name '*.js' -o -name '*.ts' -o -name '*.vue' -o -name '*.json' -o -name '*.yml' -o -name '*.yaml' -o -name '*.py' -o -name '*.md' -o -name '*.txt' -o -name '*.sh' \) \ - -not -path '*/node_modules/*' \ - -not -path '*/.venv/*' \ - -not -path '*/__pycache__/*' \ - -not -path '*/.git/*' \ - -not -path '*/.yarn/*' \ - -exec grep -l '[[:space:]]$' {} \; 2>/dev/null | head -10; then - echo 'ERROR: Trailing whitespace found' - exit 1 - else - echo '✓ No trailing whitespace found' - fi + pre-commit run trailing-whitespace --all-files --show-diff-on-failure " end-of-file-fixer: @@ -122,23 +111,12 @@ jobs: steps: - name: Login to Gitea Container Registry run: echo "${{ secrets.PACKAGE_ACCESS_TOKEN }}" | docker login dogar.darkhelm.org -u ${{ github.actor }} --password-stdin - - name: Check end of file + - name: Check end of file with pre-commit run: | docker pull dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} docker run --rm dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} bash -c " cd /workspace && - find . -type f \( -name '*.py' -o -name '*.ts' -o -name '*.js' -o -name '*.vue' -o -name '*.yml' -o -name '*.yaml' -o -name '*.toml' -o -name '*.json' -o -name '*.md' \) \ - -not -path '*/node_modules/*' \ - -not -path '*/.venv/*' \ - -not -path '*/__pycache__/*' \ - -not -path '*/.git/*' \ - -not -path '*/.yarn/*' | while read file; do - if [ -s \"\$file\" ] && [ \"\$(tail -c1 \"\$file\" | wc -l)\" -eq 0 ]; then - echo \"ERROR: \$file does not end with newline\" - exit 1 - fi - done && - echo '✓ All files end with newline' + pre-commit run end-of-file-fixer --all-files --show-diff-on-failure " check-yaml: @@ -148,26 +126,12 @@ jobs: steps: - name: Login to Gitea Container Registry run: echo "${{ secrets.PACKAGE_ACCESS_TOKEN }}" | docker login dogar.darkhelm.org -u ${{ github.actor }} --password-stdin - - name: Check YAML files + - name: Check YAML files with pre-commit run: | docker pull dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} docker run --rm dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} bash -c " - cd /workspace/backend && - source .venv/bin/activate && cd /workspace && - find . -type f \( -name '*.yml' -o -name '*.yaml' \) \ - -not -path '*/node_modules/*' \ - -not -path '*/.venv/*' \ - -not -path '*/__pycache__/*' \ - -not -path '*/.git/*' \ - -not -path '*/.yarn/*' | while read file; do - echo \"Linting \$file...\" - if ! uv run yamllint \"\$file\"; then - echo \"ERROR: YAML lint failed for \$file\" - exit 1 - fi - done && - echo '✓ All YAML files passed yamllint' + pre-commit run check-yaml --all-files --show-diff-on-failure " check-toml: @@ -177,26 +141,12 @@ jobs: steps: - name: Login to Gitea Container Registry run: echo "${{ secrets.PACKAGE_ACCESS_TOKEN }}" | docker login dogar.darkhelm.org -u ${{ github.actor }} --password-stdin - - name: Check TOML files + - name: Check TOML files with pre-commit run: | docker pull dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} docker run --rm dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} bash -c " - cd /workspace/backend && - source .venv/bin/activate && cd /workspace && - find . -type f -name '*.toml' \ - -not -path '*/node_modules/*' \ - -not -path '*/.venv/*' \ - -not -path '*/__pycache__/*' \ - -not -path '*/.git/*' \ - -not -path '*/.yarn/*' | while read file; do - echo \"Checking \$file syntax...\" - if ! python3 -c 'import tomllib, sys; tomllib.load(open(sys.argv[1], \"rb\"))' \"\$file\" 2>/dev/null; then - echo \"ERROR: Invalid TOML syntax in \$file\" - exit 1 - fi - done && - echo '✓ All TOML files have valid syntax' + pre-commit run check-toml --all-files --show-diff-on-failure " mixed-line-ending: @@ -206,22 +156,12 @@ jobs: steps: - name: Login to Gitea Container Registry run: echo "${{ secrets.PACKAGE_ACCESS_TOKEN }}" | docker login dogar.darkhelm.org -u ${{ github.actor }} --password-stdin - - name: Check line endings + - name: Check line endings with pre-commit run: | docker pull dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} docker run --rm dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} bash -c " cd /workspace && - if find . -type f \( -name '*.py' -o -name '*.ts' -o -name '*.js' -o -name '*.vue' -o -name '*.yml' -o -name '*.yaml' -o -name '*.toml' -o -name '*.json' -o -name '*.md' \) \ - -not -path '*/node_modules/*' \ - -not -path '*/.venv/*' \ - -not -path '*/__pycache__/*' \ - -not -path '*/.git/*' \ - -not -path '*/.yarn/*' | xargs file | grep -i 'crlf'; then - echo 'ERROR: Mixed line endings found (CRLF detected)' - exit 1 - else - echo '✓ Consistent line endings (LF)' - fi + pre-commit run mixed-line-ending --all-files --show-diff-on-failure " toml-lint: @@ -231,42 +171,12 @@ jobs: steps: - name: Login to Gitea Container Registry run: echo "${{ secrets.PACKAGE_ACCESS_TOKEN }}" | docker login dogar.darkhelm.org -u ${{ github.actor }} --password-stdin - - name: Check TOML formatting + - name: Check TOML formatting with pre-commit run: | docker pull dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} docker run --rm dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} bash -c " - cd /workspace/backend && - source .venv/bin/activate && cd /workspace && - echo 'Checking TOML formatting (fails if changes needed)...' && - format_needed=false && - for file in \$(find . -type f -name '*.toml' \ - -not -path '*/node_modules/*' \ - -not -path '*/.venv/*' \ - -not -path '*/__pycache__/*' \ - -not -path '*/.git/*' \ - -not -path '*/.yarn/*'); do - echo \"Checking TOML format: \$file\" - # Create a temporary formatted version - temp_file=\"\$file.tmp\" - uv run pretty-format-toml \"\$file\" > \"\$temp_file\" 2>/dev/null || { - echo \"ERROR: Failed to format \$file\" - rm -f \"\$temp_file\" - exit 1 - } - # Compare original with formatted version - if ! diff -q \"\$file\" \"\$temp_file\" >/dev/null 2>&1; then - echo \"ERROR: \$file needs formatting\" - echo \"Diff:\" - diff \"\$file\" \"\$temp_file\" || true - format_needed=true - fi - rm -f \"\$temp_file\" - done && - if [ \"\$format_needed\" = \"true\" ]; then - exit 1 - fi && - echo '✓ All TOML files are properly formatted' + pre-commit run pretty-format-toml --all-files --show-diff-on-failure " # Backend Python checks @@ -277,14 +187,12 @@ jobs: steps: - name: Login to Gitea Container Registry run: echo "${{ secrets.PACKAGE_ACCESS_TOKEN }}" | docker login dogar.darkhelm.org -u ${{ github.actor }} --password-stdin - - name: Run ruff linting + - name: Run ruff linting with pre-commit run: | docker pull dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} docker run --rm dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} bash -c " - cd /workspace/backend && - source .venv/bin/activate && - echo 'Running ruff check (no auto-fix)...' && - uv run ruff check . --config=pyproject.toml + cd /workspace && + pre-commit run ruff --all-files --show-diff-on-failure " ruff-format: @@ -294,14 +202,12 @@ jobs: steps: - name: Login to Gitea Container Registry run: echo "${{ secrets.PACKAGE_ACCESS_TOKEN }}" | docker login dogar.darkhelm.org -u ${{ github.actor }} --password-stdin - - name: Check ruff formatting + - name: Check ruff formatting with pre-commit run: | docker pull dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} docker run --rm dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} bash -c " - cd /workspace/backend && - source .venv/bin/activate && - echo 'Checking ruff formatting (fails if changes needed)...' && - uv run ruff format --check . --config=pyproject.toml + cd /workspace && + pre-commit run ruff-format --all-files --show-diff-on-failure " pyright: @@ -311,13 +217,12 @@ jobs: steps: - name: Login to Gitea Container Registry run: echo "${{ secrets.PACKAGE_ACCESS_TOKEN }}" | docker login dogar.darkhelm.org -u ${{ github.actor }} --password-stdin - - name: Run pyright type checking + - name: Run pyright type checking with pre-commit run: | docker pull dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} docker run --rm dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} bash -c " - cd /workspace/backend && - source .venv/bin/activate && - uv run pyright + cd /workspace && + pre-commit run pyright --all-files --show-diff-on-failure " darglint: @@ -327,13 +232,12 @@ jobs: steps: - name: Login to Gitea Container Registry run: echo "${{ secrets.PACKAGE_ACCESS_TOKEN }}" | docker login dogar.darkhelm.org -u ${{ github.actor }} --password-stdin - - name: Run darglint docstring linting + - name: Run darglint docstring linting with pre-commit run: | docker pull dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} docker run --rm dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} bash -c " - cd /workspace/backend && - source .venv/bin/activate && - uv run darglint src/ + cd /workspace && + pre-commit run darglint --all-files --show-diff-on-failure " no-docstring-types: @@ -343,14 +247,12 @@ jobs: steps: - name: Login to Gitea Container Registry run: echo "${{ secrets.PACKAGE_ACCESS_TOKEN }}" | docker login dogar.darkhelm.org -u ${{ github.actor }} --password-stdin - - name: Check for types in docstrings + - name: Run no docstring types check with pre-commit run: | docker pull dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} docker run --rm dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} bash -c " cd /workspace && - echo 'Checking backend Python files for types in docstrings...' && - find backend/src -name '*.py' -type f | xargs python3 scripts/check_no_docstring_types.py && - echo '✓ No prohibited types found in docstrings' + pre-commit run no-docstring-types --all-files --show-diff-on-failure " # Frontend checks @@ -361,13 +263,12 @@ jobs: steps: - name: Login to Gitea Container Registry run: echo "${{ secrets.PACKAGE_ACCESS_TOKEN }}" | docker login dogar.darkhelm.org -u ${{ github.actor }} --password-stdin - - name: Run ESLint + - name: Run ESLint with pre-commit run: | docker pull dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} docker run --rm dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} bash -c " - cd /workspace/frontend && - echo 'Running ESLint check (no auto-fix)...' && - yarn eslint . --max-warnings=0 + cd /workspace && + pre-commit run eslint --all-files --show-diff-on-failure " prettier: @@ -377,13 +278,12 @@ jobs: steps: - name: Login to Gitea Container Registry run: echo "${{ secrets.PACKAGE_ACCESS_TOKEN }}" | docker login dogar.darkhelm.org -u ${{ github.actor }} --password-stdin - - name: Check Prettier formatting + - name: Check Prettier formatting with pre-commit run: | docker pull dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} docker run --rm dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} bash -c " - cd /workspace/frontend && - echo 'Checking Prettier formatting (fails if changes needed)...' && - yarn format:check + cd /workspace && + pre-commit run prettier --all-files --show-diff-on-failure " typescript-check: @@ -393,12 +293,12 @@ jobs: steps: - name: Login to Gitea Container Registry run: echo "${{ secrets.PACKAGE_ACCESS_TOKEN }}" | docker login dogar.darkhelm.org -u ${{ github.actor }} --password-stdin - - name: Run TypeScript type checking + - name: Run TypeScript type checking with pre-commit run: | docker pull dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} docker run --rm dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} bash -c " - cd /workspace/frontend && - yarn type-check + cd /workspace && + pre-commit run typescript-check --all-files --show-diff-on-failure " tsdoc-lint: @@ -408,14 +308,12 @@ jobs: steps: - name: Login to Gitea Container Registry run: echo "${{ secrets.PACKAGE_ACCESS_TOKEN }}" | docker login dogar.darkhelm.org -u ${{ github.actor }} --password-stdin - - name: Run TSDoc linting + - name: Run TSDoc linting with pre-commit run: | docker pull dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} docker run --rm dogar.darkhelm.org/darkhelm.org/plex-playlist/cicd:${GITHUB_SHA:-latest} bash -c " - cd /workspace/frontend && - echo 'Running TSDoc linting check...' && - # Use eslint directly without --fix to check TSDoc - yarn eslint . --ext .ts,.vue --max-warnings=0 --no-fix + cd /workspace && + pre-commit run tsdoc-lint --all-files --show-diff-on-failure " # Unit tests with coverage diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 41c5c75..413a9e3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,30 +26,29 @@ repos: # Linter - id: ruff name: ruff-lint - entry: backend/.venv/bin/ruff check --fix + entry: bash -c 'cd backend && uv run ruff check --fix . --config=pyproject.toml' language: system files: ^backend/ types: [python] - args: [--config=backend/pyproject.toml] + pass_filenames: false # Formatter - id: ruff-format name: ruff-format - entry: backend/.venv/bin/ruff format + entry: bash -c 'cd backend && uv run ruff format . --config=pyproject.toml' language: system files: ^backend/ types: [python] - args: [--config=backend/pyproject.toml] + pass_filenames: false # Python type checking with pyright - repo: local hooks: - id: pyright name: pyright - entry: backend/.venv/bin/pyright + entry: bash -c 'cd backend && uv run pyright . --project=.' language: system files: ^backend/ types: [python] - args: [--pythonpath=backend/.venv/bin/python, backend] pass_filenames: false # Python docstring linting with darglint @@ -57,10 +56,11 @@ repos: hooks: - id: darglint name: darglint - entry: backend/.venv/bin/darglint + entry: bash -c 'cd backend && find . -name "*.py" -not -path "./.venv/*" -exec uv run darglint {} \;' language: system files: ^backend/.*\.py$ types: [python] + pass_filenames: false # Custom hook to enforce no types in docstrings - repo: local @@ -75,34 +75,34 @@ repos: # Frontend linting and formatting - repo: local hooks: - # ESLint (basic linting only for now) + # ESLint with auto-fix for pre-commit (CI uses --no-fix) - id: eslint name: eslint - entry: bash -c 'cd frontend && npm run lint:fix' + entry: bash -c 'cd frontend && yarn eslint . --fix' language: system files: ^frontend/.*\.(js|ts|vue)$ pass_filenames: false - # Prettier + # Prettier with auto-format for pre-commit (CI uses --check) - id: prettier name: prettier - entry: bash -c 'cd frontend && npm run format' + entry: bash -c 'cd frontend && yarn prettier --write src/' language: system files: ^frontend/.*\.(js|ts|vue|json|css|scss|md)$ pass_filenames: false - # TypeScript type checking + # TypeScript type checking (same as CI) - id: typescript-check name: typescript-check - entry: bash -c 'cd frontend && npm run type-check' + entry: bash -c 'cd frontend && yarn vue-tsc --noEmit' language: system files: ^frontend/.*\.(ts|vue)$ pass_filenames: false - # TSDoc linting + # TSDoc linting with auto-fix for pre-commit (CI uses --no-fix) - id: tsdoc-lint name: tsdoc-lint - entry: bash -c 'cd frontend && npm run lint:tsdoc' + entry: bash -c 'cd frontend && yarn eslint . --ext .ts,.vue --fix' language: system files: ^frontend/.*\.(ts|vue)$ pass_filenames: false diff --git a/Dockerfile.cicd b/Dockerfile.cicd index 60d9f45..dedceac 100644 --- a/Dockerfile.cicd +++ b/Dockerfile.cicd @@ -141,6 +141,13 @@ RUN uv sync --dev # Install backend package in development mode RUN uv pip install -e . +# Install pre-commit environments for CI validation +WORKDIR /workspace +RUN cd /workspace && \ + echo "=== Installing Pre-commit Hook Environments ===" && \ + uv run pre-commit install-hooks && \ + echo "✓ Pre-commit hook environments installed successfully" + # Set up frontend dependencies WORKDIR /workspace/frontend @@ -188,7 +195,8 @@ RUN cd /workspace/backend && \ uv run pytest --version && \ uv run yamllint --version && \ uv run toml-sort --version && \ - uv run xdoctest --version + uv run xdoctest --version && \ + uv run pre-commit --version RUN cd /workspace/frontend && \ echo "=== Frontend Tools Verification ===" && \ diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 9d73a52..ec59df5 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -14,6 +14,7 @@ dev = [ "httpx>=0.25.0", # For testing async HTTP calls "pytest-mock>=3.12.0", # File format and linting tools + "pre-commit>=3.0.0", # For running pre-commit hooks in CI "pyyaml>=6.0", "yamllint>=1.35.0", "toml-sort>=0.23.0",