54

I am trying to get a regular comment inserted in a pull request from a GitHub action. I can't seem to get it right. Octokit, the underlying library, allows you to create reviewComments to PRs, but those refer to a commit and that's not what I want, I want a simple comment. I figured I can just use octokit.issues.createComment. However, that does not seem to work. Here's the code

import * as core from '@actions/core';
const {GitHub, context} = require('@actions/github')
const parse = require('parse-diff')

async function run() {
    try {
        // get information on everything
        const token = core.getInput('github-token', {required: true})
        const github = new GitHub(token, {} )
        console.log( context )
        const PR_number = context.payload.pull_request.number

        // Check if the body contains required string
        const bodyContains = core.getInput('bodyContains')

        if ( context.payload.pull_request.body.indexOf( bodyContains) < 0  ) {
            core.setFailed("The body of the PR does not contain " + bodyContains);
            console.log( "Actor " + context.actor + " pr number " PR_number)
            const result = await github.issues.createComment({
                owner: context.actor,
                repo: context.payload.repository.full_name,
                issue_number: PR_number,
                body: "We need to have the word " + bodyContains + " in the body of the pull request"
            });
            console.log(result)
       } // more irrelevant stuff below
}}

This simply seems to retur "Not found". I can't seem to be able to find out if it's a type problem, or something different. Theoretically, owner, repo, and issue number, as well as body, should be right, and it's printed correctly. Any help will be appreciated. This is probably a more general question in the realm of GitHub API, with GitHub actions being simply the context, so I might be wrong there.

1
  • 1
    I had a similar need and wanted a bot-like comment inserted by GitHub Actions. I'm going to shamelessly share my repo, which I managed to do the trick with axios and REST call - some example PR and issue are in the repo: github.com/rytswd/respost Commented Sep 24, 2019 at 15:30

8 Answers 8

105

A canonical way is using the official Github Script actions. Don't get confused, issues and PRs are the same for the GitHub API.

EDIT 2021: (V5 or later)

Adapting to GH's newer versions, one has to reference the rest client directly. See note as of writing.

on:
  # Trigger the workflow on push or pull request
  pull_request:
    branches:
      - master
      - develop

jobs:
  comment:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/github-script@v7
        with:
          github-token: ${{secrets.GITHUB_TOKEN}}
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: '👋 Thanks for reporting!'
            })

2020: (V3)

on:
  # Trigger the workflow on push or pull request
  pull_request:
    branches:
      - master
      - develop

jobs:
  comment:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/github-script@v3
        with:
          github-token: ${{secrets.GITHUB_TOKEN}}
          script: |
            github.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: '👋 Thanks for reporting!'
            })

Seen on: https://github.com/actions/github-script#comment-on-an-issue

Sign up to request clarification or add additional context in comments.

11 Comments

I don't like this 2020 approach. Touching real API endpoints with curl should be the way to do it. Otherwise, this all github actions thingie is useless as a script, as it uses another "script", thus obscuring the intent and jeopardizing itself. As a result, making you dumb, cause you don't know (or have control over, rather) what's going on.
@SevastyanSavanyuk OP's wording could have been less opinionated, but once you are in the GH ecosystem, I think wanting to be less dependent on it is kind of not necessary. Having worked a lot with actions, this is the best way to go imo
As for "Don't get confused, issues and PRs are the same for the GitHub API.", check github.com/actions/toolkit/blob/main/packages/github/src/…
Shouldn't this be triggered by pull_request_target instead of pull_request? In a run triggered by pull_request, GITHUB_TOKEN doesn't have write access to the repository and causes the error 'Resource not accessible by integration'.
@wjkw1: it seems to be pull-requests: write with a hyphen, rather than an underscore?
|
32

I initially tried to use Respost, but it doesn't allow setting a raw body string.

So here's a way to do it with curl.

In a .github/workflows/whatever.yml:

name: Some workflow

on:
  issue_comment:
    types: [created]

