Initial commit
This commit is contained in:
19
skills/pull-request-skill/.env.example
Normal file
19
skills/pull-request-skill/.env.example
Normal file
@@ -0,0 +1,19 @@
|
||||
# GitHub Personal Access Token (OBRIGATÓRIO)
|
||||
# Create a token at: https://github.com/settings/tokens
|
||||
# Required scopes: 'repo' (full control of private repositories)
|
||||
GITHUB_TOKEN=ghp_your_personal_access_token_here
|
||||
|
||||
# Diretório de saída (OPCIONAL)
|
||||
# Onde os arquivos serão salvos (relativo à raiz do projeto)
|
||||
# Padrão: ./.reviews
|
||||
OUTPUT_DIR=./.reviews
|
||||
|
||||
# Timezone para formatação de datas (OPCIONAL)
|
||||
# Padrão: timezone do sistema local
|
||||
# Exemplos: America/Sao_Paulo, Europe/London, UTC
|
||||
# PR_REVIEW_TZ=America/Sao_Paulo
|
||||
|
||||
# Nível de logging (OPCIONAL)
|
||||
# Padrão: info
|
||||
# Opções: error, warn, info, debug
|
||||
# LOG_LEVEL=debug
|
||||
19
skills/pull-request-skill/.gitignore
vendored
Normal file
19
skills/pull-request-skill/.gitignore
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# Environment files
|
||||
.env
|
||||
.env.local
|
||||
|
||||
# Dependencies
|
||||
node_modules/
|
||||
bun.lockb
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
pr-review-combined.log
|
||||
pr-review-error.log
|
||||
|
||||
# Temporary files
|
||||
.temp-execution-*.js
|
||||
*.tmp
|
||||
|
||||
# Backup files
|
||||
*.bak
|
||||
359
skills/pull-request-skill/SKILL.md
Normal file
359
skills/pull-request-skill/SKILL.md
Normal file
@@ -0,0 +1,359 @@
|
||||
---
|
||||
name: pull-request-skill
|
||||
description: Pull Request review manager for CodeRabbit AI. **ALWAYS use when user needs to work with PR reviews, fix CodeRabbit issues, or check review status.** Downloads, organizes, and helps resolve review comments systematically. Examples - "download PR reviews", "fix CodeRabbit issues for PR 123", "check review status", "organize review comments by severity".
|
||||
---
|
||||
|
||||
You are an expert Pull Request Review Manager specializing in working with CodeRabbit AI review comments from GitHub Pull Requests.
|
||||
|
||||
## When to Engage
|
||||
|
||||
You should proactively assist when:
|
||||
|
||||
- User mentions working with CodeRabbit reviews
|
||||
- User wants to download PR review comments
|
||||
- User needs to fix issues from a PR review
|
||||
- User asks about PR review status
|
||||
- User mentions CodeRabbit, PR reviews, or review comments
|
||||
- User wants to organize or prioritize review feedback
|
||||
- User needs to resolve review threads
|
||||
|
||||
**Trigger Keywords**: coderabbit, pr review, pull request review, review comments, fix issues, download reviews, pr status
|
||||
|
||||
## Your Role
|
||||
|
||||
As a Pull Request Review Manager, you:
|
||||
|
||||
1. **Download** - Fetch CodeRabbit AI review comments from GitHub PRs
|
||||
2. **Organize** - Categorize issues by severity (critical, major, trivial)
|
||||
3. **Track** - Monitor issue resolution status
|
||||
4. **Guide** - Help users systematically resolve review feedback
|
||||
5. **Report** - Provide clear summaries of review status
|
||||
|
||||
## Available Commands
|
||||
|
||||
The reviewer plugin provides three slash commands:
|
||||
|
||||
1. `/reviewer:download-issues --pr <number>` - Download CodeRabbit reviews
|
||||
2. `/reviewer:fix-issues --pr <number>` - Fix issues from a PR review
|
||||
3. `/reviewer:pr-status --pr <number>` - Check review status
|
||||
|
||||
**Note**: PR number is optional - if not provided, the latest open PR is used.
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Download Reviews
|
||||
|
||||
```bash
|
||||
# Download reviews for PR #123
|
||||
/reviewer:download-issues --pr 123
|
||||
|
||||
# Download latest open PR
|
||||
/reviewer:download-issues
|
||||
```
|
||||
|
||||
**What happens:**
|
||||
|
||||
- Fetches all CodeRabbit AI comments from the PR
|
||||
- Organizes them into issues (review threads) and comments
|
||||
- Categorizes by severity: 🔴 Critical, 🟠 Major, 🔵 Trivial
|
||||
- Saves to `.reviews/reviews-pr-<number>/` in the working directory
|
||||
- Generates a summary report
|
||||
|
||||
**Output Structure:**
|
||||
|
||||
```
|
||||
.reviews/reviews-pr-123/
|
||||
├── summary.md # 📊 Overview with statistics
|
||||
├── pr-review-combined.log # 📋 Full execution logs
|
||||
├── pr-review-error.log # ⚠️ Error logs only
|
||||
├── issues/ # 🔧 Resolvable issues (threads)
|
||||
│ ├── issue_001_critical_unresolved.md
|
||||
│ ├── issue_002_major_unresolved.md
|
||||
│ └── issue_003_trivial_resolved.md
|
||||
└── comments/ # 💬 General comments
|
||||
├── comment_001.md
|
||||
└── comment_002.md
|
||||
```
|
||||
|
||||
### 2. Review Summary
|
||||
|
||||
After downloading, **always** read and show the user:
|
||||
|
||||
```bash
|
||||
# Read the summary
|
||||
cat .reviews/reviews-pr-<number>/summary.md
|
||||
```
|
||||
|
||||
The summary includes:
|
||||
|
||||
- Total issues by severity
|
||||
- Resolved vs unresolved count
|
||||
- Issue list with file paths and descriptions
|
||||
- Quick overview for prioritization
|
||||
|
||||
### 3. Fix Issues
|
||||
|
||||
Help users systematically resolve issues:
|
||||
|
||||
```bash
|
||||
# Fix issues from PR #123
|
||||
/reviewer:fix-issues --pr 123
|
||||
```
|
||||
|
||||
**Your role when fixing:**
|
||||
|
||||
1. Read the issue file to understand the problem
|
||||
2. Locate the relevant code file
|
||||
3. Analyze the CodeRabbit suggestion
|
||||
4. Implement the fix following best practices
|
||||
5. Mark the issue as resolved
|
||||
6. Move to the next issue
|
||||
|
||||
**Priority order:**
|
||||
|
||||
1. 🔴 Critical issues first
|
||||
2. 🟠 Major issues next
|
||||
3. 🔵 Trivial issues last
|
||||
|
||||
### 4. Check Status
|
||||
|
||||
Monitor progress on review resolution:
|
||||
|
||||
```bash
|
||||
# Check status of PR #123
|
||||
/reviewer:pr-status --pr 123
|
||||
```
|
||||
|
||||
Shows:
|
||||
|
||||
- Total issues vs resolved
|
||||
- Remaining critical/major/trivial issues
|
||||
- Progress percentage
|
||||
- Next recommended actions
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### GitHub Token Setup
|
||||
|
||||
The skill requires a `.env` file in its installation directory:
|
||||
|
||||
```bash
|
||||
# Location: ~/.claude/plugins/marketplaces/claude-craftkit/plugins/reviewer/skills/pull-request-skill/.env
|
||||
GITHUB_TOKEN=ghp_your_personal_access_token_here
|
||||
OUTPUT_DIR=./.reviews
|
||||
LOG_LEVEL=info
|
||||
PR_REVIEW_TZ=America/Sao_Paulo
|
||||
```
|
||||
|
||||
**If the token is not set:**
|
||||
|
||||
1. Guide user to create `.env` file in skill directory
|
||||
2. Help them generate token at: https://github.com/settings/tokens
|
||||
3. Required scopes: `repo` (full repository access)
|
||||
|
||||
### Dependencies
|
||||
|
||||
Dependencies are auto-installed on first run. The skill uses:
|
||||
|
||||
- `@octokit/rest` - GitHub API client
|
||||
- `@octokit/graphql` - GraphQL API
|
||||
- `winston` - Logging
|
||||
- `zod` - Validation
|
||||
- `dotenv` - Environment variables
|
||||
|
||||
## Issue Severity Levels
|
||||
|
||||
Issues are automatically categorized:
|
||||
|
||||
- **🔴 Critical**: Security issues, bugs, breaking changes
|
||||
|
||||
- **Action**: Fix immediately
|
||||
- **Examples**: Memory leaks, security vulnerabilities, data corruption
|
||||
|
||||
- **🟠 Major**: Important issues affecting functionality
|
||||
|
||||
- **Action**: Fix before merging
|
||||
- **Examples**: Logic errors, performance issues, incorrect behavior
|
||||
|
||||
- **🔵 Trivial**: Minor issues and style improvements
|
||||
- **Action**: Fix when convenient
|
||||
- **Examples**: Code style, formatting, minor optimizations
|
||||
|
||||
## Best Practices
|
||||
|
||||
### When Downloading Reviews
|
||||
|
||||
1. **Always show summary first**
|
||||
|
||||
```bash
|
||||
/reviewer:download-issues --pr 123
|
||||
# Then immediately:
|
||||
cat .reviews/reviews-pr-123/summary.md
|
||||
```
|
||||
|
||||
2. **Verify repository context**
|
||||
|
||||
- Ensure you're in the correct repository
|
||||
- Check git remote: `git remote -v`
|
||||
|
||||
3. **Handle errors gracefully**
|
||||
- Check for `.env` file if token error
|
||||
- Verify PR exists and has CodeRabbit comments
|
||||
- Check logs if issues occur: `pr-review-error.log`
|
||||
|
||||
### When Fixing Issues
|
||||
|
||||
1. **Work systematically**
|
||||
|
||||
- Start with critical issues
|
||||
- Fix one issue at a time
|
||||
- Test after each fix
|
||||
|
||||
2. **Read the full issue**
|
||||
|
||||
- Understand CodeRabbit's reasoning
|
||||
- Check the suggested code change
|
||||
- Consider the context and impact
|
||||
|
||||
3. **Follow project standards**
|
||||
|
||||
- Use project's code style
|
||||
- Run linters/formatters after changes
|
||||
- Ensure tests pass
|
||||
|
||||
4. **Mark issues as resolved**
|
||||
- Rename file: `issue_001_critical_unresolved.md` → `issue_001_critical_resolved.md`
|
||||
- Or move to `resolved/` subfolder
|
||||
|
||||
### When Reporting Status
|
||||
|
||||
1. **Provide clear summary**
|
||||
|
||||
- Total issues vs resolved
|
||||
- Breakdown by severity
|
||||
- Estimated remaining work
|
||||
|
||||
2. **Recommend next actions**
|
||||
- Prioritize critical issues
|
||||
- Suggest grouping similar issues
|
||||
- Identify quick wins
|
||||
|
||||
## Environment Variables
|
||||
|
||||
- `GITHUB_TOKEN` (required): GitHub Personal Access Token
|
||||
- `OUTPUT_DIR` (optional): Output directory relative to working dir (default: `./.reviews`)
|
||||
- `CWD` (optional): Override working directory (default: current directory)
|
||||
- `LOG_LEVEL` (optional): Logging level - `error`, `warn`, `info`, `debug` (default: `info`)
|
||||
- `PR_REVIEW_TZ` (optional): Timezone for dates (default: system timezone)
|
||||
|
||||
## Common Scenarios
|
||||
|
||||
### Scenario 1: User wants to work on PR feedback
|
||||
|
||||
**User**: "I got CodeRabbit feedback on my PR, help me fix it"
|
||||
|
||||
**Your actions**:
|
||||
|
||||
1. Ask for PR number (or auto-detect)
|
||||
2. Run `/reviewer:download-issues --pr <number>`
|
||||
3. Show the summary
|
||||
4. Ask which severity level to start with
|
||||
5. Begin fixing issues systematically
|
||||
|
||||
### Scenario 2: User wants to see what needs fixing
|
||||
|
||||
**User**: "What issues are left on PR 123?"
|
||||
|
||||
**Your actions**:
|
||||
|
||||
1. Run `/reviewer:pr-status --pr 123`
|
||||
2. Show breakdown by severity
|
||||
3. Recommend starting with critical issues
|
||||
4. Offer to begin fixing
|
||||
|
||||
### Scenario 3: User completed some fixes
|
||||
|
||||
**User**: "I fixed the critical issues, what's next?"
|
||||
|
||||
**Your actions**:
|
||||
|
||||
1. Run `/reviewer:pr-status --pr 123`
|
||||
2. Verify critical issues are resolved
|
||||
3. Show remaining major issues
|
||||
4. Offer to continue with major issues
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "GITHUB_TOKEN is not set"
|
||||
|
||||
**Solution**:
|
||||
|
||||
1. Create `.env` file: `~/.claude/plugins/marketplaces/claude-craftkit/plugins/reviewer/skills/pull-request-skill/.env`
|
||||
2. Add: `GITHUB_TOKEN=ghp_...`
|
||||
3. Generate token at: https://github.com/settings/tokens
|
||||
|
||||
### "No CodeRabbit AI comments found"
|
||||
|
||||
**Causes**:
|
||||
|
||||
- CodeRabbit hasn't reviewed the PR yet
|
||||
- PR doesn't have comments from `@coderabbitai[bot]`
|
||||
- Wrong PR number
|
||||
|
||||
**Solution**: Verify PR has CodeRabbit comments on GitHub
|
||||
|
||||
### "Repository information could not be parsed"
|
||||
|
||||
**Causes**:
|
||||
|
||||
- Not in a git repository
|
||||
- No remote configured
|
||||
- Remote URL format incorrect
|
||||
|
||||
**Solution**:
|
||||
|
||||
1. Check: `git remote -v`
|
||||
2. Remote must be: `https://github.com/owner/repo.git`
|
||||
|
||||
### "Dependencies not found"
|
||||
|
||||
**Solution**:
|
||||
|
||||
```bash
|
||||
cd ~/.claude/plugins/marketplaces/claude-craftkit/plugins/reviewer/skills/pull-request-skill
|
||||
bun install
|
||||
```
|
||||
|
||||
## Integration with Development Workflow
|
||||
|
||||
This skill works best when integrated with other tools:
|
||||
|
||||
1. **After PR creation** → Download reviews
|
||||
2. **While fixing** → Use `/quality:check` to verify changes
|
||||
3. **After fixes** → Use `/git:commit` for conventional commits
|
||||
4. **Before merge** → Use `/reviewer:pr-status` to verify all issues resolved
|
||||
|
||||
## Remember
|
||||
|
||||
- **Always download first** - Get fresh reviews before working
|
||||
- **Prioritize by severity** - Critical → Major → Trivial
|
||||
- **One issue at a time** - Focus on quality over speed
|
||||
- **Test after changes** - Ensure fixes don't break anything
|
||||
- **Track progress** - Use status command to monitor completion
|
||||
- **Communicate clearly** - Show summaries and next steps to users
|
||||
|
||||
## Success Criteria
|
||||
|
||||
A successful review resolution workflow:
|
||||
|
||||
✅ **Downloads** reviews successfully with clear summary
|
||||
✅ **Prioritizes** issues by severity (critical first)
|
||||
✅ **Fixes** issues systematically with proper testing
|
||||
✅ **Tracks** progress with status updates
|
||||
✅ **Completes** all critical and major issues before merge
|
||||
✅ **Maintains** code quality and project standards
|
||||
✅ **Communicates** progress clearly to the user
|
||||
|
||||
---
|
||||
|
||||
**You are the Pull Request Review Manager. When users need to work with CodeRabbit reviews, use this skill to guide them through the process systematically.**
|
||||
35
skills/pull-request-skill/package.json
Normal file
35
skills/pull-request-skill/package.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "pull-request-skill",
|
||||
"version": "1.0.0",
|
||||
"description": "Pull Request review exporter and issue resolver for CodeRabbit AI comments",
|
||||
"author": "marcio",
|
||||
"main": "run.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"setup": "bun install",
|
||||
"download": "bun run pr-review.ts",
|
||||
"download-pr": "bun run pr-review.ts"
|
||||
},
|
||||
"keywords": [
|
||||
"pull-request",
|
||||
"code-review",
|
||||
"coderabbit",
|
||||
"github",
|
||||
"claude-skill"
|
||||
],
|
||||
"dependencies": {
|
||||
"@octokit/graphql": "^9.0.2",
|
||||
"@octokit/plugin-retry": "^8.0.2",
|
||||
"@octokit/plugin-throttling": "^11.0.2",
|
||||
"@octokit/rest": "^22.0.0",
|
||||
"@octokit/types": "^15.0.1",
|
||||
"@types/node": "^24.9.1",
|
||||
"dotenv": "^17.2.3",
|
||||
"winston": "^3.18.3",
|
||||
"zod": "^4.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"bun": ">=1.0.0"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
1101
skills/pull-request-skill/pr-review.ts
Normal file
1101
skills/pull-request-skill/pr-review.ts
Normal file
File diff suppressed because it is too large
Load Diff
139
skills/pull-request-skill/read-pr-issues.sh
Executable file
139
skills/pull-request-skill/read-pr-issues.sh
Executable file
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Read PR Issues Script
|
||||
# Displays issues from the PR review export in a clean, readable format
|
||||
#
|
||||
# Usage:
|
||||
# ./read-pr-issues.sh --pr 277 --type issue --all
|
||||
# ./read-pr-issues.sh --pr 277 --type issue --from 1 --to 10
|
||||
# ./read-pr-issues.sh --pr 277 --type critical --all
|
||||
# ./read-pr-issues.sh --pr 277 --type major --all
|
||||
# ./read-pr-issues.sh --pr 277 --type trivial --all
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Default values
|
||||
PR=""
|
||||
TYPE="issue"
|
||||
FROM=""
|
||||
TO=""
|
||||
ALL=false
|
||||
# Use CWD if provided (for when called from skill location), otherwise use current directory
|
||||
WORKING_DIR="${CWD:-$(pwd)}"
|
||||
BASE_DIR="${OUTPUT_DIR:-./.reviews}"
|
||||
# Resolve BASE_DIR relative to WORKING_DIR if it's not absolute
|
||||
if [[ ! "$BASE_DIR" = /* ]]; then
|
||||
BASE_DIR="${WORKING_DIR}/${BASE_DIR}"
|
||||
fi
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--pr)
|
||||
PR="$2"
|
||||
shift 2
|
||||
;;
|
||||
--type)
|
||||
TYPE="$2"
|
||||
shift 2
|
||||
;;
|
||||
--from)
|
||||
FROM="$2"
|
||||
shift 2
|
||||
;;
|
||||
--to)
|
||||
TO="$2"
|
||||
shift 2
|
||||
;;
|
||||
--all)
|
||||
ALL=true
|
||||
shift
|
||||
;;
|
||||
--base-dir)
|
||||
BASE_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
echo "Usage: $0 --pr PR_NUMBER --type TYPE [--from N --to M | --all] [--base-dir DIR]"
|
||||
echo "Types: issue, critical, major, trivial"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate PR number
|
||||
if [[ -z "$PR" ]]; then
|
||||
echo "❌ Error: --pr is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set PR directory
|
||||
PR_DIR="${BASE_DIR}/reviews-pr-${PR}"
|
||||
|
||||
if [[ ! -d "$PR_DIR" ]]; then
|
||||
echo "❌ Error: PR directory not found: $PR_DIR"
|
||||
echo "Have you run the download command first?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "📂 Reading issues from: $PR_DIR"
|
||||
echo ""
|
||||
|
||||
# Determine which files to read based on type
|
||||
case "$TYPE" in
|
||||
critical|major|trivial)
|
||||
PATTERN="*_${TYPE}_*.md"
|
||||
DIR="${PR_DIR}/issues"
|
||||
;;
|
||||
issue)
|
||||
PATTERN="issue_*.md"
|
||||
DIR="${PR_DIR}/issues"
|
||||
;;
|
||||
*)
|
||||
echo "❌ Error: Unknown type: $TYPE"
|
||||
echo "Valid types: issue, critical, major, trivial"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Find matching files
|
||||
if [[ "$ALL" == true ]]; then
|
||||
FILES=($(find "$DIR" -name "$PATTERN" -type f | sort))
|
||||
else
|
||||
if [[ -z "$FROM" ]] || [[ -z "$TO" ]]; then
|
||||
echo "❌ Error: Either use --all or specify both --from and --to"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FILES=()
|
||||
for i in $(seq "$FROM" "$TO"); do
|
||||
ISSUE_NUM=$(printf "%03d" "$i")
|
||||
MATCHES=($(find "$DIR" -name "issue_${ISSUE_NUM}_*.md" -type f))
|
||||
if [[ ${#MATCHES[@]} -gt 0 ]]; then
|
||||
FILES+=("${MATCHES[0]}")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ ${#FILES[@]} -eq 0 ]]; then
|
||||
echo "⚠️ No issues found matching criteria"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Found ${#FILES[@]} issue(s)"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# Display each file
|
||||
for file in "${FILES[@]}"; do
|
||||
filename=$(basename "$file")
|
||||
echo "📄 $filename"
|
||||
echo ""
|
||||
cat "$file"
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
done
|
||||
|
||||
echo "✅ Displayed ${#FILES[@]} issue(s)"
|
||||
179
skills/pull-request-skill/resolve-pr-issues.sh
Executable file
179
skills/pull-request-skill/resolve-pr-issues.sh
Executable file
@@ -0,0 +1,179 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Resolve PR Issues Script
|
||||
# Marks review threads as resolved using GitHub CLI and updates the summary
|
||||
#
|
||||
# Usage:
|
||||
# ./resolve-pr-issues.sh --pr-dir ./ai-docs/reviews-pr-277 --from 1 --to 10
|
||||
# ./resolve-pr-issues.sh --pr-dir ./ai-docs/reviews-pr-277 --all
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Default values
|
||||
PR_DIR=""
|
||||
FROM=""
|
||||
TO=""
|
||||
ALL=false
|
||||
# Use CWD if provided (for when called from skill location), otherwise use current directory
|
||||
WORKING_DIR="${CWD:-$(pwd)}"
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--pr-dir)
|
||||
PR_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
--from)
|
||||
FROM="$2"
|
||||
shift 2
|
||||
;;
|
||||
--to)
|
||||
TO="$2"
|
||||
shift 2
|
||||
;;
|
||||
--all)
|
||||
ALL=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
echo "Usage: $0 --pr-dir PR_DIR [--from N --to M | --all]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate PR directory
|
||||
if [[ -z "$PR_DIR" ]]; then
|
||||
echo "❌ Error: --pr-dir is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Resolve PR_DIR relative to WORKING_DIR if it's not absolute
|
||||
if [[ ! "$PR_DIR" = /* ]]; then
|
||||
PR_DIR="${WORKING_DIR}/${PR_DIR}"
|
||||
fi
|
||||
|
||||
if [[ ! -d "$PR_DIR" ]]; then
|
||||
echo "❌ Error: PR directory not found: $PR_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ISSUES_DIR="${PR_DIR}/issues"
|
||||
|
||||
if [[ ! -d "$ISSUES_DIR" ]]; then
|
||||
echo "❌ Error: Issues directory not found: $ISSUES_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if gh is installed
|
||||
if ! command -v gh &> /dev/null; then
|
||||
echo "❌ Error: GitHub CLI (gh) is not installed"
|
||||
echo "Install from: https://cli.github.com"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🔧 Resolving issues in: $PR_DIR"
|
||||
echo ""
|
||||
|
||||
# Find unresolved issue files
|
||||
if [[ "$ALL" == true ]]; then
|
||||
FILES=($(find "$ISSUES_DIR" -name "issue_*_unresolved.md" -type f | sort))
|
||||
else
|
||||
if [[ -z "$FROM" ]] || [[ -z "$TO" ]]; then
|
||||
echo "❌ Error: Either use --all or specify both --from and --to"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FILES=()
|
||||
for i in $(seq "$FROM" "$TO"); do
|
||||
ISSUE_NUM=$(printf "%03d" "$i")
|
||||
MATCHES=($(find "$ISSUES_DIR" -name "issue_${ISSUE_NUM}_*_unresolved.md" -type f))
|
||||
if [[ ${#MATCHES[@]} -gt 0 ]]; then
|
||||
FILES+=("${MATCHES[@]}")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ ${#FILES[@]} -eq 0 ]]; then
|
||||
echo "✅ No unresolved issues found in specified range"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Found ${#FILES[@]} unresolved issue(s) to process"
|
||||
echo ""
|
||||
|
||||
RESOLVED_COUNT=0
|
||||
FAILED_COUNT=0
|
||||
|
||||
# Process each file
|
||||
for file in "${FILES[@]}"; do
|
||||
filename=$(basename "$file")
|
||||
|
||||
# Extract thread ID from file
|
||||
THREAD_ID=$(grep -m1 "^- Thread ID:" "$file" | sed 's/^- Thread ID: `\(.*\)`$/\1/' || echo "")
|
||||
|
||||
if [[ -z "$THREAD_ID" ]] || [[ "$THREAD_ID" == "(not found)" ]]; then
|
||||
echo "⚠️ Skipping $filename - no thread ID found"
|
||||
((FAILED_COUNT++))
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "Processing: $filename"
|
||||
echo " Thread ID: $THREAD_ID"
|
||||
|
||||
# Resolve the thread using GitHub CLI
|
||||
if gh api graphql \
|
||||
-f query='mutation($threadId: ID!) { resolveReviewThread(input: { threadId: $threadId }) { thread { isResolved } } }' \
|
||||
-F threadId="$THREAD_ID" &> /dev/null; then
|
||||
|
||||
echo " ✅ Resolved successfully"
|
||||
|
||||
# Rename file from unresolved to resolved
|
||||
NEW_FILE="${file/_unresolved.md/_resolved.md}"
|
||||
mv "$file" "$NEW_FILE"
|
||||
|
||||
# Update status in file
|
||||
sed -i.bak 's/- \[ \] UNRESOLVED/- [x] RESOLVED ✓/g' "$NEW_FILE"
|
||||
sed -i.bak 's/UNRESOLVED/RESOLVED/g' "$NEW_FILE"
|
||||
rm -f "${NEW_FILE}.bak"
|
||||
|
||||
((RESOLVED_COUNT++))
|
||||
else
|
||||
echo " ❌ Failed to resolve"
|
||||
((FAILED_COUNT++))
|
||||
fi
|
||||
|
||||
echo ""
|
||||
done
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "Summary:"
|
||||
echo " ✅ Resolved: $RESOLVED_COUNT"
|
||||
echo " ❌ Failed: $FAILED_COUNT"
|
||||
echo " 📊 Total processed: ${#FILES[@]}"
|
||||
echo ""
|
||||
|
||||
if [[ $RESOLVED_COUNT -gt 0 ]]; then
|
||||
echo "🔄 Re-running PR review export to update summary..."
|
||||
|
||||
# Extract PR number from directory name
|
||||
PR_NUM=$(basename "$PR_DIR" | sed 's/reviews-pr-//')
|
||||
|
||||
# Re-run the export script to update summary
|
||||
if command -v bun &> /dev/null; then
|
||||
SCRIPT_DIR="$(dirname "$0")"
|
||||
if CWD="$WORKING_DIR" bun run "$SCRIPT_DIR/pr-review.ts" "$PR_NUM"; then
|
||||
echo "✅ Summary updated successfully"
|
||||
else
|
||||
echo "⚠️ Warning: Failed to update summary, but issues were resolved"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ Warning: Bun not found, summary not updated automatically"
|
||||
echo "Run manually: CWD=$(pwd) bun run <skill-path>/pr-review.ts $PR_NUM"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "✅ Done!"
|
||||
173
skills/pull-request-skill/run.js
Executable file
173
skills/pull-request-skill/run.js
Executable file
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Universal Pull Request Review Exporter for Claude Code
|
||||
*
|
||||
* Executes the PR review export script with Bun:
|
||||
* - Download PR reviews: node run.js download [PR_NUMBER]
|
||||
* - Help: node run.js --help
|
||||
*
|
||||
* Ensures proper module resolution and dependency installation.
|
||||
*/
|
||||
|
||||
import { execSync, spawn } from 'node:child_process';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
// Change to skill directory for proper module resolution
|
||||
process.chdir(__dirname);
|
||||
|
||||
/**
|
||||
* Check if Bun is installed
|
||||
*/
|
||||
function checkBunInstalled() {
|
||||
try {
|
||||
execSync('bun --version', { stdio: 'pipe' });
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if dependencies are installed
|
||||
*/
|
||||
function checkDependenciesInstalled() {
|
||||
return existsSync(join(__dirname, 'node_modules'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Install dependencies using Bun
|
||||
*/
|
||||
function installDependencies() {
|
||||
console.log('📦 Dependencies not found. Installing...');
|
||||
try {
|
||||
execSync('bun install', { stdio: 'inherit', cwd: __dirname });
|
||||
console.log('✅ Dependencies installed successfully');
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error('❌ Failed to install dependencies:', e.message);
|
||||
console.error('Please run manually: cd', __dirname, '&& bun install');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show help message
|
||||
*/
|
||||
function showHelp() {
|
||||
console.log(`
|
||||
Pull Request Review Exporter - Claude Code Skill
|
||||
|
||||
USAGE:
|
||||
node run.js download [PR_NUMBER] Download CodeRabbit comments for a PR
|
||||
node run.js download Download comments for latest open PR
|
||||
node run.js --help Show this help message
|
||||
|
||||
EXAMPLES:
|
||||
node run.js download 123 Download PR #123 reviews
|
||||
node run.js download Download latest open PR reviews
|
||||
|
||||
# From any directory (saves to that directory's .reviews/)
|
||||
CWD=/path/to/repo node run.js download 123
|
||||
|
||||
ENVIRONMENT VARIABLES:
|
||||
GITHUB_TOKEN GitHub Personal Access Token (required)
|
||||
OUTPUT_DIR Output directory for reviews (default: ./.reviews)
|
||||
CWD Working directory to save reviews (default: current directory)
|
||||
LOG_LEVEL Logging level: error, warn, info, debug (default: info)
|
||||
PR_REVIEW_TZ Timezone for dates (default: system timezone)
|
||||
|
||||
SETUP:
|
||||
1. Create .env file in skill directory:
|
||||
echo "GITHUB_TOKEN=ghp_your_token_here" > .env
|
||||
|
||||
2. Optionally configure output directory and logging:
|
||||
echo "OUTPUT_DIR=./my-reviews" >> .env
|
||||
echo "LOG_LEVEL=debug" >> .env
|
||||
|
||||
For more information, see README.md
|
||||
`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the PR review export script
|
||||
*/
|
||||
function runPRReviewScript(args) {
|
||||
const scriptPath = join(__dirname, 'pr-review.ts');
|
||||
|
||||
if (!existsSync(scriptPath)) {
|
||||
console.error('❌ Error: pr-review.ts not found in skill directory');
|
||||
console.error('Expected at:', scriptPath);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('🚀 Starting PR Review Exporter...\n');
|
||||
|
||||
// Use spawn to stream output in real-time
|
||||
const bunProcess = spawn('bun', ['run', scriptPath, ...args], {
|
||||
cwd: __dirname,
|
||||
stdio: 'inherit',
|
||||
env: { ...process.env }
|
||||
});
|
||||
|
||||
bunProcess.on('error', (error) => {
|
||||
console.error('❌ Failed to start Bun process:', error.message);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
bunProcess.on('exit', (code) => {
|
||||
process.exit(code || 0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Main execution
|
||||
*/
|
||||
async function main() {
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
// Show help
|
||||
if (args.includes('--help') || args.includes('-h')) {
|
||||
showHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Check Bun installation
|
||||
if (!checkBunInstalled()) {
|
||||
console.error('❌ Bun is not installed or not in PATH');
|
||||
console.error('Please install Bun from: https://bun.sh');
|
||||
console.error('Or use: curl -fsSL https://bun.sh/install | bash');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Check and install dependencies if needed
|
||||
if (!checkDependenciesInstalled()) {
|
||||
const installed = installDependencies();
|
||||
if (!installed) {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse command
|
||||
const command = args[0];
|
||||
|
||||
if (command === 'download' || !command) {
|
||||
// Extract PR number if provided
|
||||
const prArgs = args.slice(1);
|
||||
runPRReviewScript(prArgs);
|
||||
} else {
|
||||
console.error(`❌ Unknown command: ${command}`);
|
||||
console.error('Run "node run.js --help" for usage information');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Run main function
|
||||
main().catch((error) => {
|
||||
console.error('❌ Fatal error:', error.message);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user