From 86b6862ac6e62b7e4d073198c4955ccf9534179c Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 9 Jul 2026 14:36:59 +0200 Subject: [PATCH 1/6] docs: updated to contain the latest features --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fa0bc66..c8418b2 100644 --- a/README.md +++ b/README.md @@ -11,4 +11,4 @@ Internal Rust library for CodeZero execution services (Aquila, Draco, Taurus). I - `flow_service` push definitions to Aquila via gRPC (depends on `flow_definition`) - `flow_config` env helpers and `.env` loading - `flow_health` tonic health service with NATS readiness - +- `flow_telemetry` helpers for Open Telemetry From 8f9e0b3b3e2e4160ced68b1d71160d82a5997a49 Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 9 Jul 2026 14:40:38 +0200 Subject: [PATCH 2/6] feat: added reader verification tests --- src/flow_definition/mod.rs | 251 ++++++++++++++++++++++++++++++++++++- 1 file changed, 249 insertions(+), 2 deletions(-) diff --git a/src/flow_definition/mod.rs b/src/flow_definition/mod.rs index e6d3fc1..56d9cf8 100644 --- a/src/flow_definition/mod.rs +++ b/src/flow_definition/mod.rs @@ -10,7 +10,7 @@ use std::fs; use std::path::{Path, PathBuf}; use tucana::shared::{ DefinitionDataType, FlowType, FunctionDefinition, Module, ModuleConfigurationDefinition, - RuntimeFlowType, RuntimeFunctionDefinition, Translation, + ModuleDefinition, RuntimeFlowType, RuntimeFunctionDefinition, Translation, }; use walkdir::WalkDir; @@ -43,6 +43,7 @@ struct LoadedModule { functions: Vec, runtime_functions: Vec, configurations: Vec, + definitions: Vec, } impl LoadedModule { @@ -65,7 +66,7 @@ impl LoadedModule { runtime_function_definitions: self.runtime_functions, definition_data_types: self.data_types, configurations: self.configurations, - definitions: Vec::new(), + definitions: self.definitions, } } } @@ -209,6 +210,11 @@ impl Reader { )?, ); } + "definition" | "definitions" | "module_definition" | "module_definitions" => { + module + .definitions + .extend(load_json_dir::(&path, self.should_break)?); + } _ => {} } } @@ -335,6 +341,10 @@ fn is_definition_dir(name: &str) -> bool { | "functions" | "configuration" | "configurations" + | "definition" + | "definitions" + | "module_definition" + | "module_definitions" ) } @@ -355,3 +365,240 @@ fn module_name_from_paths(root: &Path, module_path: &Path) -> String { relative.to_string() } } + +#[cfg(test)] +mod tests { + use super::*; + use std::sync::atomic::{AtomicUsize, Ordering}; + use tucana::shared::module_definition; + + static TEST_DIRECTORY_COUNTER: AtomicUsize = AtomicUsize::new(0); + + struct TestDefinitions { + root: PathBuf, + } + + impl TestDefinitions { + fn new(name: &str) -> Self { + let id = TEST_DIRECTORY_COUNTER.fetch_add(1, Ordering::Relaxed); + let root = + std::env::temp_dir().join(format!("code0-flow-{name}-{}-{id}", std::process::id())); + + if root.exists() { + fs::remove_dir_all(&root).expect("clean stale test definitions"); + } + + Self { root } + } + + fn write(&self, path: &str, content: &str) { + let path = self.root.join(path); + fs::create_dir_all(path.parent().expect("test definition parent")) + .expect("create test definition directory"); + fs::write(path, content).expect("write test definition"); + } + + fn path(&self) -> String { + self.root.to_string_lossy().to_string() + } + } + + impl Drop for TestDefinitions { + fn drop(&mut self) { + let _ = fs::remove_dir_all(&self.root); + } + } + + fn definitions_fixture() -> TestDefinitions { + let definitions = TestDefinitions::new("definitions-fixture"); + definitions.write( + "taurus/boolean/module.json", + r#"{ + "identifier": "taurus.boolean", + "name": [{"code": "en-US", "content": "Boolean"}], + "description": [{"code": "en-US", "content": "Boolean feature"}], + "documentation": "Boolean docs", + "author": "Code0", + "icon": "tabler:toggle-left", + "version": "1.0.0" + }"#, + ); + definitions.write( + "taurus/boolean/data_types/boolean.proto.json", + r#"{ + "identifier": "BOOLEAN", + "name": [{"code": "en-US", "content": "Boolean"}], + "displayMessage": [{"code": "en-US", "content": "Boolean"}], + "alias": [{"code": "en-US", "content": "bool"}], + "rules": [], + "type": "boolean", + "version": "1.0.0" + }"#, + ); + definitions.write( + "taurus/boolean/flow_types/boolean-flow.proto.json", + r#"{ + "identifier": "BOOLEAN_FLOW", + "runtimeIdentifier": "BOOLEAN_FLOW", + "settings": [], + "editable": true, + "name": [{"code": "en-US", "content": "Boolean Flow"}], + "description": [], + "documentation": [], + "displayMessage": [], + "alias": [], + "version": "1.0.0", + "displayIcon": "tabler:toggle-left", + "linkedDataTypeIdentifiers": ["BOOLEAN"], + "signature": "(): void" + }"#, + ); + definitions.write( + "taurus/boolean/functions/std_boolean_negate.proto.json", + r#"{ + "runtimeName": "std::boolean::negate", + "runtimeDefinitionName": "std::boolean::negate", + "parameterDefinitions": [], + "signature": "(): BOOLEAN", + "throwsError": false, + "name": [{"code": "en-US", "content": "Negate Boolean"}], + "description": [], + "documentation": [], + "deprecationMessage": [], + "displayMessage": [], + "alias": [], + "linkedDataTypeIdentifiers": ["BOOLEAN"], + "version": "1.0.0", + "displayIcon": "tabler:toggle-left" + }"#, + ); + definitions.write( + "taurus/boolean/runtime_functions/std_boolean_negate.proto.json", + r#"{ + "runtimeName": "std::boolean::negate", + "runtimeParameterDefinitions": [], + "signature": "(): BOOLEAN", + "throwsError": false, + "name": [{"code": "en-US", "content": "Negate Boolean"}], + "description": [], + "documentation": [], + "deprecationMessage": [], + "displayMessage": [], + "alias": [], + "linkedDataTypeIdentifiers": ["BOOLEAN"], + "version": "1.0.0", + "displayIcon": "tabler:toggle-left" + }"#, + ); + definitions.write( + "taurus/boolean/runtime_flow_types/boolean-flow.proto.json", + r#"{ + "identifier": "BOOLEAN_FLOW", + "runtimeSettings": [], + "editable": true, + "name": [{"code": "en-US", "content": "Boolean Flow"}], + "description": [], + "documentation": [], + "displayMessage": [], + "alias": [], + "version": "1.0.0", + "displayIcon": "tabler:toggle-left", + "linkedDataTypeIdentifiers": ["BOOLEAN"], + "signature": "(): void" + }"#, + ); + definitions.write( + "taurus/boolean/configurations/endpoint.proto.json", + r#"{ + "identifier": "endpoint", + "name": [{"code": "en-US", "content": "Endpoint"}], + "description": [], + "type": "TEXT", + "linkedDataTypeIdentifiers": [] + }"#, + ); + definitions.write( + "taurus/boolean/definitions/endpoint.proto.json", + r#"{ + "flowTypeIdentifier": ["BOOLEAN_FLOW"], + "endpoint": { + "host": "localhost", + "port": "8080", + "endpoint": "/boolean" + } + }"#, + ); + + definitions + } + + #[test] + fn read_features_registers_definition_features() { + let definitions = definitions_fixture(); + let reader = Reader::configure(definitions.path(), true, vec![], None); + + let features = reader.read_features().expect("read features"); + + assert_eq!(features.len(), 1); + let feature = &features[0]; + assert_eq!(feature.name, "taurus/boolean"); + assert_eq!(feature.data_types[0].identifier, "BOOLEAN"); + assert_eq!(feature.flow_types[0].identifier, "BOOLEAN_FLOW"); + assert_eq!(feature.functions[0].runtime_name, "std::boolean::negate"); + assert_eq!( + feature.runtime_functions[0].runtime_name, + "std::boolean::negate" + ); + } + + #[test] + fn read_modules_registers_full_definition_payload() { + let definitions = definitions_fixture(); + let reader = Reader::configure(definitions.path(), true, vec![], None); + + let modules = reader.read_modules().expect("read modules"); + + assert_eq!(modules.len(), 1); + let module = &modules[0]; + assert_eq!(module.identifier, "taurus.boolean"); + assert_eq!(module.definition_data_types.len(), 1); + assert_eq!(module.flow_types.len(), 1); + assert_eq!(module.runtime_flow_types.len(), 1); + assert_eq!(module.function_definitions.len(), 1); + assert_eq!(module.runtime_function_definitions.len(), 1); + assert_eq!(module.configurations.len(), 1); + assert_eq!(module.definitions.len(), 1); + assert_eq!( + module.definitions[0].flow_type_identifier, + vec!["BOOLEAN_FLOW".to_string()] + ); + + match module.definitions[0].value.as_ref() { + Some(module_definition::Value::Endpoint(endpoint)) => { + assert_eq!(endpoint.host, "localhost"); + assert_eq!(endpoint.port, 8080); + assert_eq!(endpoint.endpoint, "/boolean"); + } + value => panic!("expected endpoint module definition, got {value:?}"), + } + } + + #[test] + fn read_features_filters_definitions_by_version() { + let definitions = definitions_fixture(); + let reader = Reader::configure( + definitions.path(), + true, + vec!["taurus/boolean".to_string()], + Some("2.0.0".to_string()), + ); + + let features = reader.read_features().expect("read features"); + + assert_eq!(features.len(), 1); + assert!(features[0].data_types.is_empty()); + assert!(features[0].flow_types.is_empty()); + assert!(features[0].functions.is_empty()); + assert!(features[0].runtime_functions.is_empty()); + } +} From 667188fc57f4d752a50929eac9d4569c83b2cb9d Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 9 Jul 2026 14:52:24 +0200 Subject: [PATCH 3/6] feat: added more ci steps --- .github/workflows/build.yml | 54 +++++++++++++++++++++++++++-------- .github/workflows/publish.yml | 42 ++++++++++++++++++++------- 2 files changed, 74 insertions(+), 22 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0cccdd7..8b95da4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,9 +2,17 @@ name: Build code0-flow crate on: push: + pull_request: + +permissions: + contents: read + +env: + CARGO_TERM_COLOR: always + RUST_BACKTRACE: full jobs: - crates: + ci: runs-on: ubuntu-latest defaults: @@ -13,17 +21,39 @@ jobs: steps: - uses: actions/checkout@v7 + - name: Setup rust - run: rustup update --no-self-update stable + run: | + rustup update --no-self-update stable + rustup component add rustfmt clippy + - name: Install protoc - run: curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v28.0-rc1/protoc-28.0-rc-1-linux-x86_64.zip && unzip protoc-28.0-rc-1-linux-x86_64.zip -d ${{ runner.temp }}/proto && chmod +x ${{ runner.temp }}/proto/bin/protoc && ${{ runner.temp }}/proto/bin/protoc --version - - name: Build crate - run: PATH=${{ runner.temp }}/proto/bin:$PATH cargo build - env: - RUST_BACKTRACE: 'full' - - name: Run Tests - run: PATH=${{ runner.temp }}/proto/bin:$PATH cargo test --features all - env: - RUST_BACKTRACE: 'full' + run: | + sudo apt-get update + sudo apt-get install -y protobuf-compiler + protoc --version + + - name: Check formatting + run: cargo fmt --all -- --check + + - name: Check default feature set + run: cargo check --locked --all-targets + + - name: Check feature combinations + run: | + cargo check --locked --all-targets --no-default-features + cargo check --locked --all-targets --features flow_definition + cargo check --locked --all-targets --features flow_config + cargo check --locked --all-targets --features flow_health + cargo check --locked --all-targets --features flow_service + cargo check --locked --all-targets --features flow_telemetry + cargo check --locked --all-targets --features all + + - name: Run clippy + run: cargo clippy --locked --all-targets --features all -- -D warnings + + - name: Run tests + run: cargo test --locked --features all + - name: Package crate - run: cargo package --allow-dirty \ No newline at end of file + run: cargo package --locked diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index bdccdc5..652d144 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -5,8 +5,15 @@ on: tags: - '*' +permissions: + contents: read + +env: + CARGO_TERM_COLOR: always + RUST_BACKTRACE: full + jobs: - crates: + publish: runs-on: ubuntu-latest environment: packages @@ -16,21 +23,36 @@ jobs: shell: bash steps: - # Set up - uses: actions/checkout@v7 + - name: Setup rust - run: rustup update --no-self-update stable + run: | + rustup update --no-self-update stable + rustup component add rustfmt clippy + - name: Install protoc - run: curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v28.0-rc1/protoc-28.0-rc-1-linux-x86_64.zip && unzip protoc-28.0-rc-1-linux-x86_64.zip -d ${{ runner.temp }}/proto && chmod +x ${{ runner.temp }}/proto/bin/protoc && ${{ runner.temp }}/proto/bin/protoc --version + run: | + sudo apt-get update + sudo apt-get install -y protobuf-compiler + protoc --version + - name: Set version run: sed -i "s/version = \"0.0.0\"/version = \"${{ github.ref_name }}\"/" Cargo.toml + + - name: Check formatting + run: cargo fmt --all -- --check + + - name: Check crate + run: cargo check --locked --all-targets --features all + + - name: Run clippy + run: cargo clippy --locked --all-targets --features all -- -D warnings + + - name: Run tests + run: cargo test --locked --features all + - name: Cargo Login run: cargo login ${{secrets.CARGO_REGISTRY_TOKEN}} - - name: Build crate - run: PATH=${{ runner.temp }}/proto/bin:$PATH cargo build - env: - RUST_BACKTRACE: 'full' - # Release - name: Publish crate - run: cargo publish --allow-dirty \ No newline at end of file + run: cargo publish --allow-dirty From bde00c8f407fdadf51a8f528c063e556b4c74951 Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 9 Jul 2026 14:52:44 +0200 Subject: [PATCH 4/6] ref: cargo clippy --- src/flow_config/mod.rs | 6 +++--- src/flow_definition/error/mod.rs | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/flow_config/mod.rs b/src/flow_config/mod.rs index 96e3152..e84986a 100644 --- a/src/flow_config/mod.rs +++ b/src/flow_config/mod.rs @@ -99,7 +99,7 @@ mod tests { } let result = env_with_default(key, false); - assert_eq!(result, true); + assert!(result); unsafe { env::remove_var(key); @@ -114,7 +114,7 @@ mod tests { } let result = env_with_default(key, true); - assert_eq!(result, false); + assert!(!result); unsafe { env::remove_var(key); @@ -141,7 +141,7 @@ mod tests { } let result = env_with_default(key, false); - assert_eq!(result, false); + assert!(!result); unsafe { env::remove_var(key); diff --git a/src/flow_definition/error/mod.rs b/src/flow_definition/error/mod.rs index 0eeb34e..6a99496 100644 --- a/src/flow_definition/error/mod.rs +++ b/src/flow_definition/error/mod.rs @@ -2,6 +2,7 @@ use std::io; use std::path::PathBuf; #[derive(Debug)] +#[allow(clippy::enum_variant_names)] pub enum ReaderError { JsonError { path: PathBuf, From f3e19270e8858a86cd884ca47d9413ec3f8cdf10 Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 9 Jul 2026 14:54:42 +0200 Subject: [PATCH 5/6] deps: updted slab because it was yanked --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1dbe74e..cecbf0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1710,9 +1710,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" From 47d2cbdefd08178d9e22b09861a60314eee467ce Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 9 Jul 2026 15:12:49 +0200 Subject: [PATCH 6/6] ref: cargo clippy --- src/flow_config/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/flow_config/mod.rs b/src/flow_config/mod.rs index e84986a..df9bbd9 100644 --- a/src/flow_config/mod.rs +++ b/src/flow_config/mod.rs @@ -7,11 +7,11 @@ pub fn env_with_default(key: &str, default: T) -> T { match std::env::var(key) { Ok(string) => match T::from_str(&string) { Ok(value) => { - log::info!("Found env: {} with value: {:?}", key, &value); + log::info!("Found env: {} with value: {:?}", key, value); value } Err(_) => { - log::warn!("Failed to parse env: {} with value: {:?}", key, &string); + log::warn!("Failed to parse env: {} with value: {:?}", key, string); default } },