diff --git a/Bitbucket/bitbucket-pipelines.yml b/Bitbucket/bitbucket-pipelines.yml index b15970b..a64556d 100644 --- a/Bitbucket/bitbucket-pipelines.yml +++ b/Bitbucket/bitbucket-pipelines.yml @@ -11,6 +11,7 @@ # TABNINE_HOST - Tabnine host URL (default: https://console.tabnine.com) # TABNINE_MODEL_ID - Model ID for the Tabnine CLI agent. If empty, falls back to DEFAULT_MODEL_ID below or the system default from the admin console. # TABNINE_CLEANUP - Set to "true" to delete settings.json after each run (default: "false"). Recommended for self-hosted runners. +# TABNINE_COMMENT_PREFIX - Prefix used to identify bot comments for cleanup (default: '#### Tabnine PR Bot'). image: node:20 @@ -30,6 +31,7 @@ pipelines: - export BB_PR_ID="${BITBUCKET_PR_ID}" - export BB_COMMIT="${BITBUCKET_COMMIT}" - export BB_PR_DEST_BRANCH="${BITBUCKET_PR_DESTINATION_BRANCH}" + - export COMMENT_PREFIX="${TABNINE_COMMENT_PREFIX:-#### Tabnine PR Bot}" # Input validation - | @@ -90,8 +92,8 @@ pipelines: # Clean up previous bot summary comments - | - echo "Cleaning up previous Tabnine PR Bot comments..." - COMMENTS=$(curl -s --header "Authorization: Bearer $BB_API_TOKEN" "$BB_API_BASE/repositories/$BB_WORKSPACE/$BB_REPO_SLUG/pullrequests/$BB_PR_ID/comments?pagelen=100" | jq -r '.values[] | select(.content.raw | startswith("#### Tabnine PR Bot")) | .id') + echo "Cleaning up previous bot comments (prefix: $COMMENT_PREFIX)..." + COMMENTS=$(curl -s --header "Authorization: Bearer $BB_API_TOKEN" "$BB_API_BASE/repositories/$BB_WORKSPACE/$BB_REPO_SLUG/pullrequests/$BB_PR_ID/comments?pagelen=100" | jq -r ".values[] | select(.content.raw | startswith(\"$COMMENT_PREFIX\")) | .id") for COMMENT_ID in $COMMENTS; do echo "Deleting bot comment: $COMMENT_ID" @@ -139,28 +141,22 @@ pipelines: Based on Phase A, classify this PR into a risk tier: **Tier 1 - Low Risk** (docs, config, tests, typo fixes, dependency bumps with no code changes): - - Skip Phase C2 (cross-repo analysis) and Phase C3 (infra review) entirely. - - Post only the summary comment (Phase E) with a brief confirmation. + - Skip Phase B2 (cross-repo analysis) and Phase B3 (infra review) entirely. + - Post only the summary comment (Phase D) with a brief confirmation. - Maximum inline comments: 1 (only for genuine bugs). **Tier 2 - Standard** (feature work, refactors, most bug fixes): - - Run full Phase C audit. - - Run Phase C2 only if the diff touches public APIs, shared libraries, or interface definitions. + - Run full Phase B audit. + - Run Phase B2 only if the diff touches public APIs, shared libraries, or interface definitions. - Maximum inline comments: 5. **Tier 3 - High Risk** (security changes, auth/authz, data migrations, public API changes, infrastructure/deployment changes, shared library changes): - - Run all phases including full Phase C2 and Phase C3. + - Run all phases including full Phase B2 and Phase B3. - Maximum inline comments: 8. Determine the tier before proceeding. State the tier in your summary. - ### Phase B: Clean Up Previous Inline Comments - Before posting new inline comments, delete all previous Tabnine PR Bot inline review comments: - 1. List all PR comments: curl -s --header 'Authorization: Bearer \$BB_API_TOKEN' '$BB_API_BASE/repositories/$BB_WORKSPACE/$BB_REPO_SLUG/pullrequests/$BB_PR_ID/comments?pagelen=100' - 2. For each comment whose content.raw starts with '#### Tabnine PR Bot' and has an 'inline' property (indicating it's an inline comment), delete it using: curl -s --header 'Authorization: Bearer \$BB_API_TOKEN' --request DELETE '$BB_API_BASE/repositories/$BB_WORKSPACE/$BB_REPO_SLUG/pullrequests/$BB_PR_ID/comments/COMMENT_ID' - Note: Summary comments are cleaned up automatically before this review runs, so you only need to handle inline comments here. - - ### Phase C: Engineering Audit + ### Phase B: Engineering Audit Evaluate the code against these pillars IN PRIORITY ORDER. Spend the most effort on the highest-priority categories. **P0 - Correctness & Logic** (most critical): @@ -224,7 +220,7 @@ pipelines: - Are names self-explanatory? Are complex algorithms or non-obvious business rules documented? - Does the code follow existing project conventions? - ### Phase C2: Cross-Repository Impact Analysis (Skip for Tier 1) + ### Phase B2: Cross-Repository Impact Analysis (Skip for Tier 1) Use the Tabnine MCP context engine tools to analyze cross-repository impact of this PR: 1. **List repositories**: Call 'remote_repositories_list' to discover the organization's repository ecosystem. 2. **Find related services**: Call 'remote_search_assets' with queries derived from the changed files to find SERVICE_SUMMARY and OPENAPI_SPEC assets related to the code being modified. @@ -242,14 +238,14 @@ pipelines: - Services or repositories as nodes - Call or dependency relationships as directed edges - Use this diagram to reason about blast radius, layering violations, or unintended coupling. - 8. **Compile findings** for inclusion in the Phase E summary comment: + 8. **Compile findings** for inclusion in the Phase D summary comment: - Architecture violations or new inter-service dependencies introduced by this PR - Other repositories or services that consume the changed code (with file and line references where possible) - High-level architecture insight derived from SERVICE_SUMMARY / OPENAPI_SPEC assets - ASCII architecture diagram (only if it adds clarity; omit if trivial) - If no cross-repo impact is found, state 'No cross-repository impact detected' - ### Phase C3: Infrastructure & Configuration Review (Tier 3 only, skip if no infra files in diff) + ### Phase B3: Infrastructure & Configuration Review (Tier 3 only, skip if no infra files in diff) If the PR modifies infrastructure or configuration files, apply these checks: **Dockerfiles**: Are base images pinned (not 'latest')? Running as non-root? Secrets not in build args? **CI/CD Pipelines**: Are dependencies version-pinned? Could this break the pipeline for other branches? Secrets via secure stores? @@ -257,7 +253,7 @@ pipelines: **Terraform/IaC**: Any resource destruction? Blast radius limited? New resources tagged consistently? **Config/Env Vars**: New vars have safe defaults? Sensitive values from secret managers? App fails fast if required config missing? - ### Phase C4: Coaching Guidelines Compliance + ### Phase B4: Coaching Guidelines Compliance Use the Tabnine MCP 'get_guidelines' tool to retrieve the organization's coaching guidelines and validate the changed code against them: 1. **Identify languages**: Determine which programming languages are present in the diff (e.g., python, javascript, typescript, java, php, go, cpp, csharp, kotlin). 2. **Fetch guidelines**: Call 'get_guidelines' with the 'language' parameter for each language detected in the diff to retrieve applicable coaching guidelines. If changed files span multiple languages, call it once per language. @@ -266,7 +262,7 @@ pipelines: - Post an inline comment referencing the guideline ID and description. Coaching guideline violations are exempt from the tier comment budget -- every violation must be reported. - Use the guideline's severity to map to the inline comment severity: Critical -> [Critical], Error -> [Warning], Warning -> [Suggestion], Info -> [Suggestion]. - Include the guideline's recommended fix or best practice in the 'Suggested fix' section of the comment. - 5. **Include in summary**: Add a 'Coaching Guidelines' section to the Phase E summary if any violations were found. List violated guideline IDs grouped by severity. If no violations were found, state 'All changed code complies with coaching guidelines.' + 5. **Include in summary**: Add a 'Coaching Guidelines' section to the Phase D summary if any violations were found. List violated guideline IDs grouped by severity. If no violations were found, state 'All changed code complies with coaching guidelines.' ## 4. Comment Value Threshold (CRITICAL FILTER) @@ -281,7 +277,7 @@ pipelines: - Introduces a deployment risk (non-backward-compatible migration, missing feature flag for risky change) - Changes CI/CD configuration in a way that could break the build for other contributors - Violates critical project patterns (e.g., error handling, path handling) - - Violates any organization coaching guideline, regardless of severity (from Phase C4) + - Violates any organization coaching guideline, regardless of severity (from Phase B4) - Makes the code significantly harder to maintain or debug **DO NOT comment on:** @@ -304,9 +300,9 @@ pipelines: **Golden Rule**: If removing your comment would NOT increase the risk of bugs, security issues, or maintenance problems, DO NOT POST IT. - ### Phase D: Inline Comments + ### Phase C: Inline Comments - For each potential issue from Phase C: + For each potential issue from Phase B: 1. Apply the Comment Value Threshold filter above 2. Enforce the tier comment budget (Tier 1: max 1, Tier 2: max 5, Tier 3: max 8). If you have more findings than the budget, keep only the highest-severity ones. 3. Verify the file exists in the diff and the line number is within changed lines @@ -323,24 +319,28 @@ pipelines: - **[Warning]** -- Logic issues, edge cases, performance concerns. Strongly recommended to fix. - **[Suggestion]** -- Improvements to maintainability or clarity. Author's discretion. + **FILE-LEVEL vs LINE-LEVEL comments**: If a comment applies to the entire file rather than specific lines (e.g., a deleted file, a file that should not exist, or a concern about the file as a whole), post a FILE-LEVEL comment using 'inline.path' without 'from'/'to' instead of a comment spanning all lines. Never post a comment that covers all or most lines of a file -- this creates an excessively large comment. Use file-level comments for file-wide feedback. + Submit inline comments using the Bitbucket PR Comments API: - **IMPORTANT**: All comments MUST start with '#### Tabnine PR Bot' on the first line, followed by a blank line, then your formatted comment content. + **IMPORTANT**: All comments MUST start with '$COMMENT_PREFIX' on the first line, followed by a blank line, then your formatted comment content. + For FILE-LEVEL comments (when the comment applies to the entire file, not specific lines): + curl -s --header 'Authorization: Bearer \$BB_API_TOKEN' --request POST --header 'Content-Type: application/json' --data '{"content": {"raw": "$COMMENT_PREFIX\n\nYOUR_COMMENT"}, "inline": {"path": "FILE_PATH"}}' '$BB_API_BASE/repositories/$BB_WORKSPACE/$BB_REPO_SLUG/pullrequests/$BB_PR_ID/comments' For inline comments on specific lines: - curl -s --header 'Authorization: Bearer \$BB_API_TOKEN' --request POST --header 'Content-Type: application/json' --data '{"content": {"raw": "#### Tabnine PR Bot\n\nYOUR_COMMENT"}, "inline": {"path": "FILE_PATH", "to": LINE_NUMBER}}' '$BB_API_BASE/repositories/$BB_WORKSPACE/$BB_REPO_SLUG/pullrequests/$BB_PR_ID/comments' + curl -s --header 'Authorization: Bearer \$BB_API_TOKEN' --request POST --header 'Content-Type: application/json' --data '{"content": {"raw": "$COMMENT_PREFIX\n\nYOUR_COMMENT"}, "inline": {"path": "FILE_PATH", "to": LINE_NUMBER}}' '$BB_API_BASE/repositories/$BB_WORKSPACE/$BB_REPO_SLUG/pullrequests/$BB_PR_ID/comments' - ### Phase E: Final Summary + ### Phase D: Final Summary After submitting inline comments (or if zero comments were posted), post the holistic summary. The summary is the MOST IMPORTANT output -- most developers read only this. Create the summary comment using the Bitbucket PR Comments API: - curl -s --header 'Authorization: Bearer \$BB_API_TOKEN' --request POST --header 'Content-Type: application/json' --data '{"content": {"raw": "#### Tabnine PR Bot\n\nYOUR_SUMMARY"}}' '$BB_API_BASE/repositories/$BB_WORKSPACE/$BB_REPO_SLUG/pullrequests/$BB_PR_ID/comments' + curl -s --header 'Authorization: Bearer \$BB_API_TOKEN' --request POST --header 'Content-Type: application/json' --data '{"content": {"raw": "$COMMENT_PREFIX\n\nYOUR_SUMMARY"}}' '$BB_API_BASE/repositories/$BB_WORKSPACE/$BB_REPO_SLUG/pullrequests/$BB_PR_ID/comments' Structure your summary as follows: - **Line 1 - Risk Tier**: State the tier: [Low Risk], [Standard], or [HIGH RISK] - **What This PR Does** (1-2 sentences): Demonstrate you understood the author's intent. This builds trust. - **Assessment** (1-3 sentences): Overall verdict. Is this good to merge? Any blockers? - **Key Findings** (only if findings exist): Group by severity -- [Critical] first, then [Warning], then [Suggestion]. List max 3-5 findings; if more, prioritize by severity. - - **Cross-Repository Impact** (Tier 2-3 only): Findings from Phase C2, or 'No cross-repository impact detected.' - - **Coaching Guidelines**: Findings from Phase C4 -- list violated guideline IDs grouped by severity, or 'All changed code complies with coaching guidelines.' + - **Cross-Repository Impact** (Tier 2-3 only): Findings from Phase B2, or 'No cross-repository impact detected.' + - **Coaching Guidelines**: Findings from Phase B4 -- list violated guideline IDs grouped by severity, or 'All changed code complies with coaching guidelines.' - **Deployment & Operations** (only if relevant): Migration safety, feature flag requirements, observability gaps, infrastructure concerns. Omit entirely if no operational concerns. - **What Looks Good** (1-3 bullet points): Specific things the author did well (good test coverage, clean error handling, thoughtful API design). Always find something positive. diff --git a/GitHub/tabnine-review.yml b/GitHub/tabnine-review.yml index 432fdf1..da202e9 100644 --- a/GitHub/tabnine-review.yml +++ b/GitHub/tabnine-review.yml @@ -12,6 +12,7 @@ # TABNINE_HOST - Tabnine host URL (default: https://console.tabnine.com). Set this for self-hosted / EMT installations. # TABNINE_MODEL_ID - Model ID for the Tabnine CLI agent. If empty, falls back to DEFAULT_MODEL_ID below or the system default from the admin console. # TABNINE_CLEANUP - Set to "true" to delete settings.json after each run (default: "false"). Recommended for self-hosted runners. +# TABNINE_COMMENT_PREFIX - Prefix used to identify bot comments for cleanup (default: '#### Tabnine PR Bot'). name: "Tabnine PR Review Agent" @@ -105,15 +106,16 @@ jobs: # Use a different env var name to avoid conflict with GITHUB_TOKEN echo "$GH_TOKEN_INPUT" | gh auth login --with-token - - name: Clean Up Previous Bot Summary Comments + - name: Clean Up Previous Bot Comments shell: bash env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COMMENT_PREFIX: ${{ vars.TABNINE_COMMENT_PREFIX || '#### Tabnine PR Bot' }} run: | - echo "Cleaning up previous Tabnine PR Bot summary comments..." + echo "Cleaning up previous bot comments (prefix: $COMMENT_PREFIX)..." # Get all issue comments on the PR - COMMENTS=$(gh api "/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" --jq '.[] | select(.body | startswith("#### Tabnine PR Bot")) | .id') + COMMENTS=$(gh api "/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" --jq '[.[] | select(.body | startswith(env.COMMENT_PREFIX)) | .id] | .[]') # Delete all bot summary comments to prevent duplicates for COMMENT_ID in $COMMENTS; do @@ -122,12 +124,12 @@ jobs: done # Get all pull-request comments on the PR - PR_COMMENTS=$(gh api "/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/comments" --jq '.[] | select(.body | startswith("#### Tabnine PR Bot")) | .id') + PR_COMMENTS=$(gh api "/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/comments" --jq '[.[] | select(.body | startswith(env.COMMENT_PREFIX)) | .id] | .[]') - # Delete all bot pull request review comments to prevent duplicates + # Delete all bot inline review comments to prevent duplicates for COMMENT_ID in $PR_COMMENTS; do - echo "Deleting bot summary comment: $COMMENT_ID" - gh api --method DELETE "/repos/${{ github.repository }}/issues/comments/$COMMENT_ID" || true + echo "Deleting bot inline review comment: $COMMENT_ID" + gh api --method DELETE "/repos/${{ github.repository }}/pulls/comments/$COMMENT_ID" || true done echo "Cleanup complete." @@ -137,6 +139,7 @@ jobs: continue-on-error: true env: TABNINE_TOKEN: ${{ secrets.TABNINE_KEY }} + COMMENT_PREFIX: ${{ vars.TABNINE_COMMENT_PREFIX || '#### Tabnine PR Bot' }} run: | if [ -z "$TABNINE_TOKEN" ]; then echo "Error: TABNINE_KEY is required" @@ -168,28 +171,22 @@ jobs: Based on Phase A, classify this PR into a risk tier: **Tier 1 - Low Risk** (docs, config, tests, typo fixes, dependency bumps with no code changes): - - Skip Phase C2 (cross-repo analysis) and Phase C3 (infra review) entirely. - - Post only the summary comment (Phase E) with a brief confirmation. + - Skip Phase B2 (cross-repo analysis) and Phase B3 (infra review) entirely. + - Post only the summary comment (Phase D) with a brief confirmation. - Maximum inline comments: 1 (only for genuine bugs). **Tier 2 - Standard** (feature work, refactors, most bug fixes): - - Run full Phase C audit. - - Run Phase C2 only if the diff touches public APIs, shared libraries, or interface definitions. + - Run full Phase B audit. + - Run Phase B2 only if the diff touches public APIs, shared libraries, or interface definitions. - Maximum inline comments: 5. **Tier 3 - High Risk** (security changes, auth/authz, data migrations, public API changes, infrastructure/deployment changes, shared library changes): - - Run all phases including full Phase C2 and Phase C3. + - Run all phases including full Phase B2 and Phase B3. - Maximum inline comments: 8. Determine the tier before proceeding. State the tier in your summary. - ### Phase B: Clean Up Previous Inline Comments - Before posting new inline comments, delete all previous Tabnine PR Bot inline review comments: - 1. List all review comments: 'gh api /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/comments' - 2. For each comment whose body starts with '#### Tabnine PR Bot', delete it using: 'gh api --method DELETE /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/comments/COMMENT_ID' - Note: Summary comments are cleaned up automatically before this review runs, so you only need to handle inline comments here. - - ### Phase C: Engineering Audit + ### Phase B: Engineering Audit Evaluate the code against these pillars IN PRIORITY ORDER. Spend the most effort on the highest-priority categories. **P0 - Correctness & Logic** (most critical): @@ -253,7 +250,7 @@ jobs: - Are names self-explanatory? Are complex algorithms or non-obvious business rules documented? - Does the code follow existing project conventions? - ### Phase C2: Cross-Repository Impact Analysis (Skip for Tier 1) + ### Phase B2: Cross-Repository Impact Analysis (Skip for Tier 1) Use the Tabnine MCP context engine tools to analyze cross-repository impact of this PR: 1. **List repositories**: Call 'remote_repositories_list' to discover the organization's repository ecosystem. 2. **Find related services**: Call 'remote_search_assets' with queries derived from the changed files to find SERVICE_SUMMARY and OPENAPI_SPEC assets related to the code being modified. @@ -271,14 +268,14 @@ jobs: - Services or repositories as nodes - Call or dependency relationships as directed edges - Use this diagram to reason about blast radius, layering violations, or unintended coupling. - 8. **Compile findings** for inclusion in the Phase E summary comment: + 8. **Compile findings** for inclusion in the Phase D summary comment: - Architecture violations or new inter-service dependencies introduced by this PR - Other repositories or services that consume the changed code (with file and line references where possible) - High-level architecture insight derived from SERVICE_SUMMARY / OPENAPI_SPEC assets - ASCII architecture diagram (only if it adds clarity; omit if trivial) - If no cross-repo impact is found, state 'No cross-repository impact detected' - ### Phase C3: Infrastructure & Configuration Review (Tier 3 only, skip if no infra files in diff) + ### Phase B3: Infrastructure & Configuration Review (Tier 3 only, skip if no infra files in diff) If the PR modifies infrastructure or configuration files, apply these checks: **Dockerfiles**: Are base images pinned (not 'latest')? Running as non-root? Secrets not in build args? **CI/CD Pipelines**: Are dependencies version-pinned? Could this break the pipeline for other branches? Secrets via secure stores? @@ -286,7 +283,7 @@ jobs: **Terraform/IaC**: Any resource destruction? Blast radius limited? New resources tagged consistently? **Config/Env Vars**: New vars have safe defaults? Sensitive values from secret managers? App fails fast if required config missing? - ### Phase C4: Coaching Guidelines Compliance + ### Phase B4: Coaching Guidelines Compliance Use the Tabnine MCP 'get_guidelines' tool to retrieve the organization's coaching guidelines and validate the changed code against them: 1. **Identify languages**: Determine which programming languages are present in the diff (e.g., python, javascript, typescript, java, php, go, cpp, csharp, kotlin). 2. **Fetch guidelines**: Call 'get_guidelines' with the 'language' parameter for each language detected in the diff to retrieve applicable coaching guidelines. If changed files span multiple languages, call it once per language. @@ -295,7 +292,7 @@ jobs: - Post an inline comment referencing the guideline ID and description. Coaching guideline violations are exempt from the tier comment budget -- every violation must be reported. - Use the guideline's severity to map to the inline comment severity: Critical -> [Critical], Error -> [Warning], Warning -> [Suggestion], Info -> [Suggestion]. - Include the guideline's recommended fix or best practice in the 'Suggested fix' section of the comment. - 5. **Include in summary**: Add a 'Coaching Guidelines' section to the Phase E summary if any violations were found. List violated guideline IDs grouped by severity. If no violations were found, state 'All changed code complies with coaching guidelines.' + 5. **Include in summary**: Add a 'Coaching Guidelines' section to the Phase D summary if any violations were found. List violated guideline IDs grouped by severity. If no violations were found, state 'All changed code complies with coaching guidelines.' ## 4. Comment Value Threshold (CRITICAL FILTER) @@ -310,7 +307,7 @@ jobs: - Introduces a deployment risk (non-backward-compatible migration, missing feature flag for risky change) - Changes CI/CD configuration in a way that could break the build for other contributors - Violates critical project patterns (e.g., error handling, path handling) - - Violates any organization coaching guideline, regardless of severity (from Phase C4) + - Violates any organization coaching guideline, regardless of severity (from Phase B4) - Makes the code significantly harder to maintain or debug **DO NOT comment on:** @@ -333,9 +330,9 @@ jobs: **Golden Rule**: If removing your comment would NOT increase the risk of bugs, security issues, or maintenance problems, DO NOT POST IT. - ### Phase D: Inline Comments + ### Phase C: Inline Comments - For each potential issue from Phase C: + For each potential issue from Phase B: 1. Apply the Comment Value Threshold filter above 2. Enforce the tier comment budget (Tier 1: max 1, Tier 2: max 5, Tier 3: max 8). If you have more findings than the budget, keep only the highest-severity ones. 3. Verify the file exists in the diff and the line number is within changed lines @@ -352,14 +349,20 @@ jobs: - **[Warning]** -- Logic issues, edge cases, performance concerns. Strongly recommended to fix. - **[Suggestion]** -- Improvements to maintainability or clarity. Author's discretion. + **FILE-LEVEL vs LINE-LEVEL comments**: If a comment applies to the entire file rather than specific lines (e.g., a deleted file, a file that should not exist, or a concern about the file as a whole), post a FILE-LEVEL comment using 'subject_type=file' instead of a multi-line comment spanning all lines. Never post a multi-line comment that covers all or most lines of a file -- this creates an excessively large comment. Use file-level comments for file-wide feedback. + Submit inline comments using: - **IMPORTANT**: All comments MUST start with '#### Tabnine PR Bot' on the first line, followed by a blank line, then your formatted comment content. + **IMPORTANT**: All comments MUST start with '$COMMENT_PREFIX' on the first line, followed by a blank line, then your formatted comment content. + For FILE-LEVEL comments (when the comment applies to the entire file, not specific lines): + gh api --method POST -H 'Accept: application/vnd.github+json' /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/comments -f body='$COMMENT_PREFIX + + YOUR_COMMENT' -f commit_id='${{ github.event.pull_request.head.sha }}' -f path='FILE_PATH' -f subject_type='file' For SINGLE-LINE comments: - gh api --method POST -H 'Accept: application/vnd.github+json' /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/comments -f body='#### Tabnine PR Bot + gh api --method POST -H 'Accept: application/vnd.github+json' /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/comments -f body='$COMMENT_PREFIX YOUR_COMMENT' -f commit_id='${{ github.event.pull_request.head.sha }}' -f path='FILE_PATH' -F line=LINE_NUMBER -f side='RIGHT' For MULTI-LINE comments: - gh api --method POST -H 'Accept: application/vnd.github+json' /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/comments -f body='#### Tabnine PR Bot + gh api --method POST -H 'Accept: application/vnd.github+json' /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/comments -f body='$COMMENT_PREFIX YOUR_COMMENT' -f commit_id='${{ github.event.pull_request.head.sha }}' -f path='FILE_PATH' -F start_line=START_LINE_NUMBER -f start_side='RIGHT' -F line=END_LINE_NUMBER -f side='RIGHT' **Code Suggestions**: Use GitHub's suggestion syntax ONLY when the fix is clear, unambiguous, and replaces 10 or fewer lines: @@ -368,11 +371,11 @@ jobs: ``` For larger changes or context-dependent fixes, provide guidance as a regular comment without the suggestion block. - ### Phase E: Final Summary + ### Phase D: Final Summary After submitting inline comments (or if zero comments were posted), post the holistic summary. The summary is the MOST IMPORTANT output -- most developers read only this. Create the summary comment using: - gh api --method POST /repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments -f body='#### Tabnine PR Bot + gh api --method POST /repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments -f body='$COMMENT_PREFIX YOUR_SUMMARY' @@ -381,8 +384,8 @@ jobs: - **What This PR Does** (1-2 sentences): Demonstrate you understood the author's intent. This builds trust. - **Assessment** (1-3 sentences): Overall verdict. Is this good to merge? Any blockers? - **Key Findings** (only if findings exist): Group by severity -- [Critical] first, then [Warning], then [Suggestion]. List max 3-5 findings; if more, prioritize by severity. - - **Cross-Repository Impact** (Tier 2-3 only): Findings from Phase C2, or 'No cross-repository impact detected.' - - **Coaching Guidelines**: Findings from Phase C4 -- list violated guideline IDs grouped by severity, or 'All changed code complies with coaching guidelines.' + - **Cross-Repository Impact** (Tier 2-3 only): Findings from Phase B2, or 'No cross-repository impact detected.' + - **Coaching Guidelines**: Findings from Phase B4 -- list violated guideline IDs grouped by severity, or 'All changed code complies with coaching guidelines.' - **Deployment & Operations** (only if relevant): Migration safety, feature flag requirements, observability gaps, infrastructure concerns. Omit entirely if no operational concerns. - **What Looks Good** (1-3 bullet points): Specific things the author did well (good test coverage, clean error handling, thoughtful API design). Always find something positive. diff --git a/GitLab/.gitlab-ci.yml b/GitLab/.gitlab-ci.yml index e12e59f..1e5db08 100644 --- a/GitLab/.gitlab-ci.yml +++ b/GitLab/.gitlab-ci.yml @@ -11,6 +11,7 @@ # TABNINE_HOST - Tabnine host URL (default: https://console.tabnine.com) # TABNINE_MODEL_ID - Model ID for the Tabnine CLI agent # TABNINE_CLEANUP - Set to "true" to delete settings.json after each run. Recommended for self-hosted runners. +# TABNINE_COMMENT_PREFIX - Prefix used to identify bot comments for cleanup (default: '#### Tabnine PR Bot'). stages: - review @@ -86,18 +87,29 @@ tabnine-code-review: export HEAD_SHA="${CI_MERGE_REQUEST_DIFF_HEAD_SHA}" export BASE_SHA="${CI_MERGE_REQUEST_DIFF_BASE_SHA}" export PROJECT_PATH="${CI_PROJECT_PATH}" + export COMMENT_PREFIX="${TABNINE_COMMENT_PREFIX:-#### Tabnine PR Bot}" # Clean up previous bot summary notes - echo "Cleaning up previous Tabnine PR Bot notes..." + echo "Cleaning up previous bot comments (prefix: $COMMENT_PREFIX)..." NOTES=$(curl -s --header "PRIVATE-TOKEN: $GITLAB_API_TOKEN" \ "$GITLAB_API_URL/projects/$PROJECT_ID/merge_requests/$MR_IID/notes" \ - | jq -r '.[] | select(.body | startswith("#### Tabnine PR Bot")) | .id') + | jq -r ".[] | select(.body | startswith(\"$COMMENT_PREFIX\")) | .id") for NOTE_ID in $NOTES; do echo "Deleting bot note: $NOTE_ID" curl -s --request DELETE --header "PRIVATE-TOKEN: $GITLAB_API_TOKEN" \ "$GITLAB_API_URL/projects/$PROJECT_ID/merge_requests/$MR_IID/notes/$NOTE_ID" || true done + + # Clean up previous bot inline comments (discussion notes) + echo "Cleaning up previous bot inline comments (prefix: $COMMENT_PREFIX)..." + DISCUSSIONS=$(curl -s --header "PRIVATE-TOKEN: $GITLAB_API_TOKEN" \ + "$GITLAB_API_URL/projects/$PROJECT_ID/merge_requests/$MR_IID/discussions") + echo "$DISCUSSIONS" | jq -r ".[] | {did: .id, notes: [.notes[] | select(.body | startswith(\"$COMMENT_PREFIX\")) | .id]} | select(.notes | length > 0) | .did as \$did | .notes[] | \"\\(\$did) \\(.)\"" | while read DISCUSSION_ID NOTE_ID; do + echo "Deleting bot inline comment: discussion=$DISCUSSION_ID note=$NOTE_ID" + curl -s --request DELETE --header "PRIVATE-TOKEN: $GITLAB_API_TOKEN" \ + "$GITLAB_API_URL/projects/$PROJECT_ID/merge_requests/$MR_IID/discussions/$DISCUSSION_ID/notes/$NOTE_ID" || true + done echo "Cleanup complete." - | @@ -138,28 +150,22 @@ tabnine-code-review: Based on Phase A, classify this MR into a risk tier: **Tier 1 - Low Risk** (docs, config, tests, typo fixes, dependency bumps with no code changes): - - Skip Phase C2 (cross-repo analysis) and Phase C3 (infra review) entirely. - - Post only the summary comment (Phase E) with a brief confirmation. + - Skip Phase B2 (cross-repo analysis) and Phase B3 (infra review) entirely. + - Post only the summary comment (Phase D) with a brief confirmation. - Maximum inline comments: 1 (only for genuine bugs). **Tier 2 - Standard** (feature work, refactors, most bug fixes): - - Run full Phase C audit. - - Run Phase C2 only if the diff touches public APIs, shared libraries, or interface definitions. + - Run full Phase B audit. + - Run Phase B2 only if the diff touches public APIs, shared libraries, or interface definitions. - Maximum inline comments: 5. **Tier 3 - High Risk** (security changes, auth/authz, data migrations, public API changes, infrastructure/deployment changes, shared library changes): - - Run all phases including full Phase C2 and Phase C3. + - Run all phases including full Phase B2 and Phase B3. - Maximum inline comments: 8. Determine the tier before proceeding. State the tier in your summary. - ### Phase B: Clean Up Previous Inline Comments - Before posting new inline comments, delete all previous Tabnine PR Bot inline review comments: - 1. List all MR discussions: curl -s --header 'PRIVATE-TOKEN: \$GITLAB_API_TOKEN' '\$GITLAB_API_URL/projects/\$PROJECT_ID/merge_requests/\$MR_IID/discussions' - 2. For each discussion note whose body starts with '#### Tabnine PR Bot', delete it using: curl -s --request DELETE --header 'PRIVATE-TOKEN: \$GITLAB_API_TOKEN' '\$GITLAB_API_URL/projects/\$PROJECT_ID/merge_requests/\$MR_IID/discussions/DISCUSSION_ID/notes/NOTE_ID' - Note: Summary notes are cleaned up automatically before this review runs, so you only need to handle inline comments here. - - ### Phase C: Engineering Audit + ### Phase B: Engineering Audit Evaluate the code against these pillars IN PRIORITY ORDER. Spend the most effort on the highest-priority categories. **P0 - Correctness & Logic** (most critical): @@ -223,7 +229,7 @@ tabnine-code-review: - Are names self-explanatory? Are complex algorithms or non-obvious business rules documented? - Does the code follow existing project conventions? - ### Phase C2: Cross-Repository Impact Analysis (Skip for Tier 1) + ### Phase B2: Cross-Repository Impact Analysis (Skip for Tier 1) Use the Tabnine MCP context engine tools to analyze cross-repository impact of this MR: 1. **List repositories**: Call 'remote_repositories_list' to discover the organization's repository ecosystem. 2. **Find related services**: Call 'remote_search_assets' with queries derived from the changed files to find SERVICE_SUMMARY and OPENAPI_SPEC assets related to the code being modified. @@ -241,14 +247,14 @@ tabnine-code-review: - Services or repositories as nodes - Call or dependency relationships as directed edges - Use this diagram to reason about blast radius, layering violations, or unintended coupling. - 8. **Compile findings** for inclusion in the Phase E summary comment: + 8. **Compile findings** for inclusion in the Phase D summary comment: - Architecture violations or new inter-service dependencies introduced by this MR - Other repositories or services that consume the changed code (with file and line references where possible) - High-level architecture insight derived from SERVICE_SUMMARY / OPENAPI_SPEC assets - ASCII architecture diagram (only if it adds clarity; omit if trivial) - If no cross-repo impact is found, state 'No cross-repository impact detected' - ### Phase C3: Infrastructure & Configuration Review (Tier 3 only, skip if no infra files in diff) + ### Phase B3: Infrastructure & Configuration Review (Tier 3 only, skip if no infra files in diff) If the MR modifies infrastructure or configuration files, apply these checks: **Dockerfiles**: Are base images pinned (not 'latest')? Running as non-root? Secrets not in build args? **CI/CD Pipelines**: Are dependencies version-pinned? Could this break the pipeline for other branches? Secrets via secure stores? @@ -256,7 +262,7 @@ tabnine-code-review: **Terraform/IaC**: Any resource destruction? Blast radius limited? New resources tagged consistently? **Config/Env Vars**: New vars have safe defaults? Sensitive values from secret managers? App fails fast if required config missing? - ### Phase C4: Coaching Guidelines Compliance + ### Phase B4: Coaching Guidelines Compliance Use the Tabnine MCP 'get_guidelines' tool to retrieve the organization's coaching guidelines and validate the changed code against them: 1. **Identify languages**: Determine which programming languages are present in the diff (e.g., python, javascript, typescript, java, php, go, cpp, csharp, kotlin). 2. **Fetch guidelines**: Call 'get_guidelines' with the 'language' parameter for each language detected in the diff to retrieve applicable coaching guidelines. If changed files span multiple languages, call it once per language. @@ -265,7 +271,7 @@ tabnine-code-review: - Post an inline comment referencing the guideline ID and description. Coaching guideline violations are exempt from the tier comment budget -- every violation must be reported. - Use the guideline's severity to map to the inline comment severity: Critical -> [Critical], Error -> [Warning], Warning -> [Suggestion], Info -> [Suggestion]. - Include the guideline's recommended fix or best practice in the 'Suggested fix' section of the comment. - 5. **Include in summary**: Add a 'Coaching Guidelines' section to the Phase E summary if any violations were found. List violated guideline IDs grouped by severity. If no violations were found, state 'All changed code complies with coaching guidelines.' + 5. **Include in summary**: Add a 'Coaching Guidelines' section to the Phase D summary if any violations were found. List violated guideline IDs grouped by severity. If no violations were found, state 'All changed code complies with coaching guidelines.' ## 4. Comment Value Threshold (CRITICAL FILTER) @@ -280,7 +286,7 @@ tabnine-code-review: - Introduces a deployment risk (non-backward-compatible migration, missing feature flag for risky change) - Changes CI/CD configuration in a way that could break the build for other contributors - Violates critical project patterns (e.g., error handling, path handling) - - Violates any organization coaching guideline, regardless of severity (from Phase C4) + - Violates any organization coaching guideline, regardless of severity (from Phase B4) - Makes the code significantly harder to maintain or debug **DO NOT comment on:** @@ -303,9 +309,9 @@ tabnine-code-review: **Golden Rule**: If removing your comment would NOT increase the risk of bugs, security issues, or maintenance problems, DO NOT POST IT. - ### Phase D: Inline Comments + ### Phase C: Inline Comments - For each potential issue from Phase C: + For each potential issue from Phase B: 1. Apply the Comment Value Threshold filter above 2. Enforce the tier comment budget (Tier 1: max 1, Tier 2: max 5, Tier 3: max 8). If you have more findings than the budget, keep only the highest-severity ones. 3. Verify the file exists in the diff and the line number is within changed lines @@ -322,15 +328,21 @@ tabnine-code-review: - **[Warning]** -- Logic issues, edge cases, performance concerns. Strongly recommended to fix. - **[Suggestion]** -- Improvements to maintainability or clarity. Author's discretion. + **FILE-LEVEL vs LINE-LEVEL comments**: If a comment applies to the entire file rather than specific lines (e.g., a deleted file, a file that should not exist, or a concern about the file as a whole), post a general MR discussion (without the 'position' parameter) and mention the filename in the body. Never post an inline comment that covers all or most lines of a file -- this creates an excessively large comment. Use file-level comments for file-wide feedback. + Submit inline comments using the GitLab Discussions API: - **IMPORTANT**: All comments MUST start with '#### Tabnine PR Bot' on the first line, followed by a blank line, then your formatted comment content. + **IMPORTANT**: All comments MUST start with '$COMMENT_PREFIX' on the first line, followed by a blank line, then your formatted comment content. + For FILE-LEVEL comments (when the comment applies to the entire file, not specific lines -- post as a general discussion, not an inline comment): + curl -s --request POST --header 'PRIVATE-TOKEN: \$GITLAB_API_TOKEN' --header 'Content-Type: application/json' \\ + --data '{\"body\": \"$COMMENT_PREFIX\n\n**File: FILE_PATH**\n\nYOUR_COMMENT\"}' \\ + '\$GITLAB_API_URL/projects/\$PROJECT_ID/merge_requests/\$MR_IID/discussions' For inline comments on specific lines: curl -s --request POST --header 'PRIVATE-TOKEN: \$GITLAB_API_TOKEN' --header 'Content-Type: application/json' \\ - --data '{\"body\": \"#### Tabnine PR Bot\n\nYOUR_COMMENT\", \"position\": {\"base_sha\": \"\$BASE_SHA\", \"head_sha\": \"\$HEAD_SHA\", \"start_sha\": \"\$BASE_SHA\", \"position_type\": \"text\", \"new_path\": \"FILE_PATH\", \"new_line\": LINE_NUMBER}}' \\ + --data '{\"body\": \"$COMMENT_PREFIX\n\nYOUR_COMMENT\", \"position\": {\"base_sha\": \"\$BASE_SHA\", \"head_sha\": \"\$HEAD_SHA\", \"start_sha\": \"\$BASE_SHA\", \"position_type\": \"text\", \"new_path\": \"FILE_PATH\", \"new_line\": LINE_NUMBER}}' \\ '\$GITLAB_API_URL/projects/\$PROJECT_ID/merge_requests/\$MR_IID/discussions' For multi-line inline comments: curl -s --request POST --header 'PRIVATE-TOKEN: \$GITLAB_API_TOKEN' --header 'Content-Type: application/json' \\ - --data '{\"body\": \"#### Tabnine PR Bot\n\nYOUR_COMMENT\", \"position\": {\"base_sha\": \"\$BASE_SHA\", \"head_sha\": \"\$HEAD_SHA\", \"start_sha\": \"\$BASE_SHA\", \"position_type\": \"text\", \"new_path\": \"FILE_PATH\", \"new_line\": END_LINE_NUMBER, \"line_range\": {\"start\": {\"line_code\": \"START_LINE_CODE\", \"type\": \"new\"}, \"end\": {\"line_code\": \"END_LINE_CODE\", \"type\": \"new\"}}}}' \\ + --data '{\"body\": \"$COMMENT_PREFIX\n\nYOUR_COMMENT\", \"position\": {\"base_sha\": \"\$BASE_SHA\", \"head_sha\": \"\$HEAD_SHA\", \"start_sha\": \"\$BASE_SHA\", \"position_type\": \"text\", \"new_path\": \"FILE_PATH\", \"new_line\": END_LINE_NUMBER, \"line_range\": {\"start\": {\"line_code\": \"START_LINE_CODE\", \"type\": \"new\"}, \"end\": {\"line_code\": \"END_LINE_CODE\", \"type\": \"new\"}}}}' \\ '\$GITLAB_API_URL/projects/\$PROJECT_ID/merge_requests/\$MR_IID/discussions' **Code Suggestions**: Use GitLab's suggestion syntax ONLY when the fix is clear, unambiguous, and replaces 10 or fewer lines: \`\`\`suggestion:-0+0 @@ -338,12 +350,12 @@ tabnine-code-review: \`\`\` For larger changes or context-dependent fixes, provide guidance as a regular comment without the suggestion block. - ### Phase E: Final Summary + ### Phase D: Final Summary After submitting inline comments (or if zero comments were posted), post the holistic summary. The summary is the MOST IMPORTANT output -- most developers read only this. Create the summary note using the GitLab Notes API: curl -s --request POST --header 'PRIVATE-TOKEN: \$GITLAB_API_TOKEN' --header 'Content-Type: application/json' \\ - --data '{\"body\": \"#### Tabnine PR Bot\n\nYOUR_SUMMARY\"}' \\ + --data '{\"body\": \"$COMMENT_PREFIX\n\nYOUR_SUMMARY\"}' \\ '\$GITLAB_API_URL/projects/\$PROJECT_ID/merge_requests/\$MR_IID/notes' Structure your summary as follows: @@ -351,8 +363,8 @@ tabnine-code-review: - **What This MR Does** (1-2 sentences): Demonstrate you understood the author's intent. This builds trust. - **Assessment** (1-3 sentences): Overall verdict. Is this good to merge? Any blockers? - **Key Findings** (only if findings exist): Group by severity -- [Critical] first, then [Warning], then [Suggestion]. List max 3-5 findings; if more, prioritize by severity. - - **Cross-Repository Impact** (Tier 2-3 only): Findings from Phase C2, or 'No cross-repository impact detected.' - - **Coaching Guidelines**: Findings from Phase C4 -- list violated guideline IDs grouped by severity, or 'All changed code complies with coaching guidelines.' + - **Cross-Repository Impact** (Tier 2-3 only): Findings from Phase B2, or 'No cross-repository impact detected.' + - **Coaching Guidelines**: Findings from Phase B4 -- list violated guideline IDs grouped by severity, or 'All changed code complies with coaching guidelines.' - **Deployment & Operations** (only if relevant): Migration safety, feature flag requirements, observability gaps, infrastructure concerns. Omit entirely if no operational concerns. - **What Looks Good** (1-3 bullet points): Specific things the author did well (good test coverage, clean error handling, thoughtful API design). Always find something positive. diff --git a/README.md b/README.md index 6e00846..0804488 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ permissions: ```yaml - name: Review PR - uses: codota/tabnine-pr-agent@v1 + uses: codota/tabnine-pr-agent@v2 continue-on-error: true with: # Tabnine authentication token — required @@ -63,6 +63,20 @@ permissions: # Model ID for the Tabnine CLI agent (optional, overrides DEFAULT_MODEL_ID in action.yml) # model_id: "your-model-id" + + # Custom prompt to replace the default code review (optional) + # prompt_override: "Your custom prompt here" + + # Display name for the agent step (optional, default: 'Tabnine Agent') + # step_name: "Tabnine Agent" + + # Prefix used to identify bot comments for cleanup (optional, default: '#### Tabnine PR Bot') + # Use a unique value per action invocation to avoid cross-cleanup. + # comment_prefix: "#### Tabnine PR Bot" + + # Set to "true" to delete settings.json after each run (optional, default: "false") + # Recommended for self-hosted runners. + # cleanup: "true" ``` ### Inputs @@ -77,6 +91,10 @@ permissions: | `base_sha` | Yes | — | PR base commit SHA | | `tabnine_host` | No | `https://console.tabnine.com` | Tabnine host URL (for self-hosted / EMT installations) | | `model_id` | No | — | Model ID for the Tabnine CLI agent. If omitted, falls back to `DEFAULT_MODEL_ID` in `action.yml` or the system default from the admin console. | +| `prompt_override` | No | — | Custom prompt to replace the default code review prompt. When provided, the agent runs your prompt instead of the built-in review. | +| `step_name` | No | `Tabnine Agent` | Display name for the agent step. | +| `comment_prefix` | No | `#### Tabnine PR Bot` | Prefix used to identify bot comments for cleanup. Use a unique value per action invocation to avoid cross-cleanup. | +| `cleanup` | No | `false` | Set to `"true"` to delete `settings.json` after each run. Recommended for self-hosted runners. | ## Full Workflow Example @@ -102,7 +120,7 @@ jobs: fetch-depth: 0 - name: Review PR - uses: codota/tabnine-pr-agent@v1 + uses: codota/tabnine-pr-agent@v2 continue-on-error: true with: TABNINE_KEY: ${{ secrets.TABNINE_KEY }} @@ -129,6 +147,8 @@ Set the following CI/CD variables in **Settings > CI/CD > Variables**: | `GITLAB_API_TOKEN` | Yes | GitLab personal or project access token with `api` scope. Mark as **Masked**. | | `TABNINE_HOST` | No | Tabnine host URL for self-hosted / EMT installations (default: `https://console.tabnine.com`) | | `TABNINE_MODEL_ID` | No | Model ID for the Tabnine CLI agent. If empty, uses the system default from the admin console. | +| `TABNINE_CLEANUP` | No | Set to `"true"` to delete `settings.json` after each run. Recommended for self-hosted runners. | +| `TABNINE_COMMENT_PREFIX` | No | Prefix used to identify bot comments for cleanup (default: `#### Tabnine PR Bot`). | ## Usage @@ -166,6 +186,8 @@ Set the following repository variables in **Repository Settings > Pipelines > Re | `BB_API_TOKEN` | Yes | Bitbucket token with `pullrequest:write` and `repository:read` scopes. Mark as **Secured**. | | `TABNINE_HOST` | No | Tabnine host URL for self-hosted / EMT installations (default: `https://console.tabnine.com`) | | `TABNINE_MODEL_ID` | No | Model ID for the Tabnine CLI agent. If empty, falls back to `DEFAULT_MODEL_ID` in the pipeline yml or the system default from the admin console. | +| `TABNINE_CLEANUP` | No | Set to `"true"` to delete `settings.json` after each run. Recommended for self-hosted runners. | +| `TABNINE_COMMENT_PREFIX` | No | Prefix used to identify bot comments for cleanup (default: `#### Tabnine PR Bot`). | ## Usage diff --git a/action.yml b/action.yml index b4932ee..3858ab1 100644 --- a/action.yml +++ b/action.yml @@ -1,7 +1,9 @@ # Tabnine PR Agent for GitHub # -# This composite action runs an AI-powered code review on pull requests -# using the Tabnine CLI Agent. +# This composite action runs a Tabnine CLI Agent task on pull requests. +# By default it performs an AI-powered code review, but the prompt can be +# overridden to run any custom task (e.g., enforcing conventions, generating +# summaries, or checking documentation). # # Required Inputs: # TABNINE_KEY - Tabnine authentication credentials (JSON). Store as a repository secret. @@ -14,10 +16,13 @@ # Optional Inputs: # tabnine_host - Tabnine host URL (default: https://console.tabnine.com) # model_id - Model ID for the Tabnine CLI agent. If omitted, falls back to DEFAULT_MODEL_ID below or the system default from the admin console. +# prompt_override - Custom prompt to replace the default code review prompt. When set, the agent runs your prompt instead. +# step_name - Display name for the agent step (default: 'Tabnine Agent'). +# comment_prefix - Prefix used to identify bot comments for cleanup (default: '#### Tabnine PR Bot'). Each action invocation should use a unique prefix to avoid interfering with other invocations. # cleanup - Set to "true" to delete settings.json after each run (default: "false"). Recommended for self-hosted runners. -name: 'Tabnine: Code Review' -description: 'AI-powered code review using Tabnine CLI Agent' +name: 'Tabnine PR Agent' +description: 'Run a Tabnine CLI Agent task on a pull request' inputs: TABNINE_KEY: @@ -50,6 +55,18 @@ inputs: base_sha: required: true description: 'PR base commit SHA' + prompt_override: + required: false + description: 'Custom prompt to replace the default code review prompt. When provided, this prompt is passed to the Tabnine CLI agent instead of the built-in code review prompt.' + default: '' + step_name: + required: false + description: 'Display name for the agent step.' + default: 'Tabnine Agent' + comment_prefix: + required: false + description: 'Prefix used to identify bot comments for cleanup. Use a unique value per action invocation to avoid cross-cleanup.' + default: '#### Tabnine PR Bot' runs: using: 'composite' @@ -117,15 +134,16 @@ runs: # Use a different env var name to avoid conflict with GITHUB_TOKEN echo "$GH_TOKEN_INPUT" | gh auth login --with-token - - name: Clean Up Previous Bot Summary Comments + - name: Clean Up Previous Bot Comments shell: bash env: GH_TOKEN: ${{ inputs.github_token }} + COMMENT_PREFIX: ${{ inputs.comment_prefix }} run: | - echo "Cleaning up previous Tabnine PR Bot summary comments..." + echo "Cleaning up previous bot summary comments (prefix: $COMMENT_PREFIX)..." - # Get all issue comments on the PR - COMMENTS=$(gh api "/repos/${{ inputs.repository }}/issues/${{ inputs.pull_request_number }}/comments" --jq '.[] | select(.body | startswith("#### Tabnine PR Bot")) | .id') + # Get all issue comments on the PR matching the configured prefix + COMMENTS=$(gh api "/repos/${{ inputs.repository }}/issues/${{ inputs.pull_request_number }}/comments" --jq '[.[] | select(.body | startswith(env.COMMENT_PREFIX)) | .id] | .[]') # Delete all bot summary comments to prevent duplicates # Note: DELETE endpoint is /repos/{owner}/{repo}/issues/comments/{comment_id} (no issue number) @@ -134,17 +152,32 @@ runs: gh api --method DELETE "/repos/${{ inputs.repository }}/issues/comments/$COMMENT_ID" || true done + # Get all pull-request review (inline) comments matching the configured prefix + PR_COMMENTS=$(gh api "/repos/${{ inputs.repository }}/pulls/${{ inputs.pull_request_number }}/comments" --jq '[.[] | select(.body | startswith(env.COMMENT_PREFIX)) | .id] | .[]') + + # Delete all bot inline review comments to prevent duplicates + for COMMENT_ID in $PR_COMMENTS; do + echo "Deleting bot inline review comment: $COMMENT_ID" + gh api --method DELETE "/repos/${{ inputs.repository }}/pulls/comments/$COMMENT_ID" || true + done + echo "Cleanup complete." - - name: Code Review + - name: ${{ inputs.step_name }} shell: bash env: TABNINE_TOKEN: ${{ inputs.TABNINE_KEY }} + PROMPT_OVERRIDE: ${{ inputs.prompt_override }} run: | if [ -z "$TABNINE_TOKEN" ]; then echo "Error: TABNINE_KEY is required" exit 1 fi + + if [ -n "$PROMPT_OVERRIDE" ]; then + ~/.local/bin/tabnine -y -p "$PROMPT_OVERRIDE" + exit $? + fi ~/.local/bin/tabnine -y -p "## 1. Persona & Context You are a collaborative Staff Engineer acting as a second pair of eyes on a teammate's PR. @@ -171,28 +204,22 @@ runs: Based on Phase A, classify this PR into a risk tier: **Tier 1 - Low Risk** (docs, config, tests, typo fixes, dependency bumps with no code changes): - - Skip Phase C2 (cross-repo analysis) and Phase C3 (infra review) entirely. - - Post only the summary comment (Phase E) with a brief confirmation. + - Skip Phase B2 (cross-repo analysis) and Phase B3 (infra review) entirely. + - Post only the summary comment (Phase D) with a brief confirmation. - Maximum inline comments: 1 (only for genuine bugs). **Tier 2 - Standard** (feature work, refactors, most bug fixes): - - Run full Phase C audit. - - Run Phase C2 only if the diff touches public APIs, shared libraries, or interface definitions. + - Run full Phase B audit. + - Run Phase B2 only if the diff touches public APIs, shared libraries, or interface definitions. - Maximum inline comments: 5. **Tier 3 - High Risk** (security changes, auth/authz, data migrations, public API changes, infrastructure/deployment changes, shared library changes): - - Run all phases including full Phase C2 and Phase C3. + - Run all phases including full Phase B2 and Phase B3. - Maximum inline comments: 8. Determine the tier before proceeding. State the tier in your summary. - ### Phase B: Clean Up Previous Inline Comments - Before posting new inline comments, delete all previous Tabnine PR Bot inline review comments: - 1. List all review comments: 'gh api /repos/${{ inputs.repository }}/pulls/${{ inputs.pull_request_number }}/comments' - 2. For each comment whose body starts with '#### Tabnine PR Bot', delete it using: 'gh api --method DELETE /repos/${{ inputs.repository }}/pulls/${{ inputs.pull_request_number }}/comments/COMMENT_ID' - Note: Summary comments are cleaned up automatically before this review runs, so you only need to handle inline comments here. - - ### Phase C: Engineering Audit + ### Phase B: Engineering Audit Evaluate the code against these pillars IN PRIORITY ORDER. Spend the most effort on the highest-priority categories. **P0 - Correctness & Logic** (most critical): @@ -256,7 +283,7 @@ runs: - Are names self-explanatory? Are complex algorithms or non-obvious business rules documented? - Does the code follow existing project conventions? - ### Phase C2: Cross-Repository Impact Analysis (Skip for Tier 1) + ### Phase B2: Cross-Repository Impact Analysis (Skip for Tier 1) Use the Tabnine MCP context engine tools to analyze cross-repository impact of this PR: 1. **List repositories**: Call 'remote_repositories_list' to discover the organization's repository ecosystem. 2. **Find related services**: Call 'remote_search_assets' with queries derived from the changed files to find SERVICE_SUMMARY and OPENAPI_SPEC assets related to the code being modified. @@ -274,14 +301,14 @@ runs: - Services or repositories as nodes - Call or dependency relationships as directed edges - Use this diagram to reason about blast radius, layering violations, or unintended coupling. - 8. **Compile findings** for inclusion in the Phase E summary comment: + 8. **Compile findings** for inclusion in the Phase D summary comment: - Architecture violations or new inter-service dependencies introduced by this PR - Other repositories or services that consume the changed code (with file and line references where possible) - High-level architecture insight derived from SERVICE_SUMMARY / OPENAPI_SPEC assets - ASCII architecture diagram (only if it adds clarity; omit if trivial) - If no cross-repo impact is found, state 'No cross-repository impact detected' - ### Phase C3: Infrastructure & Configuration Review (Tier 3 only, skip if no infra files in diff) + ### Phase B3: Infrastructure & Configuration Review (Tier 3 only, skip if no infra files in diff) If the PR modifies infrastructure or configuration files, apply these checks: **Dockerfiles**: Are base images pinned (not 'latest')? Running as non-root? Secrets not in build args? **CI/CD Pipelines**: Are dependencies version-pinned? Could this break the pipeline for other branches? Secrets via secure stores? @@ -289,7 +316,7 @@ runs: **Terraform/IaC**: Any resource destruction? Blast radius limited? New resources tagged consistently? **Config/Env Vars**: New vars have safe defaults? Sensitive values from secret managers? App fails fast if required config missing? - ### Phase C4: Coaching Guidelines Compliance + ### Phase B4: Coaching Guidelines Compliance Use the Tabnine MCP 'get_guidelines' tool to retrieve the organization's coaching guidelines and validate the changed code against them: 1. **Identify languages**: Determine which programming languages are present in the diff (e.g., python, javascript, typescript, java, php, go, cpp, csharp, kotlin). 2. **Fetch guidelines**: Call 'get_guidelines' with the 'language' parameter for each language detected in the diff to retrieve applicable coaching guidelines. If changed files span multiple languages, call it once per language. @@ -298,7 +325,7 @@ runs: - Post an inline comment referencing the guideline ID and description. Coaching guideline violations are exempt from the tier comment budget -- every violation must be reported. - Use the guideline's severity to map to the inline comment severity: Critical -> [Critical], Error -> [Warning], Warning -> [Suggestion], Info -> [Suggestion]. - Include the guideline's recommended fix or best practice in the 'Suggested fix' section of the comment. - 5. **Include in summary**: Add a 'Coaching Guidelines' section to the Phase E summary if any violations were found. List violated guideline IDs grouped by severity. If no violations were found, state 'All changed code complies with coaching guidelines.' + 5. **Include in summary**: Add a 'Coaching Guidelines' section to the Phase D summary if any violations were found. List violated guideline IDs grouped by severity. If no violations were found, state 'All changed code complies with coaching guidelines.' ## 4. Comment Value Threshold (CRITICAL FILTER) @@ -313,7 +340,7 @@ runs: - Introduces a deployment risk (non-backward-compatible migration, missing feature flag for risky change) - Changes CI/CD configuration in a way that could break the build for other contributors - Violates critical project patterns (e.g., error handling, path handling) - - Violates any organization coaching guideline, regardless of severity (from Phase C4) + - Violates any organization coaching guideline, regardless of severity (from Phase B4) - Makes the code significantly harder to maintain or debug **DO NOT comment on:** @@ -336,9 +363,9 @@ runs: **Golden Rule**: If removing your comment would NOT increase the risk of bugs, security issues, or maintenance problems, DO NOT POST IT. - ### Phase D: Inline Comments + ### Phase C: Inline Comments - For each potential issue from Phase C: + For each potential issue from Phase B: 1. Apply the Comment Value Threshold filter above 2. Enforce the tier comment budget (Tier 1: max 1, Tier 2: max 5, Tier 3: max 8). If you have more findings than the budget, keep only the highest-severity ones. 3. Verify the file exists in the diff and the line number is within changed lines @@ -358,17 +385,17 @@ runs: **FILE-LEVEL vs LINE-LEVEL comments**: If a comment applies to the entire file rather than specific lines (e.g., a deleted file, a file that should not exist, or a concern about the file as a whole), post a FILE-LEVEL comment using 'subject_type=file' instead of a multi-line comment spanning all lines. Never post a multi-line comment that covers all or most lines of a file -- this creates an excessively large comment. Use file-level comments for file-wide feedback. Submit inline comments using: - **IMPORTANT**: All comments MUST start with '#### Tabnine PR Bot' on the first line, followed by a blank line, then your formatted comment content. + **IMPORTANT**: All comments MUST start with '${{ inputs.comment_prefix }}' on the first line, followed by a blank line, then your formatted comment content. For FILE-LEVEL comments (when the comment applies to the entire file, not specific lines): - gh api --method POST -H 'Accept: application/vnd.github+json' /repos/${{ inputs.repository }}/pulls/${{ inputs.pull_request_number }}/comments -f body='#### Tabnine PR Bot + gh api --method POST -H 'Accept: application/vnd.github+json' /repos/${{ inputs.repository }}/pulls/${{ inputs.pull_request_number }}/comments -f body='${{ inputs.comment_prefix }} YOUR_COMMENT' -f commit_id='${{ inputs.head_sha }}' -f path='FILE_PATH' -f subject_type='file' For SINGLE-LINE comments: - gh api --method POST -H 'Accept: application/vnd.github+json' /repos/${{ inputs.repository }}/pulls/${{ inputs.pull_request_number }}/comments -f body='#### Tabnine PR Bot + gh api --method POST -H 'Accept: application/vnd.github+json' /repos/${{ inputs.repository }}/pulls/${{ inputs.pull_request_number }}/comments -f body='${{ inputs.comment_prefix }} YOUR_COMMENT' -f commit_id='${{ inputs.head_sha }}' -f path='FILE_PATH' -F line=LINE_NUMBER -f side='RIGHT' For MULTI-LINE comments: - gh api --method POST -H 'Accept: application/vnd.github+json' /repos/${{ inputs.repository }}/pulls/${{ inputs.pull_request_number }}/comments -f body='#### Tabnine PR Bot + gh api --method POST -H 'Accept: application/vnd.github+json' /repos/${{ inputs.repository }}/pulls/${{ inputs.pull_request_number }}/comments -f body='${{ inputs.comment_prefix }} YOUR_COMMENT' -f commit_id='${{ inputs.head_sha }}' -f path='FILE_PATH' -F start_line=START_LINE_NUMBER -f start_side='RIGHT' -F line=END_LINE_NUMBER -f side='RIGHT' **Code Suggestions**: Use GitHub's suggestion syntax ONLY when the fix is clear, unambiguous, and replaces 10 or fewer lines: @@ -377,11 +404,11 @@ runs: \`\`\` For larger changes or context-dependent fixes, provide guidance as a regular comment without the suggestion block. - ### Phase E: Final Summary + ### Phase D: Final Summary After submitting inline comments (or if zero comments were posted), post the holistic summary. The summary is the MOST IMPORTANT output -- most developers read only this. Create the summary comment using: - gh api --method POST /repos/${{ inputs.repository }}/issues/${{ inputs.pull_request_number }}/comments -f body='#### Tabnine PR Bot + gh api --method POST /repos/${{ inputs.repository }}/issues/${{ inputs.pull_request_number }}/comments -f body='${{ inputs.comment_prefix }} YOUR_SUMMARY' @@ -390,8 +417,8 @@ runs: - **What This PR Does** (1-2 sentences): Demonstrate you understood the author's intent. This builds trust. - **Assessment** (1-3 sentences): Overall verdict. Is this good to merge? Any blockers? - **Key Findings** (only if findings exist): Group by severity -- [Critical] first, then [Warning], then [Suggestion]. List max 3-5 findings; if more, prioritize by severity. - - **Cross-Repository Impact** (Tier 2-3 only): Findings from Phase C2, or 'No cross-repository impact detected.' - - **Coaching Guidelines**: Findings from Phase C4 -- list violated guideline IDs grouped by severity, or 'All changed code complies with coaching guidelines.' + - **Cross-Repository Impact** (Tier 2-3 only): Findings from Phase B2, or 'No cross-repository impact detected.' + - **Coaching Guidelines**: Findings from Phase B4 -- list violated guideline IDs grouped by severity, or 'All changed code complies with coaching guidelines.' - **Deployment & Operations** (only if relevant): Migration safety, feature flag requirements, observability gaps, infrastructure concerns. Omit entirely if no operational concerns. - **What Looks Good** (1-3 bullet points): Specific things the author did well (good test coverage, clean error handling, thoughtful API design). Always find something positive.