savory
Version:
A command-line interface for operating your Codefresh account
117 lines (114 loc) • 6.08 kB
JavaScript
const
_ = require('lodash'),
fp = require('lodash/fp'),
yargs = require('yargs'),
https = require('https'),
kefir = require('kefir'),
chalk = require('chalk'),
Firebase = require('firebase'),
stripAnsi = require('strip-ansi'),
{ simpleHash } = require('../../lib/util'),
{ middleware: httpClientMiddleware } = require('../../lib/api_client'),
{ errorFormatter } = require('../style');
const
MIN_SIDEBAR_WIDTH = 5,
MAX_SIDEBAR_WIDTH = 12,
DEFAULT_WIDTH = 80,
COLOR_WHEEL = ["yellow", "blueBright", "magentaBright", "cyanBright", "whiteBright", "redBright"].map((color)=> chalk[color]),
MONITOR_TIMEOUT = 10 * 60 * 1000;
module.exports = {
command: "dump <build-id>",
description: "Dumps all the logs associated with a build",
builder: (yargs)=> {
return yargs.positional('build-id', {
type: "string"
});
},
handler: fp.pipe(httpClientMiddleware, ({ _httpClient, buildId })=> {
kefir
.fromPromise(_httpClient(["builds", buildId].join('/')))
.flatMap(fp.pipe(fp.get('progress_id'), (id)=> ["progress", id].join('/'), _httpClient, kefir.fromPromise))
.flatMap((progress)=> {
const [type, url, progressId] = fp.at(["location.type", "location.url", "_id"], progress);
return ({
"gcs": ()=> {
let req = https.get(url);
return kefir
.merge([
kefir.fromEvents(req, 'error').flatMap(kefir.constantError),
kefir
.fromEvents(req, 'response')
.take(1)
.flatMap(
(res)=> kefir
.fromEvents(res, 'data')
.takeUntilBy(kefir.fromEvents(res, 'end').take(1))
.scan(fp.concat, [])
.last()
.map(fp.pipe(
Buffer.concat,
(buf)=> buf.toString(),
JSON.parse,
fp.get('steps'),
fp.map(({ name, logs })=> logs.map((line)=> ({ name, line })))
))
)
.flatten()
])
.flatten()
.takeUntilBy(kefir.fromEvents(req, 'end').take(1));
},
"firebase": ()=> {
return kefir
.fromPromise(_httpClient('user/firebaseAuth'))
.flatMap(({ url: applicationUrl, accessToken })=> {
const firebaseClient = new Firebase(`${applicationUrl}`);
return kefir.fromNodeCallback((cb)=> firebaseClient.authWithCustomToken(accessToken, cb)).map(()=> firebaseClient);
})
.flatMap((client)=> {
let progressClient = client.child(`/build-logs/${progressId}`);
return kefir
.fromEvents(progressClient.child('steps'), 'child_added')
.flatMap((stepSnapshot)=> {
let stepName = _.get(stepSnapshot.val(), 'name');
return kefir
.fromEvents(stepSnapshot.ref().child('logs'), 'child_added')
.map((snapshot)=> ({ line: snapshot.val(), name: stepName }));
})
.takeUntilBy(
kefir
.fromEvents(progressClient.child('status'), 'value')
.map((snapshot)=> snapshot.val())
.filter((status)=> ['success', 'error', 'terminated'].includes(status))
.merge(kefir.later(MONITOR_TIMEOUT))
.take(1)
);
});
}
}[type] || (()=> kefir.constantError(new Error('Unsupported log source'))))(url);
})
.takeErrors(1)
.map(function(sidebarWidth){
return ({ name, line })=>
_(line)
.thru(stripAnsi)
.split(/\r?\n|\r/g)
.compact()
.flatMap((line)=> {
return _(line)
.chunk((yargs.terminalWidth() || DEFAULT_WIDTH) - (sidebarWidth + 3))
.map(fp.join(''))
.value();
})
.map((line)=> [
_(name).chain().truncate({ length: sidebarWidth, omission: ".." }).padEnd(sidebarWidth).thru(COLOR_WHEEL[Math.abs(simpleHash(name) % COLOR_WHEEL.length)]).value(),
line
].join(' | '))
.join('\n');
}(_.clamp(~~((yargs.terminalWidth() || DEFAULT_WIDTH) / 10), MIN_SIDEBAR_WIDTH, MAX_SIDEBAR_WIDTH)))
.filter(Boolean)
.onValue(console.log)
.onError(fp.pipe(errorFormatter, console.warn))
.onEnd(()=> process.exit()); // <-- Firebase keeps connection open
})
};