Skip to content

Commit 6946618

Browse files
authored
Merge pull request #1057 from OpenFn/projects-root
Support new Project & CLI features for integration tests
2 parents bab4dc4 + 285f238 commit 6946618

33 files changed

Lines changed: 600 additions & 184 deletions

packages/cli/CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# @openfn/cli
22

3+
## 1.16.2
4+
5+
### Patch Changes
6+
7+
- 8a50703: Allow a project to be checked out from a direct path to a project file
8+
- 7d16875: When merging, allow the source project to specified as a path to a project file
9+
- Updated dependencies [81b97c3]
10+
- Updated dependencies [43be979]
11+
- Updated dependencies [1f8d65e]
12+
- Updated dependencies [25c7a2b]
13+
- Updated dependencies [04a89e2]
14+
- Updated dependencies [7d16875]
15+
- @openfn/project@0.5.1
16+
- @openfn/lexicon@1.2.4
17+
318
## 1.16.1
419

520
### Patch Changes

packages/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@openfn/cli",
3-
"version": "1.16.1",
3+
"version": "1.16.2",
44
"description": "CLI devtools for the OpenFn toolchain",
55
"engines": {
66
"node": ">=18",

packages/cli/src/checkout/handler.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Workspace } from '@openfn/project';
1+
import Project, { Workspace } from '@openfn/project';
22
import path from 'path';
33
import type { Logger } from '../util/logger';
44
import type { CheckoutOptions } from './command';
@@ -13,20 +13,32 @@ const checkoutHandler = async (options: CheckoutOptions, logger: Logger) => {
1313
return;
1414
}
1515

16+
// get the config
17+
// TODO: try to retain the endpoint for the projects
18+
const { project: _, ...config } = workspace.getConfig() ?? {};
19+
1620
// get the project
17-
const switchProject = workspace.get(options.projectName);
21+
let switchProject;
22+
if (/\.(yaml|json)$/.test(options.projectName)) {
23+
// TODO: should we allow checkout into an arbitrary folder?
24+
const filePath = path.join(commandPath, options.projectName);
25+
logger.debug('Loading project from path ', filePath);
26+
switchProject = await Project.from('path', filePath, {
27+
config,
28+
});
29+
} else {
30+
switchProject = workspace.get(options.projectName);
31+
}
32+
1833
if (!switchProject) {
1934
logger.error(
2035
`Project with id/name ${options.projectName} not found in the workspace`
2136
);
2237
return;
2338
}
24-
// get the config
25-
// TODO: try to retain the endpoint for the projects
26-
const config = workspace.getConfig();
2739

2840
// delete workflow dir before expanding project
29-
await rimraf(path.join(commandPath, config?.workflowRoot || 'workflows'));
41+
await rimraf(path.join(commandPath, config.workflowRoot ?? 'workflows'));
3042

3143
// expand project into directory
3244
const files = switchProject.serialize('fs');

packages/cli/src/merge/handler.ts

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,38 +13,46 @@ const mergeHandler = async (options: MergeOptions, logger: Logger) => {
1313
return;
1414
}
1515

