Automating Release Notes with GitHub Actions
A comprehensive guide to integrating Auto Release Note CLI into your CI/CD workflows. Automate release note generation and never write them manually again.
Quick Start
Prerequisites
- GitHub Secrets: Add your Auto Release Note credentials
- Go to your repository → Settings → Secrets and variables → Actions
- Add
AUTO_RELEASE_TOKEN(your API token) - Add
AUTO_RELEASE_PROJECT_ID(your project ID)
- Get Your Credentials:
- API Token: Web App → Settings → API
- Project ID: Run
arn initlocally or check your.autorelease/config.json
Basic Workflow
Copy this minimal workflow to .github/workflows/release-notes.yml:
name: Generate Release Notes
on:
push:
tags:
- 'v*'
jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download CLI
run: |
DOWNLOAD_URL=$(curl -s https://api.github.com/repos/papyrus-digital/auto-release-cli-distribution/releases/latest | grep "browser_download_url.*linux_amd64.tar.gz" | cut -d '"' -f 4)
curl -LO "$DOWNLOAD_URL"
tar -xzf arn_*_linux_amd64.tar.gz
sudo mv arn /usr/local/bin/
- name: Generate Release Notes
env:
AUTO_RELEASE_TOKEN: ${{ secrets.AUTO_RELEASE_TOKEN }}
AUTO_RELEASE_PROJECT_ID: ${{ secrets.AUTO_RELEASE_PROJECT_ID }}
run: |
PREV_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")
if [ -z "$PREV_TAG" ]; then
arn generate --non-interactive --mode tag --to ${{ github.ref_name }} --template "Standard Release Notes" --output-url
else
arn generate --non-interactive --mode tag --from $PREV_TAG --to ${{ github.ref_name }} --template "Standard Release Notes" --output-url
fiWorkflow Patterns
Different teams have different release cadences. Choose the pattern that fits your workflow:
Tag-Based Releases
Best for: Teams that release on version tags (e.g., v1.0.0, v2.1.3)
When it runs: Automatically when you push a version tag
name: Generate Release Notes on Tag
on:
push:
tags:
- 'v*'
jobs:
generate-release-notes:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download Auto Release Note CLI
run: |
DOWNLOAD_URL=$(curl -s https://api.github.com/repos/papyrus-digital/auto-release-cli-distribution/releases/latest | grep "browser_download_url.*linux_amd64.tar.gz" | cut -d '"' -f 4)
curl -LO "$DOWNLOAD_URL"
tar -xzf arn_*_linux_amd64.tar.gz
sudo mv arn /usr/local/bin/
- name: Generate Release Notes
id: generate
env:
AUTO_RELEASE_TOKEN: ${{ secrets.AUTO_RELEASE_TOKEN }}
AUTO_RELEASE_PROJECT_ID: ${{ secrets.AUTO_RELEASE_PROJECT_ID }}
run: |
PREV_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")
if [ -z "$PREV_TAG" ]; then
RELEASE_URL=$(arn generate --non-interactive --mode tag --to ${{ github.ref_name }} --template "Standard Release Notes" --output-url)
else
RELEASE_URL=$(arn generate --non-interactive --mode tag --from $PREV_TAG --to ${{ github.ref_name }} --template "Standard Release Notes" --output-url)
fi
echo "url=$RELEASE_URL" >> $GITHUB_OUTPUT
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ github.ref_name }}
body: |
Release notes: ${{ steps.generate.outputs.url }}Pull Request Integration
Best for: Teams that want release notes previews on PRs
When it runs: When a PR is merged to main/master
name: Generate Release Notes for PR
on:
pull_request:
types: [closed]
branches:
- master
jobs:
generate-release-notes:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
issues: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.merge_commit_sha }}
- name: Download Auto Release Note CLI
run: |
DOWNLOAD_URL=$(curl -s https://api.github.com/repos/papyrus-digital/auto-release-cli-distribution/releases/latest | grep "browser_download_url.*linux_amd64.tar.gz" | cut -d '"' -f 4)
curl -LO "$DOWNLOAD_URL"
tar -xzf arn_*_linux_amd64.tar.gz
chmod +x arn
sudo mv arn /usr/local/bin/
- name: Generate Release Notes for PR
id: generate
env:
AUTO_RELEASE_TOKEN: ${{ secrets.AUTO_RELEASE_TOKEN }}
AUTO_RELEASE_PROJECT_ID: ${{ secrets.AUTO_RELEASE_PROJECT_ID }}
run: |
BASE_SHA=${{ github.event.pull_request.base.sha }}
HEAD_SHA=${{ github.event.pull_request.head.sha }}
RELEASE_URL=$(arn generate \
--non-interactive \
--mode commit \
--from $BASE_SHA \
--to $HEAD_SHA \
--template "Standard Changelog" \
--output-url)
echo "url=$RELEASE_URL" >> $GITHUB_OUTPUT
- name: Comment on PR
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const url = '${{ steps.generate.outputs.url }}';
const body = `## 📝 Release Notes Generated
Release notes have been automatically generated for this PR!
**View Release Notes:** [Click here](${url})
---
*Generated by Auto Release Note CLI*`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});Scheduled Releases
Best for: Teams with regular release cadences (weekly, monthly)
When it runs: On a schedule (e.g., every Monday at 9 AM)
name: Weekly Release Notes
on:
schedule:
- cron: '0 9 * * 1' # Every Monday at 9 AM UTC
jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download CLI
run: |
DOWNLOAD_URL=$(curl -s https://api.github.com/repos/papyrus-digital/auto-release-cli-distribution/releases/latest | grep "browser_download_url.*linux_amd64.tar.gz" | cut -d '"' -f 4)
curl -LO "$DOWNLOAD_URL"
tar -xzf arn_*_linux_amd64.tar.gz
sudo mv arn /usr/local/bin/
- name: Generate Release Notes
env:
AUTO_RELEASE_TOKEN: ${{ secrets.AUTO_RELEASE_TOKEN }}
AUTO_RELEASE_PROJECT_ID: ${{ secrets.AUTO_RELEASE_PROJECT_ID }}
run: |
# Get commits from last 7 days
SINCE_DATE=$(date -u -d '7 days ago' +%Y-%m-%dT%H:%M:%SZ)
arn generate --non-interactive --mode commit --since "$SINCE_DATE" --template "Standard Release Notes" --output-urlManual Dispatch
Best for: On-demand release note generation
When it runs: Manually triggered from GitHub Actions UI
name: Manual Release Notes
on:
workflow_dispatch:
inputs:
from:
description: 'From tag/branch/SHA'
required: false
to:
description: 'To tag/branch/SHA'
required: true
template:
description: 'Template name'
required: false
default: 'Standard Release Notes'
jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download CLI
run: |
DOWNLOAD_URL=$(curl -s https://api.github.com/repos/papyrus-digital/auto-release-cli-distribution/releases/latest | grep "browser_download_url.*linux_amd64.tar.gz" | cut -d '"' -f 4)
curl -LO "$DOWNLOAD_URL"
tar -xzf arn_*_linux_amd64.tar.gz
sudo mv arn /usr/local/bin/
- name: Generate Release Notes
env:
AUTO_RELEASE_TOKEN: ${{ secrets.AUTO_RELEASE_TOKEN }}
AUTO_RELEASE_PROJECT_ID: ${{ secrets.AUTO_RELEASE_PROJECT_ID }}
run: |
if [ -z "${{ inputs.from }}" ]; then
arn generate --non-interactive --mode commit --to "${{ inputs.to }}" --template "${{ inputs.template }}" --output-url
else
arn generate --non-interactive --mode commit --from "${{ inputs.from }}" --to "${{ inputs.to }}" --template "${{ inputs.template }}" --output-url
fiBest Practices
Use Appropriate Modes
- •
--mode tag: For version releases - •
--mode commit: For any git reference - •
--mode branch: For branch-based releases
Template Selection
Choose templates that match your team's style:
- • "Standard Release Notes" - General purpose
- • "Changelog Style" - Traditional format
- • "Blog Post Style" - Narrative format
Error Handling
Always handle cases where previous tags don't exist:
PREV_TAG=$(git describe --tags \
--abbrev=0 HEAD~1 2>/dev/null || echo "")
if [ -z "$PREV_TAG" ]; then
# Generate from beginning
else
# Generate between tags
fiSecurity
- ✅ Store credentials in GitHub Secrets
- ✅ Use
--output-urlflag - ✅ Rotate API tokens regularly
- ✅ Never commit secrets to code
Troubleshooting
Configuration Not Found
Ensure secrets are set correctly in GitHub repository settings:
- Go to Settings → Secrets and variables → Actions
- Verify
AUTO_RELEASE_TOKENandAUTO_RELEASE_PROJECT_IDare set - Check that environment variables are passed correctly in workflow
No Commits Found
Possible causes:
fetch-depthis too shallow - usefetch-depth: 0- Tag/branch doesn't exist
- Invalid git reference
Workflow Doesn't Trigger
Check:
- Workflow file is in
.github/workflows/ - File has
.ymlor.yamlextension - Trigger conditions match (e.g., tag pattern
v*) - Branch protection rules allow workflows
Ready to Automate?
Start generating release notes automatically with GitHub Actions. Choose a workflow pattern above and integrate it into your repository in minutes.