您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Support multiple pull request templates
// ==UserScript== // @name Bitbucket Server Multiple Pull Request Templates // @namespace https://github.com/kellyselden // @version 8 // @description Support multiple pull request templates // @author Kelly Selden // @license MIT // @source https://github.com/kellyselden/bitbucket-server-multiple-pull-request-templates // @supportURL https://github.com/kellyselden/bitbucket-server-multiple-pull-request-templates/issues/new // @include http*://*bitbucket*/projects/*/repos/*/pull-requests?create* // ==/UserScript== 'use strict'; let container = document.getElementById('compare-and-create-container'); function getEditor() { return container.querySelector('.CodeMirror').CodeMirror; } function listener(event) { let editor = getEditor(); editor.setValue(event.target.value); } function stripExtension(fileName) { let i = fileName.lastIndexOf('.'); if (i === -1 || i === 0) { return fileName; } return fileName.substring(0, i); } const selectId = 'custom-pull-request-templates-select'; async function run(formBodySide) { let templatesPath = '.pull-request-templates'; let sourceBranch = new URL(document.URL).searchParams.get('sourceBranch').replace('refs/heads/', ''); let { project, repo } = document.URL.match(/\/projects\/(?<project>\w+)\/repos\/(?<repo>\S+)\/pull-requests/).groups; let response = await fetch(`/rest/api/1.0/projects/${project}/repos/${repo}/files/${templatesPath}?at=${sourceBranch}`, { headers: { 'Content-Type': 'application/json', }, }); let data = await response.json(); if (data.errors) { for (let error of data.errors) { if (error.exceptionName === 'com.atlassian.bitbucket.content.NoSuchPathException') { console.log(error); } else { console.error(error); } } return; } let files = data.values.reduce((files, file) => { let name = stripExtension(file); if (name.toUpperCase() !== 'README') { files.push({ file, name, }); } return files; }, []); let pullRequestTemplates = await Promise.all(files.map(async ({ file, name }) => { let response = await fetch(`/rest/api/1.0/projects/${project}/repos/${repo}/raw/${templatesPath}/${file}?at=${sourceBranch}`); let text = await response.text(); return { name, text, }; })); pullRequestTemplates = pullRequestTemplates.reduce((pullRequestTemplates, { name, text }) => { pullRequestTemplates[name] = text; return pullRequestTemplates; }, {}); let extension = document.createElement('div'); extension.id = 'custom-pull-request-templates'; extension.classList.add('create-pull-request-form-extension'); let labelElement = document.createElement('label'); labelElement.htmlFor = selectId; labelElement.textContent = 'Pull request template: '; let selectElement = document.createElement('select'); selectElement.id = selectId; let defaultKey = 'default'; let defaultValue = pullRequestTemplates[defaultKey] ?? editor.getValue(); let editor = getEditor(); let option = document.createElement('option'); option.value = defaultValue; option.textContent = defaultKey; selectElement.appendChild(option); editor.setValue(defaultValue); delete pullRequestTemplates[defaultKey]; for (let [team, template] of Object.entries(pullRequestTemplates)) { let option = document.createElement('option'); option.value = template; option.textContent = team; selectElement.appendChild(option); } selectElement.addEventListener('change', listener); extension.appendChild(labelElement); extension.appendChild(selectElement); formBodySide.appendChild(extension); } function find(node, query) { if (node.matches?.(query)) { return node; } else { return node.querySelector?.(query); } } new MutationObserver(mutationsList => { for (let mutation of mutationsList) { if (mutation.type === 'childList') { for (let node of mutation.addedNodes) { let formBodySide = find(node, '.form-body-side'); if (formBodySide) { run(formBodySide); } } for (let node of mutation.removedNodes) { let select = find(node, `#${selectId}`); if (select) { select.removeEventListener('change', listener); } } } } }).observe(container, { subtree: true, childList: true, });