16-
const checkedProject = workspace.getActiveProject();
17-
if (!checkedProject) {
16+
// The target project - the think we apply changes to - is
17+
// whatever is checked out
18+
const targetProject = workspace.getActiveProject();
19+
if (!targetProject) {
1820
logger.error(`No project currently checked out`);
1921
return;
2022
}
2123

22-
const mProject = workspace.get(options.projectName);
23-
if (!mProject) {
24-
logger.error(
25-
`Project with id/name ${options.projectName} not found in the workspace`
26-
);
24+
// Lookup the source project - the thing we are getting changes from
25+
let sourceProject;
26+
if (/\.(yaml|json)$/.test(options.projectName)) {
27+
const filePath = path.join(commandPath, options.projectName);
28+
logger.debug('Loading source project from path ', filePath);
29+
sourceProject = await Project.from('path', filePath);
30+
} else {
31+
sourceProject = workspace.get(options.projectName);
32+
}
33+
if (!sourceProject) {
34+
logger.error(`Project "${options.projectName}" not found in the workspace`);
2735
return;
2836
}
2937

30-
if (checkedProject.name === mProject.name) {
38+
if (targetProject.name === sourceProject.name) {
3139
logger.error('Merging into the same project not allowed');
3240
return;
3341
}
3442

35-
if (!checkedProject.name) {
43+
if (!targetProject.name) {
3644
logger.error('The checked out project has no name/id');
3745
return;
3846
}
3947

40-
const finalPath = workspace.getProjectPath(checkedProject.name);
48+
const finalPath = workspace.getProjectPath(targetProject.name);
4149
if (!finalPath) {
4250
logger.error('Path to checked out project not found.');
4351
return;
4452
}
4553

4654
// TODO pick options from the terminal
47-
const final = Project.merge(mProject, checkedProject, {
55+
const final = Project.merge(sourceProject, targetProject, {
4856
removeUnmapped: options.removeUnmapped,
4957
workflowMappings: options.workflowMappings,
5058
});
@@ -61,7 +69,7 @@ const mergeHandler = async (options: MergeOptions, logger: Logger) => {
6169
logger
6270
);
6371
logger.success(
64-
`Project ${mProject.name} has been merged into Project ${checkedProject.name} successfully`
72+
`Project ${sourceProject.name} has been merged into Project ${targetProject.name} successfully`
6573
);
6674
};
6775

packages/lexicon/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# lexicon
22

3+
## 1.2.4
4+
5+
### Patch Changes
6+
7+
- 1f8d65e: Clarify naming conventions for id/name
8+
39
## 1.2.3
410

511
### Patch Changes

packages/lexicon/core.d.ts

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { SanitizePolicies } from '@openfn/logger';
22
import type { RawSourceMap } from 'source-map';
33

4+
/** UUID v4 */
5+
export type UUID = string;
6+
47
export type SourceMap = RawSourceMap;
58

69
export type SourceMapWithOperations = RawSourceMap & {
@@ -10,10 +13,17 @@ export type SourceMapWithOperations = RawSourceMap & {
1013
// The serialised shape of of a project, as JSON
1114
// this is what is saved to project.yaml
1215
export type Project = {
13-
name: string; // human readable name
16+
/** Single-word identifier */
17+
id: string;
18+
19+
/** human readable name */
20+
name?: string;
21+
22+
/** Shorthand identifier used by CLI commands */
23+
alias?: string;
24+
1425
description?: string;
1526

16-
// object or array?
1727
workflows: Workflow[];
1828

1929
options: {};
@@ -24,8 +34,11 @@ export type Project = {
2434
openfn?: ProjectConfig;
2535
};
2636

27-
export type ProjectConfig = {
28-
uuid: string;
37+
export type OpenFnMetadata = {
38+
uuid?: UUID;
39+
};
40+
41+
export type ProjectConfig = OpenFnMetadata & {
2942
endpoint: string;
3043
name: string;
3144
env: string;
@@ -42,7 +55,7 @@ export type ProjectConfig = {
4255
* (ie, the CLI or Worker)
4356
*/
4457
export type ExecutionPlan = {
45-
id?: UUID; // this would be the run (nee attempt) id
58+
id?: UUID; // TODO make required
4659
workflow: Workflow;
4760
options?: WorkflowOptions;
4861
};
@@ -51,11 +64,15 @@ export type ExecutionPlan = {
5164
* A workflow is just a series of steps, executed start to finish
5265
*/
5366
export type Workflow = {
54-
id?: UUID; // unique id used to track this workflow. Could be autogenerated
67+
/** The ID is the primary internal identifier for a Workflow */
68+
id?: string;
5569

56-
// TODO: make required (worker and cli may have to generate a name)
70+
/** Human readable name, like display. Can be used to generate an internal id */
5771
name?: string;
5872

73+
/** Local shorthand name for use in CLI commands. Not used by Lightning */
74+
alias?: string;
75+
5976
steps: Array<Job | Trigger>;
6077

6178
// global credentials
@@ -64,6 +81,8 @@ export type Workflow = {
6481

6582
// a path to a file where functions are defined
6683
globals?: string;
84+
85+
openfn?: OpenFnMetadata;
6786
};
6887

6988
export type StepId = string;
@@ -73,6 +92,7 @@ export type StepId = string;
7392
* (usually a job)
7493
*/
7594
export interface Step {
95+
// TODO a Step must ALWAYS have an id (util functions can default it)
7696
id?: StepId;
7797
name?: string; // user-friendly name used in logging
7898

@@ -88,7 +108,7 @@ export type StepEdge = boolean | string | ConditionalStepEdge;
88108

89109
export type ConditionalStepEdge = {
90110
condition?: string; // Javascript expression (function body, not function)
91-
label?: string;
111+
label?: string; // TODO this is probably the name
92112
disabled?: boolean;
93113
};
94114

@@ -208,6 +228,4 @@ export type ErrorReport = {
208228

209229
// TODO standard shape of error object in our stack
210230

211-
type UUID = string;
212-
213231
export type Lazy<T> = T | string;

packages/lexicon/lightning.d.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,19 @@ type TimeInMicroSeconds = string;
1717
*/
1818

1919
/**
20-
* An execution plan representing a Lightning 'Run'.
21-
* This represents the execution of a workflow.
20+
* The Lightning Plan is the data structure sent by lightning in response
21+
* to the fetch:plan event. It represents a single Run, or an execution
22+
* of a workflow given some input dataclip.
2223
*
23-
* The data structure that Lightning sends is converted by the Worker into
24-
* a runtime ExecutionPlan (as found in Core)
24+
* This structure is converted by the Worker into a runtime ExecutionPlan (as found in Core)
2525
*/
2626
export type LightningPlan = {
27+
/** The Lightning UUID for this Run (not the same as the workflow id/UUID) */
2728
id: string;
29+
30+
/** The human readable name of the workflow. Not currently sent by Lightning. */
2831
name?: string;
32+
2933
dataclip_id: string;
3034
starting_node_id: string;
3135

packages/lexicon/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@openfn/lexicon",
3-
"version": "1.2.3",
3+
"version": "1.2.4",
44
"description": "Central repo of names and type definitions",
55
"author": "Open Function Group <admin@openfn.org>",
66
"license": "ISC",

packages/project/CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# @openfn/project
22

3+
## 0.5.1
4+
5+
### Patch Changes
6+
7+
- 81b97c3: Allow projects to be loaded directly from a file
8+
- 43be979: Fix an issue loading the ohm grammer
9+
- 25c7a2b: Allow a UUID map to be passed to the project generator
10+
- 04a89e2: Add support for dirs in config
11+
- 7d16875: When merging, allow the source project to specified as a path to a project file
12+
- Updated dependencies [1f8d65e]
13+
- @openfn/lexicon@1.2.4
14+
315
## 0.5.0
416

517
### Minor Changes

packages/project/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ a-b
5151
a-c
5252
```
5353

54-
You can set properties on the workflow itself - probably the name, with `@attributes`
54+
You can set properties on the workflow itself - probably the id, with `@attributes`
5555

5656
```
57-
@name my-cool-workflow
57+
@id my-cool-workflow
5858
```
5959

6060
You can also set properties on a node by putting comma seperated key-value pairs in brackets

0 commit comments

Comments
 (0)