import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu' import chalk = require('chalk'); import { defaultMenuSettings } from '../../../../globals'; const tto = require('terminal-table-output').create(); type Stack = { name: string, status: string, drift_status: string, branch: string, updated: string, }; module.exports = { name: 'status', alias: ['s'], description: 'Show status for available testservers (s)', hidden: false, run: async (toolbox: GluegunMenuToolbox) => { const { system, strings } = toolbox const stacks = JSON.parse(strings.trim(await system.run(`aws cloudformation list-stacks`))); const teststacks: Stack[] = await Promise.all(stacks.StackSummaries.map(async (item) => { if (item.StackName.indexOf('photowall-test-') > -1 && ['CREATE_COMPLETE', 'UPDATE_COMPLETE', 'UPDATE_IN_PROGRESS', 'UPDATE_FAILED', 'CREATE_FAILED', 'CREATE_IN_PROGRESS'].includes(item.StackStatus)) { try { const pipeline = JSON.parse(strings.trim(await system.run(`aws codepipeline get-pipeline --name ${item.StackName}Pipeline`))); const branch = pipeline.pipeline.stages.filter(stage => { return stage.name === 'Source'; })[0].actions[0].configuration.Branch; const lastUpdated = pipeline.metadata.updated; return { name: item.StackName, status: item.StackStatus, drift_status: item.DriftInformation.StackDriftStatus, branch: branch, updated: lastUpdated, } } catch (e) { return { name: item.StackName, status: 'NO_STATUS', drift_status: '', branch: '', updated: '', } } } return Promise.resolve(null); })); const curratedStacks: Stack[] = teststacks.filter(Boolean); const status = (status: string) => { switch(status) { case 'NO_STATUS': return `(${chalk.red.bold('?')})`; case 'UPDATE_FAILED': case 'CREATE_FAILED': return `(${chalk.red.bold('FAILED')})`; case 'UPDATE_IN_PROGRESS': case 'CREATE_IN_PROGRESS': return `(${chalk.yellow.bold('IN PROGRESS')})`; case 'UPDATE_COMPLETE': case 'CREATE_COMPLETE': return `(${chalk.greenBright('OK')})`; } } const stackUrl = (stackname: string) => { return `https://test-${stackname.split('photowall-test-')[1]}.photowall-test.com/us`; }; const ellipsis = (a: string, max: number) => { return a.length > max ? a.substr(0, max) + '..' : a; }; const timeSince = (date: number) => { const now = Date.now(); let seconds = Math.floor((now - date) / 1000); let interval = seconds / 31536000; if (interval > 1) { return Math.floor(interval) + " years"; } interval = seconds / 2592000; if (interval > 1) { return `${chalk.red(Math.floor(interval) + " months")}`; } interval = seconds / 86400; if (interval > 1) { const days = Math.floor(interval); return `${chalk[days >= 14 ? 'yellow' : 'green'](days + " days")}`; } interval = seconds / 3600; if (interval > 1) { return `${chalk.green(Math.floor(interval) + " hours")}`; } interval = seconds / 60; if (interval > 1) { return `${chalk.green(Math.floor(interval) + " minutes")}`; } return Math.floor(seconds) + " seconds"; } tto.line('-'); tto.pushrow(['| status', 'stack', 'branch', 'time since update', 'url']) .line('-'); for (const stack of curratedStacks) { const t = new Date(stack.updated); tto.pushrow([status(stack.status), stack.name, ellipsis(stack.branch, 24), timeSince(t.getTime()), stackUrl(stack.name)]); } tto.print(true); if (toolbox.fromMenu()) { await toolbox.menu.showMenu('deployment testservers', defaultMenuSettings); } } }