Skip to content

Commit 25ff7a3

Browse files
committed
feat(workflow): implement read-only inspection commands (plan, graph, explain)
* Extracts WorkflowPlan structurally from Pipeline building. * Implements 'sailr workflow plan <profile>' with effects tracking. * Implements 'sailr workflow graph <profile> [--format mermaid]'. * Implements 'sailr workflow explain <profile> <task>'.
1 parent b8f49ae commit 25ff7a3

7 files changed

Lines changed: 720 additions & 26 deletions

File tree

src/cli.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,63 @@ pub enum WorkflowCommands {
7474
Run(WorkflowRunArgs),
7575
/// Generate a CI template for a workflow profile
7676
GenerateCi(WorkflowGenerateCiArgs),
77+
/// Plan a workflow profile
78+
Plan(WorkflowPlanArgs),
79+
/// View workflow graph
80+
Graph(WorkflowGraphArgs),
81+
/// Explain a workflow task
82+
Explain(WorkflowExplainArgs),
83+
}
84+
85+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)]
86+
pub enum WorkflowOutputFormat {
87+
Text,
88+
Json,
89+
}
90+
91+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)]
92+
pub enum WorkflowGraphFormat {
93+
Text,
94+
Mermaid,
95+
}
96+
97+
#[derive(Debug, Args)]
98+
pub struct WorkflowPlanArgs {
99+
/// Name of the workflow profile to plan
100+
pub profile: String,
101+
102+
#[arg(long, default_value = "text", value_enum)]
103+
pub format: WorkflowOutputFormat,
104+
105+
#[arg(long)]
106+
pub only: Option<String>,
107+
108+
#[arg(long)]
109+
pub ignore: Option<String>,
110+
}
111+
112+
#[derive(Debug, Args)]
113+
pub struct WorkflowGraphArgs {
114+
/// Name of the workflow profile to graph
115+
pub profile: String,
116+
117+
#[arg(long, default_value = "text", value_enum)]
118+
pub format: WorkflowGraphFormat,
119+
120+
#[arg(long)]
121+
pub only: Option<String>,
122+
123+
#[arg(long)]
124+
pub ignore: Option<String>,
125+
}
126+
127+
#[derive(Debug, Args)]
128+
pub struct WorkflowExplainArgs {
129+
/// Name of the workflow profile
130+
pub profile: String,
131+
132+
/// ID of the task to explain
133+
pub task: String,
77134
}
78135

79136
#[derive(Debug, Args)]

src/main.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,27 @@ async fn handle_workflow(cmd: WorkflowCommands) -> Result<(), CliError> {
803803
return Ok(());
804804
}
805805

806+
if let WorkflowCommands::Plan(args) = cmd {
807+
sailr::workflow::runner::WorkflowRunner::plan(args)
808+
.await
809+
.map_err(CliError::Other)?;
810+
return Ok(());
811+
}
812+
813+
if let WorkflowCommands::Graph(args) = cmd {
814+
sailr::workflow::runner::WorkflowRunner::graph(args)
815+
.await
816+
.map_err(CliError::Other)?;
817+
return Ok(());
818+
}
819+
820+
if let WorkflowCommands::Explain(args) = cmd {
821+
sailr::workflow::runner::WorkflowRunner::explain(args)
822+
.await
823+
.map_err(CliError::Other)?;
824+
return Ok(());
825+
}
826+
806827
let config = WorkflowConfig::load()?;
807828

808829
match cmd {
@@ -853,7 +874,10 @@ async fn handle_workflow(cmd: WorkflowCommands) -> Result<(), CliError> {
853874
path.display()
854875
));
855876
}
856-
WorkflowCommands::Run(_) => unreachable!(),
877+
WorkflowCommands::Run(_)
878+
| WorkflowCommands::Plan(_)
879+
| WorkflowCommands::Graph(_)
880+
| WorkflowCommands::Explain(_) => unreachable!(),
857881
}
858882

859883
Ok(())

src/workflow/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ pub mod builder_context;
22
pub mod ci;
33
pub mod config;
44
pub mod error;
5+
pub mod plan;
56
pub mod planner;
67
pub mod profile;
8+
pub mod render;
79
pub mod runner;

src/workflow/plan.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use crate::builder::SailrBuildPlan;
2+
use crate::workflow::profile::NormalizedWorkflowProfile;
3+
use crate::workflow::runner::RunnerContext;
4+
5+
#[derive(Debug, Clone)]
6+
pub struct WorkflowPlan {
7+
pub profile: NormalizedWorkflowProfile,
8+
pub runner: RunnerContext,
9+
pub tasks: Vec<WorkflowTaskPlan>,
10+
pub edges: Vec<WorkflowEdge>,
11+
pub build_plan: Option<SailrBuildPlan>,
12+
pub effects: WorkflowEffects,
13+
}
14+
15+
#[derive(Debug, Clone)]
16+
pub struct WorkflowTaskPlan {
17+
pub id: String,
18+
pub label: String,
19+
pub kind: WorkflowTaskKind,
20+
pub dependencies: Vec<String>,
21+
pub effects: WorkflowEffects,
22+
pub description: String,
23+
}
24+
25+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26+
pub enum WorkflowTaskKind {
27+
ValidateConfig,
28+
BuildPlan,
29+
ServiceBuild,
30+
Generate,
31+
Deploy,
32+
Verify,
33+
Approval,
34+
}
35+
36+
#[derive(Debug, Clone)]
37+
pub struct WorkflowEdge {
38+
pub from: String,
39+
pub to: String,
40+
}
41+
42+
#[derive(Debug, Clone, Default)]
43+
pub struct WorkflowEffects {
44+
pub mutates_filesystem: bool,
45+
pub mutates_docker: bool,
46+
pub mutates_registry: bool,
47+
pub mutates_cluster: bool,
48+
pub prompts_user: bool,
49+
}

0 commit comments

Comments
 (0)