Advanced GitHub Actions Triggers
**Last Updated:** November 2025
Overview
Advanced GitHub Actions Triggers
Last Updated: November 2025
Overview
This guide covers advanced trigger patterns for GitHub Actions workflows beyond the basic push, pull_request, and schedule triggers. These patterns enable workflow orchestration, external integrations, ChatOps, and complex automation scenarios.
Table of Contents
- Workflow Orchestration
- External Integration
- ChatOps Patterns
- Deployment Triggers
- Advanced Path Filtering
- Security Patterns
- GitHub Services Integration
- Best Practices
Workflow Orchestration
workflow_run Trigger
The workflow_run trigger allows you to chain workflows together, running one workflow after another completes. This is the recommended pattern for handling external pull requests securely.
Basic Syntax
name: Deploy Application
on:
workflow_run:
workflows: ["CI Pipeline"]
types: [completed]
branches: [main, staging]
Trigger Types
requested- Workflow run was requestedin_progress- Workflow run is currently runningcompleted- Workflow run has finished (success, failure, or cancelled)
Use Cases
1. Deployment After CI Success
# deploy.yml - Separate deployment workflow
name: Deploy to Production
on:
workflow_run:
workflows: ["CI Pipeline"]
types: [completed]
branches: [main]
jobs:
deploy:
# Only deploy if CI passed
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
environment:
name: production
url: https://example.com
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Download build artifacts from CI
uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4
with:
name: build-artifacts
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy application
run: |
echo "Deploying commit ${{ github.event.workflow_run.head_sha }}"
# Deployment commands here
2. Security Scanning for External PRs
# security-scan.yml - Runs after CI for external PRs
name: Security Scan
on:
workflow_run:
workflows: ["CI"]
types: [completed]
permissions:
security-events: write
contents: read
jobs:
scan:
# Only scan if CI passed and it was a PR
if: |
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Checkout PR code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ github.event.workflow_run.head_sha }}
- name: Run security scan
run: |
# Security scanning without exposing secrets to PR
npm audit --audit-level=high
Accessing Workflow Run Information
steps:
- name: Get workflow run details
run: |
echo "Workflow: ${{ github.event.workflow_run.name }}"
echo "Conclusion: ${{ github.event.workflow_run.conclusion }}"
echo "Head SHA: ${{ github.event.workflow_run.head_sha }}"
echo "Head Branch: ${{ github.event.workflow_run.head_branch }}"
echo "Run ID: ${{ github.event.workflow_run.id }}"
echo "Event: ${{ github.event.workflow_run.event }}"
Security Benefits
ā
Safer than pull_request_target for external PRs:
- Runs with workflow file from target branch (not PR)
- No access to PR code by default
- Secrets are safe from malicious PRs
- Must explicitly checkout PR code if needed
External Integration
repository_dispatch Trigger
The repository_dispatch trigger allows external systems to trigger workflows via the GitHub API. This enables integration with webhooks, custom dashboards, monitoring systems, and other external tools.
Basic Syntax
name: Handle External Event
on:
repository_dispatch:
types: [deploy-prod, deploy-staging, run-migration, rebuild-cache]
Event Types
Event types are custom strings you define. Common patterns:
deploy-<environment>- Deployment triggersrun-<task>- Task executionnotify-<event>- Notification handling
Triggering via API
Using curl:
curl -X POST \\
-H "Authorization: token $GITHUB_TOKEN" \\
-H "Accept: application/vnd.github.v3+json" \\
https://api.github.com/repos/OWNER/REPO/dispatches \\
-d '{
"event_type": "deploy-prod",
"client_payload": {
"version": "v1.2.3",
"requestor": "monitoring-system",
"environment": "production",
"rollback": false
}
}'
Using Python:
def trigger_deployment(repo, token, version, environment):
url = f"https://api.github.com/repos/{repo}/dispatches"
headers = {
"Authorization": f"token {token}",
"Accept": "application/vnd.github.v3+json"
}
payload = {
"event_type": f"deploy-{environment}",
"client_payload": {
"version": version,
"requestor": "api",
"environment": environment
}
}
response = requests.post(url, json=payload, headers=headers)
return response.status_code == 204
Using Node.js (Octokit):
const { Octokit } = require("@octokit/rest");
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
await octokit.repos.createDispatchEvent({
owner: "OWNER",
repo: "REPO",
event_type: "deploy-prod",
client_payload: {
version: "v1.2.3",
requestor: "api",
environment: "production"
}
});
Handling Dispatch Events
name: External Deployment Trigger
on:
repository_dispatch:
types: [deploy-prod, deploy-staging, deploy-dev]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Parse dispatch payload
id: payload
run: |
echo "Event Type: ${{ github.event.action }}"
echo "Version: ${{ github.event.client_payload.version }}"
echo "Environment: ${{ github.event.client_payload.environment }}"
echo "Requestor: ${{ github.event.client_payload.requestor }}"
# Set outputs for later steps
echo "version=${{ github.event.client_payload.version }}" >> $GITHUB_OUTPUT
echo "environment=${{ github.event.client_payload.environment }}" >> $GITHUB_OUTPUT
- name: Checkout specific version
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ steps.payload.outputs.version }}
- name: Deploy to environment
env:
ENVIRONMENT: ${{ steps.payload.outputs.environment }}
VERSION: ${{ steps.payload.outputs.version }}
run: |
echo "Deploying $VERSION to $ENVIRONMENT"
# Deployment logic here
Use Cases
1. Webhook Integration
Trigger workflows from external monitoring/alerting systems:
on:
repository_dispatch:
types: [incident-detected, performance-degradation]
jobs:
handle-alert:
runs-on: ubuntu-latest
steps:
- name: Process alert
run: |
SEVERITY="${{ github.event.client_payload.severity }}"
MESSAGE="${{ github.event.client_payload.message }}"
echo "Alert received: $MESSAGE (Severity: $SEVERITY)"
if [[ "$SEVERITY" == "critical" ]]; then
# Trigger emergency procedures
echo "Initiating critical incident response"
fi
2. Manual Trigger from Dashboard
Custom deployment dashboard that triggers GitHub Actions:
on:
repository_dispatch:
types: [dashboard-deploy]
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: ${{ github.event.client_payload.environment }}
steps:
- name: Validate payload
run: |
# Validate required fields
if [[ -z "${{ github.event.client_payload.version }}" ]]; then
echo "Error: version is required"
exit 1
fi
if [[ -z "${{ github.event.client_payload.approver }}" ]]; then
echo "Error: approver is required"
exit 1
fi
- name: Deploy
run: |
echo "Deploying version ${{ github.event.client_payload.version }}"
echo "Approved by: ${{ github.event.client_payload.approver }}"
3. Cross-Repository Triggers
Trigger workflow in repo A from repo B:
# In Repository A
on:
repository_dispatch:
types: [dependency-updated]
jobs:
rebuild:
runs-on: ubuntu-latest
steps:
- name: Rebuild with new dependency
run: |
echo "Dependency ${{ github.event.client_payload.dependency }} updated to ${{ github.event.client_payload.version }}"
# Rebuild logic
Security Considerations
š Token Security:
- Use a Personal Access Token (PAT) or GitHub App token
- Minimum required scope:
repo(for private repos) orpublic_repo(for public repos) - Store token in secrets, never in code
- Rotate tokens regularly
š Payload Validation:
- Always validate
client_payloadfields - Sanitize user input to prevent injection
- Use allowlists for critical fields
- name: Validate environment
run: |
ENV="${{ github.event.client_payload.environment }}"
# Only allow specific environments
if [[ ! "$ENV" =~ ^(dev|staging|production)$ ]]; then
echo "Error: Invalid environment: $ENV"
exit 1
fi
ChatOps Patterns
issue_comment Trigger
The issue_comment trigger allows you to implement ChatOps - executing workflows via commands in issue or PR comments.
Basic Syntax
name: ChatOps Commands
on:
issue_comment:
types: [created, edited]
Comment Types
created- New comment postededited- Comment was editeddeleted- Comment was deleted (rarely used)
Implementing ChatOps Commands
Full ChatOps Example:
name: ChatOps - Deploy Command
on:
issue_comment:
types: [created]
jobs:
deploy:
# Security checks (CRITICAL!)
if: |
github.event.issue.pull_request &&
startsWith(github.event.comment.body, '/deploy') &&
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
deployments: write
steps:
# Step 1: React to comment to show command received
- name: Add reaction to comment
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
script: |
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: 'rocket'
});
# Step 2: Parse command and arguments
- name: Parse deploy command
id: parse
run: |
COMMAND="${{ github.event.comment.body }}"
# Extract environment (default: staging)
ENV=$(echo "$COMMAND" | grep -oP '/deploy\\s+\\K\\w+' || echo 'staging')
# Validate environment
if [[ ! "$ENV" =~ ^(dev|staging|production)$ ]]; then
echo "error=Invalid environment: $ENV" >> $GITHUB_OUTPUT
exit 1
fi
echo "environment=$ENV" >> $GITHUB_OUTPUT
echo "pr_number=${{ github.event.issue.number }}" >> $GITHUB_OUTPUT
# Step 3: Get PR details
- name: Get PR branch
id: pr
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
script: |
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: ${{ steps.parse.outputs.pr_number }}
});
core.setOutput('ref', pr.data.head.ref);
core.setOutput('sha', pr.data.head.sha);
core.setOutput('repo', pr.data.head.repo.full_name);
# Step 4: Checkout PR code
- name: Checkout PR code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ steps.pr.outputs.ref }}
repository: ${{ steps.pr.outputs.repo }}
# Step 5: Deploy
- name: Deploy to environment
id: deploy
env:
ENVIRONMENT: ${{ steps.parse.outputs.environment }}
PR_SHA: ${{ steps.pr.outputs.sha }}
run: |
echo "Deploying PR #${{ steps.parse.outputs.pr_number }} to $ENVIRONMENT"
echo "SHA: $PR_SHA"
# Deployment logic here
DEPLOY_URL="https://$ENVIRONMENT.example.com"
echo "url=$DEPLOY_URL" >> $GITHUB_OUTPUT
# Step 6: Comment with results
- name: Comment deployment result
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
script: |
const environment = '${{ steps.parse.outputs.environment }}';
const url = '${{ steps.deploy.outputs.url }}';
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: ${{ steps.parse.outputs.pr_number }},
body: `ā
Deployed to **${environment}**\
\
š ${url}\
\
Triggered by: @${{ github.event.comment.user.login }}`
});
# Step 7: Handle failures
- name: Comment on failure
if: failure()
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
script: |
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: ${{ github.event.issue.number }},
body: `ā Deployment failed\
\
Check the [workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.`
});
Common ChatOps Commands
1. /deploy [environment]
startsWith(github.event.comment.body, '/deploy')
2. /run-tests [suite]
startsWith(github.event.comment.body, '/run-tests')
3. /benchmark
contains(github.event.comment.body, '/benchmark')
4. /approve
github.event.comment.body == '/approve'
Permission Checking
Author Association Levels:
OWNER- Repository ownerMEMBER- Organization memberCOLLABORATOR- Repository collaboratorCONTRIBUTOR- Has contributed