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>,
},
#[expect(dead_code, reason = "used in later milestones for PR lookup errors")]
#[error("PR not found: #{number}")]
#[diagnostic(code(stakk::forge::pr_not_found))]
PrNotFound { number: u64 },
#[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>,
},
#[expect(dead_code, reason = "used in later milestones for rate limit handling")]
#[error("rate limited; retry after {retry_after_seconds}s")]
#[diagnostic(
code(stakk::forge::rate_limited),
help("wait {retry_after_seconds}s and retry")
)]
RateLimited { retry_after_seconds: u64 },
}
#[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 = "populated by forge, read in future milestones")]
pub head_ref: String,
pub base_ref: String,
#[expect(dead_code, reason = "populated by forge, read in future milestones")]
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;
}