pkgwatch/src/source.rs

95 lines
3.2 KiB
Rust
Raw Normal View History

//! Maps a package's configured `source` to the endpoints the pipeline
//! stages talk to. The only module that knows how each hosting service
//! lays out its URLs; `checker` and `fetcher` take what it hands them.
use crate::config::{Package, Source};
use crate::github::GithubEndpoints;
use anyhow::{Context, Result};
#[derive(Debug, Clone)]
pub enum Endpoints {
Github(GithubEndpoints),
/// A Forgejo/Gitea instance's API root, i.e. `<base_url>/api/v1`.
Forgejo {
api: String,
},
}
impl Endpoints {
/// Errors only if a `forgejo-release` package has no `base_url`, which
/// `config::load_packages_dir` already rejects — this is the same check
/// again for a `Package` built some other way, not a second source of
/// truth.
pub fn for_package(pkg: &Package) -> Result<Self> {
match pkg.source {
Source::GithubRelease => Ok(Endpoints::Github(GithubEndpoints::default())),
Source::ForgejoRelease => {
let base_url = pkg
.base_url
.as_deref()
.context("source = \"forgejo-release\" needs a base_url")?;
Ok(Endpoints::Forgejo {
api: format!("{}/api/v1", base_url.trim_end_matches('/')),
})
}
}
}
/// The releases API root. GitHub and Forgejo both serve
/// `/repos/{owner}/{repo}/releases/tags/{tag}` under it with the same
/// `assets[].{name, browser_download_url}` shape, which is why
/// `fetcher` and `verifier` need only this and not the enum.
pub fn api(&self) -> &str {
match self {
Endpoints::Github(github) => &github.api,
Endpoints::Forgejo { api } => api,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn package(extra: &str) -> Package {
toml::from_str(&format!(
r#"
repo = "o/r"
asset_pattern = "x"
{extra}
[verification]
method = "same-origin-sha256"
checksum_asset_pattern = "SUMS"
"#
))
.unwrap()
}
#[test]
fn github_source_uses_real_github() {
let endpoints = Endpoints::for_package(&package("")).unwrap();
assert_eq!(endpoints.api(), "https://api.github.com");
assert!(matches!(endpoints, Endpoints::Github(_)));
}
#[test]
fn forgejo_source_appends_api_v1() {
let pkg = package("source = \"forgejo-release\"\nbase_url = \"https://code.example.com\"");
let endpoints = Endpoints::for_package(&pkg).unwrap();
assert_eq!(endpoints.api(), "https://code.example.com/api/v1");
}
#[test]
fn forgejo_source_tolerates_trailing_slash() {
let pkg = package("source = \"forgejo-release\"\nbase_url = \"https://code.example.com/\"");
let endpoints = Endpoints::for_package(&pkg).unwrap();
assert_eq!(endpoints.api(), "https://code.example.com/api/v1");
}
#[test]
fn forgejo_source_without_base_url_errors() {
let err = Endpoints::for_package(&package("source = \"forgejo-release\"")).unwrap_err();
assert!(err.to_string().contains("needs a base_url"));
}
}