spec_driven_docs/
self_depend.rs1pub mod fragments;
16pub mod leftovers;
17pub mod manager;
18pub mod pin;
19pub mod registry;
20pub mod stamp;
21pub mod status;
22pub mod txn;
23pub mod venue;
24
25use crate::domain::manifest::CANON_SOURCE;
26
27pub const BINARY_NAME: &str = "sdd";
29
30pub const SYNC_LINE: &str = "sdd self-depend sync --apply || true";
32
33pub const ENVRC: &str = ".envrc";
35
36#[must_use]
39pub fn coordinates() -> (&'static str, &'static str) {
40 let path = CANON_SOURCE
41 .trim_start_matches("https://github.com/")
42 .trim_end_matches(".git");
43 path.split_once('/').unwrap_or((path, ""))
44}
45
46#[must_use]
48pub fn slug() -> String {
49 let (owner, repo) = coordinates();
50 format!("{owner}/{repo}")
51}
52
53pub fn parse_tag(value: &str) -> Result<semver::Version, String> {
60 let tail = value.trim().rsplit('/').next().unwrap_or(value).trim();
61 let bare = tail.strip_prefix('v').unwrap_or(tail);
62 let version: semver::Version = bare
63 .parse()
64 .map_err(|_| format!("{value} is not a release tag: expected v<major>.<minor>.<patch>"))?;
65 if !version.pre.is_empty() || !version.build.is_empty() {
66 return Err(format!("{value} is not a released triple"));
67 }
68 Ok(version)
69}
70
71#[cfg(test)]
72mod tests {
73 #![allow(clippy::unwrap_used, reason = "a test panics as its failure signal")]
74
75 use super::*;
76
77 #[test]
78 fn the_coordinates_come_from_the_canon_source() {
79 let (owner, repo) = coordinates();
80 assert!(!owner.is_empty());
81 assert_eq!(repo, "spec-driven-docs");
82 assert!(CANON_SOURCE.ends_with(&slug()));
83 }
84
85 #[test]
86 fn a_tag_parses_in_every_spelling() {
87 assert_eq!(parse_tag("v0.2.16").unwrap().to_string(), "0.2.16");
88 assert_eq!(parse_tag("0.2.16").unwrap().to_string(), "0.2.16");
89 assert_eq!(
90 parse_tag("https://example.invalid/releases/tag/v1.2.3")
91 .unwrap()
92 .to_string(),
93 "1.2.3"
94 );
95 assert!(parse_tag("v1.2.3-rc.1").is_err());
96 assert!(parse_tag("latest").is_err());
97 }
98}