github_analytics/pull_data/
mod.rs1use std::collections::HashMap;
2
3use chrono::{NaiveDateTime, Utc};
4use eyre::{eyre, Result};
5use serde_json::Value;
6
7use crate::api::*;
8use crate::models::*;
9
10pub async fn pull_data(start: u64) -> Result<HashMap<String, Vec<Interaction>>> {
20 let end = chrono::NaiveDateTime::from_timestamp_millis(chrono::Local::now().timestamp_millis())
22 .ok_or(eyre!("Could not create the end date"))?;
23 let start = end
25 .checked_sub_days(chrono::Days::new(start))
26 .ok_or(eyre!("Could not create the start date"))?;
27 let repos = vec![
29 ("sayajin-labs", "kakarot"),
30 ("keep-starknet-strange", "beerus"),
31 ("keep-starknet-strange", "garaga"),
32 ("keep-starknet-strange", "quaireaux"),
33 ("keep-starknet-strange", "poseidon-rs"),
34 ];
35 let token = std::env::var("GH_TOKEN").expect("Environment variable GH_TOKEN is not set");
37 let client = reqwest::Client::builder()
39 .user_agent("keep-starknet-strange")
40 .build()?;
41 let mut repos_info: HashMap<String, Vec<Interaction>> = HashMap::new();
43 for (owner, repo) in repos {
44 let prs_and_issues = gql_query(&client, &QUERY, &token, &owner, &repo).await?;
46 let mut infos = vec![];
48 parse_interaction(
50 prs_and_issues["data"]["repository"]["pullRequests"]["nodes"]
51 .as_array()
52 .ok_or(eyre!("Could not fetch the pull requests"))?,
53 &mut infos,
54 &start,
55 &end,
56 "pr".to_owned(),
57 &repo,
58 )?;
59
60 parse_interaction(
62 prs_and_issues["data"]["repository"]["issues"]["nodes"]
63 .as_array()
64 .ok_or(eyre!("Could not fetch the issues"))?,
65 &mut infos,
66 &start,
67 &end,
68 "issue".to_owned(),
69 &repo,
70 )?;
71 repos_info.insert(repo.to_owned(), infos);
72 }
73 Ok(repos_info)
74}
75
76fn parse_interaction(
87 interactions: &Vec<Value>,
88 target: &mut Vec<Interaction>,
89 start: &NaiveDateTime,
90 end: &NaiveDateTime,
91 interaction_type: String,
92 repo: &&str,
93) -> Result<()> {
94 for interaction in interactions {
95 let created_at = chrono::NaiveDateTime::parse_from_str(
97 interaction["createdAt"]
98 .as_str()
99 .ok_or(eyre!("Could not parse created_at"))?,
100 "%Y-%m-%dT%H:%M:%SZ",
101 )?;
102
103 let ended = if interaction_type == "pr" {
105 "mergedAt"
106 } else {
107 "closedAt"
108 };
109 let closed_at: Option<NaiveDateTime> = interaction[ended].as_str().map(|closed_at| {
111 chrono::NaiveDateTime::parse_from_str(closed_at, "%Y-%m-%dT%H:%M:%SZ").unwrap()
112 });
113 let time;
115 let mut inter = interaction_type.clone();
117
118 if created_at.ge(start) && created_at.lt(end) {
121 time = created_at.and_local_timezone(Utc).unwrap();
122 inter += " created";
123 } else if closed_at.is_some()
126 && (closed_at.unwrap().ge(start) && closed_at.unwrap().lt(end))
127 {
128 time = created_at.and_local_timezone(Utc).unwrap();
129 inter += " ended";
130 } else {
132 break;
133 }
134 let author = interaction["author"]["login"]
136 .as_str()
137 .ok_or(eyre!("Could not parse author"))?;
138 target.push(Interaction {
140 time,
141 author: author.to_string(),
142 interaction_type: inter,
143 repo: repo.to_string(),
144 });
145 }
146 Ok(())
147}