UNPKG

mediumroast_js

Version:

A Command Line Interface (CLI) and Javascript SDK to interact with Mediumroast for GitHub.

275 lines (263 loc) 11.5 kB
/** * A class used for consistent outputting of CLI data * @author Michael Hay <michael.hay@mediumroast.io> * @file output.js * @copyright 2023 Mediumroast, Inc. All rights reserved. * @license Apache-2.0 * @version 2.2.0 */ // Import required modules import Table from 'cli-table3' import {Parser} from '@json2csv/plainjs' // import * as XLSX from 'xlsx' import logo from 'asciiart-logo' import FilesystemOperators from './filesystem.js' class CLIOutput { /** * A class to enable consistent output formatting for CLI operations * @constructor * @classdesc Construct utilities, environmental variables and the object type * @param {Object} env - An object containing all needed environmental variables * @param {String} objectType - A string that contains the type of object using this module */ constructor(env, objectType) { this.env = env this.objectType = objectType this.fileSystem = new FilesystemOperators() } /** * @function outputCLI * @description An output router enabling users to pick their output format of choice for a CLI * @param {String} outputType Type of output to produce/route to: table, json, csv, xls * @param {Object} results Data objects to be output */ outputCLI(results, outputType='table') { // Emit the output as per the cli options if (outputType === 'table') { this.outputTable(results) } else if (outputType === 'json') { console.log(JSON.stringify(results, null, 2)) } else if (outputType === 'csv') { this.outputCSV(results) } else if (outputType === 'xls') { this.outputXLS(results) } } // NOTE: Not exterally facing doesn't require JSDoc signture // Purpose: Output an ASCII formatted table with key object metadata to the console outputTable(objects) { // User objects output // Note: The separation between User and other objects is due to their structure. Pointedly // user objects do not contain name and description fields. let table if (this.objectType === 'Users') { table = new Table({ head: ['GitHub Id', 'Login', 'User Type', 'Role Name', 'Site Admin'], }) // NOTE: In this alpha version users aren't yet operable for (const myObj in objects) { table.push([ objects[myObj].id, objects[myObj].login, objects[myObj].type, objects[myObj].role_name, objects[myObj].site_admin ]) } } else if (this.objectType === 'Org') { table = new Table({ head: ['Id', 'Name', 'GitHub Url', 'Description'], }) for (const myObj in objects) { table.push([ objects[myObj].id !== null ? objects[myObj].id : 'No Id', objects[myObj].name !== null ? objects[myObj].name : 'No Name', objects[myObj].html_url !== null ? objects[myObj].html_url : 'No GitHub Url', objects[myObj].description !== null ? objects[myObj].description : 'No Description' ]) } } else if (this.objectType === 'MyUser') { table = new Table({ head: ['GitHub Id', 'Login', 'Name', 'Type', 'Company', 'GitHub Website'], }) for (const myObj in objects) { table.push([ objects[myObj].id !== null ? objects[myObj].id : 'No Id', objects[myObj].login !== null ? objects[myObj].login : 'No Login', objects[myObj].name !== null ? objects[myObj].name : 'No Name', objects[myObj].type !== null ? objects[myObj].type : 'No Type', objects[myObj].company !== null ? objects[myObj].company : 'No Company', objects[myObj].html_url !== null ? objects[myObj].html_url : 'No GitHub Website' ]) } // Study, Company and Interaction objects output } else if (this.objectType === 'Companies') { table = new Table({ head: ['Name', 'Role', 'Interaction Count', 'Region', 'Description'], colWidths: [27, 12, 19, 8, 50] }) for (const myObj in objects) { let totalInteractions = 0 if (Object.keys(objects[myObj].linked_interactions).length) { totalInteractions = Object.keys(objects[myObj].linked_interactions).length } table.push([ objects[myObj].name, objects[myObj].role, totalInteractions, objects[myObj].region, objects[myObj].description ]) } } else if (this.objectType === 'Interactions') { table = new Table({ head: ['Name', 'Creator Name', 'Region', 'Linked Company'], colWidths: [70, 15, 10, 25] }) for (const myObj in objects) { let linkedCompany = 'Orphaned' if(Object.keys(objects[myObj].linked_companies).length) { linkedCompany = Object.keys(objects[myObj].linked_companies)[0] } table.push([ objects[myObj].name, objects[myObj].creator_name, objects[myObj].region, linkedCompany ]) } } else if (this.objectType === 'ActionsBilling') { table = new Table({ head: ['Minutes Used', 'Paid Minutes Used', 'Minutes Remaining', 'Included Minutes'], }) for (const myObj in objects) { table.push([ objects[myObj].total_minutes_used + ' min', objects[myObj].total_paid_minutes_used + ' min', objects[myObj].included_minutes - objects[myObj].total_minutes_used + objects[myObj].total_paid_minutes_used + ' min', objects[myObj].included_minutes + ' min', ]) } } else if (this.objectType === 'StorageBilling') { table = new Table({ head: ['Storage Used', 'Paid Storage Used', 'Estimated Storage Used', 'Days Left in Cycle'], }) for (const myObj in objects) { table.push([ Math.abs(objects[myObj].estimated_paid_storage_for_month - objects[myObj].estimated_storage_for_month) + ' GiB', objects[myObj].estimated_storage_for_month + ' GiB', objects[myObj].estimated_paid_storage_for_month + ' GiB', objects[myObj].days_left_in_billing_cycle + ' days', ]) } } else if (this.objectType === 'Workflows') { table = new Table({ head: ['Name', 'Id', 'Status', 'Trigger', 'Runtime (min)'], }) for (const myObj in objects.slice(-5)) { table.push([ objects[myObj].name, objects[myObj].workflowId, objects[myObj].conclusion, objects[myObj].event, objects[myObj].runTimeMinutes + ' min' ]) } } else if (this.objectType === 'Storage') { table = new Table({ head: ['Reposistory', 'Organization', 'File Count', 'Size (MB)'], }) for (const myObj in objects.slice(-5)) { table.push([ objects[myObj].name, objects[myObj].org, objects[myObj].numFiles, objects[myObj].size + ' MB', ]) } } else { table = new Table({ head: ['Name', 'Description'], colWidths: [35, 70] }) for (const myObj in objects) { table.push([ objects[myObj].name, objects[myObj].description ]) } } console.log(table.toString()) } // NOTE: Not exterally facing doesn't require JSDoc signture // Purpose: Output a CSV file to this.env.outputDir containing all object metadata outputCSV(objects) { const fileName = 'Mr_' + this.objectType + '.csv' const myFile = this.env.outputDir + '/' + fileName const csvParser = new Parser() try { const csv = csvParser.parse(objects) this.fileSystem.saveTextOrBlobFile(myFile, csv) console.log(`SUCCESS: wrote [${this.objectType}] objects to [${myFile}]`) return [true, {status_code: 200, status_msg: `wrote [${this.objectType}] objects to [${myFile}]`}, null] } catch (err) { console.error(`ERROR: Unable to write [${this.objectType}] objects to [${myFile}] due to [${err}]`) return [false, {}, err] } } // NOTE: Not exterally facing doesn't require JSDoc signture // Purpose: Output an XLSX file to this.env.outputDir containing all object metadata outputXLS(objects) { console.log('NOTICE: XLSX output is presently disabled, a future version will reenable it.') return [false, {status_code: 501, status_msg: 'ERROR: XLSX output is presently disabled'}, null] // NOTE: // const fileName = 'Mr_' + this.objectType + '.xlsx' // const myFile = this.env.outputDir + '/' + fileName // try { // const mySheet = XLSX.utils.json_to_sheet(objects) // const myWorkbook = XLSX.utils.book_new() // XLSX.utils.book_append_sheet(myWorkbook, mySheet, this.objectType) // XLSX.writeFile(myWorkbook, myFile) // return [true, null] // } catch (err) { // return [false, err] // } } /** * @function splashScreen * @description print a splash screen with using name as the big title, description as the subtitle and a version declaration * @param {String} name Used for the big title on the splash screen. * @param {String} description Forms the subtitle on the splash screen. * @param {String} version Defines the version number on the splash screen. */ splashScreen (name, description, version) { const logoConfig = { name: name, lineChars: 10, padding: 3, margin: 3, borderColor: 'bold-gray', logoColor: 'bold-orange', textColor: 'orange', } // Print out the splash screen console.clear() console.log( logo(logoConfig) .emptyLine() .right(version) .emptyLine() .center(description) .render() ) } /** * @function printLine * @description print line for separation in various steps */ printLine () { const line = '-'.repeat(process.stdout.columns) console.log(line) } } export default CLIOutput