@openfn/project 0.10.0 → 0.11.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.d.ts CHANGED
@@ -15,6 +15,8 @@ declare class Workflow {
15
15
  options: any;
16
16
  constructor(workflow: l.Workflow);
17
17
  get steps(): WithMeta<l.Job & l.Trigger>[];
18
+ get start(): string | undefined;
19
+ set start(s: string);
18
20
  _buildIndex(): void;
19
21
  set(id: string, props: Partial<l.Job | l.StepEdge>): this;
20
22
  get(id: string): WithMeta<l.Step | l.Trigger | l.StepEdge>;
@@ -43,6 +45,7 @@ type FromPathConfig = l.WorkspaceConfig & {
43
45
 
44
46
  type FromFsConfig = {
45
47
  root: string;
48
+ config?: Partial<l.WorkspaceConfig>;
46
49
  logger?: Logger;
47
50
  };
48
51
 
@@ -66,6 +69,7 @@ type MergeProjectOptions = {
66
69
  declare class Workspace {
67
70
  config: l.WorkspaceConfig;
68
71
  activeProject?: l.ProjectMeta;
72
+ root: string;
69
73
  private projects;
70
74
  private projectPaths;
71
75
  private isValid;
@@ -77,6 +81,8 @@ declare class Workspace {
77
81
  get(nameyThing: string): Project | null;
78
82
  getProjectPath(id: string): string | undefined;
79
83
  getActiveProject(): Project | undefined;
84
+ getCheckedOutProject(): Promise<Project>;
85
+ getCredentialMap(): string | undefined;
80
86
  getConfig(): Partial<l.WorkspaceConfig>;
81
87
  get activeProjectId(): unknown;
82
88
  get valid(): boolean;
package/dist/index.js CHANGED
@@ -105,7 +105,16 @@ var Workflow = class {
105
105
  };
106
106
  this.workflow = clone(workflow);
107
107
  this.workflow.history = workflow.history?.length ? workflow.history : [];
108
- const { id, name, openfn, steps, history, ...options } = workflow;
108
+ const {
109
+ id,
110
+ name,
111
+ openfn,
112
+ steps,
113
+ history,
114
+ start: _start,
115
+ options,
116
+ ...rest
117
+ } = workflow;
109
118
  if (!(id || name)) {
110
119
  throw new Error("A Workflow MUST have a name or id");
111
120
  }
@@ -116,12 +125,18 @@ var Workflow = class {
116
125
  this.workflow.name = this.name;
117
126
  }
118
127
  this.openfn = openfn;
119
- this.options = options;
128
+ this.options = Object.assign({}, options, rest);
120
129
  this._buildIndex();
121
130
  }
122
131
  get steps() {
123
132
  return this.workflow.steps;
124
133
  }
134
+ get start() {
135
+ return this.workflow.start;
136
+ }
137
+ set start(s) {
138
+ this.workflow.start = s;
139
+ }
125
140
  _buildIndex() {
126
141
  for (const step of this.workflow.steps) {
127
142
  const s = step;
@@ -361,11 +376,17 @@ var mapWorkflow = (workflow) => {
361
376
  } else {
362
377
  e.source_job_id = node.id;
363
378
  }
364
- if (rules.condition === true) {
365
- e.condition_type = "always";
366
- } else if (rules.condition === false) {
367
- e.condition_type = "never";
368
- } else if (typeof rules.condition === "string") {
379
+ if (rules.condition) {
380
+ if (typeof rules.condition === "boolean") {
381
+ e.condition_type = rules.condition ? "always" : "never";
382
+ } else if (rules.condition.match(
383
+ /^(always|never|on_job_success|on_job_failure)$/
384
+ )) {
385
+ e.condition_type = rules.condition;
386
+ } else {
387
+ e.condition_type = "js_expression";
388
+ e.condition_expression = rules.condition;
389
+ }
369
390
  }
370
391
  wfState.edges.push(e);
371
392
  });
@@ -383,6 +404,7 @@ import { readFileSync } from "node:fs";
383
404
  import path from "node:path";
384
405
  import { pickBy, isNil as isNil2 } from "lodash-es";
385
406
  var buildConfig = (config = {}) => ({
407
+ credentials: "credentials.yaml",
386
408
  ...config,
387
409
  dirs: {
388
410
  projects: config.dirs?.projects ?? ".projects",
@@ -499,6 +521,7 @@ var extractWorkflow = (project, workflowId) => {
499
521
  const wf = {
500
522
  id: workflow.id,
501
523
  name: workflow.name,
524
+ start: workflow.start,
502
525
  // Note: if no options are defined, options will serialize to an empty object
503
526
  // Not crazy about this - maybe we should do something better? Or do we like the consistency?
504
527
  options: workflow.options,
@@ -652,20 +675,23 @@ var from_app_state_default = (state, meta = {}, config = {}) => {
652
675
  proj.workflows = stateJson.workflows.map(mapWorkflow2);
653
676
  return new Project(proj, config);
654
677
  };
655
- var mapTriggerEdgeCondition = (edge) => {
678
+ var mapEdge = (edge) => {
656
679
  const e = {
657
680
  disabled: !edge.enabled
658
681
  };
659
- if (edge.condition_type === "always") {
660
- e.condition = true;
661
- } else if (edge.condition_type === "never") {
662
- e.condition = false;
663
- } else {
682
+ if (edge.condition_type === "js_expression") {
664
683
  e.condition = edge.condition_expression;
684
+ } else if (edge.condition_type) {
685
+ e.condition = edge.condition_type;
686
+ }
687
+ if (edge.condition_label) {
688
+ e.name = edge.condition_label;
689
+ }
690
+ if (edge.id) {
691
+ e.openfn = {
692
+ uuid: edge.id
693
+ };
665
694
  }
666
- e.openfn = {
667
- uuid: edge.id
668
- };
669
695
  return e;
670
696
  };
671
697
  var mapWorkflow2 = (workflow) => {
@@ -681,6 +707,9 @@ var mapWorkflow2 = (workflow) => {
681
707
  }
682
708
  workflow.triggers.forEach((trigger) => {
683
709
  const { type, ...otherProps } = trigger;
710
+ if (!mapped.start) {
711
+ mapped.start = `trigger-${type}`;
712
+ }
684
713
  const connectedEdges = edges.filter(
685
714
  (e) => e.source_trigger_id === trigger.id
686
715
  );
@@ -693,7 +722,7 @@ var mapWorkflow2 = (workflow) => {
693
722
  if (!target) {
694
723
  throw new Error(`Failed to find ${edge.target_job_id}`);
695
724
  }
696
- obj[slugify(target.name)] = mapTriggerEdgeCondition(edge);
725
+ obj[slugify(target.name)] = mapEdge(edge);
697
726
  return obj;
698
727
  }, {})
699
728
  });
@@ -723,7 +752,7 @@ var mapWorkflow2 = (workflow) => {
723
752
  if (outboundEdges.length) {
724
753
  s.next = outboundEdges.reduce((next, edge) => {
725
754
  const target = jobs.find((j) => j.id === edge.target_job_id);
726
- next[slugify(target.name)] = mapTriggerEdgeCondition(edge);
755
+ next[slugify(target.name)] = mapEdge(edge);
727
756
  return next;
728
757
  }, {});
729
758
  }
@@ -739,16 +768,13 @@ import path2 from "node:path";
739
768
  // src/parse/from-project.ts
740
769
  var from_project_default = (data, config) => {
741
770
  let rawJson = ensure_json_default(data);
742
- let json;
743
771
  if (rawJson.cli?.version ?? rawJson.version) {
744
- json = from_v2(rawJson);
745
- } else {
746
- json = from_v1(rawJson);
772
+ return new Project_default(from_v2(rawJson), config);
747
773
  }
748
- return new Project_default(json, config);
774
+ return from_v1(rawJson, config);
749
775
  };
750
- var from_v1 = (data) => {
751
- return from_app_state_default(data);
776
+ var from_v1 = (data, config = {}) => {
777
+ return from_app_state_default(data, {}, config);
752
778
  };
753
779
  var from_v2 = (data) => {
754
780
  return {
@@ -780,7 +806,7 @@ var parseProject = async (options) => {
780
806
  const { root, logger } = options;
781
807
  const { type, content } = findWorkspaceFile(root);
782
808
  const context = loadWorkspaceFile(content, type);
783
- const config = buildConfig(context.workspace);
809
+ const config = buildConfig(options.config ?? context.workspace);
784
810
  const proj = {
785
811
  id: context.project?.id,
786
812
  name: context.project?.name,
@@ -790,14 +816,26 @@ var parseProject = async (options) => {
790
816
  };
791
817
  const workflowDir = config.workflowRoot ?? config.dirs?.workflows ?? "workflows";
792
818
  const fileType = config.formats?.workflow ?? "yaml";
793
- const pattern = `${root}/${workflowDir}/*/*.${fileType}`;
819
+ const pattern = path3.resolve(root, workflowDir) + `/**/*.${fileType}`;
794
820
  const candidateWfs = await glob(pattern, {
795
821
  ignore: ["**node_modules/**", "**tmp**"]
796
822
  });
797
823
  for (const filePath of candidateWfs) {
798
824
  const candidate = await fs.readFile(filePath, "utf-8");
799
825
  try {
800
- const wf = fileType === "yaml" ? yamlToJson(candidate) : JSON.parse(candidate);
826
+ let wf = fileType === "yaml" ? yamlToJson(candidate) : JSON.parse(candidate);
827
+ if (wf.workflow) {
828
+ if (wf.options) {
829
+ const { start, ...rest } = wf.options;
830
+ if (start) {
831
+ wf.workflow.start = start;
832
+ }
833
+ if (rest) {
834
+ wf.workflow.options = Object.assign({}, wf.workflow.options, rest);
835
+ }
836
+ }
837
+ wf = wf.workflow;
838
+ }
801
839
  if (wf.id && Array.isArray(wf.steps)) {
802
840
  for (const step of wf.steps) {
803
841
  if (step.expression && step.expression.endsWith(".js")) {
@@ -1445,6 +1483,7 @@ var Workspace = class {
1445
1483
  config;
1446
1484
  // TODO activeProject should be the actual project
1447
1485
  activeProject;
1486
+ root;
1448
1487
  projects = [];
1449
1488
  projectPaths = /* @__PURE__ */ new Map();
1450
1489
  isValid = false;
@@ -1452,6 +1491,7 @@ var Workspace = class {
1452
1491
  // Set validate to false to suppress warnings if a Workspace doesn't exist
1453
1492
  // This is appropriate if, say, fetching a project for the first time
1454
1493
  constructor(workspacePath, logger, validate = true) {
1494
+ this.root = workspacePath;
1455
1495
  this.logger = logger ?? createLogger("Workspace", { level: "info" });
1456
1496
  let context = { workspace: void 0, project: void 0 };
1457
1497
  try {
@@ -1517,6 +1557,12 @@ var Workspace = class {
1517
1557
  getActiveProject() {
1518
1558
  return this.projects.find((p) => p.openfn?.uuid === this.activeProject?.uuid) ?? this.projects.find((p) => p.id === this.activeProject?.id);
1519
1559
  }
1560
+ getCheckedOutProject() {
1561
+ return Project.from("fs", { root: this.root, config: this.config });
1562
+ }
1563
+ getCredentialMap() {
1564
+ return this.config.credentials;
1565
+ }
1520
1566
  // TODO this needs to return default values
1521
1567
  // We should always rely on the workspace to load these values
1522
1568
  getConfig() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfn/project",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Read, serialize, replicate and sync OpenFn projects",
5
5
  "type": "module",
6
6
  "exports": {