mirror of
https://github.com/serverless/serverless.git
synced 2025-12-08 19:46:03 +00:00
763 lines
30 KiB
JavaScript
Executable File
763 lines
30 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
'use strict';
|
|
|
|
require('essentials');
|
|
|
|
// global graceful-fs patch
|
|
// https://github.com/isaacs/node-graceful-fs#global-patching
|
|
require('graceful-fs').gracefulify(require('fs'));
|
|
|
|
if (require('../lib/utils/tabCompletion/isSupported') && process.argv[2] === 'completion') {
|
|
require('../lib/utils/autocomplete')();
|
|
return;
|
|
}
|
|
|
|
const handleError = require('../lib/cli/handle-error');
|
|
const humanizePropertyPathKeys = require('../lib/configuration/variables/humanize-property-path-keys');
|
|
|
|
const {
|
|
storeLocally: storeTelemetryLocally,
|
|
send: sendTelemetry,
|
|
} = require('../lib/utils/telemetry');
|
|
const generateTelemetryPayload = require('../lib/utils/telemetry/generatePayload');
|
|
const processBackendNotificationRequest = require('../lib/utils/processBackendNotificationRequest');
|
|
const isTelemetryDisabled = require('../lib/utils/telemetry/areDisabled');
|
|
const logDeprecation = require('../lib/utils/logDeprecation');
|
|
|
|
let command;
|
|
let options;
|
|
let commandSchema;
|
|
let serviceDir = null;
|
|
let configuration = null;
|
|
let serverless;
|
|
const commandUsage = {};
|
|
|
|
let hasTelemetryBeenReported = false;
|
|
|
|
process.once('uncaughtException', (error) =>
|
|
handleError(error, {
|
|
isUncaughtException: true,
|
|
command,
|
|
options,
|
|
commandSchema,
|
|
serviceDir,
|
|
configuration,
|
|
serverless,
|
|
hasTelemetryBeenReported,
|
|
commandUsage,
|
|
})
|
|
);
|
|
|
|
const processSpanPromise = (async () => {
|
|
try {
|
|
const wait = require('timers-ext/promise/sleep');
|
|
await wait(); // Ensure access to "processSpanPromise"
|
|
|
|
const resolveInput = require('../lib/cli/resolve-input');
|
|
|
|
let commands;
|
|
let isHelpRequest;
|
|
// Parse args against schemas of commands which do not require to be run in service context
|
|
({ command, commands, options, isHelpRequest, commandSchema } = resolveInput(
|
|
require('../lib/cli/commands-schema/no-service')
|
|
));
|
|
|
|
// If version number request, show it and abort
|
|
if (options.version) {
|
|
await require('../lib/cli/render-version')();
|
|
logDeprecation.printSummary();
|
|
return;
|
|
}
|
|
|
|
const ServerlessError = require('../lib/serverless-error');
|
|
|
|
// Abort if command is not supported in this environment
|
|
if (commandSchema && commandSchema.isHidden && commandSchema.noSupportNotice) {
|
|
throw new ServerlessError(
|
|
`Cannot run \`${command}\` command: ${commandSchema.noSupportNotice}`,
|
|
'NOT_SUPPORTED_COMMAND'
|
|
);
|
|
}
|
|
|
|
const path = require('path');
|
|
const uuid = require('uuid');
|
|
const _ = require('lodash');
|
|
const Serverless = require('../lib/Serverless');
|
|
const resolveVariables = require('../lib/configuration/variables/resolve');
|
|
const isPropertyResolved = require('../lib/configuration/variables/is-property-resolved');
|
|
const eventuallyReportVariableResolutionErrors = require('../lib/configuration/variables/eventually-report-resolution-errors');
|
|
const filterSupportedOptions = require('../lib/cli/filter-supported-options');
|
|
|
|
let configurationPath = null;
|
|
let providerName;
|
|
let variablesMeta;
|
|
let resolverConfiguration;
|
|
let isInteractiveSetup;
|
|
|
|
const ensureResolvedProperty = (propertyPath, { shouldSilentlyReturnIfLegacyMode } = {}) => {
|
|
if (isPropertyResolved(variablesMeta, propertyPath)) return true;
|
|
variablesMeta = null;
|
|
if (isHelpRequest) return false;
|
|
const humanizedPropertyPath = humanizePropertyPathKeys(propertyPath.split('\0'));
|
|
if (!shouldSilentlyReturnIfLegacyMode || configuration.variablesResolutionMode) {
|
|
throw new ServerlessError(
|
|
`Cannot resolve ${path.basename(
|
|
configurationPath
|
|
)}: "${humanizedPropertyPath}" property is not accessible ` +
|
|
'(configured behind variables which cannot be resolved at this stage)',
|
|
'INACCESSIBLE_CONFIGURATION_PROPERTY'
|
|
);
|
|
}
|
|
logDeprecation(
|
|
'NEW_VARIABLES_RESOLVER',
|
|
`"${humanizedPropertyPath}" is not accessible ` +
|
|
'(configured behind variables which cannot be resolved at this stage).\n' +
|
|
'Starting with next major release, ' +
|
|
'this will be communicated with a thrown error.\n' +
|
|
'Set "variablesResolutionMode: 20210326" in your service config, ' +
|
|
'to adapt to this behavior now',
|
|
{ serviceConfig: configuration }
|
|
);
|
|
return false;
|
|
};
|
|
|
|
if (!commandSchema || commandSchema.serviceDependencyMode) {
|
|
// Command is potentially service specific, follow up with resolution of service config
|
|
|
|
isInteractiveSetup = !isHelpRequest && command === '';
|
|
|
|
const resolveConfigurationPath = require('../lib/cli/resolve-configuration-path');
|
|
const readConfiguration = require('../lib/configuration/read');
|
|
|
|
// Resolve eventual service configuration path
|
|
configurationPath = await resolveConfigurationPath();
|
|
|
|
// If service configuration file is found, load its content
|
|
configuration = configurationPath
|
|
? await (async () => {
|
|
try {
|
|
return await readConfiguration(configurationPath);
|
|
} catch (error) {
|
|
// Configuration syntax error should not prevent help from being displayed
|
|
// (if possible configuration should be read for help request as registered
|
|
// plugins may introduce new commands to be listed in help output)
|
|
if (isHelpRequest) return null;
|
|
throw error;
|
|
}
|
|
})()
|
|
: null;
|
|
|
|
if (configuration) {
|
|
serviceDir = process.cwd();
|
|
if (!commandSchema) {
|
|
// If command was not recognized in first resolution phase
|
|
// parse args again also against schemas of commands which require service context
|
|
resolveInput.clear();
|
|
({ command, commands, options, isHelpRequest, commandSchema } = resolveInput(
|
|
require('../lib/cli/commands-schema/service')
|
|
));
|
|
}
|
|
|
|
// IIFE for maintanance convenience
|
|
await (async () => {
|
|
if (_.get(configuration.provider, 'variableSyntax')) {
|
|
// Request to rely on old variables resolver explictly
|
|
// abort (fallback to legacy internal resolution)
|
|
if (isHelpRequest) return;
|
|
if (configuration.variablesResolutionMode) {
|
|
throw new ServerlessError(
|
|
`Cannot resolve ${path.basename(
|
|
configurationPath
|
|
)}: "variableSyntax" is not supported with new variables resolver. ` +
|
|
'Please drop this setting',
|
|
'UNSUPPORTED_VARIABLE_SYNTAX_CONFIGURATION'
|
|
);
|
|
}
|
|
logDeprecation(
|
|
'NEW_VARIABLES_RESOLVER',
|
|
'Serverless Framework was enhanced with a new variables resolver ' +
|
|
'which doesn\'t recognize "provider.variableSyntax" setting.' +
|
|
"Starting with a new major it will be the only resolver that's used." +
|
|
'. Drop setting from a configuration to adapt to it',
|
|
{ serviceConfig: configuration }
|
|
);
|
|
return;
|
|
}
|
|
|
|
const resolveVariablesMeta = require('../lib/configuration/variables/resolve-meta');
|
|
const resolveProviderName = require('../lib/configuration/resolve-provider-name');
|
|
|
|
variablesMeta = resolveVariablesMeta(configuration);
|
|
|
|
if (
|
|
eventuallyReportVariableResolutionErrors(
|
|
configurationPath,
|
|
configuration,
|
|
variablesMeta
|
|
)
|
|
) {
|
|
// Variable syntax errors, abort
|
|
variablesMeta = null;
|
|
return;
|
|
}
|
|
|
|
// "variablesResolutionMode" must not be configured with variables as it influences
|
|
// variable resolution choices
|
|
if (!ensureResolvedProperty('variablesResolutionMode')) return;
|
|
if (!ensureResolvedProperty('disabledDeprecations')) return;
|
|
if (!ensureResolvedProperty('deprecationNotificationMode')) return;
|
|
|
|
if (isPropertyResolved(variablesMeta, 'provider\0name')) {
|
|
providerName = resolveProviderName(configuration);
|
|
if (providerName == null) {
|
|
variablesMeta = null;
|
|
return;
|
|
}
|
|
}
|
|
if (!commandSchema && providerName === 'aws') {
|
|
// If command was not recognized in previous resolution phases
|
|
// parse args again also against schemas commands which require AWS service context
|
|
resolveInput.clear();
|
|
({ command, commands, options, isHelpRequest, commandSchema } = resolveInput(
|
|
require('../lib/cli/commands-schema/aws-service')
|
|
));
|
|
}
|
|
|
|
if (variablesMeta.size) {
|
|
// Some properties are configured with variables
|
|
|
|
// Resolve eventual variables in `provider.stage` and `useDotEnv`
|
|
// (required for reliable .env resolution)
|
|
resolverConfiguration = {
|
|
serviceDir,
|
|
configuration,
|
|
variablesMeta,
|
|
sources: {
|
|
env: require('../lib/configuration/variables/sources/env'),
|
|
file: require('../lib/configuration/variables/sources/file'),
|
|
opt: require('../lib/configuration/variables/sources/opt'),
|
|
self: require('../lib/configuration/variables/sources/self'),
|
|
strToBool: require('../lib/configuration/variables/sources/str-to-bool'),
|
|
},
|
|
options: filterSupportedOptions(options, { commandSchema, providerName }),
|
|
fulfilledSources: new Set(['file', 'self', 'strToBool']),
|
|
propertyPathsToResolve: new Set(['provider\0name', 'provider\0stage', 'useDotenv']),
|
|
};
|
|
if (isInteractiveSetup) resolverConfiguration.fulfilledSources.add('opt');
|
|
await resolveVariables(resolverConfiguration);
|
|
|
|
if (
|
|
eventuallyReportVariableResolutionErrors(
|
|
configurationPath,
|
|
configuration,
|
|
variablesMeta
|
|
)
|
|
) {
|
|
// Unrecoverable resolution errors, abort
|
|
variablesMeta = null;
|
|
return;
|
|
}
|
|
|
|
if (!providerName && isPropertyResolved(variablesMeta, 'provider\0name')) {
|
|
providerName = resolveProviderName(configuration);
|
|
if (providerName == null) {
|
|
variablesMeta = null;
|
|
return;
|
|
}
|
|
if (!commandSchema && providerName === 'aws') {
|
|
// If command was not recognized in previous resolution phases
|
|
// Parse args again also against schemas of commands which work in context of an AWS
|
|
// service
|
|
resolveInput.clear();
|
|
({ command, commands, options, isHelpRequest, commandSchema } = resolveInput(
|
|
require('../lib/cli/commands-schema/aws-service')
|
|
));
|
|
|
|
if (commandSchema) {
|
|
resolverConfiguration.options = filterSupportedOptions(options, {
|
|
commandSchema,
|
|
providerName,
|
|
});
|
|
await resolveVariables(resolverConfiguration);
|
|
if (
|
|
eventuallyReportVariableResolutionErrors(
|
|
configurationPath,
|
|
configuration,
|
|
variablesMeta
|
|
)
|
|
) {
|
|
variablesMeta = null;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (
|
|
!ensureResolvedProperty('provider\0stage', { shouldSilentlyReturnIfLegacyMode: true })
|
|
) {
|
|
// Hack to not duplicate the warning with similar deprecation
|
|
logDeprecation.triggeredDeprecations.add('VARIABLES_ERROR_ON_UNRESOLVED');
|
|
return;
|
|
}
|
|
|
|
if (!ensureResolvedProperty('useDotenv')) return;
|
|
}
|
|
|
|
// Load eventual environment variables from .env files
|
|
await require('../lib/cli/conditionally-load-dotenv')(options, configuration);
|
|
|
|
if (!variablesMeta.size) return; // No properties configured with variables
|
|
|
|
resolverConfiguration.fulfilledSources.add('env');
|
|
|
|
if (isHelpRequest || commands[0] === 'plugin') {
|
|
// We do not need full config resolved, we just need to know what
|
|
// provider is service setup with, and with what eventual plugins Framework is extended
|
|
// as that influences what CLI commands and options could be used,
|
|
resolverConfiguration.propertyPathsToResolve.add('plugins');
|
|
} else {
|
|
delete resolverConfiguration.propertyPathsToResolve;
|
|
}
|
|
|
|
await resolveVariables(resolverConfiguration);
|
|
if (
|
|
eventuallyReportVariableResolutionErrors(
|
|
configurationPath,
|
|
configuration,
|
|
variablesMeta
|
|
)
|
|
) {
|
|
variablesMeta = null;
|
|
return;
|
|
}
|
|
|
|
if (!providerName) {
|
|
if (!ensureResolvedProperty('provider\0name')) return;
|
|
providerName = resolveProviderName(configuration);
|
|
if (providerName == null) {
|
|
variablesMeta = null;
|
|
return;
|
|
}
|
|
if (!commandSchema && providerName === 'aws') {
|
|
resolveInput.clear();
|
|
({ command, commands, options, isHelpRequest, commandSchema } = resolveInput(
|
|
require('../lib/cli/commands-schema/aws-service')
|
|
));
|
|
if (commandSchema) {
|
|
resolverConfiguration.options = filterSupportedOptions(options, {
|
|
commandSchema,
|
|
providerName,
|
|
});
|
|
await resolveVariables(resolverConfiguration);
|
|
if (
|
|
eventuallyReportVariableResolutionErrors(
|
|
configurationPath,
|
|
configuration,
|
|
variablesMeta
|
|
)
|
|
) {
|
|
variablesMeta = null;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!variablesMeta.size) return; // All properties successuflly resolved
|
|
|
|
if (!ensureResolvedProperty('plugins')) return;
|
|
if (!ensureResolvedProperty('package\0path')) return;
|
|
|
|
if (!ensureResolvedProperty('frameworkVersion')) return;
|
|
if (!ensureResolvedProperty('app')) return;
|
|
if (!ensureResolvedProperty('org')) return;
|
|
if (!ensureResolvedProperty('tenant')) return;
|
|
if (!ensureResolvedProperty('service', { shouldSilentlyReturnIfLegacyMode: true })) {
|
|
return;
|
|
}
|
|
if (configuration.org) {
|
|
// Dashboard requires AWS region to be resolved upfront
|
|
ensureResolvedProperty('provider\0region', { shouldSilentlyReturnIfLegacyMode: true });
|
|
}
|
|
})();
|
|
} else {
|
|
// In non-service context we recognize all AWS service commands
|
|
resolveInput.clear();
|
|
({ command, commands, options, isHelpRequest, commandSchema } = resolveInput(
|
|
require('../lib/cli/commands-schema/aws-service')
|
|
));
|
|
|
|
// Validate result command and options
|
|
require('../lib/cli/ensure-supported-command')();
|
|
}
|
|
}
|
|
|
|
const configurationFilename = configuration && configurationPath.slice(serviceDir.length + 1);
|
|
|
|
if (isInteractiveSetup) {
|
|
require('../lib/cli/ensure-supported-command')(configuration);
|
|
|
|
if (!process.stdin.isTTY && !process.env.SLS_INTERACTIVE_SETUP_ENABLE) {
|
|
throw new ServerlessError(
|
|
'Attempted to run an interactive setup in non TTY environment.\n' +
|
|
"If that's intentended enforce with SLS_INTERACTIVE_SETUP_ENABLE=1 environment variable",
|
|
'INTERACTIVE_SETUP_IN_NON_TTY'
|
|
);
|
|
}
|
|
const { configuration: configurationFromInteractive } =
|
|
await require('../lib/cli/interactive-setup')({
|
|
configuration,
|
|
serviceDir,
|
|
configurationFilename,
|
|
options,
|
|
commandUsage,
|
|
});
|
|
|
|
logDeprecation.printSummary();
|
|
|
|
hasTelemetryBeenReported = true;
|
|
if (!isTelemetryDisabled) {
|
|
storeTelemetryLocally(
|
|
generateTelemetryPayload({
|
|
command,
|
|
options,
|
|
commandSchema,
|
|
serviceDir,
|
|
configuration: configurationFromInteractive,
|
|
commandUsage,
|
|
})
|
|
);
|
|
await sendTelemetry({ serverlessExecutionSpan: processSpanPromise });
|
|
}
|
|
return;
|
|
}
|
|
|
|
serverless = new Serverless({
|
|
configuration,
|
|
serviceDir,
|
|
configurationFilename,
|
|
isConfigurationResolved:
|
|
commands[0] === 'plugin' || Boolean(variablesMeta && !variablesMeta.size),
|
|
hasResolvedCommandsExternally: true,
|
|
isTelemetryReportedExternally: true,
|
|
commands,
|
|
options,
|
|
});
|
|
|
|
try {
|
|
serverless.onExitPromise = processSpanPromise;
|
|
serverless.invocationId = uuid.v4();
|
|
await serverless.init();
|
|
if (serverless.invokedInstance) {
|
|
// Local (in service) installation was found and initialized internally,
|
|
// From now on refer to it only
|
|
serverless.invokedInstance.invocationId = serverless.invocationId;
|
|
serverless = serverless.invokedInstance;
|
|
}
|
|
|
|
// IIFE for maintanance convenience
|
|
await (async () => {
|
|
if (!configuration) return;
|
|
let hasFinalCommandSchema = null;
|
|
if (configuration.plugins) {
|
|
// After plugins are loaded, re-resolve CLI command and options schema as plugin
|
|
// might have defined extra commands and options
|
|
|
|
// TODO: Remove "serverless.pluginManager.externalPlugins" check with next major
|
|
if (serverless.pluginManager.externalPlugins) {
|
|
if (serverless.pluginManager.externalPlugins.size) {
|
|
const commandsSchema = require('../lib/cli/commands-schema/resolve-final')(
|
|
serverless.pluginManager.externalPlugins,
|
|
{ providerName: providerName || 'aws', configuration }
|
|
);
|
|
resolveInput.clear();
|
|
({ command, commands, options, isHelpRequest, commandSchema } =
|
|
resolveInput(commandsSchema));
|
|
serverless.processedInput.commands = serverless.pluginManager.cliCommands = commands;
|
|
serverless.processedInput.options = serverless.pluginManager.cliOptions = options;
|
|
hasFinalCommandSchema = true;
|
|
}
|
|
} else {
|
|
// Invocation fallen back to old Framework version, where we do not have easily
|
|
// accessible info on loaded plugins
|
|
// 1. Skip further variables resolution
|
|
variablesMeta = null;
|
|
// 2. Avoid command validation
|
|
hasFinalCommandSchema = false;
|
|
}
|
|
}
|
|
if (!providerName && !hasFinalCommandSchema) {
|
|
// Invalid configuration, ensure to recognize all AWS commands
|
|
resolveInput.clear();
|
|
({ command, commands, options, isHelpRequest, commandSchema } = resolveInput(
|
|
require('../lib/cli/commands-schema/aws-service')
|
|
));
|
|
}
|
|
if (hasFinalCommandSchema == null) hasFinalCommandSchema = true;
|
|
|
|
// Validate result command and options
|
|
if (hasFinalCommandSchema) require('../lib/cli/ensure-supported-command')(configuration);
|
|
if (isHelpRequest) return;
|
|
if (!_.get(variablesMeta, 'size')) return;
|
|
|
|
// Resolve remaininig service configuration variables
|
|
if (providerName === 'aws') {
|
|
// Ensure properties which are crucial to some variable source resolvers
|
|
// are actually resolved.
|
|
if (
|
|
!ensureResolvedProperty('provider\0credentials', {
|
|
shouldSilentlyReturnIfLegacyMode: true,
|
|
}) ||
|
|
!ensureResolvedProperty('provider\0deploymentBucket\0serverSideEncryption', {
|
|
shouldSilentlyReturnIfLegacyMode: true,
|
|
}) ||
|
|
!ensureResolvedProperty('provider\0profile', {
|
|
shouldSilentlyReturnIfLegacyMode: true,
|
|
}) ||
|
|
!ensureResolvedProperty('provider\0region', {
|
|
shouldSilentlyReturnIfLegacyMode: true,
|
|
})
|
|
) {
|
|
return;
|
|
}
|
|
}
|
|
if (commandSchema) {
|
|
resolverConfiguration.options = filterSupportedOptions(options, {
|
|
commandSchema,
|
|
providerName,
|
|
});
|
|
}
|
|
if (configuration.variablesResolutionMode >= 20210326) {
|
|
// New resolver, resolves just recognized CLI options. Therefore we cannot assume
|
|
// we have full "opt" source data if user didn't explicitly switch to new resolver
|
|
resolverConfiguration.fulfilledSources.add('opt');
|
|
}
|
|
|
|
// Register serverless instance and AWS provider specific variable sources
|
|
resolverConfiguration.sources.sls =
|
|
require('../lib/configuration/variables/sources/instance-dependent/get-sls')(serverless);
|
|
resolverConfiguration.fulfilledSources.add('sls');
|
|
|
|
if (providerName === 'aws') {
|
|
Object.assign(resolverConfiguration.sources, {
|
|
cf: require('../lib/configuration/variables/sources/instance-dependent/get-cf')(
|
|
serverless
|
|
),
|
|
s3: require('../lib/configuration/variables/sources/instance-dependent/get-s3')(
|
|
serverless
|
|
),
|
|
ssm: require('../lib/configuration/variables/sources/instance-dependent/get-ssm')(
|
|
serverless
|
|
),
|
|
aws: require('../lib/configuration/variables/sources/instance-dependent/get-aws')(
|
|
serverless
|
|
),
|
|
});
|
|
resolverConfiguration.fulfilledSources.add('cf').add('s3').add('ssm');
|
|
}
|
|
|
|
// Register dashboard specific variable source resolvers
|
|
if (
|
|
// TODO: Remove "tenant" support with next major
|
|
(configuration.org || configuration.tenant) &&
|
|
serverless.pluginManager.dashboardPlugin
|
|
) {
|
|
for (const [sourceName, sourceConfig] of Object.entries(
|
|
serverless.pluginManager.dashboardPlugin.configurationVariablesSources
|
|
)) {
|
|
resolverConfiguration.sources[sourceName] = sourceConfig;
|
|
resolverConfiguration.fulfilledSources.add(sourceName);
|
|
}
|
|
}
|
|
|
|
// Register variable source resolvers provided by external plugins
|
|
const resolverExternalPluginSources = require('../lib/configuration/variables/sources/resolve-external-plugin-sources');
|
|
resolverExternalPluginSources(
|
|
configuration,
|
|
resolverConfiguration,
|
|
serverless.pluginManager.externalPlugins
|
|
);
|
|
|
|
// Having all source resolvers configured, resolve variables
|
|
await resolveVariables(resolverConfiguration);
|
|
if (!variablesMeta.size) {
|
|
serverless.isConfigurationInputResolved = true;
|
|
return;
|
|
}
|
|
if (
|
|
eventuallyReportVariableResolutionErrors(configurationPath, configuration, variablesMeta)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
// Do not confirm on unresolved sources with partially resolved configuration
|
|
if (resolverConfiguration.propertyPathsToResolve) return;
|
|
|
|
// Report unrecognized variable sources found in variables configured in service config
|
|
const unresolvedSources =
|
|
require('../lib/configuration/variables/resolve-unresolved-source-types')(variablesMeta);
|
|
const recognizedSourceNames = new Set(Object.keys(resolverConfiguration.sources));
|
|
if (!(configuration.variablesResolutionMode >= 20210326)) {
|
|
const legacyCfVarPropertyPaths = new Set();
|
|
const legacySsmVarPropertyPaths = new Set();
|
|
for (const [sourceType, propertyPaths] of unresolvedSources) {
|
|
if (sourceType.startsWith('cf.')) {
|
|
for (const propertyPath of propertyPaths) legacyCfVarPropertyPaths.add(propertyPath);
|
|
unresolvedSources.delete(sourceType);
|
|
}
|
|
if (sourceType.startsWith('ssm.')) {
|
|
for (const propertyPath of propertyPaths) legacySsmVarPropertyPaths.add(propertyPath);
|
|
unresolvedSources.delete(sourceType);
|
|
}
|
|
if (sourceType === 'param' || sourceType === 'output') {
|
|
logDeprecation(
|
|
'NEW_VARIABLES_RESOLVER',
|
|
'"param" and "output" variable sources can be resolved only in context of ' +
|
|
'services deployed to Serverless Dashboard (with "org" setting configured).\n' +
|
|
'Starting with next major release, ' +
|
|
'this will be communicated with a thrown error.\n',
|
|
{ serviceConfig: configuration }
|
|
);
|
|
unresolvedSources.delete(sourceType);
|
|
}
|
|
}
|
|
if (legacyCfVarPropertyPaths.size) {
|
|
logDeprecation(
|
|
'NEW_VARIABLES_RESOLVER',
|
|
'Syntax for referencing CF outputs was upgraded to ' +
|
|
'"${cf(<region>):stackName.outputName}" (while ' +
|
|
'"${cf.<region>:stackName.outputName}" is now deprecated, ' +
|
|
'as not supported by new variables resolver).\n' +
|
|
'Please upgrade to use new form instead.' +
|
|
'Starting with next major release, ' +
|
|
'this will be communicated with a thrown error.\n',
|
|
{ serviceConfig: configuration }
|
|
);
|
|
}
|
|
if (legacySsmVarPropertyPaths.size) {
|
|
logDeprecation(
|
|
'NEW_VARIABLES_RESOLVER',
|
|
'Syntax for referencing SSM parameters was upgraded to ' +
|
|
'"${ssm(<region>):parameter-path}" (while ' +
|
|
'"${ssm.<region>:parameter-path}" is now deprecated, ' +
|
|
'as not supported by new variables resolver).\n' +
|
|
'Please upgrade to use new form instead.' +
|
|
'Starting with next major release, ' +
|
|
'this will be communicated with a thrown error.\n',
|
|
{ serviceConfig: configuration }
|
|
);
|
|
}
|
|
|
|
const unrecognizedSourceNames = Array.from(unresolvedSources.keys()).filter(
|
|
(sourceName) => !recognizedSourceNames.has(sourceName)
|
|
);
|
|
if (unrecognizedSourceNames.length) {
|
|
logDeprecation(
|
|
'NEW_VARIABLES_RESOLVER',
|
|
`Approached unrecognized configuration variable sources: "${unrecognizedSourceNames.join(
|
|
'", "'
|
|
)}".\n` +
|
|
'From a next major this will be communicated with a thrown error.\n' +
|
|
'Set "variablesResolutionMode: 20210326" in your service config, ' +
|
|
'to adapt to new behavior now',
|
|
{ serviceConfig: configuration }
|
|
);
|
|
}
|
|
} else {
|
|
const unrecognizedSourceNames = Array.from(unresolvedSources.keys()).filter(
|
|
(sourceName) => !recognizedSourceNames.has(sourceName)
|
|
);
|
|
|
|
if (
|
|
unrecognizedSourceNames.includes('param') ||
|
|
unrecognizedSourceNames.includes('output')
|
|
) {
|
|
throw new ServerlessError(
|
|
'"Cannot resolve configuration: ' +
|
|
'"param" and "output" variable sources can be resolved only in context of ' +
|
|
'services deployed to Serverless Dashboard (with "org" setting configured)',
|
|
'DASHBOARD_VARIABLE_SOURCES_MISUSE'
|
|
);
|
|
}
|
|
throw new ServerlessError(
|
|
`Approached unrecognized configuration variable sources: "${unrecognizedSourceNames.join(
|
|
'", "'
|
|
)}"`,
|
|
'UNRECOGNIZED_VARIABLE_SOURCES'
|
|
);
|
|
}
|
|
})();
|
|
|
|
if (isHelpRequest && serverless.pluginManager.externalPlugins) {
|
|
// Show help
|
|
require('../lib/cli/render-help')(serverless.pluginManager.externalPlugins);
|
|
} else {
|
|
// Run command
|
|
await serverless.run();
|
|
}
|
|
|
|
logDeprecation.printSummary();
|
|
|
|
hasTelemetryBeenReported = true;
|
|
if (!isTelemetryDisabled && !isHelpRequest && serverless.isTelemetryReportedExternally) {
|
|
storeTelemetryLocally({
|
|
...generateTelemetryPayload({
|
|
command,
|
|
options,
|
|
commandSchema,
|
|
serviceDir,
|
|
configuration,
|
|
serverless,
|
|
}),
|
|
outcome: 'success',
|
|
});
|
|
let backendNotificationRequest;
|
|
if (commands.join(' ') === 'deploy') {
|
|
backendNotificationRequest = await sendTelemetry({
|
|
serverlessExecutionSpan: processSpanPromise,
|
|
});
|
|
}
|
|
if (backendNotificationRequest) {
|
|
await processBackendNotificationRequest(backendNotificationRequest);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
// If Dashboard Plugin, capture error
|
|
const dashboardPlugin =
|
|
serverless.pluginManager.dashboardPlugin ||
|
|
serverless.pluginManager.plugins.find((p) => p.enterprise);
|
|
const dashboardErrorHandler = _.get(dashboardPlugin, 'enterprise.errorHandler');
|
|
if (!dashboardErrorHandler) throw error;
|
|
try {
|
|
await dashboardErrorHandler(error, serverless.invocationId);
|
|
} catch (dashboardErrorHandlerError) {
|
|
const log = require('@serverless/utils/log');
|
|
const tokenizeException = require('../lib/utils/tokenize-exception');
|
|
const exceptionTokens = tokenizeException(dashboardErrorHandlerError);
|
|
log(
|
|
`Publication to Serverless Dashboard errored with:\n${' '.repeat('Serverless: '.length)}${
|
|
exceptionTokens.isUserError || !exceptionTokens.stack
|
|
? exceptionTokens.message
|
|
: exceptionTokens.stack
|
|
}`,
|
|
{ color: 'orange' }
|
|
);
|
|
}
|
|
throw error;
|
|
}
|
|
} catch (error) {
|
|
handleError(error, {
|
|
command,
|
|
options,
|
|
commandSchema,
|
|
serviceDir,
|
|
configuration,
|
|
serverless,
|
|
hasTelemetryBeenReported,
|
|
commandUsage,
|
|
});
|
|
}
|
|
})();
|