diff --git a/README.md b/README.md index 94e0ab0d..a1f65e91 100644 --- a/README.md +++ b/README.md @@ -287,6 +287,7 @@ cloudsite update your-domain.com |------|------| |``|(_main argument_,_optional_) The command to run or a sub-command group.| |`--format`|Sets the format for the output. May be 'terminal' (default), 'text', 'json', or 'yaml'.| +|`--no-reminders`, `-R`|Suppresses any reminders. Particularly useful for programmatic usage where the extra output might break things.| |`--quiet`, `-q`|Makes informational output less chatty.| |`--sso-profile`|The AWS local SSO profile to use for authentication.| |`--throw-error`|In the case of an exception, the default is to print the message. When --throw-error is set, the exception is left uncaught.| diff --git a/make/55-readme-md.mk b/make/55-readme-md.mk index ddd8a34a..d9c8c2da 100644 --- a/make/55-readme-md.mk +++ b/make/55-readme-md.mk @@ -8,6 +8,6 @@ BUILD_TARGETS+=$(CLOUDSITE_README_BUILT) $(CLOUDSITE_README_BUILT): $(CLOUDSITE_README_PREFIX) $(CLOUDSITE_README_SUFFIX) $(CLOUDSITE_CLI_DEF) cp $(CLOUDSITE_README_PREFIX) $@ echo >> $@ - $(SDLC_CLOUDSITE_EXEC_JS) document >> $@ + $(SDLC_CLOUDSITE_EXEC_JS) --no-reminders document >> $@ cat $(CLOUDSITE_README_SUFFIX) >> $@ diff --git a/src/cli/cloudsite.mjs b/src/cli/cloudsite.mjs index 779fddcb..969a7327 100644 --- a/src/cli/cloudsite.mjs +++ b/src/cli/cloudsite.mjs @@ -26,6 +26,7 @@ const cloudsite = async () => { const argv = mainOptions._unknown || [] const { command/*, quiet */ } = mainOptions + const noReminders = mainOptions['no-reminders'] let db try { @@ -46,7 +47,9 @@ const cloudsite = async () => { configureLogger(globalOptions) - checkReminders({ reminders : db.reminders }) + if (noReminders !== true) { + checkReminders({ reminders : db.reminders }) + } const origDB = structuredClone(db) diff --git a/src/cli/constants.mjs b/src/cli/constants.mjs index 41fdeb32..8f07e980 100644 --- a/src/cli/constants.mjs +++ b/src/cli/constants.mjs @@ -11,6 +11,12 @@ const globalOptionsSpec = [ name : 'format', description : "Sets the format for the output. May be 'terminal' (default), 'text', 'json', or 'yaml'." }, + { + name : 'no-reminders', + alias : 'R', + type : Boolean, + description : 'Suppresses any reminders. Particularly useful for programmatic usage where the extra output might break things.' + }, { name : 'quiet', alias : 'q', type : Boolean, description : 'Makes informational output less chatty.' }, { name : 'sso-profile', description : 'The AWS local SSO profile to use for authentication.' }, { diff --git a/src/cli/lib/check-format.mjs b/src/cli/lib/check-format.mjs index 532e7394..f1f90a04 100644 --- a/src/cli/lib/check-format.mjs +++ b/src/cli/lib/check-format.mjs @@ -1,9 +1,8 @@ -import { errorOut } from './error-out' import { VALID_FORMATS } from '../constants' const checkFormat = (format) => { if (format !== undefined && !VALID_FORMATS.includes(format)) { - errorOut(`Invalid output format '${format}'. Must be one of: ${VALID_FORMATS.join(', ')}`) + throw new Error(`Invalid output format '${format}'. Must be one of: ${VALID_FORMATS.join(', ')}`) } } diff --git a/src/cli/lib/error-out.mjs b/src/cli/lib/error-out.mjs deleted file mode 100644 index 7d83c569..00000000 --- a/src/cli/lib/error-out.mjs +++ /dev/null @@ -1,5 +0,0 @@ -const errorOut = (msg, exitCode = 1) => { - throw new Error(msg, { exitCode }) -} - -export { errorOut } diff --git a/src/cli/lib/get-site-info.mjs b/src/cli/lib/get-site-info.mjs index 17364f10..86d73153 100644 --- a/src/cli/lib/get-site-info.mjs +++ b/src/cli/lib/get-site-info.mjs @@ -1,13 +1,11 @@ -import { errorOut } from './error-out' - const getSiteInfo = ({ apexDomain, db }) => { if (apexDomain === undefined) { - errorOut('Must specify site domain.\n') + throw new Error('Must specify site domain.') } const siteInfo = db.sites[apexDomain] if (siteInfo === undefined) { - errorOut(`No such site '${apexDomain}' found.\n`) + throw new Error(`No such site '${apexDomain}' found.`) } return siteInfo diff --git a/src/cli/lib/get-value-container-and-key.mjs b/src/cli/lib/get-value-container-and-key.mjs index 3a704b18..30976e1f 100644 --- a/src/cli/lib/get-value-container-and-key.mjs +++ b/src/cli/lib/get-value-container-and-key.mjs @@ -1,5 +1,3 @@ -import { errorOut } from './error-out' - const getValueContainerAndKey = ({ path, pathPrefix, rootContainer, skipValueCheck, spec, value }) => { const origPath = (pathPrefix === undefined ? '' : pathPrefix) + path.join('.') // used if validation error if (path === undefined || path.length === 0) { @@ -36,7 +34,7 @@ const getValueContainerAndKey = ({ path, pathPrefix, rootContainer, skipValueChe } else { const currSpec = spec?.[bit] if (currSpec === undefined && i > 0) { - errorOut(`Invalid option path '${origPath}'; no such element '${bit}'.\n`) + throw new Error(`Invalid option path '${origPath}'; no such element '${bit}'.\n`) } const container = currContainer[bit] if (container === undefined) { diff --git a/src/cli/lib/handle-detail.mjs b/src/cli/lib/handle-detail.mjs index 479937fb..323b4235 100644 --- a/src/cli/lib/handle-detail.mjs +++ b/src/cli/lib/handle-detail.mjs @@ -2,7 +2,6 @@ import commandLineArgs from 'command-line-args' import { checkFormat } from './check-format' import { cliSpec } from '../constants' -import { errorOut } from './error-out' import { getOptionsSpec } from './get-options-spec' import { getSiteInfo } from './get-site-info' @@ -13,7 +12,7 @@ const handleDetail = ({ argv, db }) => { const { format } = detailOptions if (apexDomain === undefined) { - errorOut('Apex domain must be specified.') + throw new Error('Apex domain must be specified.') } checkFormat(format) diff --git a/src/cli/lib/handle-import.mjs b/src/cli/lib/handle-import.mjs index 1a1c5465..9717ec23 100644 --- a/src/cli/lib/handle-import.mjs +++ b/src/cli/lib/handle-import.mjs @@ -4,7 +4,6 @@ import commandLineArgs from 'command-line-args' import { cliSpec } from '../constants' import { doImport } from '../../lib/actions/import' -import { errorOut } from './error-out' import { getOptionsSpec } from './get-options-spec' import { processSourceType } from './process-source-type' import { progressLogger } from '../../lib/shared/progress-logger' @@ -27,13 +26,13 @@ const handleImport = async ({ argv, db }) => { const sourceType = processSourceType({ sourcePath, sourceType : importOptions['source-type'] }) if (domainAndStack?.length !== 2) { - errorOut(`Unexpected number of positional arguments, expect 2 (domain and stack name), but got ${domainAndStack?.length || '0'}.\n`) + throw new Error(`Unexpected number of positional arguments, expect 2 (domain and stack name), but got ${domainAndStack?.length || '0'}.\n`) } if (region === undefined) { - errorOut("You must specify the '--region' parameter.\n") + throw new Error("You must specify the '--region' parameter.\n") } if (sourcePath === undefined) { - errorOut("You must specify the '--source-path' parameter.\n") + throw new Error("You must specify the '--source-path' parameter.\n") } let domain, stack @@ -48,13 +47,13 @@ const handleImport = async ({ argv, db }) => { const sitesInfo = db.sites if (sitesInfo[domain] !== undefined && refresh !== true) { - errorOut(`Domain '${domain}' is already in the sites DB. To update/refresh the values, use the '--refresh' option.`) + throw new Error(`Domain '${domain}' is already in the sites DB. To update/refresh the values, use the '--refresh' option.`) } if (domain === undefined) { - errorOut(`Could not determine domain name from arguments (${domainAndStack}).\n`) + throw new Error(`Could not determine domain name from arguments (${domainAndStack}).\n`) } if (stack === undefined) { - errorOut(`Could not determine stack name from arguments (${domainAndStack}).\n`) + throw new Error(`Could not determine stack name from arguments (${domainAndStack}).\n`) } // now, actually do the import diff --git a/src/cli/lib/options.mjs b/src/cli/lib/options.mjs index b9c9a7d8..a89d70d8 100644 --- a/src/cli/lib/options.mjs +++ b/src/cli/lib/options.mjs @@ -1,4 +1,3 @@ -import { errorOut } from './error-out' import { getValueContainerAndKey } from './get-value-container-and-key' import * as plugins from '../../lib/plugins' import { progressLogger } from '../../lib/shared/progress-logger' @@ -20,7 +19,7 @@ const updatePluginSettings = ({ confirmed, doDelete, options, siteInfo }) => { const plugin = plugins[pluginName] if (plugin === undefined) { - errorOut(`No such plugin '${pluginName}'; use one of: ${Object.keys(plugins).join(', ')}.\n`) + throw new Error(`No such plugin '${pluginName}'; use one of: ${Object.keys(plugins).join(', ')}.\n`) } if (siteInfo.plugins === undefined) { @@ -47,7 +46,7 @@ const updatePluginSettings = ({ confirmed, doDelete, options, siteInfo }) => { delete siteInfo.plugins[pluginName] progressLogger.write(`Deleted plugin settings for '${pluginName}'; was:\n${JSON.stringify(pluginSettings, null, ' ')}\n`) } else { - errorOut("Interactive confirmation not yet enabled. Use the '--confirmed' option. Note, this will delete all plugin settings and data and cannot be recovered. You must run 'cloudsite update' for this change to take effect. To re-enable the plugin, you must re-initialize all required settings and update the site.\n", 3) + throw new Error("Interactive confirmation not yet enabled. Use the '--confirmed' option. Note, this will delete all plugin settings and data and cannot be recovered. You must run 'cloudsite update' for this change to take effect. To re-enable the plugin, you must re-initialize all required settings and update the site.\n", 3) } } else if (doDelete === true) { const wasValue = valueContainer[valueKey] diff --git a/src/cli/lib/plugin-settings/handle-plugin-settings-set.mjs b/src/cli/lib/plugin-settings/handle-plugin-settings-set.mjs index 9cb0c3e5..4627ec02 100644 --- a/src/cli/lib/plugin-settings/handle-plugin-settings-set.mjs +++ b/src/cli/lib/plugin-settings/handle-plugin-settings-set.mjs @@ -1,7 +1,6 @@ import commandLineArgs from 'command-line-args' import { cliSpec } from '../../constants' -import { errorOut } from '../error-out' import { getOptionsSpec } from '../get-options-spec' import { getSiteInfo } from '../get-site-info' import * as optionsLib from '../options' @@ -23,17 +22,17 @@ const handlePluginSettingsSet = async ({ argv, db }) => { const siteInfo = getSiteInfo({ apexDomain, db }) if (doDelete === true && name === undefined && options.length === 0) { - errorOut("You must specify a '--name' or at least one '--option' when '--delete' is set.\n") + throw new Error("You must specify a '--name' or at least one '--option' when '--delete' is set.\n") } else if (name !== undefined && (value !== undefined || doDelete === true)) { options.push({ name, value : smartConvert(value) }) // the 'option' values are already converted } else if (name !== undefined && value === undefined) { // but delete is not set (checked above) - errorOut("You must specify a '--value' or '--delete' when '--name' is set.\n") + throw new Error("You must specify a '--value' or '--delete' when '--name' is set.\n") } else if (name === undefined && value !== undefined) { - errorOut("You must specify a '--name' when '--value' is set.\n") + throw new Error("You must specify a '--name' when '--value' is set.\n") } if (doDelete !== true && options.length === 0) { - errorOut("Invalid options; specify '--name'+'--value', '--delete'/'--name', or one or more '--option' options.\n") + throw new Error("Invalid options; specify '--name'+'--value', '--delete'/'--name', or one or more '--option' options.\n") } // take actions and update the options diff --git a/src/cli/lib/process-source-type.mjs b/src/cli/lib/process-source-type.mjs index 0c62c99d..46dd1d7a 100644 --- a/src/cli/lib/process-source-type.mjs +++ b/src/cli/lib/process-source-type.mjs @@ -2,14 +2,13 @@ import { existsSync as fileExists } from 'node:fs' import { resolve as resolvePath } from 'node:path' import { SOURCE_TYPES } from '../constants' -import { errorOut } from './error-out' const processSourceType = ({ sourcePath, sourceType }) => { if (sourceType === undefined) { const docusaurusConfigPath = resolvePath(sourcePath, '..', 'docusaurus.config.js') sourceType = fileExists(docusaurusConfigPath) ? 'docusaurus' : 'vanilla' } else if (!SOURCE_TYPES.includes(sourceType)) { - errorOut(`Invalid site source type '${sourceType}'; must be one of ${SOURCE_TYPES.join(', ')}.\n`, 2) + throw new Error(`Invalid site source type '${sourceType}'; must be one of ${SOURCE_TYPES.join(', ')}.\n`, 2) } return sourceType