diff --git a/src/commands/activate.ts b/src/commands/activate.ts index 4b1a0053..b59780ec 100644 --- a/src/commands/activate.ts +++ b/src/commands/activate.ts @@ -63,7 +63,7 @@ export async function handler( checkConfigForCredentials(config); - printActivateConfig(config); + printActivateConfig(config, flags.outputFormat); const details = config.buildSid ? `(${config.buildSid})` @@ -78,7 +78,7 @@ export async function handler( `Activated new build ${details} on ${config.targetEnvironment || 'production'}` ); - printActivateResult(result); + printActivateResult(result, flags.outputFormat); } catch (err) { handleError(err, spinner); } diff --git a/src/commands/deploy.ts b/src/commands/deploy.ts index cc152b32..a8b4b787 100644 --- a/src/commands/deploy.ts +++ b/src/commands/deploy.ts @@ -74,7 +74,6 @@ export async function handler( externalCliOptions?: ExternalCliOptions ): Promise { setLogLevelByName(flags.logLevel); - const cwd = flags.cwd ? path.resolve(flags.cwd) : process.cwd(); flags.cwd = cwd; const command = getFullCommand(flags); @@ -100,7 +99,7 @@ export async function handler( checkConfigForCredentials(config); - printConfigInfo(config); + printConfigInfo(config, flags.outputFormat); const spinner = getOraSpinner('Deploying Function').start(); try { @@ -111,7 +110,7 @@ export async function handler( const result = await client.deployLocalProject(config); spinner.text = 'Serverless project successfully deployed\n'; spinner.succeed(); - printDeployedResources(config, result); + printDeployedResources(config, result, flags.outputFormat); const { serviceSid, buildSid } = result; await saveLatestDeploymentData( config.cwd, diff --git a/src/commands/list-templates.ts b/src/commands/list-templates.ts index b15855e3..ee421c70 100644 --- a/src/commands/list-templates.ts +++ b/src/commands/list-templates.ts @@ -1,10 +1,9 @@ -import chalk from 'chalk'; import { Arguments } from 'yargs'; import { fetchListOfTemplates } from '../templating/actions'; import { getOraSpinner, setLogLevelByName } from '../utils/logger'; -import { writeOutput } from '../utils/output'; import { baseCliOptions, BaseFlags } from './shared'; import { CliInfo } from './types'; +import { printTemplates } from '../printers/list-templates'; export async function handler(flags: Arguments): Promise { setLogLevelByName(flags.logLevel); @@ -21,11 +20,7 @@ export async function handler(flags: Arguments): Promise { spinner.stop(); - templates.forEach(template => { - writeOutput( - chalk`‣ ${template.name} ({cyan ${template.id}})\n {dim ${template.description}}` - ); - }); + printTemplates(templates, flags.outputFormat); } export const cliInfo: CliInfo = { options: { ...baseCliOptions } }; diff --git a/src/commands/list.ts b/src/commands/list.ts index 875c5d7b..220d3fe4 100644 --- a/src/commands/list.ts +++ b/src/commands/list.ts @@ -39,7 +39,6 @@ export async function handler( externalCliOptions?: ExternalCliOptions ): Promise { setLogLevelByName(flags.logLevel); - let config: ListConfig; try { config = await getConfigFromFlags(flags, externalCliOptions); @@ -66,7 +65,7 @@ export async function handler( try { const client = new TwilioServerlessApiClient(config); const result = await client.list({ ...config }); - printListResult(result, config); + printListResult(result, config, flags.outputFormat); } catch (err) { handleError(err); } diff --git a/src/commands/logs.ts b/src/commands/logs.ts index dcc0e169..eedcea58 100644 --- a/src/commands/logs.ts +++ b/src/commands/logs.ts @@ -42,7 +42,6 @@ export async function handler( externalCliOptions?: ExternalCliOptions ): Promise { setLogLevelByName(flags.logLevel); - let config: LogsConfig; try { config = await getConfigFromFlags(flags, externalCliOptions); @@ -68,11 +67,11 @@ export async function handler( if (flags.tail) { const stream = await client.getLogsStream({ ...config }); stream.on('data', (log: LogApiResource) => { - printLog(log, config.outputFormat); + printLog(log, flags.outputFormat); }); } else { const result = (await client.getLogs({ ...config })) as LogApiResource[]; - printLogs(result, config, config.outputFormat); + printLogs(result, flags.outputFormat); } } catch (err) { handleError(err); @@ -100,13 +99,6 @@ export const cliInfo: CliInfo = { type: 'boolean', describe: 'Continuously stream the logs', }, - 'output-format': { - type: 'string', - alias: 'o', - default: '', - describe: 'Output the log in a different format', - choices: ['', 'json'], - }, env: { type: 'string', describe: diff --git a/src/commands/new.ts b/src/commands/new.ts index 1655a994..9558e3f3 100644 --- a/src/commands/new.ts +++ b/src/commands/new.ts @@ -9,6 +9,7 @@ import { setLogLevelByName, logger } from '../utils/logger'; import { baseCliOptions, BaseFlags, ExternalCliOptions } from './shared'; import { CliInfo } from './types'; import { getFullCommand } from './utils'; +import { printNewResult } from '../printers/new'; export type NewCliFlags = Arguments< BaseFlags & { @@ -114,6 +115,7 @@ export async function handler( try { await downloadTemplate(flags.template, sanitizedNamespace, targetDirectory); + printNewResult(sanitizedNamespace, flags.template); } catch (error) { logger.error(error.message, error.name); } diff --git a/src/commands/shared.ts b/src/commands/shared.ts index dd8cf7da..a62845b5 100644 --- a/src/commands/shared.ts +++ b/src/commands/shared.ts @@ -1,8 +1,11 @@ import { Options } from 'yargs'; import { LoggingLevel, LoggingLevelNames } from '../utils/logger'; +export type OutputFormat = 'json' | 'pretty' | undefined; + export type BaseFlags = { logLevel: LoggingLevelNames; + outputFormat: OutputFormat; }; export type SharedFlags = BaseFlags & { @@ -36,6 +39,13 @@ export const baseCliOptions: { [key: string]: Options } = { describe: 'Level of logging messages.', choices: Object.keys(LoggingLevel), }, + 'output-format': { + type: 'string', + default: 'pretty', + alias: 'o', + describe: 'Format of command output.', + choices: ['json', 'pretty'], + }, }; export const sharedApiRelatedCliOptions: { [key: string]: Options } = { diff --git a/src/config/logs.ts b/src/config/logs.ts index 6c880fbd..1aa85d5f 100644 --- a/src/config/logs.ts +++ b/src/config/logs.ts @@ -21,7 +21,6 @@ export type LogsConfig = ClientConfig & accountSid: string; authToken: string; properties?: string[]; - outputFormat?: string; }; export type LogsCliFlags = Arguments< @@ -31,7 +30,6 @@ export type LogsCliFlags = Arguments< serviceSid?: string; functionSid?: string; tail: boolean; - outputFormat?: string; } >; @@ -64,7 +62,6 @@ export async function getConfigFromFlags( const command = getFullCommand(flags); const serviceSid = checkForValidServiceSid(command, flags.serviceSid); - const outputFormat = flags.outputFormat || externalCliOptions?.outputFormat; const region = flags.region; const edge = flags.edge; @@ -74,7 +71,6 @@ export async function getConfigFromFlags( authToken, environment, serviceSid, - outputFormat, filterByFunction: flags.functionSid, tail: flags.tail, region, diff --git a/src/printers/activate.ts b/src/printers/activate.ts index c211994a..ac9948d9 100644 --- a/src/printers/activate.ts +++ b/src/printers/activate.ts @@ -1,12 +1,19 @@ import { ActivateConfig, ActivateResult } from '@twilio-labs/serverless-api'; import { stripIndent } from 'common-tags'; import { logger } from '../utils/logger'; -import { writeOutput } from '../utils/output'; +import { writeOutput, writeJSONOutput } from '../utils/output'; import { getTwilioConsoleDeploymentUrl, redactPartOfString } from './utils'; import chalk = require('chalk'); import terminalLink = require('terminal-link'); +import { OutputFormat } from '../commands/shared'; -export function printActivateConfig(config: ActivateConfig) { +export function printActivateConfig( + config: ActivateConfig, + outputFormat: OutputFormat +) { + if (outputFormat === 'json') { + return; + } const message = chalk` {cyan.bold Account} ${config.accountSid} {cyan.bold Token} ${redactPartOfString(config.authToken)} @@ -14,7 +21,15 @@ export function printActivateConfig(config: ActivateConfig) { logger.info(stripIndent(message) + '\n'); } -export function printActivateResult(result: ActivateResult) { +export function printActivateResult( + result: ActivateResult, + outputFormat: OutputFormat +) { + if (outputFormat === 'json') { + writeJSONOutput(result, null, '\t'); + return; + } + logger.info(chalk.cyan.bold('\nActive build available at:')); writeOutput(result.domain); diff --git a/src/printers/deploy.ts b/src/printers/deploy.ts index d8dd139a..c361eb7c 100644 --- a/src/printers/deploy.ts +++ b/src/printers/deploy.ts @@ -10,13 +10,14 @@ import { stripIndent } from 'common-tags'; import terminalLink from 'terminal-link'; import { MergeExclusive } from 'type-fest'; import { logger } from '../utils/logger'; -import { writeOutput } from '../utils/output'; +import { writeOutput, writeJSONOutput } from '../utils/output'; import { getTwilioConsoleDeploymentUrl, printObjectWithoutHeaders, redactPartOfString, shouldPrettyPrint, } from './utils'; +import { OutputFormat } from '../commands/shared'; function sortByAccess< T extends MergeExclusive @@ -83,7 +84,7 @@ function prettyPrintConfigInfo(config: DeployLocalProjectConfig) { } logger.info('\nDeploying functions & assets to the Twilio Runtime'); - writeOutput( + logger.info( chalk` {bold.cyan Account}\t\t${config.accountSid} {bold.cyan Token}\t\t${redactPartOfString(config.authToken)} @@ -171,7 +172,13 @@ function prettyPrintDeployedResources( } } -export function printConfigInfo(config: DeployLocalProjectConfig) { +export function printConfigInfo( + config: DeployLocalProjectConfig, + outputFormat: OutputFormat +) { + if (outputFormat === 'json') { + return; + } if (shouldPrettyPrint) { prettyPrintConfigInfo(config); } else { @@ -181,8 +188,13 @@ export function printConfigInfo(config: DeployLocalProjectConfig) { export function printDeployedResources( config: DeployLocalProjectConfig, - result: DeployResult + result: DeployResult, + outputFormat: OutputFormat ) { + if (outputFormat === 'json') { + writeJSONOutput(result); + return; + } if (shouldPrettyPrint) { prettyPrintDeployedResources(config, result); } else { diff --git a/src/printers/list-templates.ts b/src/printers/list-templates.ts new file mode 100644 index 00000000..6bc2cd3f --- /dev/null +++ b/src/printers/list-templates.ts @@ -0,0 +1,34 @@ +import chalk from 'chalk'; +import { Template } from '../templating/data'; +import { writeOutput, writeJSONOutput } from '../utils/output'; +import { OutputFormat } from '../commands/shared'; +import { shouldPrettyPrint } from './utils'; + +function prettyPrintTemplates(templates: Template[]) { + templates.forEach(template => { + writeOutput( + chalk`‣ ${template.name} ({cyan ${template.id}})\n {dim ${template.description}}` + ); + }); +} + +function plainPrintTemplates(templates: Template[]) { + templates.forEach(template => { + writeOutput(`${template.name} (${template.id})\n ${template.description}`); + }); +} + +export function printTemplates( + templates: Template[], + outputFormat: OutputFormat +) { + if (outputFormat === 'json') { + writeJSONOutput(templates); + return; + } + if (shouldPrettyPrint) { + prettyPrintTemplates(templates); + } else { + plainPrintTemplates(templates); + } +} diff --git a/src/printers/list.ts b/src/printers/list.ts index bce8ffd4..cd439c7a 100644 --- a/src/printers/list.ts +++ b/src/printers/list.ts @@ -16,8 +16,9 @@ import logSymbols from 'log-symbols'; import title from 'title'; import { ListConfig } from '../config/list'; import { logger } from '../utils/logger'; -import { writeOutput } from '../utils/output'; +import { writeOutput, writeJSONOutput } from '../utils/output'; import { redactPartOfString, shouldPrettyPrint, windowSize } from './utils'; +import { OutputFormat } from '../commands/shared'; type KeyMaps = { [key in ListOptions]: string[]; @@ -313,7 +314,15 @@ function printListResultTerminal(result: ListResult, config: ListConfig): void { writeOutput(output); } -export function printListResult(result: ListResult, config: ListConfig): void { +export function printListResult( + result: ListResult, + config: ListConfig, + outputFormat: OutputFormat +): void { + if (outputFormat === 'json') { + writeJSONOutput(result); + return; + } if (shouldPrettyPrint && !config.properties && !config.extendedOutput) { printListResultTerminal(result, config); } else { diff --git a/src/printers/logs.ts b/src/printers/logs.ts index 15bda668..2a56d332 100644 --- a/src/printers/logs.ts +++ b/src/printers/logs.ts @@ -1,16 +1,16 @@ import { LogList, LogApiResource } from '@twilio-labs/serverless-api'; import { LogsConfig } from '../config/logs'; import { writeOutput } from '../utils/output'; +import { OutputFormat } from '../commands/shared'; export function printLogs( result: LogApiResource[], - config: LogsConfig, - outputFormat?: string + outputFormat: OutputFormat ) { result.forEach(log => printLog(log, outputFormat)); } -export function printLog(log: LogApiResource, outputFormat?: string) { +export function printLog(log: LogApiResource, outputFormat: OutputFormat) { if (outputFormat === 'json') { writeOutput(JSON.stringify(log)); } else { diff --git a/src/printers/new.ts b/src/printers/new.ts index e69de29b..c26ba5f7 100644 --- a/src/printers/new.ts +++ b/src/printers/new.ts @@ -0,0 +1,16 @@ +import chalk from 'chalk'; +import { logger } from '../utils/logger'; +import { join } from 'path'; + +export function printNewResult(namespace: string, templateName: string) { + logger.info( + chalk`{green SUCCESS} Downloaded new template into the "${namespace}" subdirectories.` + ); + logger.info( + `Check ${join( + 'readmes', + namespace, + `${templateName}.md` + )} for template instructions.` + ); +} diff --git a/src/templating/actions.ts b/src/templating/actions.ts index 4cdd03af..bef2fb3d 100644 --- a/src/templating/actions.ts +++ b/src/templating/actions.ts @@ -1,8 +1,5 @@ -import chalk from 'chalk'; -import { logger } from '../utils/logger'; import { getTemplateFiles } from './data'; import { writeFiles } from './filesystem'; -import path from 'path'; export async function downloadTemplate( templateName: string, @@ -10,18 +7,7 @@ export async function downloadTemplate( targetDirectory: string ): Promise { const files = await getTemplateFiles(templateName); - await writeFiles(files, targetDirectory, namespace, templateName); - logger.info( - chalk`{green SUCCESS} Downloaded new template into the "${namespace}" subdirectories.` - ); - logger.info( - `Check ${path.join( - 'readmes', - namespace, - `${templateName}.md` - )} for template instructions.` - ); } export { fetchListOfTemplates } from './data'; diff --git a/src/utils/output.ts b/src/utils/output.ts index 113eb6a6..b10db1a0 100644 --- a/src/utils/output.ts +++ b/src/utils/output.ts @@ -1,3 +1,7 @@ export function writeOutput(...args: any[]) { console.log(...args); } + +export function writeJSONOutput(...args: any[]) { + writeOutput(JSON.stringify(args, null, '\t')); +}