@openfn/cli 1.18.5 → 1.19.0

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.
package/dist/index.js CHANGED
@@ -32,6 +32,18 @@ function spawn_default(opts2) {
32
32
  import yargs from "yargs";
33
33
  import { hideBin } from "yargs/helpers";
34
34
 
35
+ // src/env.ts
36
+ import { config } from "dotenv";
37
+ import { expand } from "dotenv-expand";
38
+ var env;
39
+ var env_default = (path3) => {
40
+ env = expand(config({ path: path3, override: true, debug: false, quiet: true }));
41
+ if (env.error) {
42
+ return null;
43
+ }
44
+ return env.parsed;
45
+ };
46
+
35
47
  // src/options.ts
36
48
  import nodePath from "node:path";
37
49
 
@@ -39,7 +51,7 @@ import nodePath from "node:path";
39
51
  var DEFAULT_REPO_DIR = "/tmp/openfn/repo";
40
52
 
41
53
  // src/util/expand-adaptors.ts
42
- var expand = (name) => {
54
+ var expand2 = (name) => {
43
55
  if (typeof name === "string") {
44
56
  const [left] = name.split("=");
45
57
  if (left.match("/") || left.endsWith(".js")) {
@@ -51,13 +63,13 @@ var expand = (name) => {
51
63
  };
52
64
  var expand_adaptors_default = (input) => {
53
65
  if (Array.isArray(input)) {
54
- return input?.map(expand);
66
+ return input?.map(expand2);
55
67
  }
56
68
  const plan = input;
57
69
  Object.values(plan.workflow.steps).forEach((step) => {
58
70
  const job = step;
59
71
  if (job.adaptors) {
60
- job.adaptors = job.adaptors.map(expand);
72
+ job.adaptors = job.adaptors.map(expand2);
61
73
  }
62
74
  });
63
75
  return plan;
@@ -307,7 +319,7 @@ var endpoint = {
307
319
  description: "[beta only] URL to Lightning endpoint"
308
320
  }
309
321
  };
310
- var env = {
322
+ var env2 = {
311
323
  name: "env",
312
324
  yargs: {
313
325
  description: "[beta only] Environment name (eg staging, prod, branch)"
@@ -1016,7 +1028,7 @@ var options7 = [
1016
1028
  beta,
1017
1029
  configPath,
1018
1030
  endpoint,
1019
- env,
1031
+ env2,
1020
1032
  log,
1021
1033
  override(path2, {
1022
1034
  description: "path to output the project to"
@@ -1174,6 +1186,10 @@ var workflowVersionCommand = {
1174
1186
  var command_default14 = workflowVersionCommand;
1175
1187
 
1176
1188
  // src/cli.ts
1189
+ var env3 = env_default();
1190
+ if (env3) {
1191
+ process.env.$DOT_ENV_OVERRIDES = Object.keys(env3).join(",");
1192
+ }
1177
1193
  var y = yargs(hideBin(process.argv));
1178
1194
  var cmd = y.command(command_default7).command(command_default3).command(command_default2).command(command_default4).command(install).command(repo).command(command_default10).command(command_default6).command(command_default).command(command_default8).command(command_default5).command(command_default9).command(command_default11).command(command_default12).command(command_default13).command(command_default14).command({
1179
1195
  command: "version",
@@ -1609,21 +1609,22 @@ import { deployProject } from "@openfn/deploy";
1609
1609
  async function handler(options, logger) {
1610
1610
  const { OPENFN_API_KEY } = process.env;
1611
1611
  const { endpoint } = options;
1612
- const config = {
1612
+ const config2 = {
1613
1613
  apiKey: options.apiKey
1614
1614
  };
1615
1615
  if (!options.apiKey && OPENFN_API_KEY) {
1616
1616
  logger.info("Using OPENFN_API_KEY environment variable");
1617
- config.apiKey = OPENFN_API_KEY;
1617
+ config2.apiKey = OPENFN_API_KEY;
1618
1618
  }
1619
1619
  const project = await Project2.from("fs", { root: options.path || "." });
1620
+ console.log({ openfn: project.openfn });
1620
1621
  const state = project.serialize("state", { format: "json" });
1621
1622
  logger.debug("Converted local project to app state:");
1622
1623
  logger.debug(JSON.stringify(state, null, 2));
1623
- config.endpoint = endpoint || project.openfn?.endpoint;
1624
+ config2.endpoint = endpoint || project.openfn?.endpoint;
1624
1625
  logger.info("Sending project to app...");
1625
- await deployProject(config, state);
1626
- logger.success("Updated project at", config.endpoint);
1626
+ await deployProject(config2, state);
1627
+ logger.success("Updated project at", config2.endpoint);
1627
1628
  }
1628
1629
 
1629
1630
  // src/deploy/handler.ts
@@ -1633,23 +1634,23 @@ async function deployHandler(options, logger, deployFn = actualDeploy) {
1633
1634
  return handler(options, logger);
1634
1635
  }
1635
1636
  try {
1636
- const config = mergeOverrides(await getConfig(options.configPath), options);
1637
- logger.debug("Deploying with config", JSON.stringify(config, null, 2));
1637
+ const config2 = mergeOverrides(await getConfig(options.configPath), options);
1638
+ logger.debug("Deploying with config", JSON.stringify(config2, null, 2));
1638
1639
  if (options.confirm === false) {
1639
- config.requireConfirmation = options.confirm;
1640
+ config2.requireConfirmation = options.confirm;
1640
1641
  }
1641
1642
  if (process.env["OPENFN_API_KEY"]) {
1642
1643
  logger.info("Using OPENFN_API_KEY environment variable");
1643
- config.apiKey = process.env["OPENFN_API_KEY"];
1644
+ config2.apiKey = process.env["OPENFN_API_KEY"];
1644
1645
  }
1645
1646
  if (process.env["OPENFN_ENDPOINT"]) {
1646
1647
  logger.info("Using OPENFN_ENDPOINT environment variable");
1647
- config.endpoint = process.env["OPENFN_ENDPOINT"];
1648
+ config2.endpoint = process.env["OPENFN_ENDPOINT"];
1648
1649
  }
1649
- logger.debug("Deploying with config", config);
1650
+ logger.debug("Deploying with config", config2);
1650
1651
  logger.info(`Deploying`);
1651
- validateConfig(config);
1652
- const isOk = await deployFn(config, logger);
1652
+ validateConfig(config2);
1653
+ const isOk = await deployFn(config2, logger);
1653
1654
  process.exitCode = isOk ? 0 : 1;
1654
1655
  return isOk;
1655
1656
  } catch (error) {
@@ -1661,15 +1662,15 @@ async function deployHandler(options, logger, deployFn = actualDeploy) {
1661
1662
  throw error;
1662
1663
  }
1663
1664
  }
1664
- function mergeOverrides(config, options) {
1665
+ function mergeOverrides(config2, options) {
1665
1666
  return {
1666
- ...config,
1667
- apiKey: pickFirst(process.env["OPENFN_API_KEY"], config.apiKey),
1668
- endpoint: pickFirst(process.env["OPENFN_ENDPOINT"], config.endpoint),
1669
- statePath: pickFirst(options.statePath, config.statePath),
1670
- specPath: pickFirst(options.projectPath, config.specPath),
1667
+ ...config2,
1668
+ apiKey: pickFirst(process.env["OPENFN_API_KEY"], config2.apiKey),
1669
+ endpoint: pickFirst(process.env["OPENFN_ENDPOINT"], config2.endpoint),
1670
+ statePath: pickFirst(options.statePath, config2.statePath),
1671
+ specPath: pickFirst(options.projectPath, config2.specPath),
1671
1672
  configPath: options.configPath,
1672
- requireConfirmation: pickFirst(options.confirm, config.requireConfirmation)
1673
+ requireConfirmation: pickFirst(options.confirm, config2.requireConfirmation)
1673
1674
  };
1674
1675
  }
1675
1676
  function pickFirst(...args) {
@@ -1894,8 +1895,8 @@ var sortKeys = (obj) => {
1894
1895
  });
1895
1896
  return newObj;
1896
1897
  };
1897
- var generateKey = (config, adaptor) => {
1898
- const sorted = sortKeys(config);
1898
+ var generateKey = (config2, adaptor) => {
1899
+ const sorted = sortKeys(config2);
1899
1900
  const key = `${JSON.stringify(sorted)}-${adaptor}`;
1900
1901
  return createHash("sha256").update(key).digest("hex");
1901
1902
  };
@@ -2021,8 +2022,8 @@ var metadataHandler = async (options, logger) => {
2021
2022
  const state = await load_state_default({}, options, logger);
2022
2023
  logger.success(`Generating metadata`);
2023
2024
  logger.info("config:", state);
2024
- const config = state.configuration;
2025
- if (!config || Object.keys(config).length === 0) {
2025
+ const config2 = state.configuration;
2026
+ if (!config2 || Object.keys(config2).length === 0) {
2026
2027
  logger.error("ERROR: Invalid configuration passed");
2027
2028
  process.exit(1);
2028
2029
  }
@@ -2030,7 +2031,7 @@ var metadataHandler = async (options, logger) => {
2030
2031
  logger.success("Done!");
2031
2032
  logger.print(getCachePath2(repoDir, id));
2032
2033
  };
2033
- const id = generateKey(config, adaptor);
2034
+ const id = generateKey(config2, adaptor);
2034
2035
  if (!options.force) {
2035
2036
  logger.debug("config hash: ", id);
2036
2037
  const cached = await get2(repoDir, id);
@@ -2056,7 +2057,7 @@ var metadataHandler = async (options, logger) => {
2056
2057
  const mod = await import(adaptorPath);
2057
2058
  if (mod.metadata && typeof mod.metadata === "function") {
2058
2059
  logger.info("Metadata function found. Generating metadata...");
2059
- const result = await mod.metadata(config);
2060
+ const result = await mod.metadata(config2);
2060
2061
  decorateMetadata(result);
2061
2062
  await set2(
2062
2063
  repoDir,
@@ -2102,12 +2103,12 @@ import {
2102
2103
  } from "@openfn/deploy";
2103
2104
 
2104
2105
  // src/pull/beta.ts
2105
- import { confirm } from "@inquirer/prompts";
2106
- import path9 from "path";
2106
+ import path9 from "node:path";
2107
2107
  import fs4 from "node:fs/promises";
2108
+ import { rimraf } from "rimraf";
2109
+ import { confirm } from "@inquirer/prompts";
2108
2110
  import { getProject } from "@openfn/deploy";
2109
2111
  import Project3, { Workspace } from "@openfn/project";
2110
- import { rimraf } from "rimraf";
2111
2112
  async function handler2(options, logger) {
2112
2113
  const { OPENFN_API_KEY, OPENFN_ENDPOINT } = process.env;
2113
2114
  const cfg = {
@@ -2124,7 +2125,7 @@ async function handler2(options, logger) {
2124
2125
  }
2125
2126
  const outputRoot = path9.resolve(options.path || ".");
2126
2127
  const workspace = new Workspace(outputRoot);
2127
- const config = workspace.getConfig();
2128
+ const config2 = workspace.getConfig();
2128
2129
  const { data } = await getProject(cfg, options.projectId);
2129
2130
  const name = options.env || "project";
2130
2131
  const project = await Project3.from(
@@ -2133,13 +2134,16 @@ async function handler2(options, logger) {
2133
2134
  {
2134
2135
  endpoint: cfg.endpoint,
2135
2136
  env: name,
2137
+ // TODO this is NOT an openfn metadata key
2138
+ // (it should not be sent back to lighting)
2139
+ // should add it to the local or meta objects instead
2136
2140
  fetched_at: (/* @__PURE__ */ new Date()).toISOString()
2137
2141
  },
2138
- config
2142
+ config2
2139
2143
  );
2140
2144
  const projectFileName = project.getIdentifier();
2141
2145
  await fs4.mkdir(`${outputRoot}/.projects`, { recursive: true });
2142
- let stateOutputPath = `${outputRoot}/.projects/${projectFileName}`;
2146
+ const stateOutputPath = `${outputRoot}/.projects/${projectFileName}`;
2143
2147
  const workflowsRoot = path9.resolve(
2144
2148
  outputRoot,
2145
2149
  project.config.dirs.workflows ?? "workflows"
@@ -2147,7 +2151,7 @@ async function handler2(options, logger) {
2147
2151
  if (!await confirm({
2148
2152
  message: `This will remove all files in ${path9.resolve(
2149
2153
  workflowsRoot
2150
- )} and rebuild the workflow. Are you sure you wish to proceed?
2154
+ )}. Are you sure you wish to proceed?
2151
2155
  `,
2152
2156
  default: true
2153
2157
  })) {
@@ -2155,13 +2159,13 @@ async function handler2(options, logger) {
2155
2159
  return false;
2156
2160
  }
2157
2161
  await rimraf(workflowsRoot);
2158
- const state = project?.serialize("state");
2159
- if (project.config.formats.project === "yaml") {
2160
- await fs4.writeFile(`${stateOutputPath}.yaml`, state);
2162
+ const projFile = project?.serialize("project");
2163
+ if (typeof projFile === "string") {
2164
+ await fs4.writeFile(`${stateOutputPath}.yaml`, projFile);
2161
2165
  } else {
2162
2166
  await fs4.writeFile(
2163
2167
  `${stateOutputPath}.json`,
2164
- JSON.stringify(state, null, 2)
2168
+ JSON.stringify(projFile, null, 2)
2165
2169
  );
2166
2170
  }
2167
2171
  logger.success(`Saved project file to ${stateOutputPath}`);
@@ -2185,20 +2189,20 @@ async function pullHandler(options, logger) {
2185
2189
  return handler2(options, logger);
2186
2190
  }
2187
2191
  try {
2188
- const config = mergeOverrides2(await getConfig2(options.configPath), options);
2192
+ const config2 = mergeOverrides2(await getConfig2(options.configPath), options);
2189
2193
  if (process.env["OPENFN_API_KEY"]) {
2190
2194
  logger.info("Using OPENFN_API_KEY environment variable");
2191
- config.apiKey = process.env["OPENFN_API_KEY"];
2195
+ config2.apiKey = process.env["OPENFN_API_KEY"];
2192
2196
  }
2193
2197
  if (process.env["OPENFN_ENDPOINT"]) {
2194
2198
  logger.info("Using OPENFN_ENDPOINT environment variable");
2195
- config.endpoint = process.env["OPENFN_ENDPOINT"];
2199
+ config2.endpoint = process.env["OPENFN_ENDPOINT"];
2196
2200
  }
2197
2201
  logger.always(
2198
2202
  "Downloading existing project state (as JSON) from the server."
2199
2203
  );
2200
2204
  const { data: project } = await getProject2(
2201
- config,
2205
+ config2,
2202
2206
  options.projectId,
2203
2207
  options.snapshots
2204
2208
  );
@@ -2219,12 +2223,12 @@ async function pullHandler(options, logger) {
2219
2223
  );
2220
2224
  const url2 = new URL(
2221
2225
  `api/provision/yaml?${queryParams.toString()}`,
2222
- config.endpoint
2226
+ config2.endpoint
2223
2227
  );
2224
2228
  logger.debug("Fetching project spec from", url2);
2225
2229
  const res = await fetch(url2, {
2226
2230
  headers: {
2227
- Authorization: `Bearer ${config.apiKey}`,
2231
+ Authorization: `Bearer ${config2.apiKey}`,
2228
2232
  Accept: "application/json"
2229
2233
  }
2230
2234
  });
@@ -2236,16 +2240,16 @@ async function pullHandler(options, logger) {
2236
2240
  process.exitCode = 1;
2237
2241
  process.exit(1);
2238
2242
  }
2239
- const resolvedPath = path10.resolve(config.specPath);
2243
+ const resolvedPath = path10.resolve(config2.specPath);
2240
2244
  logger.debug("reading spec from", resolvedPath);
2241
2245
  const updatedSpec = await syncRemoteSpec(
2242
2246
  await res.text(),
2243
2247
  state,
2244
- config,
2248
+ config2,
2245
2249
  logger
2246
2250
  );
2247
2251
  await fs5.writeFile(
2248
- path10.resolve(config.statePath),
2252
+ path10.resolve(config2.statePath),
2249
2253
  JSON.stringify(state, null, 2)
2250
2254
  );
2251
2255
  await fs5.writeFile(resolvedPath, updatedSpec);
@@ -2263,13 +2267,13 @@ async function pullHandler(options, logger) {
2263
2267
  throw error;
2264
2268
  }
2265
2269
  }
2266
- function mergeOverrides2(config, options) {
2270
+ function mergeOverrides2(config2, options) {
2267
2271
  return {
2268
- ...config,
2269
- apiKey: pickFirst2(process.env["OPENFN_API_KEY"], config.apiKey),
2270
- endpoint: pickFirst2(process.env["OPENFN_ENDPOINT"], config.endpoint),
2272
+ ...config2,
2273
+ apiKey: pickFirst2(process.env["OPENFN_API_KEY"], config2.apiKey),
2274
+ endpoint: pickFirst2(process.env["OPENFN_ENDPOINT"], config2.endpoint),
2271
2275
  configPath: options.configPath,
2272
- requireConfirmation: pickFirst2(options.confirm, config.requireConfirmation)
2276
+ requireConfirmation: pickFirst2(options.confirm, config2.requireConfirmation)
2273
2277
  };
2274
2278
  }
2275
2279
  function pickFirst2(...args) {
@@ -2353,12 +2357,12 @@ var checkoutHandler = async (options, logger) => {
2353
2357
  logger.error("Command was run in an invalid openfn workspace");
2354
2358
  return;
2355
2359
  }
2356
- const { project: _, ...config } = workspace.getConfig();
2360
+ const { project: _, ...config2 } = workspace.getConfig();
2357
2361
  let switchProject;
2358
2362
  if (/\.(yaml|json)$/.test(options.projectId)) {
2359
2363
  const filePath = options.projectId.startsWith("/") ? options.projectId : path13.join(commandPath, options.projectId);
2360
2364
  logger.debug("Loading project from path ", filePath);
2361
- switchProject = await Project5.from("path", filePath, config);
2365
+ switchProject = await Project5.from("path", filePath, config2);
2362
2366
  } else {
2363
2367
  switchProject = workspace.get(options.projectId);
2364
2368
  }
@@ -2367,7 +2371,7 @@ var checkoutHandler = async (options, logger) => {
2367
2371
  `Project with id ${options.projectId} not found in the workspace`
2368
2372
  );
2369
2373
  }
2370
- await rimraf2(path13.join(commandPath, config.workflowRoot ?? "workflows"));
2374
+ await rimraf2(path13.join(commandPath, config2.workflowRoot ?? "workflows"));
2371
2375
  const files = switchProject.serialize("fs");
2372
2376
  for (const f in files) {
2373
2377
  if (files[f]) {
@@ -2559,6 +2563,25 @@ ${prefix(name)}${version2}`;
2559
2563
  };
2560
2564
  var print_versions_default = printVersions;
2561
2565
 
2566
+ // src/env.ts
2567
+ import { config } from "dotenv";
2568
+ import { expand as expand2 } from "dotenv-expand";
2569
+ var env;
2570
+ var report = (logger) => {
2571
+ let envs = [];
2572
+ if (process.env.$DOT_ENV_OVERRIDES) {
2573
+ envs = process.env.$DOT_ENV_OVERRIDES.split(",").map((s) => s.trim());
2574
+ } else {
2575
+ envs = Object.keys(env?.parsed ?? {});
2576
+ }
2577
+ if (envs.length) {
2578
+ logger?.always(`Imported ${envs.length} env vars from .env file`);
2579
+ logger?.debug("Envs set from .env: ", envs.join(", "));
2580
+ } else if (env && env.error) {
2581
+ logger?.debug(".env not found");
2582
+ }
2583
+ };
2584
+
2562
2585
  // src/commands.ts
2563
2586
  var handlers = {
2564
2587
  apollo: handler_default,
@@ -2588,6 +2611,7 @@ var parse = async (options, log) => {
2588
2611
  if (options.command === "execute" || options.command === "test") {
2589
2612
  await print_versions_default(logger, options);
2590
2613
  }
2614
+ report(logger);
2591
2615
  const { monorepoPath } = options;
2592
2616
  if (monorepoPath) {
2593
2617
  if (monorepoPath === "ERR") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfn/cli",
3
- "version": "1.18.5",
3
+ "version": "1.19.0",
4
4
  "description": "CLI devtools for the OpenFn toolchain",
5
5
  "engines": {
6
6
  "node": ">=18",
@@ -41,19 +41,21 @@
41
41
  "dependencies": {
42
42
  "@inquirer/prompts": "^1.2.3",
43
43
  "chalk": "^5.6.2",
44
+ "dotenv": "^17.2.3",
45
+ "dotenv-expand": "^12.0.3",
44
46
  "figures": "^5.0.0",
45
47
  "rimraf": "^6.0.1",
46
48
  "treeify": "^1.1.0",
47
49
  "undici": "7.12.0",
48
50
  "ws": "^8.18.3",
49
51
  "yargs": "^17.7.2",
52
+ "@openfn/compiler": "1.2.1",
53
+ "@openfn/deploy": "0.11.4",
50
54
  "@openfn/describe-package": "0.1.5",
51
- "@openfn/lexicon": "^1.2.6",
52
- "@openfn/deploy": "0.11.3",
53
- "@openfn/compiler": "1.1.5",
54
- "@openfn/project": "^0.9.0",
55
- "@openfn/logger": "1.0.6",
56
- "@openfn/runtime": "1.7.5"
55
+ "@openfn/lexicon": "^1.2.7",
56
+ "@openfn/logger": "1.1.0",
57
+ "@openfn/project": "^0.9.1",
58
+ "@openfn/runtime": "1.7.6"
57
59
  },
58
60
  "files": [
59
61
  "dist",