Playground Links

Adds links to our playgrounds and jira tickets to the PR title.

  1. // ==UserScript==
  2. // @name Playground Links
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.1
  5. // @description Adds links to our playgrounds and jira tickets to the PR title.
  6. // @author https://github.com/cgriebel
  7. // @match https://github.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=github.com
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function () {
  13. 'use strict';
  14.  
  15. function onLocationChange() {
  16. initPr();
  17. initCompare();
  18. initCreatePr();
  19. }
  20.  
  21. function initCompare() {
  22. if (!/RogerAI\/.*\/compare\//.test(window.location.pathname)) return;
  23. compare.addJiraLinks();
  24. }
  25.  
  26. function initPr() {
  27. if (!/RogerAI\/.*\/pull\/\d/.test(window.location.pathname)) return;
  28. pr.addJiraLink();
  29. pr.addPlaygroundLink();
  30. pr.addPlaygroundTicketLinks();
  31. }
  32.  
  33. function initCreatePr() {
  34. if (!/RogerAI\/.*\/compare\//.test(window.location.pathname)) return;
  35. const header = document.querySelector('.compare-pr-header.Subhead h1')
  36. if (header?.textContent !== 'Open a pull request' || header.getAttribute('data-cg-init')) return;
  37. createPr.addJiraTag();
  38. createPr.assignSelf();
  39. header.setAttribute('data-cg-init', true)
  40. }
  41.  
  42. const jiraRegex = /\[([A-Za-z]+\-\d+)\]/;
  43. const matchToJiraLink = match => `https://roger-team.atlassian.net/browse/${match[1]}`;
  44.  
  45. function capitalizeFirstLetter(string) {
  46. return string.charAt(0).toUpperCase() + string.slice(1);
  47. }
  48.  
  49. const compare = {
  50. addJiraLinks() {
  51. var loading = document.querySelector('[aria-label="Loading Commits"]');
  52. if (loading) {
  53. setTimeout(compare.addJiraLinks, 20);
  54. return;
  55. }
  56.  
  57. const rowNodes = [...document.querySelectorAll('.js-commits-list-item')]
  58. rowNodes.forEach(row => {
  59. const titleElem = row.querySelector('.js-details-container.Details > p');
  60.  
  61. console.log(titleElem)
  62. const title = titleElem.textContent;
  63. const match = title.match(jiraRegex);
  64. if (!match) return;
  65. const link = matchToJiraLink(match);
  66. console.log(link)
  67. const button = document.createElement('div');
  68. button.setAttribute("class", "d-inline-block")
  69. button.innerHTML = `<a href="${link}" target="_blank">Jira</a>`
  70.  
  71. const actions = row.children[1];
  72. actions.insertBefore(button, actions.children[0])
  73. })
  74. }
  75. }
  76.  
  77. const pr = {
  78. replaceSegment(reg, buildLink) {
  79. const titleElement = document.querySelector('.gh-header-title .js-issue-title');
  80. if (!titleElement) return;
  81. const titleNodes = [...titleElement.childNodes];
  82.  
  83. const sanitizedText = titleNodes
  84. .filter(n => n.nodeType === Node.TEXT_NODE)
  85. .map(n => n.textContent)
  86. .join(" ");
  87.  
  88. if (!sanitizedText.match(reg)?.length) return;
  89.  
  90. const newNodes = titleNodes.reduce((acc, n) => {
  91. const titleText = n.textContent;
  92. const match = titleText.match(reg);
  93. if (n.nodeType === Node.TEXT_NODE && match?.length) {
  94. var parts = titleText.split(match[0]);
  95. acc.push(document.createTextNode(parts[0]))
  96. var link = document.createElement('a');
  97. link.setAttribute("target", "_blank")
  98. link.text = match[0]
  99. link.setAttribute("href", buildLink(match));
  100. acc.push(link);
  101. if (parts[1]) {
  102. acc.push(document.createTextNode(parts[1]))
  103. }
  104. } else {
  105. acc.push(n);
  106. }
  107. return acc;
  108. }, [])
  109.  
  110. titleNodes.forEach(n => titleElement.removeChild(n));
  111. newNodes.forEach(n => titleElement.appendChild(n));
  112. },
  113. addPlaygroundLink() {
  114. const prNumber = document.querySelector('.gh-header-title .f1-light').textContent.replace('#', '');
  115. pr.replaceSegment(/\[playground\]/i, match => {
  116. let site = "";
  117. if(window.location.pathname.includes("roger-admin"))
  118. {
  119. site = "-admin";
  120. }
  121. return `https://pr-${prNumber}${site}.playgrounds.corpayone.com`
  122. });
  123. },
  124. addJiraLink() {
  125. pr.replaceSegment(jiraRegex, matchToJiraLink);
  126. },
  127. addPlaygroundTicketLinks() {
  128. const prefixes = {
  129. "admin": "roger-admin",
  130. "api": "Roger-Backend",
  131. "data-entry": "roger-data-entry",
  132. "economic": "roger-apps-economic",
  133. "identity": "roger-identity",
  134. "ripe": "ripe",
  135. "web": "Roger-Web",
  136. };
  137.  
  138. const prefixReg = Object.keys(prefixes).join("|");
  139. const regex = new RegExp(`\\[((${prefixReg}):pull\\-(\\d+))\\]`);
  140. pr.replaceSegment(regex, match => `https://github.com/RogerAI/${prefixes[match[2]]}/pull/${match[3]}`);
  141. }
  142. }
  143.  
  144. const createPr = {
  145. addJiraTag() {
  146. const sourceBranch = document.querySelector('#head-ref-selector .Button-label span').textContent;
  147. const match = sourceBranch.match(/([a-zA-Z]+)\/([A-Z]+\-\d+)/);;
  148. if (!match) return;
  149. console.log("Add Jira Tag")
  150. const branchType = match[1];
  151. const ticketId = match[2];
  152. const ticketTag = `[${ticketId}]`;
  153. const titleElem = document.querySelector('#pull_request_title');
  154. const title = titleElem.value;
  155. const titleTicketId = ticketId.replace('-', ' ');
  156. let titleMsg = title.replace(RegExp(`${branchType}/${titleTicketId} `, 'i'), '');
  157.  
  158. // avoid duplicates from a refresh
  159. titleMsg = titleMsg.replaceAll(`${ticketTag} `, '');
  160. titleMsg = capitalizeFirstLetter(titleMsg);
  161. titleElem.value = `${ticketTag} ${titleMsg}`;
  162. },
  163. assignSelf() {
  164. var assignSelfBtn = document.querySelector('.js-issue-assign-self')
  165. assignSelfBtn?.click()
  166. }
  167. }
  168.  
  169. function initialize() {
  170. console.log("Initializing Playground Link Script");
  171. let oldPushState = history.pushState;
  172. history.pushState = function pushState() {
  173. let ret = oldPushState.apply(this, arguments);
  174. window.dispatchEvent(new Event('pushstate'));
  175. window.dispatchEvent(new Event('locationchange'));
  176. return ret;
  177. };
  178.  
  179. let oldReplaceState = history.replaceState;
  180. history.replaceState = function replaceState() {
  181. let ret = oldReplaceState.apply(this, arguments);
  182. window.dispatchEvent(new Event('replacestate'));
  183. window.dispatchEvent(new Event('locationchange'));
  184. return ret;
  185. };
  186.  
  187. window.addEventListener('popstate', () => {
  188. window.dispatchEvent(new Event('locationchange'));
  189. });
  190.  
  191. window.addEventListener('locationchange', function () {
  192. onLocationChange();
  193. });
  194.  
  195. initPr();
  196. setInterval(() => initPr(), 250);
  197. setInterval(() => initCreatePr(), 250);
  198. }
  199.  
  200. initialize();
  201. })();