1use failure::{Error, ResultExt};
2use std::fmt::{self, Debug, Formatter};
3
4use config::GithubConfig;
5use utils::Paginated;
6use {Provider, Repo};
7
8#[derive(Clone)]
10pub struct GitHub {
11 cfg: GithubConfig,
12}
13
14impl GitHub {
15 pub fn with_config(cfg: GithubConfig) -> GitHub {
17 GitHub { cfg }
18 }
19
20 fn get_owned(&self) -> Result<Vec<Repo>, Error> {
21 debug!("Fetching owned repositories");
22
23 let mut owned = Vec::new();
24
25 for repo in Paginated::new(
26 self.cfg.api_key.reveal_str(),
27 "https://api.github.com/user/repos",
28 ) {
29 let repo: RawRepo = repo?;
30 owned.push(self.convert_repo(repo));
31 }
32
33 debug!("{} owned repos", owned.len());
34 Ok(owned)
35 }
36
37 fn get_starred(&self) -> Result<Vec<Repo>, Error> {
38 debug!("Fetching starred repositories");
39
40 let mut starred = Vec::new();
41
42 for repo in Paginated::new(
43 self.cfg.api_key.reveal_str(),
44 "https://api.github.com/user/starred",
45 ) {
46 let repo: RawRepo = repo?;
47 starred.push(self.convert_repo(repo));
48 }
49
50 debug!("{} starred repos", starred.len());
51 Ok(starred)
52 }
53
54 fn convert_repo(&self, raw: RawRepo) -> Repo {
55 Repo {
56 name: raw.name,
57 owner: raw.owner.login,
58 url: raw.clone_url,
59 provider: self.name().to_string(),
60 }
61 }
62}
63
64impl Provider for GitHub {
65 fn name(&self) -> &str {
66 "github"
67 }
68
69 fn repositories(&self) -> Result<Vec<Repo>, Error> {
70 let mut repos = Vec::new();
71
72 if self.cfg.owned {
73 repos.extend(
74 self.get_owned()
75 .context("Unable to fetch owned repositories")?,
76 );
77 }
78 if self.cfg.starred {
79 repos.extend(
80 self.get_starred()
81 .context("Unable to fetch starred repositories")?,
82 );
83 }
84
85 Ok(repos)
86 }
87}
88
89impl Debug for GitHub {
90 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
91 f.debug_struct("GitHub").finish()
92 }
93}
94
95#[derive(Debug, Clone, Default, Deserialize)]
96#[serde(default)]
97struct RawRepo {
98 name: String,
99 clone_url: String,
100 owner: Owner,
101}
102
103#[derive(Debug, Clone, Default, Deserialize)]
104#[serde(default)]
105struct Owner {
106 login: String,
107 #[serde(rename = "type")]
108 kind: String,
109}