From e671daa2b6fc2508a52db28d4cb1f90a49d04166 Mon Sep 17 00:00:00 2001 From: Pedro Arantes Date: Sun, 18 Oct 2020 12:30:58 -0300 Subject: [PATCH] feat: allow js, ts, json, yml and yaml cloudformation template extensions --- packages/cli/src/deploy/cloudFormation.ts | 56 +++++++++++++++++-- packages/cli/src/deploy/command.ts | 1 - .../cli/src/utils/cloudFormationTemplate.ts | 8 ++- packages/cli/src/utils/readObjectFile.ts | 13 +++-- packages/website/components/Header.tsx | 9 ++- packages/website/components/Layout.tsx | 4 ++ packages/website/components/MaxWidth.tsx | 11 +++- .../docs/getting-started/configuration.md | 0 packages/website/pages/docs/usage/deploy.md | 3 + 9 files changed, 89 insertions(+), 16 deletions(-) create mode 100644 packages/website/pages/docs/getting-started/configuration.md create mode 100644 packages/website/pages/docs/usage/deploy.md diff --git a/packages/cli/src/deploy/cloudFormation.ts b/packages/cli/src/deploy/cloudFormation.ts index 8f7a3bc..b918fa2 100644 --- a/packages/cli/src/deploy/cloudFormation.ts +++ b/packages/cli/src/deploy/cloudFormation.ts @@ -1,10 +1,13 @@ import AWS from 'aws-sdk'; +import fs from 'fs'; import log from 'npmlog'; +import path from 'path'; import { CloudFormationTemplate, getEnvironment, - readCloudFormationTemplate, + readCloudFormationYamlTemplate, + readObjectFile, } from '../utils'; import { addDefaults } from './addDefaults.cloudFormation'; @@ -277,6 +280,47 @@ export const deploy = async ({ return describeStack({ stackName }); }; +const findAndReadCloudFormationTemplate = ({ + templatePath: defaultTemplatePath, +}: { + templatePath?: string; +}): CloudFormationTemplate => { + const templatePath = + defaultTemplatePath || + ['ts', 'js', 'yaml', 'yml', 'json'] + .map((extension) => `src/cloudformation.${extension}`) + /** + * Iterate over extensions. If the template of the current extension is + * found, we save it on the accumulator and return it every time until + * the loop ends. + */ + .reduce((acc, cur) => { + if (acc) { + return acc; + } + return fs.existsSync(path.resolve(process.cwd(), cur)) ? cur : acc; + }, ''); + + if (!templatePath) { + throw new Error('Cannot find a CloudFormation template.'); + } + + const extension = templatePath?.split('.').pop() as string; + + const fullPath = path.resolve(process.cwd(), templatePath); + + /** + * We need to read Yaml first because CloudFormation specific tags aren't + * recognized when parsing a simple Yaml file. I.e., a possible error: + * "Error message: "unknown tag ! at line 21, column 34:\n" + */ + if (['yaml', 'yml'].includes(extension)) { + return readCloudFormationYamlTemplate({ templatePath }); + } + + return readObjectFile({ path: fullPath }); +}; + export const deployCloudFormation = async ({ lambdaInput, lambdaExternals, @@ -302,13 +346,13 @@ export const deployCloudFormation = async ({ return template; } - if (templatePath) { - return readCloudFormationTemplate({ templatePath }); - } - - throw new Error('"template" or "templatePath" must be defined'); + return findAndReadCloudFormationTemplate({ templatePath }); })(); + console.log(cloudFormationTemplate); + + process.exit(1); + await cloudFormation() .validateTemplate({ TemplateBody: JSON.stringify(cloudFormationTemplate), diff --git a/packages/cli/src/deploy/command.ts b/packages/cli/src/deploy/command.ts index 4d2f5db..a92c142 100644 --- a/packages/cli/src/deploy/command.ts +++ b/packages/cli/src/deploy/command.ts @@ -97,7 +97,6 @@ export const deployCommand: CommandModule< }, 'template-path': { alias: 't', - default: 'src/cloudformation.yml', type: 'string', }, }) diff --git a/packages/cli/src/utils/cloudFormationTemplate.ts b/packages/cli/src/utils/cloudFormationTemplate.ts index c7ecf15..1195a1a 100644 --- a/packages/cli/src/utils/cloudFormationTemplate.ts +++ b/packages/cli/src/utils/cloudFormationTemplate.ts @@ -161,11 +161,15 @@ const getYamlTypes = (tagAndTypeArr: TagAndType[]) => const getSchema = (tagAndTypeArr: TagAndType[] = []) => yaml.Schema.create(getYamlTypes([...tagAndTypeArr, ...cloudFormationTypes])); -export const dumpCloudFormationTemplate = ( +export const dumpToYamlCloudFormationTemplate = ( cloudFormationTemplate: CloudFormationTemplate, ) => yaml.safeDump(cloudFormationTemplate, { schema: getSchema() }); -export const readCloudFormationTemplate = ({ +/** + * CloudFormation + * @param param0 + */ +export const readCloudFormationYamlTemplate = ({ templatePath, }: { templatePath: string; diff --git a/packages/cli/src/utils/readObjectFile.ts b/packages/cli/src/utils/readObjectFile.ts index 109a7a9..8f85399 100644 --- a/packages/cli/src/utils/readObjectFile.ts +++ b/packages/cli/src/utils/readObjectFile.ts @@ -3,6 +3,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import fs from 'fs'; import yaml from 'js-yaml'; +import typescript from 'typescript'; export const readYaml = ({ path }: { path: string }) => { const template = fs.readFileSync(path, 'utf8') || JSON.stringify({}); @@ -16,12 +17,16 @@ export const readObjectFile = ({ path }: { path: string }) => { const extension = path.split('.').pop(); + if (extension === 'ts') { + const file = fs.readFileSync(path).toString(); + // eslint-disable-next-line no-eval + const obj = eval(typescript.transpile(file)); + return typeof obj === 'function' ? obj() : obj; + } + if (extension === 'js') { const obj = require(path); - if (typeof obj === 'function') { - return obj(); - } - return obj; + return typeof obj === 'function' ? obj() : obj; } if (extension === 'json') { diff --git a/packages/website/components/Header.tsx b/packages/website/components/Header.tsx index a37ea79..d84e6a7 100644 --- a/packages/website/components/Header.tsx +++ b/packages/website/components/Header.tsx @@ -11,7 +11,14 @@ const Header = () => { backgroundColor: 'black', }} > - + Carlin diff --git a/packages/website/components/Layout.tsx b/packages/website/components/Layout.tsx index 0e50091..15bc95c 100644 --- a/packages/website/components/Layout.tsx +++ b/packages/website/components/Layout.tsx @@ -30,6 +30,10 @@ const navs: Array<{ { group: 'Usage', links: [ + { + name: 'deploy', + href: '/docs/usage/deploy', + }, { name: 'deploy static-app', href: '/docs/usage/deploy-static-app', diff --git a/packages/website/components/MaxWidth.tsx b/packages/website/components/MaxWidth.tsx index 49602dc..7686ff8 100644 --- a/packages/website/components/MaxWidth.tsx +++ b/packages/website/components/MaxWidth.tsx @@ -1,7 +1,14 @@ import { Container, SxProps } from 'theme-ui'; -const MaxWidth: React.FC = ({ children }) => { - return {children}; +const MaxWidth: React.FC = ({ + children, + className, +}) => { + return ( + + {children} + + ); }; export default MaxWidth; diff --git a/packages/website/pages/docs/getting-started/configuration.md b/packages/website/pages/docs/getting-started/configuration.md new file mode 100644 index 0000000..e69de29 diff --git a/packages/website/pages/docs/usage/deploy.md b/packages/website/pages/docs/usage/deploy.md new file mode 100644 index 0000000..8721458 --- /dev/null +++ b/packages/website/pages/docs/usage/deploy.md @@ -0,0 +1,3 @@ +## CloudFormation Template + +We may create CloudFormation templates with these extensions: `.ts`, `.js`, `.json`, `.yml`, `.yaml`.