@@ -3,11 +3,12 @@ use forage_core::auth::{
|
||||
UserProfile,
|
||||
};
|
||||
use forage_core::platform::{
|
||||
Artifact, ArtifactContext, ArtifactDestination, ArtifactRef, ArtifactSource, CreatePolicyInput,
|
||||
CreateReleasePipelineInput, CreateTriggerInput, Destination, DestinationType, Environment,
|
||||
ForestPlatform, NotificationPreference, Organisation, OrgMember, PipelineStage,
|
||||
PipelineStageConfig, PlatformError, Policy, PolicyConfig, ReleasePipeline, Trigger,
|
||||
UpdatePolicyInput, UpdateReleasePipelineInput, UpdateTriggerInput,
|
||||
ApprovalDecisionEntry, ApprovalState, Artifact, ArtifactContext, ArtifactDestination,
|
||||
ArtifactRef, ArtifactSource, CreatePolicyInput, CreateReleasePipelineInput, CreateTriggerInput,
|
||||
Destination, DestinationType, Environment, ForestPlatform, NotificationPreference, Organisation,
|
||||
OrgMember, PipelineStage, PipelineStageConfig, PlatformError, Policy, PolicyConfig,
|
||||
PolicyEvaluation, ReleasePipeline, Trigger, UpdatePolicyInput, UpdateReleasePipelineInput,
|
||||
UpdateTriggerInput,
|
||||
};
|
||||
use forage_grpc::policy_service_client::PolicyServiceClient;
|
||||
use forage_grpc::release_pipeline_service_client::ReleasePipelineServiceClient;
|
||||
@@ -582,6 +583,9 @@ fn convert_pipeline_stage(s: forage_grpc::PipelineStage) -> PipelineStage {
|
||||
Some(forage_grpc::pipeline_stage::Config::Wait(w)) => {
|
||||
PipelineStageConfig::Wait { duration_seconds: w.duration_seconds }
|
||||
}
|
||||
Some(forage_grpc::pipeline_stage::Config::Plan(_)) => {
|
||||
PipelineStageConfig::Deploy { environment: String::new() }
|
||||
}
|
||||
None => PipelineStageConfig::Deploy { environment: String::new() },
|
||||
};
|
||||
PipelineStage {
|
||||
@@ -698,6 +702,7 @@ fn convert_policy(p: forage_grpc::Policy) -> Policy {
|
||||
let policy_type_str = match forage_grpc::PolicyType::try_from(p.policy_type) {
|
||||
Ok(forage_grpc::PolicyType::SoakTime) => "soak_time",
|
||||
Ok(forage_grpc::PolicyType::BranchRestriction) => "branch_restriction",
|
||||
Ok(forage_grpc::PolicyType::ExternalApproval) => "approval",
|
||||
_ => "unknown",
|
||||
};
|
||||
let config = match p.config {
|
||||
@@ -712,6 +717,10 @@ fn convert_policy(p: forage_grpc::Policy) -> Policy {
|
||||
branch_pattern: c.branch_pattern,
|
||||
}
|
||||
}
|
||||
Some(forage_grpc::policy::Config::ExternalApproval(c)) => PolicyConfig::Approval {
|
||||
target_environment: c.target_environment,
|
||||
required_approvals: c.required_approvals,
|
||||
},
|
||||
None => PolicyConfig::SoakTime {
|
||||
source_environment: String::new(),
|
||||
target_environment: String::new(),
|
||||
@@ -761,6 +770,20 @@ fn policy_config_to_grpc(
|
||||
),
|
||||
),
|
||||
),
|
||||
PolicyConfig::Approval {
|
||||
target_environment,
|
||||
required_approvals,
|
||||
} => (
|
||||
forage_grpc::PolicyType::ExternalApproval as i32,
|
||||
Some(
|
||||
forage_grpc::create_policy_request::Config::ExternalApproval(
|
||||
forage_grpc::ExternalApprovalConfig {
|
||||
target_environment: target_environment.clone(),
|
||||
required_approvals: *required_approvals,
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -775,8 +798,9 @@ fn convert_member(m: forage_grpc::OrganisationMember) -> OrgMember {
|
||||
|
||||
fn map_platform_status(status: tonic::Status) -> PlatformError {
|
||||
match status.code() {
|
||||
tonic::Code::Unauthenticated | tonic::Code::PermissionDenied => {
|
||||
PlatformError::NotAuthenticated
|
||||
tonic::Code::Unauthenticated => PlatformError::NotAuthenticated,
|
||||
tonic::Code::PermissionDenied => {
|
||||
PlatformError::Other(status.message().into())
|
||||
}
|
||||
tonic::Code::NotFound => PlatformError::NotFound(status.message().into()),
|
||||
tonic::Code::Unavailable => PlatformError::Unavailable(status.message().into()),
|
||||
@@ -1270,6 +1294,7 @@ impl ForestPlatform for GrpcForestClient {
|
||||
environments: environments.to_vec(),
|
||||
force: false,
|
||||
use_pipeline,
|
||||
prepare_only: false,
|
||||
},
|
||||
)
|
||||
.map_err(|e| PlatformError::Other(e.to_string()))?;
|
||||
@@ -1481,6 +1506,9 @@ impl ForestPlatform for GrpcForestClient {
|
||||
Some(forage_grpc::create_policy_request::Config::BranchRestriction(b)) => {
|
||||
forage_grpc::update_policy_request::Config::BranchRestriction(b)
|
||||
}
|
||||
Some(forage_grpc::create_policy_request::Config::ExternalApproval(a)) => {
|
||||
forage_grpc::update_policy_request::Config::ExternalApproval(a)
|
||||
}
|
||||
None => forage_grpc::update_policy_request::Config::SoakTime(
|
||||
forage_grpc::SoakTimeConfig::default(),
|
||||
),
|
||||
@@ -1724,6 +1752,168 @@ impl ForestPlatform for GrpcForestClient {
|
||||
.map_err(map_platform_status)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn evaluate_policies(
|
||||
&self,
|
||||
access_token: &str,
|
||||
organisation: &str,
|
||||
project: &str,
|
||||
target_environment: &str,
|
||||
release_intent_id: Option<&str>,
|
||||
) -> Result<Vec<PolicyEvaluation>, PlatformError> {
|
||||
let req = platform_authed_request(
|
||||
access_token,
|
||||
forage_grpc::EvaluatePoliciesRequest {
|
||||
project: Some(forage_grpc::Project {
|
||||
organisation: organisation.into(),
|
||||
project: project.into(),
|
||||
}),
|
||||
target_environment: target_environment.into(),
|
||||
branch: None,
|
||||
release_intent_id: release_intent_id.map(|s| s.to_string()),
|
||||
},
|
||||
)?;
|
||||
let resp = self
|
||||
.policy_client()
|
||||
.evaluate_policies(req)
|
||||
.await
|
||||
.map_err(map_platform_status)?;
|
||||
Ok(resp
|
||||
.into_inner()
|
||||
.evaluations
|
||||
.into_iter()
|
||||
.map(convert_policy_evaluation)
|
||||
.collect())
|
||||
}
|
||||
|
||||
async fn approve_release(
|
||||
&self,
|
||||
access_token: &str,
|
||||
organisation: &str,
|
||||
project: &str,
|
||||
release_intent_id: &str,
|
||||
target_environment: &str,
|
||||
comment: Option<&str>,
|
||||
force_bypass: bool,
|
||||
) -> Result<ApprovalState, PlatformError> {
|
||||
let req = platform_authed_request(
|
||||
access_token,
|
||||
forage_grpc::ExternalApproveReleaseRequest {
|
||||
project: Some(forage_grpc::Project {
|
||||
organisation: organisation.into(),
|
||||
project: project.into(),
|
||||
}),
|
||||
release_intent_id: release_intent_id.into(),
|
||||
target_environment: target_environment.into(),
|
||||
comment: comment.map(|s| s.to_string()),
|
||||
force_bypass,
|
||||
},
|
||||
)?;
|
||||
let resp = self
|
||||
.policy_client()
|
||||
.external_approve_release(req)
|
||||
.await
|
||||
.map_err(map_platform_status)?;
|
||||
Ok(convert_approval_state(resp.into_inner().state))
|
||||
}
|
||||
|
||||
async fn reject_release(
|
||||
&self,
|
||||
access_token: &str,
|
||||
organisation: &str,
|
||||
project: &str,
|
||||
release_intent_id: &str,
|
||||
target_environment: &str,
|
||||
comment: Option<&str>,
|
||||
) -> Result<ApprovalState, PlatformError> {
|
||||
let req = platform_authed_request(
|
||||
access_token,
|
||||
forage_grpc::ExternalRejectReleaseRequest {
|
||||
project: Some(forage_grpc::Project {
|
||||
organisation: organisation.into(),
|
||||
project: project.into(),
|
||||
}),
|
||||
release_intent_id: release_intent_id.into(),
|
||||
target_environment: target_environment.into(),
|
||||
comment: comment.map(|s| s.to_string()),
|
||||
},
|
||||
)?;
|
||||
let resp = self
|
||||
.policy_client()
|
||||
.external_reject_release(req)
|
||||
.await
|
||||
.map_err(map_platform_status)?;
|
||||
Ok(convert_approval_state(resp.into_inner().state))
|
||||
}
|
||||
|
||||
async fn get_approval_state(
|
||||
&self,
|
||||
access_token: &str,
|
||||
organisation: &str,
|
||||
project: &str,
|
||||
release_intent_id: &str,
|
||||
target_environment: &str,
|
||||
) -> Result<ApprovalState, PlatformError> {
|
||||
let req = platform_authed_request(
|
||||
access_token,
|
||||
forage_grpc::GetExternalApprovalStateRequest {
|
||||
project: Some(forage_grpc::Project {
|
||||
organisation: organisation.into(),
|
||||
project: project.into(),
|
||||
}),
|
||||
release_intent_id: release_intent_id.into(),
|
||||
target_environment: target_environment.into(),
|
||||
},
|
||||
)?;
|
||||
let resp = self
|
||||
.policy_client()
|
||||
.get_external_approval_state(req)
|
||||
.await
|
||||
.map_err(map_platform_status)?;
|
||||
Ok(convert_approval_state(resp.into_inner().state))
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_policy_evaluation(e: forage_grpc::PolicyEvaluation) -> PolicyEvaluation {
|
||||
let policy_type = match e.policy_type {
|
||||
1 => "soak_time",
|
||||
2 => "branch_restriction",
|
||||
3 => "approval",
|
||||
_ => "unknown",
|
||||
};
|
||||
let approval_state = e.approval_state.map(|s| convert_approval_state(Some(s)));
|
||||
PolicyEvaluation {
|
||||
policy_name: e.policy_name,
|
||||
policy_type: policy_type.into(),
|
||||
passed: e.passed,
|
||||
reason: e.reason,
|
||||
approval_state,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_approval_state(state: Option<forage_grpc::ExternalApprovalState>) -> ApprovalState {
|
||||
match state {
|
||||
Some(s) => ApprovalState {
|
||||
required_approvals: s.required_approvals,
|
||||
current_approvals: s.current_approvals,
|
||||
decisions: s
|
||||
.decisions
|
||||
.into_iter()
|
||||
.map(|d| ApprovalDecisionEntry {
|
||||
user_id: d.user_id,
|
||||
username: d.username,
|
||||
decision: d.decision,
|
||||
decided_at: d.decided_at,
|
||||
comment: d.comment,
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
None => ApprovalState {
|
||||
required_approvals: 0,
|
||||
current_approvals: 0,
|
||||
decisions: vec![],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user