This repository contains reusable GitHub Actions workflows that integrate Linear ticket tracking with Slack notifications. When PRs are created or merged targeting main, the workflows automatically:
- Extract Linear ticket IDs from commits
- Send formatted notifications to Slack
- Update Linear ticket status to "Done" after merge
Your GitHub organization must have the following secrets configured:
LINEAR_API_KEY- Linear API key with permission to read and update issuesSLACK_RELEASE_CHANGELOG_WEBHOOK- Slack webhook URL for the release changelog channelGITHUB_TOKEN- Automatically provided by GitHub Actions (no setup needed)
The workflows extract ticket IDs from commit messages (including subject and body) and PR titles using the following pattern:
- Format:
[PREFIX][-_]<number>where PREFIX is any 2-10 letter code (case insensitive) - Examples:
ACC-123DEV-456REP-434MREC-789acc_012(underscores are normalized to dashes)feat: add new feature (DEV-8139)Merge pull request #123 from dualentry/martins/dev-8282-endpoints
Note: The script searches both the commit subject line AND the commit body, so tickets mentioned anywhere in the full commit message will be detected.
Commits without ticket IDs are automatically skipped.
Create workflow files in your repository that call these reusable workflows.
Create .github/workflows/linear-pr-opened.yml:
name: Linear - PR Opened
on:
pull_request:
branches: ["main"]
types: [opened, reopened, synchronize]
jobs:
notify:
uses: dualentry/github-actions/.github/workflows/linear-slack-pr-opened.yml@main
with:
base-branch: dev # Branch to compare against (default: dev)
environment: production # Environment name (default: production)
secrets:
LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }}
SLACK_RELEASE_CHANGELOG_WEBHOOK: ${{ secrets.SLACK_RELEASE_CHANGELOG_WEBHOOK }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Create .github/workflows/linear-pr-merged.yml:
name: Linear - PR Merged
on:
push:
branches: ["main"]
jobs:
release:
uses: dualentry/github-actions/.github/workflows/linear-slack-pr-merged.yml@main
with:
base-branch: dev # Branch to compare against (default: dev)
environment: production # Environment name (default: production)
update-linear-status: true # Update Linear tickets to Done (default: true)
secrets:
LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }}
SLACK_RELEASE_CHANGELOG_WEBHOOK: ${{ secrets.SLACK_RELEASE_CHANGELOG_WEBHOOK }}
Create .github/workflows/codeowners-approved.yml:
name: CODEOWNERS Approved - Slack
on:
pull_request_review:
types: [submitted]
permissions:
pull-requests: read
issues: write
contents: read
jobs:
notify:
uses: dualentry/github-actions/.github/workflows/codeowners-approved-slack.yml@main
# with:
# skip-draft: true # Skip draft PRs (default: true)
# slack-message-prefix: ":rocket: Ready for merge" # Custom message prefix
secrets:
SLACK_RELEASE_CHANGELOG_WEBHOOK: ${{ secrets.SLACK_RELEASE_CHANGELOG_WEBHOOK }}
Prerequisites for CODEOWNERS approval notifications:
- Enable branch protection on your target branch with:
- Require a pull request before merging
- Require approvals (>= 1)
- Require review from Code Owners (this is key!)
- Create a
CODEOWNERSfile in your repo - Add
SLACK_RELEASE_CHANGELOG_WEBHOOKsecret (Slack incoming webhook) - Important: This workflow file must exist on the default branch for the
pull_request_reviewtrigger to work
| Input | Description | Required | Default |
|---|---|---|---|
base-branch |
Base branch to compare against | No | dev |
environment |
Environment name for Slack message | No | production |
| Input | Description | Required | Default |
|---|---|---|---|
base-branch |
Base branch to compare against | No | dev |
environment |
Environment name for Slack message | No | production |
update-linear-status |
Whether to update Linear ticket status to Done | No | true |
| Input | Description | Required | Default |
|---|---|---|---|
skip-draft |
Skip notification for draft PRs | No | true |
slack-message-prefix |
Custom prefix for Slack message (emoji + text) | No | :white_check_mark: CODEOWNERS gate satisfied |
| Secret | Description | Required |
|---|---|---|
SLACK_RELEASE_CHANGELOG_WEBHOOK |
Slack incoming webhook URL | Yes |
GH_TOKEN |
GitHub token with PR read access | No (uses GITHUB_TOKEN) |
If you want to trigger notifications for dev branch as well:
name: Linear - Dev Deployment
on:
push:
branches: ["dev"]
jobs:
release:
uses: dualentry/github-actions/.github/workflows/linear-slack-pr-merged.yml@main
with:
base-branch: dev
environment: dev
update-linear-status: false # Don't mark as Done for dev deployments
secrets:
LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }}
SLACK_RELEASE_CHANGELOG_WEBHOOK: ${{ secrets.SLACK_RELEASE_CHANGELOG_WEBHOOK }}
π New PR Ready for Review
Application: `frontend`
Environment: `production`
βββββββββββββββββββββββ
**A pull request has been opened with the following tickets:**
β’ Improve bill due_date logic (DEV-8139)
β’ New endpoint to get organization parent company defaults (DEV-8281)
β’ Add onboarding checklist visibility endpoints (DEV-8282)
View Pull Request
π Tickets Released
Application: `backend`
Environment: `production`
βββββββββββββββββββββββ
**The following tickets have been released:**
β’ Improve bill due_date logic (DEV-8139)
β’ New endpoint to get organization parent company defaults (DEV-8281)
β’ Add onboarding checklist visibility endpoints (DEV-8282)
β
CODEOWNERS gate satisfied
PR #123 β feat: add new feature
Base: `main` Head: `abc1234...`
Approved by: `reviewer-username`
Behavior notes:
- Only triggers when the
reviewDecisionbecomesAPPROVED(i.e., all required CODEOWNERS have approved) - De-duplicates per head SHA: if you push new commits and get re-approved, it will notify again
- Adds a hidden marker comment to track which SHA was notified
The repository includes three main scripts:
Extracts Linear ticket IDs from git commits between two refs.
./extract-tickets.sh <base-ref> <head-ref>
# Returns: ["DEV-123", "ACC-456"]
Sends formatted Slack notifications with ticket information.
./notify-slack.sh <event-type> <tickets-json>
# event-type: "pr_opened" or "pr_merged"
Updates Linear ticket status to "Done".
./update-linear-status.sh <tickets-json>
You can test the scripts locally:
# Set required environment variables
export LINEAR_API_KEY="your-key"
export SLACK_RELEASE_CHANGELOG_WEBHOOK="your-webhook"
export REPOSITORY_NAME="test-repo"
export ENVIRONMENT="dev"
# Test ticket extraction
cd .github/scripts
./extract-tickets.sh origin/dev origin/main
# Test Slack notification (requires extracted tickets)
./notify-slack.sh pr_opened '["DEV-123","ACC-456"]'
# Test Linear status update
./update-linear-status.sh '["DEV-123","ACC-456"]'
- Ensure commit messages or PR titles contain ticket IDs in the correct format
- Check that the base branch comparison is correct
- Verify git refs are properly fetched
- Verify
SLACK_RELEASE_CHANGELOG_WEBHOOKis correctly configured - Check webhook URL is valid and accessible
- Ensure Slack app has permission to post to the channel
- Verify
LINEAR_API_KEYhas permission to update issues - Check that "Done" workflow state exists in your Linear workspace
- Ensure ticket IDs are valid and accessible
- Make sure scripts are executable:
chmod +x .github/scripts/*.sh - The workflows automatically set execute permissions, but manual runs may require this
Internal use only - DualEntry organization.