From 6eeaeb05defa6a8c2aefcd56f10240c57d795b16 Mon Sep 17 00:00:00 2001 From: Patrick Hermann Date: Thu, 28 May 2026 09:20:48 +0000 Subject: [PATCH] feat(linting): add pre-commit reusable workflow Wraps github.com/stuttgart-things/dagger/linting@v0.115.0 `run-pre-commit`, so callers don't need Python / pre-commit / hook environments on the runner. Findings are exported to a file, displayed in the log, attached as an artifact, and added to the GitHub step summary. The dagger function masks pre-commit's real exit code with `|| true`, so the reusable inspects the captured text and fails when any hook line ends in `...Failed`. A `continue-on-error` input flips this to advisory. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/call-pre-commit.yaml | 145 +++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 .github/workflows/call-pre-commit.yaml diff --git a/.github/workflows/call-pre-commit.yaml b/.github/workflows/call-pre-commit.yaml new file mode 100644 index 0000000..364099d --- /dev/null +++ b/.github/workflows/call-pre-commit.yaml @@ -0,0 +1,145 @@ +--- +name: Pre-commit Hooks with Dagger +on: + workflow_call: + inputs: + runs-on: + required: false + type: string + default: ubuntu-latest + environment-name: + required: false + type: string + default: linting + src: + description: "Path to the repo root (relative to the checkout)" + required: false + type: string + default: "." + config-path: + description: "Path to .pre-commit-config.yaml (relative to src)" + required: false + type: string + default: ".pre-commit-config.yaml" + skip-hooks: + description: >- + Comma-separated list of hook IDs to skip + (forwarded to the SKIP env var pre-commit reads). + required: false + type: string + default: "" + output-file: + description: "Path on the runner where the findings file is exported." + required: false + type: string + default: "/tmp/pre-commit-findings.txt" + continue-on-error: + description: >- + When true, hook failures don't fail the job — useful for advisory runs. + required: false + type: boolean + default: false + dagger-version: + description: "Dagger CLI version" + required: false + type: string + default: "0.20.8" + linting-module-version: + description: "Version of stuttgart-things/dagger/linting to invoke" + required: false + type: string + default: v0.115.0 + artifact-retention-days: + required: false + type: number + default: 30 + +permissions: + contents: read + +jobs: + pre-commit: + name: Pre-commit Hooks + runs-on: ${{ inputs.runs-on }} + environment: ${{ inputs.environment-name }} + steps: + - name: Checkout + uses: actions/checkout@v6.0.2 + with: + fetch-depth: 0 + + - name: Build skip-hooks arg + id: skip + run: | + set -eu + raw='${{ inputs.skip-hooks }}' + if [ -n "$raw" ]; then + echo "arg=--skip-hooks $raw" >> "$GITHUB_OUTPUT" + else + echo "arg=" >> "$GITHUB_OUTPUT" + fi + + - name: Run pre-commit + uses: dagger/dagger-for-github@v8.4.1 + with: + version: ${{ inputs.dagger-version }} + verb: call + module: github.com/stuttgart-things/dagger/linting@${{ inputs.linting-module-version }} + args: >- + run-pre-commit + --src ${{ inputs.src }} + --config-path ${{ inputs.config-path }} + ${{ steps.skip.outputs.arg }} + export --path ${{ inputs.output-file }} + cloud-token: ${{ secrets.DAGGER_CLOUD_TOKEN }} + + - name: Display findings + if: always() + id: findings + run: | + set -eu + OUT='${{ inputs.output-file }}' + if [ ! -f "$OUT" ]; then + echo "::error::pre-commit findings file not found at $OUT" + echo "failed=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + echo "==> pre-commit output" + cat "$OUT" + # The dagger function masks the real exit code with `|| true`, so the + # text is authoritative. pre-commit prints `...Failed` per failure. + if grep -qE '\.\.\.+Failed$' "$OUT"; then + echo "failed=true" >> "$GITHUB_OUTPUT" + else + echo "failed=false" >> "$GITHUB_OUTPUT" + fi + + - name: Upload findings + if: always() + uses: actions/upload-artifact@v7 + with: + name: pre-commit-findings + path: ${{ inputs.output-file }} + if-no-files-found: ignore + retention-days: ${{ inputs.artifact-retention-days }} + + - name: Add to job summary + if: always() + run: | + { + echo '## Pre-commit Hooks' + echo + if [ -f '${{ inputs.output-file }}' ]; then + echo '```' + cat '${{ inputs.output-file }}' + echo '```' + else + echo '_no findings file produced_' + fi + } >> "$GITHUB_STEP_SUMMARY" + + - name: Fail on hook failure + if: always() && steps.findings.outputs.failed == 'true' && inputs.continue-on-error != true + run: | + echo "::error::one or more pre-commit hooks failed" + exit 1