Greasy Fork is available in English.

Playground Links

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

// ==UserScript==
// @name         Playground Links
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Adds links to our playgrounds and jira tickets to the PR title.
// @author       https://github.com/cgriebel
// @match        https://github.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=github.com
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    function onLocationChange() {
        initPr();
        initCompare();
        initCreatePr();
    }

    function initCompare() {
        if (!/RogerAI\/.*\/compare\//.test(window.location.pathname)) return;
        compare.addJiraLinks();
    }

    function initPr() {
        if (!/RogerAI\/.*\/pull\/\d/.test(window.location.pathname)) return;
        pr.addJiraLink();
        pr.addPlaygroundLink();
        pr.addPlaygroundTicketLinks();
    }

    function initCreatePr() {
        if (!/RogerAI\/.*\/compare\//.test(window.location.pathname)) return;
        const header = document.querySelector('.compare-pr-header.Subhead h1')
        if (header?.textContent !== 'Open a pull request' || header.getAttribute('data-cg-init')) return;
        createPr.addJiraTag();
        createPr.assignSelf();
        header.setAttribute('data-cg-init', true)
    }

    const jiraRegex = /\[([A-Za-z]+\-\d+)\]/;
    const matchToJiraLink = match => `https://roger-team.atlassian.net/browse/${match[1]}`;

    function capitalizeFirstLetter(string) {
        return string.charAt(0).toUpperCase() + string.slice(1);
    }

    const compare = {
        addJiraLinks() {
            var loading = document.querySelector('[aria-label="Loading Commits"]');
            if (loading) {
                setTimeout(compare.addJiraLinks, 20);
                return;
            }

            const rowNodes = [...document.querySelectorAll('.js-commits-list-item')]
            rowNodes.forEach(row => {
                const titleElem = row.querySelector('.js-details-container.Details > p');

                console.log(titleElem)
                const title = titleElem.textContent;
                const match = title.match(jiraRegex);
                if (!match) return;
                const link = matchToJiraLink(match);
                console.log(link)
                const button = document.createElement('div');
                button.setAttribute("class", "d-inline-block")
                button.innerHTML = `<a href="${link}" target="_blank">Jira</a>`

                const actions = row.children[1];
                actions.insertBefore(button, actions.children[0])
            })
        }
    }

    const pr = {
        replaceSegment(reg, buildLink) {
            const titleElement = document.querySelector('.gh-header-title .js-issue-title');
            if (!titleElement) return;
            const titleNodes = [...titleElement.childNodes];

            const sanitizedText = titleNodes
                .filter(n => n.nodeType === Node.TEXT_NODE)
                .map(n => n.textContent)
                .join(" ");

            if (!sanitizedText.match(reg)?.length) return;

            const newNodes = titleNodes.reduce((acc, n) => {
                const titleText = n.textContent;
                const match = titleText.match(reg);
                if (n.nodeType === Node.TEXT_NODE && match?.length) {
                    var parts = titleText.split(match[0]);
                    acc.push(document.createTextNode(parts[0]))
                    var link = document.createElement('a');
                    link.setAttribute("target", "_blank")
                    link.text = match[0]
                    link.setAttribute("href", buildLink(match));
                    acc.push(link);
                    if (parts[1]) {
                        acc.push(document.createTextNode(parts[1]))
                    }
                } else {
                    acc.push(n);
                }
                return acc;
            }, [])

            titleNodes.forEach(n => titleElement.removeChild(n));
            newNodes.forEach(n => titleElement.appendChild(n));
        },
        addPlaygroundLink() {
            const prNumber = document.querySelector('.gh-header-title .f1-light').textContent.replace('#', '');
            pr.replaceSegment(/\[playground\]/i, match => {
                let site = "";
                if(window.location.pathname.includes("roger-admin"))
                {
                    site = "-admin";
                }
                return `https://pr-${prNumber}${site}.playgrounds.corpayone.com`
            });
        },
        addJiraLink() {
            pr.replaceSegment(jiraRegex, matchToJiraLink);
        },
        addPlaygroundTicketLinks() {
            const prefixes = {
                "admin": "roger-admin",
                "api": "Roger-Backend",
                "data-entry": "roger-data-entry",
                "economic": "roger-apps-economic",
                "identity": "roger-identity",
                "ripe": "ripe",
                "web": "Roger-Web",
            };

            const prefixReg = Object.keys(prefixes).join("|");
            const regex = new RegExp(`\\[((${prefixReg}):pull\\-(\\d+))\\]`);
            pr.replaceSegment(regex, match => `https://github.com/RogerAI/${prefixes[match[2]]}/pull/${match[3]}`);
        }
    }

    const createPr = {
        addJiraTag() {
            const sourceBranch = document.querySelector('#head-ref-selector .Button-label span').textContent;
            const match = sourceBranch.match(/([a-zA-Z]+)\/([A-Z]+\-\d+)/);;
            if (!match) return;
            console.log("Add Jira Tag")
            const branchType = match[1];
            const ticketId = match[2];
            const ticketTag = `[${ticketId}]`;
            const titleElem = document.querySelector('#pull_request_title');
            const title = titleElem.value;
            const titleTicketId = ticketId.replace('-', ' ');
            let titleMsg = title.replace(RegExp(`${branchType}/${titleTicketId} `, 'i'), '');

            // avoid duplicates from a refresh
            titleMsg = titleMsg.replaceAll(`${ticketTag} `, '');
            titleMsg = capitalizeFirstLetter(titleMsg);
            titleElem.value = `${ticketTag} ${titleMsg}`;
        },
        assignSelf() {
            var assignSelfBtn = document.querySelector('.js-issue-assign-self')
            assignSelfBtn?.click()
        }
    }

    function initialize() {
        console.log("Initializing Playground Link Script");
        let oldPushState = history.pushState;
        history.pushState = function pushState() {
            let ret = oldPushState.apply(this, arguments);
            window.dispatchEvent(new Event('pushstate'));
            window.dispatchEvent(new Event('locationchange'));
            return ret;
        };

        let oldReplaceState = history.replaceState;
        history.replaceState = function replaceState() {
            let ret = oldReplaceState.apply(this, arguments);
            window.dispatchEvent(new Event('replacestate'));
            window.dispatchEvent(new Event('locationchange'));
            return ret;
        };

        window.addEventListener('popstate', () => {
            window.dispatchEvent(new Event('locationchange'));
        });

        window.addEventListener('locationchange', function () {
            onLocationChange();
        });

        initPr();
        setInterval(() => initPr(), 250);
        setInterval(() => initCreatePr(), 250);
    }

    initialize();
})();