Van Deploy

Auto Deploy for Van!

目前为 2022-05-31 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Van Deploy
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.2
  5. // @description Auto Deploy for Van!
  6. // @author Alexander
  7. // @match https://van.huolala.work/projects/835/*
  8. // @match https://van.huolala.work/projects/833/*
  9. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  10. // @grant none
  11. // @license MIT
  12. // ==/UserScript==
  13.  
  14.  
  15. (function() {
  16. 'use strict';
  17. // console.log(' van deploy is running ')
  18. let monitor
  19. const startTime = new Date().getTime()
  20. const sleep = (time = 1000) => new Promise(resolve => setTimeout(resolve, time));
  21.  
  22.  
  23. class DeployTask {
  24. constructor(config) {
  25. this.id = config.id // building id
  26. this.branch = config.branch // branch
  27. this.startTime = new Date().getTime()
  28. // this.config = config
  29. this.status = 'pending' // pending, success, failed, deploying , deployed, undeployed
  30. this.intervalID = undefined
  31. this.deployInterval = undefined
  32. this.start()
  33. }
  34.  
  35. getDom() {
  36. const taskDom = Array.from(document.getElementsByTagName('strong')).find(dom => dom.innerText === this.id)
  37. return taskDom ? taskDom.parentNode.parentNode : null
  38. }
  39.  
  40. async start () {
  41. try {
  42. console.log('task ', this.id, ' start')
  43. this.status = 'pending'
  44. await this.query()
  45. await this.queueForDeply()
  46. console.log('task is deploying ', this.id)
  47. this.status = 'deploying'
  48. await this.deploy()
  49. this.stop()
  50. } catch (error) {
  51. console.log('deploy error ', error)
  52. this.stop()
  53. }
  54. }
  55.  
  56. async query() {
  57. return new Promise((resolve, reject) => {
  58.  
  59. this.intervalID = setInterval(() => {
  60. console.log(this.id, ' building status query ')
  61. const dom = this.getDom()
  62. if (!dom) {
  63. return
  64. }
  65. console.log('task is pending', this.id)
  66. const status = dom.getElementsByClassName('anticon')[0].className.split(' ')
  67.  
  68. if (status.some(classItem => ['anticon-check-circle'].includes(classItem))) {
  69. clearInterval(this.intervalID)
  70. this.status = 'success'
  71. resolve()
  72. }
  73. if (status.some(classItem => ['anticon-close-circle'].includes(classItem))) {
  74. clearInterval(this.intervalID)
  75. this.status = 'failed'
  76. reject()
  77. }
  78. }, 1000)
  79. })
  80. }
  81.  
  82. async queueForDeply () {
  83. return new Promise((resolve, reject) => {
  84. console.log('queue for deploy ', this.id)
  85. this.deployInterval = setInterval(() => {
  86. if (monitor.canDeploy()) {
  87. clearInterval(this.deployInterval)
  88. resolve()
  89. }
  90. }, 500)
  91. })
  92. }
  93.  
  94. async deploy() {
  95. const dom = this.getDom()
  96. let deployed = false
  97. if (!dom) {
  98. return
  99. }
  100. dom.click()
  101. await sleep(3000)
  102. document.querySelector('.publish-btn-check button').click()
  103. await sleep(1000)
  104.  
  105. Array.from(document.getElementsByClassName('fast-publish-btn-menu')[0].getElementsByClassName('ant-menu-item-group')).forEach(envDom => {
  106. const envName = envDom.getElementsByClassName('ant-menu-item-group-title')[0].innerText.toLocaleLowerCase().trim()
  107.  
  108. if (this.branch.includes(envName) ) {
  109. deployed = true
  110. envDom.getElementsByClassName('ant-space-item')[0].click()
  111. }
  112. // env.getElementsByClassName('ant-space-item')
  113. })
  114. if (deployed) {
  115. this.status = 'deployed'
  116. return Promise.resolve()
  117. }
  118. this.status = 'undeployed'
  119. return Promise.reject()
  120. }
  121.  
  122.  
  123. stop() {
  124. // deployed, failed
  125. console.log('task ', this.id, ' stop')
  126. clearInterval(this.intervalID)
  127. clearInterval(this.deployInterval)
  128. }
  129. }
  130.  
  131.  
  132. class DeloyMonitor {
  133. constructor() {
  134. this.tasksQueue = []
  135. this.intervalID = undefined
  136. }
  137.  
  138. async getTaskNodes () {
  139. const parentNode = document.getElementsByClassName('task-list-sider__list')[0]
  140. let nodes
  141. if (!parentNode) {
  142. await sleep(50)
  143. nodes = await this.getTaskNodes()
  144. return nodes
  145. }
  146. nodes = parentNode.getElementsByClassName('task-card')
  147. if (!nodes || nodes.length === 0) {
  148. await sleep(50)
  149. nodes = await this.getTaskNodes()
  150. return nodes
  151. }
  152. return nodes
  153. }
  154.  
  155. parseNode(node) {
  156. const id = node.getElementsByClassName('first-line')[0].getElementsByTagName('strong')[0].innerText
  157. const branch = node.getElementsByClassName('branch')[0].innerText.trim()
  158. const user = node.getElementsByClassName('second-line')[0].getElementsByTagName('strong')[0].innerText.split(' ')[1];
  159. // const status = node.className.split(' ')[1];
  160. // pending : anticon-sync anticon-spin
  161. // success : anticon-check-circle
  162. // failed : anticon-close-circle
  163. // deployed : anticon-flag
  164. const status = node.getElementsByClassName('anticon')[0].className.split(' ')
  165. // console.log('id', id, 'status', status)
  166. return { id, branch, user, status }
  167. }
  168.  
  169. start () {
  170.  
  171. this.intervalID = setInterval(async () => {
  172. console.log('deloyMonitor is running')
  173. const taskNodes = await this.getTaskNodes();
  174.  
  175. Array.from(taskNodes).forEach(node => {
  176.  
  177. const { id, branch, user, status } = this.parseNode(node)
  178. // add new task
  179. const task = this.tasksQueue.find(item => item.id === id)
  180. if (!task && status.some(statusClass => ['anticon-sync', 'anticon-spin'].includes(statusClass))) {
  181. const task = new DeployTask({ id, branch, user, status })
  182. console.log('add new task ', id , task)
  183. this.tasksQueue.push(task)
  184. }
  185. // remove when failed , deployed
  186. if (status.some(statusClass => ['anticon-close-circle', 'anticon-flag'].includes(statusClass))) {
  187. const taskIndex = this.tasksQueue.findIndex(item => item.id === id)
  188. taskIndex !== -1 && console.log('will remove task ', id , task, 'taskIndex', taskIndex)
  189. taskIndex !== -1 && this.tasksQueue.splice(taskIndex, 1)
  190. }
  191.  
  192. // remove when success but undeployed
  193. if (status.some(statusClass => ['anticon-check-circle'].includes(statusClass))) {
  194. const taskIndex = this.tasksQueue.findIndex(item => item.id === id)
  195. const successTask = this.tasksQueue[taskIndex]
  196. successTask.status === 'undeployed' && this.tasksQueue.splice(taskIndex, 1)
  197. }
  198. })
  199. console.clear()
  200. console.log('at time', parseInt((new Date().getTime() - startTime) / 1000), 'tasks are ',[...this.tasksQueue])
  201. }, 5000)
  202. }
  203.  
  204. stop () {
  205. console.log('Please press the Logout button to logout.')
  206. this.tasksQueue.forEach(task => task.stop())
  207. clearInterval(this.intervalID)
  208. }
  209. canDeploy (){
  210. return !this.tasksQueue.some(task => task.status === 'deploying')
  211. }
  212. }
  213.  
  214. monitor = new DeloyMonitor()
  215. monitor.start();
  216.  
  217. window.onbeforeunload = function(e) {
  218. monitor.stop();
  219. };
  220.  
  221. })();