pub(crate) mod doctor_v3;
pub(crate) mod labels;
pub(crate) mod project;
pub(crate) mod v1;
pub(crate) mod v2;
pub(crate) mod v3;
pub(crate) use project::Project;
pub(crate) const CURRENT_VERSION: u32 = 2;
pub(crate) const DOCTOR_CURRENT_VERSION: u32 = 3;
pub(crate) const WHY_CURRENT_VERSION: u32 = 3;
pub(crate) fn validate_schema_version(requested: u32) -> anyhow::Result<u32> {
if requested == 0 || requested > CURRENT_VERSION {
anyhow::bail!(
"unsupported --schema-version {requested}; this binary speaks 1..={CURRENT_VERSION}",
);
}
Ok(requested)
}
pub(crate) fn validate_doctor_schema_version(requested: u32) -> anyhow::Result<u32> {
if requested == 0 || requested > DOCTOR_CURRENT_VERSION {
anyhow::bail!(
"unsupported --schema-version {requested}; `runner doctor` speaks 1..={DOCTOR_CURRENT_VERSION}",
);
}
Ok(requested)
}
pub(crate) fn schema_url(command: &str, version: u32) -> String {
format!("https://kjanat.github.io/schemas/{command}.v{version}.schema.json")
}
pub(crate) fn validate_why_schema_version(requested: u32) -> anyhow::Result<u32> {
if requested == 0 || requested > WHY_CURRENT_VERSION {
anyhow::bail!(
"unsupported --schema-version {requested}; `runner why` speaks 1..={WHY_CURRENT_VERSION}",
);
}
Ok(requested)
}
#[cfg(test)]
mod tests {
use super::{
CURRENT_VERSION, DOCTOR_CURRENT_VERSION, WHY_CURRENT_VERSION, labels::source_label_for,
validate_doctor_schema_version, validate_schema_version, validate_why_schema_version,
};
use crate::types::TaskSource;
#[test]
fn source_label_for_returns_legacy_strings_under_v1() {
assert_eq!(source_label_for(TaskSource::Justfile, 1), "justfile");
assert_eq!(source_label_for(TaskSource::BaconToml, 1), "bacon.toml");
assert_eq!(source_label_for(TaskSource::MiseToml, 1), "mise.toml");
assert_eq!(source_label_for(TaskSource::Makefile, 1), "Makefile");
assert_eq!(source_label_for(TaskSource::TurboJson, 1), "turbo.json");
assert_eq!(source_label_for(TaskSource::DenoJson, 1), "deno.json");
assert_eq!(source_label_for(TaskSource::Taskfile, 1), "Taskfile");
assert_eq!(source_label_for(TaskSource::CargoAliases, 1), "cargo");
assert_eq!(source_label_for(TaskSource::GoPackage, 1), "go");
assert_eq!(source_label_for(TaskSource::PackageJson, 1), "package.json");
}
#[test]
fn source_label_for_returns_tool_names_under_v2() {
assert_eq!(source_label_for(TaskSource::Justfile, 2), "just");
assert_eq!(source_label_for(TaskSource::BaconToml, 2), "bacon");
assert_eq!(source_label_for(TaskSource::MiseToml, 2), "mise");
assert_eq!(source_label_for(TaskSource::Makefile, 2), "make");
assert_eq!(source_label_for(TaskSource::TurboJson, 2), "turbo");
assert_eq!(source_label_for(TaskSource::DenoJson, 2), "deno");
assert_eq!(source_label_for(TaskSource::Taskfile, 2), "task");
assert_eq!(source_label_for(TaskSource::CargoAliases, 2), "cargo");
assert_eq!(source_label_for(TaskSource::GoPackage, 2), "go");
assert_eq!(source_label_for(TaskSource::PackageJson, 2), "package.json");
}
#[test]
fn current_version_matches_v2_labels() {
assert_eq!(CURRENT_VERSION, 2);
assert_eq!(
source_label_for(TaskSource::Justfile, CURRENT_VERSION),
"just"
);
}
#[test]
fn why_version_matches_v3_labels() {
assert_eq!(WHY_CURRENT_VERSION, 3);
assert_eq!(
source_label_for(TaskSource::CargoAliases, WHY_CURRENT_VERSION),
"cargo-alias"
);
assert_eq!(
source_label_for(TaskSource::Justfile, WHY_CURRENT_VERSION),
"just"
);
assert_eq!(
source_label_for(TaskSource::PackageJson, WHY_CURRENT_VERSION),
"package.json"
);
}
#[test]
fn validate_schema_version_accepts_supported_range() {
assert_eq!(validate_schema_version(1).unwrap(), 1);
assert_eq!(validate_schema_version(2).unwrap(), 2);
}
#[test]
fn validate_schema_version_rejects_zero_and_future_versions() {
let err = validate_schema_version(0).expect_err("v0 must error");
assert!(format!("{err}").contains("unsupported"));
let err = validate_schema_version(99).expect_err("future versions must error");
let msg = format!("{err}");
assert!(msg.contains("unsupported"));
assert!(
msg.contains("1..=2"),
"error should advertise the supported range: {msg}",
);
let err = validate_schema_version(3).expect_err("doctor/list must reject v3");
assert!(format!("{err}").contains("1..=2"));
}
#[test]
fn validate_doctor_schema_version_spans_one_through_three() {
assert_eq!(DOCTOR_CURRENT_VERSION, 3);
assert_eq!(validate_doctor_schema_version(1).unwrap(), 1);
assert_eq!(validate_doctor_schema_version(2).unwrap(), 2);
assert_eq!(validate_doctor_schema_version(3).unwrap(), 3);
let err = validate_doctor_schema_version(0).expect_err("v0 must error");
assert!(format!("{err}").contains("unsupported"));
let err = validate_doctor_schema_version(4).expect_err("future versions must error");
assert!(
format!("{err}").contains("1..=3"),
"error should advertise the doctor range",
);
}
#[test]
fn validate_why_schema_version_spans_one_through_three() {
assert_eq!(validate_why_schema_version(1).unwrap(), 1);
assert_eq!(validate_why_schema_version(2).unwrap(), 2);
assert_eq!(validate_why_schema_version(3).unwrap(), 3);
let err = validate_why_schema_version(0).expect_err("v0 must error");
assert!(format!("{err}").contains("unsupported"));
let err = validate_why_schema_version(4).expect_err("future versions must error");
assert!(
format!("{err}").contains("1..=3"),
"error should advertise the why range",
);
}
}