name: Lint Frontend on: workflow_call: inputs: allow-failure: description: "When true, Biome errors are reported but job exits 0 (non-blocking)." required: false type: boolean default: false workflow_dispatch: inputs: branch: description: "(Optional) Branch to checkout" required: false type: string env: NODE_VERSION: "22" jobs: run-linters: name: Run Biome runs-on: ubuntu-latest permissions: contents: write steps: - name: Checkout code uses: actions/checkout@v6 with: ref: ${{ inputs.branch || github.ref }} # Need full history so biome can diff against the PR base fetch-depth: 0 - name: Setup Node.js uses: actions/setup-node@v6 id: setup-node with: node-version: ${{ env.NODE_VERSION }} - name: Cache Node.js dependencies uses: actions/cache@v5 id: npm-cache with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('src/frontend/package-lock.json') }} restore-keys: | ${{ runner.os }}-node- - name: Install Node.js dependencies run: | cd src/frontend npm install if: ${{ steps.setup-node.outputs.cache-hit != 'true' }} - name: Run Biome on PR-changed files run: | # Determine the branch this PR targets (falls back to `main` for # workflow_dispatch / non-PR contexts). BASE_REF="${{ github.base_ref || 'main' }}" echo "=== Debug ===" echo "HEAD: $(git rev-parse HEAD)" echo "BASE_REF: $BASE_REF" echo "origin/$BASE_REF: $(git rev-parse "origin/$BASE_REF" 2>/dev/null || echo NOT_FOUND)" # Merge-base = the commit where this branch forked off its target. # Diffing against it yields ONLY the files this PR introduced, # ignoring unrelated upstream changes merged into the base since. MERGE_BASE=$(git merge-base HEAD "origin/$BASE_REF") echo "MERGE_BASE: $MERGE_BASE" # Collect frontend files modified in this PR. Filter to file types # biome can process (ts/tsx/js/jsx/json/jsonc and the like). CHANGED_FILES=$(git diff --name-only --diff-filter=ACMR \ "$MERGE_BASE"...HEAD -- 'src/frontend/' \ | grep -E '\.(tsx?|jsx?|c(js|ts)|m(js|ts)|jsonc?)$' \ || true) if [ -z "$CHANGED_FILES" ]; then echo "No frontend files changed in this PR — skipping biome." exit 0 fi echo "=== Files to lint ===" echo "$CHANGED_FILES" # Biome runs from src/frontend; strip that prefix from paths. RELATIVE_FILES=$(echo "$CHANGED_FILES" | sed 's|^src/frontend/||') cd src/frontend if ${{ inputs.allow-failure || 'false' }}; then echo "$RELATIVE_FILES" | xargs npx @biomejs/biome check \ --files-ignore-unknown=true \ --diagnostic-level=error || echo "Biome found errors (non-blocking for this run)." else echo "$RELATIVE_FILES" | xargs npx @biomejs/biome check \ --files-ignore-unknown=true \ --diagnostic-level=error fi