The Real Fix for Release-Please Triggers¶
A few days ago I wrote about why release-please PRs don't trigger builds and proposed a dual-trigger pattern as the fix. Today I discovered that pattern is a workaround with side effects. Here's the actual solution.
The Workaround I Documented¶
The previous post explained that GITHUB_TOKEN actions don't emit workflow events, and proposed adding a secondary push trigger:
This works. Release-please commits trigger push events, so the build runs.
But it's solving the wrong problem.
The Actual Problem¶
Root Cause
GITHUB_TOKEN is the wrong authentication mechanism for release-please.
The issue isn't that we need a different trigger. When a GitHub App creates a PR, the pull_request event fires normally. No workarounds needed.
flowchart LR
subgraph token[GITHUB_TOKEN]
T1[Create PR] --> T2[No event]
end
subgraph app[GitHub App]
A1[Create PR] --> A2[pull_request event]
end
T2 -.->|workaround needed| Build
A2 --> Build[Build Pipeline]
%% Ghostty Hardcore Theme
style T1 fill:#f92572,color:#1b1d1e
style T2 fill:#f92572,color:#1b1d1e
style A1 fill:#a7e22e,color:#1b1d1e
style A2 fill:#a7e22e,color:#1b1d1e
style Build fill:#65d9ef,color:#1b1d1e
The Real Fix¶
The Solution
Generate a GitHub App token. The PR will trigger pull_request events like any developer-created PR.
Generate a GitHub App token and pass it to release-please:
jobs:
release-please:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Generate App Token
id: app-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.CORE_APP_ID }}
private-key: ${{ secrets.CORE_APP_PRIVATE_KEY }}
owner: your-org
- uses: googleapis/release-please-action@v4
id: release
with:
token: ${{ steps.app-token.outputs.token }}
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
That's it. The PR now triggers pull_request events like any developer-created PR.
Why Not a PAT?¶
Personal Access Tokens also work, but they're the wrong tool:
- Tied to individual user accounts
- Revoked when the user leaves
- Broader permissions than needed
- Manual rotation required
GitHub Apps are the proper solution for machine-to-machine authentication.
The Duplicate Trigger Problem¶
If you implemented my original workaround and then add the GitHub App fix, you'll get duplicate workflow runs:
pull_requestevent fires (GitHub App works correctly)pushevent fires (workaround still active)
The fix: remove the workaround.
on:
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
# push trigger for release-please branches - REMOVED
# No longer needed with GitHub App token
workflow_dispatch:
Before and After¶
| Aspect | Dual-Trigger Workaround | GitHub App Token |
|---|---|---|
| Event type | push |
pull_request |
| PR context available | Limited | Full |
| Duplicate runs risk | Yes, if both triggers exist | No |
| Setup complexity | Low | Medium (one-time App setup) |
| Authentication model | Default token | Proper machine identity |
When to Use the Workaround¶
The dual-trigger pattern still has a place:
- No GitHub App available - Teams without org-level App access
- Quick testing - Validating the concept before proper setup
- Simple repos - Where the complexity isn't justified
But for production pipelines, use the GitHub App approach.
Updated Documentation¶
The Release Pipelines guide has been updated to reflect this. The dual-trigger pattern is now documented as a fallback, not the primary solution.
Lessons Learned¶
- Workarounds become technical debt - The dual-trigger pattern solved the symptom, not the cause
- Question the constraint - Instead of "how do I trigger on push?", ask "why isn't pull_request working?"
- GitHub Apps are underutilized - They solve many authentication edge cases cleanly
The build pipeline now runs on pull_request events. No workarounds. No duplicate runs. Just proper authentication.