///|
/// Release gates that combine validation, content, accessibility, and export checks.
pub struct ReleasePolicy {
minimum_score : Int
require_accessibility : Bool
require_content : Bool
require_non_empty_exports : Bool
required_formats : Array[String]
} derive(Debug, Eq)
///|
pub fn ReleasePolicy::default() -> ReleasePolicy {
{
minimum_score: 70,
require_accessibility: true,
require_content: false,
require_non_empty_exports: true,
required_formats: ["markdown", "html", "json"],
}
}
///|
pub fn ReleasePolicy::strict() -> ReleasePolicy {
{
minimum_score: 85,
require_accessibility: true,
require_content: true,
require_non_empty_exports: true,
required_formats: [
"markdown", "html", "css", "json", "yaml", "tailwind", "figma",
],
}
}
///|
pub fn ReleasePolicy::with_minimum_score(
self : ReleasePolicy,
score : Int,
) -> ReleasePolicy {
{
..self,
minimum_score: if score < 0 {
0
} else if score > 100 {
100
} else {
score
},
}
}
///|
pub fn ReleasePolicy::with_content_requirement(
self : ReleasePolicy,
required : Bool,
) -> ReleasePolicy {
{ ..self, require_content: required }
}
///|
pub fn ReleasePolicy::with_formats(
self : ReleasePolicy,
formats : Array[String],
) -> ReleasePolicy {
{ ..self, required_formats: formats }
}
///|
pub struct ReleaseCheck {
name : String
passed : Bool
message : String
} derive(Debug, Eq)
///|
pub fn ReleaseCheck::new(
name : String,
passed : Bool,
message : String,
) -> ReleaseCheck {
{ name, passed, message }
}
///|
pub fn ReleaseCheck::status(self : ReleaseCheck) -> String {
if self.passed {
"pass"
} else {
"fail"
}
}
///|
pub struct ReleaseReport {
ready : Bool
checks : Array[ReleaseCheck]
score : Int
} derive(Debug, Eq)
///|
pub fn BrandBook::release_report(
self : BrandBook,
policy : ReleasePolicy,
) -> ReleaseReport {
let quality = BrandQualityReport::from_brand_book(self)
let manifest = ExportManifest::for_brand_book(self)
let checks : Array[ReleaseCheck] = []
checks.push(
ReleaseCheck::new(
"quality score",
quality.score >= policy.minimum_score,
quality.score.to_string() + "/100",
),
)
checks.push(
ReleaseCheck::new(
"validation",
!quality.audit.has_errors(),
quality.audit.summary(),
),
)
if policy.require_accessibility {
checks.push(
ReleaseCheck::new(
"accessibility",
self.accessibility_score() >= 70,
self.accessibility_score().to_string() + "/100",
),
)
}
if policy.require_content {
let content = self.audit_content(ContentPolicy::strict())
checks.push(
ReleaseCheck::new("content", !content.has_errors(), content.summary()),
)
}
if policy.require_non_empty_exports {
checks.push(
ReleaseCheck::new(
"exports",
manifest.total_bytes() > 0,
manifest.total_bytes().to_string() + " bytes",
),
)
}
for format in policy.required_formats {
checks.push(
ReleaseCheck::new(
"format:" + format,
manifest.formats().contains(format),
"required format present",
),
)
}
{
ready: checks.all(fn(check) { check.passed }),
checks,
score: quality.score,
}
}
///|
pub fn ReleaseReport::passed(self : ReleaseReport) -> Bool {
self.ready
}
///|
pub fn ReleaseReport::failed_checks(
self : ReleaseReport,
) -> Array[ReleaseCheck] {
self.checks.filter(fn(check) { !check.passed })
}
///|
pub fn ReleaseReport::passed_checks(
self : ReleaseReport,
) -> Array[ReleaseCheck] {
self.checks.filter(fn(check) { check.passed })
}
///|
pub fn ReleaseReport::check_named(
self : ReleaseReport,
name : String,
) -> ReleaseCheck? {
for check in self.checks {
if check.name == name {
return Some(check)
}
}
None
}
///|
pub fn ReleaseReport::summary(self : ReleaseReport) -> String {
self.score.to_string() +
"/100, " +
self.passed_checks().length().to_string() +
"/" +
self.checks.length().to_string() +
" checks passed"
}
///|
pub fn ReleaseReport::to_markdown(self : ReleaseReport) -> String {
let status = if self.ready { "ready" } else { "blocked" }
let lines : Array[String] = [
"# Release readiness",
"",
"Status: **" + status + "**",
"",
"| Check | Status | Evidence |",
"| --- | --- | --- |",
]
for check in self.checks {
lines.push(
"| " + check.name + " | " + check.status() + " | " + check.message + " |",
)
}
lines.join("\n")
}
///|
pub fn ReleaseReport::to_json(self : ReleaseReport) -> String {
"{\"ready\":" +
self.ready.to_string() +
",\"score\":" +
self.score.to_string() +
",\"checks\":[" +
self.checks
.map(fn(check) {
"{\"name\":\"" +
json_escape(check.name) +
"\",\"passed\":" +
check.passed.to_string() +
",\"message\":\"" +
json_escape(check.message) +
"\"}"
})
.join(",") +
"]}"
}
///|
pub fn BrandBook::is_release_ready(self : BrandBook) -> Bool {
self.release_report(ReleasePolicy::default()).passed()
}
///|
pub fn BrandBook::release_markdown(self : BrandBook) -> String {
self.release_report(ReleasePolicy::default()).to_markdown()
}