mvp-0.0.1 #32
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
| name: Claude code review (non-blocking) | |
| on: | |
| pull_request: | |
| types: [ opened, synchronize, reopened, ready_for_review ] | |
| paths: | |
| - '**/*.scala' | |
| - '**/*.sbt' | |
| - '.scalafix.conf' | |
| - '.scalafmt.conf' | |
| - 'project/**' | |
| - '.github/workflows/**' | |
| - 'AGENTS.md' | |
| - 'docs/adr/**' | |
| - 'docs/plan/**' | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| id-token: write # Required for OIDC token generation | |
| concurrency: | |
| group: claude-review-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| jobs: | |
| claude-review: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| continue-on-error: true | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Get PR diff summary | |
| id: diff | |
| run: | | |
| echo 'patch<<EOF' >> $GITHUB_OUTPUT | |
| git fetch origin ${{ github.event.pull_request.base.ref }} | |
| git --no-pager diff --unified=0 --minimal --patch origin/${{ github.event.pull_request.base.ref }}...HEAD | sed -n '1,6000p' | |
| echo 'EOF' >> $GITHUB_OUTPUT | |
| - name: Generate FlowForge review context | |
| id: ctx | |
| shell: bash | |
| run: | | |
| echo 'context<<EOF' >> $GITHUB_OUTPUT | |
| bash scripts/ff-claude-context.sh | sed -n '1,4000p' | |
| echo 'EOF' >> $GITHUB_OUTPUT | |
| - name: Run claude code action (flowforge review) | |
| if: true | |
| id: claude | |
| uses: anthropics/claude-code-action@v1 | |
| with: | |
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| prompt: | | |
| You are the FlowForge strict code reviewer. Review the DIFF and | |
| produce a concise list of findings with severity labels (HIGH/MED/LOW), | |
| followed by minimal patch suggestions. Use this FlowForge checklist: | |
| 1) ADR‑022 Safety & Errors | |
| - No try/catch/Try in main sources; use Safety/EffectSystem. | |
| - Result/ValidatedResult naming; ErrorMapper mapping present. | |
| - bracket/guarantee for resource cleanup; no manual finally. | |
| 2) Idiomatic Scala (docs/plan/refactor-idiomatic-scala2.md) | |
| - Pure transforms; effectful IO via EffectSystem. | |
| - No concrete IO in main modules; avoid println; no null. | |
| - No asInstanceOf/Any; exhaustive matches; for‑comprehensions. | |
| 3) Spark/Delta best practices | |
| - Avoid collect on large data; prefer Dataset/DataFrame ops. | |
| - Use F.blocking for IO; avoid driver‑side loops; partitioning sane. | |
| - Delta constraints: only NOT NULL and CHECK; no UNIQUE claims. | |
| 4) CI/lint conformance | |
| - Scalafmt/scalafix friendly; no wildcard imports; organized imports. | |
| Output: | |
| - Findings: bullet list with (SEVERITY) and 1–2 line rationale. | |
| - Quick patches: fenced unified diffs with minimal edits (<= ~30 lines each). | |
| - Module plan: for modules touched in DIFF, list 2–4 next actions (e.g., replace Try with Safety, add bracket for streams, remove collect in hot path, swap println→logger). | |
| - Cross‑ref ADR names (e.g., ADR‑022) and docs (e.g., refactor-idiomatic-scala2.md) by name. | |
| DIFF TO REVIEW: | |
| --- | |
| ${{ steps.diff.outputs.patch }} | |
| --- | |
| CONTEXT (repository map, pattern scans, ADRs heads): | |
| --- | |
| ${{ steps.ctx.outputs.context }} | |
| --- | |
| claude_args: >- | |
| --allowedTools "Read" "Bash(rg:*)" | |
| --max-turns 4 | |
| --verbose | |
| - name: Post review (inline when available) | |
| if: steps.claude.outputs.response != '' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| echo "Preparing review body and inline comments" | |
| RESP_FILE=$(mktemp) | |
| echo "${{ steps.claude.outputs.response }}" > "$RESP_FILE" | |
| REVIEW_EVENT=COMMENT | |
| if grep -q "(HIGH)" "$RESP_FILE"; then REVIEW_EVENT=REQUEST_CHANGES; fi | |
| # Parse simple inline comments of the form: INLINE: path:line: message | |
| INLINE_FILE=$(mktemp) | |
| awk '/^INLINE: /{sub(/^INLINE: /, ""); print}' "$RESP_FILE" > "$INLINE_FILE" | |
| if [ -s "$INLINE_FILE" ]; then | |
| echo "Found inline comments; creating review via GitHub Reviews API" | |
| COMMENTS_JSON=$(mktemp) | |
| PR_SHA="${{ github.event.pull_request.head.sha }}" | |
| echo '[' > "$COMMENTS_JSON" | |
| FIRST=1 | |
| while IFS= read -r line; do | |
| path=$(echo "$line" | awk -F: '{print $1}') | |
| lineno=$(echo "$line" | awk -F: '{print $2}') | |
| msg=$(echo "$line" | cut -d: -f3- | sed 's/^ //') | |
| [ -z "$path" ] && continue | |
| [ -z "$lineno" ] && lineno=1 | |
| if [ $FIRST -eq 0 ]; then echo ',' >> "$COMMENTS_JSON"; fi | |
| FIRST=0 | |
| printf '{"path":"%s","line":%s,"side":"RIGHT","body":%s}' \ | |
| "$path" "$lineno" "$(printf '%s' "$msg" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')" >> "$COMMENTS_JSON" | |
| done < "$INLINE_FILE" | |
| echo ']' >> "$COMMENTS_JSON" | |
| gh api \ | |
| repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews \ | |
| -f event=$REVIEW_EVENT \ | |
| -f body="FlowForge AI review ($REVIEW_EVENT)" \ | |
| -f commit_id="$PR_SHA" \ | |
| -F comments=@"$COMMENTS_JSON" \ | |
| -H "Accept: application/vnd.github+json" | |
| else | |
| echo "Posting single review with $REVIEW_EVENT" | |
| gh pr review ${{ github.event.pull_request.number }} --body-file "$RESP_FILE" --event $REVIEW_EVENT | |
| fi |