Last active
April 24, 2025 16:46
-
-
Save escherize/daeda2467ee60e5255a4c24212041036 to your computer and use it in GitHub Desktop.
violent monkey script for ci rerun
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
// ==UserScript== | |
// @name GitHub Rerun Failed Jobs (Manual Trigger + Watcher) @escherize | |
// @namespace http://tampermonkey.net/ | |
// @version 0.7 | |
// @description Manually trigger a watcher to auto re-run failed GitHub Actions jobs | |
// @match https://github.com/*/*/actions/runs/** | |
// @grant none | |
// ==/UserScript== | |
(function () { | |
'use strict'; | |
const waitForTextButton = (text, timeout = 60000) => new Promise((resolve, reject) => { | |
const interval = 300; | |
const maxTries = timeout / interval; | |
let tries = 0; | |
const timer = setInterval(() => { | |
const btn = Array.from(document.querySelectorAll('span')) | |
.find(el => el.textContent.trim() === text); | |
if (btn) { | |
clearInterval(timer); | |
resolve(btn); | |
} else if (++tries > maxTries) { | |
clearInterval(timer); | |
reject(`Timeout waiting for button: ${text}`); | |
} | |
}, interval); | |
}); | |
const tryRerun = async () => { | |
console.log('[ManualRerun] Waiting for "Re-run jobs"...'); | |
const rerunButton = await waitForTextButton('Re-run jobs'); | |
console.log('[ManualRerun] Clicking dropdown...'); | |
rerunButton.click(); | |
console.log('[ManualRerun] Waiting for "Re-run failed jobs"...'); | |
const failedJobsBtn = await waitForTextButton('Re-run failed jobs'); | |
failedJobsBtn.click(); | |
setTimeout(() => { | |
const buttons = Array.from(document.querySelectorAll('button')) | |
.filter(btn => btn.textContent.trim() === 'Re-run jobs') | |
.reverse(); | |
console.log(`[ManualRerun] Clicking ${buttons.length} "Re-run jobs" buttons...`); | |
buttons.forEach(btn => btn.click()); | |
}, 1000); | |
}; | |
let observer; | |
const startWatcher = () => { | |
if (observer) { | |
console.log('[ManualRerun] Watcher already active.'); | |
return; | |
} | |
triggerButton.textContent = '👀 Watching for Re-run...'; | |
observer = new MutationObserver(() => { | |
const found = Array.from(document.querySelectorAll('button')) | |
.some(btn => btn.textContent.trim() === 'Re-run jobs'); | |
if (found) { | |
observer.disconnect(); | |
observer = null; | |
triggerButton.textContent = '✅ Re-run Triggered!'; | |
tryRerun().catch(err => { | |
console.error('[ManualRerun] Failed:', err); | |
triggerButton.textContent = '❌ Re-run Failed'; | |
}); | |
} | |
}); | |
observer.observe(document.body, { childList: true, subtree: true }); | |
console.log('[ManualRerun] Watcher started...'); | |
}; | |
const triggerButton = document.createElement('button'); | |
triggerButton.textContent = '▶️ Start Re-run Watcher'; | |
triggerButton.style.position = 'fixed'; | |
triggerButton.style.top = '10px'; | |
triggerButton.style.right = '10px'; | |
triggerButton.style.zIndex = 9999; | |
triggerButton.style.padding = '8px 12px'; | |
triggerButton.style.fontSize = '14px'; | |
triggerButton.style.background = '#0366d6'; | |
triggerButton.style.color = 'white'; | |
triggerButton.style.border = 'none'; | |
triggerButton.style.borderRadius = '6px'; | |
triggerButton.style.cursor = 'pointer'; | |
document.body.appendChild(triggerButton); | |
triggerButton.addEventListener('click', startWatcher); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment