Create & copy release content for coding project.

Make your release real quick!

  1. // ==UserScript==
  2. // @name Create & copy release content for coding project.
  3. // @namespace https://greasyfork.org/zh-CN/scripts/395451
  4. // @version 1.9.0
  5. // @description Make your release real quick!
  6. // @author You
  7. // @match https://*.coding.net/p/*/d/*/git/compare/*
  8. // @match https://*.codingcorp.net/p/*/d/*/git/compare/*
  9. // @grant GM_setClipboard
  10. // @grant GM_notification
  11. // @grant GM_addStyle
  12. // ==/UserScript==
  13.  
  14. (function () {
  15. const PageRegExp = /\/p\/(.*)[\/d\/(.*)]?\/git\/compare\/(.*)\.\.\.(.*)/;
  16.  
  17. const getDateStr = () => {
  18. const t = new Date()
  19. const y = t.getUTCFullYear();
  20. const m = `0${t.getUTCMonth() + 1}`.slice(-2);
  21. const d = `0${t.getUTCDate()}`.slice(-2);
  22. const dateStr = `${y}-${m}-${d}`;
  23. const tag = `${y}${m}${d}.1`;
  24. return [dateStr, tag];
  25. }
  26.  
  27. const getContent = (source, target, content, date, tag, depot, project, corp) => `# 更新日期
  28.  
  29. > 开始时间:${date} 10:00
  30. > 结束时间:
  31.  
  32.  
  33. # 发布类型
  34.  
  35. 常规发布
  36.  
  37.  
  38. # 负责人
  39.  
  40. @name
  41.  
  42.  
  43. # 改动说明
  44.  
  45. ${content}
  46.  
  47.  
  48. # ${depot} diff
  49.  
  50. https://${corp}.coding.net/p/${project}/d/${depot}/git/compare/${source}...${target}
  51.  
  52.  
  53. # 更新服务
  54.  
  55. 服务 | 标签 | 顺序
  56. :---------- | :----------: | ----------:
  57. e-${depot} | ${tag} | 1
  58.  
  59.  
  60. # 发布后 ${depot} master 指向
  61.  
  62. \`\`\`
  63. ${target}
  64. \`\`\`
  65.  
  66.  
  67. # Checklist
  68.  
  69. # 测试链接
  70.  
  71. http://codingcorp.coding.testing-1-corp.coding.io/?buffet=${target}
  72. http://codingcorp.staging-corp.coding.io/?buffet=${target}
  73. https://codingcorp.coding.net/?buffet=${target}
  74.  
  75.  
  76. `;
  77.  
  78. const getCompareResult = (source, target, depot, project, corp) =>
  79. fetch(`/api/user/${corp}/project/${project}/depot/${depot}/git/compare_v2?source=${source}&target=${target}&w=&prefix=`);
  80.  
  81. const getMRId = url => {
  82. const match = url.match(/\d+(\/)?$/) || [];
  83. return match.shift() || 0;
  84. }
  85.  
  86. const matchFromPath = () => {
  87. const { pathname, host } = window.location;
  88. const match = pathname.match(/\/p\/(.*)[\/d\/(.*)]?\/git\/compare\/(.*)\.\.\.(.*)/) || [];
  89.  
  90. const len = match.length;
  91. if (len < 3 || !match[1]) {
  92. throw new Error(`failed to parse url.`);
  93. }
  94.  
  95. const [project, depot] = match[1].split(`/d/`);
  96.  
  97. return [
  98. ...match.slice(-2),
  99. depot || project,
  100. project,
  101. window.location.host.split('.').shift(),
  102. ];
  103. }
  104.  
  105. async function makeRelease() {
  106. const [source, target, depot, project, corp] = matchFromPath()
  107. const res = await getCompareResult(source, target, depot, project, corp);
  108. const { data: { commits = [] } } = await res.json()
  109. const mrs = commits.filter(c => c.rawMessage.startsWith(`Accept Merge Request #`))
  110.  
  111. const list = mrs.map(m => {
  112. const arr = m.rawMessage.split('\n');
  113. const title = arr.find(i => i.includes(`Merge Request:`)).replace(`Merge Request:`, '').trim();
  114. const creator = arr.find(i => i.includes(`Created By:`)).replace(`Created By:`, '').trim();
  115. const link = arr.find(i => i.includes(`URL:`)).replace(`URL:`, '').trim();
  116. const mrId = getMRId(link);
  117. const mrText = `<a href="${link}">#${mrId}</a>`;
  118. return `- ` + [title, creator, mrText].join(`, `);
  119. });
  120. const content = list.join(`\n`);
  121.  
  122. const [date, tag] = getDateStr();
  123. const text = getContent(source, target, content, date, tag, depot, project, corp);
  124. GM_setClipboard(text, `text`);
  125. GM_notification(`Copied to 📝`, `💯`);
  126. }
  127.  
  128. const style = `button#create-copy-release-btn {
  129. z-index: 100;
  130. position: absolute;
  131. right: 200px;
  132. top: 46px;
  133. display: inline-block;
  134. border: none;
  135. padding: 1rem 2rem;
  136. margin: 0;
  137. text-decoration: none;
  138. background: #0069ed;
  139. color: #ffffff;
  140. font-family: sans-serif;
  141. font-size: 1rem;
  142. cursor: pointer;
  143. text-align: center;
  144. transition: background 250ms ease-in-out,
  145. transform 150ms ease;
  146. -webkit-appearance: none;
  147. -moz-appearance: none;
  148. }
  149.  
  150. button#create-copy-release-btn:hover,
  151. button#create-copy-release-btn:focus {
  152. background: #0053ba;
  153. }
  154.  
  155. button#create-copy-release-btn:focus {
  156. outline: 1px solid #fff;
  157. outline-offset: -4px;
  158. }
  159.  
  160. button#create-copy-release-btn:active {
  161. transform: scale(0.99);
  162. }`;
  163. GM_addStyle(style);
  164.  
  165. const btn = document.createElement('button');
  166. btn.innerText = `Create & Copy Release`;
  167. btn.id = `create-copy-release-btn`;
  168. btn.onclick = makeRelease;
  169.  
  170. let timer = null;
  171. let inserted = false;
  172. timer = setInterval(() => {
  173. const isComparePage = PageRegExp.test(window.location.pathname);
  174.  
  175. if (inserted) {
  176. if (isComparePage) return;
  177. btn.parentNode.removeChild(btn);
  178. inserted = false;
  179. return;
  180. }
  181.  
  182. if (!isComparePage) {
  183. return;
  184. }
  185.  
  186. const s = document.querySelector(`[class*=ref-selector]`);
  187. if (!s) return;
  188.  
  189. if (!inserted) {
  190. s.parentNode.appendChild(btn);
  191. inserted = true;
  192. }
  193. // clearInterval(timer);
  194. }, 200);
  195. })()