Skip to content
Open
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
200 changes: 200 additions & 0 deletions .github/workflows/amber-auto-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
# Amber Automatic Code Review
#
# Uses memory system to apply repository-specific standards
# Comments appear from github-actions[bot]
#
# Required GitHub Secret:
# - CLAUDE_CODE_OAUTH_TOKEN: OAuth token for Claude Code

name: Amber Automatic Code Review

on:
pull_request_target:
types: [opened, synchronize]

jobs:
amber-review:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
actions: read

steps:
- name: Checkout PR head
uses: actions/checkout@v5
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0

- name: Minimize old Claude review comments
continue-on-error: true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
REPO="${{ github.repository }}"
PR_NUMBER="${{ github.event.pull_request.number }}"

echo "Finding previous Claude Code Review comments to minimize..."

# Get all comment IDs from github-actions[bot] with "Claude Code Review" at the start
# Using startswith() to avoid matching code blocks or inline mentions
COMMENT_IDS=$(gh api "repos/$REPO/issues/$PR_NUMBER/comments" \
--jq '.[] | select(.user.login == "github-actions[bot]" and (.body | startswith("# Claude Code Review"))) | .node_id')

if [ -z "$COMMENT_IDS" ]; then
echo "No old Claude Code Review comments found"
exit 0
fi

# Minimize each comment with error handling
# Use here-string to avoid subshell variable scoping issues with pipe
COUNT=0
ERRORS=0
while read -r id; do
if [ -n "$id" ]; then
if gh api graphql -f query='mutation($id: ID!) { minimizeComment(input: {subjectId: $id, classifier: OUTDATED}) { minimizedComment { isMinimized } } }' -f id="$id" 2>&1; then
echo "✓ Minimized $id"
((COUNT++))
else
echo "✗ Failed to minimize $id" >&2
((ERRORS++))
fi
fi
done <<< "$COMMENT_IDS"

echo "Minimized $COUNT comment(s), $ERRORS error(s)"

- name: Run Amber Code Review (with memory system)
id: amber-review
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
github_token: ${{ secrets.GITHUB_TOKEN }}
allowed_non_write_users: '*'
claude_args: |
--allowedTools "Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh issue list:*)"
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}

Load the following memory system files to understand repository standards:

1. Read CLAUDE.md (master project instructions)
2. Read .claude/context/backend-development.md
3. Read .claude/context/frontend-development.md
4. Read .claude/context/security-standards.md
5. Read .claude/patterns/k8s-client-usage.md
6. Read .claude/patterns/error-handling.md
7. Read .claude/patterns/react-query-usage.md

After loading all memory files, perform a comprehensive code review following the standards and patterns you just loaded.

Focus on:
1. **Code Quality** - Does it follow CLAUDE.md patterns?
2. **Security** - Check security standards (user token auth, RBAC, token redaction)
3. **Performance** - Any bottlenecks?
4. **Testing** - Adequate coverage?
5. **Architecture** - Follows project structure from memory context?
6. **Error Handling** - Follows error handling patterns?

Use `gh pr comment` to post your review with this format:

# Claude Code Review

## Summary
[Brief overview]

## Issues by Severity

### 🚫 Blocker Issues
[Must fix before merge]

### 🔴 Critical Issues
[Should fix before merge]

### 🟡 Major Issues
[Important to address]

### 🔵 Minor Issues
[Nice-to-have improvements]

## Positive Highlights
[Things done well]

## Recommendations
[Prioritized action items]

- name: Add workflow link with memory system visibility
if: steps.amber-review.conclusion == 'success'
uses: actions/github-script@v7
env:
RUN_ID: ${{ github.run_id }}
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_REPOSITORY: ${{ github.repository }}
with:
script: |
const prNumber = context.payload.pull_request.number;
const runId = process.env.RUN_ID;
const serverUrl = process.env.GITHUB_SERVER_URL;
const repository = process.env.GITHUB_REPOSITORY;

// Find review comment
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});

const reviewComment = comments.data
.filter(c => c.user.login === 'github-actions[bot]' && c.body.startsWith('# Claude Code Review'))
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))[0];

if (!reviewComment) {
console.log('No review comment found');
return;
}

if (reviewComment.body.includes('View AI decision process')) {
console.log('Transparency link already added');
return;
}

const transparencySection = `

---
🔍 [View AI decision process](${serverUrl}/${repository}/actions/runs/${runId}) (logs available for 90 days)

<details>
<summary>📋 View memory system files loaded (click to expand)</summary>

### What Amber Loaded for Code Review

Amber automatically loaded these repository standards from the memory system:

1. **CLAUDE.md** - Master project instructions, development standards
2. **backend-development.md** - Go backend, K8s integration patterns
3. **frontend-development.md** - NextJS, Shadcn UI, React Query patterns
4. **security-standards.md** - Auth, RBAC, token handling
5. **k8s-client-usage.md** - User token vs service account patterns
6. **error-handling.md** - Consistent error patterns
7. **react-query-usage.md** - Data fetching patterns

**Impact**: This review used your repository's specific code quality standards, security patterns, and best practices from the memory system (PRs #359, #360) - not just generic code review guidelines.

</details>
`;

const updatedBody = reviewComment.body + transparencySection;

await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: reviewComment.id,
body: updatedBody
});

console.log('Added transparency link to review comment');
25 changes: 22 additions & 3 deletions .github/workflows/amber-issue-handler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -249,11 +249,17 @@ jobs:
env:
ISSUE_NUMBER: ${{ steps.issue-details.outputs.issue_number }}
ACTION_TYPE: ${{ steps.action-type.outputs.type }}
RUN_ID: ${{ github.run_id }}
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_REPOSITORY: ${{ github.repository }}
uses: actions/github-script@v7
with:
script: |
const issueNumber = parseInt(process.env.ISSUE_NUMBER);
const actionType = process.env.ACTION_TYPE;
const runId = process.env.RUN_ID;
const serverUrl = process.env.GITHUB_SERVER_URL;
const repository = process.env.GITHUB_REPOSITORY;

