Files
pwcli/src/commands/deployment/testservers/status/status.ts
T

229 lines
6.6 KiB
TypeScript

import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu';
import chalk = require('chalk');
import { defaultMenuSettings, getSettings } from '../../../../globals';
import { getTestStacksInfo } from '../../../../common/testservers';
import { getIssueFromRepo } from '../../../../services/github_rest';
const tto = require('terminal-table-output').create();
module.exports = {
name: 'status',
alias: ['s'],
description: 'Show status for available testservers (s)',
hidden: false,
run: async (toolbox: GluegunMenuToolbox) => {
// Load settings
const config = await getSettings(toolbox);
if (!config) {
await toolbox.menu.showMenu('setup', defaultMenuSettings);
return;
}
const testStacks = await getTestStacksInfo(toolbox);
const status = (status: string) => {
switch (status) {
case 'UPDATE_FAILED':
case 'CREATE_FAILED':
case 'ROLLBACK_COMPLETE':
return `(${chalk.red('FAILED')})`;
case 'UPDATE_IN_PROGRESS':
case 'CREATE_IN_PROGRESS':
return `(${chalk.yellow('IN PROGRESS')})`;
case 'UPDATE_COMPLETE':
case 'CREATE_COMPLETE':
return `(${chalk.green('OK')})`;
default:
return `(${chalk.red.bold('?')})`;
}
};
const getStatusIcon = (status: string): string => {
switch (status) {
case 'open':
return '✅ open';
case 'closed':
return '❌ closed';
case 'null':
return '❔ unknown';
}
};
const getIssueStatus = async (issueNumber: string) => {
if (!issueNumber) return getStatusIcon('null'); // GUARD
const issueData = await getIssueFromRepo(
toolbox,
config.gh_token,
'photowall',
issueNumber,
);
return {
issue: issueNumber,
status: getStatusIcon(issueData ? issueData.state : 'null'),
issueUpdated: issueData ? issueData.updated_at : null,
};
};
const printIssueStatus = (
issueStatuses: { issue: string; status: string }[],
issueNumber: string,
) => {
const issueStatus = issueStatuses.find(
(issueStatus) => issueStatus.issue === issueNumber,
);
return issueStatus ? issueStatus.status : getStatusIcon('null');
};
const stackUrl = (stackname: string) => {
return `https://test-${
stackname.split('photowall-test-')[1]
}.photowall-test.com/us`;
};
const ellipsis = (a: string, max: number) => {
if (a) {
return a.length > max ? a.substr(0, max) + '..' : a;
} else {
return a;
}
};
const timeSince = (date: number) => {
const now = Date.now();
const seconds = Math.floor((now - date) / 1000);
let interval = seconds / 31536000;
// Years
if (interval > 1) {
return Math.floor(interval) + ' years';
}
// Months
interval = seconds / 2592000;
if (interval > 1) {
return `${chalk.red('WTF!')}`;
}
// Days
interval = seconds / 86400;
if (interval > 1) {
const days = Math.floor(interval);
let color = 'green';
if (days >= 2) {
if (days <= 12) {
// Gradient from yellow (#FFFF00) to dark red (#8B0000) over 10 days (days 2-12)
const gradientColors = [
'#FFFF00', // 2 days - yellow
'#FFE600', // 3 days
'#FFCC00', // 4 days
'#FFB300', // 5 days
'#FF9900', // 6 days
'#FF8000', // 7 days
'#FF6600', // 8 days
'#FF4D00', // 9 days
'#FF3300', // 10 days
'#CC2900', // 11 days
'#8B0000', // 12 days - dark red
];
const colorIndex = Math.min(days - 2, gradientColors.length - 1);
color = gradientColors[colorIndex];
} else {
color = '#8B0000'; // dark red for 12+ days
}
return `${chalk.hex(color)(days + ' days')}`;
} else {
return `${chalk.green(days + ' days')}`;
}
}
// Hours
interval = seconds / 3600;
if (interval > 1) {
return `${chalk.green(Math.floor(interval) + ' hours')}`;
}
// Minutes
interval = seconds / 60;
if (interval > 1) {
return `${chalk.green(Math.floor(interval) + ' minutes')}`;
}
// Seconds
return Math.floor(seconds) + ' seconds';
};
tto.line('-');
tto
.pushrow([
'| status',
'stack',
'branch',
'issue status',
// 'issue updated',
'last commit',
// 'url'
])
.line('-');
// Sort on stackname
testStacks.sort((a, b) => {
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
});
// Get issue status
const issueStatusPromises = [];
for (const stack of testStacks) {
const regex = /^(\d+)/;
const match = stack.branch.match(regex);
const branchIssueNumber = match ? match[1] : null;
if (branchIssueNumber) {
issueStatusPromises.push(getIssueStatus(branchIssueNumber));
}
}
const issueStatuses = await Promise.all(issueStatusPromises);
// Sort the testStacks list on number. They are named like photowall-test-XX where XX is the number.
testStacks.sort((a, b) => {
const aNumber = parseInt(a.name.split('photowall-test-')[1]);
const bNumber = parseInt(b.name.split('photowall-test-')[1]);
return aNumber - bNumber;
});
for (const stack of testStacks) {
const regex = /^(\d+)/;
const match = stack.branch.match(regex);
const branchIssueNumber = match ? match[1] : null;
const t = new Date(stack.updated);
tto.pushrow([
status(stack.status),
stack.name,
ellipsis(stack.branch, 24),
printIssueStatus(issueStatuses, branchIssueNumber),
// issueStatuses.find(
// (issueStatus) => issueStatus.issue === branchIssueNumber,
// )
// ? timeSince(
// new Date(
// issueStatuses.find(
// (issueStatus) => issueStatus.issue === branchIssueNumber,
// ).issueUpdated,
// ).getTime(),
// )
// : '-',
!isNaN(t.getTime())
? timeSince(t.getTime())
: timeSince(new Date(stack.created).getTime()),
// stackUrl(stack.name)
]);
}
tto.print(true);
if (toolbox.fromMenu()) {
await toolbox.menu.showMenu(
'deployment testservers',
defaultMenuSettings,
);
}
},
};