actions.rs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. use async_trait::async_trait;
  2. use reqwest::Client;
  3. use std::env;
  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 pr: 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(
  46. Client::new(),
  47. env::var("GITHUB_API_TOKEN").expect("Missing GITHUB_API_TOKEN"),
  48. );
  49. let mut context = Context::new();
  50. for Query { repo, queries } in &self.actions {
  51. let repository = Repository {
  52. full_name: repo.to_string(),
  53. };
  54. for QueryMap { name, query } in queries {
  55. match query.kind {
  56. github::QueryKind::List => {
  57. let issues_search_result = repository.get_issues(&gh, &query).await;
  58. match issues_search_result {
  59. Ok(issues) => {
  60. let issues_decorator: Vec<_> = issues
  61. .iter()
  62. .map(|issue| {
  63. let pr = if issue.pull_request.is_some() {
  64. // FIXME: link to PR.
  65. // We need to tweak PullRequestDetails for this
  66. "[has_pr] "
  67. } else {
  68. ""
  69. }
  70. .to_string();
  71. IssueDecorator {
  72. title: issue.title.clone(),
  73. number: issue.number,
  74. html_url: issue.html_url.clone(),
  75. pr,
  76. labels: issue
  77. .labels
  78. .iter()
  79. .map(|l| l.name.as_ref())
  80. .collect::<Vec<_>>()
  81. .join(", "),
  82. assignees: issue
  83. .assignees
  84. .iter()
  85. .map(|u| u.login.as_ref())
  86. .collect::<Vec<_>>()
  87. .join(", "),
  88. }
  89. })
  90. .collect();
  91. context.insert(*name, &issues_decorator);
  92. }
  93. Err(err) => {
  94. eprintln!("ERROR: {}", err);
  95. err.chain()
  96. .skip(1)
  97. .for_each(|cause| eprintln!("because: {}", cause));
  98. std::process::exit(1);
  99. }
  100. }
  101. }
  102. github::QueryKind::Count => {
  103. let count = repository.get_issues_count(&gh, &query).await;
  104. match count {
  105. Ok(count) => {
  106. context.insert(*name, &count);
  107. }
  108. Err(err) => {
  109. eprintln!("ERROR: {}", err);
  110. err.chain()
  111. .skip(1)
  112. .for_each(|cause| eprintln!("because: {}", cause));
  113. std::process::exit(1);
  114. }
  115. }
  116. }
  117. };
  118. }
  119. }
  120. TEMPLATES
  121. .render(&format!("{}.tt", self.name), &context)
  122. .unwrap()
  123. }
  124. }