Skip to content

Commit 66ee7a9

Browse files
authored
feat: import executables from makefile, docker-compose, and package.json (#274)
1 parent e927a5b commit 66ee7a9

27 files changed

+1106
-349
lines changed

desktop/src-tauri/src/types/generated/flowfile.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2203,6 +2203,11 @@ impl ::std::default::Default for ExecutableVerb {
22032203
#[doc = " }"]
22042204
#[doc = " },"]
22052205
#[doc = " \"fromFile\": {"]
2206+
#[doc = " \"description\": \"DEPRECATED: Use `imports` instead\","]
2207+
#[doc = " \"default\": [],"]
2208+
#[doc = " \"$ref\": \"#/definitions/FromFile\""]
2209+
#[doc = " },"]
2210+
#[doc = " \"imports\": {"]
22062211
#[doc = " \"default\": [],"]
22072212
#[doc = " \"$ref\": \"#/definitions/FromFile\""]
22082213
#[doc = " },"]
@@ -2236,8 +2241,11 @@ pub struct FlowFile {
22362241
pub description_file: ::std::string::String,
22372242
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
22382243
pub executables: ::std::vec::Vec<Executable>,
2244+
#[doc = "DEPRECATED: Use `imports` instead"]
22392245
#[serde(rename = "fromFile", default = "defaults::flow_file_from_file")]
22402246
pub from_file: FromFile,
2247+
#[serde(default = "defaults::flow_file_imports")]
2248+
pub imports: FromFile,
22412249
#[doc = "The namespace to be given to all executables in the flow file.\nIf not set, the executables in the file will be grouped into the root (*) namespace. \nNamespaces can be reused across multiple flow files.\n\nNamespaces are used to reference executables in the CLI using the format `workspace:namespace/name`.\n"]
22422250
#[serde(default)]
22432251
pub namespace: ::std::string::String,
@@ -2259,6 +2267,7 @@ impl ::std::default::Default for FlowFile {
22592267
description_file: Default::default(),
22602268
executables: Default::default(),
22612269
from_file: defaults::flow_file_from_file(),
2270+
imports: defaults::flow_file_imports(),
22622271
namespace: Default::default(),
22632272
tags: Default::default(),
22642273
visibility: Default::default(),
@@ -3813,6 +3822,7 @@ pub mod builder {
38133822
executables:
38143823
::std::result::Result<::std::vec::Vec<super::Executable>, ::std::string::String>,
38153824
from_file: ::std::result::Result<super::FromFile, ::std::string::String>,
3825+
imports: ::std::result::Result<super::FromFile, ::std::string::String>,
38163826
namespace: ::std::result::Result<::std::string::String, ::std::string::String>,
38173827
tags: ::std::result::Result<::std::vec::Vec<::std::string::String>, ::std::string::String>,
38183828
visibility: ::std::result::Result<
@@ -3827,6 +3837,7 @@ pub mod builder {
38273837
description_file: Ok(Default::default()),
38283838
executables: Ok(Default::default()),
38293839
from_file: Ok(super::defaults::flow_file_from_file()),
3840+
imports: Ok(super::defaults::flow_file_imports()),
38303841
namespace: Ok(Default::default()),
38313842
tags: Ok(Default::default()),
38323843
visibility: Ok(Default::default()),
@@ -3877,6 +3888,16 @@ pub mod builder {
38773888
.map_err(|e| format!("error converting supplied value for from_file: {}", e));
38783889
self
38793890
}
3891+
pub fn imports<T>(mut self, value: T) -> Self
3892+
where
3893+
T: ::std::convert::TryInto<super::FromFile>,
3894+
T::Error: ::std::fmt::Display,
3895+
{
3896+
self.imports = value
3897+
.try_into()
3898+
.map_err(|e| format!("error converting supplied value for imports: {}", e));
3899+
self
3900+
}
38803901
pub fn namespace<T>(mut self, value: T) -> Self
38813902
where
38823903
T: ::std::convert::TryInto<::std::string::String>,
@@ -3916,6 +3937,7 @@ pub mod builder {
39163937
description_file: value.description_file?,
39173938
executables: value.executables?,
39183939
from_file: value.from_file?,
3940+
imports: value.imports?,
39193941
namespace: value.namespace?,
39203942
tags: value.tags?,
39213943
visibility: value.visibility?,
@@ -3929,6 +3951,7 @@ pub mod builder {
39293951
description_file: Ok(value.description_file),
39303952
executables: Ok(value.executables),
39313953
from_file: Ok(value.from_file),
3954+
imports: Ok(value.imports),
39323955
namespace: Ok(value.namespace),
39333956
tags: Ok(value.tags),
39343957
visibility: Ok(value.visibility),
@@ -3992,4 +4015,7 @@ pub mod defaults {
39924015
pub(super) fn flow_file_from_file() -> super::FromFile {
39934016
super::FromFile(vec![])
39944017
}
4018+
pub(super) fn flow_file_imports() -> super::FromFile {
4019+
super::FromFile(vec![])
4020+
}
39954021
}

desktop/src/types/generated/flowfile.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,13 @@ export type CommonTags = string[];
3939
*/
4040
export type CommonVisibility = 'public' | 'private' | 'internal' | 'hidden';
4141
/**
42-
* A list of `.sh` files to convert into generated executables in the file's executable group.
42+
* DEPRECATED: Use `imports` instead
4343
*/
4444
export type FromFile = string[];
45+
/**
46+
* A list of `.sh` files to convert into generated executables in the file's executable group.
47+
*/
48+
export type FromFile1 = string[];
4549

4650
/**
4751
* Configuration for a group of Flow CLI executables. The file must have the extension `.flow`, `.flow.yaml`, or `.flow.yml`
@@ -62,6 +66,7 @@ export interface FlowFile {
6266
descriptionFile?: string;
6367
executables?: Executable[];
6468
fromFile?: FromFile;
69+
imports?: FromFile1;
6570
/**
6671
* The namespace to be given to all executables in the flow file.
6772
* If not set, the executables in the file will be grouped into the root (*) namespace.

docs/guide/executables.md

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -356,17 +356,31 @@ Current time: {{ .timestamp }}
356356
- `templateFile`: Markdown template file (required)
357357
- `templateDataFile`: JSON/YAML data file
358358

359-
## Generated Executables
359+
## Importing Executables
360360

361-
Generate executables from shell scripts with special comments:
361+
Generate executables from shell scripts, Makefiles, package.json scripts, or docker-compose services:
362362

363363
```yaml
364364
# In flowfile
365-
fromFile:
365+
imports:
366366
- "scripts/deploy.sh"
367367
- "scripts/backup.sh"
368+
- "Makefile"
369+
- "frontend/package.json"
370+
- "docker-compose.yaml"
368371
```
369372

373+
All imported executables are automatically tagged with `generated` and their file type (e.g., `docker-compose`, `makefile`, `package.json`).
374+
375+
376+
<!-- tabs:start -->
377+
378+
#### **Shell Scripts (.sh files)**
379+
380+
Shell scripts are imported as single executables with the script's filename as the name and `exec` as the default verb.
381+
382+
You can use special comments to override executable metadata:
383+
370384
```bash
371385
#!/bin/bash
372386
# scripts/deploy.sh
@@ -394,6 +408,81 @@ kubectl apply -f k8s/
394408
# <f|description>
395409
```
396410

411+
#### **Makefiles**
412+
413+
Makefile targets are imported as executables with a verb and name that best represents the target.
414+
415+
```makefile
416+
# Makefile
417+
418+
# f:name=app f:verb=build f:description="Build the application"
419+
build:
420+
go build -o bin/app ./cmd/app
421+
422+
# Run all tests
423+
test:
424+
go test ./...
425+
426+
# f:visibility=internal
427+
clean:
428+
rm -rf bin/
429+
```
430+
431+
The same comment parsing syntax works in Makefiles - use `# f:key=value` to override executable configuration.
432+
433+
#### **Package.json Scripts**
434+
435+
NPM scripts from package.json are imported as executables with a verb and name that best represents the script name.
436+
437+
```json
438+
{
439+
"scripts": {
440+
"build": "webpack --mode production",
441+
"test": "jest",
442+
"dev": "webpack-dev-server --mode development",
443+
"lint": "eslint src/"
444+
}
445+
}
446+
```
447+
448+
This creates executables like:
449+
- `build` - Runs the build script
450+
- `test` - Runs the test script
451+
- `start dev` - Runs the development server
452+
- `lint` - Runs the linter
453+
454+
#### **Docker Compose Services**
455+
456+
Docker Compose files are imported to create executables for managing services:
457+
458+
```yaml
459+
# docker-compose.yml
460+
version: '3.8'
461+
services:
462+
app:
463+
build: .
464+
ports:
465+
- "3000:3000"
466+
467+
db:
468+
image: postgres:13
469+
environment:
470+
POSTGRES_DB: myapp
471+
472+
redis:
473+
image: redis:6
474+
```
475+
476+
This creates executables like:
477+
- `start app` - Start the app service
478+
- `start db` - Start the database service
479+
- `start redis` - Start the Redis service
480+
- `start` (alias: all, services) - Start all services
481+
- `stop` (alias: all, services) - Stop all services
482+
- `build app` - Build the app service (if build config exists)
483+
484+
<!-- tabs:end -->
485+
397486
## Executable References
398487

399488
Reference other executables to build modular workflows:

docs/schemas/flowfile_schema.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,11 @@
628628
}
629629
},
630630
"fromFile": {
631+
"$ref": "#/definitions/FromFile",
632+
"description": "DEPRECATED: Use `imports` instead",
633+
"default": []
634+
},
635+
"imports": {
631636
"$ref": "#/definitions/FromFile",
632637
"default": []
633638
},

docs/types/flowfile.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ in order to be discovered by the CLI. It's configuration is used to define a gro
1717
| `description` | A description of the executables defined within the flow file. This description will used as a shared description for all executables in the flow file. | `string` | | |
1818
| `descriptionFile` | A path to a markdown file that contains the description of the executables defined within the flow file. | `string` | | |
1919
| `executables` | | `array` ([Executable](#Executable)) | [] | |
20-
| `fromFile` | | [FromFile](#FromFile) | [] | |
20+
| `fromFile` | DEPRECATED: Use `imports` instead | [FromFile](#FromFile) | [] | |
21+
| `imports` | | [FromFile](#FromFile) | [] | |
2122
| `namespace` | The namespace to be given to all executables in the flow file. If not set, the executables in the file will be grouped into the root (*) namespace. Namespaces can be reused across multiple flow files. Namespaces are used to reference executables in the CLI using the format `workspace:namespace/name`. | `string` | | |
2223
| `tags` | Tags to be applied to all executables defined within the flow file. | `array` (`string`) | [] | |
2324
| `visibility` | | [CommonVisibility](#CommonVisibility) | <no value> | |

internal/cache/executable_generator.go

Lines changed: 0 additions & 88 deletions
This file was deleted.

internal/cache/executables_cache.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/pkg/errors"
88
"gopkg.in/yaml.v3"
99

10+
"github.com/flowexec/flow/internal/fileparser"
1011
"github.com/flowexec/flow/internal/filesystem"
1112
"github.com/flowexec/flow/types/common"
1213
"github.com/flowexec/flow/types/executable"
@@ -69,8 +70,8 @@ func (c *ExecutableCacheImpl) Update(logger io.Logger) error { //nolint:gocognit
6970
continue
7071
}
7172
for _, flowFile := range flowFiles {
72-
if len(flowFile.FromFile) > 0 {
73-
generated, err := generatedExecutables(logger, name, flowFile)
73+
if len(flowFile.FromFile) > 0 || len(flowFile.Imports) > 0 {
74+
generated, err := fileparser.ExecutablesFromImports(logger, name, flowFile)
7475
if err != nil {
7576
logger.Errorx(
7677
"failed to generate executables from files",
@@ -160,7 +161,7 @@ func (c *ExecutableCacheImpl) GetExecutableByRef(logger io.Logger, ref executabl
160161
cfg.SetDefaults()
161162
cfg.SetContext(wsInfo.WorkspaceName, wsInfo.WorkspacePath, cfgPath)
162163

163-
generated, err := generatedExecutables(logger, wsInfo.WorkspaceName, cfg)
164+
generated, err := fileparser.ExecutablesFromImports(logger, wsInfo.WorkspaceName, cfg)
164165
if err != nil {
165166
logger.Warnx(
166167
"failed to generate executables from files",
@@ -206,7 +207,7 @@ func (c *ExecutableCacheImpl) GetExecutableList(logger io.Logger) (executable.Ex
206207
cfg.SetDefaults()
207208
cfg.SetContext(wsInfo.WorkspaceName, wsInfo.WorkspacePath, cfgPath)
208209

209-
generated, err := generatedExecutables(logger, wsInfo.WorkspaceName, cfg)
210+
generated, err := fileparser.ExecutablesFromImports(logger, wsInfo.WorkspaceName, cfg)
210211
if err != nil {
211212
logger.Warnx(
212213
"failed to generate executables from files",

0 commit comments

Comments
 (0)