Skip to main content
Glama
approve.rs4.88 kB
use axum::{ Json, extract::{ Host, OriginalUri, Path, State, }, }; use dal::{ ChangeSet, ChangeSetId, WorkspacePk, WsEvent, change_set::approval::ChangeSetApproval, workspace_snapshot::DependentValueRoot, }; use sdf_core::dal_wrapper; use serde::Deserialize; use si_events::{ ChangeSetApprovalStatus, audit_log::AuditLogKind, }; use super::{ ChangeSetAPIError, Error, Result, post_to_webhook, }; use crate::{ AppState, extract::{ HandlerContext, PosthogClient, }, service::v2::AccessBuilder, track, }; #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Request { pub status: ChangeSetApprovalStatus, } #[allow(clippy::too_many_arguments)] pub async fn approve( HandlerContext(builder): HandlerContext, AccessBuilder(access_builder): AccessBuilder, PosthogClient(posthog_client): PosthogClient, OriginalUri(original_uri): OriginalUri, Host(host_name): Host, Path((workspace_pk, change_set_id)): Path<(WorkspacePk, ChangeSetId)>, State(mut state): State<AppState>, Json(request): Json<Request>, ) -> Result<()> { let ctx = builder .build(access_builder.build(change_set_id.into())) .await?; // Ensure that DVU roots are empty before continuing? // todo(brit): maybe we can get away without this. Ex: Approve a PR before tests finish if DependentValueRoot::roots_exist(&ctx).await? { // TODO(nick): we should consider requiring this check in integration tests too. Why did I // not do this at the time of writing? Tests have multiple ways to call "apply", whether // its via helpers or through the change set methods directly. In addition, they test // for success and failure, not solely for success. We should still do this, but not within // the PR corresponding to when this message was written. return Err(Error::DvuRootsNotEmpty(ctx.change_set_id())); } // Cache the old status. let change_set = ChangeSet::get_by_id(&ctx, ctx.visibility().change_set_id).await?; let old_status = change_set.status; // This is the core of the route! let spicedb_client = state .spicedb_client() .ok_or(ChangeSetAPIError::SpiceDBClientNotFound)?; let approving_ids_with_hashes = dal_wrapper::change_set::new_approval_approving_ids_with_hashes(&ctx, spicedb_client) .await?; ChangeSetApproval::new(&ctx, request.status, approving_ids_with_hashes).await?; WsEvent::change_set_approval_status_changed(&ctx, ctx.change_set_id()) .await? .publish_on_commit(&ctx) .await?; // Tracking, audit logging, etc. { match request.status { // NOTE(nick): this matches what was in the original approve route. ChangeSetApprovalStatus::Approved => { track( &posthog_client, &ctx, &original_uri, &host_name, "approve_change_set_apply", serde_json::json!({ "merged_change_set": change_set.id, }), ); ctx.write_audit_log( AuditLogKind::ApproveChangeSetApply { from_status: old_status.into(), }, change_set.name, ) .await?; } ChangeSetApprovalStatus::Rejected => { // NOTE(nick): this matches what was in the original reject route. track( &posthog_client, &ctx, &original_uri, &host_name, "reject_change_set_apply", serde_json::json!({ "change_set": change_set.id, }), ); ctx.write_audit_log( AuditLogKind::RejectChangeSetApply { from_status: old_status.into(), }, change_set.name, ) .await?; } } } let change_set_view = ChangeSet::get_by_id(&ctx, ctx.visibility().change_set_id) .await? .into_frontend_type(&ctx) .await?; let actor = ctx.history_actor().email(&ctx).await?; let change_set_url = format!("https://{host_name}/w/{workspace_pk}/{change_set_id}"); let message = format!( "{} {} merge of change set {}: {}", actor, request.status, change_set_view.name.clone(), change_set_url ); post_to_webhook(&ctx, workspace_pk, message.as_str()).await?; ctx.commit().await?; Ok(()) }

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