--- description: Address Gitea/Forgejo PR review comments with code changes --- # Gitea PR Review You are tasked with **addressing** PR review comments by making code changes, then summarizing what was done. This skill drives PR progress, not just conversation. ## Philosophy **Comments are work items, not conversation starters.** When a reviewer leaves a comment, they're identifying something that needs attention. This skill: 1. Categorizes comments by actionability 2. Makes code changes to address actionable comments 3. Commits and pushes those changes 4. Posts a single summary comment describing what was done ## Prerequisites - `tea` CLI configured with a Gitea/Forgejo instance - Access token from tea config: `~/.config/tea/config.yml` - Repository must be a Gitea/Forgejo remote (not GitHub) - **Nix users**: All tools available via nixpkgs (`nix run nixpkgs#tea`) ## Initial Setup When this command is invoked: 1. **Parse the input for PR number**: - If a PR number is provided as argument, use it - If no PR number, detect from current branch (see PR Detection section) 2. **Verify required tools are available**: ```bash which tea ``` If tea is missing: ``` Error: `tea` CLI not found. Please install: - Nix: nix run nixpkgs#tea - Other: https://gitea.com/gitea/tea ``` **STOP** if tea is missing. 3. **Extract configuration from tea config**: ```bash # Read tea config (it's YAML but simple enough to grep) TEA_CONFIG="$HOME/.config/tea/config.yml" GITEA_URL=$(grep -A1 'logins:' "$TEA_CONFIG" | grep 'url:' | head -1 | sed 's/.*url: //') TOKEN=$(grep -A5 'logins:' "$TEA_CONFIG" | grep 'token:' | head -1 | sed 's/.*token: //') ``` If config is missing or invalid: ``` Error: Could not read tea config at ~/.config/tea/config.yml Please ensure `tea` is installed and configured: 1. Install tea 2. Log in: tea login add --url https://your-gitea-instance --token YOUR_TOKEN ``` **STOP** if config is invalid. 4. **Detect repository info from git remote**: ```bash REMOTE_URL=$(git remote get-url origin) # Parse owner and repo from URL (handles both SSH and HTTPS) OWNER=$(echo "$REMOTE_URL" | sed -E 's#.*[:/]([^/]+)/[^/]+\.git$#\1#') REPO=$(echo "$REMOTE_URL" | sed -E 's#.*/([^/]+)\.git$#\1#') ``` 5. **Ensure we're on the PR branch**: ```bash CURRENT_BRANCH=$(git branch --show-current) # Verify this branch corresponds to the PR ``` 6. **Respond with**: ``` Addressing PR review comments for PR #{PR_NUMBER}... Repository: {OWNER}/{REPO} Branch: {CURRENT_BRANCH} Gitea URL: {GITEA_URL} ``` ## PR Detection If no PR number is provided, detect from the current branch: ```bash CURRENT_BRANCH=$(git branch --show-current) tea pr list --fields index,head --output simple | grep "$CURRENT_BRANCH" ``` If no PR exists for the current branch, use `AskUserQuestion`: ``` No PR found for branch '{CURRENT_BRANCH}'. Would you like to: 1. Enter a PR number manually 2. Cancel ``` ## Workflow ### Step 1: Fetch and Parse Comments Fetch all reviews and their comments: ```bash # Fetch reviews (filter out dismissed reviews) curl -s -H "Authorization: token $TOKEN" \ "$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews" \ | jq '[.[] | select(.dismissed != true)]' # For each review, fetch comments curl -s -H "Authorization: token $TOKEN" \ "$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews/$REVIEW_ID/comments" ``` **Filter resolved comments**: When processing comments, skip any that have been marked as resolved. Check the `resolver` field in the comment response - if it's not null, the comment has been resolved and should be skipped. ```bash # Example: Filter to only unresolved comments jq '[.[] | select(.resolver == null)]' ``` If no reviews found or all comments are resolved: ``` No unresolved reviews found for PR #{PR_NUMBER}. Nothing to address. ``` **STOP** here. ### Step 2: Categorize Comments For each comment, categorize it as one of: | Category | Description | Action | |----------|-------------|--------| | **actionable** | Requests a code change, addition, or fix | Launch subagent to make change | | **question** | Asks for clarification or explanation | Include answer in summary | | **acknowledged** | FYI, self-resolved, or "no action needed" noted | Note in summary | | **blocked** | Requires external input or is out of scope | Flag for user | **Categorization heuristics**: - Contains "add", "change", "fix", "update", "consider adding", "should be" → **actionable** - Contains "?" or "why", "how", "what" → **question** - Contains "no need to update", "will be separate", "acknowledged" → **acknowledged** - Contains "discuss", "later", "out of scope", "blocked by" → **blocked** Display the categorization: ``` ## Comment Analysis ### Actionable (will make changes): 1. {file}:{line} - "{comment_summary}" → Will add nix note to prerequisites ### Questions (will answer in summary): 2. {file}:{line} - "{comment_summary}" → Explain CI token approach ### Acknowledged (no action needed): 3. {file}:{line} - "{comment_summary}" → Reviewer noted separate skill ### Blocked (needs input): (none) ``` ### Step 3: User Confirmation Use `AskUserQuestion` to confirm the plan: ``` I've categorized {N} comments. My plan: **Will make changes for:** - {file}:{line}: {planned_change} **Will explain in summary:** - {file}:{line}: {planned_explanation} **No action needed:** - {file}:{line}: {reason} Proceed with this plan? ``` Options: 1. **Proceed** - Execute the plan 2. **Modify** - Let user adjust categorization 3. **Cancel** - Exit without changes ### Step 4: Address Actionable Comments (Parallel Subagents) For each actionable comment, launch a subagent using the Task tool: ``` Launch Task subagent with: - subagent_type: "general-purpose" - prompt: | You are addressing a PR review comment. Make the requested change and nothing else. **File**: {file_path} **Line**: {line_number} **Comment**: {comment_body} **Diff context**: ``` {diff_hunk} ``` Instructions: 1. Read the file to understand context 2. Make the minimal change to address the comment 3. Do NOT commit - just make the edit 4. Report what you changed Be precise. Only change what's needed to address this specific comment. ``` **Important**: Launch actionable comment subagents in parallel when they touch different files. For comments on the same file, run sequentially to avoid conflicts. Wait for all subagents to complete and collect their results. ### Step 5: Commit and Push After all subagents complete: 1. **Stage changes**: ```bash git add -A ``` 2. **Create commit with summary**: ```bash git commit -m "Address PR review comments Changes made: - {file1}: {change_summary} - {file2}: {change_summary} Addresses comments from review by {reviewer}" ``` 3. **Push to remote**: ```bash git push ``` ### Step 6: Post Summary Comment Post a single comment summarizing all actions taken: ```bash tea comment $PR_NUMBER "$(cat <<'EOF' ## Review Comments Addressed cc @{reviewer1} @{reviewer2} **Changes made** (commit {SHORT_SHA}): - `{file1}:{line}`: {what_was_changed} - `{file2}:{line}`: {what_was_changed} **Responses to questions**: - `{file3}:{line}`: {answer_to_question} **Acknowledged** (no action needed): - `{file4}:{line}`: {reason_no_action} --- *Automated response via /gitea_pr_review* EOF )" ``` ### Step 7: Final Summary Display to user: ``` ## PR Review Complete **Commit**: {SHA} **Changes**: {N} files modified ### Actions Taken: - [x] {file1}:{line} - Added nix prerequisite note - [x] {file2}:{line} - Explained CI approach in comment - [ ] {file3}:{line} - Acknowledged (separate skill) **Reviewers tagged**: @{reviewer1}, @{reviewer2} **Comment posted**: {comment_url} PR URL: {GITEA_URL}/{OWNER}/{REPO}/pulls/{PR_NUMBER} ``` **Note**: When posting the summary comment, tag all reviewers who left comments so they receive notifications about the changes. ## Error Handling ### Subagent failed to make change If a subagent fails: ``` Warning: Could not address comment on {file}:{line} Reason: {error} Options: 1. Skip this comment and continue 2. Retry with manual guidance 3. Abort all changes ``` ### Push failed ``` Error pushing changes: {error} Your changes are committed locally. You may need to: 1. Pull and resolve conflicts: git pull --rebase 2. Push again: git push ``` ### No actionable comments If all comments are questions/acknowledged: ``` No code changes needed. All comments are either questions or acknowledged items. Posting summary comment with explanations... ``` ## API Reference ### Endpoints Used | Action | Method | Endpoint | |--------|--------|----------| | List reviews | GET | `/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews` | | Get review comments | GET | `/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments` | | Create issue comment | POST | via `tea comment` | ### Review States - `PENDING` - Draft review not yet submitted - `COMMENT` - General comment without approval/rejection - `APPROVE` - Approving the changes - `REQUEST_CHANGES` - Requesting changes before merge ## Shell Command Patterns Claude Code's bash execution has quirks. Use these patterns for reliability: ### curl requests **DO** - Use single quotes for URL and header separately: ```bash curl -s 'https://git.example.com/api/v1/repos/owner/repo/pulls/1/reviews' \ -H 'Authorization: token YOUR_TOKEN_HERE' | jq . ``` **DON'T** - Variable expansion in `-H` flag often fails: ```bash # This may fail with "blank argument" errors curl -s -H "Authorization: token $TOKEN" "$URL" ``` ### Iterating over reviews **DO** - Run separate commands for each review ID: ```bash echo "=== Review 4 ===" && curl -s 'URL/reviews/4/comments' -H 'Authorization: token ...' | jq . echo "=== Review 5 ===" && curl -s 'URL/reviews/5/comments' -H 'Authorization: token ...' | jq . ``` **DON'T** - For loops with multiline bodies often fail: ```bash # This may cause syntax errors for id in 4 5 6; do curl -s "URL/reviews/$id/comments" done ``` ### tea comment **DO** - Use single-quoted string for comment body: ```bash tea comment 26 '## Summary Changes made: - Item 1 - Item 2' ``` **DON'T** - Heredocs may hang or timeout: ```bash # This may hang indefinitely tea comment 26 "$(cat <<'EOF' ... EOF )" ``` ## Limitations 1. **Thread replies**: Gitea API doesn't support inline thread replies. We post a single summary comment instead. 2. **Complex changes**: For comments requiring significant refactoring, the subagent may need guidance. The skill will flag these as "blocked" for user input. 3. **Merge conflicts**: If the branch is behind, you may need to rebase before changes can be pushed. ## Example Session ``` User: /gitea_pr_review 26 Assistant: Addressing PR review comments for PR #26... Repository: johno/nixos-configs Branch: bead/nixos-configs-vru Gitea URL: https://git.johnogle.info ## Comment Analysis ### Actionable (will make changes): 1. gitea_pr_review.md:12 - "could we indicate nix+nixpkgs satisfies this?" → Will add note that nix users can get tools via nixpkgs ### Questions (will answer in summary): (none) ### Acknowledged (no action needed): 2. gitea_pr_review.md:50 - "we eventually want to run this in CI..." → Reviewer noted this will be a separate skill Proceed with this plan? [Proceed] Launching subagent to address comment 1... [Subagent completes edit] Committing changes... [abc1234] Address PR review comments Pushing to remote... Done. Posting summary comment... ## PR Review Complete **Commit**: abc1234 **Changes**: 1 file modified ### Actions Taken: - [x] gitea_pr_review.md:12 - Added nix prerequisite note - [ ] gitea_pr_review.md:50 - Acknowledged (separate skill) **Comment posted**: https://git.johnogle.info/.../pulls/26#issuecomment-XXX PR URL: https://git.johnogle.info/johno/nixos-configs/pulls/26 ``` ## See Also - `tea` CLI: https://gitea.com/gitea/tea - Gitea API: https://docs.gitea.com/api/ - `/beads_workflow` for full development workflow