All checks were successful
/ build (push) Successful in 1m4s
Forgejo has a limit of 5000 characters per mermaid graph. We started hitting this for some issues. Regenerate a somewhat simplified version of the subtree in this case which hopefully does not hit the same limit again.
187 lines
5 KiB
Rust
187 lines
5 KiB
Rust
use anyhow::Context as _;
|
|
|
|
pub type CommentId = u64;
|
|
|
|
pub struct BotCommentInfo {
|
|
pub body: String,
|
|
pub id: CommentId,
|
|
}
|
|
|
|
pub async fn make_bot_comment(
|
|
ctx: &crate::Context,
|
|
issue_number: u64,
|
|
) -> anyhow::Result<BotCommentInfo> {
|
|
let initial_message =
|
|
"_Please be patient, this issue is currently being integrated into the techtree..._";
|
|
|
|
let res = ctx
|
|
.forgejo
|
|
.issue_create_comment(
|
|
&ctx.owner,
|
|
&ctx.repo,
|
|
issue_number,
|
|
forgejo_api::structs::CreateIssueCommentOption {
|
|
body: initial_message.to_owned(),
|
|
updated_at: None,
|
|
},
|
|
)
|
|
.await?;
|
|
|
|
Ok(BotCommentInfo {
|
|
id: res.id.unwrap(),
|
|
body: initial_message.to_owned(),
|
|
})
|
|
}
|
|
|
|
pub async fn find_bot_comment(
|
|
ctx: &crate::Context,
|
|
issue_number: u64,
|
|
) -> anyhow::Result<Option<BotCommentInfo>> {
|
|
let mut comments = ctx
|
|
.forgejo
|
|
.issue_get_comments(
|
|
&ctx.owner,
|
|
&ctx.repo,
|
|
issue_number,
|
|
forgejo_api::structs::IssueGetCommentsQuery {
|
|
..Default::default()
|
|
},
|
|
)
|
|
.await
|
|
.context("Failed fetching comments for issue")?;
|
|
|
|
comments.sort_by_key(|comment| comment.created_at);
|
|
|
|
let maybe_bot_comment = comments
|
|
.iter()
|
|
.rev()
|
|
.find(|comment| comment.user.as_ref().unwrap().id == Some(-2));
|
|
|
|
Ok(maybe_bot_comment.map(|c| BotCommentInfo {
|
|
body: c.body.clone().unwrap_or("".to_owned()),
|
|
id: c.id.unwrap(),
|
|
}))
|
|
}
|
|
|
|
/// Find existing bot comment or create a new one.
|
|
///
|
|
/// Returns a tuple of the comment information and a boolean indicating whether the comment was
|
|
/// newly created.
|
|
pub async fn find_or_make_bot_comment(
|
|
ctx: &crate::Context,
|
|
issue_number: u64,
|
|
) -> anyhow::Result<(BotCommentInfo, bool)> {
|
|
if let Some(comment) = find_bot_comment(ctx, issue_number)
|
|
.await
|
|
.context("Failed to search for bot comment in issue")?
|
|
{
|
|
Ok((comment, false))
|
|
} else {
|
|
make_bot_comment(ctx, issue_number)
|
|
.await
|
|
.context("Failed to make new bot comment in issue")
|
|
.map(|c| (c, true))
|
|
}
|
|
}
|
|
|
|
pub async fn update_bot_comment(
|
|
ctx: &crate::Context,
|
|
id: CommentId,
|
|
new_body: String,
|
|
) -> anyhow::Result<()> {
|
|
ctx.forgejo
|
|
.issue_edit_comment(
|
|
&ctx.owner,
|
|
&ctx.repo,
|
|
id,
|
|
forgejo_api::structs::EditIssueCommentOption {
|
|
body: new_body,
|
|
updated_at: None,
|
|
},
|
|
)
|
|
.await
|
|
.context("Failed to update comment body")?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn update_bot_comment_from_subtree(
|
|
ctx: &crate::Context,
|
|
id: CommentId,
|
|
subtree: &crate::tree::Subtree<'_>,
|
|
hash: &str,
|
|
) -> anyhow::Result<()> {
|
|
let mut mermaid = subtree.to_mermaid(&ctx.repo_url.to_string(), false);
|
|
|
|
// When the mermaid graph gets too big, regenerate a simplified version.
|
|
if mermaid.len() > 4990 {
|
|
log::info!("Mermaid graph is too big, generating simplified version...");
|
|
mermaid = subtree.to_mermaid(&ctx.repo_url.to_string(), true);
|
|
}
|
|
|
|
let full_text = if mermaid.len() > 4990 {
|
|
format!(
|
|
r##"## Partial Techtree
|
|
_Sorry, the partial techtree is still too big to be displayed for this element..._
|
|
|
|
<small>Digest: {hash}; Last Updated: {timestamp}</small>"##,
|
|
timestamp = ctx.timestamp,
|
|
)
|
|
} else {
|
|
format!(
|
|
r##"## Partial Techtree
|
|
```mermaid
|
|
{mermaid}
|
|
```
|
|
|
|
<small>Digest: {hash}; Last Updated: {timestamp}</small>"##,
|
|
timestamp = ctx.timestamp,
|
|
)
|
|
};
|
|
|
|
update_bot_comment(&ctx, id, full_text).await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn remove_stale_label(ctx: &crate::Context, issue_number: u64) -> anyhow::Result<()> {
|
|
let labels = ctx
|
|
.forgejo
|
|
.issue_get_labels(&ctx.owner, &ctx.repo, issue_number)
|
|
.await
|
|
.context("Failed fetching issue labels")?;
|
|
|
|
let stale_label_id = labels
|
|
.iter()
|
|
.filter(|l| l.name.as_deref() == Some("Stale"))
|
|
.next()
|
|
.map(|l| l.id.unwrap());
|
|
|
|
if let Some(stale_label_id) = stale_label_id {
|
|
log::info!("Removing `Stale` label from issue #{issue_number}...");
|
|
|
|
let res = ctx
|
|
.forgejo
|
|
.issue_remove_label(
|
|
&ctx.owner,
|
|
&ctx.repo,
|
|
issue_number,
|
|
stale_label_id,
|
|
forgejo_api::structs::DeleteLabelsOption {
|
|
updated_at: Some(time::OffsetDateTime::now_utc()),
|
|
},
|
|
)
|
|
.await;
|
|
|
|
if let Err(e) = res {
|
|
// At the moment, the token for Forgejo Actions cannot remove issue labels.
|
|
// See https://codeberg.org/forgejo/forgejo/issues/2415
|
|
log::warn!(
|
|
"Failed to remove `Stale` label for #{issue_number}. This is a known Forgejo limitation at the moment... ({e})"
|
|
);
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|