All files / src/context/yaml/handlers actions.ts

89.74% Statements 35/39
62.5% Branches 15/24
88.88% Functions 8/9
94.44% Lines 34/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102  1x 1x 1x 1x 1x       1x             1x   1x           41x   41x   3x   1x                 1x     1x       1x   1x       1x 1x 1x   1x 1x 1x   1x       6x   6x     6x 2x 1x     1x   1x     6x 1x                             1x         1x  
/* eslint-disable consistent-return */
import path from 'path';
import fs from 'fs-extra';
import { constants } from '../../../tools';
import { sanitize } from '../../../utils';
import log from '../../../logger';
import { YAMLHandler } from '.';
import YAMLContext from '..';
import { ParsedAsset } from '../../../types';
import { Action, isMarketplaceAction } from '../../../tools/auth0/handlers/actions';
 
type ParsedActions = ParsedAsset<'actions', Partial<Action>[]>;
 
type Secret = { name: string; value: string };
 
function parseCode(context: YAMLContext, code: string) {
  Eif (code) {
    //@ts-ignore TODO: understand why two arguments are passed when context.loadFile only accepts one
    return context.loadFile(code, constants.ACTIONS_DIRECTORY);
  }
}
 
async function parse(context: YAMLContext): Promise<ParsedActions> {
  // Load the script file for each action
  const { actions } = context.assets;
 
  if (!actions) return { actions: null };
 
  return {
    actions: [
      ...actions.map((action) => ({
        ...action,
        code: parseCode(context, action.code || ''),
      })),
    ],
  };
}
 
function mapSecrets(secrets: { name: string; value: string }[]): Secret[] {
  Iif (secrets && secrets.length > 0) {
    return secrets.map((secret) => ({ name: secret.name, value: secret.value }));
  }
  return [];
}
 
function mapActionCode(basePath: string, action: { code: string; name: string }): string {
  const { code } = action;
 
  Iif (!code) {
    return '';
  }
 
  const actionName = sanitize(action.name);
  const actionVersionsFolder = path.join(basePath, constants.ACTIONS_DIRECTORY, actionName);
  fs.ensureDirSync(actionVersionsFolder);
 
  const codeFile = path.join(actionVersionsFolder, 'code.js');
  log.info(`Writing ${codeFile}`);
  fs.writeFileSync(codeFile, code);
 
  return `./${constants.ACTIONS_DIRECTORY}/${actionName}/code.js`;
}
 
async function dump(context: YAMLContext): Promise<ParsedActions> {
  const { actions } = context.assets;
 
  Iif (!actions) return { actions: null };
 
  // Marketplace actions are not currently supported for management (See ESD-23225)
  const filteredActions = actions.filter((action) => {
    if (isMarketplaceAction(action)) {
      log.warn(
        `Skipping export of marketplace action "${action.name}". Management of marketplace actions are not currently supported.`
      );
      return false;
    }
    return true;
  });
 
  return {
    actions: filteredActions.map((action) => ({
      name: action.name,
      deployed: !!action.deployed || !!action.all_changes_deployed,
      //@ts-ignore because Action resource needs to be typed more accurately
      code: mapActionCode(context.basePath, action),
      runtime: action.runtime,
      dependencies: action.dependencies || [],
      status: action.status,
      secrets:
        typeof action.secrets === 'string' ? action.secrets : mapSecrets(action.secrets || []), //Enables keyword preservation to operate on action secrets
      supported_triggers: action.supported_triggers,
    })),
  };
}
 
const ActionsHandler: YAMLHandler<ParsedActions> = {
  parse,
  dump,
};
 
export default ActionsHandler;