Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ forge run --filter test.unit-tests
```

When `--filter <stage>` is used, FORGE resolves and executes that stage along with any stages it depends on.
When `--filter <stage>.<step>` 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 <stage>.<step>` 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:

Expand Down
56 changes: 53 additions & 3 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,17 @@ pub fn apply_filter(
let stage_map: HashMap<String, &Stage> =
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,
};
Expand All @@ -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<String> = target_stage
.steps
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down
Loading