waypoint_core/commands/
safety.rs1use serde::Serialize;
4use tokio_postgres::Client;
5
6use crate::config::WaypointConfig;
7use crate::error::Result;
8use crate::safety;
9
10#[derive(Debug, Clone, Serialize)]
12pub struct SafetyCommandReport {
13 pub reports: Vec<safety::SafetyReport>,
15 pub overall_verdict: safety::SafetyVerdict,
17}
18
19pub async fn execute_file(
21 client: &Client,
22 config: &WaypointConfig,
23 file_path: &str,
24) -> Result<safety::SafetyReport> {
25 let sql = std::fs::read_to_string(file_path)?;
26 let script = std::path::Path::new(file_path)
27 .file_name()
28 .map(|f| f.to_string_lossy().to_string())
29 .unwrap_or_else(|| file_path.to_string());
30
31 safety::analyze_migration(
32 client,
33 &config.migrations.schema,
34 &sql,
35 &script,
36 &config.safety,
37 )
38 .await
39}
40
41pub async fn execute(client: &Client, config: &WaypointConfig) -> Result<SafetyCommandReport> {
43 use crate::history;
44 use crate::migration::scan_migrations;
45
46 let schema = &config.migrations.schema;
47 let table = &config.migrations.table;
48
49 history::create_history_table(client, schema, table).await?;
50 let resolved = scan_migrations(&config.migrations.locations)?;
51 let applied = history::get_applied_migrations(client, schema, table).await?;
52 let effective = history::effective_applied_versions(&applied);
53
54 let mut reports = Vec::new();
55 let mut overall = safety::SafetyVerdict::Safe;
56
57 for migration in &resolved {
58 if migration.is_undo() {
59 continue;
60 }
61 if let Some(version) = migration.version() {
62 if effective.contains(&version.raw) {
63 continue; }
65 }
66
67 let report = safety::analyze_migration(
68 client,
69 schema,
70 &migration.sql,
71 &migration.script,
72 &config.safety,
73 )
74 .await?;
75
76 if report.overall_verdict > overall {
77 overall = report.overall_verdict;
78 }
79 reports.push(report);
80 }
81
82 Ok(SafetyCommandReport {
83 reports,
84 overall_verdict: overall,
85 })
86}