A GitHub Action that enforces multi-owner mandatory approvals on Pull Requests, ensuring that ALL relevant code owners approve changes before merging. Unlike GitHub's native CODEOWNERS which may allow merging with only one approval, this bot ensures every required owner group has at least one approval.
GitHub's native CODEOWNERS functionality falls short when multiple file types are modified in a single PR. For example:
- PR modifies both
.jsfiles (owned by@frontend-team) and.mdfiles (owned by@docs-team) - GitHub requests reviews from both teams but may allow merging with only one approval
- This bot ensures BOTH
@frontend-teamAND@docs-teammust approve before merging
- π Multi-owner enforcement: Requires ALL relevant code owner groups to approve
- π GitHub CODEOWNERS support: Works with your existing
.github/CODEOWNERSfile - π Team and user support: Handles both
@usernameand@org/team-namepatterns - π¬ Clear PR comments: Shows approval status with checkboxes and file listings
- β Status checks: Creates GitHub status checks that block merging until approved
- π Performance optimized: Caching and pagination for large repositories
- π§ Fail-safe: Defaults to blocking merge if any errors occur
- π Detailed reporting: Shows which files require which owners
- Create
.github/workflows/code-owners-bot.ymlin your repository:
name: 'Code Owners Approval Bot'
on:
pull_request:
types: [opened, synchronize, ready_for_review]
pull_request_review:
types: [submitted, dismissed]
permissions:
contents: read
pull-requests: write
checks: write
issues: write
jobs:
code-owners-check:
name: 'Check Code Owners Approvals'
runs-on: ubuntu-latest
steps:
- uses: tmbtech/multi-codeowners@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}- Clone this repository
- Install dependencies:
yarn install - Build:
yarn build - Run locally:
yarn dev
The bot requires the following GitHub permissions:
contents: read- Read repository content and CODEOWNERS filepull-requests: write- Create and update PR commentschecks: write- Create and update status checksissues: write- Create PR comments (PRs are issues in GitHub API)
Create a .github/CODEOWNERS file in your repository:
# Global owners
* @global-team
# Frontend files
*.js @frontend-team
*.ts @frontend-team
*.tsx @frontend-team
# Backend files
*.py @backend-team
*.go @backend-team
# Documentation
*.md @docs-team
/docs/ @docs-team
# Configuration
*.json @devops-team @security-team
*.yml @devops-team
# Multiple owners for critical files
package.json @frontend-team @devops-team @security-team
- Trigger: Runs on PR events (opened, synchronize, review submitted)
- Analysis: Parses CODEOWNERS and identifies changed files
- Mapping: Maps changed files to required owner groups
- Approval Check: Checks if all required owner groups have approved
- Reporting: Updates GitHub status check and PR comment
- Enforcement: Blocks merge if any required approvals are missing
PR changes these files:
src/app.js(requires@frontend-team)README.md(requires@docs-team)package.json(requires@frontend-teamAND@devops-team)
Required approvals: @frontend-team, @docs-team, @devops-team
Result: PR can only merge when at least one member from each team approves.
## π₯ Code Owners Approval Status
β³ **2/3 required code owner groups have approved.**
### Required Approvals:
- [x] **@frontend-team** (approved by @alice)
- `src/app.js`
- `package.json`
- [x] **@docs-team** (approved by @bob)
- `README.md`
- [ ] **@devops-team** (pending)
- `package.json`
---
*This comment is automatically updated by the Dynamic Code Owners Reviewer Bot*Bot shows "pending" but team member approved
- Check if the reviewer is actually a member of the GitHub team
- Ensure team membership is public or bot has org access
- Individual users (
@username) don't require team membership
Status check not appearing
- Verify the bot has
checks: writepermission - Check GitHub Actions logs for errors
- Ensure the workflow runs on the correct PR events
CODEOWNERS not found
- File must be in
.github/CODEOWNERS,CODEOWNERS, or.CODEOWNERS - Check file syntax with GitHub's CODEOWNERS validator
- Ensure file exists in the base branch
Enable debug logging by adding to your workflow:
env:
ACTIONS_STEP_DEBUG: trueAdd a condition to skip certain PRs:
jobs:
code-owners-check:
if: >-
github.actor != 'dependabot[bot]' &&
!contains(github.event.pull_request.labels.*.name, 'skip-owners')Configure branch protection to require the status check:
- Go to Settings β Branches
- Add rule for your main branch
- Enable "Require status checks to pass before merging"
- Select "code-owners-approval" check
This repository includes three example workflow files that demonstrate different use cases:
Purpose: Comprehensive testing with multiple scenarios
- Matrix testing: Tests different file change scenarios (docs-only, config-only, source-only, etc.)
- Debug logging: Enabled by default with
ACTIONS_STEP_DEBUG: true - Artifacts: Saves action outputs (
result,required_owners,missing_approvals) for each scenario - Summary reports: Generates detailed test summaries in GitHub Actions UI
How to use:
- Automatically runs on PR events
- Check the "Artifacts" section of workflow runs to download test results
- Look at the "Summary" tab for scenario explanations and results table
Purpose: Copy-paste template for other repositories
- Comprehensive comments: Every configuration option is explained
- Best practices: Shows recommended permissions, triggers, and conditions
- Example CODEOWNERS: Includes a complete example CODEOWNERS file in comments
- Troubleshooting guide: Built-in documentation for common issues
How to use:
- Copy this file to your repository as
.github/workflows/codeowners-enforcement.yml - Change the
uses: ./line touses: delavrx1/multi-codeowners@v1 - Customize triggers, permissions, and conditions as needed
- Create a CODEOWNERS file in your repository
π demo-scenarios.yml
Purpose: Interactive demonstrations and testing
- Multiple scenarios: Tests different CODEOWNERS patterns in separate jobs
- Manual triggers: Use
workflow_dispatchto test specific scenarios - Live examples: Each job creates a temporary CODEOWNERS file to demonstrate patterns
- Educational: Shows multi-owner, single-owner, no-owner, and mixed-ownership scenarios
How to use:
- Go to Actions β "Code Owners Demo Scenarios" β "Run workflow"
- Select which scenario to run (or "all" for comprehensive testing)
- Check the job summaries for detailed explanations of each pattern
Action Outputs:
result:"success"or"failure"- overall approval statusrequired_owners: JSON array of all owner groups that need approvalmissing_approvals: JSON array of owner groups still waiting for approval
Artifacts (from test-codeowners-enforcement.yml):
test-results-{scenario}/result.txt: Pass/fail status for each scenariotest-results-{scenario}/required_owners.json: Required owners for that scenariotest-results-{scenario}/missing_approvals.json: Missing approvals for that scenario
GitHub Action Logs:
- Enable
ACTIONS_STEP_DEBUG: truefor verbose logging - Look for "Code Owners Bot" step logs for detailed file mapping
- Check status check details in PR for approval breakdown
yarn test # Run all tests
yarn test:watch # Run tests in watch mode
yarn lint # Lint code
yarn build # Build actionsrc/
βββ index.ts # Main entry point
βββ bot.ts # Main bot orchestrator
βββ codeowners.ts # CODEOWNERS parsing logic
βββ changed-files.ts # PR file change detection
βββ owner-mapping.ts # File to owner mapping
βββ approval-checker.ts # Approval status checking
βββ reporter.ts # GitHub status & comment reporting
βββ __tests__/ # Unit tests
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make changes and add tests
- Run tests:
yarn test - Commit changes:
git commit -m 'Add amazing feature' - Push to branch:
git push origin feature/amazing-feature - Open a Pull Request
MIT License - see LICENSE file for details.
- GitHub's CODEOWNERS documentation
- GitHub Actions ecosystem
- Contributors and users of this action
Need help? Open an issue or check the documentation.