Skip to content

Instantly share code, notes, and snippets.

@KerberosMorphy
Last active July 9, 2021 18:22
Show Gist options
  • Save KerberosMorphy/a6b9cbc472aa1a3d2310245d460476b9 to your computer and use it in GitHub Desktop.
Save KerberosMorphy/a6b9cbc472aa1a3d2310245d460476b9 to your computer and use it in GitHub Desktop.
Bitbucket PR commits navigation
// ==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