diff --git a/docs/usage.md b/docs/usage.md index 9c66c7e..3315abe 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -99,7 +99,7 @@ forge run --filter test.unit-tests ``` When `--filter ` is used, FORGE resolves and executes that stage along with any stages it depends on. -When `--filter .` is used, FORGE runs only that specific step. If the filter target stage or step does not exist, FORGE displays available options and exits with error code 2. +When `--filter .` is used, FORGE runs the target stage's dependency stages first, then only the selected step in the target stage. If the filter target stage or step does not exist, FORGE displays available options and exits with error code 2. Enable or disable caching: diff --git a/src/config/mod.rs b/src/config/mod.rs index c9ef508..9cb0603 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -243,7 +243,17 @@ pub fn apply_filter( let stage_map: HashMap = config.stages.iter().map(|s| (s.name.clone(), s)).collect(); - let target_stage_name = match filter { + let full_filter = match filter { + FilterTarget::Stage(name) => name.clone(), + FilterTarget::Step { stage, step } => format!("{stage}.{step}"), + }; + let resolved_filter = if stage_map.contains_key(&full_filter) { + FilterTarget::Stage(full_filter) + } else { + filter.clone() + }; + + let target_stage_name = match &resolved_filter { FilterTarget::Stage(name) => name, FilterTarget::Step { stage, .. } => stage, }; @@ -263,7 +273,7 @@ pub fn apply_filter( ))); } - if let FilterTarget::Step { stage, step } = filter { + if let FilterTarget::Step { stage, step } = &resolved_filter { let target_stage = stage_map.get(stage).unwrap(); let available_steps: Vec = target_stage .steps @@ -318,7 +328,7 @@ pub fn apply_filter( config.stages.retain(|s| required.contains(&s.name)); // If filtering to a specific step, filter that stage's steps - if let FilterTarget::Step { stage, step } = filter { + if let FilterTarget::Step { stage, step } = &resolved_filter { for s in &mut config.stages { if s.name == *stage { s.steps.retain(|st| st.name == *step); @@ -455,6 +465,46 @@ mod tests { assert!(!config.stages[0].parallel); } + #[test] + fn test_apply_filter_prefers_full_dotted_stage_name() { + let mut config = ForgeConfig { + version: "1.0".to_string(), + stages: vec![Stage { + name: "test.unit".to_string(), + steps: vec![ + Step { + name: "first".to_string(), + command: "echo first".to_string(), + image: "".to_string(), + working_dir: "".to_string(), + env: HashMap::new(), + depends_on: vec![], + }, + Step { + name: "second".to_string(), + command: "echo second".to_string(), + image: "".to_string(), + working_dir: "".to_string(), + env: HashMap::new(), + depends_on: vec![], + }, + ], + parallel: false, + depends_on: vec![], + }], + steps: vec![], + cache: CacheConfig::default(), + secrets: vec![], + }; + + let filter = FilterTarget::parse("test.unit").unwrap(); + apply_filter(&mut config, &filter).unwrap(); + + assert_eq!(config.stages.len(), 1); + assert_eq!(config.stages[0].name, "test.unit"); + assert_eq!(config.stages[0].steps.len(), 2); + } + #[test] fn test_apply_filter_nonexistent_stage() { let mut config = ForgeConfig {