Last active
October 11, 2021 12:28
-
-
Save dscho/585172971f0989ed340a563bbacc6cad to your computer and use it in GitHub Desktop.
Trigger GitHub workflow_dispatch from the blob view of the workflow file
This file contains 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 Trigger workflow_dispatch from the blob view of the workflow file | |
// @source https://gist.github.com/dscho/585172971f0989ed340a563bbacc6cad | |
// @updateURL https://gist.github.com/dscho/585172971f0989ed340a563bbacc6cad/raw/workflow_dispatch-from-blob.user.js | |
// @downloadURL https://gist.github.com/dscho/585172971f0989ed340a563bbacc6cad/raw/workflow_dispatch-from-blob.user.js | |
// @namespace http://tampermonkey.net/ | |
// @version 0.1 | |
// @description Trigger a workflow from the blob view of the workflow file | |
// @author Johannes Schindelin | |
// @match https://github.com/*/blob/*/.github/workflows/*.yml | |
// @icon https://www.google.com/s2/favicons?domain=github.com | |
// @grant GM_addElement | |
// @grant GM.xmlHttpRequest | |
// @grant GM_getValue | |
// @grant GM_setValue | |
// @connect raw.githubusercontent.com | |
// @connect api.github.com | |
// @require https://ajax.googleapis.com/ajax/libs/jquery/3.5.0/jquery.min.js | |
// @require https://raw.githubusercontent.com/nodeca/js-yaml/master/dist/js-yaml.min.js | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
const match = window.location.toString().match(/^(https:\/\/github\.com\/([^/]+\/[^/]+)\/)blob(\/(.*)\/\.github\/workflows\/([^/]+\.yml))$/) | |
if (!match) return; | |
const ownerRepo = match[2]; | |
const ref = match[4]; | |
const filename = match[5]; | |
const addButton = (innerHTML, callback) => { | |
const button = GM_addElement(document.getElementById('blob-path').parentElement, 'a', { | |
class: "btn mr-2 d-none d-md-block" | |
}); | |
button.innerHTML = innerHTML; | |
button.onclick = callback; | |
return button; | |
}; | |
const handleYAML = (yaml) => { | |
const parsed = jsyaml.load(yaml); | |
document.myParsed = parsed; | |
if (parsed?.on?.workflow_dispatch === undefined) return; | |
let button; | |
let formDiv; | |
button = addButton("Run workflow", () => { | |
button.onclick = undefined; | |
const div = GM_addElement(button, 'div', { | |
id: "workflow-popover", | |
class: "Popover position-relative position-absolute Popover-message Popover-message--large Popover-message--top-right mt-2 right-0 text-left p-3 mx-auto Box color-shadow-large" | |
}); | |
button.onclick = (e) => { | |
if (e.target !== button) return; | |
e.stopPropagation(); | |
div.style.display = (div.style.display === 'none' ? '' : 'none'); | |
}; | |
for (const [label, input] of Object.entries(parsed.on.workflow_dispatch?.inputs || {})) { | |
const group = GM_addElement(div, 'div', { | |
class: "form-group mt-1 mb-2" | |
}); | |
const groupHeader = GM_addElement(group, 'div', { | |
class: "form-group-header" | |
}); | |
GM_addElement(groupHeader, 'label', { | |
class: "color-text-primary text-mono f6" | |
}).innerHTML = input.description || label; | |
const groupBody = GM_addElement(group, 'div', { | |
class: "form-group-body" | |
}); | |
const inputElement = GM_addElement(groupBody, 'input', { | |
class: "form-control input-contrast input-sm", | |
type: "text", | |
name: `inputs[${label}]`, | |
value: input.default | |
}); | |
input.inputElement = inputElement; | |
} | |
let pat | |
let token = GM_getValue('gh-token'); | |
if (token === undefined) { | |
GM_addElement(div, 'label', { | |
class: "color-text-primary text-mono f6" | |
}).innerHTML = "PAT"; | |
pat = GM_addElement(div, 'input', { | |
class: "form-control input-contrast input-sm", | |
type: "password", | |
name: "PAT" | |
}); | |
} | |
const runButton = GM_addElement(div, 'button', { | |
type: "submit", | |
class: "btn btn-primary btn-sm mt-2", | |
autofocus: "" | |
}); | |
runButton.innerHTML = "Run workflow"; | |
const onclick = () => { | |
runButton.onclick = undefined; | |
if (token === undefined) { | |
if (!pat.value) { | |
runButton.onclick = onclick; | |
pat.focus(); | |
return; | |
} | |
pat.style.display = 'none'; | |
pat.previousSibling.style.display = 'none'; | |
token = pat.value; | |
pat.value = ''; | |
GM_setValue('gh-token', token); | |
} | |
runButton.innerHTML = "<i>Starting</i>"; | |
const triggerURL = `https://api.github.com/repos/${ownerRepo}/actions/workflows/${filename}/dispatches`; | |
const triggerBody = { ref: ref, inputs: {} }; | |
for (const [label, input] of Object.entries(parsed.on.workflow_dispatch?.inputs || {})) { | |
triggerBody.inputs[label] = input.inputElement.value; | |
} | |
GM.xmlHttpRequest({ | |
url: triggerURL, | |
method: 'POST', | |
data: JSON.stringify(triggerBody), | |
headers: { | |
accept: "application/vnd.github.v3+json" | |
}, | |
headers: { | |
Authorization: `token ${token}` | |
}, | |
onload: (data) => { | |
div.style.display = 'none'; | |
const workflowsURL = `https://github.com/${ownerRepo}/actions/workflows/${filename}?query=branch%3A${encodeURIComponent(ref)}`; | |
window.location = workflowsURL; | |
}, | |
onerror: (data) => { | |
console.log(data); | |
alert("Error!"); | |
runButton.onclick = onclick; | |
runButton.innerHTML = "Run workflow"; | |
} | |
}); | |
}; | |
runButton.onclick = onclick; | |
}); | |
}; | |
const rawURL = `https://raw.githubusercontent.com/${ownerRepo}/${match[3]}`; | |
// console.log(`${match[1]}raw${match[3]}`); | |
GM.xmlHttpRequest({ | |
url: rawURL, | |
headers: { | |
accept: "text/plain", | |
}, | |
onload: (data) => { | |
if (data.status === 200) | |
handleYAML(data.response); | |
else if (data.status === 404) { | |
const token = GM_getValue('gh-token'); | |
if (!token) | |
console.log("Private repository? Have no token to play with..."); | |
else { | |
console.log("Private repository? Try again with token..."); | |
GM.xmlHttpRequest({ | |
url: rawURL, | |
headers: { | |
Accept: "text/plain", | |
Authorization: `token ${token}` | |
}, | |
onload: (data) => { | |
if (data.status === 200) | |
handleYAML(data.response); | |
else { | |
console.log(`Failed to retrieve ${rawURL} from private repository`); | |
console.log(data); | |
} | |
}, | |
onerror: (data) => { | |
console.log(`Failed to retrieve ${rawURL}`); | |
console.log(data); | |
} | |
}); | |
} | |
return; | |
} else { | |
console.log(`Unhandled status ${data.status} when retrieving ${rawURL}`); | |
console.log(data); | |
} | |
}, | |
onerror: (data) => { | |
console.log(`Failed to retrieve ${rawURL}`); | |
console.log(data); | |
} | |
}); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment