diff --git a/Dockerfile b/Dockerfile index d351ff5..24459c3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ ARG NODE_TAG -FROM node:${NODE_TAG} +FROM node:${NODE_TAG}-alpine RUN mkdir /pipe WORKDIR /pipe diff --git a/pipe/entrypoint.ts b/pipe/entrypoint.ts index 4ed8ba1..8a028c9 100644 --- a/pipe/entrypoint.ts +++ b/pipe/entrypoint.ts @@ -1,29 +1,54 @@ +import { glob } from "glob"; import { runCLICommand } from "./cmd"; import { env } from "./env"; import { findServerlessYaml } from "./findServerlessYaml"; import { injectCfnRole } from "./injectCfnRole"; import { uploadDeploymentBadge } from "./uploadDeploymentBadge"; +import { nodeModulesDirectoryExist } from "./findNodeModules"; + +const cloneDir = process.env.BITBUCKET_CLONE_DIR || ""; async function main() { let deploymentStatus = false; try { + const rootServerlessYmlFile = await glob( + `${cloneDir}/serverless.{yml,yaml}`, + {} + ); + const nxProject = rootServerlessYmlFile.length == 0; + if (!env.awsAccessKeyId || !env.awsSecretAccessKey) { throw new Error("AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY not set"); } - const serverlessFiles = await findServerlessYaml( - `${process.env.BITBUCKET_CLONE_DIR}/services` + const servicesPath = nxProject ? env.servicesPath : ""; + let serverlessFiles = await findServerlessYaml( + `${cloneDir}${servicesPath}` ); + await Promise.all( serverlessFiles.map((file) => injectCfnRole(file, env.cfnRole)) ); - await runCLICommand([ - "npm ci", + const commands = [ `npx serverless config credentials --provider aws --profile ${env.profile} --key ${env.awsAccessKeyId} --secret ${env.awsSecretAccessKey}`, - `npx nx run-many -t deploy -- --verbose --stage ${env.stage} --aws-profile ${env.profile}`, - ]); + ]; + + const nodeModulesExists = await nodeModulesDirectoryExist(cloneDir); + if (!nodeModulesExists) { + commands.unshift("npm ci"); + } + + const nxCommand = nxProject + ? `npx nx run-many -t ${env.cmd} --` + : `npx serverless ${env.cmd}`; + const verboseOption = env.debug ? "--verbose" : ""; + const serverlessCommand = `${nxCommand} --stage ${env.stage} --aws-profile ${env.profile}${verboseOption}`; + + commands.push(serverlessCommand); + + await runCLICommand(commands); deploymentStatus = true; } catch (error) { diff --git a/pipe/env.ts b/pipe/env.ts index 51da4bc..dd0ca6f 100644 --- a/pipe/env.ts +++ b/pipe/env.ts @@ -2,6 +2,7 @@ interface Env { debug: boolean; stage: string; profile: string; + cmd: string; awsAccessKeyId?: string; awsSecretAccessKey?: string; cfnRole?: string; @@ -12,12 +13,14 @@ interface Env { bitbucketBranch?: string; bitbucketRepoSlug?: string; bitbucketWorkspace?: string; + servicesPath?: string; } export const env: Env = { debug: process.env.DEBUG === "true", stage: process.env.STAGE || "stg", profile: process.env.PROFILE || "bitbucket-deployer", + cmd: process.env.cmd || "deploy", awsAccessKeyId: process.env.AWS_ACCESS_KEY_ID, awsSecretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, cfnRole: process.env.CFN_ROLE, @@ -28,4 +31,5 @@ export const env: Env = { bitbucketBranch: process.env.BITBUCKET_BRANCH, bitbucketRepoSlug: process.env.BITBUCKET_REPO_SLUG, bitbucketWorkspace: process.env.BITBUCKET_WORKSPACE, + servicesPath: process.env.servicesPath || "/services", }; diff --git a/pipe/findNodeModules.ts b/pipe/findNodeModules.ts new file mode 100644 index 0000000..ec4e7bd --- /dev/null +++ b/pipe/findNodeModules.ts @@ -0,0 +1,16 @@ +import * as fs from "fs"; + +export async function nodeModulesDirectoryExist( + directoryPath: string +): Promise { + return fs.promises + .access(`${directoryPath}/node_modules`, fs.constants.F_OK) + .then(() => true) + .catch((error) => { + if (error.code === "ENOENT") { + return false; + } else { + throw error; + } + }); +} diff --git a/pipe/findServerlessYaml.ts b/pipe/findServerlessYaml.ts index 3bc9960..5087ccb 100644 --- a/pipe/findServerlessYaml.ts +++ b/pipe/findServerlessYaml.ts @@ -6,7 +6,7 @@ export async function findServerlessYaml(basePath: string) { console.log(`Fetching serverless configuration with pattern ${globPattern}`); - const files = await glob(globPattern, {}); + const files = await glob(globPattern, { ignore: ["**/node_modules/**"] }); for (const file of files) { console.log("Found serverless.yml at: ", file);