1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
use git2::Repository;
use slog::Logger;

use codealong::{AnalyzeOpts, Repo, RepoConfig};

use crate::client::Client;
use crate::cursor::Cursor;
use crate::error::*;
use crate::pull_request::PullRequest;
use crate::pull_request_analyzer::PullRequestAnalyzer;

pub struct PullRequestsAnalyzer<'client> {
    repo: Repository,
    config: RepoConfig,
    client: &'client Client,
    logger: Logger,
}

impl<'client> PullRequestsAnalyzer<'client> {
    pub fn new(
        repo: Repository,
        config: RepoConfig,
        client: &'client Client,
        parent_logger: &Logger,
    ) -> PullRequestsAnalyzer<'client> {
        PullRequestsAnalyzer {
            repo,
            logger: parent_logger.new(o!("repo" => config.repo.name.to_owned())),
            config,
            client,
        }
    }

    pub fn analyze(
        &self,
        opts: AnalyzeOpts,
    ) -> Result<impl Iterator<Item = Result<PullRequestAnalyzer>>> {
        let cursor = self.build_cursor(opts.clone());
        Ok(PullRequestsCursor {
            repo: &self.repo,
            cursor,
            config: &self.config,
            opts,
            logger: self.logger.clone(),
        })
    }

    pub fn guess_len(&self, opts: AnalyzeOpts) -> Result<usize> {
        if opts.since.is_some() {
            Ok(self.analyze(opts)?.count())
        } else {
            Ok(self
                .build_cursor(opts)
                .guess_len()
                .ok_or("error estimating count of pull requests")?)
        }
    }

    pub fn from_repo(repo: &Repo, client: &'client Client, logger: &Logger) -> Result<Self> {
        Ok(Self::new(repo.repository()?, repo.config(), client, logger))
    }

    fn build_cursor(&self, _opts: AnalyzeOpts) -> Cursor<PullRequest> {
        let url = format!(
            "https://api.github.com/repos/{}/pulls?state=all",
            self.config.repo.github_name.as_ref().unwrap()
        );
        Cursor::new(&self.client, &url, &self.logger)
    }
}

struct PullRequestsCursor<'client> {
    repo: &'client Repository,
    config: &'client RepoConfig,
    cursor: Cursor<'client, PullRequest>,
    opts: AnalyzeOpts,
    logger: Logger,
}

impl<'client> Iterator for PullRequestsCursor<'client> {
    type Item = Result<PullRequestAnalyzer<'client>>;

    fn next(&mut self) -> Option<Result<PullRequestAnalyzer<'client>>> {
        loop {
            let pr = self.cursor.next();
            match pr {
                None => break None,
                Some(pr) => {
                    if let Some(ref since) = self.opts.since {
                        if since > &pr.updated_at {
                            break None;
                        }
                    }

                    if !self.opts.ignore_unknown_authors
                        || self.config.config.is_github_login_known(&pr.user.login)
                    {
                        let analyzer =
                            PullRequestAnalyzer::new(&self.repo, pr, &self.config, &self.logger);
                        break Some(Ok(analyzer));
                    }
                }
            }
        }
    }
}