import chalk from 'chalk' ; import debug from 'debug' ; import semver from 'semver' ; import 'source-map-support/register' ; import { TASK_COMPILE , TASK_HELP } from '../../builtin-tasks/task-names' ; import { TaskArguments } from '../../types' ; import { REDSPOT_NAME } from '../constants' ; import { RedspotContext } from '../context' ; import { loadConfigAndTasks } from '../core/config/config-loading' ; import { RedspotError , RedspotPluginError } from '../core/errors' ; import { ERRORS , getErrorCode } from '../core/errors-list' ; import { isRedspotInstalledLocallyOrLinked } from '../core/execution-mode' ; import { getEnvRedspotArguments } from '../core/params/env-variables' ; import { REDSPOT_PARAM_DEFINITIONS } from '../core/params/redspot-params' ; import { isCwdInsideProject } from '../core/project-structure' ; import { Environment } from '../core/runtime-environment' ; import { loadTsNode , willRunWithTypescript } from '../core/typescript-support' ; import { isRunningOnCiServer } from '../util/ci-detection' ; import { hasConsentedTelemetry , writeTelemetryConsent } from '../util/global-dir' ; import { getPackageJson , PackageJson } from '../util/packageInfo' ; import { Analytics } from './analytics' ; import { ArgumentsParser } from './ArgumentsParser' ; import logger from '../../logger' ; const log = debug ( 'redspot:core:cli' ) ; const ANALYTICS_SLOW_TASK_THRESHOLD = 300 ; async function printVersionMessage ( packageJson ) { console . log ( packageJson . version ) ; } function ensureValidNodeVersion ( packageJson ) { const requirement = packageJson . engines . node ; if ( ! semver . satisfies ( process . version , requirement ) ) { throw new RedspotError ( ERRORS . GENERAL . INVALID_NODE_VERSION , { requirement } ) ; } } async function main ( ) { let showStackTraces = process . argv . includes ( '--show-stack-traces' ) ; try { const packageJson = await getPackageJson ( ) ; ensureValidNodeVersion ( packageJson ) ; const envVariableArguments = getEnvRedspotArguments ( REDSPOT_PARAM_DEFINITIONS , process . env ) ; const argumentsParser = new ArgumentsParser ( ) ; const { redspotArguments , taskName : parsedTaskName , unparsedCLAs } = argumentsParser . parseRedspotArguments ( REDSPOT_PARAM_DEFINITIONS , envVariableArguments , process . argv . slice ( 2 ) ) ; if ( redspotArguments . verbose ) { debug . enable ( 'redspot*' ) ; } showStackTraces = redspotArguments . showStackTraces ; if ( redspotArguments . config === undefined && ! isCwdInsideProject ( ) && process . stdout . isTTY === true ) { console . log ( chalk . red ( `You are not inside a Redspot project.` ) ) ; console . log ( '' ) ; console . log ( `Run the following command to create a new Redspot project: ` ) ; console . log ( chalk . cyan ( `  $ npx redspot-new <project-name>` ) ) ; console . log ( '' ) ; return ; } if ( redspotArguments . version ) { await printVersionMessage ( packageJson ) ; return ; } if ( ! isRedspotInstalledLocallyOrLinked ( ) ) { throw new RedspotError ( ERRORS . GENERAL . NON_LOCAL_INSTALLATION ) ; } if ( willRunWithTypescript ( redspotArguments . config ) ) { loadTsNode ( ) ; } let taskName = parsedTaskName ?? TASK_HELP ; const ctx = RedspotContext . createRedspotContext ( ) ; const config = loadConfigAndTasks ( redspotArguments ) ; const telemetryConsent = hasConsentedTelemetry ( ) ; const analytics = await Analytics . getInstance ( telemetryConsent ) ; const envExtenders = ctx . extendersManager . getExtenders ( ) ; const taskDefinitions = ctx . tasksDSL . getTaskDefinitions ( ) ; const [ abortAnalytics , hitPromise ] = await analytics . sendTaskHit ( taskName ) ; let taskArguments ; if ( redspotArguments . help && taskName !== TASK_HELP ) { taskArguments = { task : taskName } ; taskName = TASK_HELP ; } else { const taskDefinition = taskDefinitions [ taskName ] ; if ( taskDefinition === undefined ) { throw new RedspotError ( ERRORS . ARGUMENTS . UNRECOGNIZED_TASK , { task : taskName } ) ; } if ( taskDefinition . isSubtask ) { throw new RedspotError ( ERRORS . ARGUMENTS . RUNNING_SUBTASK_FROM_CLI , { name : taskDefinition . name } ) ; } taskArguments = argumentsParser . parseTaskArguments ( taskDefinition , unparsedCLAs ) ; } const env = new Environment ( config , redspotArguments , taskDefinitions , envExtenders ) ; ctx . setRedspotRuntimeEnvironment ( env ) ; const timestampBeforeRun = new Date ( ) . getTime ( ) ; await env . run ( taskName , taskArguments ) ; const timestampAfterRun = new Date ( ) . getTime ( ) ; if ( timestampAfterRun - timestampBeforeRun > ANALYTICS_SLOW_TASK_THRESHOLD ) { await hitPromise ; } else { abortAnalytics ( ) ; } log ( `Killing Redspot after successfully running task ${ taskName }` ) ; } catch ( error ) { let isRedspotError = false ; if ( RedspotError . isRedspotError ( error ) ) { isRedspotError = true ; console . error ( chalk . red ( `Error ${ error . message }` ) ) ; } else if ( RedspotPluginError . isRedspotPluginError ( error ) ) { isRedspotError = true ; console . error ( chalk . red ( `Error in plugin ${ error . pluginName }: ${ error . message }` ) ) ; } else if ( error instanceof Error ) { console . error ( chalk . red ( 'An unexpected error occurred:' ) ) ; showStackTraces = true ; } else { console . error ( chalk . red ( 'An unexpected error occurred.' ) ) ; showStackTraces = true ; } console . log ( '' ) ; if ( showStackTraces ) { console . error ( error ) ; } else { if ( ! isRedspotError ) { console . error ( `If you think this is a bug in Redspot, please report it here: https://github.com/patractlabs/redspot/issues/new` ) ; } if ( RedspotError . isRedspotError ( error ) ) { logger . log ( error . errorDescriptor . description + '\n' ) ; } else { } } process . exit ( 1 ) ; } } main ( ) . then ( ( ) => process . exit ( process . exitCode ) ) . catch ( ( error ) => { console . error ( error ) ; process . exit ( 1 ) ; } ) ;