Van Deploy

Auto Deploy for Van!

Version au 31/05/2022. Voir la dernière version.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==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();
  };

})();