jobs:
  comment:
    if: contains(github.event.comment.body, 'special string')

    runs-on: ubuntu-latest

    steps:
      - name: Add comment to PR
        env:
          URL: ${{ github.event.issue.comments_url }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          curl \
            -X POST \
            $URL \
            -H "Content-Type: application/json" \
            -H "Authorization: token $GITHUB_TOKEN" \
            --data '{ "body": "blah blah" }'

2 Comments

For the event pull_request I had to use ${{ github.event.pull_request.comments_url }} for the URL
for help with string substitution see here for single/double quotes stackoverflow.com/questions/13799789/…
17

The other answers don't mention is the security restrictions of a GitHub action run from a fork that triggers the pull_request event. The GITHUB_TOKEN in these actions does not have write access to the repository and therefore cannot create a comment. See permissions for the GITHUB_TOKEN.

The GitHub docs for the workflow_run event have a good example of how to work around this. The basic idea is to have the workflow that is triggered by the pull_request event upload any info needed in the comment as a build artifact using actions/upload-artifact. Then a separate workflow triggered by a workflow_run event downloads the information using actions/download-artifact.

NOTE: For security, since the workflow triggered by workflow_run has write access, it must be committed to the default branch before it can be used. (Also keep in mind that the build artifacts could contain malicious data from a malicious pull request).

Here is a copy of the example workflows from the linked docs (in case the link breaks or the docs change):

name: Upload data

on:
  pull_request:

jobs:
  upload:
    runs-on: ubuntu-latest

    steps:        
      - name: Save PR number
        env:
          PR_NUMBER: ${{ github.event.number }}
        run: |
          mkdir -p ./pr
          echo $PR_NUMBER > ./pr/pr_number
      - uses: actions/upload-artifact@v3
        with:
          name: pr_number
          path: pr/
name: Use the data

on:
  workflow_run:
    workflows: [Upload data]
    types:
      - completed

jobs:
  download:
    runs-on: ubuntu-latest
    steps:
      - name: 'Download artifact'
        uses: actions/github-script@v5
        with:
          script: |
            let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
               owner: context.repo.owner,
               repo: context.repo.repo,
               run_id: context.payload.workflow_run.id,
            });
            let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
              return artifact.name == "pr_number"
            })[0];
            let download = await github.rest.actions.downloadArtifact({
               owner: context.repo.owner,
               repo: context.repo.repo,
               artifact_id: matchArtifact.id,
               archive_format: 'zip',
            });
            let fs = require('fs');
            fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/pr_number.zip`, Buffer.from(download.data));

      - name: 'Unzip artifact'
        run: unzip pr_number.zip

      - name: 'Comment on PR'
        uses: actions/github-script@v5
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            let fs = require('fs');
            let issue_number = Number(fs.readFileSync('./pr_number'));
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: issue_number,
              body: 'Thank you for the PR!'
            });

1 Comment

You could also call the workflow from another workflow and pass the message as a parameter.
10

You can also use the @actions/github which will permit you to use an octokit client to simplify the actions :

const core = require('@actions/core');
const github = require('@actions/github');

async function run() {
  try {
    const message = core.getInput('message');
    const github_token = core.getInput('GITHUB_TOKEN');

    const context = github.context;
    if (context.payload.pull_request == null) {
        core.setFailed('No pull request found.');
        return;
    }
    const pull_request_number = context.payload.pull_request.number;

    const octokit = new github.GitHub(github_token);
    const new_comment = octokit.issues.createComment({
        ...context.repo,
        issue_number: pull_request_number,
        body: message
      });

  } catch (error) {
    core.setFailed(error.message);
  }
}

run();

Taken from this repo.

1 Comment

Here's a demo as standalone workflow: workflow.yml, main.js. But yeah, just use actions/github-script most likely: stackoverflow.com/a/64126737/895245
6

in 2024 this is how it worked for me:

name: My name example
on:
  pull_request:
    types: [opened, edited, synchronize, reopened]

jobs:
  comment-in-pr:

    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
      repository-projects: write
      id-token: write

    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - uses: actions/github-script@v6
        with:
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: '👋 Thanks for reporting!'
            })

3 Comments

I think this only works when you submit the PR from the same repository. If another user submits a PR from a fork, it fails with "Resource not accessible by integration"
Solution for my case was to use pull_request_target instead of pull_request
@SvemirBrkic Note that using pull_request_target is much more dangerous because it allows the code in the action write access to your repo!
3

Update 2025-11-13: Add ghprcomment

In my setting, the pull requests come from forks. Then, it is difficult to add comments, because of restricted token rights.

Therefore, I wrote a script to comment on PRs.

Define the messages to be posted

The ghprcomment.yml provides a list of jobs and the respective message to be posted. The job names are ordered by priority. The first job that failed is used to determine the message to post.

Example:

- jobName: job1
  message: |
    Job 1 failed

    Please check your IDE configuration for proper import ordering
- jobName: job3
  message: |
    Job 3 failed

    Please run OpenRewrite.
- jobName: job2
  message: |
    Job 2 failed

    Please run "[Checkstyle](https://checkstyle.sourceforge.io/)" in your IDE and check for errors.

The full file is available at ghprcomment.yml.

GitHub workflow

One needs to create a GitHub workflow running within the repository context. For that, create a new GitHub workflow triggered by the other workflow. You need to adapt a) the name of the triggering workflow (Check in the example) and b) the repository where it should be commented (koppor/workflow-comment-test) in the example.

name: Comment on PR

on:
  workflow_run:
    workflows: ["Check"]
    types:
      - completed

jobs:
  comment:
    # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#running-a-workflow-based-on-the-conclusion-of-another-workflow
    if: ${{ github.event.workflow_run.conclusion == 'failure' }}
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      pull-requests: write
    timeout-minutes: 10
    steps:
       - name: Download PR number
         uses: actions/download-artifact@v4
         with:
            name: pr_number
            github-token: ${{ secrets.GITHUB_TOKEN }}
            run-id: ${{ github.event.workflow_run.id }}
       - name: Read pr_number.txt
         id: read-pr_number
         run: |
            PR_NUMBER=$(cat pr_number.txt)
            echo "Read PR number $PR_NUMBER"
            echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
       - name: Checkout
         if: ${{ steps.read-pr_number.outputs.pr_number != '' }}
         uses: actions/checkout@v4
         with:
            fetch-depth: '0'
            show-progress: 'false'
            token: ${{ secrets.GITHUB_TOKEN }}
       - name: jbang
         if: ${{ steps.read-pr_number.outputs.pr_number != '' }}
         uses: jbangdev/[email protected]
         with:
            script: ghprcomment@koppor/ghprcomment
            scriptargs: "-r koppor/workflow-comment-test -p ${{ steps.read-pr_number.outputs.pr_number }} -w ${{ github.event.workflow_run.id }}"
            trust: https://github.com/koppor/ghprcomment/
         env:
            GITHUB_OAUTH: ${{ secrets.GITHUB_TOKEN }}

The full example is available at pr-comment.yml. Real world file: https://github.com/JabRef/jabref/blob/main/.github/ghprcomment.yml.

In the triggering workflow, you need to add a step to upload the pull request number:

name: "Check"
...
jobs:
  upload-pr-number:
    runs-on: ubuntu-latest
    steps:
      - name: Create pr_number.txt
        run: echo "${{ github.event.number }}" > pr_number.txt
      - uses: actions/upload-artifact@v4
        with:
          name: pr_number
          path: pr_number.txt

In case you want to comment on PRs from non-forks, I like the GitHub action Comment Pull Request for that. Mostly, because it allows for updating comments.

Example for adding a comment:

- name: Comment PR
  uses: thollander/actions-comment-pull-request@v2
  with:
    message: |
      Hello world ! :wave:
    reactions: eyes, rocket

Updating a comment is done via "tags" (which render as "hidden" HTML elements)

- name: Comment PR with execution number
  uses: thollander/actions-comment-pull-request@v2
  with:
    message: |
      _(execution **${{ github.run_id }}** / attempt **${{ github.run_attempt }}**)_
    comment_tag: execution

Comments

1

That's what works for me, when I want to comment on a PR from a push event (not pull_request event, where it's easy):

      - uses: actions/github-script@v6
        with:
          script: |
            github.rest.issues.createComment({
              issue_number: (await github.rest.repos.listPullRequestsAssociatedWithCommit({
                commit_sha: context.sha,
                owner: context.repo.owner,
                repo: context.repo.repo,
              })).data[0].number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: '👋 Thanks for reporting!'
            })

The key part is this, which allows to get the right "issue number" for a PR:

await github.rest.repos.listPullRequestsAssociatedWithCommit({
                commit_sha: context.sha,
                owner: context.repo.owner,
                repo: context.repo.repo,
              })).data[0].number

Comments

1

You need write permission to your job for this, this worked for me. Taken inspiration from another comment -

stage_test:
    permissions: write-all
    runs-on: [ubuntu-latest]
    steps:
    - name: Check out code
      uses: actions/checkout@v2 
    - name: Comment PR
      uses: thollander/actions-comment-pull-request@v2
      with:
        message: |
          Test successful !
        reactions: rocket

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.