diff --git a/src/templates/mod.rs b/src/templates/mod.rs index 081e322..a63c2c1 100644 --- a/src/templates/mod.rs +++ b/src/templates/mod.rs @@ -263,9 +263,14 @@ pub(crate) fn clear_download_override() { TEST_DOWNLOAD_OVERRIDE.with(|o| *o.borrow_mut() = None); } -/// List template names available in the remote registry. +/// List template names available in the remote registry: the templates its +/// `registry.toml` declares. Listing the repo's directories instead would +/// offer anything that lives there (a `scripts/` folder) as a template. pub fn list_remote() -> Result> { - let url = format!("https://api.github.com/repos/{}/contents", REGISTRY_REPO); + let url = format!( + "https://raw.githubusercontent.com/{}/main/registry.toml", + REGISTRY_REPO + ); let response = reqwest::blocking::Client::new() .get(&url) @@ -277,19 +282,24 @@ pub fn list_remote() -> Result> { anyhow::bail!("Registry returned HTTP {}", response.status()); } + parse_registry_names(&response.text()?) +} + +/// Template names declared in a `registry.toml` (`[[templates]]` entries, +/// each with a `nombre`), sorted. +fn parse_registry_names(text: &str) -> Result> { + #[derive(serde::Deserialize)] + struct Registry { + #[serde(default)] + templates: Vec, + } #[derive(serde::Deserialize)] struct Entry { - name: String, - #[serde(rename = "type")] - kind: String, + nombre: String, } - let entries: Vec = response.json()?; - let mut names: Vec = entries - .into_iter() - .filter(|e| e.kind == "dir") - .map(|e| e.name) - .collect(); + let registry: Registry = toml::from_str(text).context("Invalid registry.toml")?; + let mut names: Vec = registry.templates.into_iter().map(|t| t.nombre).collect(); names.sort(); Ok(names) } @@ -480,6 +490,32 @@ mod tests { assert!(result.files.is_empty()); } + #[test] + fn parse_registry_names_lists_declared_templates_sorted() { + let text = r#" +[[templates]] +nombre = "taller" +descripcion = "Workshop deliverable" +version = "0.2.0" + +[[templates]] +nombre = "cv" +descripcion = "One-page résumé" +version = "0.1.0" +"#; + assert_eq!(parse_registry_names(text).unwrap(), ["cv", "taller"]); + } + + #[test] + fn parse_registry_names_rejects_invalid_toml() { + assert!(parse_registry_names("[[templates]\nnombre =").is_err()); + } + + #[test] + fn parse_registry_names_empty_registry_is_empty() { + assert!(parse_registry_names("").unwrap().is_empty()); + } + #[test] fn load_dir_recursive_file_contents_match() { let tmp = tempfile::tempdir().unwrap();