Van Deploy

Auto Deploy for Van!

Per 31-05-2022. Zie de nieuwste versie.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

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

})();