Monday Branch Status Tracking - Implementation Plan
Overview
This document outlines the implementation plan for automatic Monday.com status updates based on which Git branch a commit resides in. As code moves through the development pipeline (development → main → production), Monday tasks will automatically update their status.
Current State
Currently, the integration handles:
- PR opened → Status set to "Code Review"
- PR merged to development → Status set to "Deployed to Dev"
Proposed Enhancement
Extend the integration to track commits as they flow through all branches:
Branch → Status Mapping
| Branch | Trigger | Monday Status | Description |
|---|---|---|---|
development | PR merged | Deployed to Dev | Code deployed to dev environment, ready for dev testing |
main | Push/merge | Ready for Testing | Code on staging, ready for QA (Stephanie) |
production | Push/merge | Done | Code is live in production |
Technical Implementation
How GitHub Push Events Work
When code is pushed to any branch, GitHub sends a webhook with:
{
"ref": "refs/heads/main",
"before": "abc123...", // Previous HEAD
"after": "def456...", // New HEAD
"commits": [...] // Only direct commits, not merge history
}
The Challenge: Finding All Commits in a Merge
When you merge development into main, the push event only shows the merge commit, not all the individual commits that were in development. We need to find all commits that were added.
Solution: GitHub Compare API
Use the GitHub Compare API to get all commits between two SHAs:
GET /repos/{owner}/{repo}/compare/{before}...{after}
Response includes:
{
"commits": [
{
"sha": "abc123",
"commit": {
"message": "Fix bug\n\nhttps://pivotapp.monday.com/boards/123/pulses/456"
}
},
// ... all commits in the range
]
}
Implementation Flow
Code Changes Required
1. New Handler: handleBranchPush
Location: pivot-kpi/lib/github/push-handlers.ts
interface BranchStatusMapping {
branch: string;
statusType: 'readyForTesting' | 'done';
}
const BRANCH_STATUS_MAP: BranchStatusMapping[] = [
{ branch: 'main', statusType: 'readyForTesting' },
{ branch: 'production', statusType: 'done' },
];
async function handleBranchPush(payload: GitHubPushPayload) {
const branch = payload.ref.replace('refs/heads/', '');
const mapping = BRANCH_STATUS_MAP.find(m => m.branch === branch);
if (!mapping) return; // Not a tracked branch
// Get all commits in the push range
const commits = await getCommitRange(
payload.repository.full_name,
payload.before,
payload.after
);
// Extract all Monday task IDs
const taskIds = new Set<string>();
for (const commit of commits) {
const ids = extractMondayTaskIds(commit.message);
ids.forEach(id => taskIds.add(id));
}
// Update each task's status
for (const taskId of taskIds) {
await updateItemStatus(taskId, mapping.statusType);
}
}
2. GitHub Compare API Helper
Location: pivot-kpi/lib/github/api.ts
async function getCommitRange(
repo: string,
before: string,
after: string
): Promise<CommitInfo[]> {
const response = await fetch(
`https://api.github.com/repos/${repo}/compare/${before}...${after}`,
{
headers: {
'Authorization': `token ${process.env.GITHUB_TOKEN}`,
'Accept': 'application/vnd.github.v3+json',
},
}
);
const data = await response.json();
return data.commits.map(c => ({
sha: c.sha,
message: c.commit.message,
// ... other fields
}));
}
3. Update Monday Client Status Labels
Location: pivot-kpi/lib/monday/client.ts
Add new status labels to the configuration:
const TASK_STATUS_CONFIG = {
statusColumnId: 'status9',
statusLabels: {
codeReview: 'Code review',
deployedToDev: 'Deployed to Dev',
readyForTesting: 'Ready for Testing', // NEW
done: 'Done', // NEW
},
};
const SUBTASK_STATUS_CONFIG = {
statusColumnId: 'status',
statusLabels: {
codeReview: 'Code Review',
deployedToDev: 'Deployed to Dev',
readyForTesting: 'Ready for Testing', // NEW
done: 'Done', // NEW
},
};
4. Update Webhook Router
Location: pivot-kpi/app/api/webhooks/github/route.ts
// Add handling for push events to main/production
if (event === 'push') {
const branch = payload.ref.replace('refs/heads/', '');
if (branch === 'main' || branch === 'production') {
const results = await handleBranchPush(payload);
return NextResponse.json({
message: `Processed push to ${branch}`,
results
});
}
}
Edge Cases to Handle
1. Squashed Commits
When PRs are squash-merged, all commit messages are combined. The Monday links should still be in the squashed commit message.
Solution: The extractMondayTaskIds function already handles this - it extracts all Monday URLs from the entire commit message.
2. Force Pushes
Force pushes can rewrite history. The before SHA might not be an ancestor of after.
Solution: Wrap the compare API call in a try-catch. If it fails, skip processing for that push.
3. Direct Pushes to Main/Production
Commits pushed directly (not via PR) should still trigger status updates.
Solution: The push handler processes all commits in the range, regardless of how they got there.
4. Duplicate Updates
The same commit might be pushed multiple times (e.g., during rebases).
Solution: Monday's status column is idempotent - setting it to the same value has no effect. No special handling needed.
5. Reverted Commits
If a commit is reverted, should the status change back?
Decision needed: Initially, no. Status only moves forward. Reverts are manual process decisions.
Testing Plan
Phase 1: Local Testing
- Set up ngrok to receive webhook events
- Create test branches and merge PRs
- Verify Monday status updates correctly
Phase 2: Staging Deployment
- Deploy to pivot-kpi staging
- Test with real pivot repository
- Monitor for edge cases
Phase 3: Production Rollout
- Deploy to production
- Monitor first few merges
- Document any issues
Rollout Strategy
Step 1: Main Branch Only
Start by only handling pushes to main:
- Lower risk - only affects staging status
- Easier to test and validate
Step 2: Add Production Branch
Once main is stable, add production handling:
- Final piece of the automation
- Completes the full workflow
Success Metrics
- 100% of Monday tasks auto-update when code reaches staging
- 100% of Monday tasks auto-update when code reaches production
- Zero manual status updates needed in normal workflow
- < 30 seconds from push to status update
Timeline
| Phase | Description | Status |
|---|---|---|
| Phase 1 | PR opened → Code Review | ✅ Complete |
| Phase 2 | PR merged → Deployed to Dev | ✅ Complete |
| Phase 3 | Push to main → Deployed to non-production | ✅ Complete |
| Phase 4 | Push to production → Deployed to production | ✅ Complete |
Note (Jan 2026): Phases 3 and 4 were implemented using the GitHub Compare API to handle merge commits correctly. When merging branches, the push event only contains the merge commit - the Compare API fetches all individual commits that were added, ensuring Monday task IDs are extracted from all commits, not just the merge commit.
Dependencies
- GitHub Personal Access Token with
reposcope (for Compare API) - Monday API token (already configured)
- Webhook already receiving push events
Related Documentation
- Monday-GitHub Integration - Current integration docs
- Monday-GitHub Integration Implementation - Technical details
- Monday Workflow - Overall workflow documentation