@@ -1,179 +1,88 @@
|
|||||||
# 🧩 PR Commenter for GitHub & Gitea
|
# 🧱 Git Auto Comment Action
|
||||||
|
|
||||||
A composite Action that posts PR comments from **large output files**, such as Terraform/OpenTofu plans, logs, or diffs — directly to **GitHub** or **Gitea** pull requests.
|
Automatically post comments or pull request reviews to **Gitea** or **GitHub**, with optional debug logging and diff parsing.
|
||||||
|
|
||||||
It’s based on [`tofu-pr-commenter`](https://github.com/alexnorell/tofu-pr-commenter) but extended for **Gitea compatibility**, **multi-line comment templates**, and **general-purpose content handling** (not just diffs).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🚀 Features
|
## 🚀 Features
|
||||||
|
|
||||||
- ✅ Works with **GitHub** and **Gitea** PR APIs
|
- 🧩 Supports **GitHub** and **Gitea**
|
||||||
- ✅ Handles **large text outputs** (plans, diffs, logs, etc.)
|
- 💬 Posts formatted PR comments or reviews
|
||||||
- ✅ Allows **multiline comment templates** with placeholders
|
- 🪶 Uses `{line}` / `{lines}` placeholders in templates
|
||||||
- ✅ Defaults to environment variables from the Action runner (no hardcoded repo info required)
|
- 🧠 Parses diffs to include relevant code changes
|
||||||
- ✅ Can run on **both GitHub Actions** and **Gitea Actions**
|
- 🎨 Optional **colorized debug mode**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ⚙️ Inputs
|
## 🧰 Inputs
|
||||||
|
|
||||||
| Name | Required | Default | Description |
|
| Name | Required | Default | Description |
|
||||||
|------|-----------|----------|-------------|
|
|------|-----------|----------|-------------|
|
||||||
| `platform` | ❌ | `github` | Platform type (`github` or `gitea`) |
|
| `platform` | No | `github` | Target platform (`github` or `gitea`) |
|
||||||
| `token` | ✅ | — | Access token for API requests (`GITHUB_TOKEN` or personal token) |
|
| `token` | ✅ | — | API token |
|
||||||
| `pr_index` | ✅ | — | Pull request number or index |
|
| `repo_owner` | ✅ | — | Repository owner |
|
||||||
| `repo_owner` | ❌ | `${{ github.repository_owner }}` | Repository owner |
|
| `repo_name` | ✅ | — | Repository name |
|
||||||
| `repo_name` | ❌ | `${{ github.repository }}` | Repository name |
|
| `pr_index` | ✅ | — | Pull request index (Gitea) or issue number (GitHub) |
|
||||||
| `api_url` | ❌ | `${{ github.api_url }}` | API URL for Gitea (required only for Gitea) |
|
| `api_url` | No | — | Base API URL (required for Gitea) |
|
||||||
| `content` | ❌ | — | Large text input — diff, plan, or log content |
|
| `diff` | No | — | Diff or plan text to include in the comment |
|
||||||
| `comment_template` | ❌ | See below | Comment body template supporting `{line}` and `{lines}` placeholders |
|
| `comment_template` | No | `"Auto-comment: changed line -> {line}"` | Template text. Supports `{line}` and `{lines}` placeholders |
|
||||||
|
| `debug` | No | `false` | Enable verbose, colorized debug logs |
|
||||||
### 🧠 Template Variables
|
|
||||||
|
|
||||||
| Placeholder | Description |
|
|
||||||
|--------------|--------------|
|
|
||||||
| `{line}` | The specific line being commented on (when parsed from diff-style input) |
|
|
||||||
| `{lines}` | The full set of added lines for that file or section |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🧩 Default `comment_template`
|
## 🧮 Example Usage
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
comment_template: |
|
name: Auto PR Comment
|
||||||
Auto-comment:
|
|
||||||
---
|
|
||||||
{line}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 💡 Example: GitHub Action Workflow
|
|
||||||
```yaml
|
|
||||||
name: Comment Terraform Plan on PR
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
types: [opened, synchronize]
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
plan-comment:
|
comment:
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Run Terraform Plan
|
|
||||||
id: plan
|
|
||||||
run: |
|
|
||||||
terraform plan -no-color > plan.txt
|
|
||||||
echo "plan_text<<EOF" >> $GITHUB_OUTPUT
|
|
||||||
cat plan.txt >> $GITHUB_OUTPUT
|
|
||||||
echo "EOF" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Comment Plan on GitHub PR
|
|
||||||
uses: "https://gitea.example.com/your-org/pr-commenter-action@main"
|
|
||||||
with:
|
|
||||||
platform: github
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
pr_index: ${{ github.event.pull_request.number }}
|
|
||||||
content: ${{ steps.plan.outputs.plan_text }}
|
|
||||||
comment_template: |
|
|
||||||
🚀 **Terraform Plan Summary**
|
|
||||||
```
|
|
||||||
{lines}
|
|
||||||
```
|
|
||||||
```
|
|
||||||
|
|
||||||
## 💡 Example: Gitea Action Workflow
|
|
||||||
```yaml
|
|
||||||
name: Comment Plan on PR (Gitea)
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
plan-comment:
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Run Tofu Plan
|
- name: Post PR Comment
|
||||||
id: tofu
|
uses: your-org/git-auto-comment@main
|
||||||
run: |
|
|
||||||
tofu plan -no-color > tofu-plan.txt
|
|
||||||
echo "plan_text<<EOF" >> $GITEA_OUTPUT
|
|
||||||
cat tofu-plan.txt >> $GITEA_OUTPUT
|
|
||||||
echo "EOF" >> $GITEA_OUTPUT
|
|
||||||
|
|
||||||
- name: Post Plan to Gitea PR
|
|
||||||
uses: "https://gitea.example.com/your-org/pr-commenter-action@main"
|
|
||||||
with:
|
with:
|
||||||
platform: gitea
|
platform: gitea
|
||||||
token: ${{ secrets.GITEA_TOKEN }}
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
repo_owner: "tar-valon"
|
||||||
|
repo_name: "terraform-configs"
|
||||||
|
pr_index: ${{ github.event.pull_request.number }}
|
||||||
api_url: "https://gitea.example.com/api/v1"
|
api_url: "https://gitea.example.com/api/v1"
|
||||||
pr_index: ${{ gitea.event.pull_request.number }}
|
diff: |
|
||||||
content: ${{ steps.tofu.outputs.plan_text }}
|
+ added line one
|
||||||
|
+ added line two
|
||||||
comment_template: |
|
comment_template: |
|
||||||
🧠 **OpenTofu Plan Diff**
|
🧱 **Terraform Plan Output**
|
||||||
```
|
```
|
||||||
{lines}
|
{lines}
|
||||||
```
|
```
|
||||||
|
debug: "true"
|
||||||
```
|
```
|
||||||
|
## 🧩 Debug Mode
|
||||||
|
|
||||||
## 🪵 Example: Posting Large Log Output
|
Set `debug: "true"` (or environment variable `DEBUG=true`) to enable verbose, colorized output:
|
||||||
```yaml
|
- Prints API endpoint, payload size, and preview
|
||||||
- name: Upload build logs to PR
|
- Truncates long payloads automatically
|
||||||
uses: "https://gitea.example.com/your-org/pr-commenter-action@main"
|
- Highlights errors and successes in color
|
||||||
with:
|
|
||||||
platform: gitea
|
|
||||||
token: ${{ secrets.GITEA_TOKEN }}
|
|
||||||
api_url: "https://gitea.example.com/api/v1"
|
|
||||||
pr_index: 42
|
|
||||||
content: ${{ steps.build.outputs.log }}
|
|
||||||
comment_template: |
|
|
||||||
🧾 **Build Log Summary**
|
|
||||||
```
|
|
||||||
{lines}
|
|
||||||
```
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🧰 Local Development
|
## 🧪 Local Testing
|
||||||
|
```bash
|
||||||
You can test the script locally by exporting the necessary environment variables and running:
|
|
||||||
|
|
||||||
```
|
|
||||||
export PLATFORM=gitea
|
export PLATFORM=gitea
|
||||||
export TOKEN=<your_token>
|
export TOKEN=your_token
|
||||||
export REPO_OWNER=your-org
|
export REPO_OWNER=myorg
|
||||||
export REPO_NAME=your-repo
|
export REPO_NAME=myrepo
|
||||||
export PR_INDEX=42
|
export PR_INDEX=42
|
||||||
export API_URL=https://gitea.example.com/api/v1
|
export API_URL=https://gitea.example.com/api/v1
|
||||||
export CONTENT="$(cat plan.txt)"
|
export COMMENT_TEMPLATE="Plan output:\n{lines}"
|
||||||
python3 comment_pr.py
|
export DIFF="$(git diff HEAD~1)"
|
||||||
```
|
export DEBUG=true
|
||||||
|
|
||||||
## ⚠️ Limitations & Tips for Large Files
|
python git-auto-comment.py
|
||||||
|
```
|
||||||
1. GitHub & Gitea Comment Limits
|
|
||||||
- GitHub: max ~65,536 characters per comment.
|
|
||||||
- Gitea: may vary depending on server configuration.
|
|
||||||
|
|
||||||
2. Chunk Large Content
|
|
||||||
- For extremely long plans/logs, split content into smaller chunks and post multiple comments.
|
|
||||||
- Example using shell `split`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
split -l 5000 plan.txt plan_chunk_
|
|
||||||
for file in plan_chunk_*; do
|
|
||||||
CONTENT=$(cat "$file")
|
|
||||||
python3 comment_pr.py ...
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Diff Parsing
|
|
||||||
- If your content is a diff, {line} and {lines} placeholders work.
|
|
||||||
- Otherwise, the action will post the entire content under {lines}.
|
|
||||||
|
|
||||||
4. Avoid Passing Huge Strings via Env Variables
|
|
||||||
- Always prefer writing output to a file and reading it in the script.
|
|
||||||
+49
-32
@@ -1,61 +1,78 @@
|
|||||||
name: "PR Commenter (GitHub/Gitea Compatible)"
|
name: "Git Auto Comment"
|
||||||
description: "Posts PR comments to GitHub or Gitea, supporting diffs or large file inputs (plans, logs, etc.)."
|
description: "Automatically post pull request comments or reviews on Gitea or GitHub."
|
||||||
author: "Trez.One / AlexNorell (adapted for Gitea)"
|
author: "Charish Patel"
|
||||||
|
branding:
|
||||||
|
icon: "message-square"
|
||||||
|
color: "blue"
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
platform:
|
platform:
|
||||||
description: "Target platform: github or gitea"
|
description: "Platform to use (github or gitea)."
|
||||||
required: false
|
required: false
|
||||||
default: "github"
|
default: "github"
|
||||||
|
|
||||||
token:
|
token:
|
||||||
description: "Auth token for GitHub or Gitea API"
|
description: "API token for authentication."
|
||||||
required: true
|
required: true
|
||||||
repo_name:
|
|
||||||
description: "Repository name (defaults to GITHUB_REPOSITORY)"
|
|
||||||
required: false
|
|
||||||
repo_owner:
|
repo_owner:
|
||||||
description: "Repository owner (defaults to GITHUB_REPOSITORY_OWNER)"
|
description: "Repository owner."
|
||||||
required: false
|
|
||||||
api_url:
|
|
||||||
description: "API base URL (required for Gitea)"
|
|
||||||
required: false
|
|
||||||
pr_index:
|
|
||||||
description: "Pull request index or number"
|
|
||||||
required: true
|
required: true
|
||||||
plan_file:
|
|
||||||
description: "Path to file containing large plan/log content"
|
repo_name:
|
||||||
|
description: "Repository name."
|
||||||
|
required: true
|
||||||
|
|
||||||
|
pr_index:
|
||||||
|
description: "Pull request index or issue number."
|
||||||
|
required: true
|
||||||
|
|
||||||
|
api_url:
|
||||||
|
description: "Base API URL (required for Gitea)."
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
|
diff:
|
||||||
|
description: "Diff or plan text to include in the comment."
|
||||||
|
required: false
|
||||||
|
|
||||||
comment_template:
|
comment_template:
|
||||||
description: "Template for comment body (supports {line} and {lines})"
|
description: "Template for comment body. Supports {line} and {lines} placeholders."
|
||||||
required: false
|
required: false
|
||||||
default: |
|
default: "Auto-comment: changed line -> {line}"
|
||||||
🚀 **Automated Comment**
|
|
||||||
---
|
debug:
|
||||||
{lines}
|
description: "Enable verbose debug logging with colorized output."
|
||||||
|
required: false
|
||||||
|
default: "false"
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: "composite"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Python virtual environment
|
- name: Install Python 3
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -y
|
||||||
|
sudo apt-get install -y python3 python3-venv python3-pip
|
||||||
|
|
||||||
|
- name: Set up venv and install deps
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
python3 -m venv venv
|
python3 -m venv venv
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
pip install --upgrade pip
|
pip install -r ${{ github.action_path }}/requirements.txt
|
||||||
pip install -r $GITHUB_ACTION_PATH/requirements.txt
|
|
||||||
echo "VENV_PATH=$PWD/venv" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Run git-auto-comment
|
- name: Run git-auto-comment
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
|
||||||
source $VENV_PATH/bin/activate
|
|
||||||
python3 $GITHUB_ACTION_PATH/git-auto-comment.py
|
|
||||||
env:
|
env:
|
||||||
PLATFORM: ${{ inputs.platform }}
|
PLATFORM: ${{ inputs.platform }}
|
||||||
TOKEN: ${{ inputs.token }}
|
TOKEN: ${{ inputs.token }}
|
||||||
REPO_NAME: ${{ inputs.repo_name }}
|
|
||||||
REPO_OWNER: ${{ inputs.repo_owner }}
|
REPO_OWNER: ${{ inputs.repo_owner }}
|
||||||
API_URL: ${{ inputs.api_url }}
|
REPO_NAME: ${{ inputs.repo_name }}
|
||||||
PR_INDEX: ${{ inputs.pr_index }}
|
PR_INDEX: ${{ inputs.pr_index }}
|
||||||
PLAN_FILE: ${{ inputs.plan_file }}
|
API_URL: ${{ inputs.api_url }}
|
||||||
|
DIFF: ${{ inputs.diff }}
|
||||||
COMMENT_TEMPLATE: ${{ inputs.comment_template }}
|
COMMENT_TEMPLATE: ${{ inputs.comment_template }}
|
||||||
|
DEBUG: ${{ inputs.debug }}
|
||||||
|
run: |
|
||||||
|
source venv/bin/activate
|
||||||
|
python ${{ github.action_path }}/git-auto-comment.py
|
||||||
|
|||||||
+97
-65
@@ -3,83 +3,115 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
import json
|
import json
|
||||||
|
import requests
|
||||||
|
|
||||||
# --- Check for required dependency ---
|
# --- ANSI color helpers ---
|
||||||
try:
|
def color(text, code):
|
||||||
import requests
|
return f"\033[{code}m{text}\033[0m"
|
||||||
except ImportError:
|
|
||||||
print(
|
|
||||||
"❌ The 'requests' library is not installed.\n"
|
|
||||||
"Please ensure it's available in your runner.\n"
|
|
||||||
"If using a composite action, add:\n"
|
|
||||||
" - name: Install Python dependencies\n"
|
|
||||||
" run: |\n"
|
|
||||||
" python3 -m pip install --upgrade pip\n"
|
|
||||||
" python3 -m pip install requests",
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# --- Read environment variables ---
|
def green(text): return color(text, "32")
|
||||||
|
def red(text): return color(text, "31")
|
||||||
|
def yellow(text): return color(text, "33")
|
||||||
|
def cyan(text): return color(text, "36")
|
||||||
|
def bold(text): return color(text, "1")
|
||||||
|
|
||||||
|
# --- Inputs ---
|
||||||
platform = os.environ.get("PLATFORM", "github").lower()
|
platform = os.environ.get("PLATFORM", "github").lower()
|
||||||
token = os.environ.get("TOKEN")
|
token = os.environ.get("TOKEN")
|
||||||
owner = os.environ.get("REPO_OWNER", os.environ.get("GITHUB_REPOSITORY_OWNER"))
|
owner = os.environ.get("REPO_OWNER", os.environ.get("GITHUB_REPOSITORY_OWNER"))
|
||||||
repo = os.environ.get("REPO_NAME", os.environ.get("GITHUB_REPOSITORY"))
|
repo = os.environ.get("REPO_NAME", os.environ.get("GITHUB_REPOSITORY"))
|
||||||
pr_index = os.environ.get("PR_INDEX")
|
pr_index = os.environ.get("PR_INDEX")
|
||||||
api_url = os.environ.get("API_URL", os.environ.get("GITHUB_API_URL"))
|
api_url = os.environ.get("API_URL", os.environ.get("GITHUB_API_URL"))
|
||||||
plan_file = os.environ.get("PLAN_FILE")
|
diff_text = os.environ.get("DIFF")
|
||||||
diff_text = os.environ.get("DIFF") # still supported for legacy usage
|
|
||||||
comment_template = os.environ.get("COMMENT_TEMPLATE", "Auto-comment: changed line -> {line}")
|
comment_template = os.environ.get("COMMENT_TEMPLATE", "Auto-comment: changed line -> {line}")
|
||||||
|
debug_mode = os.environ.get("DEBUG", "false").lower() == "true"
|
||||||
|
|
||||||
if not token or not pr_index:
|
if not token or not pr_index:
|
||||||
print("❌ TOKEN and PR_INDEX are required.", file=sys.stderr)
|
print(red("❌ TOKEN and PR_INDEX are required."))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# --- Load content from file or environment ---
|
# --- Build URLs and headers ---
|
||||||
content_text = None
|
def build_comment_url():
|
||||||
if plan_file and os.path.exists(plan_file):
|
if platform == "github":
|
||||||
try:
|
return f"https://api.github.com/repos/{owner}/{repo}/issues/{pr_index}/comments"
|
||||||
with open(plan_file, "r", encoding="utf-8") as f:
|
elif platform == "gitea":
|
||||||
content_text = f.read()
|
if not api_url:
|
||||||
except Exception as e:
|
print(red("❌ API_URL required for Gitea platform."))
|
||||||
print(f"⚠️ Failed to read file '{plan_file}': {e}", file=sys.stderr)
|
sys.exit(1)
|
||||||
sys.exit(1)
|
return f"{api_url}/repos/{owner}/{repo}/pulls/{pr_index}/reviews"
|
||||||
elif diff_text:
|
|
||||||
content_text = diff_text
|
|
||||||
|
|
||||||
# --- Prepare comment body ---
|
|
||||||
if not content_text:
|
|
||||||
body = comment_template.replace("{line}", "").replace("{lines}", "")
|
|
||||||
else:
|
|
||||||
body = comment_template.replace("{lines}", content_text).replace("{line}", "")
|
|
||||||
|
|
||||||
# --- Determine API endpoint ---
|
|
||||||
if platform == "github":
|
|
||||||
url = f"https://api.github.com/repos/{owner}/{repo}/issues/{pr_index}/comments"
|
|
||||||
elif platform == "gitea":
|
|
||||||
if not api_url:
|
|
||||||
print("❌ Gitea API URL required for Gitea platform", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
url = f"{api_url}/repos/{owner}/{repo}/pulls/{pr_index}/comments"
|
|
||||||
else:
|
|
||||||
print(f"❌ Unsupported platform: {platform}", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# --- Post the comment ---
|
|
||||||
headers = {"Authorization": f"token {token}", "Content-Type": "application/json"}
|
|
||||||
payload = {"body": body}
|
|
||||||
|
|
||||||
print(f"🛰️ Posting comment to {platform.upper()} PR #{pr_index}...")
|
|
||||||
|
|
||||||
try:
|
|
||||||
resp = requests.post(url, headers=headers, json=payload)
|
|
||||||
if resp.status_code in (200, 201):
|
|
||||||
print("✅ Comment posted successfully!")
|
|
||||||
sys.exit(0)
|
|
||||||
else:
|
else:
|
||||||
print(f"❌ Failed to post comment: {resp.status_code}", file=sys.stderr)
|
print(red(f"❌ Unsupported platform: {platform}"))
|
||||||
print(resp.text, file=sys.stderr)
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
except requests.exceptions.RequestException as e:
|
|
||||||
print(f"❌ Network or API error: {e}", file=sys.stderr)
|
def build_headers():
|
||||||
sys.exit(1)
|
return {
|
||||||
|
"Authorization": f"token {token}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- POST comment ---
|
||||||
|
def post_comment(body_text):
|
||||||
|
url = build_comment_url()
|
||||||
|
headers = build_headers()
|
||||||
|
payload = {"body": body_text}
|
||||||
|
|
||||||
|
if debug_mode:
|
||||||
|
preview = (body_text[:400] + "... [truncated]") if len(body_text) > 400 else body_text
|
||||||
|
print(bold(cyan("🧩 DEBUG MODE ENABLED")))
|
||||||
|
print(f" {yellow('Platform:')} {platform}")
|
||||||
|
print(f" {yellow('Repo:')} {owner}/{repo}")
|
||||||
|
print(f" {yellow('PR Index:')} {pr_index}")
|
||||||
|
print(f" {yellow('Endpoint:')} {url}")
|
||||||
|
print(f" {yellow('Comment size:')} {len(body_text)} characters")
|
||||||
|
print(f" {yellow('Payload preview:')} {json.dumps(payload)[:200]}{'... [truncated]' if len(json.dumps(payload))>200 else ''}")
|
||||||
|
print(f" {yellow('Comment preview:')}\n{preview}\n{'-'*60}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
resp = requests.post(url, headers=headers, json=payload, timeout=60)
|
||||||
|
if resp.status_code in (200, 201):
|
||||||
|
print(green(f"✅ Comment posted successfully to {platform.capitalize()}!"))
|
||||||
|
else:
|
||||||
|
print(red(f"❌ Failed to post comment ({resp.status_code}):"))
|
||||||
|
print(resp.text)
|
||||||
|
sys.exit(1)
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
print(red(f"❌ Request error: {e}"))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# --- No diff provided ---
|
||||||
|
if not diff_text:
|
||||||
|
body = comment_template.replace("{line}", "").replace("{lines}", "")
|
||||||
|
post_comment(body)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
# --- Parse unified diff ---
|
||||||
|
diff_files = {}
|
||||||
|
current_file = None
|
||||||
|
new_line_num = 0
|
||||||
|
|
||||||
|
for line in diff_text.splitlines():
|
||||||
|
if line.startswith("+++ b/"):
|
||||||
|
current_file = line[6:].strip()
|
||||||
|
diff_files[current_file] = []
|
||||||
|
new_line_num = 0
|
||||||
|
elif line.startswith("@@"):
|
||||||
|
m = re.match(r"@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@", line)
|
||||||
|
if m:
|
||||||
|
new_line_num = int(m.group(1)) - 1
|
||||||
|
elif line.startswith("+") and not line.startswith("+++"):
|
||||||
|
new_line_num += 1
|
||||||
|
content = line[1:]
|
||||||
|
diff_files[current_file].append((new_line_num, content))
|
||||||
|
elif not line.startswith("-"):
|
||||||
|
new_line_num += 1
|
||||||
|
|
||||||
|
# --- Post combined comment per file ---
|
||||||
|
for file_path, lines in diff_files.items():
|
||||||
|
if not lines:
|
||||||
|
continue
|
||||||
|
all_lines_content = "\n".join([line_content for _, line_content in lines])
|
||||||
|
body = comment_template.replace("{lines}", all_lines_content)
|
||||||
|
post_comment(body)
|
||||||
|
|
||||||
|
print(green("🎉 All comments posted successfully."))
|
||||||
|
|||||||
Reference in New Issue
Block a user