carlin 1.48.0 → 1.48.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +84 -5
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -813,7 +813,34 @@ var saveEnvironmentOutput = /* @__PURE__ */ __name(async ({ outputs, stackName }
813
813
  const latestFilePath = path.join(dotCarlinFolderPath, LATEST_DEPLOY_OUTPUTS_FILENAME);
814
814
  await fs3.promises.writeFile(latestFilePath, JSON.stringify(envFile, null, 2));
815
815
  }, "saveEnvironmentOutput");
816
- var printStackOutputsAfterDeploy = /* @__PURE__ */ __name(async ({ stackName }) => {
816
+ var exportEnvVars = /* @__PURE__ */ __name(async ({ outputs, envExport }) => {
817
+ const githubEnvFile = process.env.GITHUB_ENV;
818
+ for (const [cfOutputKey, envVarName] of Object.entries(envExport)) {
819
+ const output = outputs.find(({ OutputKey }) => {
820
+ return OutputKey === cfOutputKey;
821
+ });
822
+ if (!output?.OutputValue) {
823
+ log5.warn(logPrefix3, `envExport: CloudFormation output "${cfOutputKey}" not found or has no value. Skipping export of "${envVarName}".`);
824
+ continue;
825
+ }
826
+ const value = output.OutputValue;
827
+ if (githubEnvFile) {
828
+ if (value.includes("\n")) {
829
+ log5.warn(logPrefix3, `envExport: value for "${cfOutputKey}" contains newlines and cannot be exported to GITHUB_ENV safely. Skipping.`);
830
+ continue;
831
+ }
832
+ await fs3.promises.appendFile(githubEnvFile, `${envVarName}=${value}
833
+ `);
834
+ log5.info(logPrefix3, `envExport: wrote ${envVarName} to GITHUB_ENV`);
835
+ } else {
836
+ const escapedValue = value.replace(/'/g, `'\\''`);
837
+ process.stdout.write(`export ${envVarName}='${escapedValue}'
838
+ `);
839
+ log5.info(logPrefix3, `envExport: printed export ${envVarName} to stdout`);
840
+ }
841
+ }
842
+ }, "exportEnvVars");
843
+ var printStackOutputsAfterDeploy = /* @__PURE__ */ __name(async ({ stackName, envExport }) => {
817
844
  const { EnableTerminationProtection, StackName, Outputs = [] } = await describeStack({
818
845
  stackName
819
846
  });
@@ -834,6 +861,12 @@ var printStackOutputsAfterDeploy = /* @__PURE__ */ __name(async ({ stackName })
834
861
  ""
835
862
  ].join("\n"));
836
863
  }
864
+ if (envExport && Object.keys(envExport).length > 0) {
865
+ await exportEnvVars({
866
+ outputs: Outputs,
867
+ envExport
868
+ });
869
+ }
837
870
  }, "printStackOutputsAfterDeploy");
838
871
  var deleteStack = /* @__PURE__ */ __name(async ({ stackName }) => {
839
872
  log5.info(logPrefix3, `Deleting stack ${stackName}...`);
@@ -906,7 +939,7 @@ var enableTerminationProtection = /* @__PURE__ */ __name(async ({ stackName }) =
906
939
  throw error;
907
940
  }
908
941
  }, "enableTerminationProtection");
909
- var deploy = /* @__PURE__ */ __name(async ({ terminationProtection = false, ...paramsAndTemplate }) => {
942
+ var deploy = /* @__PURE__ */ __name(async ({ terminationProtection = false, envExport, ...paramsAndTemplate }) => {
910
943
  const { params, template } = await addDefaults(paramsAndTemplate);
911
944
  const stackName = params.StackName;
912
945
  if (!stackName) {
@@ -945,7 +978,8 @@ var deploy = /* @__PURE__ */ __name(async ({ terminationProtection = false, ...p
945
978
  });
946
979
  }
947
980
  await printStackOutputsAfterDeploy({
948
- stackName
981
+ stackName,
982
+ envExport
949
983
  });
950
984
  return describeStack({
951
985
  stackName
@@ -3458,7 +3492,7 @@ var getCloudformationTemplateOptions = /* @__PURE__ */ __name(({ cliOptions, sta
3458
3492
  }, "getCloudformationTemplateOptions");
3459
3493
  var deployCloudFormation = /* @__PURE__ */ __name(async (cliOptions) => {
3460
3494
  try {
3461
- const { lambdaDockerfile, lambdaEntryPoints, lambdaEntryPointsBaseDir, lambdaImage, lambdaExternal, lambdaFormat, lambdaOutdir, parameters, template, templatePath } = cliOptions;
3495
+ const { lambdaDockerfile, lambdaEntryPoints, lambdaEntryPointsBaseDir, lambdaImage, lambdaExternal, lambdaFormat, lambdaOutdir, parameters, template, templatePath, envExport } = cliOptions;
3462
3496
  const { stackName } = await handleDeployInitialization({
3463
3497
  logPrefix: logPrefix12
3464
3498
  });
@@ -3619,7 +3653,8 @@ var deployCloudFormation = /* @__PURE__ */ __name(async (cliOptions) => {
3619
3653
  await deployCloudFormationDeployLambdaCode();
3620
3654
  const output = await deploy({
3621
3655
  params,
3622
- template: cloudFormationTemplate
3656
+ template: cloudFormationTemplate,
3657
+ envExport
3623
3658
  });
3624
3659
  return output;
3625
3660
  } catch (error) {
@@ -5028,6 +5063,50 @@ var options6 = {
5028
5063
  describe: "Set the stack name.",
5029
5064
  type: "string"
5030
5065
  },
5066
+ /**
5067
+ * Mapping of CloudFormation output keys to environment variable names.
5068
+ * After a successful deployment, carlin reads the stack outputs and exports
5069
+ * the mapped variables to the CI/CD runner environment:
5070
+ *
5071
+ * - **GitHub Actions**: appends `KEY=VALUE` lines to `$GITHUB_ENV`.
5072
+ * - **Generic shell**: prints `export KEY=VALUE` lines to stdout.
5073
+ *
5074
+ * Configure in your `carlin.ts`:
5075
+ *
5076
+ * ```ts
5077
+ * export default {
5078
+ * envExport: {
5079
+ * AppSyncApiGraphQLUrl: 'VITE_APPSYNC_GRAPHQL_ENDPOINT',
5080
+ * AppSyncApiArn: 'APPSYNC_API_ARN',
5081
+ * },
5082
+ * };
5083
+ * ```
5084
+ *
5085
+ * Can also be combined with per-environment config:
5086
+ *
5087
+ * ```ts
5088
+ * export default {
5089
+ * environments: {
5090
+ * Staging: {
5091
+ * envExport: {
5092
+ * AppSyncApiGraphQLUrl: 'VITE_APPSYNC_GRAPHQL_ENDPOINT',
5093
+ * },
5094
+ * },
5095
+ * },
5096
+ * };
5097
+ * ```
5098
+ */
5099
+ "env-export": {
5100
+ describe: "Mapping of CloudFormation output keys to environment variable names to export after deployment.",
5101
+ coerce: /* @__PURE__ */ __name((arg) => {
5102
+ if (typeof arg === "object" && arg !== null && !Array.isArray(arg) && Object.values(arg).every((v) => {
5103
+ return typeof v === "string";
5104
+ })) {
5105
+ return arg;
5106
+ }
5107
+ return void 0;
5108
+ }, "coerce")
5109
+ },
5031
5110
  "template-path": {
5032
5111
  alias: "t",
5033
5112
  describe: "Path to the CloudFormation template.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "carlin",
3
- "version": "1.48.0",
3
+ "version": "1.48.2",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "author": "Pedro Arantes <arantespp@gmail.com> (https://twitter.com/arantespp)",
@@ -47,9 +47,9 @@
47
47
  "uglify-js": "^3.19.3",
48
48
  "vercel": "^39.1.1",
49
49
  "yargs": "^17.7.2",
50
- "@ttoss/cloudformation": "^0.12.7",
51
- "@ttoss/read-config-file": "^2.2.5",
52
- "@ttoss/config": "^1.37.5"
50
+ "@ttoss/cloudformation": "^0.12.9",
51
+ "@ttoss/config": "^1.37.7",
52
+ "@ttoss/read-config-file": "^2.2.7"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/adm-zip": "^0.5.6",
@@ -69,7 +69,7 @@
69
69
  "jest": "^30.3.0",
70
70
  "tsup": "^8.5.1",
71
71
  "typescript": "~6.0.2",
72
- "@ttoss/test-utils": "^4.2.5"
72
+ "@ttoss/test-utils": "^4.2.7"
73
73
  },
74
74
  "keywords": [],
75
75
  "publishConfig": {