76 lines
2.7 KiB
C++
76 lines
2.7 KiB
C++
#pragma once
|
|
// Step 605: Deployment Promotion Gate
|
|
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "ScoreClampUtil.h"
|
|
#include "ValidationErrorUtil.h"
|
|
|
|
struct EnvironmentGateState {
|
|
std::string environmentId;
|
|
int requiredChecks = 0;
|
|
int passedChecks = 0;
|
|
int manualApprovals = 0;
|
|
int blockingIssues = 0;
|
|
};
|
|
|
|
class DeploymentPromotionGate {
|
|
public:
|
|
bool upsert(const EnvironmentGateState& state, std::string* error) {
|
|
if (!error) return false;
|
|
error->clear();
|
|
if (state.environmentId.empty()) return failWith(error, "environment_id_missing");
|
|
if (state.requiredChecks < 0) return failWith(error, "required_checks_invalid");
|
|
if (state.passedChecks < 0) return failWith(error, "passed_checks_invalid");
|
|
if (state.manualApprovals < 0) return failWith(error, "manual_approvals_invalid");
|
|
if (state.blockingIssues < 0) return failWith(error, "blocking_issues_invalid");
|
|
if (state.passedChecks > state.requiredChecks) return failWith(error, "passed_checks_exceed_required");
|
|
if (states_.count(state.environmentId) == 0) order_.push_back(state.environmentId);
|
|
states_[state.environmentId] = state;
|
|
return true;
|
|
}
|
|
|
|
bool promotable(const std::string& environmentId, std::string* error) const {
|
|
if (!error) return false;
|
|
error->clear();
|
|
auto it = states_.find(environmentId);
|
|
if (it == states_.end()) return failWith(error, "environment_missing");
|
|
const auto& state = it->second;
|
|
return state.requiredChecks > 0 &&
|
|
state.passedChecks == state.requiredChecks &&
|
|
state.manualApprovals > 0 &&
|
|
state.blockingIssues == 0;
|
|
}
|
|
|
|
int promotionScore(const std::string& environmentId, std::string* error) const {
|
|
if (!error) return 0;
|
|
error->clear();
|
|
auto it = states_.find(environmentId);
|
|
if (it == states_.end()) {
|
|
failWith(error, "environment_missing");
|
|
return 0;
|
|
}
|
|
const auto& state = it->second;
|
|
if (state.requiredChecks == 0) return 0;
|
|
int score = (state.passedChecks * 100) / state.requiredChecks;
|
|
score += state.manualApprovals * 5;
|
|
score -= state.blockingIssues * 20;
|
|
return clampToPercent(score);
|
|
}
|
|
|
|
std::vector<std::string> blockedEnvironments() const {
|
|
std::vector<std::string> blocked;
|
|
for (const auto& id : order_) {
|
|
const auto& state = states_.at(id);
|
|
if (state.blockingIssues > 0 || state.passedChecks < state.requiredChecks) blocked.push_back(id);
|
|
}
|
|
return blocked;
|
|
}
|
|
|
|
private:
|
|
std::map<std::string, EnvironmentGateState> states_;
|
|
std::vector<std::string> order_;
|
|
};
|