Skip to content

Instantly share code, notes, and snippets.

@ideepu
Last active May 29, 2026 11:50
Show Gist options
  • Select an option

  • Save ideepu/dcd72b05bc6e82c74f5ef5374bc94055 to your computer and use it in GitHub Desktop.

Select an option

Save ideepu/dcd72b05bc6e82c74f5ef5374bc94055 to your computer and use it in GitHub Desktop.
GIthub PR Merge Queue
function MergeQueue(WEBHOOK_URL, KVDB_URL) {
'use strict';
// Extract PR details safely from URL and DOM
const getPRDetails = () => {
const pathParts = window.location.pathname.split('/');
const repo = `${pathParts[1]}/${pathParts[2]}`;
const prId = pathParts[4] || "0000";
const title = document.querySelector('.js-issue-title')?.innerText.trim() || "Unknown Title";
const author = document.querySelector('.author')?.innerText.trim() || "Unknown Author";
const link = window.location.href;
return { id: `${repo}#${prId}`, prId, repo, title, author, link };
};
const sendToSlack = (textBlock) => {
GM_xmlhttpRequest({
method: "POST",
url: WEBHOOK_URL,
headers: { "Content-Type": "application/json" },
data: JSON.stringify({ text: textBlock })
});
};
const saveCloudQueue = (queueArray, callback) => {
GM_xmlhttpRequest({
method: "POST",
url: KVDB_URL,
headers: { "Content-Type": "application/json" },
data: JSON.stringify(queueArray),
onload: () => { if (callback) callback(); }
});
};
const fetchCloudQueue = (callback) => {
GM_xmlhttpRequest({
method: "GET",
url: KVDB_URL,
headers: { "Content-Type": "application/json" },
onload: (response) => {
if (response.status === 200) {
try { callback(JSON.parse(response.responseText) || []); } catch (e) { callback([]); }
} else { callback([]); }
},
onerror: () => callback([])
});
};
const broadcastQueueState = (headerText) => {
fetchCloudQueue((currentQueue) => {
let message = `*${headerText}*\n`;
if (currentQueue.length === 0) {
message += "πŸ“­ The shared queue is completely empty.";
} else {
message += "*Current Shared Queue Status:*\n";
currentQueue.forEach((pr, index) => {
message += `${index + 1}. *[${pr.id}]* <${pr.link}|${pr.title}> - Added by: @${pr.author}\n`;
});
}
sendToSlack(message);
});
};
const addToQueue = () => {
const currentPR = getPRDetails();
fetchCloudQueue((queue) => {
if (queue.some(pr => pr.id === currentPR.id)) {
alert("This PR is already inside the shared queue!");
return;
}
queue.push(currentPR);
saveCloudQueue(queue, () => {
sendToSlack(`πŸ“₯ *PR Added to Global Queue (Position #${queue.length})*\n*PR:* <${currentPR.link}|${currentPR.title}>\n*Creator:* @${currentPR.author}`);
renderUIElements();
});
});
};
const removeFromQueue = () => {
const currentPR = getPRDetails();
fetchCloudQueue((queue) => {
const updated = queue.filter(pr => pr.id !== currentPR.id);
saveCloudQueue(updated, () => {
broadcastQueueState(`πŸ—‘οΈ *PR manually removed from queue: [${currentPR.id}]*`);
renderUIElements();
});
});
};
const clearEntireQueue = () => {
if (!confirm("⚠️ Clear the ENTIRE shared team queue?")) return;
if (!confirm("πŸ”₯ Are you absolutely sure? This affects all team members.")) return;
saveCloudQueue([], () => {
broadcastQueueState(`πŸ’₯ *The global PR queue was completely wiped clean by a team member.*`);
renderUIElements();
});
};
// Renders the queue management panel inside the safe GitHub page footer
const renderUIElements = () => {
// Only run on pull request pages
if (!window.location.pathname.includes('/pull/')) {
document.getElementById('pr-footer-queue-panel')?.remove();
return;
}
// Target the standard, global GitHub footer wrapper element
const pageFooter = document.querySelector('footer') || document.querySelector('.footer');
if (!pageFooter) return;
fetchCloudQueue((queue) => {
// Clean up any older twins to avoid rendering loops
document.getElementById('pr-footer-queue-panel')?.remove();
const currentPR = getPRDetails();
const isInQueue = queue.some(pr => pr.id === currentPR.id);
// Create a clean, centered container block inside the footer layout
const panel = document.createElement('div');
panel.id = 'pr-footer-queue-panel';
panel.style.width = '100%';
panel.style.maxWidth = '600px';
panel.style.margin = '20px auto 10px auto';
panel.style.padding = '16px';
panel.style.backgroundColor = '#161b22';
panel.style.border = '1px solid #30363d';
panel.style.borderRadius = '8px';
panel.style.display = 'flex';
panel.style.flexDirection = 'column';
panel.style.gap = '10px';
panel.style.textAlign = 'center';
panel.style.boxShadow = '0 2px 8px rgba(0,0,0,0.2)';
// Header layout text
const title = document.createElement('div');
title.innerText = "πŸ“‹ Team Shared Pull Request Merge Queue Manager";
title.style.color = '#c9d1d9';
title.style.fontSize = '13px';
title.style.fontWeight = 'bold';
panel.appendChild(title);
// Flex-row container for holding the action buttons neatly side-by-side
const row = document.createElement('div');
row.style.display = 'flex';
row.style.justifyContent = 'center';
row.style.gap = '8px';
// Primary Queue Action Button (Add or Remove)
const actionBtn = document.createElement('button');
actionBtn.style.padding = '6px 12px';
actionBtn.style.borderRadius = '6px';
actionBtn.style.border = '1px solid #f0f6fc1a';
actionBtn.style.fontWeight = '600';
actionBtn.style.fontSize = '12px';
actionBtn.style.cursor = 'pointer';
if (isInQueue) {
actionBtn.innerText = "❌ Remove PR From Queue";
actionBtn.style.backgroundColor = '#da3633';
actionBtn.style.color = '#ffffff';
} else {
actionBtn.innerText = "πŸ“₯ Add This PR to Queue";
actionBtn.style.backgroundColor = '#238636';
actionBtn.style.color = '#ffffff';
}
actionBtn.onclick = isInQueue ? removeFromQueue : addToQueue;
row.appendChild(actionBtn);
// Safe Clear Queue Button (Rendered only if active items populate the cloud)
if (queue.length > 0) {
const clearBtn = document.createElement('button');
clearBtn.innerText = `🧹 Clear Entire Queue (${queue.length})`;
clearBtn.style.padding = '6px 12px';
clearBtn.style.borderRadius = '6px';
clearBtn.style.border = '1px solid #f0f6fc1a';
clearBtn.style.backgroundColor = '#21262d';
clearBtn.style.color = '#c9d1d9';
clearBtn.style.fontWeight = '600';
clearBtn.style.fontSize = '12px';
clearBtn.style.cursor = 'pointer';
clearBtn.onclick = clearEntireQueue;
row.appendChild(clearBtn);
}
panel.appendChild(row);
// Append it natively right into the footer element zone
pageFooter.appendChild(panel);
});
};
let greenStateNotified = false;
const runQueueMonitorEngine = () => {
if (!window.location.pathname.includes('/pull/')) return;
fetchCloudQueue((queue) => {
if (queue.length === 0) return;
const currentPR = getPRDetails();
const topOfQueue = queue[0];
const isMergedBadgeVisible = document.querySelector('[data-status="pullMerged"]');
if (currentPR.id === topOfQueue.id && isMergedBadgeVisible) {
const updatedQueue = queue.filter(pr => pr.id !== currentPR.id);
saveCloudQueue(updatedQueue, () => {
greenStateNotified = false;
broadcastQueueState(`βœ… *PR [${currentPR.id}] has been merged!*`);
renderUIElements();
});
return;
}
if (currentPR.id === topOfQueue.id) {
const mergeButton = document.querySelector('.merge-box-button-merging');
const isButtonGreen = mergeButton && !mergeButton.disabled;
if (isButtonGreen && !greenStateNotified) {
greenStateNotified = true;
sendToSlack(`🟒 *Top of Queue is Ready to Merge!*\nPR <${topOfQueue.link}|${topOfQueue.id}> is now green. Ready for impact!`);
} else if (!isButtonGreen) {
greenStateNotified = false;
}
}
});
};
const runEngineWithLayoutCheck = () => {
renderUIElements();
runQueueMonitorEngine();
};
const init = () => {
renderUIElements();
setInterval(runEngineWithLayoutCheck, 4000);
};
if (document.readyState === 'complete') {init();} else {window.addEventListener('load', init);}document.addEventListener('turbo:render', init);document.addEventListener('ghmo:container', init);}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment