How to Run a Workflow on Issue Comment Commands in GitHub Actions
ChatOps lets reviewers trigger deploys or tests by commenting, but you must parse the command and check who sent it.
Trigger on issue_comment, gate on the comment body and author association, then run the action the command requested.
Steps
- Trigger on issue_comment with type created.
- Gate the job with an if that matches the command prefix in the comment body.
- Check github.event.comment.author_association so only collaborators can run it.
- Acknowledge with a reaction or reply so the author sees it was picked up.
Workflow
name: Comment Command
on:
issue_comment:
types: [created]
jobs:
deploy:
if: ${{ startsWith(github.event.comment.body, '/deploy') && github.event.comment.author_association == 'MEMBER' }}
runs-on: ubuntu-latest
steps:
- run: echo "running deploy requested by ${{ github.event.comment.user.login }}"Notes
- issue_comment fires for both issues and PRs, so check github.event.issue.pull_request if you only want PRs.
- Latchkey managed runners run these on-demand command jobs cheaper and self-heal on runner failure.
Verify it actually works
A workflow that runs is not a workflow that works. Confirm the behaviour on a real event rather than on a manual dispatch, because trigger conditions, permissions, and context values all differ between the two.
# 1. validate the file before pushing
docker run --rm -v "$(pwd):/repo" --workdir /repo rhysd/actionlint:latest -color
# 2. trigger the real event, not workflow_dispatch
git commit --allow-empty -m "ci: verify trigger" && git push
# 3. watch it and read the conclusion, not just the colour
gh run watch
gh run view --log-failedWhat usually goes wrong first
- The workflow file must exist on the default branch before scheduled or dispatch triggers appear at all.
GITHUB_TOKENpermissions default to read-only in many organisations. Declare apermissions:block listing every scope the job needs.- Fork pull requests get a read-only token and no access to secrets, regardless of workflow configuration.
actions/checkoutgives you depth 1 on a detached HEAD, so anything needing history or a branch name needsfetch-depth: 0.