actions.rs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. use async_trait::async_trait;
  2. use reqwest::Client;
  3. use tera::{Context, Tera};
  4. use crate::github::{self, GithubClient, Repository};
  5. #[async_trait]
  6. pub trait Action {
  7. async fn call(&self) -> String;
  8. }
  9. pub struct Step<'a> {
  10. pub name: &'a str,
  11. pub actions: Vec<Query<'a>>,
  12. }
  13. pub struct Query<'a> {
  14. pub repo: &'a str,
  15. pub queries: Vec<QueryMap<'a>>,
  16. }
  17. pub struct QueryMap<'a> {
  18. pub name: &'a str,
  19. pub query: github::Query<'a>,
  20. }
  21. #[derive(serde::Serialize)]
  22. pub struct IssueDecorator {
  23. pub number: u64,
  24. pub title: String,
  25. pub html_url: String,
  26. pub repo_name: String,
  27. pub labels: String,
  28. pub assignees: String,
  29. }
  30. lazy_static! {
  31. pub static ref TEMPLATES: Tera = {
  32. match Tera::new("templates/*") {
  33. Ok(t) => t,
  34. Err(e) => {
  35. println!("Parsing error(s): {}", e);
  36. ::std::process::exit(1);
  37. }
  38. }
  39. };
  40. }
  41. // Group all the pending FCP for these teams
  42. pub const IN_PRE_FCP_COMPILER_TEAM: &str = "in_pre_fcp_compiler_team";
  43. pub const IN_PRE_FCP_RUST: &str = "in_pre_fcp_rust";
  44. pub const IN_PRE_FCP_FORGE: &str = "in_pre_fcp_forge";
  45. const PENDINGFCP: [&str; 3] = [IN_PRE_FCP_COMPILER_TEAM, IN_PRE_FCP_RUST, IN_PRE_FCP_FORGE];
  46. // Group all the FCP for these teams
  47. pub const IN_FCP_COMPILER_TEAM: &str = "in_fcp_compiler_team";
  48. pub const IN_FCP_RUST: &str = "in_fcp_rust";
  49. pub const IN_FCP_FORGE: &str = "in_fcp_forge";
  50. const THINGSINFCP: [&str; 3] = [IN_FCP_COMPILER_TEAM, IN_FCP_RUST, IN_FCP_FORGE];
  51. // Group all the Finalized FCP for these teams
  52. pub const FCP_FINISHED_COMPILER_TEAM: &str = "fcp_finished_compiler_team";
  53. pub const FCP_FINISHED_RUST: &str = "fcp_finished_rust";
  54. pub const FCP_FINISHED_FORGE: &str = "fcp_finished_forge";
  55. const FINALIZEDFCP: [&str; 3] = [
  56. FCP_FINISHED_COMPILER_TEAM,
  57. FCP_FINISHED_RUST,
  58. FCP_FINISHED_FORGE,
  59. ];
  60. #[async_trait]
  61. impl<'a> Action for Step<'a> {
  62. async fn call(&self) -> String {
  63. let gh = GithubClient::new_with_default_token(Client::new());
  64. let mut context = Context::new();
  65. let mut all_pending_fcp: Vec<(&str, Vec<IssueDecorator>)> = vec![];
  66. let mut all_things_in_fcp: Vec<(&str, Vec<IssueDecorator>)> = vec![];
  67. let mut all_finalized_fcp: Vec<(&str, Vec<IssueDecorator>)> = vec![];
  68. for Query { repo, queries } in &self.actions {
  69. let repository = Repository {
  70. full_name: repo.to_string(),
  71. };
  72. for QueryMap { name, query } in queries {
  73. match query.kind {
  74. github::QueryKind::List => {
  75. let issues_search_result = repository.get_issues(&gh, &query).await;
  76. match issues_search_result {
  77. Ok(issues) => {
  78. let issues_decorator: Vec<_> = issues
  79. .iter()
  80. .map(|issue| IssueDecorator {
  81. title: issue.title.clone(),
  82. number: issue.number,
  83. html_url: issue.html_url.clone(),
  84. repo_name: repository
  85. .full_name
  86. .split("/")
  87. .last()
  88. .expect("Failed to split repository name")
  89. .to_string(),
  90. labels: issue
  91. .labels
  92. .iter()
  93. .map(|l| l.name.as_ref())
  94. .collect::<Vec<_>>()
  95. .join(", "),
  96. assignees: issue
  97. .assignees
  98. .iter()
  99. .map(|u| u.login.as_ref())
  100. .collect::<Vec<_>>()
  101. .join(", "),
  102. })
  103. .collect();
  104. // group query results for multiline FCP and add them later
  105. if PENDINGFCP.contains(name) {
  106. all_pending_fcp.push(("in_pre_fcp", issues_decorator));
  107. } else if THINGSINFCP.contains(name) {
  108. all_things_in_fcp.push(("in_fcp", issues_decorator));
  109. } else if FINALIZEDFCP.contains(name) {
  110. all_finalized_fcp.push(("fcp_finished", issues_decorator));
  111. } else {
  112. context.insert(*name, &issues_decorator);
  113. }
  114. }
  115. Err(err) => {
  116. eprintln!("ERROR: {}", err);
  117. err.chain()
  118. .skip(1)
  119. .for_each(|cause| eprintln!("because: {}", cause));
  120. std::process::exit(1);
  121. }
  122. }
  123. }
  124. github::QueryKind::Count => {
  125. let count = repository.get_issues_count(&gh, &query).await;
  126. match count {
  127. Ok(count) => {
  128. context.insert(*name, &count);
  129. }
  130. Err(err) => {
  131. eprintln!("ERROR: {}", err);
  132. err.chain()
  133. .skip(1)
  134. .for_each(|cause| eprintln!("because: {}", cause));
  135. std::process::exit(1);
  136. }
  137. }
  138. }
  139. };
  140. }
  141. }
  142. // Add to a single template the aggregate of each group
  143. for (name, issue_decorator) in all_pending_fcp {
  144. context.insert(name, &issue_decorator);
  145. }
  146. for (name, issue_decorator) in all_things_in_fcp {
  147. context.insert(name, &issue_decorator);
  148. }
  149. for (name, issue_decorator) in all_finalized_fcp {
  150. context.insert(name, &issue_decorator);
  151. }
  152. TEMPLATES
  153. .render(&format!("{}.tt", self.name), &context)
  154. .unwrap()
  155. }
  156. }