Instantly share code, notes, and snippets.
Last active
July 9, 2021 18:22
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save KerberosMorphy/a6b9cbc472aa1a3d2310245d460476b9 to your computer and use it in GitHub Desktop.
Bitbucket PR commits navigation
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 Bitbucket PR commits navigation | |
// @namespace https://github.com/KerberosMorphy | |
// @source https://gist.github.com/KerberosMorphy/a6b9cbc472aa1a3d2310245d460476b9 | |
// @version 0.1 | |
// @description Bitbucket PR commits navigation | |
// @author Benoit Verret | |
// @match https://bitbucket.dimonoff.com/projects/*/repos/*/pull-requests/*/diff | |
// @match https://bitbucket.dimonoff.com/projects/*/repos/*/pull-requests/*/commits/* | |
// @icon https://www.google.com/s2/favicons?domain=dimonoff.com | |
// @grant GM_xmlhttpRequest | |
// @grant GM_addStyle | |
// @require https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js | |
// @connect bitbucket.dimonoff.com | |
// ==/UserScript== | |
/* global $ */ | |
// FIXME: Lorsqu'on change de commit via le menu déroulant, les boutons ne sont pas actualisé car la page n'est pas rechargé | |
// Possible fix: https://stackoverflow.com/questions/8281441/fire-greasemonkey-script-on-ajax-request/8283815#8283815 | |
const currentURL = new URL(window.location.href) | |
const commitsRequestURL = `https://${currentURL.host}/rest/api/1.0${currentURL.pathname.match(/(?<base>.*pull-requests\/\d{1,4}).*/).groups.base}/commits?limit=100`; | |
const commitsBaseURL = `${currentURL.pathname.match(/(?<base>.*pull-requests\/\d{1,4}).*/).groups.base}/commits/`; | |
fetch (commitsRequestURL) | |
.then(response => response.json()) | |
.then(processJSON_Response) | |
.catch(error => console.error(error)); | |
function getFirstCommitsURL(currentCommit, commits) { | |
return currentCommit == commits[commits.length-1].id ? false : `${commitsBaseURL}${commits[commits.length-1].id}`; | |
} | |
function getLastCommitsURL(currentCommit, commits) { | |
return currentCommit == commits[0].id ? false : `${commitsBaseURL}${commits[0].id}`; | |
} | |
function getPreviousCommitsURL(currentCommit, commits) { | |
const result = commits.map((commit, index) => { | |
if (commit.id === currentCommit && index+1 < commits.length) { | |
return `${commitsBaseURL}${commits[index+1].id}`; | |
} | |
}); | |
const filteredResult = result.filter(url => !!url) | |
return !!filteredResult.length ? filteredResult[0] : false; | |
} | |
function getNextCommitsURL(currentCommit, commits) { | |
const result = commits.map((commit, index) => { | |
if (commit.id === currentCommit && index > 0) { | |
return `${commitsBaseURL}${commits[index-1].id}`; | |
} | |
}); | |
const filteredResult = result.filter(url => !!url) | |
return !!filteredResult.length ? filteredResult[0] : false; | |
} | |
function getCurrentCommit(locationURL) { | |
if (!!locationURL.includes("/commits/")) { | |
return locationURL.match(/.*\/commits\/(?<ref>[a-f0-9]*).*/).groups.ref; | |
} | |
return false; | |
} | |
function buildButton(url, name, title) { | |
if (!!url) { | |
return ` | |
<button class="aui-button commit-button" title="${title}" onclick="window.location='${url}';"> | |
${name} | |
</button> | |
`; | |
} | |
return ` | |
<button class="aui-button commit-button" title="${title}" disabled> | |
${name} | |
</button> | |
`; | |
} | |
function buildCommitsNavigationBlock(firstCommitBtn, previousCommitBtn, nextCommitBtn, lastCommitBtn) { | |
return $( ` | |
<div class="aui-toolbar2 commit-navigation-toolbar"> | |
${firstCommitBtn} | |
${previousCommitBtn} | |
${nextCommitBtn} | |
${lastCommitBtn} | |
</div> | |
` ); | |
} | |
function processJSON_Response(response) { | |
// Get PR commits from response and current commit if in commit view | |
const commits = response.values; | |
const currentCommit = getCurrentCommit(window.location.href); | |
// Get commits URL for navigation | |
const lastCommitURL = getLastCommitsURL(currentCommit, commits); | |
const firstCommitURL = getFirstCommitsURL(currentCommit, commits); | |
const nextCommitURL = !!currentCommit ? getNextCommitsURL(currentCommit, commits) : false; | |
const previousCommitURL = !!currentCommit ? getPreviousCommitsURL(currentCommit, commits) : false; | |
// Generate Button HTML block | |
const firstCommitBtn = buildButton(firstCommitURL, "First", "Go to the first commit"); | |
const previousCommitBtn = buildButton(previousCommitURL, "Previous", "Got to the previous commit"); | |
const nextCommitBtn = buildButton(nextCommitURL, "Next", "Go to the next commit"); | |
const lastCommitBtn = buildButton(lastCommitURL, "Last", "Go to the last commit"); | |
// Generate Navigation block | |
const commitsNavigationBlock = buildCommitsNavigationBlock(firstCommitBtn, previousCommitBtn, nextCommitBtn, lastCommitBtn); | |
// Get injection target and inject Navigation block | |
const targetInjection = $("div[class='file-tree-container'] > button[class*='commit-selector-button']"); | |
if (!targetInjection.length) { | |
throw "Bitbucket PR Commit Navigation script => Target node not found."; | |
} | |
targetInjection.after(commitsNavigationBlock); | |
} | |
// Inject Custom Style | |
GM_addStyle ( ` | |
.commit-navigation-toolbar { | |
display: inline-flex; | |
padding-right: 20px; | |
width: 100% | |
} | |
.commit-button { | |
flex: 1; | |
} | |
` ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment