Skip to main content

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

BranchTriggerMonday StatusDescription
developmentPR mergedDeployed to DevCode deployed to dev environment, ready for dev testing
mainPush/mergeReady for TestingCode on staging, ready for QA (Stephanie)
productionPush/mergeDoneCode 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

  1. Set up ngrok to receive webhook events
  2. Create test branches and merge PRs
  3. Verify Monday status updates correctly

Phase 2: Staging Deployment

  1. Deploy to pivot-kpi staging
  2. Test with real pivot repository
  3. Monitor for edge cases

Phase 3: Production Rollout

  1. Deploy to production
  2. Monitor first few merges
  3. 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

PhaseDescriptionStatus
Phase 1PR opened → Code Review✅ Complete
Phase 2PR merged → Deployed to Dev✅ Complete
Phase 3Push to main → Deployed to non-production✅ Complete
Phase 4Push 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 repo scope (for Compare API)
  • Monday API token (already configured)
  • Webhook already receiving push events