triage.rs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. use crate::handlers::Context;
  2. use chrono::{Duration, Utc};
  3. use hyper::{Body, Response, StatusCode};
  4. use serde::Serialize;
  5. use serde_json::value::{to_value, Value};
  6. use std::sync::Arc;
  7. use url::Url;
  8. const YELLOW_DAYS: i64 = 7;
  9. const RED_DAYS: i64 = 14;
  10. pub fn index() -> Result<Response<Body>, hyper::Error> {
  11. Ok(Response::builder()
  12. .header("Content-Type", "text/html")
  13. .status(StatusCode::OK)
  14. .body(Body::from(include_str!("../templates/triage/index.html")))
  15. .unwrap())
  16. }
  17. pub async fn pulls(
  18. ctx: Arc<Context>,
  19. owner: &str,
  20. repo: &str,
  21. ) -> Result<Response<Body>, hyper::Error> {
  22. let octocrab = &ctx.octocrab;
  23. let res = octocrab
  24. .pulls(owner, repo)
  25. .list()
  26. .sort(octocrab::params::pulls::Sort::Updated)
  27. .direction(octocrab::params::Direction::Ascending)
  28. .per_page(100)
  29. .send()
  30. .await;
  31. let mut page = match res {
  32. Ok(page) => page,
  33. Err(_) => {
  34. return Ok(Response::builder()
  35. .status(StatusCode::NOT_FOUND)
  36. .body(Body::from("The repository is not found."))
  37. .unwrap());
  38. }
  39. };
  40. let mut base_pulls = page.take_items();
  41. let mut next_page = page.next;
  42. while let Some(mut page) = octocrab
  43. .get_page::<octocrab::models::pulls::PullRequest>(&next_page)
  44. .await
  45. .unwrap()
  46. {
  47. base_pulls.extend(page.take_items());
  48. next_page = page.next;
  49. }
  50. let mut pulls: Vec<Value> = Vec::new();
  51. for base_pull in base_pulls.into_iter() {
  52. let assignee = base_pull.assignee.map_or("".to_string(), |v| v.login);
  53. let updated_at = base_pull
  54. .updated_at
  55. .map_or("".to_string(), |v| v.format("%Y-%m-%d").to_string());
  56. let yellow_line = Utc::now() - Duration::days(YELLOW_DAYS);
  57. let red_line = Utc::now() - Duration::days(RED_DAYS);
  58. let need_triage = match base_pull.updated_at {
  59. Some(updated_at) if updated_at <= red_line => "red".to_string(),
  60. Some(updated_at) if updated_at <= yellow_line => "yellow".to_string(),
  61. _ => "green".to_string(),
  62. };
  63. let days_from_last_updated_at = if let Some(updated_at) = base_pull.updated_at {
  64. (Utc::now() - updated_at).num_days()
  65. } else {
  66. (Utc::now() - base_pull.created_at.unwrap()).num_days()
  67. };
  68. let labels = base_pull.labels.map_or("".to_string(), |labels| {
  69. labels
  70. .iter()
  71. .map(|label| label.name.clone())
  72. .collect::<Vec<_>>()
  73. .join(", ")
  74. });
  75. let wait_for_author = labels.contains("S-waiting-on-author");
  76. let wait_for_review = labels.contains("S-waiting-on-review");
  77. let html_url = base_pull.html_url.unwrap();
  78. let number = base_pull.number;
  79. let title = base_pull.title.unwrap();
  80. let author = base_pull.user.unwrap().login;
  81. let pull = PullRequest {
  82. html_url,
  83. number,
  84. title,
  85. assignee,
  86. updated_at,
  87. need_triage,
  88. labels,
  89. author,
  90. wait_for_author,
  91. wait_for_review,
  92. days_from_last_updated_at,
  93. };
  94. pulls.push(to_value(pull).unwrap());
  95. }
  96. let mut context = tera::Context::new();
  97. context.insert("pulls", &pulls);
  98. context.insert("owner", &owner);
  99. context.insert("repo", &repo);
  100. let tera = tera::Tera::new("templates/triage/**/*").unwrap();
  101. let body = Body::from(tera.render("pulls.html", &context).unwrap());
  102. Ok(Response::builder()
  103. .header("Content-Type", "text/html")
  104. .status(StatusCode::OK)
  105. .body(body)
  106. .unwrap())
  107. }
  108. #[derive(Serialize)]
  109. struct PullRequest {
  110. pub html_url: Url,
  111. pub number: u64,
  112. pub title: String,
  113. pub assignee: String,
  114. pub updated_at: String,
  115. pub need_triage: String,
  116. pub labels: String,
  117. pub author: String,
  118. pub wait_for_author: bool,
  119. pub wait_for_review: bool,
  120. pub days_from_last_updated_at: i64,
  121. }