actions.rs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. use std::collections::HashMap;
  2. use async_trait::async_trait;
  3. use reqwest::Client;
  4. use tera::{Context, Tera};
  5. use crate::github::{self, GithubClient, Repository};
  6. #[async_trait]
  7. pub trait Action {
  8. async fn call(&self) -> String;
  9. }
  10. pub struct Step<'a> {
  11. pub name: &'a str,
  12. pub actions: Vec<Query<'a>>,
  13. }
  14. pub struct Query<'a> {
  15. pub repo: &'a str,
  16. pub queries: Vec<QueryMap<'a>>,
  17. }
  18. pub struct QueryMap<'a> {
  19. pub name: &'a str,
  20. pub query: github::Query<'a>,
  21. }
  22. #[derive(serde::Serialize)]
  23. pub struct IssueDecorator {
  24. pub number: u64,
  25. pub title: String,
  26. pub html_url: String,
  27. pub repo_name: String,
  28. pub labels: String,
  29. pub assignees: String,
  30. }
  31. lazy_static! {
  32. pub static ref TEMPLATES: Tera = {
  33. match Tera::new("templates/*") {
  34. Ok(t) => t,
  35. Err(e) => {
  36. println!("Parsing error(s): {}", e);
  37. ::std::process::exit(1);
  38. }
  39. }
  40. };
  41. }
  42. #[async_trait]
  43. impl<'a> Action for Step<'a> {
  44. async fn call(&self) -> String {
  45. let gh = GithubClient::new_with_default_token(Client::new());
  46. let mut context = Context::new();
  47. let mut results = HashMap::new();
  48. for Query { repo, queries } in &self.actions {
  49. let repository = Repository {
  50. full_name: repo.to_string(),
  51. };
  52. for QueryMap { name, query } in queries {
  53. match query.kind {
  54. github::QueryKind::List => {
  55. let issues_search_result = repository.get_issues(&gh, &query).await;
  56. match issues_search_result {
  57. Ok(issues) => {
  58. let issues_decorator: Vec<_> = issues
  59. .iter()
  60. .map(|issue| IssueDecorator {
  61. title: issue.title.clone(),
  62. number: issue.number,
  63. html_url: issue.html_url.clone(),
  64. repo_name: repository
  65. .full_name
  66. .split("/")
  67. .last()
  68. .expect("Failed to split repository name")
  69. .to_string(),
  70. labels: issue
  71. .labels
  72. .iter()
  73. .map(|l| l.name.as_ref())
  74. .collect::<Vec<_>>()
  75. .join(", "),
  76. assignees: issue
  77. .assignees
  78. .iter()
  79. .map(|u| u.login.as_ref())
  80. .collect::<Vec<_>>()
  81. .join(", "),
  82. })
  83. .collect();
  84. results
  85. .entry(*name)
  86. .or_insert(Vec::new())
  87. .extend(issues_decorator);
  88. }
  89. Err(err) => {
  90. eprintln!("ERROR: {}", err);
  91. err.chain()
  92. .skip(1)
  93. .for_each(|cause| eprintln!("because: {}", cause));
  94. std::process::exit(1);
  95. }
  96. }
  97. }
  98. github::QueryKind::Count => {
  99. let count = repository.get_issues_count(&gh, &query).await;
  100. match count {
  101. Ok(count) => {
  102. context.insert(*name, &count);
  103. }
  104. Err(err) => {
  105. eprintln!("ERROR: {}", err);
  106. err.chain()
  107. .skip(1)
  108. .for_each(|cause| eprintln!("because: {}", cause));
  109. std::process::exit(1);
  110. }
  111. }
  112. }
  113. };
  114. }
  115. }
  116. for (name, issues) in &results {
  117. context.insert(*name, issues);
  118. }
  119. TEMPLATES
  120. .render(&format!("{}.tt", self.name), &context)
  121. .unwrap()
  122. }
  123. }