2026-09-20 08:36:13 +00:00
|
|
|
//! Maps a package's configured `source` to the endpoints the pipeline
|
2026-09-20 08:39:35 +00:00
|
|
|
//! stages talk to. `checker` and `fetcher` take what it hands them and
|
|
|
|
|
//! build their own paths under it.
|
2026-09-20 08:36:13 +00:00
|
|
|
|
|
|
|
|
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 {
|
2026-09-20 08:39:35 +00:00
|
|
|
/// Defensive: errors only if a `forgejo-release` package has no
|
|
|
|
|
/// `base_url`, which `config::load_packages_dir` already guarantees.
|
2026-09-20 08:36:13 +00:00
|
|
|
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::*;
|
2026-09-20 08:39:35 +00:00
|
|
|
use crate::test_support::same_origin_package as package;
|
2026-09-20 08:36:13 +00:00
|
|
|
|
|
|
|
|
#[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"));
|
|
|
|
|
}
|
|
|
|
|
}
|