@@ -14,7 +14,11 @@ pub struct WorkflowPlanner {
1414}
1515
1616impl WorkflowPlanner {
17- pub fn new ( profile : NormalizedWorkflowProfile , env : Arc < Environment > , options : BuildOptions ) -> Self {
17+ pub fn new (
18+ profile : NormalizedWorkflowProfile ,
19+ env : Arc < Environment > ,
20+ options : BuildOptions ,
21+ ) -> Self {
1822 Self {
1923 profile,
2024 env,
@@ -27,32 +31,40 @@ impl WorkflowPlanner {
2731 let mut build_plan = None ;
2832
2933 // 0. Validate Phase
30- if self . profile . deploy . is_active ( ) {
31- if self . profile . deploy_context . is_none ( ) {
32- return Err ( "Validation Error: deploy_context is required when deploy is active" . to_string ( ) ) ;
33- }
34- return Err ( "workflow deploy execution is not enabled in this PR; use sailr deploy or sailr go" . to_string ( ) ) ;
35- }
3634
37- let validate_task = Task :: new ( "workflow:validate-config" )
38- . exec_fn ( move |_ctx| async move {
39- crate :: LOGGER . info ( "Validating Sailr environment config..." ) ;
40- Ok ( ( ) )
41- } ) ;
35+ let validate_task = Task :: new ( "workflow:validate-config" ) . exec_fn ( move |_ctx| async move {
36+ crate :: LOGGER . info ( "Validating Sailr environment config..." ) ;
37+ Ok ( ( ) )
38+ } ) ;
4239 pipeline. add ( validate_task) ;
4340 let mut last_tasks: Vec < String > = vec ! [ "workflow:validate-config" . to_string( ) ] ;
4441
4542 // 1. Build Phase
4643 if self . profile . build . is_active ( ) {
4744 let plan = create_sailr_build_plan ( & self . env , & self . options ) ?;
48-
45+
4946 // Only add runkernel tasks if we actually want to run the build.
50- // If build == Plan, create_sailr_build_plan already printed the plan (via builder.rs integration),
51- // but we don't want to execute it. Wait, create_sailr_build_plan does not print the plan.
52- // In RunkernelBuildBackend::build, it prints it.
47+ // If build == Plan, create_sailr_build_plan already printed the plan (via builder.rs integration),
48+ // but we don't want to execute it. Wait, create_sailr_build_plan does not print the plan.
49+ // In RunkernelBuildBackend::build, it prints it.
5350 // But we can just avoid adding tasks to the pipeline if it's just plan.
5451 if self . profile . build == crate :: workflow:: profile:: WorkflowStepMode :: Plan {
55- crate :: builder:: print_sailr_plan ( & plan, & self . options ) ;
52+ let plan_for_task = plan. clone ( ) ;
53+ let options_for_task = self . options . clone ( ) ;
54+
55+ let task = Task :: new ( "workflow:build-plan" )
56+ . depends_on ( & [ "workflow:validate-config" ] )
57+ . exec_fn ( move |_ctx| {
58+ let p = plan_for_task. clone ( ) ;
59+ let o = options_for_task. clone ( ) ;
60+ async move {
61+ crate :: builder:: print_sailr_plan ( & p, & o) ;
62+ Ok ( ( ) )
63+ }
64+ } ) ;
65+
66+ pipeline. add ( task) ;
67+ last_tasks = vec ! [ "workflow:build-plan" . to_string( ) ] ;
5668 build_plan = Some ( plan) ;
5769 } else {
5870 add_runkernel_tasks ( & mut pipeline, & plan) ?;
@@ -66,7 +78,7 @@ impl WorkflowPlanner {
6678 build_deps. push ( s. service . name . clone ( ) ) ;
6779 }
6880 }
69-
81+
7082 last_tasks. extend ( build_deps) ;
7183 build_plan = Some ( plan) ;
7284 }
@@ -114,3 +126,93 @@ impl WorkflowPlanner {
114126 Ok ( ( pipeline, build_plan) )
115127 }
116128}
129+
130+ #[ cfg( test) ]
131+ mod tests {
132+ use super :: * ;
133+ use crate :: workflow:: profile:: {
134+ ApprovalMode , ReportMode , WorkflowEngine , WorkflowMode , WorkflowStepMode ,
135+ } ;
136+
137+ fn dummy_profile (
138+ deploy_mode : WorkflowStepMode ,
139+ build_mode : WorkflowStepMode ,
140+ ) -> NormalizedWorkflowProfile {
141+ NormalizedWorkflowProfile {
142+ name : "test" . to_string ( ) ,
143+ environment : "local" . to_string ( ) ,
144+ mode : WorkflowMode :: Check ,
145+ engine : WorkflowEngine :: Runkernel ,
146+ interactive : false ,
147+ build : build_mode,
148+ generate : WorkflowStepMode :: Run ,
149+ deploy : deploy_mode,
150+ test : WorkflowStepMode :: Disabled ,
151+ verify : WorkflowStepMode :: Disabled ,
152+ deploy_context : Some ( "local" . to_string ( ) ) ,
153+ namespace : Some ( "default" . to_string ( ) ) ,
154+ approval : ApprovalMode :: None ,
155+ apply : false ,
156+ report : ReportMode :: Text ,
157+ }
158+ }
159+
160+ fn dummy_options ( plan : bool ) -> BuildOptions {
161+ BuildOptions {
162+ cache_dir : ".sailr" . to_string ( ) ,
163+ force : false ,
164+ only : vec ! [ ] ,
165+ ignore : vec ! [ ] ,
166+ plan,
167+ dry_run : false ,
168+ explain : false ,
169+ dump_scope : false ,
170+ policy : Default :: default ( ) ,
171+ }
172+ }
173+
174+ #[ test]
175+ fn check_profile_never_creates_deploy ( ) {
176+ let env = Environment :: load_from_file ( "local" ) . unwrap ( ) ;
177+ let profile = dummy_profile ( WorkflowStepMode :: Disabled , WorkflowStepMode :: Plan ) ;
178+ let planner = WorkflowPlanner :: new ( profile, Arc :: new ( env) , dummy_options ( true ) ) ;
179+ let ( pipeline, _) = planner. build_pipeline ( ) . unwrap ( ) ;
180+ assert ! ( !pipeline. tasks( ) . any( |t| t. name. starts_with( "deploy:" ) ) ) ;
181+ }
182+
183+ #[ test]
184+ fn check_profile_creates_validate_config ( ) {
185+ let env = Environment :: load_from_file ( "local" ) . unwrap ( ) ;
186+ let profile = dummy_profile ( WorkflowStepMode :: Disabled , WorkflowStepMode :: Plan ) ;
187+ let planner = WorkflowPlanner :: new ( profile, Arc :: new ( env) , dummy_options ( true ) ) ;
188+ let ( pipeline, _) = planner. build_pipeline ( ) . unwrap ( ) ;
189+ assert ! ( pipeline. tasks( ) . any( |t| t. name == "workflow:validate-config" ) ) ;
190+ }
191+
192+ #[ test]
193+ fn check_profile_creates_build_plan_when_build_plan ( ) {
194+ let env = Environment :: load_from_file ( "local" ) . unwrap ( ) ;
195+ let profile = dummy_profile ( WorkflowStepMode :: Disabled , WorkflowStepMode :: Plan ) ;
196+ let planner = WorkflowPlanner :: new ( profile, Arc :: new ( env) , dummy_options ( true ) ) ;
197+ let ( pipeline, _) = planner. build_pipeline ( ) . unwrap ( ) ;
198+ assert ! ( pipeline. tasks( ) . any( |t| t. name == "workflow:build-plan" ) ) ;
199+ }
200+
201+ #[ test]
202+ fn build_disabled_creates_no_build_plan ( ) {
203+ let env = Environment :: load_from_file ( "local" ) . unwrap ( ) ;
204+ let profile = dummy_profile ( WorkflowStepMode :: Disabled , WorkflowStepMode :: Disabled ) ;
205+ let planner = WorkflowPlanner :: new ( profile, Arc :: new ( env) , dummy_options ( false ) ) ;
206+ let ( pipeline, _) = planner. build_pipeline ( ) . unwrap ( ) ;
207+ assert ! ( !pipeline. tasks( ) . any( |t| t. name == "workflow:build-plan" ) ) ;
208+ }
209+
210+ #[ test]
211+ fn generate_task_is_created_when_generate_run ( ) {
212+ let env = Environment :: load_from_file ( "local" ) . unwrap ( ) ;
213+ let profile = dummy_profile ( WorkflowStepMode :: Disabled , WorkflowStepMode :: Plan ) ;
214+ let planner = WorkflowPlanner :: new ( profile, Arc :: new ( env) , dummy_options ( true ) ) ;
215+ let ( pipeline, _) = planner. build_pipeline ( ) . unwrap ( ) ;
216+ assert ! ( pipeline. tasks( ) . any( |t| t. name == "workflow:generate" ) ) ;
217+ }
218+ }
0 commit comments