//! Where a package's releases are published: the `ReleaseSource` trait, //! one file per host implementing it, and `for_package`, which picks the //! implementation for a package from its configured `source`. The //! submodules are private and re-exported here, so the rest of the crate //! imports everything from `crate::release_source` and never a host's //! file. mod contract; mod forgejo; mod github; pub use contract::ReleaseSource; pub use forgejo::ForgejoEndpoints; pub use github::GithubEndpoints; use crate::config::{Package, Source}; use anyhow::{Context, Result}; /// Defensive: errors only if a `forgejo-release` package has no /// `base_url`, which `config::load_packages_dir` already guarantees. pub fn for_package(pkg: &Package) -> Result> { match pkg.source { Source::GithubRelease => Ok(Box::new(GithubEndpoints::default())), Source::ForgejoRelease => { let base_url = pkg .base_url .as_deref() .context("source = \"forgejo-release\" needs a base_url")?; Ok(Box::new(ForgejoEndpoints::from_base_url(base_url))) } } } #[cfg(test)] mod tests { use super::*; use crate::test_support::same_origin_package as package; #[test] fn github_source_uses_real_github() { let source = for_package(&package("")).unwrap(); assert_eq!(source.api(), "https://api.github.com"); } #[test] fn forgejo_source_uses_the_instances_api() { let pkg = package("source = \"forgejo-release\"\nbase_url = \"https://code.example.com\""); let source = for_package(&pkg).unwrap(); assert_eq!(source.api(), "https://code.example.com/api/v1"); } #[test] fn forgejo_source_without_base_url_errors() { let err = for_package(&package("source = \"forgejo-release\"")).unwrap_err(); assert!(err.to_string().contains("needs a base_url")); } }