1 | require('lazy-ass');
|
2 | var check = require('check-more-types');
|
3 | var utils = require('./utils');
|
4 | var R = require('ramda');
|
5 | var _ = require('lodash');
|
6 | var Promise = require('bluebird');
|
7 | var debug = require('debug')('between');
|
8 |
|
9 | var reposApi = utils.github.repos;
|
10 | var getCommits = Promise.promisify(reposApi.getCommits);
|
11 |
|
12 | function getCommitsFrom(user, repo, latest, stop, previousCommits) {
|
13 | previousCommits = previousCommits || [];
|
14 | debug('commits %s/%s latest %s stop %s, previous number %d',
|
15 | user, repo, utils.shortenSha(latest), utils.shortenSha(stop),
|
16 | previousCommits.length);
|
17 |
|
18 | return getCommits({
|
19 | user: user,
|
20 | repo: repo,
|
21 | sha: latest
|
22 | }).then(function (commits) {
|
23 | debug('got %d new commits from %s to %s',
|
24 | commits.length,
|
25 | utils.shortenSha(R.head(commits).sha),
|
26 | utils.shortenSha(R.last(commits).sha)
|
27 | );
|
28 |
|
29 | var allCommits = previousCommits.length ? previousCommits.concat(commits.slice(1)) : commits;
|
30 | var fromIndex = _.findIndex(allCommits, 'sha', stop);
|
31 | if (fromIndex === -1) {
|
32 | if (commits.length === 1) {
|
33 | debug('fetched single commit %s, stopping', utils.shortenSha(commits[0].sha));
|
34 | return allCommits;
|
35 | }
|
36 |
|
37 | var last = R.last(allCommits).sha;
|
38 | console.log('could not find the stop commit, fetching more commits starting with %s', last);
|
39 |
|
40 | return Promise.delay(1).then(function () {
|
41 | return getCommitsFrom(user, repo, last, stop, allCommits);
|
42 | });
|
43 | } else {
|
44 | return allCommits;
|
45 | }
|
46 | });
|
47 | }
|
48 |
|
49 |
|
50 |
|
51 | function getCommitsBetween(options) {
|
52 | utils.verifyRepoOptions(options);
|
53 | var schema = {
|
54 | from: check.commitId,
|
55 | to: check.commitId
|
56 | };
|
57 | la(check.schema(schema, options), 'invalid from and to commits', options);
|
58 |
|
59 | return getCommitsFrom(options.user, options.repo, options.to, options.from)
|
60 | .then(function (commits) {
|
61 | la(check.array(commits), 'could not get list of commits', options);
|
62 | debug('found %d commits finishing with the latest commit %s',
|
63 | commits.length, utils.shortenSha(options.to));
|
64 |
|
65 | return R.map(function (commit) {
|
66 | return {
|
67 | sha: commit.sha,
|
68 | message: commit.commit.message
|
69 | }
|
70 | }, commits);
|
71 | }).then(function (commits) {
|
72 | var fromIndex = _.findIndex(commits, 'sha', options.from);
|
73 | debug('from commit %s is at index %d', options.from, fromIndex);
|
74 |
|
75 |
|
76 |
|
77 |
|
78 | return _.slice(commits, 0, fromIndex);
|
79 | });
|
80 | }
|
81 |
|
82 | function getCommitComment(options, id) {
|
83 | la(check.commitId(id), 'missing commit id', arguments);
|
84 | var get = Promise.promisify(reposApi.getCommit);
|
85 | debug('loading commit for %s/%s sha %s', options.user, options.repo, id);
|
86 |
|
87 | return get({
|
88 | user: options.user,
|
89 | repo: options.repo,
|
90 | sha: id
|
91 | }).then(R.prop('commit'))
|
92 | .then(R.prop('message'));
|
93 | }
|
94 |
|
95 | function getComments(options, ids) {
|
96 | utils.verifyRepoOptions(options);
|
97 |
|
98 | ids = check.array(ids) ? ids : [ids];
|
99 | la(check.arrayOf(check.commitId, ids), 'expected list of commit ids', ids);
|
100 |
|
101 | var getComment = R.partial(getCommitComment, options);
|
102 |
|
103 | return Promise.all(
|
104 | ids.map(getComment)
|
105 | , { concurrency: 2 });
|
106 | }
|
107 |
|
108 | var Report = require('./report');
|
109 | var areValidOptions = check.schema.bind(null, {
|
110 | user: check.unemptyString,
|
111 | repo: check.unemptyString,
|
112 | from: check.commitId,
|
113 | to: check.commitId
|
114 | });
|
115 |
|
116 | function getCommentsBetweenCommits(options) {
|
117 | la(areValidOptions(options), 'bad options', options);
|
118 | var report = new Report(options);
|
119 |
|
120 | return getCommitsBetween(options)
|
121 | .tap(function (commits) {
|
122 | report.ids = _.pluck(commits, 'sha');
|
123 | report.comments = _.pluck(commits, 'message');
|
124 | })
|
125 | |
126 |
|
127 |
|
128 |
|
129 |
|
130 | .then(R.always(report));
|
131 | }
|
132 |
|
133 |
|
134 | module.exports = getCommentsBetweenCommits;
|
135 |
|
136 | if (!module.parent) {
|
137 |
|
138 | function smallNumberOfCommitsExample() {
|
139 | var options = {
|
140 | user: 'bahmutov',
|
141 | repo: 'next-update',
|
142 | from: '627250039b89fba678f57f428ee9151c370d4dad',
|
143 | to: '3d2b1fa3523c0be35ecfb30d4c81407fd4ce30a6'
|
144 | };
|
145 | getCommentsBetweenCommits(options)
|
146 | .tap(function (report) {
|
147 | la(check.object(report), 'did not get a report', report);
|
148 | report.print();
|
149 | });
|
150 | }
|
151 |
|
152 | function largeNumberOfCommitsExample() {
|
153 | var options = {
|
154 | user: 'chalk',
|
155 | repo: 'chalk',
|
156 | from: 'b0a0e42bfe96f77e0ce273c87b910ccc9280bbeb',
|
157 | to: '994758f01293f1fdcf63282e9917cb9f2cfbdaac'
|
158 | };
|
159 | getCommentsBetweenCommits(options)
|
160 | .tap(function (report) {
|
161 | la(check.object(report), 'did not get a report', report);
|
162 | report.print();
|
163 | });
|
164 | }
|
165 |
|
166 | largeNumberOfCommitsExample();
|
167 | }
|