Skip to main content

facto_core/forges/
trait_def.rs

1use std::future::Future;
2use std::pin::Pin;
3
4use thiserror::Error;
5
6use crate::models::{ReleaseInfo, RepoSort, RepositorySearchResult, TagPin};
7
8#[derive(Debug, Error)]
9pub enum ForgeError {
10    #[error("http error: {0}")]
11    Http(#[from] reqwest::Error),
12    #[error("timeout")]
13    Timeout,
14    #[error("rate limited")]
15    RateLimited,
16    #[error("parse error: {0}")]
17    Parse(String),
18    #[error("not supported")]
19    NotSupported,
20}
21
22pub type ForgeResult<T> = Result<T, ForgeError>;
23
24/// A code forge backend (e.g., GitHub, GitLab, Codeberg).
25///
26/// Implementations provide release listings and tag resolution.
27pub trait Forge: Send + Sync {
28    /// Unique forge identifier (e.g., "github", "gitlab").
29    fn id(&self) -> &str;
30    /// Human-readable forge name.
31    fn display_name(&self) -> &str;
32
33    /// Whether this forge supports release listings.
34    fn supports_releases(&self) -> bool {
35        false
36    }
37
38    /// List releases for a repository, newest first.
39    fn list_releases<'a>(
40        &'a self,
41        _owner: &'a str,
42        _repo: &'a str,
43        _limit: usize,
44    ) -> Pin<Box<dyn Future<Output = ForgeResult<Vec<ReleaseInfo>>> + Send + 'a>> {
45        Box::pin(async { Err(ForgeError::NotSupported) })
46    }
47
48    /// Resolve a tag or ref to its full commit SHA.
49    fn resolve_tag<'a>(
50        &'a self,
51        _owner: &'a str,
52        _repo: &'a str,
53        _tag: &'a str,
54    ) -> Pin<Box<dyn Future<Output = ForgeResult<TagPin>> + Send + 'a>> {
55        Box::pin(async { Err(ForgeError::NotSupported) })
56    }
57
58    /// Whether this forge supports repository search.
59    fn supports_search(&self) -> bool {
60        false
61    }
62
63    /// Search repositories/projects, best-effort sorted. `language` is a
64    /// best-effort filter (only some forges honour it).
65    fn search_repositories<'a>(
66        &'a self,
67        _query: &'a str,
68        _sort: RepoSort,
69        _language: Option<&'a str>,
70        _limit: usize,
71    ) -> Pin<Box<dyn Future<Output = ForgeResult<Vec<RepositorySearchResult>>> + Send + 'a>> {
72        Box::pin(async { Err(ForgeError::NotSupported) })
73    }
74}