pub use escouade_plugin_protocol::forge::*;
use crate::tr;
use anyhow::Result;
use serde_json::Value;
use std::future::Future;
use std::pin::Pin;
use std::time::Duration;
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
pub fn instant(v: &Value) -> Option<u64> {
let t = chrono::DateTime::parse_from_rfc3339(v.as_str()?)
.ok()?
.timestamp();
u64::try_from(t).ok().filter(|t| *t > 0)
}
#[derive(Debug)]
pub struct Unsupported(pub &'static str);
impl std::fmt::Display for Unsupported {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let what = self.0;
f.write_str(&tr!(
"Cet hébergeur ne sait pas faire : {what}",
"This code host can’t do it: {what}"
))
}
}
impl std::error::Error for Unsupported {}
pub fn unsupported<'a, T: Send + 'a>(what: &'static str) -> BoxFuture<'a, Result<T>> {
Box::pin(async move { Err(Unsupported(what).into()) })
}
pub trait Forge: Send + Sync {
fn me(&self) -> BoxFuture<'_, Result<Identity>>;
fn create_pr<'a>(
&'a self,
_repo: &'a RepoRef,
_pr: &'a PullRequestDraft,
) -> BoxFuture<'a, Result<PullRequest>> {
unsupported("create_pr")
}
fn pull_request<'a>(
&'a self,
_repo: &'a RepoRef,
_number: u64,
) -> BoxFuture<'a, Result<PullRequest>> {
unsupported("pull_request")
}
fn pull_requests_of_branch<'a>(
&'a self,
_repo: &'a RepoRef,
_branch: &'a str,
) -> BoxFuture<'a, Result<Vec<PullRequest>>> {
unsupported("pull_requests_of_branch")
}
fn parent<'a>(&'a self, _repo: &'a RepoRef) -> BoxFuture<'a, Result<Option<RepoRef>>> {
Box::pin(async { Ok(None) })
}
fn open_pull_requests<'a>(
&'a self,
_repo: &'a RepoRef,
) -> BoxFuture<'a, Result<Vec<PullRequest>>> {
unsupported("open_pull_requests")
}
fn pull_requests<'a>(
&'a self,
_repo: &'a RepoRef,
_numbers: &'a [u64],
) -> BoxFuture<'a, Result<Vec<PullRequest>>> {
unsupported("pull_requests")
}
fn merge<'a>(
&'a self,
_repo: &'a RepoRef,
_number: u64,
_strategy: MergeStrategy,
) -> BoxFuture<'a, Result<()>> {
unsupported("merge")
}
fn merge_options<'a>(
&'a self,
_repo: &'a RepoRef,
_number: u64,
) -> BoxFuture<'a, Result<MergeOptions>> {
unsupported("merge_options")
}
fn auto_merge<'a>(
&'a self,
_repo: &'a RepoRef,
_number: u64,
_strategy: MergeStrategy,
) -> BoxFuture<'a, Result<()>> {
unsupported("auto_merge")
}
fn checks<'a>(&'a self, _repo: &'a RepoRef, _number: u64) -> BoxFuture<'a, Result<Vec<Check>>> {
unsupported("checks")
}
fn job_log<'a>(&'a self, _repo: &'a RepoRef, _job: &'a str) -> BoxFuture<'a, Result<String>> {
unsupported("job_log")
}
fn reviews<'a>(
&'a self,
_repo: &'a RepoRef,
_number: u64,
) -> BoxFuture<'a, Result<Vec<Review>>> {
unsupported("reviews")
}
fn comments<'a>(
&'a self,
_repo: &'a RepoRef,
_number: u64,
) -> BoxFuture<'a, Result<Vec<ReviewComment>>> {
unsupported("comments")
}
fn comment<'a>(
&'a self,
_repo: &'a RepoRef,
_number: u64,
_body: &'a str,
) -> BoxFuture<'a, Result<()>> {
unsupported("comment")
}
fn rerun_failed<'a>(
&'a self,
_repo: &'a RepoRef,
_number: u64,
) -> BoxFuture<'a, Result<usize>> {
unsupported("rerun_failed")
}
fn branch_checks<'a>(
&'a self,
_repo: &'a RepoRef,
_branch: &'a str,
) -> BoxFuture<'a, Result<Vec<Check>>> {
unsupported("branch_checks")
}
fn rerun_failed_of_branch<'a>(
&'a self,
_repo: &'a RepoRef,
_branch: &'a str,
) -> BoxFuture<'a, Result<usize>> {
unsupported("rerun_failed_of_branch")
}
fn review<'a>(
&'a self,
_repo: &'a RepoRef,
_number: u64,
_review: &'a ReviewDraft,
) -> BoxFuture<'a, Result<()>> {
unsupported("review")
}
fn reply<'a>(
&'a self,
_repo: &'a RepoRef,
_number: u64,
_comment: &'a str,
_body: &'a str,
) -> BoxFuture<'a, Result<()>> {
unsupported("reply")
}
fn resolve<'a>(
&'a self,
_repo: &'a RepoRef,
_number: u64,
_comment: &'a str,
) -> BoxFuture<'a, Result<()>> {
unsupported("resolve")
}
fn rate_limit(&self) -> Option<RateLimit> {
None
}
fn deployments<'a>(
&'a self,
_repo: &'a RepoRef,
_git_ref: &'a str,
) -> BoxFuture<'a, Result<Vec<Deployment>>> {
unsupported("deployments")
}
fn environments<'a>(&'a self, _repo: &'a RepoRef) -> BoxFuture<'a, Result<Vec<Deployment>>> {
unsupported("environments")
}
}
#[derive(Debug, Clone, Copy)]
pub struct Pace {
pub slow_below: f64,
pub max_wait: Duration,
}
impl Default for Pace {
fn default() -> Self {
Self {
slow_below: 0.1,
max_wait: Duration::from_secs(30),
}
}
}
impl Pace {
pub fn delay(&self, rl: &RateLimit, now: u64) -> Duration {
let left = rl.reset.saturating_sub(now);
let wait = if rl.remaining == 0 {
left.saturating_add(1) as f64
} else if rl.limit == 0 || f64::from(rl.remaining) / f64::from(rl.limit) >= self.slow_below
{
return Duration::ZERO;
} else {
left as f64 / f64::from(rl.remaining + 1)
};
Duration::from_secs_f64(wait).min(self.max_wait)
}
}