{"id":13493935,"url":"https://github.com/mshick/add-pr-comment","last_synced_at":"2026-04-03T00:35:26.802Z","repository":{"id":36329316,"uuid":"223494945","full_name":"mshick/add-pr-comment","owner":"mshick","description":"uses: mshick/add-pr-comment@v2","archived":false,"fork":false,"pushed_at":"2024-06-16T10:13:01.000Z","size":3978,"stargazers_count":247,"open_issues_count":25,"forks_count":61,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-03-01T04:51:51.178Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mshick.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-11-22T22:11:44.000Z","updated_at":"2026-02-24T09:43:11.000Z","dependencies_parsed_at":"2024-07-31T22:08:34.346Z","dependency_job_id":null,"html_url":"https://github.com/mshick/add-pr-comment","commit_stats":{"total_commits":171,"total_committers":11,"mean_commits":"15.545454545454545","dds":"0.11695906432748537","last_synced_commit":"dd126dd8c253650d181ad9538d8b4fa218fc31e8"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/mshick/add-pr-comment","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mshick%2Fadd-pr-comment","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mshick%2Fadd-pr-comment/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mshick%2Fadd-pr-comment/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mshick%2Fadd-pr-comment/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mshick","download_url":"https://codeload.github.com/mshick/add-pr-comment/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mshick%2Fadd-pr-comment/sbom","scorecard":{"id":665655,"data":{"date":"2025-08-11","repo":{"name":"github.com/mshick/add-pr-comment","commit":"dd126dd8c253650d181ad9538d8b4fa218fc31e8"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Code-Review","score":0,"reason":"Found 1/26 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":3,"reason":"dependency not pinned by hash detected -- score normalized to 3","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/mshick/add-pr-comment/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/mshick/add-pr-comment/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:47: update your workflow using https://app.stepsecurity.io/secureworkflow/mshick/add-pr-comment/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:50: update your workflow using https://app.stepsecurity.io/secureworkflow/mshick/add-pr-comment/ci.yml/main?enable=pin","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   2 out of   2 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 8 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"28 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-h5c3-5r3r-rr8q","Warn: Project is vulnerable to: GHSA-rmvr-2pp2-xj38","Warn: Project is vulnerable to: GHSA-xx4v-prfh-6cgc","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-pxg6-pf52-xh8x","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-67mh-4wv8-2f99","Warn: Project is vulnerable to: GHSA-4q6p-r6v2-jvc5","Warn: Project is vulnerable to: GHSA-pfrx-2q88-qq97","Warn: Project is vulnerable to: GHSA-9pv7-vfvm-6vr7","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-mwcw-c2x4-8c55","Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j","Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-c24v-8rfc-w8vw","Warn: Project is vulnerable to: GHSA-8jhw-289h-jh2g","Warn: Project is vulnerable to: GHSA-64vr-g452-qvp3","Warn: Project is vulnerable to: GHSA-9cwx-2883-4wfx","Warn: Project is vulnerable to: GHSA-vg6x-rcgg-rjx6","Warn: Project is vulnerable to: GHSA-x574-m823-4x7w","Warn: Project is vulnerable to: GHSA-4r4m-qw57-chr8","Warn: Project is vulnerable to: GHSA-xcj6-pq6g-qj4x","Warn: Project is vulnerable to: GHSA-356w-63v5-8wf4","Warn: Project is vulnerable to: GHSA-859w-5945-r5v3"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-21T17:56:43.455Z","repository_id":36329316,"created_at":"2025-08-21T17:56:43.455Z","updated_at":"2025-08-21T17:56:43.455Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30035482,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-03T06:58:30.252Z","status":"ssl_error","status_checked_at":"2026-03-03T06:58:15.329Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T19:01:20.136Z","updated_at":"2026-04-03T00:35:26.795Z","avatar_url":"https://github.com/mshick.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# add-pr-comment\n\n\u003c!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --\u003e\n[![All Contributors](https://img.shields.io/badge/all_contributors-8-orange.svg?style=flat-square)](#contributors-)\n\u003c!-- ALL-CONTRIBUTORS-BADGE:END --\u003e\n\n[![CI](https://github.com/mshick/add-pr-comment/actions/workflows/ci.yml/badge.svg)](https://github.com/mshick/add-pr-comment/actions/workflows/ci.yml)\n[![Check dist/](https://github.com/mshick/add-pr-comment/actions/workflows/check-dist.yml/badge.svg)](https://github.com/mshick/add-pr-comment/actions/workflows/check-dist.yml)\n[![CodeQL](https://github.com/mshick/add-pr-comment/actions/workflows/codeql.yml/badge.svg)](https://github.com/mshick/add-pr-comment/actions/workflows/codeql.yml)\n[![Coverage](./badges/coverage.svg)](./badges/coverage.svg)\n\nA GitHub Action which adds a comment to a pull request issue or commit.\n\nThis action also works on [issue](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#issues),\n[issue_comment](https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#issue_comment),\n[deployment_status](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#deployment_status),\n[push](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#push)\nand any other event where an issue can be found directly on the payload or via a commit sha.\n\n## Features\n\n- Modify issues for PRs merged to main.\n- By default will post \"sticky\" comments. If on a subsequent run the message text changes the original comment will be updated.\n- Multiple sticky comments allowed by setting unique `message-id`s.\n- Optional message overrides based on job status.\n- Multiple posts to the same conversation optionally allowable.\n- Supports a proxy for fork-based PRs. [See below](#proxy-for-fork-based-prs).\n- Supports creating a message from a file path.\n- Supports [file attachments](#file-attachments) via GitHub Artifacts.\n- Automatic [message truncation](#message-truncation) for oversized messages (e.g., large Terraform plans).\n- Supports [commit comments](#commit-comments) in addition to PR/issue comments.\n- Available as a [library](#programmatic-usage) for use in custom actions and scripts.\n\n## Usage\n\nNote that write access needs to be granted for the pull-requests scope.\n\n```yaml\non:\n  pull_request:\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n      - uses: mshick/add-pr-comment@v3\n        with:\n          message: |\n            **Hello**\n            🌏\n            !\n```\n\nYou can even use it on PR Issues that are related to PRs that were merged into main, for example:\n\n```yaml\non:\n  push:\n    branches:\n      - main\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n      - uses: mshick/add-pr-comment@v3\n        with:\n          message: |\n            **Hello MAIN**\n```\n\n## Configuration options\n\n| Input                    | Location | Description                                                                                                                                                                 | Required | Default                            |\n| ------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ---------------------------------- |\n| message                  | with     | The message you'd like displayed, supports Markdown and all valid Unicode characters.                                                                                       | maybe    |                                    |\n| message-path             | with     | Path to a message you'd like displayed. Will be read and displayed just like a normal message. Supports multi-line input and globs. Multiple messages will be concatenated. | maybe    |                                    |\n| message-success          | with     | A message override, printed in case of success.                                                                                                                             | no       |                                    |\n| message-failure          | with     | A message override, printed in case of failure.                                                                                                                             | no       |                                    |\n| message-cancelled        | with     | A message override, printed in case of cancelled.                                                                                                                           | no       |                                    |\n| message-skipped          | with     | A message override, printed in case of skipped.                                                                                                                             | no       |                                    |\n| status                   | with     | Required if you want to use message status overrides.                                                                                                                       | no       | {{ job.status }}                   |\n| repo-owner               | with     | Owner of the repo.                                                                                                                                                          | no       | {{ github.repository_owner }}      |\n| repo-name                | with     | Name of the repo.                                                                                                                                                           | no       | {{ github.event.repository.name }} |\n| repo-token               | with     | Valid GitHub token, either the temporary token GitHub provides or a personal access token.                                                                                  | no       | {{ github.token }}                 |\n| message-id               | with     | Message id to use when searching existing comments. If found, updates the existing (sticky comment).                                                                        | no       |                                    |\n| delete-on-status         | with     | If specified and a comment exists and the status is matching the value of this option, the comment will be deleted                                                          | no       |                                    |\n| refresh-message-position | with     | Should the sticky message be the last one in the PR's feed.                                                                                                                 | no       | false                              |\n| allow-repeats            | with     | Boolean flag to allow identical messages to be posted each time this action is run.                                                                                         | no       | false                              |\n| proxy-url                | with     | String for your proxy service URL if you'd like this to work with fork-based PRs.                                                                                           | no       |                                    |\n| issue                    | with     | Optional issue number override.                                                                                                                                             | no       |                                    |\n| update-only              | with     | Only update the comment if it already exists.                                                                                                                               | no       | false                              |\n| GITHUB_TOKEN             | env      | Valid GitHub token, can alternatively be defined in the env.                                                                                                                | no       |                                    |\n| preformatted             | with     | Treat message text as pre-formatted and place it in a codeblock                                                                                                             | no       |                                    |\n| find                     | with     | Patterns to find in an existing message and replace with either `replace` text or a resolved `message`. See [Find-and-Replace](#find-and-replace) for more detail.          | no       |                                    |\n| replace                  | with     | Strings to replace a found pattern with. Each new line is a new replacement, or if you only have one pattern, you can replace with a multiline string.                      | no       |                                    |\n| attach-path              | with     | A file path or glob pattern for files to upload as artifacts and link in the comment. See [File Attachments](#file-attachments).                                            | no       |                                    |\n| attach-name              | with     | Name for the uploaded artifact.                                                                                                                                             | no       | pr-comment-attachments             |\n| attach-text              | with     | Markdown content for the attachment section. Always separated from the comment by a horizontal rule. Supports `%ARTIFACT_URL%` and `%ATTACH_NAME%` template variables.      | no       | (see [File Attachments](#file-attachments)) |\n| truncate                 | with     | Truncation mode when the message exceeds the safe comment length. See [Message Truncation](#message-truncation).                                                            | no       | artifact                           |\n| comment-target           | with     | Where to post the comment. Use `pr` for pull request/issue comments or `commit` for commit comments. See [Commit Comments](#commit-comments).                              | no       | pr                                 |\n| commit-sha               | with     | The commit SHA to comment on when `comment-target` is `commit`. Defaults to the current commit.                                                                             | no       | {{ github.sha }}                   |\n\n## Outputs\n\n| Output            | Description                                                       |\n| ----------------- | ----------------------------------------------------------------- |\n| `comment-created` | `\"true\"` if a new comment was created, `\"false\"` otherwise.       |\n| `comment-updated` | `\"true\"` if an existing comment was updated, `\"false\"` otherwise. |\n| `comment-id`      | The numeric ID of the created or updated comment.                 |\n| `artifact-url`    | If files were attached, the URL to download the artifact.         |\n| `truncated`       | `\"true\"` if the message was truncated, `\"false\"` otherwise.      |\n| `truncated-artifact-url` | If truncated in artifact mode, the URL to download the full message. |\n\n### Using outputs in subsequent steps\n\n```yaml\n- uses: mshick/add-pr-comment@v3\n  id: comment\n  with:\n    message: 'Hello world'\n\n- name: Check outputs\n  run: |\n    echo \"Comment created: ${{ steps.comment.outputs.comment-created }}\"\n    echo \"Comment updated: ${{ steps.comment.outputs.comment-updated }}\"\n    echo \"Comment ID: ${{ steps.comment.outputs.comment-id }}\"\n```\n\n\u003e **Tip:** By default, comments are \"upsert\" — a comment is created on the first run and updated on subsequent runs when matched by `message-id`. If you want this create-or-update behavior, you do not need to set `update-only`. Setting `update-only: true` skips comment creation entirely and only updates an existing comment. Use it when you specifically want no comment to appear unless one was already posted by a previous step or run.\n\n## Advanced Uses\n\n### Proxy for Fork-based PRs\n\nGitHub limits `GITHUB_TOKEN` and other API access token permissions when creating a PR from a fork. This precludes adding comments when your PRs are coming from forks, which is the norm for open source projects. To work around this situation I've created a simple companion app you can deploy to Cloud Run or another host to proxy the create comment requests with a personal access token you provide.\n\nSee this issue: https://github.community/t/github-actions-are-severely-limited-on-prs/18179/4 for more details.\n\nCheck out the proxy service here: https://github.com/mshick/add-pr-comment-proxy\n\n**Example**\n\n```yaml\non:\n  pull_request:\n\njobs:\n  pr:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n      - uses: mshick/add-pr-comment@v3\n        with:\n          message: |\n            **Howdie!**\n          proxy-url: https://add-pr-comment-proxy-94idvmwyie-uc.a.run.app\n```\n\n### Status Message Overrides\n\nYou can override your messages based on your job status. This can be helpful\nif you don't anticipate having the data required to create a helpful message in\ncase of failure, but you still want a message to be sent to the PR comment.\n\n**Example**\n\n```yaml\non:\n  pull_request:\n\njobs:\n  pr:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n      - uses: mshick/add-pr-comment@v3\n        if: always()\n        with:\n          message: |\n            **Howdie!**\n          message-failure: |\n            Uh oh!\n```\n\n### Multiple Message Files\n\nInstead of directly setting the message you can also load a file with the text\nof your message using `message-path`. `message-path` supports loading multiple\nfiles and files on multiple lines, the contents of which will be concatenated.\n\n**Example**\n\n```yaml\non:\n  pull_request:\n\njobs:\n  pr:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n      - uses: mshick/add-pr-comment@v3\n        if: always()\n        with:\n          message-path: |\n            message-part-*.txt\n```\n\n### Find-and-Replace\n\nPatterns can be matched and replaced to update comments. This could be useful\nfor some situations, for instance, updating a checklist comment.\n\nFind is a regular expression passed to the [RegExp() constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/RegExp). You can also\ninclude modifiers to override the default `gi`.\n\n**Example**\n\nOriginal message:\n\n```\n[ ] Hello\n[ ] World\n```\n\nAction:\n\n```yaml\non:\n  pull_request:\n\njobs:\n  pr:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n      - uses: mshick/add-pr-comment@v3\n        if: always()\n        with:\n          find: |\n            \\n\\\\[ \\\\]\n          replace: |\n            [X]\n```\n\nFinal message:\n\n```\n[X] Hello\n[X] World\n```\n\nMultiple find and replaces can be used:\n\n**Example**\n\nOriginal message:\n\n```\nhello world!\n```\n\nAction:\n\n```yaml\non:\n  pull_request:\n\njobs:\n  pr:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n      - uses: mshick/add-pr-comment@v3\n        if: always()\n        with:\n          find: |\n            hello\n            world\n          replace: |\n            goodnight\n            moon\n```\n\nFinal message:\n\n```\ngoodnight moon!\n```\n\nIt defaults to your resolved message (either from `message` or `message-path`) to\ndo a replacement:\n\n**Example**\n\nOriginal message:\n\n```\nhello\n\n\u003c\u003c FILE_CONTENTS \u003e\u003e\n\nworld\n```\n\nAction:\n\n```yaml\non:\n  pull_request:\n\njobs:\n  pr:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n      - uses: mshick/add-pr-comment@v3\n        if: always()\n        with:\n          message-path: |\n            message.txt\n          find: |\n            \u003c\u003c FILE_CONTENTS \u003e\u003e\n```\n\nFinal message:\n\n```\nhello\n\nsecret message from message.txt\n\nworld\n```\n\n### File Attachments\n\nYou can attach files to your PR comments by uploading them as GitHub Artifacts and embedding download links in the comment body. Files matching the `attach-path` glob are uploaded as a single artifact, and a markdown section with the download link is appended to your comment, separated by a horizontal rule.\n\n\u003e **Note:** Artifact download URLs require GitHub authentication and expire based on your repository's retention settings (default 90 days). Images will not render inline — they appear as download links. This is a GitHub platform limitation.\n\n**Simple — attach a file with defaults**\n\n```yaml\non:\n  pull_request:\n\njobs:\n  report:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n      - uses: actions/checkout@v4\n      - run: echo \"Build output here\" \u003e report.txt\n      - uses: mshick/add-pr-comment@v3\n        with:\n          message: |\n            Build complete! See attached report.\n          attach-path: report.txt\n```\n\n**Advanced — glob pattern, custom name, and custom text template**\n\n```yaml\non:\n  pull_request:\n\njobs:\n  report:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n      - uses: actions/checkout@v4\n      - run: |\n          mkdir -p coverage\n          echo \"line coverage: 85%\" \u003e coverage/summary.txt\n          echo \"\u003chtml\u003e...\u003c/html\u003e\" \u003e coverage/report.html\n      - uses: mshick/add-pr-comment@v3\n        with:\n          message: |\n            ## Coverage Report\n            Tests passed with 85% line coverage.\n          attach-path: coverage/*\n          attach-name: coverage-report\n          attach-text: '📎 [Download %ATTACH_NAME%](%ARTIFACT_URL%)'\n```\n\nThe `attach-text` input supports two template variables:\n\n| Variable         | Replaced with                      |\n| ---------------- | ---------------------------------- |\n| `%ARTIFACT_URL%` | The artifact download URL          |\n| `%ATTACH_NAME%`  | The value of the `attach-name` input |\n\n### Message Truncation\n\nGitHub's API limits comment bodies to 65,536 characters. Messages that exceed this limit (common with large Terraform plans, verbose test output, etc.) would previously cause the action to fail with an \"Argument list too long\" or API error.\n\nThis action automatically truncates oversized messages to stay within a safe limit (61,440 characters, which includes a 4,096 character buffer). The `truncate` input controls what happens with the full message:\n\n| Mode | Behavior |\n| ---- | -------- |\n| `artifact` (default) | The full, untruncated message is uploaded as a downloadable GitHub Artifact. The comment is truncated and a download link is appended. |\n| `simple` | The comment is truncated and a notice is appended. No artifact is uploaded. |\n\nIf artifact upload fails (e.g., permissions, network issues), the action automatically falls back to simple truncation.\n\n**Example — default artifact mode**\n\n```yaml\non:\n  pull_request:\n\njobs:\n  plan:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n      - uses: actions/checkout@v4\n      - run: terraform plan -no-color \u003e plan.txt\n      - uses: mshick/add-pr-comment@v3\n        with:\n          message-path: plan.txt\n```\n\nIf the plan output exceeds the safe limit, the comment will be truncated and end with:\n\n\u003e **This message was truncated.** [Download full message](https://github.com/...)\n\n**Example — simple mode (no artifact)**\n\n```yaml\n- uses: mshick/add-pr-comment@v3\n  with:\n    message-path: plan.txt\n    truncate: simple\n```\n\nThe comment will be truncated and end with:\n\n\u003e **This message was truncated.**\n\n**Using the truncation outputs**\n\n```yaml\n- uses: mshick/add-pr-comment@v3\n  id: comment\n  with:\n    message-path: plan.txt\n\n- name: Check if truncated\n  if: steps.comment.outputs.truncated == 'true'\n  run: |\n    echo \"Message was truncated\"\n    echo \"Full message: ${{ steps.comment.outputs.truncated-artifact-url }}\"\n```\n\n\u003e **Tip:** For very large outputs like Terraform plans, prefer using `message-path` over the `message` input. The `message` input is passed via environment variables, which have OS-level size limits that can cause failures before the action even runs. File-based input via `message-path` avoids this entirely.\n\n### Commit Comments\n\nInstead of posting to a pull request or issue, you can post comments directly on a commit. This is useful for workflows triggered by `push` events or when you want feedback attached to a specific commit rather than a PR conversation.\n\n**Example**\n\n```yaml\non:\n  push:\n    branches:\n      - main\n\njobs:\n  notify:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: mshick/add-pr-comment@v3\n        with:\n          comment-target: commit\n          message: |\n            Build succeeded for ${{ github.sha }}\n```\n\nYou can also specify a different commit SHA:\n\n```yaml\n- uses: mshick/add-pr-comment@v3\n  with:\n    comment-target: commit\n    commit-sha: ${{ github.event.before }}\n    message: |\n      Comparing changes since this commit.\n```\n\n\u003e **Note:** Commit comments use a different GitHub API than issue/PR comments. Sticky comments (`message-id`), `update-only`, `refresh-message-position`, and `delete-on-status` all work with commit comments. The `proxy-url` option is not supported for commit comments.\n\n### Bring your own issues\n\nYou can set an issue id explicitly. Helpful for cases where you want to post\nto an issue but for some reason the event would not allow the id to be determined.\n\n**Example**\n\n\u003e In this case `add-pr-comment` should have no problem finding the issue number\n\u003e on its own, but for demonstration purposes.\n\n```yaml\non:\n  deployment_status:\n\njobs:\n  pr:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n      - id: pr\n        run: |\n          issue=$(gh pr list --search \"${{ github.sha }}\" --state open --json number --jq \".[0].number\")\n          echo \"issue=$issue\" \u003e\u003e$GITHUB_OUTPUT\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n      - uses: mshick/add-pr-comment@v3\n        with:\n          issue: ${{ steps.pr.outputs.issue }}\n          message: |\n            **Howdie!**\n```\n\n### Delete on status\n\nThis option can be used if comment needs to be removed if a status is reached.\n\n**Example**\n\n\u003e Here, a comment will be added on failure, but on a subsequent run,\n\u003e if the job reaches success status, the comment will be deleted.\n\n```yaml\non:\n  pull_request:\n\njobs:\n  pr:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n      - uses: mshick/add-pr-comment@v3\n        if: always()\n        with:\n          message-failure: There was a failure\n          delete-on-status: success\n```\n\n## Programmatic Usage\n\nThis package also exports its core functions as a library, so you can use them in your own custom GitHub Actions or scripts.\n\n```bash\nnpm install @mshick/add-pr-comment\n```\n\n```typescript\nimport {\n  createComment,\n  getExistingComment,\n  updateComment,\n  deleteComment,\n  createCommitComment,\n  getMessage,\n  truncateMessage,\n  uploadAttachments,\n} from '@mshick/add-pr-comment'\n```\n\nThe library exports functions for managing both issue/PR comments and commit comments, file discovery, message resolution, truncation, attachments, and proxy support. Type definitions are included.\n\n## Security\n\n### Version Pinning\n\nThere are three ways to reference this action, from most to least secure:\n\n1. **Commit SHA (most secure)**: `uses: mshick/add-pr-comment@ffd016c7e151d97d69d21a843022fd4cd5b96fe5` — immutable, can never change.\n2. **Semver tag (recommended)**: `uses: mshick/add-pr-comment@v3.9.0` — protected by tag rulesets, cannot be moved or deleted once created.\n3. **Major version tag (convenient but less secure)**: `uses: mshick/add-pr-comment@v3` — floating tag that is updated on each release to point to the latest version. While convenient, floating tags are a potential security risk as they could theoretically be re-pointed to a different commit.\n\nFor maximum security, pin to a full semver tag or commit SHA. Semver tags (e.g., `v3.9.0`) in this repository are protected by GitHub tag rulesets and cannot be modified after creation.\n\nReleases include build provenance attestations generated by [`actions/attest-build-provenance`](https://github.com/actions/attest-build-provenance), which can be used to verify that the release was produced by the official CI pipeline.\n\n## Contributors ✨\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://app.lizardbyte.dev\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/42013603?v=4?s=100\" width=\"100px;\" alt=\"ReenigneArcher\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eReenigneArcher\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/mshick/add-pr-comment/commits?author=ReenigneArcher\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/aryella-lacerda\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/28730324?v=4?s=100\" width=\"100px;\" alt=\"Aryella Lacerda\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAryella Lacerda\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/mshick/add-pr-comment/commits?author=aryella-lacerda\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/vincent-joignie-dd\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/103102299?v=4?s=100\" width=\"100px;\" alt=\"vincent-joignie-dd\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003evincent-joignie-dd\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/mshick/add-pr-comment/commits?author=vincent-joignie-dd\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://ahanoff.dev\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/2371703?v=4?s=100\" width=\"100px;\" alt=\"Akhan Zhakiyanov\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAkhan Zhakiyanov\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/mshick/add-pr-comment/commits?author=ahanoff\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/ahatzz11\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/6256032?v=4?s=100\" width=\"100px;\" alt=\"Alex Hatzenbuhler\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAlex Hatzenbuhler\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/mshick/add-pr-comment/commits?author=ahatzz11\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"http://www.august8.net\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/766820?v=4?s=100\" width=\"100px;\" alt=\"Tommy Wang\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eTommy Wang\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/mshick/add-pr-comment/commits?author=twang817\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/ljetten\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/7528045?v=4?s=100\" width=\"100px;\" alt=\"Laura Jetten\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eLaura Jetten\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/mshick/add-pr-comment/commits?author=ljetten\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/manan-jadhav-ab\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/166636237?v=4?s=100\" width=\"100px;\" alt=\"Manan Jadhav\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eManan Jadhav\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/mshick/add-pr-comment/commits?author=manan-jadhav-ab\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-restore --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmshick%2Fadd-pr-comment","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmshick%2Fadd-pr-comment","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmshick%2Fadd-pr-comment/lists"}