await github.rest.issues.createComment({
owner: context.repo.owner,
Expand All @@ -268,7 +274,10 @@ jobs:
- No linting issues found
- The requested changes may have already been applied

If you believe changes are still needed, please provide more specific instructions or file paths in the issue description.`
If you believe changes are still needed, please provide more specific instructions or file paths in the issue description.

---
🔍 [View AI decision process](${serverUrl}/${repository}/actions/runs/${runId}) (logs available for 90 days)`
});

- name: Push branch to remote
Expand All @@ -283,6 +292,9 @@ jobs:
if: steps.check-changes.outputs.has_changes == 'true'
env:
ISSUE_NUMBER: ${{ steps.issue-details.outputs.issue_number }}
RUN_ID: ${{ github.run_id }}
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_REPOSITORY: ${{ github.repository }}
uses: actions/github-script@v7
with:
script: |
Expand All @@ -291,6 +303,9 @@ jobs:
const execFileAsync = promisify(execFile);

const issueNumber = parseInt(process.env.ISSUE_NUMBER);
const runId = process.env.RUN_ID;
const serverUrl = process.env.GITHUB_SERVER_URL;
const repository = process.env.GITHUB_REPOSITORY;

// Safely get git diff (no shell injection risk with execFile)
const { stdout: diff } = await execFileAsync('git', ['diff', 'HEAD~1', '--stat']);
Expand All @@ -299,7 +314,7 @@ jobs:
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body: `## Amber Change Summary\n\nThe following files were modified:\n\n\`\`\`\n${diff}\n\`\`\`\n\n**Next Steps:**\n- Review that changes match the issue description\n- Verify no scope creep or unintended modifications\n- A PR will be created shortly for formal review`
body: `## Amber Change Summary\n\nThe following files were modified:\n\n\`\`\`\n${diff}\n\`\`\`\n\n**Next Steps:**\n- Review that changes match the issue description\n- Verify no scope creep or unintended modifications\n- A PR will be created shortly for formal review\n\n---\n🔍 [View AI decision process](${serverUrl}/${repository}/actions/runs/${runId}) (logs available for 90 days)`
});

- name: Create Pull Request
Expand All @@ -311,6 +326,8 @@ jobs:
ISSUE_TITLE: ${{ steps.issue-details.outputs.issue_title }}
ACTION_TYPE: ${{ steps.action-type.outputs.type }}
GITHUB_REPOSITORY: ${{ github.repository }}
RUN_ID: ${{ github.run_id }}
GITHUB_SERVER_URL: ${{ github.server_url }}
uses: actions/github-script@v7
with:
script: |
Expand All @@ -320,6 +337,8 @@ jobs:
const issueTitle = process.env.ISSUE_TITLE;
const actionType = process.env.ACTION_TYPE;
const repository = process.env.GITHUB_REPOSITORY;
const runId = process.env.RUN_ID;
const serverUrl = process.env.GITHUB_SERVER_URL;

// Create PR with error handling (Issue #3)
try {
Expand Down Expand Up @@ -369,7 +388,7 @@ jobs:
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body: `🤖 Amber has created a pull request to address this issue: #${pr.data.number}\n\nThe changes are ready for review. All automated checks will run on the PR.`
body: `🤖 Amber has created a pull request to address this issue: #${pr.data.number}\n\nThe changes are ready for review. All automated checks will run on the PR.\n\n---\n🔍 [View AI decision process](${serverUrl}/${repository}/actions/runs/${runId}) (logs available for 90 days)`
});

console.log('Created PR:', pr.data.html_url);
Expand Down
51 changes: 48 additions & 3 deletions .github/workflows/claude-code-review.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

# Claude Code Review with Fork Support
#
# Manual @claude reviews only - automatic reviews now handled by amber-auto-review.yml
# Uses default workflow token for GitHub operations (comments appear from github-actions[bot])
# Supports fork PRs and automatically minimizes old review comments
#
Expand All @@ -10,11 +11,16 @@
name: Claude Code Review

on:
pull_request_target:
types: [opened, synchronize]
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]

jobs:
claude-review:
# Only run when @claude is mentioned
if: |
contains(github.event.comment.body, '@claude')
runs-on: ubuntu-latest
permissions:
contents: write
Expand Down Expand Up @@ -153,5 +159,44 @@ jobs:

## Recommendations
[Prioritized action items]

Focus on substance. Be constructive and specific.

- name: Add workflow link to review
if: steps.claude-review.conclusion == 'success'
uses: actions/github-script@v7
env:
RUN_ID: ${{ github.run_id }}
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_REPOSITORY: ${{ github.repository }}
with:
script: |
const prNumber = context.payload.pull_request.number;
const runId = process.env.RUN_ID;
const serverUrl = process.env.GITHUB_SERVER_URL;
const repository = process.env.GITHUB_REPOSITORY;

// Find Claude Code Review comment
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});

const reviewComment = comments.data
.filter(c => c.user.login === 'github-actions[bot]' && c.body.startsWith('# Claude Code Review'))
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))[0];

if (!reviewComment || reviewComment.body.includes('View AI decision process')) {
console.log('No review comment found or already has workflow link');
return;
}

const updatedBody = reviewComment.body + `\n\n---\n🔍 [View AI decision process](${serverUrl}/${repository}/actions/runs/${runId}) (logs available for 90 days)`;

await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: reviewComment.id,
body: updatedBody
});
Loading