From b08b55726b08fdb13497b04bd5dbb39c77cebb39 Mon Sep 17 00:00:00 2001 From: Daniel F B Morinigo Date: Thu, 5 Feb 2026 19:06:25 +0800 Subject: [PATCH] fix: Kilo pr review --- .github/workflows/README-opencode.md | 177 ++++++++++++ .github/workflows/kilo-pr-review.yaml | 6 +- .github/workflows/opencode-pr-review.yaml | 332 ++++++++++++++++++++++ 3 files changed, 512 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/README-opencode.md create mode 100644 .github/workflows/opencode-pr-review.yaml diff --git a/.github/workflows/README-opencode.md b/.github/workflows/README-opencode.md new file mode 100644 index 0000000..f0719b7 --- /dev/null +++ b/.github/workflows/README-opencode.md @@ -0,0 +1,177 @@ +# OpenCode PR Review Workflow + +This workflow uses [OpenCode](https://opencode.ai/) to automatically review pull requests from other repositories using GitHub Actions workflow dispatch. + +## Features + +- ๐Ÿค– AI-powered code review with line-specific comments +- ๐ŸŽฏ Configurable review strictness (strict, balanced, lenient) +- ๐Ÿ”„ Supports `workflow_dispatch` and `workflow_call` triggers +- ๐Ÿ“Š Commit status integration +- ๐Ÿงช Dry-run mode for testing +- ๐Ÿ”Œ Optional PR event payload support + +## Setup + +### 1. Required Secrets + +Add these secrets to your repository or organization: + +- `TOKEN`: GitHub token with `repo`, `pull_requests:write`, and `issues:write` permissions +- `OPENCODE_API_KEY`: Your AI provider API key (e.g., Anthropic API key for Claude) + +### 2. Configure the Model + +Edit the `AI_MODEL` environment variable in the workflow file: + +```yaml +env: + AI_MODEL: "anthropic/claude-sonnet-4-20250514" +``` + +Supported formats: `provider/model` (e.g., `anthropic/claude-sonnet-4-20250514`, `openai/gpt-4`) + +## Usage + +### Manual Trigger (Workflow Dispatch) + +Run the workflow from the Actions tab: + +1. Go to **Actions** โ†’ **AI PR Review (OpenCode)** +2. Click **Run workflow** +3. Fill in: + - **repository**: Target repo in `owner/repo` format + - **pr_number**: Pull request number to review + - **review_style**: `strict`, `balanced` (default), or `lenient` + - **dry_run**: Check to test without posting comments + +### From Another Workflow (Workflow Call) + +Call this workflow from another repository: + +```yaml +name: Auto PR Review + +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + review: + uses: alaudadevops/run-actions/.github/workflows/opencode-pr-review.yaml@main + with: + repository: ${{ github.repository }} + pr_number: ${{ github.event.pull_request.number }} + review_style: balanced + dry_run: false + secrets: + TOKEN: ${{ secrets.GITHUB_TOKEN }} + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} +``` + +### Advanced: With PR Event Payload + +Pass the full PR event payload for additional context: + +```yaml +jobs: + review: + uses: alaudadevops/run-actions/.github/workflows/opencode-pr-review.yaml@main + with: + repository: ${{ github.repository }} + pr_number: ${{ github.event.pull_request.number }} + pr_event_payload: ${{ toJSON(github.event.pull_request) }} + review_style: balanced + secrets: + TOKEN: ${{ secrets.GITHUB_TOKEN }} + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} +``` + +## Review Styles + +- **strict**: Thorough review, flags any deviation from best practices +- **balanced** (default): Pragmatic approach, focuses on significant issues +- **lenient**: Only critical issues and obvious improvements + +## How It Works + +1. **Validates** the PR exists and is open +2. **Clones** the target repository and checks out the PR branch +3. **Prepares** a review prompt based on the selected style +4. **Runs OpenCode** to analyze the PR and post inline comments +5. **Updates** commit status with review results +6. **Posts** a summary comment on the PR + +## OpenCode Behavior + +OpenCode will: + +- Review the entire PR diff +- Post inline comments on specific lines with issues +- Provide a summary comment with overall assessment +- Flag issues by severity (critical, error, warning, info) +- Suggest concrete improvements with code examples + +## Customization + +### Custom Prompts + +Modify the "Prepare review prompt" step to customize the review behavior: + +```yaml +- name: Prepare review prompt + run: | + cat > review_prompt.txt << 'EOF' + # Your custom review instructions here + EOF +``` + +### Different AI Models + +Change the `AI_MODEL` environment variable to use different models: + +```yaml +env: + # OpenAI GPT-4 + AI_MODEL: "openai/gpt-4" + + # Or Google Gemini + AI_MODEL: "google/gemini-pro" +``` + +Make sure you have the appropriate API key configured in secrets. + +## Troubleshooting + +### Review Comments Not Appearing + +- Ensure the `TOKEN` has sufficient permissions (`pull_requests:write`) +- Check that the PR is still open +- Verify the PR branch is up-to-date + +### API Rate Limits + +- OpenCode respects GitHub API rate limits +- For high-volume usage, consider using a GitHub App token instead + +### Model Errors + +- Verify your `OPENCODE_API_KEY` is valid +- Check the model name format: `provider/model` +- Ensure your account has access to the specified model + +## Comparison with Kilo Workflow + +| Feature | OpenCode | Kilo | +|---------|----------|------| +| Setup complexity | Simple | Moderate | +| Comment format | Native GitHub review | Custom JSON format | +| Line validation | Built-in | Manual | +| Prompt system | Simple text | System + personalized | +| Output format | Direct PR comments | JSON diagnostics | + +## Learn More + +- [OpenCode Documentation](https://opencode.ai/docs/) +- [OpenCode GitHub Integration](https://opencode.ai/docs/github/) +- [GitHub Actions Workflow Syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions) diff --git a/.github/workflows/kilo-pr-review.yaml b/.github/workflows/kilo-pr-review.yaml index a351786..a1aaaef 100644 --- a/.github/workflows/kilo-pr-review.yaml +++ b/.github/workflows/kilo-pr-review.yaml @@ -56,7 +56,7 @@ env: SHARED_PROMPT_PATH: ".github/prompts/code-review.md" PERSONALIZED_PROMPT_PATH: ".github/prompts/pr-review.md" #AI_MODEL: "mistralai/devstral-2512:free" - AI_MODEL: "moonshotai/kimi-k2.5:free" + AI_MODEL: "z-ai/glm-4.7:free" jobs: review-pr: @@ -286,7 +286,7 @@ jobs: run: | mkdir -p ~/.kilocode/cli - # Configure Kilo CLI with API key + # Configure Kilo CLI with API key (newest 1.0.x syntax) cat > ~/.kilocode/cli/config.json << EOF { "version": "1.0.0", @@ -316,7 +316,7 @@ jobs: run: | echo "๐Ÿค– Starting Kilo code review..." - kilocode --auto --timeout 600 --append-system-prompt-file ../review_prompt.md "Review this PR according to the guidelines in the system prompt" | tee ../kilo_output.log + kilo run --auto --file ../review_prompt.md "Review this PR according to guidelines in the attached file" | tee ../kilo_output.log COMMENT_COUNT=0 HAS_OVERVIEW=false diff --git a/.github/workflows/opencode-pr-review.yaml b/.github/workflows/opencode-pr-review.yaml new file mode 100644 index 0000000..e92129c --- /dev/null +++ b/.github/workflows/opencode-pr-review.yaml @@ -0,0 +1,332 @@ +name: AI PR Review (OpenCode) + +on: + workflow_dispatch: + inputs: + repository: + description: "Repository to review (owner/repo format)" + required: true + type: string + pr_number: + description: "Pull request number to review" + required: true + type: string + pr_event_payload: + description: "Optional: JSON payload from pull_request event" + required: false + type: string + review_style: + description: "Review style (strict, balanced, lenient)" + required: false + default: "balanced" + type: string + dry_run: + description: "Dry run mode (output review but don't post comments)" + required: false + default: false + type: boolean + + workflow_call: + inputs: + repository: + description: "Repository to review (owner/repo format)" + required: true + type: string + pr_number: + description: "Pull request number to review" + required: true + type: string + pr_event_payload: + description: "Optional: JSON payload from pull_request event" + required: false + type: string + review_style: + description: "Review style (strict, balanced, lenient)" + required: false + default: "balanced" + type: string + dry_run: + description: "Dry run mode (output review but don't post comments)" + required: false + default: false + type: boolean + secrets: + TOKEN: + description: "GitHub token with repo access" + required: true + OPENCODE_API_KEY: + description: "API key for the AI provider (e.g., Anthropic API key)" + required: true + +env: + # Configure your model here - format: provider/model + AI_MODEL: "anthropic/claude-sonnet-4-20250514" + +jobs: + review-pr: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + pull-requests: write + issues: write + + steps: + - name: Checkout run-actions repo + uses: actions/checkout@v4 + with: + path: run-actions + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: "24" + + - name: Install GitHub CLI + uses: dev-hanz-ops/install-gh-cli-action@v0.2.1 + with: + gh-cli-version: 2.81.0 + + - name: Auth with GitHub CLI + run: | + echo -n "${{ secrets.TOKEN }}" | gh auth login --with-token + echo "โœ… GitHub CLI authenticated" + + - name: Validate PR exists + id: validate-pr + run: | + REPO="${{ inputs.repository }}" + PR_NUMBER="${{ inputs.pr_number }}" + + echo "๐Ÿ” Validating PR #$PR_NUMBER in $REPO..." + + # Get PR details + PR_DATA=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json number,title,state,headRefName,baseRefName,author,additions,deletions,changedFiles,headRefOid 2>&1) || { + echo "โŒ Failed to fetch PR #$PR_NUMBER from $REPO" + echo "Error: $PR_DATA" + exit 1 + } + + echo "$PR_DATA" | jq . + + # Check if PR is open + PR_STATE=$(echo "$PR_DATA" | jq -r '.state') + if [ "$PR_STATE" != "OPEN" ]; then + echo "โš ๏ธ PR #$PR_NUMBER is not open (state: $PR_STATE). Skipping review." + echo "skip=true" >> $GITHUB_OUTPUT + exit 0 + fi + + # Extract PR info for later use + echo "pr_title=$(echo "$PR_DATA" | jq -r '.title')" >> $GITHUB_OUTPUT + echo "pr_author=$(echo "$PR_DATA" | jq -r '.author.login')" >> $GITHUB_OUTPUT + echo "head_branch=$(echo "$PR_DATA" | jq -r '.headRefName')" >> $GITHUB_OUTPUT + echo "base_branch=$(echo "$PR_DATA" | jq -r '.baseRefName')" >> $GITHUB_OUTPUT + echo "additions=$(echo "$PR_DATA" | jq -r '.additions')" >> $GITHUB_OUTPUT + echo "deletions=$(echo "$PR_DATA" | jq -r '.deletions')" >> $GITHUB_OUTPUT + echo "changed_files=$(echo "$PR_DATA" | jq -r '.changedFiles')" >> $GITHUB_OUTPUT + echo "head_sha=$(echo "$PR_DATA" | jq -r '.headRefOid')" >> $GITHUB_OUTPUT + echo "skip=false" >> $GITHUB_OUTPUT + + echo "โœ… PR validated successfully" + + - name: Set commit status (pending) + if: steps.validate-pr.outputs.skip != 'true' && inputs.dry_run != true + run: | + REPO="${{ inputs.repository }}" + HEAD_SHA="${{ steps.validate-pr.outputs.head_sha }}" + WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + + echo "๐Ÿ“ Setting commit status to pending for $HEAD_SHA..." + + gh api "repos/$REPO/statuses/$HEAD_SHA" \ + --method POST \ + -f state="pending" \ + -f target_url="$WORKFLOW_URL" \ + -f description="AI Code Review in progress..." \ + -f context="AI Code Review (OpenCode)" || { + echo "โš ๏ธ Failed to set commit status" + } + + echo "โœ… Commit status set to pending" + + - name: Clone target repository + if: steps.validate-pr.outputs.skip != 'true' + run: | + REPO="${{ inputs.repository }}" + PR_NUMBER="${{ inputs.pr_number }}" + + echo "๐Ÿ“ฆ Cloning $REPO..." + gh repo clone "$REPO" target-repo + cd target-repo + gh pr checkout $PR_NUMBER + echo "โœ… Repository cloned and PR checked out" + + - name: Prepare review prompt + if: steps.validate-pr.outputs.skip != 'true' + run: | + REPO="${{ inputs.repository }}" + PR_NUMBER="${{ inputs.pr_number }}" + PR_TITLE="${{ steps.validate-pr.outputs.pr_title }}" + REVIEW_STYLE="${{ inputs.review_style }}" + + # Create a concise review prompt + cat > review_prompt.txt << 'EOF' + Review this pull request and provide specific, actionable feedback. + + Focus on: + - Code quality and best practices + - Potential bugs or logical errors + - Security concerns + - Performance issues + - Maintainability and readability + + EOF + + # Add review style guidance + case "$REVIEW_STYLE" in + strict) + cat >> review_prompt.txt << 'EOF' + Be thorough and strict in your review. Flag any deviation from best practices. + EOF + ;; + balanced) + cat >> review_prompt.txt << 'EOF' + Balance thoroughness with pragmatism. Focus on significant issues. + EOF + ;; + lenient) + cat >> review_prompt.txt << 'EOF' + Focus only on critical issues and obvious improvements. + EOF + ;; + esac + + cat >> review_prompt.txt << 'EOF' + + When you identify issues: + - Comment directly on the relevant lines of code + - Be specific about what needs to change and why + - Provide concrete suggestions or code examples when helpful + - Prioritize your feedback (critical issues first) + + Provide a summary comment on the PR with: + - Overall assessment + - Key issues found (if any) + - Positive aspects of the changes + EOF + + echo "โœ… Review prompt prepared" + cat review_prompt.txt + echo "---" + + - name: Load review prompt + if: steps.validate-pr.outputs.skip != 'true' && inputs.dry_run != true + id: load-prompt + run: | + # Use GitHub Actions output with EOF delimiter for multiline + { + echo "prompt_content<> $GITHUB_OUTPUT + + - name: Run OpenCode review + if: steps.validate-pr.outputs.skip != 'true' && inputs.dry_run != true + working-directory: target-repo + uses: anomalyco/opencode/github@latest + env: + ANTHROPIC_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + GITHUB_TOKEN: ${{ secrets.TOKEN }} + with: + model: ${{ env.AI_MODEL }} + use_github_token: true + prompt: ${{ steps.load-prompt.outputs.prompt_content }} + + - name: Simulate review (dry run) + if: steps.validate-pr.outputs.skip != 'true' && inputs.dry_run == true + run: | + echo "๐Ÿ” DRY RUN MODE" + echo "================================" + echo "Would run OpenCode review with:" + echo " Model: ${{ env.AI_MODEL }}" + echo " Repository: ${{ inputs.repository }}" + echo " PR: #${{ inputs.pr_number }}" + echo " Review Style: ${{ inputs.review_style }}" + echo "" + echo "Prompt:" + cat review_prompt.txt + echo "================================" + + - name: Update commit status (success) + if: steps.validate-pr.outputs.skip != 'true' && inputs.dry_run != true && success() + run: | + REPO="${{ inputs.repository }}" + HEAD_SHA="${{ steps.validate-pr.outputs.head_sha }}" + WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + + echo "๐Ÿ“ Updating commit status to success..." + + gh api "repos/$REPO/statuses/$HEAD_SHA" \ + --method POST \ + -f state="success" \ + -f target_url="$WORKFLOW_URL" \ + -f description="AI Code Review completed" \ + -f context="AI Code Review (OpenCode)" || { + echo "โš ๏ธ Failed to update commit status" + } + + echo "โœ… Commit status updated" + + - name: Update commit status (failure) + if: steps.validate-pr.outputs.skip != 'true' && inputs.dry_run != true && failure() + run: | + REPO="${{ inputs.repository }}" + HEAD_SHA="${{ steps.validate-pr.outputs.head_sha }}" + WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + + echo "๐Ÿ“ Updating commit status to failure..." + + gh api "repos/$REPO/statuses/$HEAD_SHA" \ + --method POST \ + -f state="error" \ + -f target_url="$WORKFLOW_URL" \ + -f description="AI Code Review failed" \ + -f context="AI Code Review (OpenCode)" || { + echo "โš ๏ธ Failed to update commit status" + } + + - name: Generate step summary + if: always() + run: | + REPO="${{ inputs.repository }}" + PR_NUMBER="${{ inputs.pr_number }}" + SKIP="${{ steps.validate-pr.outputs.skip }}" + DRY_RUN="${{ inputs.dry_run }}" + MODEL="${{ env.AI_MODEL }}" + REVIEW_STYLE="${{ inputs.review_style }}" + + cat >> $GITHUB_STEP_SUMMARY << EOF + # AI PR Review Summary (OpenCode) + + | Property | Value | + |----------|-------| + | **Repository** | [$REPO](https://github.com/$REPO) | + | **PR** | [#$PR_NUMBER](https://github.com/$REPO/pull/$PR_NUMBER) | + | **Model** | \`$MODEL\` | + | **Style** | $REVIEW_STYLE | + | **Status** | $([ "$SKIP" = "true" ] && echo "โญ๏ธ Skipped (PR not open)" || [ "$DRY_RUN" = "true" ] && echo "๐Ÿ” Dry Run" || echo "โœ… Completed") | + + EOF + + if [ "$SKIP" != "true" ] && [ "$DRY_RUN" != "true" ]; then + echo "## Review Details" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "OpenCode has reviewed the pull request and posted comments directly on the PR." >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "View the review at: https://github.com/$REPO/pull/$PR_NUMBER" >> $GITHUB_STEP_SUMMARY + elif [ "$DRY_RUN" = "true" ]; then + echo "## Dry Run Mode" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "This was a dry run. No comments were posted." >> $GITHUB_STEP_SUMMARY + fi