1pub mod author;
2pub mod commits;
3pub mod repos;
4pub mod url;
5#[derive(Debug)]
9pub enum Error {
10 ReqwestError(reqwest::Error),
11 EnvError(std::env::VarError),
12}
13
14pub struct Client {
18 token: String,
19}
20
21pub struct Owner {
25 service: String,
26 username: String,
27}
28
29impl Client {
30 pub fn new_from_env() -> Result<Client, Error> {
31 let token = match std::env::var("CODECOV_OWNER_TOKEN") {
32 Ok(token) => token,
33 Err(e) => return Err(Error::EnvError(e)),
34 };
35 Ok(Client::new(token))
36 }
37
38 pub fn new(token: String) -> Client {
39 Client { token }
40 }
41
42 fn auth_header_val(&self) -> String {
43 format!("bearer {}", self.token)
44 }
45
46 fn owner_endpoint(&self, owner: &Owner) -> String {
47 format!(
48 "{}/{}/{}",
49 "https://codecov.io/api/v2", owner.service, owner.username
50 )
51 }
52
53 pub fn get_all_repos(&self, owner: &Owner) -> Result<Vec<repos::Repo>, Error> {
59 let mut repos = Vec::new();
60 let mut url = format!("{}/repos?page_size=100", self.owner_endpoint(owner));
61 loop {
62 let mut repo_list = self.get_repos_page(&url)?;
63 match &mut repo_list {
64 repos::ReposAPIResponse {
65 results,
66 next: Some(next_url),
67 ..
68 } => {
69 repos.append(results);
70 url = next_url.to_string();
71 continue;
72 }
73 repos::ReposAPIResponse {
74 results,
75 next: None,
76 ..
77 } => {
78 repos.append(results);
79 break;
80 }
81 }
82 }
83 Ok(repos)
84 }
85
86 fn get_repos_page(&self, url: &str) -> Result<repos::ReposAPIResponse, Error> {
91 let client = reqwest::blocking::Client::new();
92 let req = client
93 .get(url)
94 .header("Authorization", self.auth_header_val());
95 let res = match req.send() {
96 Ok(res) => res,
97 Err(e) => return Err(Error::ReqwestError(e)),
98 };
99 let repos = match res.json::<repos::ReposAPIResponse>() {
100 Ok(repos) => repos,
101 Err(e) => return Err(Error::ReqwestError(e)),
102 };
103 Ok(repos)
104 }
105
106 pub fn get_commits(
107 &self,
108 author: &author::Author,
109 ) -> Result<commits::CommitsAPIResponse, Error> {
110 let client = reqwest::blocking::Client::new();
111 let owner_endpoint = self.owner_endpoint(&Owner {
112 service: author.service.clone(),
113 username: author.username.clone(),
114 });
115 let url = format!("{}/repos/{}/commits", owner_endpoint, author.name,);
116 let req = client
117 .get(url)
118 .header("Authorization", self.auth_header_val());
119 let res = match req.send() {
120 Ok(res) => res,
121 Err(e) => return Err(Error::ReqwestError(e)),
122 };
123 let commits = match res.json::<commits::CommitsAPIResponse>() {
124 Ok(commits) => commits,
125 Err(e) => return Err(Error::ReqwestError(e)),
126 };
127 Ok(commits)
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn test_get_all_repos() {
137 let client = Client::new_from_env().unwrap();
138 let owner = Owner {
139 service: "github".to_string(),
140 username: "codecov".to_string(),
141 };
142 let repos = client.get_all_repos(&owner).unwrap();
143 assert!(!repos.is_empty());
144 }
145
146 #[test]
147 fn test_get_commits() {
148 let client = Client::new_from_env().unwrap();
149 let author = author::Author {
150 service: "github".to_string(),
151 username: "codecov".to_string(),
152 name: "codecov-demo".to_string(),
153 };
154 let commits = client.get_commits(&author).unwrap();
155 assert!(!commits.results.is_empty());
156 }
157}