pub mod comment;
pub mod github;
use miette::Diagnostic;
use thiserror::Error;
#[derive(Debug, Error, Diagnostic)]
pub enum ForgeError {
#[error("API error: {message}")]
#[diagnostic(code(stakk::forge::api))]
Api {
message: String,
#[source]
source: Box<dyn std::error::Error + Send + Sync>,
},
#[error("authentication failed: {message}")]
#[diagnostic(
code(stakk::forge::auth_failed),
help("your token may have expired — run `gh auth login` to re-authenticate")
)]
AuthFailed {
message: String,
#[source]
source: Box<dyn std::error::Error + Send + Sync>,
},
#[error("malformed forge response: missing field `{field}`")]
#[diagnostic(
code(stakk::forge::malformed_response),
help(
"the forge API response is missing the `{field}` field — this may indicate a forge \
API change"
)
)]
MalformedResponse { field: &'static str },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PrState {
Open,
Closed,
Merged,
}
#[derive(Debug, Clone)]
pub struct PullRequest {
pub number: u64,
pub html_url: String,
pub title: String,
#[expect(
dead_code,
reason = "part of PR data model, not yet consumed by submission logic"
)]
pub head_ref: String,
pub base_ref: String,
#[expect(
dead_code,
reason = "part of PR data model, not yet consumed by submission logic"
)]
pub state: PrState,
pub body: Option<String>,
}
#[derive(Debug, Clone)]
pub struct Comment {
pub id: u64,
pub body: String,
}
#[derive(Debug, Clone)]
pub struct CreatePrParams {
pub title: String,
pub head: String,
pub base: String,
pub body: Option<String>,
pub draft: bool,
}
pub trait Forge: Send + Sync {
fn get_authenticated_user(
&self,
) -> impl std::future::Future<Output = Result<String, ForgeError>> + Send;
fn find_pr_for_branch(
&self,
head: &str,
) -> impl std::future::Future<Output = Result<Option<PullRequest>, ForgeError>> + Send;
fn create_pr(
&self,
params: CreatePrParams,
) -> impl std::future::Future<Output = Result<PullRequest, ForgeError>> + Send;
fn update_pr_base(
&self,
pr_number: u64,
new_base: &str,
) -> impl std::future::Future<Output = Result<(), ForgeError>> + Send;
fn update_pr_title(
&self,
pr_number: u64,
title: &str,
) -> impl std::future::Future<Output = Result<(), ForgeError>> + Send;
fn list_comments(
&self,
pr_number: u64,
) -> impl std::future::Future<Output = Result<Vec<Comment>, ForgeError>> + Send;
fn create_comment(
&self,
pr_number: u64,
body: &str,
) -> impl std::future::Future<Output = Result<Comment, ForgeError>> + Send;
fn update_comment(
&self,
comment_id: u64,
body: &str,
) -> impl std::future::Future<Output = Result<(), ForgeError>> + Send;
fn update_pr_body(
&self,
pr_number: u64,
body: &str,
) -> impl std::future::Future<Output = Result<(), ForgeError>> + Send;
fn delete_comment(
&self,
comment_id: u64,
) -> impl std::future::Future<Output = Result<(), ForgeError>> + Send;
}