codealong_github/
pull_requests_analyzer.rs

1use git2::Repository;
2use slog::Logger;
3
4use codealong::{AnalyzeOpts, Repo, RepoConfig};
5
6use crate::client::Client;
7use crate::cursor::Cursor;
8use crate::error::*;
9use crate::pull_request::PullRequest;
10use crate::pull_request_analyzer::PullRequestAnalyzer;
11
12pub struct PullRequestsAnalyzer<'client> {
13    repo: Repository,
14    config: RepoConfig,
15    client: &'client Client,
16    logger: Logger,
17}
18
19impl<'client> PullRequestsAnalyzer<'client> {
20    pub fn new(
21        repo: Repository,
22        config: RepoConfig,
23        client: &'client Client,
24        parent_logger: &Logger,
25    ) -> PullRequestsAnalyzer<'client> {
26        PullRequestsAnalyzer {
27            repo,
28            logger: parent_logger.new(o!("repo" => config.repo.name.to_owned())),
29            config,
30            client,
31        }
32    }
33
34    pub fn analyze(
35        &self,
36        opts: AnalyzeOpts,
37    ) -> Result<impl Iterator<Item = Result<PullRequestAnalyzer>>> {
38        let cursor = self.build_cursor(opts.clone());
39        Ok(PullRequestsCursor {
40            repo: &self.repo,
41            cursor,
42            config: &self.config,
43            opts,
44            logger: self.logger.clone(),
45        })
46    }
47
48    pub fn guess_len(&self, opts: AnalyzeOpts) -> Result<usize> {
49        if opts.since.is_some() {
50            Ok(self.analyze(opts)?.count())
51        } else {
52            Ok(self
53                .build_cursor(opts)
54                .guess_len()
55                .ok_or("error estimating count of pull requests")?)
56        }
57    }
58
59    pub fn from_repo(repo: &Repo, client: &'client Client, logger: &Logger) -> Result<Self> {
60        Ok(Self::new(repo.repository()?, repo.config(), client, logger))
61    }
62
63    fn build_cursor(&self, _opts: AnalyzeOpts) -> Cursor<PullRequest> {
64        let url = format!(
65            "https://api.github.com/repos/{}/pulls?state=all",
66            self.config.repo.github_name.as_ref().unwrap()
67        );
68        Cursor::new(&self.client, &url, &self.logger)
69    }
70}
71
72struct PullRequestsCursor<'client> {
73    repo: &'client Repository,
74    config: &'client RepoConfig,
75    cursor: Cursor<'client, PullRequest>,
76    opts: AnalyzeOpts,
77    logger: Logger,
78}
79
80impl<'client> Iterator for PullRequestsCursor<'client> {
81    type Item = Result<PullRequestAnalyzer<'client>>;
82
83    fn next(&mut self) -> Option<Result<PullRequestAnalyzer<'client>>> {
84        loop {
85            let pr = self.cursor.next();
86            match pr {
87                None => break None,
88                Some(pr) => {
89                    if let Some(ref since) = self.opts.since {
90                        if since > &pr.updated_at {
91                            break None;
92                        }
93                    }
94
95                    if !self.opts.ignore_unknown_authors
96                        || self.config.config.is_github_login_known(&pr.user.login)
97                    {
98                        let analyzer =
99                            PullRequestAnalyzer::new(&self.repo, pr, &self.config, &self.logger);
100                        break Some(Ok(analyzer));
101                    }
102                }
103            }
104        }
105    }
106}