Skip to main content
Glama
approval.rs5.16 kB
//! This module contains the ability to approve change sets with a corresponding checksum. #![warn( bad_style, clippy::missing_panics_doc, clippy::panic, clippy::panic_in_result_fn, clippy::unwrap_in_result, clippy::unwrap_used, dead_code, improper_ctypes, missing_debug_implementations, missing_docs, no_mangle_generic_items, non_shorthand_field_patterns, overflowing_literals, path_statements, patterns_in_fns_without_body, unconditional_recursion, unreachable_pub, unused, unused_allocation, unused_comparisons, unused_parens, while_true )] use chrono::{ DateTime, Utc, }; use serde::{ Deserialize, Serialize, }; use si_data_pg::{ PgError, PgRow, }; use si_db::HistoryActor; pub use si_events::ChangeSetApprovalStatus; use si_events::merkle_tree_hash::MerkleTreeHash; use si_id::{ ChangeSetApprovalId, ChangeSetId, EntityId, UserPk, }; use telemetry::prelude::*; use thiserror::Error; use super::{ ChangeSetError, calculate_checksum, }; use crate::{ DalContext, TransactionsError, WorkspaceSnapshotError, }; #[allow(missing_docs)] #[derive(Debug, Error)] pub enum ChangeSetApprovalError { #[error("change set error")] ChangeSet(#[from] ChangeSetError), #[error("invalid user for a new change set approval")] InvalidUserForNewApproval, #[error("pg error: {0}")] Pg(#[from] PgError), #[error("strum parse error: {0}")] StrumParse(#[from] strum::ParseError), #[error("transactions error: {0}")] Transactions(#[from] TransactionsError), #[error("workspace snapshot error: {0}")] WorkspaceSnapshot(#[from] WorkspaceSnapshotError), } type Result<T> = std::result::Result<T, ChangeSetApprovalError>; /// An individual approval for applying a [`ChangeSet`](crate::ChangeSet). The checksum reflects /// all entities that the approver can be responsible for. #[derive(Debug, Serialize, Deserialize)] pub struct ChangeSetApproval { id: ChangeSetApprovalId, created_at: DateTime<Utc>, change_set_id: ChangeSetId, status: ChangeSetApprovalStatus, user_id: UserPk, checksum: String, } impl TryFrom<PgRow> for ChangeSetApproval { type Error = ChangeSetApprovalError; fn try_from(value: PgRow) -> std::result::Result<Self, Self::Error> { let status_string: String = value.try_get("status")?; let status = ChangeSetApprovalStatus::try_from(status_string.as_str())?; Ok(Self { id: value.try_get("id")?, created_at: value.try_get("created_at")?, change_set_id: value.try_get("change_set_id")?, status, user_id: value.try_get("user_id")?, checksum: value.try_get("checksum")?, }) } } impl ChangeSetApproval { /// Creates a new approval. #[instrument(name = "change_set.approval.new", level = "info", skip_all)] pub async fn new( ctx: &DalContext, status: ChangeSetApprovalStatus, ids_with_hashes: Vec<(EntityId, MerkleTreeHash)>, ) -> Result<Self> { let checksum = calculate_checksum(ctx, ids_with_hashes).await?; let change_set_id = ctx.change_set_id(); let user_id = match ctx.history_actor() { HistoryActor::User(user_id) => user_id, HistoryActor::SystemInit => { return Err(ChangeSetApprovalError::InvalidUserForNewApproval); } }; let row = ctx .txns() .await? .pg() .query_one( "INSERT INTO change_set_approvals (change_set_id, status, user_id, checksum) VALUES ($1, $2, $3, $4) RETURNING *", &[&change_set_id, &status.to_string(), &user_id, &checksum.to_string()] ) .await?; Self::try_from(row) } /// Returns the ID of the approval. pub fn id(&self) -> ChangeSetApprovalId { self.id } /// Returns the status of the approval. pub fn status(&self) -> ChangeSetApprovalStatus { self.status } /// Returns the ID of the approver. pub fn user_id(&self) -> UserPk { self.user_id } /// Returns the checksum based on the changes compared to HEAD when the approval was performed. pub fn checksum(&self) -> &str { self.checksum.as_str() } /// Lists all latest approvals in the [`ChangeSet`](crate::ChangeSet) for each checksum and user. #[instrument(name = "change_set.approval.list_latest", level = "info", skip_all)] pub async fn list_latest(ctx: &DalContext) -> Result<Vec<Self>> { let change_set_id = ctx.change_set_id(); let rows = ctx .txns() .await? .pg() .query( "SELECT * from latest_change_set_approvals WHERE change_set_id = $1 ORDER BY created_at DESC", &[&change_set_id], ) .await?; let mut approvals = Vec::with_capacity(rows.len()); for row in rows { approvals.push(Self::try_from(row)?); } Ok(approvals) } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server