Skip to content

chore(claude): normalize line endings and refresh the agent-facing docs #440

chore(claude): normalize line endings and refresh the agent-facing docs

chore(claude): normalize line endings and refresh the agent-facing docs #440

Workflow file for this run

name: Code Quality
on:
pull_request:
branches: [main]
# Detects whether a PR *adds* new dead code or duplication compared to main.
# - fallow covers VueApp (dead code, unused exports, complexity, duplication)
# - jscpd covers C# (web/Areas/**/*.cs) since fallow is JS/TS-only
# - resharper-pr-gate covers C# inspections (dead-conditional, NRT-contract, and
# redundancy findings the Roslyn build doesn't catch); PR-scoped so pre-existing
# issues are not blocking — only NEW findings at lines this PR added/modified fail.
# Passes if counts are equal to or lower than main.
jobs:
fallow-regression:
name: Fallow regression (VueApp)
runs-on: ubuntu-latest
steps:
- name: Checkout PR head
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
cache: npm
cache-dependency-path: |
package-lock.json
VueApp/package-lock.json
- name: Install dependencies (root)
run: npm ci
- name: Install dependencies (VueApp)
# fallow resolves the tsconfig chain (incl. @tsconfig/node24) and needs
# VueApp's node_modules to produce accurate counts. Without this step,
# CI reports inflated unresolved-imports / unused-types numbers.
run: npm ci --prefix VueApp
- name: Baseline complexity on main
# `fallow audit`'s complexity gate re-attributes pre-existing findings as
# "new" when files are substantially refactored — moves/rewrites defeat
# its base-snapshot matching, so untouched hotspots get re-flagged.
# Baseline complexity against main's tree (same worktree approach as the
# jscpd-regression jobs below) so only genuinely-new complexity fails.
# Duplication is already gated by jscpd-regression; fallow's own
# duplication verdict is warn-only, so it isn't baselined here.
env:
BASE_REF: ${{ github.base_ref }}
run: |
BASE_TREE="$(mktemp -d)"
git worktree add --detach "$BASE_TREE" "origin/$BASE_REF"
npx fallow health --root "$BASE_TREE/VueApp" --save-baseline "$RUNNER_TEMP/fallow-health-baseline.json" --quiet || true
git worktree remove --force "$BASE_TREE"
- name: Audit fallow on changed files
# `fallow audit` scopes to files changed since --base and returns a
# pass/warn/fail verdict. --health-baseline excludes complexity that
# already existed on main, so a refactor that moves code doesn't fail on
# pre-existing hotspots.
run: npx fallow audit --root VueApp --base origin/${{ github.base_ref }} --health-baseline "$RUNNER_TEMP/fallow-health-baseline.json"
jscpd-regression-csharp:
name: JSCPD regression (C#)
runs-on: ubuntu-latest
steps:
- name: Checkout PR head
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
cache: npm
cache-dependency-path: |
package-lock.json
VueApp/package-lock.json
- name: Install dependencies (root)
run: npm ci
- name: Baseline jscpd on main
# Use a separate worktree at the base ref so the baseline scan sees
# main's full tree — files added by the PR aren't present, files
# changed by the PR carry main's content. Pathspec `git checkout`
# would leave PR-only files in place and pollute the baseline.
env:
BASE_REF: ${{ github.base_ref }}
run: |
BASE_TREE="$(mktemp -d)"
git worktree add --detach "$BASE_TREE" "origin/$BASE_REF"
node scripts/audit-jscpd-regression.js --save .jscpd-baseline-cs.json "$BASE_TREE/web/Areas" --format csharp --pattern '**/*.cs' --min-lines 15
git worktree remove --force "$BASE_TREE"
- name: Check jscpd regression on PR
run: node scripts/audit-jscpd-regression.js --check .jscpd-baseline-cs.json web/Areas --format csharp --pattern '**/*.cs' --min-lines 15
jscpd-regression-vue:
name: JSCPD regression (Vue/TS)
runs-on: ubuntu-latest
steps:
- name: Checkout PR head
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
cache: npm
cache-dependency-path: |
package-lock.json
VueApp/package-lock.json
- name: Install dependencies (root)
run: npm ci
- name: Baseline jscpd on main
# See the C# baseline step above for why we use a worktree here.
env:
BASE_REF: ${{ github.base_ref }}
run: |
BASE_TREE="$(mktemp -d)"
git worktree add --detach "$BASE_TREE" "origin/$BASE_REF"
node scripts/audit-jscpd-regression.js --save .jscpd-baseline-vue.json "$BASE_TREE/VueApp/src"
git worktree remove --force "$BASE_TREE"
- name: Check jscpd regression on PR
run: node scripts/audit-jscpd-regression.js --check .jscpd-baseline-vue.json VueApp/src
resharper-pr-gate:
name: ReSharper PR-scoped gate (C#)
runs-on: ubuntu-latest
steps:
- name: Checkout PR head
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
cache: npm
cache-dependency-path: package-lock.json
- uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0
with:
global-json-file: global.json
- name: Install dependencies (root)
run: npm ci
- name: Restore dotnet local tools (jb / dotnet-ef / libman)
run: dotnet tool restore
- name: Restore NuGet
run: dotnet restore Viper.sln
- name: Run inspectcode + PR-diff gate
# The script runs the full inspectcode scan, parses the SARIF, and only
# fails on findings located at lines this PR added/modified vs base ref.
run: node scripts/audit-resharper-regression.js --base origin/${{ github.base_ref }}
- name: Upload SARIF report
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: resharper-sarif
path: inspect-report/inspect.sarif
retention-days: 3