|
|
|
@@ -1,217 +1,350 @@
|
|
|
|
---
|
|
|
|
---
|
|
|
|
description: Manage and respond to Gitea/Forgejo PR review comments
|
|
|
|
description: Address Gitea/Forgejo PR review comments with code changes
|
|
|
|
---
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
# Gitea PR Review Comments
|
|
|
|
# Gitea PR Review
|
|
|
|
|
|
|
|
|
|
|
|
This skill enables reading PR review comments and posting inline thread replies on Gitea/Forgejo instances.
|
|
|
|
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
|
|
|
|
## Prerequisites
|
|
|
|
|
|
|
|
|
|
|
|
- `tea` CLI configured with a Gitea/Forgejo instance
|
|
|
|
- `tea` CLI configured with a Gitea/Forgejo instance
|
|
|
|
- Access token from tea config: `~/.config/tea/config.yml`
|
|
|
|
- Access token from tea config: `~/.config/tea/config.yml`
|
|
|
|
- Repository must be a Gitea/Forgejo remote (not GitHub)
|
|
|
|
- Repository must be a Gitea/Forgejo remote (not GitHub)
|
|
|
|
|
|
|
|
- **Nix users**: All tools available via nixpkgs (`nix run nixpkgs#tea`)
|
|
|
|
|
|
|
|
|
|
|
|
## Configuration
|
|
|
|
## Initial Setup
|
|
|
|
|
|
|
|
|
|
|
|
Get the Gitea instance URL and token from tea config:
|
|
|
|
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
|
|
|
|
```bash
|
|
|
|
# Get the default login URL and token
|
|
|
|
which tea
|
|
|
|
yq -r '.logins[] | select(.name == "default") | .url' ~/.config/tea/config.yml
|
|
|
|
|
|
|
|
yq -r '.logins[] | select(.name == "default") | .token' ~/.config/tea/config.yml
|
|
|
|
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Or if you have a specific login name:
|
|
|
|
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
|
|
|
|
```bash
|
|
|
|
yq -r '.logins[] | select(.name == "YOUR_LOGIN") | .url' ~/.config/tea/config.yml
|
|
|
|
# Read tea config (it's YAML but simple enough to grep)
|
|
|
|
yq -r '.logins[] | select(.name == "YOUR_LOGIN") | .token' ~/.config/tea/config.yml
|
|
|
|
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: //')
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Commands
|
|
|
|
If config is missing or invalid:
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
Error: Could not read tea config at ~/.config/tea/config.yml
|
|
|
|
|
|
|
|
|
|
|
|
### 1. List PR Review Comments
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
|
|
Fetch all reviews and their comments for a PR:
|
|
|
|
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
|
|
|
|
```bash
|
|
|
|
# Set environment variables
|
|
|
|
CURRENT_BRANCH=$(git branch --show-current)
|
|
|
|
GITEA_URL="https://git.johnogle.info"
|
|
|
|
tea pr list --fields index,head --output simple | grep "$CURRENT_BRANCH"
|
|
|
|
TOKEN="<your-token>"
|
|
|
|
```
|
|
|
|
OWNER="<repo-owner>"
|
|
|
|
|
|
|
|
REPO="<repo-name>"
|
|
|
|
|
|
|
|
PR_NUMBER="<pr-number>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Get all reviews for the PR
|
|
|
|
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" \
|
|
|
|
curl -s -H "Authorization: token $TOKEN" \
|
|
|
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews" | jq
|
|
|
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews" \
|
|
|
|
|
|
|
|
| jq '[.[] | select(.dismissed != true)]'
|
|
|
|
|
|
|
|
|
|
|
|
# Get comments for a specific review
|
|
|
|
# For each review, fetch comments
|
|
|
|
REVIEW_ID="<review-id>"
|
|
|
|
|
|
|
|
curl -s -H "Authorization: token $TOKEN" \
|
|
|
|
curl -s -H "Authorization: token $TOKEN" \
|
|
|
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews/$REVIEW_ID/comments" | jq
|
|
|
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews/$REVIEW_ID/comments"
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2. View All Review Comments (Combined)
|
|
|
|
**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
|
|
|
|
```bash
|
|
|
|
# Get all reviews and their comments in one view
|
|
|
|
# Example: Filter to only unresolved comments
|
|
|
|
curl -s -H "Authorization: token $TOKEN" \
|
|
|
|
jq '[.[] | select(.resolver == null)]'
|
|
|
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews" | \
|
|
|
|
|
|
|
|
jq -r '.[] | "Review \(.id) by \(.user.login): \(.state)\n Body: \(.body)"'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# For each review, show inline comments
|
|
|
|
|
|
|
|
for REVIEW_ID in $(curl -s -H "Authorization: token $TOKEN" \
|
|
|
|
|
|
|
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews" | jq -r '.[].id'); do
|
|
|
|
|
|
|
|
echo "=== Review $REVIEW_ID comments ==="
|
|
|
|
|
|
|
|
curl -s -H "Authorization: token $TOKEN" \
|
|
|
|
|
|
|
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews/$REVIEW_ID/comments" | \
|
|
|
|
|
|
|
|
jq -r '.[] | "[\(.path):\(.line)] \(.body)"'
|
|
|
|
|
|
|
|
done
|
|
|
|
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3. Reply to Review Comments (Web Endpoint Method)
|
|
|
|
If no reviews found or all comments are resolved:
|
|
|
|
|
|
|
|
|
|
|
|
The Gitea REST API does not support replying to review comment threads. The web UI uses a different endpoint:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
```
|
|
|
|
POST /{owner}/{repo}/pulls/{pr_number}/files/reviews/comments
|
|
|
|
No unresolved reviews found for PR #{PR_NUMBER}.
|
|
|
|
Content-Type: multipart/form-data
|
|
|
|
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)
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Required form fields:**
|
|
|
|
### Step 3: User Confirmation
|
|
|
|
- `reply`: Review ID to reply to
|
|
|
|
|
|
|
|
- `content`: The reply message
|
|
|
|
|
|
|
|
- `path`: File path
|
|
|
|
|
|
|
|
- `line`: Line number
|
|
|
|
|
|
|
|
- `side`: `proposed` or `original`
|
|
|
|
|
|
|
|
- `single_review`: `true`
|
|
|
|
|
|
|
|
- `origin`: `timeline`
|
|
|
|
|
|
|
|
- `_csrf`: CSRF token (required for web endpoint)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Authentication Challenge:**
|
|
|
|
Use `AskUserQuestion` to confirm the plan:
|
|
|
|
This endpoint requires session-based authentication, not API tokens. Options:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### Option A: Use Browser Session (Recommended)
|
|
|
|
```
|
|
|
|
|
|
|
|
I've categorized {N} comments. My plan:
|
|
|
|
|
|
|
|
|
|
|
|
1. Log in to Gitea in your browser
|
|
|
|
**Will make changes for:**
|
|
|
|
2. Open browser developer tools and copy cookies
|
|
|
|
- {file}:{line}: {planned_change}
|
|
|
|
3. Use the session cookies with curl
|
|
|
|
|
|
|
|
|
|
|
|
**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
|
|
|
|
```bash
|
|
|
|
# First, get CSRF token from the PR page
|
|
|
|
tea comment $PR_NUMBER "$(cat <<'EOF'
|
|
|
|
CSRF=$(curl -s -c cookies.txt -b cookies.txt \
|
|
|
|
## Review Comments Addressed
|
|
|
|
"$GITEA_URL/$OWNER/$REPO/pulls/$PR_NUMBER/files" | \
|
|
|
|
|
|
|
|
grep -oP 'name="_csrf" value="\K[^"]+')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Post the reply
|
|
|
|
cc @{reviewer1} @{reviewer2}
|
|
|
|
curl -s -b cookies.txt \
|
|
|
|
|
|
|
|
-F "reply=$REVIEW_ID" \
|
|
|
|
**Changes made** (commit {SHORT_SHA}):
|
|
|
|
-F "content=Your reply message here" \
|
|
|
|
- `{file1}:{line}`: {what_was_changed}
|
|
|
|
-F "path=$FILE_PATH" \
|
|
|
|
- `{file2}:{line}`: {what_was_changed}
|
|
|
|
-F "line=$LINE_NUMBER" \
|
|
|
|
|
|
|
|
-F "side=proposed" \
|
|
|
|
**Responses to questions**:
|
|
|
|
-F "single_review=true" \
|
|
|
|
- `{file3}:{line}`: {answer_to_question}
|
|
|
|
-F "origin=timeline" \
|
|
|
|
|
|
|
|
-F "_csrf=$CSRF" \
|
|
|
|
**Acknowledged** (no action needed):
|
|
|
|
"$GITEA_URL/$OWNER/$REPO/pulls/$PR_NUMBER/files/reviews/comments"
|
|
|
|
- `{file4}:{line}`: {reason_no_action}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
*Automated response via /gitea_pr_review*
|
|
|
|
|
|
|
|
EOF
|
|
|
|
|
|
|
|
)"
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### Option B: Create Top-Level Comment (Fallback)
|
|
|
|
### Step 7: Final Summary
|
|
|
|
|
|
|
|
|
|
|
|
If thread replies are not critical, use the API to create a top-level comment:
|
|
|
|
Display to user:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
```
|
|
|
|
# Create a top-level comment mentioning the review context
|
|
|
|
## PR Review Complete
|
|
|
|
curl -s -X POST \
|
|
|
|
|
|
|
|
-H "Authorization: token $TOKEN" \
|
|
|
|
**Commit**: {SHA}
|
|
|
|
-H "Content-Type: application/json" \
|
|
|
|
**Changes**: {N} files modified
|
|
|
|
-d "{\"body\": \"Re: @reviewer's comment on $FILE_PATH:$LINE_NUMBER\n\nYour reply here\"}" \
|
|
|
|
|
|
|
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/issues/$PR_NUMBER/comments"
|
|
|
|
### 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}
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Or use tea CLI:
|
|
|
|
**Note**: When posting the summary comment, tag all reviewers who left comments so they receive notifications about the changes.
|
|
|
|
```bash
|
|
|
|
|
|
|
|
tea comment $PR_NUMBER "Re: @reviewer's comment on $FILE_PATH:$LINE_NUMBER
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Your reply here"
|
|
|
|
## 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
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 4. Submit a New Review
|
|
|
|
### Push failed
|
|
|
|
|
|
|
|
|
|
|
|
Create a new review with inline comments:
|
|
|
|
```
|
|
|
|
|
|
|
|
Error pushing changes: {error}
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
Your changes are committed locally. You may need to:
|
|
|
|
curl -s -X POST \
|
|
|
|
1. Pull and resolve conflicts: git pull --rebase
|
|
|
|
-H "Authorization: token $TOKEN" \
|
|
|
|
2. Push again: git push
|
|
|
|
-H "Content-Type: application/json" \
|
|
|
|
|
|
|
|
-d '{
|
|
|
|
|
|
|
|
"body": "Overall review comments",
|
|
|
|
|
|
|
|
"event": "COMMENT",
|
|
|
|
|
|
|
|
"comments": [
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
"path": "path/to/file.py",
|
|
|
|
|
|
|
|
"body": "Comment on this line",
|
|
|
|
|
|
|
|
"new_position": 10
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
}' \
|
|
|
|
|
|
|
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews"
|
|
|
|
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Event types: `COMMENT`, `APPROVE`, `REQUEST_CHANGES`
|
|
|
|
### No actionable comments
|
|
|
|
|
|
|
|
|
|
|
|
## Workflow Example
|
|
|
|
If all comments are questions/acknowledged:
|
|
|
|
|
|
|
|
|
|
|
|
### Reading and Responding to Reviews
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1. **Set up environment**:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
|
|
export GITEA_URL=$(yq -r '.logins[] | select(.name == "default") | .url' ~/.config/tea/config.yml)
|
|
|
|
|
|
|
|
export TOKEN=$(yq -r '.logins[] | select(.name == "default") | .token' ~/.config/tea/config.yml)
|
|
|
|
|
|
|
|
export OWNER="johno"
|
|
|
|
|
|
|
|
export REPO="nixos-configs"
|
|
|
|
|
|
|
|
export PR_NUMBER="5"
|
|
|
|
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
No code changes needed.
|
|
|
|
|
|
|
|
|
|
|
|
2. **List all pending review comments**:
|
|
|
|
All comments are either questions or acknowledged items.
|
|
|
|
```bash
|
|
|
|
Posting summary comment with explanations...
|
|
|
|
# Get reviews
|
|
|
|
|
|
|
|
curl -s -H "Authorization: token $TOKEN" \
|
|
|
|
|
|
|
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews" | \
|
|
|
|
|
|
|
|
jq -r '.[] | select(.state == "REQUEST_CHANGES" or .state == "COMMENT") |
|
|
|
|
|
|
|
|
"Review \(.id) by \(.user.login) (\(.state)):\n\(.body)\n"'
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3. **Get detailed comments for a review**:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
|
|
REVIEW_ID="2"
|
|
|
|
|
|
|
|
curl -s -H "Authorization: token $TOKEN" \
|
|
|
|
|
|
|
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews/$REVIEW_ID/comments" | \
|
|
|
|
|
|
|
|
jq -r '.[] | "File: \(.path):\(.line)\nComment: \(.body)\nID: \(.id)\n---"'
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4. **Respond using top-level comment** (most reliable):
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
|
|
tea comment $PR_NUMBER "Addressing review feedback:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- File \`path/to/file.py\` line 10: Fixed the issue by...
|
|
|
|
|
|
|
|
- File \`other/file.py\` line 25: Updated as suggested..."
|
|
|
|
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## API Reference
|
|
|
|
## API Reference
|
|
|
|
|
|
|
|
|
|
|
|
### Endpoints
|
|
|
|
### Endpoints Used
|
|
|
|
|
|
|
|
|
|
|
|
| Action | Method | Endpoint |
|
|
|
|
| Action | Method | Endpoint |
|
|
|
|
|--------|--------|----------|
|
|
|
|
|--------|--------|----------|
|
|
|
|
| List reviews | GET | `/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews` |
|
|
|
|
| List reviews | GET | `/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews` |
|
|
|
|
| Get review | GET | `/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}` |
|
|
|
|
|
|
|
|
| Get review comments | GET | `/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments` |
|
|
|
|
| Get review comments | GET | `/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments` |
|
|
|
|
| Create review | POST | `/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews` |
|
|
|
|
| Create issue comment | POST | via `tea comment` |
|
|
|
|
| Submit review | POST | `/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}` |
|
|
|
|
|
|
|
|
| Delete review | DELETE | `/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}` |
|
|
|
|
|
|
|
|
| Create issue comment | POST | `/api/v1/repos/{owner}/{repo}/issues/{index}/comments` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Review States
|
|
|
|
### Review States
|
|
|
|
|
|
|
|
|
|
|
|
@@ -220,25 +353,120 @@ Event types: `COMMENT`, `APPROVE`, `REQUEST_CHANGES`
|
|
|
|
- `APPROVE` - Approving the changes
|
|
|
|
- `APPROVE` - Approving the changes
|
|
|
|
- `REQUEST_CHANGES` - Requesting changes before merge
|
|
|
|
- `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
|
|
|
|
## Limitations
|
|
|
|
|
|
|
|
|
|
|
|
1. **Thread replies**: The Gitea REST API does not support replying directly to review comment threads. This is a known limitation. Workarounds:
|
|
|
|
1. **Thread replies**: Gitea API doesn't support inline thread replies. We post a single summary comment instead.
|
|
|
|
- Use top-level comments with context
|
|
|
|
|
|
|
|
- Use the web UI manually for thread replies
|
|
|
|
|
|
|
|
- Implement session-based authentication to use the web endpoint
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2. **CSRF tokens**: The web endpoint for thread replies requires CSRF tokens, which expire and need to be fetched from the page.
|
|
|
|
2. **Complex changes**: For comments requiring significant refactoring, the subagent may need guidance. The skill will flag these as "blocked" for user input.
|
|
|
|
|
|
|
|
|
|
|
|
3. **Session auth**: API tokens work for REST API but not for web endpoints that require session cookies.
|
|
|
|
3. **Merge conflicts**: If the branch is behind, you may need to rebase before changes can be pushed.
|
|
|
|
|
|
|
|
|
|
|
|
## Tips
|
|
|
|
## Example Session
|
|
|
|
|
|
|
|
|
|
|
|
- Always quote file paths and line numbers when responding via top-level comments
|
|
|
|
```
|
|
|
|
- Use `tea pr view $PR_NUMBER --comments` to see all comments
|
|
|
|
User: /gitea_pr_review 26
|
|
|
|
- Use `tea open pulls/$PR_NUMBER` to open the PR in browser for manual thread replies
|
|
|
|
Assistant: Addressing PR review comments for PR #26...
|
|
|
|
- Consider using `tea pr approve $PR_NUMBER` after addressing all comments
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
## See Also
|
|
|
|
|
|
|
|
|
|
|
|
- Gitea API Documentation: https://docs.gitea.com/api/1.20/
|
|
|
|
|
|
|
|
- `tea` CLI: https://gitea.com/gitea/tea
|
|
|
|
- `tea` CLI: https://gitea.com/gitea/tea
|
|
|
|
|
|
|
|
- Gitea API: https://docs.gitea.com/api/
|
|
|
|
|
|
|
|
- `/beads_workflow` for full development workflow
|
|
|
|
|