Van Deploy

Auto Deploy for Van!

Устаревшая версия за 31.05.2022. Перейдите к последней версии.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name         Van Deploy
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  Auto Deploy for Van!
// @author       Alexander
// @match        https://van.huolala.work/projects/835/*
// @match        https://van.huolala.work/projects/833/*
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        none
// @license      MIT
// ==/UserScript==


(function() {
  'use strict';
  // console.log(' van deploy is running ')
  let monitor
  const startTime = new Date().getTime()
  const sleep = (time = 1000) => new Promise(resolve => setTimeout(resolve, time));


  class DeployTask {
    constructor(config) {
      this.id = config.id // building id
      this.branch = config.branch // branch
      this.startTime = new Date().getTime()
      // this.config = config
      this.status = 'pending' // pending, success, failed, deploying , deployed, undeployed
      this.intervalID = undefined
      this.deployInterval = undefined
      this.start()
    }

    getDom() {
      const taskDom = Array.from(document.getElementsByTagName('strong')).find(dom => dom.innerText === this.id)
      return taskDom ? taskDom.parentNode.parentNode : null
    }

    async start () {
      try {
        console.log('task ', this.id, ' start')
        this.status = 'pending'
        await this.query()
        await this.queueForDeply()
        console.log('task is deploying ', this.id)
        this.status = 'deploying'
        await this.deploy()
        this.stop()
      } catch (error) {
        console.log('deploy error ', error)
        this.stop()
      }
    }

    async query() {
      return new Promise((resolve, reject) => {

        this.intervalID = setInterval(() => {
          console.log(this.id, ' building status query ')
          const dom = this.getDom()
          if (!dom) {
            return
          }
          console.log('task is pending', this.id)
          const status = dom.getElementsByClassName('anticon')[0].className.split(' ')

          if (status.some(classItem => ['anticon-check-circle'].includes(classItem))) {
            clearInterval(this.intervalID)
            this.status = 'success'
            resolve()
          }
          if (status.some(classItem => ['anticon-close-circle'].includes(classItem))) {
            clearInterval(this.intervalID)
            this.status = 'failed'
            reject()
          }
        }, 1000)
      })
    }

    async queueForDeply () {
      return new Promise((resolve, reject) => {
        console.log('queue for deploy ', this.id)
        this.deployInterval = setInterval(() => {
          if (monitor.canDeploy()) {
            clearInterval(this.deployInterval)
            resolve()
          }
        }, 500)
      })
    }

    async deploy() {
      const dom = this.getDom()
      let deployed = false
      if (!dom) {
        return
      }
      dom.click()
      await sleep(3000)
      document.querySelector('.publish-btn-check button').click()
      await sleep(1000)

      Array.from(document.getElementsByClassName('fast-publish-btn-menu')[0].getElementsByClassName('ant-menu-item-group')).forEach(envDom => {
        const envName = envDom.getElementsByClassName('ant-menu-item-group-title')[0].innerText.toLocaleLowerCase().trim()

        if (this.branch.includes(envName) ) {
          deployed = true
          envDom.getElementsByClassName('ant-space-item')[0].click()
        }
        // env.getElementsByClassName('ant-space-item')
      })
      if (deployed) {
        this.status = 'deployed'
        return Promise.resolve()
      }
      this.status = 'undeployed'
      return Promise.reject()
    }


    stop() {
      // deployed, failed
      console.log('task ', this.id, ' stop')
      clearInterval(this.intervalID)
      clearInterval(this.deployInterval)
    }
  }


  class DeloyMonitor {
    constructor() {
      this.tasksQueue = []
      this.intervalID = undefined
    }

    async getTaskNodes () {
      const parentNode = document.getElementsByClassName('task-list-sider__list')[0]
      let nodes
      if (!parentNode) {
        await sleep(50)
        nodes = await this.getTaskNodes()
        return nodes
      }
      nodes = parentNode.getElementsByClassName('task-card')
      if (!nodes || nodes.length === 0) {
        await sleep(50)
        nodes = await this.getTaskNodes()
        return nodes
      }
      return nodes
    }

    parseNode(node) {
      const id = node.getElementsByClassName('first-line')[0].getElementsByTagName('strong')[0].innerText
      const branch = node.getElementsByClassName('branch')[0].innerText.trim()
      const user = node.getElementsByClassName('second-line')[0].getElementsByTagName('strong')[0].innerText.split(' ')[1];
      // const status = node.className.split(' ')[1];
      // pending : anticon-sync anticon-spin
      // success : anticon-check-circle
      // failed : anticon-close-circle
      // deployed : anticon-flag
      const status = node.getElementsByClassName('anticon')[0].className.split(' ')
      // console.log('id', id, 'status', status)
      return { id, branch, user, status }
    }

    start () {

      this.intervalID = setInterval(async () => {
        console.log('deloyMonitor is running')
        const taskNodes = await this.getTaskNodes();

        Array.from(taskNodes).forEach(node => {

          const { id, branch, user, status } = this.parseNode(node)
          // add new task
          const task = this.tasksQueue.find(item => item.id === id)
          if (!task && status.some(statusClass => ['anticon-sync', 'anticon-spin'].includes(statusClass))) {
            
            const task = new DeployTask({ id, branch, user, status })
            console.log('add new task ', id , task)
            this.tasksQueue.push(task)
          }
          
          // remove when failed , deployed
          if (status.some(statusClass => ['anticon-close-circle', 'anticon-flag'].includes(statusClass))) {
            const taskIndex = this.tasksQueue.findIndex(item => item.id === id)
            taskIndex !== -1 && console.log('will remove task ', id , task, 'taskIndex', taskIndex)
            taskIndex !== -1 && this.tasksQueue.splice(taskIndex, 1)
          }

          //  remove when success but undeployed
          if (status.some(statusClass => ['anticon-check-circle'].includes(statusClass))) {
            const taskIndex = this.tasksQueue.findIndex(item => item.id === id)
            const successTask = this.tasksQueue[taskIndex]
            successTask.status === 'undeployed' && this.tasksQueue.splice(taskIndex, 1)
          }
          
        })
        console.clear()
        console.log('at time', parseInt((new Date().getTime() - startTime) / 1000), 'tasks are ',[...this.tasksQueue])
      }, 5000)
    }

    stop () {
      console.log('Please press the Logout button to logout.')
      this.tasksQueue.forEach(task => task.stop())
      clearInterval(this.intervalID)
    }
    canDeploy (){
      return !this.tasksQueue.some(task => task.status === 'deploying')
    }
  }

  monitor = new DeloyMonitor()
  monitor.start();

  window.onbeforeunload = function(e) {
    monitor.stop();
  };

})();