@openfn/cli 1.21.0 → 1.23.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
@@ -147,6 +147,7 @@ var ensureLogOpts = (opts2) => {
147
147
  var ensure_log_opts_default = ensureLogOpts;
148
148
 
149
149
  // src/options.ts
150
+ import { existsSync } from "node:fs";
150
151
  var setDefaultValue = (opts2, key2, value2) => {
151
152
  const v = opts2[key2];
152
153
  if (isNaN(v) && !v) {
@@ -284,6 +285,19 @@ var credentials = {
284
285
  yargs: {
285
286
  alias: ["creds"],
286
287
  description: "A path which points to a credential map"
288
+ },
289
+ ensure(opts2) {
290
+ if (opts2.credentials) {
291
+ const mapPath = nodePath.resolve(
292
+ opts2.workspace ?? "",
293
+ opts2.credentials
294
+ );
295
+ if (!existsSync(mapPath)) {
296
+ const e = new Error("Credential map not found at " + mapPath);
297
+ delete e.stack;
298
+ throw e;
299
+ }
300
+ }
287
301
  }
288
302
  };
289
303
  var describe = {
@@ -363,13 +377,12 @@ var inputPath = {
363
377
  },
364
378
  ensure: (opts2) => {
365
379
  const { path: basePath } = opts2;
366
- if (basePath?.endsWith(".json")) {
380
+ if (basePath?.match(/.(json|ya?ml)$/)) {
367
381
  opts2.planPath = basePath;
368
382
  } else if (basePath?.endsWith(".js")) {
369
383
  opts2.expressionPath = basePath;
370
- } else {
371
- const base = getBaseDir(opts2);
372
- setDefaultValue(opts2, "expressionPath", nodePath.join(base, "job.js"));
384
+ } else if (!opts2.expressionPath) {
385
+ opts2.workflowName = basePath;
373
386
  }
374
387
  }
375
388
  };
@@ -902,6 +915,7 @@ var env2 = {
902
915
  var alias = {
903
916
  name: "alias",
904
917
  yargs: {
918
+ alias: ["env"],
905
919
  description: "Environment name (eg staging, prod, branch)"
906
920
  }
907
921
  };
@@ -923,7 +937,7 @@ var workflowMappings = {
923
937
  var outputPath2 = {
924
938
  name: "output-path",
925
939
  yargs: {
926
- alias: ["output"],
940
+ alias: ["o", "output"],
927
941
  type: "string",
928
942
  description: "Path to output the fetched project to"
929
943
  }
@@ -1021,7 +1035,8 @@ var options5 = [
1021
1035
  stateStdin,
1022
1036
  timeout,
1023
1037
  trace,
1024
- useAdaptorsMonorepo
1038
+ useAdaptorsMonorepo,
1039
+ workspace
1025
1040
  ];
1026
1041
  var executeCommand = {
1027
1042
  command: "execute <path> [workflow]",
@@ -332,20 +332,34 @@ var getAutoinstallTargets = (plan) => {
332
332
  var get_autoinstall_targets_default = getAutoinstallTargets;
333
333
 
334
334
  // src/execute/apply-credential-map.ts
335
+ var CREDENTIALS_KEY = "$CREDENTIALS$";
335
336
  var applyCredentialMap = (plan, map = {}, logger) => {
336
337
  const stepsWithCredentialIds = plan.workflow.steps.filter(
337
- (step) => typeof step.configuration === "string" && !step.configuration.endsWith(".json")
338
+ (step) => typeof step.configuration === "string" && !step.configuration.endsWith(".json") || step.configuration?.[CREDENTIALS_KEY]
338
339
  );
339
340
  const unmapped = {};
340
341
  for (const step of stepsWithCredentialIds) {
341
- if (map[step.configuration]) {
342
- logger?.debug(
343
- `Applying credential ${step.configuration} to "${step.name ?? step.id}"`
344
- );
345
- step.configuration = map[step.configuration];
342
+ if (typeof step.configuration === "string") {
343
+ const configId = step.configuration;
344
+ if (configId in map) {
345
+ step.configuration = map[configId];
346
+ } else {
347
+ unmapped[configId] = true;
348
+ delete step.configuration;
349
+ }
346
350
  } else {
347
- unmapped[step.configuration] = true;
348
- delete step.configuration;
351
+ const configId = step.configuration[CREDENTIALS_KEY];
352
+ delete step.configuration[CREDENTIALS_KEY];
353
+ if (configId in map) {
354
+ Object.assign(step.configuration, map[configId]);
355
+ } else {
356
+ unmapped[configId] = true;
357
+ }
358
+ if (!(configId in unmapped)) {
359
+ logger?.debug(
360
+ `Applied credential ${configId} to "${step.name ?? step.id}"`
361
+ );
362
+ }
349
363
  }
350
364
  }
351
365
  if (Object.keys(unmapped).length) {
@@ -711,16 +725,15 @@ var validateAdaptors = async (options7, logger) => {
711
725
  if (options7.skipAdaptorValidation) {
712
726
  return;
713
727
  }
714
- const isPlan = options7.planPath || options7.workflowPath || options7.workflow;
715
728
  const hasDeclaredAdaptors = options7.adaptors && options7.adaptors.length > 0;
716
- if (isPlan && hasDeclaredAdaptors) {
729
+ if (!options7.expressionPath && hasDeclaredAdaptors) {
717
730
  logger.error("ERROR: adaptor and workflow provided");
718
731
  logger.error(
719
732
  "This is probably not what you meant to do. A workflow should declare an adaptor for each job."
720
733
  );
721
734
  throw new Error("adaptor and workflow provided");
722
735
  }
723
- if (!isPlan && !hasDeclaredAdaptors) {
736
+ if (options7.expressionPath && !hasDeclaredAdaptors) {
724
737
  logger.warn("WARNING: No adaptor provided!");
725
738
  logger.warn(
726
739
  "This job will probably fail. Pass an adaptor with the -a flag, eg:"
@@ -736,7 +749,7 @@ var validate_adaptors_default = validateAdaptors;
736
749
  import fs3 from "node:fs/promises";
737
750
  import path4, { dirname as dirname2 } from "node:path";
738
751
  import { isPath } from "@openfn/compiler";
739
- import Project, { yamlToJson } from "@openfn/project";
752
+ import { Workspace, yamlToJson } from "@openfn/project";
740
753
 
741
754
  // src/util/expand-adaptors.ts
742
755
  var expand = (name) => {
@@ -823,47 +836,60 @@ var resolve_path_default = (path17, root) => {
823
836
 
824
837
  // src/util/load-plan.ts
825
838
  var loadPlan = async (options7, logger) => {
826
- const { workflowPath, planPath, expressionPath } = options7;
839
+ const { workflowPath, planPath, expressionPath, workflowName } = options7;
840
+ let workflowObj;
841
+ if (workflowName || options7.workflow) {
842
+ logger.debug(
843
+ "Loading workflow from active project in workspace at ",
844
+ options7.workspace
845
+ );
846
+ const workspace2 = new Workspace(options7.workspace);
847
+ const proj = await workspace2.getCheckedOutProject();
848
+ const name = workflowName || options7.workflow;
849
+ const workflow2 = proj?.getWorkflow(name);
850
+ if (!workflow2) {
851
+ const e = new Error(`Could not find Workflow "${name}"`);
852
+ delete e.stack;
853
+ throw e;
854
+ }
855
+ workflowObj = {
856
+ workflow: workflow2.toJSON()
857
+ };
858
+ options7.credentials ??= workspace2.getConfig().credentials;
859
+ options7.collectionsEndpoint ??= proj.openfn?.endpoint;
860
+ }
827
861
  if (options7.path && /ya?ml$/.test(options7.path)) {
828
862
  const content = await fs3.readFile(path4.resolve(options7.path), "utf-8");
829
- const workflow2 = yamlToJson(content);
830
863
  options7.baseDir = dirname2(options7.path);
831
- return loadXPlan({ workflow: workflow2 }, options7, logger);
832
- }
833
- if (options7.path && options7.workflow) {
834
- options7.baseDir = options7.path;
835
- return fromProject(options7.path, options7.workflow, options7, logger);
836
- }
837
- if (!expressionPath && !workflowPath && !/\.(js|json|yaml)+$/.test(options7.path || "") && !options7.workflow) {
838
- const workflow2 = options7.path;
839
- return fromProject(path4.resolve("."), workflow2, options7, logger);
864
+ workflowObj = yamlToJson(content);
865
+ const { options: o, ...rest } = workflowObj;
866
+ if (!workflowObj.workflow && workflowObj.options) {
867
+ workflowObj = { workflow: rest, options: o };
868
+ }
840
869
  }
841
- if (expressionPath) {
870
+ if (!workflowObj && expressionPath) {
842
871
  return loadExpression(options7, logger);
843
872
  }
844
873
  const jsonPath = planPath || workflowPath;
845
- if (!options7.baseDir) {
874
+ if (jsonPath && !options7.baseDir) {
846
875
  options7.baseDir = path4.dirname(jsonPath);
847
876
  }
848
- const json = await loadJson(jsonPath, logger);
849
- const defaultName = path4.parse(jsonPath).name;
850
- if (json.workflow) {
851
- return loadXPlan(json, options7, logger, defaultName);
877
+ workflowObj = workflowObj ?? await loadJson(jsonPath, logger);
878
+ const defaultName = workflowObj.name || path4.parse(jsonPath ?? "").name;
879
+ if (workflowObj.jobs) {
880
+ return loadOldWorkflow(workflowObj, options7, logger, defaultName);
881
+ } else if (workflowObj.workflow) {
882
+ return loadXPlan(
883
+ workflowObj,
884
+ Object.assign({}, workflowObj.options, options7),
885
+ logger,
886
+ defaultName
887
+ );
852
888
  } else {
853
- return loadOldWorkflow(json, options7, logger, defaultName);
889
+ return loadXPlan({ workflow: workflowObj }, options7, logger, defaultName);
854
890
  }
855
891
  };
856
892
  var load_plan_default = loadPlan;
857
- var fromProject = async (rootDir, workflowName, options7, logger) => {
858
- logger.debug("Loading Repo from ", path4.resolve(rootDir));
859
- const project = await Project.from("fs", { root: rootDir });
860
- logger.debug("Loading workflow ", workflowName);
861
- const workflow2 = project.getWorkflow(workflowName);
862
- if (!workflow2) {
863
- throw new Error(`Workflow "${workflowName}" not found`);
864
- }
865
- return loadXPlan({ workflow: workflow2 }, options7, logger);
866
- };
867
893
  var loadJson = async (workflowPath, logger) => {
868
894
  let text;
869
895
  try {
@@ -1034,11 +1060,12 @@ var ensureAdaptors = (plan) => {
1034
1060
  });
1035
1061
  };
1036
1062
  var ensureCollections = (plan, {
1037
- endpoint: endpoint2 = "https://app.openfn.org",
1063
+ endpoint: endpoint2,
1038
1064
  version = "latest",
1039
1065
  apiKey: apiKey2 = "null"
1040
1066
  } = {}, logger) => {
1041
1067
  let collectionsFound = false;
1068
+ endpoint2 ??= plan.options?.collectionsEndpoint ?? "https://app.openfn.org";
1042
1069
  Object.values(plan.workflow.steps).filter((step) => step.expression?.match(/(collections\.)/)).forEach((step) => {
1043
1070
  const job = step;
1044
1071
  if (!job.adaptors?.find(
@@ -1049,6 +1076,11 @@ var ensureCollections = (plan, {
1049
1076
  job.adaptors.push(
1050
1077
  `@openfn/language-collections@${version || "latest"}`
1051
1078
  );
1079
+ if (typeof job.configuration === "string") {
1080
+ job.configuration = {
1081
+ [CREDENTIALS_KEY]: job.configuration
1082
+ };
1083
+ }
1052
1084
  job.configuration = Object.assign({}, job.configuration, {
1053
1085
  collections_endpoint: `${endpoint2}/collections`,
1054
1086
  collections_token: apiKey2
@@ -1239,7 +1271,7 @@ var loadAndApplyCredentialMap = async (plan, options7, logger) => {
1239
1271
  if (options7.credentials) {
1240
1272
  try {
1241
1273
  const credsRaw = await readFile3(
1242
- path5.resolve(options7.credentials),
1274
+ path5.resolve(options7.workspace, options7.credentials),
1243
1275
  "utf8"
1244
1276
  );
1245
1277
  if (options7.credentials.endsWith(".json")) {
@@ -1247,13 +1279,16 @@ var loadAndApplyCredentialMap = async (plan, options7, logger) => {
1247
1279
  } else {
1248
1280
  creds = yamlToJson2(credsRaw);
1249
1281
  }
1282
+ logger.info("Credential map loaded ");
1250
1283
  } catch (e) {
1251
- logger.error("Error processing credential map:");
1252
- logger.error(e);
1253
- process.exitCode = 1;
1254
- return;
1284
+ if (e?.message?.match(/ENOENT/)) {
1285
+ logger.debug("Credential map not found at", options7.credentials);
1286
+ } else {
1287
+ logger.error("Error processing credential map:");
1288
+ process.exitCode = 1;
1289
+ throw e;
1290
+ }
1255
1291
  }
1256
- logger.info("Credential map loaded ");
1257
1292
  }
1258
1293
  return apply_credential_map_default(plan, creds, logger);
1259
1294
  };
@@ -1726,7 +1761,7 @@ import {
1726
1761
  } from "@openfn/deploy";
1727
1762
 
1728
1763
  // src/deploy/beta.ts
1729
- import Project2 from "@openfn/project";
1764
+ import Project from "@openfn/project";
1730
1765
  import { deployProject } from "@openfn/deploy";
1731
1766
 
1732
1767
  // src/projects/util.ts
@@ -1834,7 +1869,7 @@ var DeployError = class extends Error {
1834
1869
  // src/deploy/beta.ts
1835
1870
  async function handler(options7, logger) {
1836
1871
  const config2 = loadAppAuthConfig(options7, logger);
1837
- const project = await Project2.from("fs", {
1872
+ const project = await Project.from("fs", {
1838
1873
  root: options7.workspace || "."
1839
1874
  });
1840
1875
  const state = project.serialize("state", { format: "json" });
@@ -2369,7 +2404,7 @@ var override = (command7, yargs) => {
2369
2404
 
2370
2405
  // src/projects/fetch.ts
2371
2406
  import path12 from "node:path";
2372
- import Project3, { Workspace } from "@openfn/project";
2407
+ import Project2, { Workspace as Workspace2 } from "@openfn/project";
2373
2408
 
2374
2409
  // src/util/ensure-log-opts.ts
2375
2410
  var defaultLoggerOptions = {
@@ -2547,6 +2582,7 @@ var env = {
2547
2582
  var alias = {
2548
2583
  name: "alias",
2549
2584
  yargs: {
2585
+ alias: ["env"],
2550
2586
  description: "Environment name (eg staging, prod, branch)"
2551
2587
  }
2552
2588
  };
@@ -2568,7 +2604,7 @@ var workflowMappings = {
2568
2604
  var outputPath = {
2569
2605
  name: "output-path",
2570
2606
  yargs: {
2571
- alias: ["output"],
2607
+ alias: ["o", "output"],
2572
2608
  type: "string",
2573
2609
  description: "Path to output the fetched project to"
2574
2610
  }
@@ -2620,7 +2656,7 @@ var printProjectName = (project) => `${project.qname} (${project.id})`;
2620
2656
  var handler2 = async (options7, logger) => {
2621
2657
  const workspacePath = options7.workspace ?? process.cwd();
2622
2658
  logger.debug("Using workspace at", workspacePath);
2623
- const workspace2 = new Workspace(workspacePath, logger, false);
2659
+ const workspace2 = new Workspace2(workspacePath, logger, false);
2624
2660
  const { outputPath: outputPath2 } = options7;
2625
2661
  const localTargetProject = await resolveOutputProject(
2626
2662
  workspace2,
@@ -2654,7 +2690,7 @@ async function resolveOutputProject(workspace2, options7, logger) {
2654
2690
  logger.debug("Checking for local copy of project...");
2655
2691
  if (options7.outputPath) {
2656
2692
  try {
2657
- const customProject = await Project3.from("path", options7.outputPath);
2693
+ const customProject = await Project2.from("path", options7.outputPath);
2658
2694
  logger.debug(
2659
2695
  `Found existing local project ${printProjectName(customProject)} at`,
2660
2696
  options7.outputPath
@@ -2710,7 +2746,7 @@ async function fetchRemoteProject(workspace2, options7, logger) {
2710
2746
  projectUUID,
2711
2747
  logger
2712
2748
  );
2713
- const project = await Project3.from(
2749
+ const project = await Project2.from(
2714
2750
  "state",
2715
2751
  data,
2716
2752
  {
@@ -2766,7 +2802,7 @@ To ignore this error and override the local file, pass --force (-f)
2766
2802
  }
2767
2803
 
2768
2804
  // src/projects/checkout.ts
2769
- import Project4, { Workspace as Workspace2 } from "@openfn/project";
2805
+ import Project3, { Workspace as Workspace3 } from "@openfn/project";
2770
2806
  import path13 from "path";
2771
2807
  import fs4 from "fs";
2772
2808
  import { rimraf } from "rimraf";
@@ -2783,13 +2819,13 @@ var command2 = {
2783
2819
  var handler3 = async (options7, logger) => {
2784
2820
  const projectIdentifier = options7.project;
2785
2821
  const workspacePath = options7.workspace ?? process.cwd();
2786
- const workspace2 = new Workspace2(workspacePath, logger);
2822
+ const workspace2 = new Workspace3(workspacePath, logger);
2787
2823
  const { project: _, ...config2 } = workspace2.getConfig();
2788
2824
  let switchProject;
2789
2825
  if (/\.(yaml|json)$/.test(projectIdentifier)) {
2790
2826
  const filePath = projectIdentifier.startsWith("/") ? projectIdentifier : path13.join(workspacePath, projectIdentifier);
2791
2827
  logger.debug("Loading project from path ", filePath);
2792
- switchProject = await Project4.from("path", filePath, config2);
2828
+ switchProject = await Project3.from("path", filePath, config2);
2793
2829
  } else {
2794
2830
  switchProject = workspace2.get(projectIdentifier);
2795
2831
  }
@@ -2852,6 +2888,7 @@ var pull_default = handler4;
2852
2888
  // src/pull/handler.ts
2853
2889
  async function pullHandler(options7, logger) {
2854
2890
  if (options7.beta) {
2891
+ options7.project = options7.projectId;
2855
2892
  return pull_default(options7, logger);
2856
2893
  }
2857
2894
  try {
@@ -2959,7 +2996,7 @@ __export(handler_exports, {
2959
2996
  });
2960
2997
 
2961
2998
  // src/projects/list.ts
2962
- import { Workspace as Workspace3 } from "@openfn/project";
2999
+ import { Workspace as Workspace4 } from "@openfn/project";
2963
3000
  var options4 = [log, workspace];
2964
3001
  var command4 = {
2965
3002
  command: "list [project-path]",
@@ -2972,7 +3009,7 @@ var handler5 = async (options7, logger) => {
2972
3009
  logger.info("Searching for projects in workspace at:");
2973
3010
  logger.info(" ", options7.workspace);
2974
3011
  logger.break();
2975
- const workspace2 = new Workspace3(options7.workspace);
3012
+ const workspace2 = new Workspace4(options7.workspace);
2976
3013
  if (!workspace2.valid) {
2977
3014
  throw new Error("No OpenFn projects found");
2978
3015
  }
@@ -2990,7 +3027,7 @@ ${project.workflows.map((w) => " - " + w.id).join("\n")}`;
2990
3027
  }
2991
3028
 
2992
3029
  // src/projects/version.ts
2993
- import { Workspace as Workspace4 } from "@openfn/project";
3030
+ import { Workspace as Workspace5 } from "@openfn/project";
2994
3031
  var options5 = [workflow, workspace, workflowMappings];
2995
3032
  var command5 = {
2996
3033
  command: "version [workflow]",
@@ -2999,7 +3036,7 @@ var command5 = {
2999
3036
  builder: (yargs) => build(options5, yargs)
3000
3037
  };
3001
3038
  var handler6 = async (options7, logger) => {
3002
- const workspace2 = new Workspace4(options7.workspace);
3039
+ const workspace2 = new Workspace5(options7.workspace);
3003
3040
  if (!workspace2.valid) {
3004
3041
  logger.error("Command was run in an invalid openfn workspace");
3005
3042
  return;
@@ -3034,7 +3071,7 @@ ${final}`);
3034
3071
  };
3035
3072
 
3036
3073
  // src/projects/merge.ts
3037
- import Project6, { Workspace as Workspace5 } from "@openfn/project";
3074
+ import Project5, { Workspace as Workspace6 } from "@openfn/project";
3038
3075
  import path15 from "node:path";
3039
3076
  import fs6 from "node:fs/promises";
3040
3077
  var options6 = [
@@ -3070,7 +3107,7 @@ var command6 = {
3070
3107
  };
3071
3108
  var handler7 = async (options7, logger) => {
3072
3109
  const workspacePath = options7.workspace;
3073
- const workspace2 = new Workspace5(workspacePath);
3110
+ const workspace2 = new Workspace6(workspacePath);
3074
3111
  if (!workspace2.valid) {
3075
3112
  logger.error("Command was run in an invalid openfn workspace");
3076
3113
  return;
@@ -3079,7 +3116,7 @@ var handler7 = async (options7, logger) => {
3079
3116
  if (options7.base) {
3080
3117
  const basePath = path15.resolve(options7.base);
3081
3118
  logger.debug("Loading target project from path", basePath);
3082
- targetProject = await Project6.from("path", basePath);
3119
+ targetProject = await Project5.from("path", basePath);
3083
3120
  } else {
3084
3121
  targetProject = workspace2.getActiveProject();
3085
3122
  if (!targetProject) {
@@ -3093,7 +3130,7 @@ var handler7 = async (options7, logger) => {
3093
3130
  if (/\.(ya?ml|json)$/.test(sourceProjectIdentifier)) {
3094
3131
  const filePath = path15.join(workspacePath, sourceProjectIdentifier);
3095
3132
  logger.debug("Loading source project from path ", filePath);
3096
- sourceProject = await Project6.from("path", filePath);
3133
+ sourceProject = await Project5.from("path", filePath);
3097
3134
  } else {
3098
3135
  logger.debug(
3099
3136
  `Loading source project from workspace ${sourceProjectIdentifier}`
@@ -3119,7 +3156,7 @@ var handler7 = async (options7, logger) => {
3119
3156
  logger.error("Path to checked out project not found.");
3120
3157
  return;
3121
3158
  }
3122
- const final = Project6.merge(sourceProject, targetProject, {
3159
+ const final = Project5.merge(sourceProject, targetProject, {
3123
3160
  removeUnmapped: options7.removeUnmapped,
3124
3161
  workflowMappings: options7.workflowMappings,
3125
3162
  force: options7.force
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfn/cli",
3
- "version": "1.21.0",
3
+ "version": "1.23.0",
4
4
  "description": "CLI devtools for the OpenFn toolchain",
5
5
  "engines": {
6
6
  "node": ">=18",
@@ -50,12 +50,12 @@
50
50
  "ws": "^8.18.3",
51
51
  "yargs": "^17.7.2",
52
52
  "@openfn/compiler": "1.2.2",
53
- "@openfn/describe-package": "0.1.5",
54
53
  "@openfn/deploy": "0.11.5",
55
- "@openfn/project": "^0.10.0",
56
54
  "@openfn/lexicon": "^1.3.0",
57
- "@openfn/runtime": "1.7.7",
58
- "@openfn/logger": "1.1.1"
55
+ "@openfn/logger": "1.1.1",
56
+ "@openfn/describe-package": "0.1.5",
57
+ "@openfn/project": "^0.11.0",
58
+ "@openfn/runtime": "1.8.1"
59
59
  },
60
60
  "files": [
61
61
  "dist",