From 8a86508ebbe00332e81a3c9460f4b8fecd1df1e8 Mon Sep 17 00:00:00 2001 From: "Trez.One" Date: Tue, 21 Oct 2025 19:13:52 -0400 Subject: [PATCH] Large file handling. --- README.md | 194 ++++++++++++++++++++++++++++++-------------- action.yml | 97 ++++++++++------------ git-auto-comment.py | 10 +-- 3 files changed, 183 insertions(+), 118 deletions(-) diff --git a/README.md b/README.md index ba6f4e6..d06623d 100644 --- a/README.md +++ b/README.md @@ -1,103 +1,179 @@ -# PR Commenter Diff-Aware Action +# 🧩 PR Commenter for GitHub & Gitea -A GitHub/Gitea Action to automatically post comments to pull requests based on a `git diff`. Supports: +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. -- Inline comments per changed line -- Multiline comment templates -- Cross-platform support (GitHub and Gitea) -- Diff-aware commenting, automatically detecting added lines -- Default values for repository info -- Optional `diff` input β€” can post general PR comments without a diff -- Remote URL usage for Gitea Actions +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 -- **GitHub & Gitea support**: Works seamlessly on both platforms. -- **Diff-aware**: Parses a `git diff` to determine which lines were added. -- **Inline comments**: Comments appear directly on changed lines in PRs. -- **Multiline templates**: Supports `{line}` for a single line and `{lines}` for all added lines in a file. -- **Optional diff**: If no diff is provided, posts a general PR comment. -- **Default repository values**: `repo_name`, `repo_owner`, and `api_url` default to GitHub environment variables if not provided. -- **Remote URL usage**: Can reference the action directly from a Git repository URL for Gitea. +- βœ… Works with **GitHub** and **Gitea** PR APIs +- βœ… Handles **large text outputs** (plans, diffs, logs, etc.) +- βœ… Allows **multiline comment templates** with placeholders +- βœ… Defaults to environment variables from the Action runner (no hardcoded repo info required) +- βœ… Can run on **both GitHub Actions** and **Gitea Actions** --- -## Inputs +## βš™οΈ Inputs -| Input | Description | Required | Default | -|-------|-------------|----------|---------| -| `platform` | Target platform: `github` or `gitea` | yes | `github` | -| `token` | API token for authentication | yes | - | -| `api_url` | Gitea API URL (only required for Gitea, e.g., `https://gitea.example.com/api/v1`) | no | `${{ github.api_url }}` | -| `repo_owner` | Repository owner (user/org) | no | `${{ github.repository_owner }}` | -| `repo_name` | Repository name | no | `${{ github.repository }}` | -| `pr_index` | PR number (GitHub) or index (Gitea) | yes | - | -| `diff` | Git diff to parse (optional). If empty, posts only a general PR comment. | no | - | -| `comment_template` | Multiline template for comment body. Use placeholders `{line}` and `{lines}` | no | `Auto-comment: changed line -> {line}` | +| Name | Required | Default | Description | +|------|-----------|----------|-------------| +| `platform` | ❌ | `github` | Platform type (`github` or `gitea`) | +| `token` | βœ… | β€” | Access token for API requests (`GITHUB_TOKEN` or personal token) | +| `pr_index` | βœ… | β€” | Pull request number or index | +| `repo_owner` | ❌ | `${{ github.repository_owner }}` | Repository owner | +| `repo_name` | ❌ | `${{ github.repository }}` | Repository name | +| `api_url` | ❌ | `${{ github.api_url }}` | API URL for Gitea (required only for Gitea) | +| `content` | ❌ | β€” | Large text input β€” diff, plan, or log content | +| `comment_template` | ❌ | See below | Comment body template supporting `{line}` and `{lines}` placeholders | + +### 🧠 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 | --- -## Example Usage - -### GitHub PR +## 🧩 Default `comment_template` ```yaml +comment_template: | + Auto-comment: + --- + {line} +``` + +## πŸ’‘ Example: GitHub Action Workflow +```yaml +name: Comment Terraform Plan on PR +on: + pull_request: + branches: + - main + jobs: - comment-pr-diff: + plan-comment: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - name: Generate git diff - id: gitdiff + - name: Run Terraform Plan + id: plan run: | - git fetch origin main - git diff origin/main > diff.txt + terraform plan -no-color > plan.txt + echo "plan_text<> $GITHUB_OUTPUT + cat plan.txt >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT - - name: Post diff-aware comments to GitHub PR + - 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 }} - diff: ${{ steps.gitdiff.outputs.diff }} + content: ${{ steps.plan.outputs.plan_text }} comment_template: | - Auto-comment on file: - --- - Changed line: {line} - Full added lines in this file: + πŸš€ **Terraform Plan Summary** + ``` {lines} + ``` ``` -### Gitea PR - +## πŸ’‘ Example: Gitea Action Workflow ```yaml +name: Comment Plan on PR (Gitea) +on: + pull_request: + branches: + - main + jobs: - comment-pr-diff: + plan-comment: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Checkout + uses: actions/checkout@v4 - - name: Generate git diff - id: gitdiff + - name: Run Tofu Plan + id: tofu run: | - git fetch origin main - git diff origin/main > diff.txt + tofu plan -no-color > tofu-plan.txt + echo "plan_text<> $GITEA_OUTPUT + cat tofu-plan.txt >> $GITEA_OUTPUT + echo "EOF" >> $GITEA_OUTPUT - - name: Post diff-aware comments to Gitea PR + - name: Post Plan to Gitea PR uses: "https://gitea.example.com/your-org/pr-commenter-action@main" with: platform: gitea token: ${{ secrets.GITEA_TOKEN }} api_url: "https://gitea.example.com/api/v1" - pr_index: 42 - diff: ${{ steps.gitdiff.outputs.diff }} + pr_index: ${{ gitea.event.pull_request.number }} + content: ${{ steps.tofu.outputs.plan_text }} comment_template: | - Auto-comment on file: - --- - Changed line: {line} - Full added lines in this file: + 🧠 **OpenTofu Plan Diff** + ``` {lines} -``` \ No newline at end of file + ``` +``` + +## πŸͺ΅ Example: Posting Large Log Output +```yaml +- name: Upload build logs to PR + uses: "https://gitea.example.com/your-org/pr-commenter-action@main" + 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 + +You can test the script locally by exporting the necessary environment variables and running: + +``` +export PLATFORM=gitea +export TOKEN= +export REPO_OWNER=your-org +export REPO_NAME=your-repo +export PR_INDEX=42 +export API_URL=https://gitea.example.com/api/v1 +export CONTENT="$(cat plan.txt)" +python3 comment_pr.py +``` + +## ⚠️ Limitations & Tips for Large Files + +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. \ No newline at end of file diff --git a/action.yml b/action.yml index ba10584..0c050fa 100644 --- a/action.yml +++ b/action.yml @@ -1,64 +1,53 @@ -name: "PR Commenter Diff-Aware" -description: "Post comments to changed lines in a PR based on a git diff, for GitHub or Gitea. Supports multiline templates." -author: "Trez.One" - -branding: - icon: "paperclip" - color: "blue" +name: "PR Commenter for GitHub and Gitea" +description: "Posts PR comments from large outputs like diffs, logs, or Terraform plans." +author: "Your Name" +inputs: + platform: + description: "Platform type: github or gitea" + required: false + default: "github" + token: + description: "Access token for the API" + required: true + pr_index: + description: "Pull request number or index" + required: true + repo_owner: + description: "Repository owner (default: GITHUB_REPOSITORY_OWNER)" + required: false + repo_name: + description: "Repository name (default: GITHUB_REPOSITORY)" + required: false + api_url: + description: "API URL for Gitea (default: GITHUB_API_URL)" + required: false + content: + description: "Large text content (diff, log, plan, etc.)" + required: false + comment_template: + description: "Template for the comment body (supports multiline and placeholders {line}, {lines})" + required: false + default: | + Auto-comment: + --- + {line} runs: using: "composite" steps: - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: "3.11" - - - name: Install dependencies - shell: bash + - name: Install Python dependencies run: pip install requests + shell: bash - - name: Run PR commenter - run: python comment_pr_diff.py - shell: python + - name: Run PR Commenter + run: python3 ${{ github.action_path }}/comment_pr.py + shell: bash env: PLATFORM: ${{ inputs.platform }} TOKEN: ${{ inputs.token }} - API_URL: ${{ inputs.api_url || github.api_url }} - REPO_OWNER: ${{ inputs.repo_owner || github.repository_owner }} - REPO_NAME: ${{ inputs.repo_name || github.repository }} PR_INDEX: ${{ inputs.pr_index }} - DIFF: ${{ inputs.diff }} - COMMENT_TEMPLATE: ${{ inputs.comment_template }} - -inputs: - platform: - description: "Target platform: github or gitea" - required: true - default: "github" - token: - description: "API token for authentication" - required: true - api_url: - description: "Gitea API URL (only required for Gitea, e.g., https://gitea.example.com/api/v1)" - required: false - repo_owner: - description: "Repository owner (user/org)" - required: false - repo_name: - description: "Repository name" - required: false - pr_index: - description: "PR number (GitHub) or index (Gitea)" - required: true - diff: - description: "Git diff to parse (optional). If empty, posts only a general PR comment." - required: false - comment_template: - description: | - Multiline template for comment body. - Use placeholders: - - {line} β†’ replaced by single changed line - - {lines} β†’ replaced by all added lines in the file - required: false - default: "Auto-comment: changed line -> {line}" \ No newline at end of file + REPO_OWNER: ${{ inputs.repo_owner }} + REPO_NAME: ${{ inputs.repo_name }} + API_URL: ${{ inputs.api_url }} + CONTENT: ${{ inputs.content }} + COMMENT_TEMPLATE: ${{ inputs.comment_template }} \ No newline at end of file diff --git a/git-auto-comment.py b/git-auto-comment.py index 92551ee..f2eb5ad 100755 --- a/git-auto-comment.py +++ b/git-auto-comment.py @@ -11,15 +11,15 @@ 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["PR_INDEX"] api_url = os.environ.get("API_URL", os.environ.get("GITHUB_API_URL")) -diff_text = os.environ.get("DIFF") # optional +content_text = os.environ.get("CONTENT") # optional large text input comment_template = os.environ.get("COMMENT_TEMPLATE", "Auto-comment: changed line -> {line}") if not token or not pr_index: print("TOKEN and PR_INDEX are required.", file=sys.stderr) sys.exit(1) -# If diff_text is empty, just post a general PR comment -if not diff_text: +# If no content provided, just post a general PR comment +if not content_text: body = comment_template.replace("{line}", "").replace("{lines}", "") if platform == "github": url = f"https://api.github.com/repos/{owner}/{repo}/issues/{pr_index}/comments" @@ -44,12 +44,12 @@ if not diff_text: print(resp.text, file=sys.stderr) sys.exit(1) -# --- If diff_text exists, parse diff normally --- +# --- If content_text exists, parse it for added lines like a diff --- diff_files = {} current_file = None new_line_num = None -for line in diff_text.splitlines(): +for line in content_text.splitlines(): if line.startswith("+++ b/"): current_file = line[6:].strip() diff_files[current_file] = []