Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da8a711a60 | ||
|
|
8cc6306728 | ||
|
|
13b7a94257 |
1 changed files with 44 additions and 35 deletions
|
|
@ -105,6 +105,18 @@ async fn fetch_json(
|
||||||
resp.json().await.ok()
|
resp.json().await.ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Map a Forgejo notification `subject.type` to a human-readable label.
|
||||||
|
/// Known values: "Pull", "Issue", "Commit", "Repository". Any unknown
|
||||||
|
/// type is passed through as-is so new Forgejo types degrade gracefully
|
||||||
|
/// rather than silently collapsing into a generic label.
|
||||||
|
fn notif_type_label(t: &str) -> &str {
|
||||||
|
match t {
|
||||||
|
"Pull" => "PR",
|
||||||
|
"Issue" => "issue",
|
||||||
|
other => other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Truncate a string to `max` bytes at a char boundary, appending `…` if cut.
|
/// Truncate a string to `max` bytes at a char boundary, appending `…` if cut.
|
||||||
fn truncate(s: &str, max: usize) -> String {
|
fn truncate(s: &str, max: usize) -> String {
|
||||||
if s.len() <= max {
|
if s.len() <= max {
|
||||||
|
|
@ -158,11 +170,7 @@ async fn format_notification(
|
||||||
.unwrap_or("")
|
.unwrap_or("")
|
||||||
.trim();
|
.trim();
|
||||||
|
|
||||||
let kind = match notif_type {
|
let kind = format!("comment on {}", notif_type_label(notif_type));
|
||||||
"Pull Request" => "comment on PR",
|
|
||||||
"Issue" => "comment on issue",
|
|
||||||
_ => "comment",
|
|
||||||
};
|
|
||||||
let mut out = format!(
|
let mut out = format!(
|
||||||
"[{kind}] {title}\nrepo: {repo}\nurl: {}\n\n{author}: {}\n",
|
"[{kind}] {title}\nrepo: {repo}\nurl: {}\n\n{author}: {}\n",
|
||||||
if comment_html_url.is_empty() { html_url } else { comment_html_url },
|
if comment_html_url.is_empty() { html_url } else { comment_html_url },
|
||||||
|
|
@ -174,40 +182,41 @@ async fn format_notification(
|
||||||
out
|
out
|
||||||
} else {
|
} else {
|
||||||
// Notification triggered by creation or state change of the subject.
|
// Notification triggered by creation or state change of the subject.
|
||||||
let subject = fetch_json(client, subject_api_url, token).await;
|
//
|
||||||
let author = subject
|
// Classification uses notif["subject"]["state"] directly — Forgejo
|
||||||
.as_ref()
|
// returns "open" / "closed" / "merged" here. We do NOT rely on
|
||||||
.and_then(|s| s["user"]["login"].as_str())
|
// fetching the PR/issue detail for `merged`:
|
||||||
.unwrap_or("?");
|
// - `subject.url` points to the *issues* endpoint, which returns
|
||||||
let body = subject
|
// `pull_request.merged`, not top-level `merged`.
|
||||||
.as_ref()
|
// - Forgejo API type is "Pull" / "Issue", never "Pull Request".
|
||||||
.and_then(|s| s["body"].as_str())
|
let notif_state = notif["subject"]["state"].as_str().unwrap_or("");
|
||||||
.unwrap_or("")
|
|
||||||
.trim();
|
|
||||||
let state = subject
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|s| s["state"].as_str())
|
|
||||||
.unwrap_or("");
|
|
||||||
let merged = subject
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|s| s["merged"].as_bool())
|
|
||||||
.unwrap_or(false);
|
|
||||||
|
|
||||||
let kind = match (notif_type, state, merged) {
|
let label = notif_type_label(notif_type);
|
||||||
("Pull Request", "closed", true) => "PR merged".to_owned(),
|
let kind = match notif_state {
|
||||||
("Pull Request", "closed", false) => "PR closed".to_owned(),
|
"merged" => format!("{label} merged"),
|
||||||
("Pull Request", _, _) => "new PR".to_owned(),
|
"closed" => format!("{label} closed"),
|
||||||
("Issue", "closed", _) => "issue closed".to_owned(),
|
"open" | "" => format!("new {label}"),
|
||||||
("Issue", _, _) => "new issue".to_owned(),
|
other => format!("{label}: {other}"),
|
||||||
_ => format!("new {notif_type}"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Fetch subject only for body/author on new (open) items — not
|
||||||
|
// worth an extra HTTP round-trip for already-closed/merged ones.
|
||||||
|
let is_open = notif_state == "open" || notif_state.is_empty();
|
||||||
let mut out = format!("[{kind}] {title}\nrepo: {repo}\nurl: {html_url}");
|
let mut out = format!("[{kind}] {title}\nrepo: {repo}\nurl: {html_url}");
|
||||||
if !body.is_empty() && !state.contains("closed") && !merged {
|
if is_open {
|
||||||
out.push_str(&format!(
|
let subject = fetch_json(client, subject_api_url, token).await;
|
||||||
"\n\n{author}: {}",
|
let author = subject
|
||||||
truncate(body, BODY_TRUNCATE)
|
.as_ref()
|
||||||
));
|
.and_then(|s| s["user"]["login"].as_str())
|
||||||
|
.unwrap_or("?");
|
||||||
|
let body = subject
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|s| s["body"].as_str())
|
||||||
|
.unwrap_or("")
|
||||||
|
.trim();
|
||||||
|
if !body.is_empty() {
|
||||||
|
out.push_str(&format!("\n\n{author}: {}", truncate(body, BODY_TRUNCATE)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue