A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/serverless/serverless/issues/8364 below:

Seclude CLI params and service config resolution from the core · Issue #8364 · serverless/serverless · GitHub

Use case description

Ideally it should be straightforward to use Serverless Framework programmatically. Additionally clean separation of concerns will help significantly the maintenance and will allow to integrate Components engine into the repository.

Improvements towards separation of Packaging and Deployment phases has been moved to #8499

Proposed solution

Step by step let's seclude CLI params and service config resolution logic from a core and layout a new processing flow as follows:

  1. If CLI command is -v, output version info and abort
  2. If in service context:
    1. Resolve service configuration (with support for -c, --config CLI params), into plain not normalized in any way JSON structure). (If there's parsing error and it's not a CLI help request, crash with meaningful error)
    2. Resolve file, self and strToBool variable sources (but only those not depending on other resolvers)
    3. Ensure that provider and eventual provider.stage properties are fully resolved. (If there's a validation error and it's not a CLI help request, crash with meaningful error on provider being not resolved. Show deprecation and warning notice on provider.stage not being resolved)
    4. Load eventual extra env variables from .env files (If there's parsing error and it's not a CLI help request, crash with meaningful error)
    5. Resolve env and remaining file, self and strToBool variable sources (but only those not depending on other resolvers)
    6. Ensure eventual plugins property is fully resolved.
    7. Initialize plugins (at this stage plugins should have no access to service config or any meta):
      (If there's initialization error and it's not a CLI help request, crash with meaningful error)
      1. Register plugin config schema extensions
      2. Register plugin variable extensions
      3. Register commands and hooks
  3. If CLI help request. Display help and abort
  4. Parse CLI arguments (with respect to map of supported commands and options)
  5. If in service context:
    1. Resolve variables for all variable sources which do not depend on config properties
    2. Resolve all remaining variables in service config
  6. Run lifecycle events for CLI command

Additionally to have Framework CLI totally programatic, #1720 has to be addressed.

Implementation spec

Preliminary notes:

0.1 Unify process error handling
  1. Wrap all process logic with try/catch clause
  2. Configure handler which generally mirrors one at Error class (but presents simplified logic due to more generic approach). Place handler logic in lib/cli/handle-error.js (and ensure some tests for it)
  3. Ensure that uncaughtExceptions are handled with same error handler
  4. Remove lib/classes/Error.js logError utility
0.2 Generalize process execution span promise handling (as currently served by serverless.onExitPromise)
  1. Reflect execution span of introduced above try/catch clause in promise accessible at lib/cli/execution-span.js (module should export an unresolved promise and method (to be used internally) for resolving it)
  2. Assign lib/cli/execution-span.js promise to serverless.executionSpan (as it can be valuable for a plugins). Remove it's so far counterpart serverless.onExitPromise and in places it was used, refer to either promise exported by lib/cli/execution-span.js or serverless.executionSpan
  3. Move analytics.sendPending() to top of the try/catch clause
1.0 Seclude -v, --version CLI params handling
  1. At begin of the flow implement following:
  2. Remove -v, --version option handling and recognition from CLI.js class
2.0 Resolve eventual service config file path (service context)
  1. Follow up with service context detection logic. It should be implemented in lib/cli/resolve-service-config-path.js and resemble logic we have now here: const getConfigFilePath = async (servicePath, options = {}) => { if (options.config) { const customPath = path.join(servicePath, options.config); return fileExists(customPath).then(exists => { return exists ? customPath : null; }); } const jsonPath = path.join(servicePath, 'serverless.json'); const ymlPath = path.join(servicePath, 'serverless.yml'); const yamlPath = path.join(servicePath, 'serverless.yaml'); const jsPath = path.join(servicePath, 'serverless.js'); const tsPath = path.join(servicePath, 'serverless.ts'); const [jsonExists, ymlExists, yamlExists, jsExists, tsExists] = await Promise.all([ fileExists(jsonPath), fileExists(ymlPath), fileExists(yamlPath), fileExists(jsPath), fileExists(tsPath), ]); if (yamlExists) { return yamlPath; } else if (ymlExists) { return ymlPath; } else if (jsonExists) { return jsonPath; } else if (jsExists) { return jsPath; } else if (tsExists) { return tsPath; } return null; };
  2. Remove from internals any config file path resolution logic and ensure that above is handled as single point of truth:
2.1 Parse service config file source
  1. Follow up with service config content resolution (bare resolution with no normalization or vars resolution at this point). It should be implemented in lib/service-config/read-source.js, and resemble logic we have here: getServerlessConfigFilePath(serverless).then(configFilePath => { if (!configFilePath) return null; const fileExtension = path.extname(configFilePath); const isJSOrTsConfigFile = fileExtension === '.js' || fileExtension === '.ts'; return (isJSOrTsConfigFile ? handleJsOrTsConfigFile(configFilePath) : readFile(configFilePath) ).then(config => { if (_.isPlainObject(config)) return config; throw new ServerlessError( `${path.basename(configFilePath)} must export plain object`, 'INVALID_CONFIG_OBJECT_TYPE' ); }); }) . if readServiceConfigSource crashes expose the error only if it's not CLI help request, otherwise behave as we're not in service context.
  2. Remove from internals any config source resolution:
2.2 Initial (partial) variables resolution

For that we would need to Implement new variables resolver with following modules:

lib/variables/resolve-variables-map.js

Function that takes serviceConfig as an input. Traverses it's properties and returns map of all properties which use variable syntax. Result map should expose all information needed for complete variables resolution without a need of repeated property parsing.

After we will fully override variable resolution that's currently in a framework (point 5.2), function should be configured to also override all serviceConfig properties which depend on variables with null values (technically we move all information to variables map, and remove it from serviceConfig. It's to ensure that eventual further serviceConfig processing in case of variable resolution errors is not affected by unresolved properties content)

Expected format of result map

const sep = "\0";

const exampleResultMap = {
  [`custom${sep}creds`]: {
    raw:
      '${file(../config.${opt:stage, self:provider.stage, "dev"}.json):CREDS}_${self:custom.foo}',
    meta: [
      // Start from last to first
      // If vars are part of a string, provide start and end locations
      // and unconditionally coerce result to string
      { start: 71, end: 89, sources: [{ source: 'self', address: { raw: 'custom.foo' } }] },
      {
        start: 0,
        end: 70,
        sources: [
          {
            source: 'file',
            param: {
              raw: '../config.${opt:stage, self:provider.stage, "dev"}.json',
              meta: [
                {
                  start: 10,
                  end: 50,
                  sources: [
                    { source: 'opt', address: { raw: 'stage' } },
                    { source: 'self', address: { raw: 'provider.stage' } },
                    { raw: 'dev' },
                  ],
                },
              ],
            },
            address: { raw: 'CREDS' },
          },
        ],
      },
    ],
  },
  [`layers${sep}hello${sep}path`]: {
    raw: '${self:custom.layerPath}',
    // If property value is entirely constructed with var
    // No start/end points need to be configured
    // In such case we also support any result type (no string coercion)
    variables: [{ sources: [{ source: 'self', address: { raw: 'custom.layerPath' } }] }],
  },
};

Note: In case of resolution from external files, new added content will need to have eventual variables resolved through same util

lib/variables/resolve-variables.js

Function that takes serviceConfig, variablesMap and variablesResolvers as an input.

variablesResolvers is expected to be a simple map with source type as a key (e.g. self, fileetc.) and function that takesserviceConfig` and eeventual param configured for resolver as arguments. Function may return result sync way or async via returned promise

There should be attempt to resolve every property.

If there's any fail. Function crashes, and on it's error it should expose errorneusVariableKeys property with keys to each variable resolutions that failed.

Having above:

  1. Generate variables map
  2. Attempt to resolve file, self and strToBool variable sources (but only those not depending on other resolvers). If it fails ignore any not supported source errors. If there are other errors and it's not a CLI help request, in initial stage, ignore them, but after addressing 5.2 signal them with warning message and show a deprecation that with next major we will fail.
2.3 Ensure provider and provider.stage properties are resolved.
  1. Inspect variables map:
2.4 Ensure to load env variables from .env files

Follow up with resolution of environment variables from .env files (currently being implemented at #8413)

2.5 Further (partial) variables resolution

As in 2.1 step, attempt to resolve file, self, strToBool and env variable sources (but only those not depending on other resolvers). If it fails ignore any not supported source errors. If there are other errors and it's not a CLI help request in initial stage, ignore them, but after addressing 5.2 signal them with warning message and show a deprecation that with next major we will fail.

2.6 Ensure eventual plugins property is fully resolved.

Inspect variables map, if plugins property still depends on variable resolution, crash with meaningful error, that we cannot accept given form of configuration

2.7.0 Recognize help command
  1. Implement is help CLI command logic in lib/cli/is-help-command.js (it should follow cli.isHelpRequest logic but also recognize --help-components) and adapt it in internals:
2.7.1 Recognize commands which are independent of external plugins

Handling of those commands ideally should be totally secluded from Framework engine, still to not impose too timetaking refactor at this step let's simply mark them, to make further processing possible (having that addressed, let's open an issue calling for their seclusion)

  1. If CLI command is either plugin, login, logout or dashboard pass to Serverless constructor a shouldMutePluginInitializationErrors: true option, and internally assign t to _shouldMutePluginInitializationErrors property
  2. In pluginManager.resolveServicePlugins() Rely on serverles._shouldMutePluginInitializationErrors and remove pluginManager.pluginIndependentCommands property.
2.7.2 Initialize Serverless instance

(this will most likely lay out naturally and should not require any code changes)

Follow up with construction of Serverless instance and invoke of serverless.init()

3.0 If CLI help command show help and abort
  1. Implement display option help logic (to be used by various help variants) in lib/cli/help/options.js. It should take our common command configuration object, and resemble logic we have at cli.displayCommandOptions()
  2. Implement interactive CLI help logic in lib/cli/help/interactive.js. It should be a function that accepts an interactiveCLI command configuration and resembles logic we have at `cli.generateInteactiveCliHelp()
  3. Implement main CLI help logic in lib/cli/help/framework.js. It should be a function that accepts a loadedPlugins and resembles logic we have at cli.generateMainHelp() (note we should have CLI: Remove help --verbose option and improve general help output #8497 addressed at this point)
  4. Implement specific command help logic in lib/cli/help/command.js. It should be a function that accepts commandName and command arguments, and:
  5. if interactive CLI help request. Find InteractiveCli plugin, run lib/cli/help/interactive.js with its comand and abort
  6. If general (not command specific) help request, run lib/cli/help/framework.js with serverless.cli.loadedCommands
  7. If command help request, find given command in serverless.cli.loadedCommands
    1. If specified command is not found show warning and output general help
    2. Otherwise run lib/cli/help/command.js with resolved comman
  8. Remove following code:
4.0 Parse CLI arguments
  1. Having a map of all supported commands and options follow up with resolution of CLI arguments:
  2. Pass resolved commands and options to serverless.run() method. In context serverless.run() assign those properties onprocessedInput property
5.1 Resolve variables for all variable sources which do not depend on config properties

As in 2.1 step, attempt to resolve all variable sources which do not depend on config properties.

If it fails ignore any not supported source errors. If there are other errors in initial stage, ignore them, but after addressing 5.2 signal them with warning message and show a deprecation that with next major we will fail.

5.2 Resolve all remaining variables in service config

As in 2.1 step, attempt to resolve all remaining variables.

If it fails signal them with warning message and show a deprecation that with next major we will fail. Additionally:

Remove all variable resolution logic from Framework core

6.0 Run lifecycle events for CLI command

(this will most likely lay out naturally and should not require any code changes)

Follow up with serverless.run()

Progress summary:

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4