GitHub Actions Issue and PR Automation
Busy repositories collect dozens of issues and pull requests every week. Sorting, labeling, and greeting each one by hand drains time from real development. Workflows react to these events instantly and handle the routine work.
Issue and PR Automation in Simple Words
Picture a receptionist at a clinic. Each visitor gets a greeting, a numbered ticket, and a pointer to the right department. Workflows play the receptionist for your repository. Every new issue or pull request receives a welcome, a label, and a route to the right person.
Events That Start Workflows
| Event | Common Types | Typical Use |
|---|---|---|
| issues | opened, labeled, closed | Welcome and triage |
| issue_comment | created | Respond to commands |
| pull_request | opened, synchronize, ready_for_review | Labeling and checks |
| schedule | cron timer | Close stale items |
Automation Flow
New issue opened
|
v
+---------------+ +-----------------+ +------------------+
| Workflow runs | --> | Add label | --> | Post welcome |
| | | "needs-triage" | | comment |
+---------------+ +-----------------+ +------------------+Welcome Comment With github-script
The actions/github-script action runs short JavaScript snippets with a ready-made GitHub client.
name: Welcome
on:
issues:
types: [ opened ]
permissions:
issues: write
jobs:
greet:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v7
with:
script: |
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: "Thanks for opening this issue. A maintainer will review it soon."
});
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: ["needs-triage"]
});Label Pull Requests by File Path
The actions/labeler action reads a rules file and applies labels based on changed files.
# .github/labeler.yml
documentation:
- changed-files:
- any-glob-to-any-file: "docs/**"
frontend:
- changed-files:
- any-glob-to-any-file: "src/ui/**"
name: Label PRs
on:
pull_request:
permissions:
contents: read
pull-requests: write
jobs:
label:
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v5
PR changes docs/intro.md --> label: documentation
PR changes src/ui/menu.js --> label: frontendClose Stale Items
The actions/stale action warns and then closes items with no recent activity. A scheduled trigger runs it daily.
name: Stale Cleanup
on:
schedule:
- cron: "30 1 * * *"
permissions:
issues: write
pull-requests: write
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
days-before-stale: 60
days-before-close: 14
stale-issue-message: "This issue has had no activity for 60 days."Permissions Matter
Each example grants only the scopes it needs. Commenting on an issue needs issues: write. Labeling a pull request needs pull-requests: write. Missing scopes cause the error "Resource not accessible by integration".
Safety With Forked Pull Requests
The pull_request event gives forked contributions a read-only token, so labeling may fail on fork PRs. The pull_request_target event gives write access but runs in the context of your base branch. Never check out and run code from the fork inside a pull_request_target workflow. Untrusted code with a write token can damage your repository.
Ideas to Try
- Assign new bug reports to a rotating maintainer.
- Add a checklist comment to every pull request.
- Move issues to a project board when they receive a label.
- Remind authors to update the changelog when source files change.
Start with one small automation, watch it for a week, and add more after the team trusts it.
