@@ -4,7 +4,7 @@ use anyhow::{Context, Result};
44use std:: collections:: { HashMap , HashSet } ;
55use std:: path:: Path ;
66
7- use super :: types:: { FrontMatter , PipelineParameter , Repository , TriggerConfig } ;
7+ use super :: types:: { FrontMatter , OnConfig , PipelineParameter , Repository } ;
88use super :: extensions:: { CompilerExtension , Extension , McpgServerConfig , McpgGatewayConfig , McpgConfig , CompileContext } ;
99use crate :: compile:: types:: McpConfig ;
1010use crate :: fuzzy_schedule;
@@ -146,14 +146,14 @@ pub fn validate_front_matter_identity(front_matter: &FrontMatter) -> Result<()>
146146 }
147147
148148 // Validate trigger.pipeline fields for newlines and ADO expressions
149- if let Some ( trigger_config) = & front_matter. triggers {
149+ if let Some ( trigger_config) = & front_matter. on_config {
150150 if let Some ( pipeline) = & trigger_config. pipeline {
151- validate:: reject_pipeline_injection ( & pipeline. name , "triggers .pipeline.name" ) ?;
151+ validate:: reject_pipeline_injection ( & pipeline. name , "on .pipeline.name" ) ?;
152152 if let Some ( project) = & pipeline. project {
153- validate:: reject_pipeline_injection ( project, "triggers .pipeline.project" ) ?;
153+ validate:: reject_pipeline_injection ( project, "on .pipeline.project" ) ?;
154154 }
155155 for branch in & pipeline. branches {
156- validate:: reject_pipeline_injection ( branch, & format ! ( "triggers .pipeline.branches entry {:?}" , branch) ) ?;
156+ validate:: reject_pipeline_injection ( branch, & format ! ( "on .pipeline.branches entry {:?}" , branch) ) ?;
157157 }
158158 }
159159 }
@@ -202,20 +202,20 @@ pub fn generate_schedule(name: &str, config: &super::types::ScheduleConfig) -> R
202202/// When `triggers.pr` is explicitly configured, PR triggers stay enabled regardless
203203/// of schedule or pipeline triggers (overrides suppression). Native ADO branch/path
204204/// filters are emitted if configured.
205- pub fn generate_pr_trigger ( triggers : & Option < TriggerConfig > , has_schedule : bool ) -> String {
206- let has_pipeline_trigger = triggers
205+ pub fn generate_pr_trigger ( on_config : & Option < OnConfig > , has_schedule : bool ) -> String {
206+ let has_pipeline_trigger = on_config
207207 . as_ref ( )
208208 . and_then ( |t| t. pipeline . as_ref ( ) )
209209 . is_some ( ) ;
210210
211- let has_pr_trigger = triggers
211+ let has_pr_trigger = on_config
212212 . as_ref ( )
213213 . and_then ( |t| t. pr . as_ref ( ) )
214214 . is_some ( ) ;
215215
216216 // Explicit triggers.pr overrides schedule/pipeline suppression
217217 if has_pr_trigger {
218- return super :: pr_filters:: generate_native_pr_trigger ( triggers . as_ref ( ) . unwrap ( ) . pr . as_ref ( ) . unwrap ( ) ) ;
218+ return super :: pr_filters:: generate_native_pr_trigger ( on_config . as_ref ( ) . unwrap ( ) . pr . as_ref ( ) . unwrap ( ) ) ;
219219 }
220220
221221 match ( has_pipeline_trigger, has_schedule) {
@@ -227,8 +227,8 @@ pub fn generate_pr_trigger(triggers: &Option<TriggerConfig>, has_schedule: bool)
227227}
228228
229229/// Generate CI trigger configuration
230- pub fn generate_ci_trigger ( triggers : & Option < TriggerConfig > , has_schedule : bool ) -> String {
231- let has_pipeline_trigger = triggers
230+ pub fn generate_ci_trigger ( on_config : & Option < OnConfig > , has_schedule : bool ) -> String {
231+ let has_pipeline_trigger = on_config
232232 . as_ref ( )
233233 . and_then ( |t| t. pipeline . as_ref ( ) )
234234 . is_some ( ) ;
@@ -241,8 +241,8 @@ pub fn generate_ci_trigger(triggers: &Option<TriggerConfig>, has_schedule: bool)
241241}
242242
243243/// Generate pipeline resource YAML for pipeline completion triggers
244- pub fn generate_pipeline_resources ( triggers : & Option < TriggerConfig > ) -> Result < String > {
245- let Some ( trigger_config) = triggers else {
244+ pub fn generate_pipeline_resources ( on_config : & Option < OnConfig > ) -> Result < String > {
245+ let Some ( trigger_config) = on_config else {
246246 return Ok ( String :: new ( ) ) ;
247247 } ;
248248
@@ -1798,7 +1798,7 @@ pub async fn compile_shared(
17981798 validate_front_matter_identity ( front_matter) ?;
17991799
18001800 // 2. Generate schedule
1801- let schedule = match & front_matter. schedule {
1801+ let schedule = match front_matter. schedule ( ) {
18021802 Some ( s) => generate_schedule ( & front_matter. name , s)
18031803 . with_context ( || format ! ( "Failed to parse schedule '{}'" , s. expression( ) ) ) ?,
18041804 None => String :: new ( ) ,
@@ -1839,10 +1839,10 @@ pub async fn compile_shared(
18391839 ) ?;
18401840 let working_directory = generate_working_directory ( & effective_workspace) ;
18411841 let trigger_repo_directory = generate_trigger_repo_directory ( & front_matter. checkout ) ;
1842- let pipeline_resources = generate_pipeline_resources ( & front_matter. triggers ) ?;
1843- let has_schedule = front_matter. schedule . is_some ( ) ;
1844- let pr_trigger = generate_pr_trigger ( & front_matter. triggers , has_schedule) ;
1845- let ci_trigger = generate_ci_trigger ( & front_matter. triggers , has_schedule) ;
1842+ let pipeline_resources = generate_pipeline_resources ( & front_matter. on_config ) ?;
1843+ let has_schedule = front_matter. has_schedule ( ) ;
1844+ let pr_trigger = generate_pr_trigger ( & front_matter. on_config , has_schedule) ;
1845+ let ci_trigger = generate_ci_trigger ( & front_matter. on_config , has_schedule) ;
18461846
18471847 // 6. Generate source path and pipeline path
18481848 let source_path = generate_source_path ( input_path) ;
@@ -1856,11 +1856,7 @@ pub async fn compile_shared(
18561856 . unwrap_or_else ( || DEFAULT_POOL . to_string ( ) ) ;
18571857
18581858 // 8. Setup/teardown jobs, parameters, prepare/finalize steps
1859- let pr_filters = front_matter
1860- . triggers
1861- . as_ref ( )
1862- . and_then ( |t| t. pr . as_ref ( ) )
1863- . and_then ( |pr| pr. filters . as_ref ( ) ) ;
1859+ let pr_filters = front_matter. pr_filters ( ) ;
18641860 let has_pr_filters = pr_filters. is_some ( ) ;
18651861 let setup_job = generate_setup_job ( & front_matter. setup , & pool, pr_filters) ;
18661862 let teardown_job = generate_teardown_job ( & front_matter. teardown , & pool) ;
@@ -2522,13 +2518,15 @@ mod tests {
25222518
25232519 #[ test]
25242520 fn test_generate_pr_trigger_pipeline_only ( ) {
2525- let triggers = Some ( crate :: compile:: types:: TriggerConfig {
2521+ let triggers = Some ( crate :: compile:: types:: OnConfig {
25262522 pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
25272523 name : "Build" . into ( ) ,
25282524 project : None ,
25292525 branches : vec ! [ ] ,
2526+ filters : None ,
25302527 } ) ,
25312528 pr : None ,
2529+ schedule : None ,
25322530 } ) ;
25332531 let result = generate_pr_trigger ( & triggers, false ) ;
25342532 assert ! ( result. contains( "pr: none" ) ) ;
@@ -2537,13 +2535,15 @@ mod tests {
25372535
25382536 #[ test]
25392537 fn test_generate_pr_trigger_both_pipeline_and_schedule ( ) {
2540- let triggers = Some ( crate :: compile:: types:: TriggerConfig {
2538+ let triggers = Some ( crate :: compile:: types:: OnConfig {
25412539 pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
25422540 name : "Build" . into ( ) ,
25432541 project : None ,
25442542 branches : vec ! [ ] ,
2543+ filters : None ,
25452544 } ) ,
25462545 pr : None ,
2546+ schedule : None ,
25472547 } ) ;
25482548 let result = generate_pr_trigger ( & triggers, true ) ;
25492549 assert ! ( result. contains( "pr: none" ) ) ;
@@ -2570,27 +2570,31 @@ mod tests {
25702570
25712571 #[ test]
25722572 fn test_generate_ci_trigger_pipeline_only ( ) {
2573- let triggers = Some ( crate :: compile:: types:: TriggerConfig {
2573+ let triggers = Some ( crate :: compile:: types:: OnConfig {
25742574 pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
25752575 name : "Build" . into ( ) ,
25762576 project : None ,
25772577 branches : vec ! [ ] ,
2578+ filters : None ,
25782579 } ) ,
25792580 pr : None ,
2581+ schedule : None ,
25802582 } ) ;
25812583 let result = generate_ci_trigger ( & triggers, false ) ;
25822584 assert_eq ! ( result, "trigger: none" ) ;
25832585 }
25842586
25852587 #[ test]
25862588 fn test_generate_ci_trigger_both_pipeline_and_schedule ( ) {
2587- let triggers = Some ( crate :: compile:: types:: TriggerConfig {
2589+ let triggers = Some ( crate :: compile:: types:: OnConfig {
25882590 pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
25892591 name : "Build" . into ( ) ,
25902592 project : None ,
25912593 branches : vec ! [ ] ,
2594+ filters : None ,
25922595 } ) ,
25932596 pr : None ,
2597+ schedule : None ,
25942598 } ) ;
25952599 let result = generate_ci_trigger ( & triggers, true ) ;
25962600 assert_eq ! ( result, "trigger: none" ) ;
@@ -2606,20 +2610,22 @@ mod tests {
26062610
26072611 #[ test]
26082612 fn test_generate_pipeline_resources_empty_trigger_config ( ) {
2609- let triggers = Some ( crate :: compile:: types:: TriggerConfig { pipeline : None , pr : None } ) ;
2613+ let triggers = Some ( crate :: compile:: types:: OnConfig { schedule : None , pipeline : None , pr : None } ) ;
26102614 let result = generate_pipeline_resources ( & triggers) . unwrap ( ) ;
26112615 assert ! ( result. is_empty( ) ) ;
26122616 }
26132617
26142618 #[ test]
26152619 fn test_generate_pipeline_resources_with_branches ( ) {
2616- let triggers = Some ( crate :: compile:: types:: TriggerConfig {
2620+ let triggers = Some ( crate :: compile:: types:: OnConfig {
26172621 pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
26182622 name : "Build Pipeline" . into ( ) ,
26192623 project : Some ( "OtherProject" . into ( ) ) ,
26202624 branches : vec ! [ "main" . into( ) , "release/*" . into( ) ] ,
2625+ filters : None ,
26212626 } ) ,
26222627 pr : None ,
2628+ schedule : None ,
26232629 } ) ;
26242630 let result = generate_pipeline_resources ( & triggers) . unwrap ( ) ;
26252631 assert ! ( result. contains( "source: 'Build Pipeline'" ) ) ;
@@ -2633,13 +2639,15 @@ mod tests {
26332639
26342640 #[ test]
26352641 fn test_generate_pipeline_resources_without_branches_triggers_on_any ( ) {
2636- let triggers = Some ( crate :: compile:: types:: TriggerConfig {
2642+ let triggers = Some ( crate :: compile:: types:: OnConfig {
26372643 pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
26382644 name : "My Pipeline" . into ( ) ,
26392645 project : None ,
26402646 branches : vec ! [ ] ,
2647+ filters : None ,
26412648 } ) ,
26422649 pr : None ,
2650+ schedule : None ,
26432651 } ) ;
26442652 let result = generate_pipeline_resources ( & triggers) . unwrap ( ) ;
26452653 assert ! ( result. contains( "source: 'My Pipeline'" ) ) ;
@@ -2650,13 +2658,15 @@ mod tests {
26502658
26512659 #[ test]
26522660 fn test_generate_pipeline_resources_resource_id_is_snake_case ( ) {
2653- let triggers = Some ( crate :: compile:: types:: TriggerConfig {
2661+ let triggers = Some ( crate :: compile:: types:: OnConfig {
26542662 pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
26552663 name : "My Build Pipeline" . into ( ) ,
26562664 project : None ,
26572665 branches : vec ! [ ] ,
2666+ filters : None ,
26582667 } ) ,
26592668 pr : None ,
2669+ schedule : None ,
26602670 } ) ;
26612671 let result = generate_pipeline_resources ( & triggers) . unwrap ( ) ;
26622672 // The pipeline resource ID should be snake_case derived from the name
@@ -3562,49 +3572,55 @@ mod tests {
35623572 #[ test]
35633573 fn test_validate_front_matter_identity_rejects_newline_in_trigger_pipeline_name ( ) {
35643574 let mut fm = minimal_front_matter ( ) ;
3565- fm. triggers = Some ( TriggerConfig {
3575+ fm. on_config = Some ( OnConfig {
35663576 pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
35673577 name : "Build\n injected: true" . to_string ( ) ,
35683578 project : None ,
35693579 branches : vec ! [ ] ,
3580+ filters : None ,
35703581 } ) ,
35713582 pr : None ,
3583+ schedule : None ,
35723584 } ) ;
35733585 let result = validate_front_matter_identity ( & fm) ;
35743586 assert ! ( result. is_err( ) ) ;
3575- assert ! ( result. unwrap_err( ) . to_string( ) . contains( "triggers .pipeline.name" ) ) ;
3587+ assert ! ( result. unwrap_err( ) . to_string( ) . contains( "on .pipeline.name" ) ) ;
35763588 }
35773589
35783590 #[ test]
35793591 fn test_validate_front_matter_identity_rejects_newline_in_trigger_pipeline_project ( ) {
35803592 let mut fm = minimal_front_matter ( ) ;
3581- fm. triggers = Some ( TriggerConfig {
3593+ fm. on_config = Some ( OnConfig {
35823594 pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
35833595 name : "Build Pipeline" . to_string ( ) ,
35843596 project : Some ( "OtherProject\n injected: true" . to_string ( ) ) ,
35853597 branches : vec ! [ ] ,
3598+ filters : None ,
35863599 } ) ,
35873600 pr : None ,
3601+ schedule : None ,
35883602 } ) ;
35893603 let result = validate_front_matter_identity ( & fm) ;
35903604 assert ! ( result. is_err( ) ) ;
3591- assert ! ( result. unwrap_err( ) . to_string( ) . contains( "triggers .pipeline.project" ) ) ;
3605+ assert ! ( result. unwrap_err( ) . to_string( ) . contains( "on .pipeline.project" ) ) ;
35923606 }
35933607
35943608 #[ test]
35953609 fn test_validate_front_matter_identity_rejects_newline_in_trigger_pipeline_branch ( ) {
35963610 let mut fm = minimal_front_matter ( ) ;
3597- fm. triggers = Some ( TriggerConfig {
3611+ fm. on_config = Some ( OnConfig {
35983612 pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
35993613 name : "Build Pipeline" . to_string ( ) ,
36003614 project : None ,
36013615 branches : vec ! [ "main\n injected: true" . to_string( ) ] ,
3616+ filters : None ,
36023617 } ) ,
36033618 pr : None ,
3619+ schedule : None ,
36043620 } ) ;
36053621 let result = validate_front_matter_identity ( & fm) ;
36063622 assert ! ( result. is_err( ) ) ;
3607- assert ! ( result. unwrap_err( ) . to_string( ) . contains( "triggers .pipeline.branches" ) ) ;
3623+ assert ! ( result. unwrap_err( ) . to_string( ) . contains( "on .pipeline.branches" ) ) ;
36083624 }
36093625
36103626 #[ test]
@@ -3619,13 +3635,15 @@ mod tests {
36193635 #[ test]
36203636 fn test_validate_front_matter_identity_allows_valid_trigger_pipeline_fields ( ) {
36213637 let mut fm = minimal_front_matter ( ) ;
3622- fm. triggers = Some ( TriggerConfig {
3638+ fm. on_config = Some ( OnConfig {
36233639 pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
36243640 name : "Build Pipeline" . to_string ( ) ,
36253641 project : Some ( "OtherProject" . to_string ( ) ) ,
36263642 branches : vec ! [ "main" . to_string( ) , "release/*" . to_string( ) ] ,
3643+ filters : None ,
36273644 } ) ,
36283645 pr : None ,
3646+ schedule : None ,
36293647 } ) ;
36303648 let result = validate_front_matter_identity ( & fm) ;
36313649 assert ! ( result. is_ok( ) ) ;
@@ -3643,13 +3661,15 @@ mod tests {
36433661 #[ test]
36443662 fn test_validate_front_matter_identity_rejects_ado_expression_in_trigger_pipeline_name ( ) {
36453663 let mut fm = minimal_front_matter ( ) ;
3646- fm. triggers = Some ( TriggerConfig {
3664+ fm. on_config = Some ( OnConfig {
36473665 pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
36483666 name : "Build $(System.AccessToken)" . to_string ( ) ,
36493667 project : None ,
36503668 branches : vec ! [ ] ,
3669+ filters : None ,
36513670 } ) ,
36523671 pr : None ,
3672+ schedule : None ,
36533673 } ) ;
36543674 let result = validate_front_matter_identity ( & fm) ;
36553675 assert ! ( result. is_err( ) ) ;
@@ -3659,13 +3679,15 @@ mod tests {
36593679 #[ test]
36603680 fn test_validate_front_matter_identity_rejects_ado_expression_in_trigger_pipeline_project ( ) {
36613681 let mut fm = minimal_front_matter ( ) ;
3662- fm. triggers = Some ( TriggerConfig {
3682+ fm. on_config = Some ( OnConfig {
36633683 pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
36643684 name : "Build Pipeline" . to_string ( ) ,
36653685 project : Some ( "$(System.AccessToken)" . to_string ( ) ) ,
36663686 branches : vec ! [ ] ,
3687+ filters : None ,
36673688 } ) ,
36683689 pr : None ,
3690+ schedule : None ,
36693691 } ) ;
36703692 let result = validate_front_matter_identity ( & fm) ;
36713693 assert ! ( result. is_err( ) ) ;
@@ -3675,13 +3697,15 @@ mod tests {
36753697 #[ test]
36763698 fn test_validate_front_matter_identity_rejects_ado_expression_in_trigger_pipeline_branch ( ) {
36773699 let mut fm = minimal_front_matter ( ) ;
3678- fm. triggers = Some ( TriggerConfig {
3700+ fm. on_config = Some ( OnConfig {
36793701 pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
36803702 name : "Build Pipeline" . to_string ( ) ,
36813703 project : None ,
36823704 branches : vec ! [ "$[variables['token']]" . to_string( ) ] ,
3705+ filters : None ,
36833706 } ) ,
36843707 pr : None ,
3708+ schedule : None ,
36853709 } ) ;
36863710 let result = validate_front_matter_identity ( & fm) ;
36873711 assert ! ( result. is_err( ) ) ;
@@ -3690,13 +3714,15 @@ mod tests {
36903714
36913715 #[ test]
36923716 fn test_pipeline_resources_escapes_single_quotes ( ) {
3693- let triggers = Some ( TriggerConfig {
3717+ let triggers = Some ( OnConfig {
36943718 pipeline : Some ( crate :: compile:: types:: PipelineTrigger {
36953719 name : "Build's Pipeline" . to_string ( ) ,
36963720 project : Some ( "My'Project" . to_string ( ) ) ,
36973721 branches : vec ! [ "main" . to_string( ) , "it's-branch" . to_string( ) ] ,
3722+ filters : None ,
36983723 } ) ,
36993724 pr : None ,
3725+ schedule : None ,
37003726 } ) ;
37013727 let result = generate_pipeline_resources ( & triggers) . unwrap ( ) ;
37023728 assert ! ( result. contains( "source: 'Build''s Pipeline'" ) ) ;
0 commit comments