Create & copy release content for coding project.

Make your release real quick!

Stan na 08-09-2020. Zobacz najnowsza wersja.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

// ==UserScript==
// @name         Create & copy release content for coding project.
// @namespace    https://greasyfork.org/zh-CN/scripts/395451
// @version      1.6
// @description  Make your release real quick!
// @author       You
// @match        https://*.coding.net/p/*/d/*/git/compare/*
// @grant        GM_setClipboard
// @grant        GM_notification
// @grant        GM_addStyle
// ==/UserScript==

(function () {
    const PageRegExp = /\/p\/(.*)[\/d\/(.*)]?\/git\/compare\/(.*)\.\.\.(.*)/;

    const getDateStr = () => {
        const t = new Date()
        const y = t.getUTCFullYear();
        const m = `0${t.getUTCMonth() + 1}`.slice(-2);
        const d = `0${t.getUTCDate()}`.slice(-2);
        const dateStr = `${y}-${m}-${d}`;
        const tag = `${y}${m}${d}.1`;
        return [dateStr, tag];
    }

    const getContent = (source, target, content, date, tag, depot, project, corp) => `# 更新日期

> 开始时间:${date} 10:00
> 结束时间:


# 发布类型

常规发布


# 负责人

@name


# 改动说明

${content}


# ${depot} diff

https://${corp}.coding.net/p/${project}/d/${depot}/git/compare/${source}...${target}


# 更新服务

服务 | 标签 | 顺序
:---------- | :----------: | ----------:
e-${depot}  |  ${tag}  |  1


# 发布后 ${depot} master 指向

\`\`\`
${target}
\`\`\`


# Checklist

# 测试链接

http://codingcorp.coding.testing-1-corp.coding.io/?buffet=${target}
http://codingcorp.staging-corp.coding.io/?buffet=${target}
https://codingcorp.coding.net/?buffet=${target}


`;

    const getCompareResult = (source, target, depot, project, corp) =>
        fetch(`https://${corp}.coding.net/api/user/${corp}/project/${project}/depot/${depot}/git/compare_v2?source=${source}&target=${target}&w=&prefix=`);

    const getMRId = url => {
        const match = url.match(/\d+(\/)?$/) || [];
        return match.shift() || 0;
    }

    const matchFromPath = () => {
        const { pathname, host } = window.location;
        const match = pathname.match(/\/p\/(.*)[\/d\/(.*)]?\/git\/compare\/(.*)\.\.\.(.*)/) || [];

        const len = match.length;
        if (len < 3 || !match[1]) {
            throw new Error(`failed to parse url.`);
        }

        const corp = host.replace('.coding.net', '');
        const [project, depot] = match[1].split(`/d/`);

        return [
            ...match.slice(-2),
            depot || project,
            project,
            corp,
        ];
    }

    async function makeRelease() {
        const [source, target, depot, project, corp] = matchFromPath()
        const res = await getCompareResult(source, target, depot, project, corp);
        const { data: { commits = [] } } = await res.json()
        const mrs = commits.filter(c => c.rawMessage.startsWith(`Accept Merge Request #`))

        const list = mrs.map(m => {
            const arr = m.rawMessage.split('\n');
            const title = arr.find(i => i.includes(`Merge Request:`)).replace(`Merge Request:`, '').trim();
            const creator = arr.find(i => i.includes(`Created By:`)).replace(`Created By:`, '').trim();
            const link = arr.find(i => i.includes(`URL:`)).replace(`URL:`, '').trim();
            const mrId = getMRId(link);
            const mrText = `<a href="${link}">#${mrId}</a>`;
            return `- ` + [title, creator, mrText].join(`, `);
        });
        const content = list.join(`\n`);

        const [date, tag] = getDateStr();
        const text = getContent(source, target, content, date, tag, depot, project, corp);
        GM_setClipboard(text, `text`);
        GM_notification(`Copied to 📝`, `💯`);
    }

    const style = `button#create-copy-release-btn {
z-index: 100;
position: absolute;
right: 30px;
top: 50px;
display: inline-block;
border: none;
padding: 1rem 2rem;
margin: 0;
text-decoration: none;
background: #0069ed;
color: #ffffff;
font-family: sans-serif;
font-size: 1rem;
cursor: pointer;
text-align: center;
transition: background 250ms ease-in-out,
transform 150ms ease;
-webkit-appearance: none;
-moz-appearance: none;
}

button#create-copy-release-btn:hover,
button#create-copy-release-btn:focus {
background: #0053ba;
}

button#create-copy-release-btn:focus {
outline: 1px solid #fff;
outline-offset: -4px;
}

button#create-copy-release-btn:active {
transform: scale(0.99);
}`;
    GM_addStyle(style);

    const btn = document.createElement('button');
    btn.innerText = `Create & Copy Release`;
    btn.id = `create-copy-release-btn`;
    btn.onclick = makeRelease;

    let timer = null;
    let inserted = false;
    timer = setInterval(() => {
        const isComparePage = PageRegExp.test(window.location.pathname);

        if (inserted) {
            if (isComparePage) return;
            btn.parentNode.removeChild(btn);
            inserted = false;
            return;
        }

        if (!isComparePage) {
            return;
        }

        const s = document.querySelector(`[class*=ref-selector]`);
        if (!s) return;

        if (!inserted) {
            s.parentNode.appendChild(btn);
            inserted = true;
        }
        // clearInterval(timer);
    }, 200);
})()