Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .github/workflows/claude-code-review.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Claude Code Review

on:
pull_request:
pull_request_target:
types: [opened, synchronize]
# Optional: Only run on specific file changes
# paths:
Expand All @@ -21,14 +21,19 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
pull-requests: write
issues: read
id-token: write

steps:
# SECURITY: Using pull_request_target is safe here because:
# 1. We checkout the base branch (not PR code) - no untrusted code execution
# 2. Claude Code Action uses GitHub API to read PR, doesn't execute PR code
# 3. Allowed tools are restricted to safe read-only gh commands + gh pr comment
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.base.ref }}
fetch-depth: 1

- name: Run Claude Code Review
Expand Down
95 changes: 95 additions & 0 deletions .github/workflows/e2e-comment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
name: E2E Test Comment

on:
workflow_run:
workflows: ['Main']
types:
- completed

jobs:
comment:
runs-on: ubuntu-latest
if: >
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion != 'skipped'
permissions:
pull-requests: write

steps:
- name: Download PR number
uses: actions/download-artifact@v4
with:
name: pr-number
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}

- name: Read PR number
id: pr
run: echo "number=$(cat pr-number.txt)" >> $GITHUB_OUTPUT

- name: Download test results
uses: actions/download-artifact@v4
with:
name: test-results
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
continue-on-error: true

- name: Generate test results message
id: test-results
uses: actions/github-script@v7
with:
result-encoding: string
script: |
const fs = require('fs');

try {
if (fs.existsSync('results.json')) {
const results = JSON.parse(fs.readFileSync('results.json', 'utf8'));
const { stats } = results;

const failed = stats.unexpected || 0;
const passed = stats.expected || 0;
const flaky = stats.flaky || 0;
const skipped = stats.skipped || 0;
const duration = Math.round((stats.duration || 0) / 1000);

const summary = failed > 0
? `❌ **${failed} test${failed > 1 ? 's' : ''} failed**`
: `✅ **All tests passed**`;

return `## E2E Test Results

${summary} • ${passed} passed • ${skipped} skipped • ${duration}s

| Status | Count |
|--------|-------|
| ✅ Passed | ${passed} |
| ❌ Failed | ${failed} |
| ⚠️ Flaky | ${flaky} |
| ⏭️ Skipped | ${skipped} |

[View full report →](https://github.com/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }})`;
} else {
return `## E2E Test Results

❌ **Test results file not found**

[View full report →](https://github.com/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }})`;
}
} catch (error) {
console.log('Could not parse test results:', error.message);
return `## E2E Test Results

❌ **Error reading test results**

[View full report →](https://github.com/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }})`;
}

- name: Comment PR with test results
uses: mshick/add-pr-comment@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
message: ${{ steps.test-results.outputs.result }}
message-id: e2e-test-results
issue: ${{ steps.pr.outputs.number }}
63 changes: 7 additions & 56 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,63 +146,14 @@ jobs:
path: packages/app/test-results/
retention-days: 30

- name: Generate test results message
id: test-results
- name: Save PR number
if: always() && github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
result-encoding: string
script: |
const fs = require('fs');
const path = require('path');

try {
const resultsPath = path.join('packages/app/test-results/results.json');
if (fs.existsSync(resultsPath)) {
const results = JSON.parse(fs.readFileSync(resultsPath, 'utf8'));
const { stats } = results;

const failed = stats.unexpected || 0;
const passed = stats.expected || 0;
const flaky = stats.flaky || 0;
const skipped = stats.skipped || 0;
const duration = Math.round((stats.duration || 0) / 1000);

const summary = failed > 0
? `❌ **${failed} test${failed > 1 ? 's' : ''} failed**`
: `✅ **All tests passed**`;

return `## E2E Test Results

${summary} • ${passed} passed • ${skipped} skipped • ${duration}s

| Status | Count |
|--------|-------|
| ✅ Passed | ${passed} |
| ❌ Failed | ${failed} |
| ⚠️ Flaky | ${flaky} |
| ⏭️ Skipped | ${skipped} |
run: echo ${{ github.event.pull_request.number }} > pr-number.txt

[View full report →](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})`;
} else {
return `## E2E Test Results

❌ **Test results file not found**

[View full report →](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})`;
}
} catch (error) {
console.log('Could not parse test results:', error.message);
return `## E2E Test Results

❌ **Error reading test results**

[View full report →](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})`;
}

- name: Comment PR with test results
uses: mshick/add-pr-comment@v2
- name: Upload PR number
uses: actions/upload-artifact@v4
if: always() && github.event_name == 'pull_request'
with:
message: ${{ steps.test-results.outputs.result }}
message-id: e2e-test-results
name: pr-number
path: pr-number.txt
retention-days: 1
Loading