From eea108bf562e544c30a5f8aa08a2541001d19b2f Mon Sep 17 00:00:00 2001 From: Leynos Date: Wed, 23 Jul 2025 21:56:59 +0100 Subject: [PATCH 1/9] Add steps deserialization with phony default --- ...havioural-testing-in-rust-with-cucumber.md | 2 +- docs/netsuke-design.md | 17 +++--- docs/roadmap.md | 4 +- src/ast.rs | 18 +++++- tests/ast_tests.rs | 57 +++++++++++++++++++ tests/data/step_invalid.yml | 10 ++++ tests/data/steps.yml | 13 +++++ tests/features/manifest.feature | 8 +++ tests/steps/manifest_steps.rs | 12 ++++ 9 files changed, 127 insertions(+), 14 deletions(-) create mode 100644 tests/data/step_invalid.yml create mode 100644 tests/data/steps.yml diff --git a/docs/behavioural-testing-in-rust-with-cucumber.md b/docs/behavioural-testing-in-rust-with-cucumber.md index 27a5b888..0ae173ac 100644 --- a/docs/behavioural-testing-in-rust-with-cucumber.md +++ b/docs/behavioural-testing-in-rust-with-cucumber.md @@ -1166,7 +1166,7 @@ aligned with what is needed. [^31]: Cucumber in cucumber – Rust – [Docs.rs](http://Docs.rs) — accessed on 14 July 2025 — - + [^32]: CLI (command-line interface) - Cucumber Rust Book, accessed on 14 July 2025, diff --git a/docs/netsuke-design.md b/docs/netsuke-design.md index b5707908..c4fc5981 100644 --- a/docs/netsuke-design.md +++ b/docs/netsuke-design.md @@ -403,7 +403,7 @@ deserialization and easy debugging. Rust -````rust +```rust // In src/ast.rs use serde::Deserialize; @@ -551,7 +551,7 @@ targets: - name: my_app sources: "{{ glob('src/*.c') }}" rule: compile -```` +``` The value of `sources`, `{{ glob('src/*.c') }}`, is not a valid YAML string from the perspective of a strict parser. Attempting to deserialize this @@ -590,10 +590,11 @@ provides a default `Empty` variant, so optional lists are trivial to represent. The manifest version is parsed using the `semver` crate to validate that it follows semantic versioning rules. Global and target variable maps now share the `HashMap` type for consistency. This keeps YAML manifests -concise while ensuring forward compatibility. -Targets also accept optional `phony` and `always` booleans. They default to -`false`, making it explicit when a step should run regardless of file -timestamps. +concise while ensuring forward compatibility. Targets also accept optional +`phony` and `always` booleans. They default to `false`, making it explicit when +a step should run regardless of file timestamps. Targets listed in the `steps` +section are deserialised using a custom helper so they are always treated as +`phony` tasks. This ensures preparation actions never generate build artefacts. ### 3.5 Testing @@ -1003,14 +1004,14 @@ structures to the Ninja file syntax. Code snippet - ````ninja + ```ninja # Generated from an ir::Action rule cc command = gcc -c -o $out $in description = CC $out depfile = $out.d deps = gcc ```ninja - ```` + ``` 3. **Write Build Edges:** Iterate through the `graph.targets` map. For each `ir::BuildEdge`, write a corresponding Ninja `build` statement. This diff --git a/docs/roadmap.md b/docs/roadmap.md index ff72c40e..5127b353 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -29,8 +29,8 @@ compilation pipeline from parsing to execution. - [x] Support `phony` and `always` boolean flags on targets. *(done)* - - [ ] Parse the actions steps list, treating each entry as a target with - phony: true. + - [x] Parse the actions steps list, treating each entry as a target with + phony: true. *(done)* - [ ] Implement the YAML parsing logic to deserialize a static Netsukefile into the NetsukeManifest AST. diff --git a/src/ast.rs b/src/ast.rs index 70f3141a..50f3fda1 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -18,7 +18,18 @@ //! ``` use semver::Version; -use serde::Deserialize; +use serde::{Deserialize, de::Deserializer}; + +fn deserialize_steps<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let mut steps = Vec::::deserialize(deserializer)?; + for step in &mut steps { + step.phony = true; + } + Ok(steps) +} use std::collections::HashMap; /// Top-level manifest structure parsed from a `Netsukefile`. @@ -58,8 +69,9 @@ pub struct NetsukeManifest { #[serde(default)] pub rules: Vec, - /// Optional top-level steps executed before normal targets. - #[serde(default)] + /// Optional top-level steps executed before normal targets. Each step is + /// implicitly marked as `phony` during deserialisation. + #[serde(default, deserialize_with = "deserialize_steps")] pub steps: Vec, /// Primary build targets. diff --git a/tests/ast_tests.rs b/tests/ast_tests.rs index 3c659448..efbafc4e 100644 --- a/tests/ast_tests.rs +++ b/tests/ast_tests.rs @@ -244,3 +244,60 @@ fn phony_and_always_flags() { assert!(!target.phony); assert!(!target.always); } + +#[test] +fn steps_are_marked_phony() { + let yaml = r#" + netsuke_version: "1.0.0" + steps: + - name: setup + recipe: + kind: command + command: "echo hi" + targets: + - name: done + recipe: + kind: command + command: "true" + "#; + let manifest = serde_yml::from_str::(yaml).expect("parse"); + let step = manifest.steps.first().expect("step"); + assert!(step.phony); + assert!(!step.always); +} + +#[test] +fn steps_override_phony_false() { + let yaml = r#" + netsuke_version: "1.0.0" + steps: + - name: setup + recipe: + kind: command + command: "echo hi" + phony: false + targets: + - name: done + recipe: + kind: command + command: "true" + "#; + let manifest = serde_yml::from_str::(yaml).expect("parse"); + let step = manifest.steps.first().expect("step"); + assert!(step.phony, "steps must be treated as phony"); +} + +#[test] +fn steps_missing_fields_fail() { + let yaml = r#" + netsuke_version: "1.0.0" + steps: + - name: setup + targets: + - name: done + recipe: + kind: command + command: "true" + "#; + assert!(serde_yml::from_str::(yaml).is_err()); +} diff --git a/tests/data/step_invalid.yml b/tests/data/step_invalid.yml new file mode 100644 index 00000000..293f9b93 --- /dev/null +++ b/tests/data/step_invalid.yml @@ -0,0 +1,10 @@ +netsuke_version: "1.0.0" +steps: + - name: setup + phony: false +targets: + - name: done + recipe: + kind: command + command: "true" + diff --git a/tests/data/steps.yml b/tests/data/steps.yml new file mode 100644 index 00000000..83d98916 --- /dev/null +++ b/tests/data/steps.yml @@ -0,0 +1,13 @@ +netsuke_version: "1.0.0" +steps: + - name: setup + recipe: + kind: command + command: "echo hi" + phony: false +targets: + - name: done + recipe: + kind: command + command: "true" + diff --git a/tests/features/manifest.feature b/tests/features/manifest.feature index 8176e057..89fdc125 100644 --- a/tests/features/manifest.feature +++ b/tests/features/manifest.feature @@ -9,3 +9,11 @@ Feature: Manifest parsing When the manifest file "tests/data/phony.yml" is parsed Then the first target is phony And the first target is always rebuilt + + Scenario: Steps are always treated as phony + When the manifest file "tests/data/steps.yml" is parsed + Then the first step is phony + + Scenario: Invalid step fails to parse + When the manifest file "tests/data/step_invalid.yml" is parsed + Then parsing the manifest fails diff --git a/tests/steps/manifest_steps.rs b/tests/steps/manifest_steps.rs index 8f0775f4..17de5b2a 100644 --- a/tests/steps/manifest_steps.rs +++ b/tests/steps/manifest_steps.rs @@ -68,3 +68,15 @@ fn first_target_always(world: &mut CliWorld) { let first = manifest.targets.first().expect("targets"); assert!(first.always); } + +#[then("the first step is phony")] +fn first_step_phony(world: &mut CliWorld) { + let manifest = world.manifest.as_ref().expect("manifest"); + let first = manifest.steps.first().expect("steps"); + assert!(first.phony); +} + +#[then("parsing the manifest fails")] +fn manifest_parse_error(world: &mut CliWorld) { + assert!(world.manifest_error.is_some(), "expected parse error"); +} From f818f7b25ae62344012b92a8d803aa6a493c290e Mon Sep 17 00:00:00 2001 From: Leynos Date: Wed, 23 Jul 2025 22:40:24 +0100 Subject: [PATCH 2/9] Refactor step tests and add helper --- tests/ast_tests.rs | 149 ++++++++++++++++++++++++++++++--------------- 1 file changed, 101 insertions(+), 48 deletions(-) diff --git a/tests/ast_tests.rs b/tests/ast_tests.rs index efbafc4e..38fd428e 100644 --- a/tests/ast_tests.rs +++ b/tests/ast_tests.rs @@ -4,6 +4,11 @@ use netsuke::ast::*; use rstest::rstest; use semver::Version; +/// Convenience wrapper around `serde_yml::from_str` for manifest tests. +fn parse_manifest(yaml: &str) -> Result { + serde_yml::from_str::(yaml) +} + #[rstest] fn parse_minimal_manifest() { let yaml = r#"netsuke_version: "1.0.0" @@ -34,7 +39,6 @@ targets: panic!("Expected command recipe, got: {:?}", first.recipe); } } - #[test] fn missing_required_fields() { let yaml = r#" @@ -201,17 +205,31 @@ fn optional_fields() { assert!(matches!(rule.deps, StringOrList::Empty)); } -#[test] -fn invalid_enum_variants() { - let yaml = r#" - netsuke_version: "1.0.0" - targets: - - name: hello - recipe: - kind: not_a_kind - command: "echo hi" - "#; - assert!(serde_yml::from_str::(yaml).is_err()); +#[rstest] +#[case::invalid_enum_variant( + r#" + netsuke_version: "1.0.0" + targets: + - name: hello + recipe: + kind: not_a_kind + command: "echo hi" +"# +)] +#[case::steps_missing_recipe( + r#" + netsuke_version: "1.0.0" + steps: + - name: setup + targets: + - name: done + recipe: + kind: command + command: "true" +"# +)] +fn parsing_failures(#[case] yaml: &str) { + assert!(parse_manifest(yaml).is_err()); } #[test] @@ -245,29 +263,69 @@ fn phony_and_always_flags() { assert!(!target.always); } -#[test] -fn steps_are_marked_phony() { - let yaml = r#" - netsuke_version: "1.0.0" - steps: - - name: setup - recipe: - kind: command - command: "echo hi" - targets: - - name: done - recipe: - kind: command - command: "true" - "#; - let manifest = serde_yml::from_str::(yaml).expect("parse"); +#[rstest] +#[case::default_flags( + r#" + netsuke_version: "1.0.0" + steps: + - name: setup + recipe: + kind: command + command: "echo hi" + targets: + - name: done + recipe: + kind: command + command: "true" +"#, + true, + false +)] +#[case::explicit_phony_false( + r#" + netsuke_version: "1.0.0" + steps: + - name: setup + recipe: + kind: command + command: "echo hi" + phony: false + targets: + - name: done + recipe: + kind: command + command: "true" +"#, + true, + false +)] +#[case::explicit_always_true( + r#" + netsuke_version: "1.0.0" + steps: + - name: setup + recipe: + kind: command + command: "echo hi" + always: true + targets: + - name: done + recipe: + kind: command + command: "true" +"#, + true, + true +)] +fn steps_behavior(#[case] yaml: &str, #[case] expected_phony: bool, #[case] expected_always: bool) { + let manifest = parse_manifest(yaml).expect("parse"); let step = manifest.steps.first().expect("step"); - assert!(step.phony); - assert!(!step.always); + assert_eq!(step.phony, expected_phony); + assert_eq!(step.always, expected_always); } #[test] -fn steps_override_phony_false() { +fn multiple_steps_are_marked_phony() { let yaml = r#" netsuke_version: "1.0.0" steps: @@ -275,29 +333,24 @@ fn steps_override_phony_false() { recipe: kind: command command: "echo hi" - phony: false - targets: - - name: done + - name: build recipe: kind: command - command: "true" - "#; - let manifest = serde_yml::from_str::(yaml).expect("parse"); - let step = manifest.steps.first().expect("step"); - assert!(step.phony, "steps must be treated as phony"); -} - -#[test] -fn steps_missing_fields_fail() { - let yaml = r#" - netsuke_version: "1.0.0" - steps: - - name: setup + command: "make build" + - name: test + recipe: + kind: command + command: "cargo test" targets: - name: done recipe: kind: command command: "true" "#; - assert!(serde_yml::from_str::(yaml).is_err()); + let manifest = parse_manifest(yaml).expect("parse"); + assert_eq!(manifest.steps.len(), 3); + for step in &manifest.steps { + assert!(step.phony); + assert!(!step.always); + } } From 9b6d940662d54a42a0177b9df85fbbdedc36b0ae Mon Sep 17 00:00:00 2001 From: Leynos Date: Wed, 23 Jul 2025 23:00:43 +0100 Subject: [PATCH 3/9] Rename steps to actions --- docs/netsuke-design.md | 19 ++++++----- docs/roadmap.md | 2 +- src/ast.rs | 18 +++++----- tests/ast_tests.rs | 34 +++++++++++-------- .../{step_invalid.yml => action_invalid.yml} | 2 +- tests/data/{steps.yml => actions.yml} | 2 +- tests/features/manifest.feature | 10 +++--- tests/steps/manifest_steps.rs | 6 ++-- 8 files changed, 49 insertions(+), 44 deletions(-) rename tests/data/{step_invalid.yml => action_invalid.yml} (93%) rename tests/data/{steps.yml => actions.yml} (95%) diff --git a/docs/netsuke-design.md b/docs/netsuke-design.md index c4fc5981..4c372223 100644 --- a/docs/netsuke-design.md +++ b/docs/netsuke-design.md @@ -177,7 +177,7 @@ level keys. the sources it depends on, and the rule used to produce it. This corresponds to a Ninja `build` statement.[^3] -- `steps`: A secondary list of build targets. Any target placed here is +- `actions`: A secondary list of build targets. Any target placed here is treated as `{ phony: true, always: false }` by default. - `defaults`: An optional list of target names to be built when Netsuke is @@ -193,7 +193,7 @@ erDiagram string netsuke_version map vars list rules - list steps + list actions list targets list defaults } @@ -223,7 +223,7 @@ erDiagram enum value } NETSUKE_MANIFEST ||--o{ RULE : contains - NETSUKE_MANIFEST ||--o{ TARGET : has_steps + NETSUKE_MANIFEST ||--o{ TARGET : has_actions NETSUKE_MANIFEST ||--o{ TARGET : has_targets RULE }o--|| RECIPE : uses TARGET }o--|| RECIPE : uses @@ -274,7 +274,7 @@ Each entry in the `rules` list is a mapping that defines a reusable action. ### 2.4 Defining `targets` Each entry in `targets` defines a build edge; placing a target in the optional -`steps` list instead marks it as `phony: true` with `always` left `false`. +`actions` list instead marks it as `phony: true` with `always` left `false`. - `name`: The primary output file or files for this build step. This can be a single string or a list of strings. @@ -421,7 +421,7 @@ pub struct NetsukeManifest { pub rules: Vec, #[serde(default)] - pub steps: Vec, + pub actions: Vec, pub targets: Vec, @@ -519,7 +519,7 @@ let ast = NetsukeManifest { netsuke_version: Version::parse("1.0.0").unwrap(), vars: HashMap::new(), rules: vec![], - steps: vec![], + actions: vec![], targets: vec![Target { name: StringOrList::String("hello".into()), recipe: Recipe::Command { @@ -592,9 +592,10 @@ follows semantic versioning rules. Global and target variable maps now share the `HashMap` type for consistency. This keeps YAML manifests concise while ensuring forward compatibility. Targets also accept optional `phony` and `always` booleans. They default to `false`, making it explicit when -a step should run regardless of file timestamps. Targets listed in the `steps` -section are deserialised using a custom helper so they are always treated as -`phony` tasks. This ensures preparation actions never generate build artefacts. +an action should run regardless of file timestamps. Targets listed in the +`actions` section are deserialised using a custom helper so they are always +treated as `phony` tasks. This ensures preparation actions never generate build +artefacts. ### 3.5 Testing diff --git a/docs/roadmap.md b/docs/roadmap.md index 5127b353..66918610 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -29,7 +29,7 @@ compilation pipeline from parsing to execution. - [x] Support `phony` and `always` boolean flags on targets. *(done)* - - [x] Parse the actions steps list, treating each entry as a target with + - [x] Parse the actions list, treating each entry as a target with phony: true. *(done)* - [ ] Implement the YAML parsing logic to deserialize a static Netsukefile diff --git a/src/ast.rs b/src/ast.rs index 50f3fda1..55320c6e 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -20,15 +20,15 @@ use semver::Version; use serde::{Deserialize, de::Deserializer}; -fn deserialize_steps<'de, D>(deserializer: D) -> Result, D::Error> +fn deserialize_actions<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { - let mut steps = Vec::::deserialize(deserializer)?; - for step in &mut steps { - step.phony = true; + let mut actions = Vec::::deserialize(deserializer)?; + for action in &mut actions { + action.phony = true; } - Ok(steps) + Ok(actions) } use std::collections::HashMap; @@ -39,7 +39,7 @@ use std::collections::HashMap; /// /// ```yaml /// netsuke_version: "1.0.0" -/// steps: [] +/// actions: [] /// targets: /// - name: hello /// recipe: @@ -69,10 +69,10 @@ pub struct NetsukeManifest { #[serde(default)] pub rules: Vec, - /// Optional top-level steps executed before normal targets. Each step is + /// Optional setup actions executed before normal targets. Each action is /// implicitly marked as `phony` during deserialisation. - #[serde(default, deserialize_with = "deserialize_steps")] - pub steps: Vec, + #[serde(default, deserialize_with = "deserialize_actions")] + pub actions: Vec, /// Primary build targets. pub targets: Vec, diff --git a/tests/ast_tests.rs b/tests/ast_tests.rs index 38fd428e..33e156c1 100644 --- a/tests/ast_tests.rs +++ b/tests/ast_tests.rs @@ -216,10 +216,10 @@ fn optional_fields() { command: "echo hi" "# )] -#[case::steps_missing_recipe( +#[case::actions_missing_recipe( r#" netsuke_version: "1.0.0" - steps: + actions: - name: setup targets: - name: done @@ -267,7 +267,7 @@ fn phony_and_always_flags() { #[case::default_flags( r#" netsuke_version: "1.0.0" - steps: + actions: - name: setup recipe: kind: command @@ -284,7 +284,7 @@ fn phony_and_always_flags() { #[case::explicit_phony_false( r#" netsuke_version: "1.0.0" - steps: + actions: - name: setup recipe: kind: command @@ -302,7 +302,7 @@ fn phony_and_always_flags() { #[case::explicit_always_true( r#" netsuke_version: "1.0.0" - steps: + actions: - name: setup recipe: kind: command @@ -317,18 +317,22 @@ fn phony_and_always_flags() { true, true )] -fn steps_behavior(#[case] yaml: &str, #[case] expected_phony: bool, #[case] expected_always: bool) { +fn actions_behavior( + #[case] yaml: &str, + #[case] expected_phony: bool, + #[case] expected_always: bool, +) { let manifest = parse_manifest(yaml).expect("parse"); - let step = manifest.steps.first().expect("step"); - assert_eq!(step.phony, expected_phony); - assert_eq!(step.always, expected_always); + let action = manifest.actions.first().expect("action"); + assert_eq!(action.phony, expected_phony); + assert_eq!(action.always, expected_always); } #[test] -fn multiple_steps_are_marked_phony() { +fn multiple_actions_are_marked_phony() { let yaml = r#" netsuke_version: "1.0.0" - steps: + actions: - name: setup recipe: kind: command @@ -348,9 +352,9 @@ fn multiple_steps_are_marked_phony() { command: "true" "#; let manifest = parse_manifest(yaml).expect("parse"); - assert_eq!(manifest.steps.len(), 3); - for step in &manifest.steps { - assert!(step.phony); - assert!(!step.always); + assert_eq!(manifest.actions.len(), 3); + for action in &manifest.actions { + assert!(action.phony); + assert!(!action.always); } } diff --git a/tests/data/step_invalid.yml b/tests/data/action_invalid.yml similarity index 93% rename from tests/data/step_invalid.yml rename to tests/data/action_invalid.yml index 293f9b93..a491a75b 100644 --- a/tests/data/step_invalid.yml +++ b/tests/data/action_invalid.yml @@ -1,5 +1,5 @@ netsuke_version: "1.0.0" -steps: +actions: - name: setup phony: false targets: diff --git a/tests/data/steps.yml b/tests/data/actions.yml similarity index 95% rename from tests/data/steps.yml rename to tests/data/actions.yml index 83d98916..e8d13461 100644 --- a/tests/data/steps.yml +++ b/tests/data/actions.yml @@ -1,5 +1,5 @@ netsuke_version: "1.0.0" -steps: +actions: - name: setup recipe: kind: command diff --git a/tests/features/manifest.feature b/tests/features/manifest.feature index 89fdc125..7482cc28 100644 --- a/tests/features/manifest.feature +++ b/tests/features/manifest.feature @@ -10,10 +10,10 @@ Feature: Manifest parsing Then the first target is phony And the first target is always rebuilt - Scenario: Steps are always treated as phony - When the manifest file "tests/data/steps.yml" is parsed - Then the first step is phony + Scenario: Actions are always treated as phony + When the manifest file "tests/data/actions.yml" is parsed + Then the first action is phony - Scenario: Invalid step fails to parse - When the manifest file "tests/data/step_invalid.yml" is parsed + Scenario: Invalid action fails to parse + When the manifest file "tests/data/action_invalid.yml" is parsed Then parsing the manifest fails diff --git a/tests/steps/manifest_steps.rs b/tests/steps/manifest_steps.rs index 17de5b2a..fcff4887 100644 --- a/tests/steps/manifest_steps.rs +++ b/tests/steps/manifest_steps.rs @@ -69,10 +69,10 @@ fn first_target_always(world: &mut CliWorld) { assert!(first.always); } -#[then("the first step is phony")] -fn first_step_phony(world: &mut CliWorld) { +#[then("the first action is phony")] +fn first_action_phony(world: &mut CliWorld) { let manifest = world.manifest.as_ref().expect("manifest"); - let first = manifest.steps.first().expect("steps"); + let first = manifest.actions.first().expect("actions"); assert!(first.phony); } From ce52c83d249d9d0934582ac4c2aabecad98b62c8 Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 24 Jul 2025 00:32:33 +0100 Subject: [PATCH 4/9] Normalize footnote spacing --- docs/behavioural-testing-in-rust-with-cucumber.md | 3 +-- tests/data/action_invalid.yml | 3 +-- tests/data/actions.yml | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/behavioural-testing-in-rust-with-cucumber.md b/docs/behavioural-testing-in-rust-with-cucumber.md index 0ae173ac..55983c39 100644 --- a/docs/behavioural-testing-in-rust-with-cucumber.md +++ b/docs/behavioural-testing-in-rust-with-cucumber.md @@ -1165,8 +1165,7 @@ aligned with what is needed. [^31]: Cucumber in cucumber – Rust – [Docs.rs](http://Docs.rs) — accessed on 14 - July 2025 — - + July 2025 — [^32]: CLI (command-line interface) - Cucumber Rust Book, accessed on 14 July 2025, diff --git a/tests/data/action_invalid.yml b/tests/data/action_invalid.yml index a491a75b..4d73a0e7 100644 --- a/tests/data/action_invalid.yml +++ b/tests/data/action_invalid.yml @@ -6,5 +6,4 @@ targets: - name: done recipe: kind: command - command: "true" - + command: "true" \ No newline at end of file diff --git a/tests/data/actions.yml b/tests/data/actions.yml index e8d13461..1e1de523 100644 --- a/tests/data/actions.yml +++ b/tests/data/actions.yml @@ -9,5 +9,4 @@ targets: - name: done recipe: kind: command - command: "true" - + command: "true" \ No newline at end of file From b6ba0f3d3085c6735916642cae5ca37d37c011a2 Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 24 Jul 2025 17:23:31 +0100 Subject: [PATCH 5/9] Add trailing newline to YAML fixtures --- tests/data/action_invalid.yml | 2 +- tests/data/actions.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/data/action_invalid.yml b/tests/data/action_invalid.yml index 4d73a0e7..427a6f7d 100644 --- a/tests/data/action_invalid.yml +++ b/tests/data/action_invalid.yml @@ -6,4 +6,4 @@ targets: - name: done recipe: kind: command - command: "true" \ No newline at end of file + command: "true" diff --git a/tests/data/actions.yml b/tests/data/actions.yml index 1e1de523..aa642af7 100644 --- a/tests/data/actions.yml +++ b/tests/data/actions.yml @@ -9,4 +9,4 @@ targets: - name: done recipe: kind: command - command: "true" \ No newline at end of file + command: "true" From da4ba6c13a53dcea43629f87ac4ae1296e2518ed Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 24 Jul 2025 21:11:18 +0100 Subject: [PATCH 6/9] Remove ignored phony field in actions fixture --- tests/data/actions.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/data/actions.yml b/tests/data/actions.yml index aa642af7..14e0e1f5 100644 --- a/tests/data/actions.yml +++ b/tests/data/actions.yml @@ -4,7 +4,6 @@ actions: recipe: kind: command command: "echo hi" - phony: false targets: - name: done recipe: From adf6427a20e094e68434f92b25f89e8b6835d154 Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 24 Jul 2025 23:24:53 +0100 Subject: [PATCH 7/9] Fix footnote formatting and YAML fixture --- docs/behavioural-testing-in-rust-with-cucumber.md | 9 +++++---- tests/data/action_invalid.yml | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/behavioural-testing-in-rust-with-cucumber.md b/docs/behavioural-testing-in-rust-with-cucumber.md index 55983c39..45b55f8f 100644 --- a/docs/behavioural-testing-in-rust-with-cucumber.md +++ b/docs/behavioural-testing-in-rust-with-cucumber.md @@ -1164,11 +1164,12 @@ aligned with what is needed. accessed on July 14, 2025, -[^31]: Cucumber in cucumber – Rust – [Docs.rs](http://Docs.rs) — accessed on 14 - July 2025 — +[^31]: Cucumber in cucumber – [Docs.rs](http://Docs.rs) — accessed on + 14 July 2025 — + -[^32]: CLI (command-line interface) - Cucumber Rust Book, accessed on - 14 July 2025, +[^32]: CLI (command-line interface) - Cucumber Rust Book, accessed + on 14 July 2025, [^33]: Continuous Integration - Cucumber, accessed on 14 July 2025, diff --git a/tests/data/action_invalid.yml b/tests/data/action_invalid.yml index 427a6f7d..d1232431 100644 --- a/tests/data/action_invalid.yml +++ b/tests/data/action_invalid.yml @@ -1,7 +1,6 @@ netsuke_version: "1.0.0" actions: - name: setup - phony: false targets: - name: done recipe: From 4951b5da5d827754b1dde15b042ee35de82e8bd1 Mon Sep 17 00:00:00 2001 From: Leynos Date: Fri, 25 Jul 2025 12:07:05 +0100 Subject: [PATCH 8/9] Fix footnote indentation --- docs/behavioural-testing-in-rust-with-cucumber.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/behavioural-testing-in-rust-with-cucumber.md b/docs/behavioural-testing-in-rust-with-cucumber.md index 45b55f8f..a3dfef12 100644 --- a/docs/behavioural-testing-in-rust-with-cucumber.md +++ b/docs/behavioural-testing-in-rust-with-cucumber.md @@ -1169,7 +1169,8 @@ aligned with what is needed. [^32]: CLI (command-line interface) - Cucumber Rust Book, accessed - on 14 July 2025, + on 14 July 2025, + [^33]: Continuous Integration - Cucumber, accessed on 14 July 2025, From 24476dde59125d0836dc4d672367581ce538d268 Mon Sep 17 00:00:00 2001 From: Leynos Date: Fri, 25 Jul 2025 17:38:16 +0100 Subject: [PATCH 9/9] Fix footnote styling and clarify invalid action fixture --- docs/behavioural-testing-in-rust-with-cucumber.md | 5 ++--- tests/data/action_invalid.yml | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/behavioural-testing-in-rust-with-cucumber.md b/docs/behavioural-testing-in-rust-with-cucumber.md index a3dfef12..c49f15bb 100644 --- a/docs/behavioural-testing-in-rust-with-cucumber.md +++ b/docs/behavioural-testing-in-rust-with-cucumber.md @@ -1168,9 +1168,8 @@ aligned with what is needed. 14 July 2025 — -[^32]: CLI (command-line interface) - Cucumber Rust Book, accessed - on 14 July 2025, - +[^32]: CLI (command–line interface) - Cucumber Rust Book, accessed + on 14 July 2025, [^33]: Continuous Integration - Cucumber, accessed on 14 July 2025, diff --git a/tests/data/action_invalid.yml b/tests/data/action_invalid.yml index d1232431..2690d38a 100644 --- a/tests/data/action_invalid.yml +++ b/tests/data/action_invalid.yml @@ -1,3 +1,5 @@ +# This fixture is intentionally invalid. It lacks keys like `recipe` and +# `phony` so the loader should fail when parsing it. netsuke_version: "1.0.0" actions: - name: setup