use crate::compose::{Global, Project, SchemaVersion};
#[derive(schemars::JsonSchema)]
#[allow(dead_code)]
struct ComposeSchema {
global: Global,
project: Project,
}
pub fn current_schema_json() -> String {
let mut s = serde_json::to_string_pretty(&schemars::schema_for!(ComposeSchema))
.expect("schema serializes");
s.push('\n');
s
}
const EMBEDDED: &[(&str, &str)] = &[
(
SchemaVersion::CURRENT,
include_str!("../schemas/compose-2.0.1.json"),
),
("2.0.0", include_str!("../schemas/compose-2.0.0.json")),
];
pub fn bundled(version: &str) -> Option<&'static str> {
EMBEDDED
.iter()
.find(|(v, _)| *v == version)
.map(|(_, schema)| *schema)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn schema_matches_committed_golden() {
let derived = current_schema_json();
let committed = bundled(SchemaVersion::CURRENT).expect("current golden is bundled");
assert_eq!(
derived,
committed,
"compose schema drifted from schemas/compose-{current}.json. \
If this is an intentional schema change: bump SchemaVersion::CURRENT \
(MAJOR=remove/rename/semantics, MINOR=new optional field, PATCH=doc-only), \
then commit the regenerated schemas/compose-<new>.json. \
If unintentional, revert the type change.",
current = SchemaVersion::CURRENT,
);
}
#[test]
fn bundled_lookup_resolves_current_and_misses_unknown() {
assert!(bundled(SchemaVersion::CURRENT).is_some());
assert!(bundled("0.0.0").is_none());
}
#[test]
fn schema_covers_per_project_agent_tree() {
let schema: serde_json::Value =
serde_json::from_str(¤t_schema_json()).expect("schema is valid json");
assert!(
schema["definitions"]["Agent"].is_object(),
"compose schema must define the per-project `Agent` type; did ComposeSchema regress to Global-only?"
);
}
#[test]
#[ignore = "writes the source tree; run manually to regenerate the golden"]
fn regen_golden() {
let path = format!(
"{}/schemas/compose-{}.json",
env!("CARGO_MANIFEST_DIR"),
SchemaVersion::CURRENT
);
std::fs::write(&path, current_schema_json()).expect("write golden");
}
}