briareus
Version:
Briareus assists with Feature Branch deploys to ECS
200 lines (162 loc) • 5.53 kB
JavaScript
'use static'
const readline = require('readline');
const moment = require('moment');
const colors = require('colors/safe');
const indent = require('indent');
const EventEmitter = require('events');
const DeploymentRenderer = require('../../node_modules/ecs-deployment-monitor/lib/renderer');
const indentWidth = 4;
var _spinner;
class Renderer {
/**
* watch
*
* Watch a deployment and render information about state changes to output stream.
*
* @param {object} variant A task object
* @param {stream} output A stream. If process.stdout then tty is assumed and
* it will be sent decorative output
*/
constructor(variant, output) {
this.variant = variant;
this.output = output;
this.hasShownInfoBanner = false;
// If output is a tty then force color output
if (this.output instanceof require('tty').WriteStream) colors.enable();
variant.on('event', (data) => this._eventProcess(data));
}
/**
* _showWaitingMessage
*
* Show a temporary waiting message while state is in progress.
*/
_showWaitingMessage(msg) {
// Only shown if output is a tty (process.stdout).
if (!(this.output instanceof require('tty').WriteStream)) return;
let spinnerSymbols = ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];
let i = 0;
_spinner = setInterval(() => {
readline.clearLine(this.output);
readline.cursorTo(this.output, indentWidth - 2);
this.output.write(colors.cyan(spinnerSymbols[i % spinnerSymbols.length]));
this.output.write(' ' + colors.gray(msg));
i++;
}, 1000);
}
/**
* _removeWaitingMessage
*
* Remove the waiting message
*/
_removeWaitingMessage() {
clearInterval(_spinner);
readline.clearLine(this.output);
readline.cursorTo(this.output, 0);
}
/**
* _getStateDurationText
*
* Get the duration the current state has been in progress for in
* descriptive text form.
*
* @param {integer} durationSeconds Duration in seconds
* @return {string}
*/
_getStateDurationText(durationSeconds) {
let duration = moment.duration(durationSeconds, 'seconds');
let durationText = `${duration.seconds()} seconds`;
if (duration.minutes()) {
durationText = `${duration.minutes()} minutes ${durationText}`
}
if (duration.hours()) {
durationText = `${duration.hours()} hours ${durationText}`
}
return durationText;
}
/**
* _eventProcess
*
* Process an event change on a deployment
*
* @param {string} event The event
*/
_eventProcess(event) {
switch (event.name) {
case 'exec:start':
this._showInfoBanner(event);
break;
case 'phase:start':
this._startPhase(event);
break;
case 'action:start':
this._startAction(event);
break;
case 'action:error':
this._errorAction(event);
break;
case 'action:complete':
this._completeAction(event);
break;
case 'deploy:end':
this._showDeployCompleteBanner(event)
break;
}
}
_showInfoBanner(event) {
if (this.hasShownInfoBanner) return false;
let screenWidth = 80;
let textColor = 'gray';
let borderColor = 'gray';
let borderChar = '+';
function drawTextLine(text) {
return colors[borderColor](borderChar) + " " + colors[textColor](text);
}
let banner = `
${colors[borderColor]("".padStart(screenWidth, borderChar))}
${' Slug: ' + this.variant.data.slug}
${' HashedSlug: ' + this.variant.data.hashedSlug}
${' Endpoint: ' + this.variant.data.endpoint.url}
${colors[borderColor]("".padStart(screenWidth, borderChar))}
`
this.output.write(banner + "\n");
this.hasShownInfoBanner = true
}
_startPhase(event) {
this.output.write(colors.cyan(`${event.data.phase.message} \n`));
this.output.write(colors.cyan("=".repeat(event.data.phase.message.length)) + "\n");
this.output.write("\n");
}
_startAction(event) {
this.output.write(colors.cyan(`-> ${event.data.action.id} \n`));
if (event.data.action.message) {
this._showWaitingMessage(event.data.action.message);
}
}
_errorAction(event) {
this._removeWaitingMessage();
this.output.write(colors.red(`-> ${event.data.action.id} \n`));
this.output.write(indent(colors.red(event.data.action.message), indentWidth) + "\n");
if (event.data.action.extra) {
this.output.write(indent(colors.red(event.data.action.extra), indentWidth) + "\n");
}
}
_completeAction(event) {
this._removeWaitingMessage();
let message = indent(colors.green('✓') + " " + colors.gray(event.data.action.message), indentWidth - 2);
if (event.data.monitor) {
if (event.data.monitor.isSteady) message = indent(colors.green(event.data.action.message), indentWidth)
if (event.data.monitor.isFailure) message = indent(colors.red(event.data.action.message), indentWidth)
}
this.output.write(message + "\n");
if (event.data.action.id !== 'Steady') {
this.output.write(indent(colors.gray(`Step took ${this._getStateDurationText(event.data.action.duration)} to complete`), indentWidth) + "\n");
}
this.output.write("\n");
}
_showDeployCompleteBanner(event) {
// Don't show banner if we have an error
if (event.data.error) return;
this.output.write(colors.green(`Briareus has successfully deployed the build to ${this.variant.data.endpoint.url}\n`))
}
}
module.exports = Renderer;