您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Auto Deploy for Van!
// ==UserScript== // @name Van Deploy // @namespace http://tampermonkey.net/ // @version 0.5.4 // @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== const getStorage = (name) => { // const cookieObj = document.cookie.split(';').reduce((acc, cur) => { // const [key, value] = cur.split('='); // acc[key.trim()] = value; // return acc; // } , {}) // return cookieObj[name || ''] || ''; return localStorage.getItem(name || '') || ''; }; const setStorage = (name, value) => { // const cookieObj = document.cookie.split(';').reduce((acc, cur) => { // const [key, value] = cur.split('='); // acc[key.trim()] = value; // return acc; // } , {}) // cookieObj[name] = value; // const newCookie = Object.keys(cookieObj).map(i => `${i}=${cookieObj[i]}`).join(';'); // document.cookie = newCookie; localStorage.setItem(name, value); }; (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)); const committerDeployMap = { 'pk.peng': 'stable-1', 'alexander.xie': 'stable-2', 'james.fu': 'stable-3', 'edison.ma': 'stable-4', }; class DeployTask { constructor(config) { this.id = config.id; // building id this.branch = config.branch; // branch this.committer = config.user; // committer this.startTime = new Date().getTime(); // this.config = config this.status = 'pending'; // pending, success, failed, deploying , deployed, undeployed this.queryId = undefined; this.deployInterval = undefined; this.start(); } donnotDeployToMyEnv() { return document.getElementById('deployEnv')?.checked; } 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.queryId = 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.queryId); this.status = 'success'; resolve(); } if (status.some(classItem => ['anticon-close-circle'].includes(classItem))) { clearInterval(this.queryId); 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); if (!document.getElementsByClassName('ant-dropdown')[0] || getComputedStyle( document.getElementsByClassName('ant-dropdown')[0]).display === 'none') { document.querySelector('.publish-btn-check button').click(); } await sleep(1000); Array.from(document.getElementsByClassName('fast-publish-btn-menu')[0].getElementsByClassName('ant-dropdown-menu-item-group')).forEach(envDom => { const envName = envDom.getElementsByClassName('ant-dropdown-menu-item-group-title')[0].innerText.toLocaleLowerCase().trim(); if (this.branch.includes(envName) ) { // stg、pre分支发对应的环境 envDom.getElementsByClassName('ant-space-item')[0].click(); } else if (['stg', 'pre'].includes(envName.toLocaleLowerCase()) && !this.donnotDeployToMyEnv()) { // 特性分支 发stg和pre对应的个人环境 const deployName = committerDeployMap[this.committer]; // envDom.getElementsByClassName('ant-space-item')[0].click() Array.from(envDom.getElementsByClassName('ant-space-item')).forEach(dployDom => { if (dployDom.innerText === deployName) { dployDom.click(); } }); } deployed = true; // env.getElementsByClassName('ant-space-item') }); await sleep(300); document.querySelector('.publish-btn-check button').click(); if (deployed) { this.status = 'deployed'; return Promise.resolve(); } this.status = 'undeployed'; return Promise.reject(); } stop() { // deployed, failed console.log('monitor ', this.queryId, ' stop'); clearInterval(this.queryId); clearInterval(this.deployInterval); } } class DeloyMonitor { constructor() { this.tasksQueue = []; this.monitorId = undefined; this.hibernateId = undefined; } getTaskNodes () { let count = 0; let queryIntervalId; const getNodes = () => { try { const parentNode = document.getElementsByClassName('task-list-sider__list')[0]; const nodes = parentNode.getElementsByClassName('task-card'); return nodes; } catch (error) { return null; } }; return new Promise((resolve, reject) => { queryIntervalId = setInterval(() => { count++; const nodesout = getNodes(); if (nodesout) { clearInterval(this.hibernateId); return resolve(nodesout); } if (count > 60) { clearInterval(queryIntervalId); return reject(); } }, 1000); }); } 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 }; } getCurrentUser() { try { const myCookie = document.cookie.split(';').reduce((acc, cur) => { const [key, value] = cur.trim().split('='); acc[key] = value; return acc; }, {}); const jsonStr = decodeURIComponent(myCookie?.sensorsdata2015jssdkcross || '{}'); const user = JSON.parse(jsonStr)?.distinct_id; return user; } catch (error) { console.log('parse cookie error', error); } } addToggleCheckbox() { // getStorage setStorage if(document.getElementById('deployEnv')) { return; } const container = document.createElement('div'); const notDeployToMyEnv = getStorage('not_deploy_to_my_env') === 'no'; //default yes const domStr = ` <div style="position: fixed; top: 150px; right: 40px;"> <input type="checkbox" id="deployEnv" name="deployEnv" value="Bike" ${notDeployToMyEnv ? 'checked' : ''}> <label for="deployEnv">不发布特性分支到个人环境</label> </div> `; container.innerHTML = domStr; container.addEventListener('click', (e) => { // console.log(e); const { checked } = e?.target || {}; setStorage('not_deploy_to_my_env', checked ? 'no' : 'yes'); }); document.getElementById('root').appendChild(container); } donnotDeployToMyEnv() { return document.getElementById('deployEnv').checked; } start () { if (this.monitorId) { return console.error('DeloyMonitor has already runned'); } this.monitorId = setInterval(async () => { console.log('deloyMonitor is running'); if (!navigator.onLine) { this.hibernate(); } try { this.addToggleCheckbox(); const taskNodes = await this.getTaskNodes(); console.log('taskNodes 999', taskNodes); if (!taskNodes) { setTimeout(this.reload, 1000); } Array.from(taskNodes).forEach(node => { const { id, branch, user, status } = this.parseNode(node); console.log('task user', user, this.getCurrentUser()); // add new task const task = this.tasksQueue.find(item => item.id === id); const isStgPre = branch.includes('stg') || branch.includes('pre'); const waitingDeploy = status.some(statusClass => ['anticon-sync', 'anticon-spin'].includes(statusClass)); const isMyPush = user === this.getCurrentUser(); // if (isStgPre && !task && waitingDeploy && isMyPush) { if (isMyPush && !task && waitingDeploy) { 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); if (taskIndex !== -1) { task.stop(); 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]; if (['undeployed', 'pending'].includes(successTask?.status)) { successTask.stop(); this.tasksQueue.splice(taskIndex, 1); } } }); } catch (err) { this.reload(); } finally { console.clear(); const timespan = parseInt((new Date().getTime() - startTime) / 1000); console.log('at time', timespan , 'tasks are ',[...this.tasksQueue]); timespan > 3600 && this.reload(); } }, 5000); } stop () { console.log('monitor stop'); this.tasksQueue.forEach(task => task.stop()); clearInterval(this.monitorId); this.monitorId = undefined; } canDeploy (){ return !this.tasksQueue.some(task => task.status === 'deploying'); } reload() { window.location.reload(); } hibernate () { console.log('hibernate'); this.stop(); this.tasksQueue = []; this.hibernateId = setInterval(() => { if (navigator.onLine) { this.start(); clearInterval(this.hibernateId); this.hibernateId = undefined; } }, 60 * 1000); } } monitor = new DeloyMonitor(); monitor.start(); window.onbeforeunload = function(e) { monitor.stop(); }; window.addEventListener('online', () => monitor.start()); window.addEventListener('offline', () => monitor.hibernate()); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址