From 20a1c652f61437ac35ce85ef8a66ae93fd64b3d0 Mon Sep 17 00:00:00 2001 From: gl0w Date: Thu, 10 Sep 2026 07:33:15 +0100 Subject: [PATCH] m6/readme-bug: extensionless chain + regression tests --- src/build.rs | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/src/build.rs b/src/build.rs index 5083fa7..0cf0a67 100644 --- a/src/build.rs +++ b/src/build.rs @@ -147,8 +147,9 @@ pub fn resolve_clone_url(repo: &Path, flag: Option<&str>) -> Option { } /// README lookup chain (f0rge convention): repo-root `README.md` > -/// `readme.md` > `README`, else `.forge/wiki/README.md` > -/// `.forge/wiki/readme.md`, else none. +/// `readme.md` > `README` > `readme`, else `.forge/wiki/README.md` > +/// `.forge/wiki/readme.md` > `.forge/wiki/README` > `.forge/wiki/readme`, +/// else none. /// /// Returns the winning path plus its blob. pub fn find_readme(repo: &Path, branch: &str) -> Option<(String, gitx::Blob)> { @@ -156,8 +157,11 @@ pub fn find_readme(repo: &Path, branch: &str) -> Option<(String, gitx::Blob)> { "README.md", "readme.md", "README", + "readme", ".forge/wiki/README.md", ".forge/wiki/readme.md", + ".forge/wiki/README", + ".forge/wiki/readme", ] { if let Ok(blob) = gitx::show(repo, branch, Path::new(candidate)) { return Some((candidate.to_string(), blob)); @@ -946,6 +950,78 @@ mod tests { assert_eq!(path, "README.md"); } + #[test] + fn readme_chain_shows_extensionless_wiki_readme() { + let dir = mktemp("readme-extless"); + git(&dir, &["init", "-b", "main"]); + git(&dir, &["config", "user.name", "hu13-test"]); + git(&dir, &["config", "user.email", "hu13@test.local"]); + git(&dir, &["config", "commit.gpgsign", "false"]); + // Extensionless wiki README only (f0rge issue #35). + std::fs::create_dir_all(dir.join(".forge").join("wiki")).unwrap(); + std::fs::write( + dir.join(".forge").join("wiki").join("README"), + "# Wiki extless\n", + ) + .unwrap(); + std::fs::write(dir.join("notes.txt"), "x\n").unwrap(); + git(&dir, &["add", "-A"]); + git(&dir, &["commit", "-m", "wiki extless only"]); + let (path, _) = find_readme(&dir, "main").expect("wiki extless fallback"); + assert_eq!(path, ".forge/wiki/README"); + // Code tab renders it. + let out = mktemp("out-extless"); + run_build(&dir, &out, &opts()).expect("build"); + let index = std::fs::read_to_string(out.join("index.html")).expect("index"); + assert!(index.contains("Wiki extless"), "code tab shows wiki README"); + assert!( + index.contains("from .forge/wiki/README"), + "code tab names source" + ); + } + + #[test] + fn readme_chain_full_priority_order() { + let dir = mktemp("readme-priority"); + git(&dir, &["init", "-b", "main"]); + git(&dir, &["config", "user.name", "hu13-test"]); + git(&dir, &["config", "user.email", "hu13@test.local"]); + git(&dir, &["config", "commit.gpgsign", "false"]); + let chain = [ + "README.md", + "readme.md", + "README", + "readme", + ".forge/wiki/README.md", + ".forge/wiki/readme.md", + ".forge/wiki/README", + ".forge/wiki/readme", + ]; + std::fs::create_dir_all(dir.join(".forge").join("wiki")).unwrap(); + for (i, cand) in chain.iter().enumerate() { + std::fs::write(dir.join(cand), format!("# marker {i}\n")).unwrap(); + } + std::fs::write(dir.join("notes.txt"), "x\n").unwrap(); + git(&dir, &["add", "-A"]); + git(&dir, &["commit", "-m", "all readmes"]); + for (i, want) in chain.iter().enumerate() { + let (path, blob) = find_readme(&dir, "main").expect("readme present"); + assert_eq!(&path, want, "priority position {i}"); + assert!( + blob.display.contains(&format!("marker {i}")), + "winning body at {want}" + ); + // Root extensionless beats wiki once wiki-only remains. + if *want == "readme" { + let (p, _) = find_readme(&dir, "main").expect("root extless"); + assert_eq!(p, "readme"); + } + git(&dir, &["rm", "-q", want]); + git(&dir, &["commit", "-m", &format!("drop {want}")]); + } + assert!(find_readme(&dir, "main").is_none(), "none when chain empty"); + } + #[test] fn build_emits_commits_and_wiki() { let repo = fixture_repo(); -- 2.55.0