Last active
May 29, 2026 11:50
-
-
Save ideepu/dcd72b05bc6e82c74f5ef5374bc94055 to your computer and use it in GitHub Desktop.
GIthub PR Merge Queue
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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