+97
-65
@@ -3,83 +3,115 @@ import os
|
||||
import sys
|
||||
import re
|
||||
import json
|
||||
import requests
|
||||
|
||||
# --- Check for required dependency ---
|
||||
try:
|
||||
import requests
|
||||
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)
|
||||
# --- ANSI color helpers ---
|
||||
def color(text, code):
|
||||
return f"\033[{code}m{text}\033[0m"
|
||||
|
||||
# --- 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()
|
||||
token = os.environ.get("TOKEN")
|
||||
owner = os.environ.get("REPO_OWNER", os.environ.get("GITHUB_REPOSITORY_OWNER"))
|
||||
repo = os.environ.get("REPO_NAME", os.environ.get("GITHUB_REPOSITORY"))
|
||||
pr_index = os.environ.get("PR_INDEX")
|
||||
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") # still supported for legacy usage
|
||||
diff_text = os.environ.get("DIFF")
|
||||
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:
|
||||
print("❌ TOKEN and PR_INDEX are required.", file=sys.stderr)
|
||||
print(red("❌ TOKEN and PR_INDEX are required."))
|
||||
sys.exit(1)
|
||||
|
||||
# --- Load content from file or environment ---
|
||||
content_text = None
|
||||
if plan_file and os.path.exists(plan_file):
|
||||
try:
|
||||
with open(plan_file, "r", encoding="utf-8") as f:
|
||||
content_text = f.read()
|
||||
except Exception as e:
|
||||
print(f"⚠️ Failed to read file '{plan_file}': {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
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)
|
||||
# --- Build URLs and headers ---
|
||||
def build_comment_url():
|
||||
if platform == "github":
|
||||
return f"https://api.github.com/repos/{owner}/{repo}/issues/{pr_index}/comments"
|
||||
elif platform == "gitea":
|
||||
if not api_url:
|
||||
print(red("❌ API_URL required for Gitea platform."))
|
||||
sys.exit(1)
|
||||
return f"{api_url}/repos/{owner}/{repo}/pulls/{pr_index}/reviews"
|
||||
else:
|
||||
print(f"❌ Failed to post comment: {resp.status_code}", file=sys.stderr)
|
||||
print(resp.text, file=sys.stderr)
|
||||
print(red(f"❌ Unsupported platform: {platform}"))
|
||||
sys.exit(1)
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ Network or API error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
def build_headers():
|
||||
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