Files: fcd0394b609d327dce26b03dac5c0bb5b62e9915 / index.js
3623 bytesRaw
1 | var pull = require('pull-stream') |
2 | var paramap = require('pull-paramap') |
3 | var asyncMemo = require('asyncmemo') |
4 | var Issues = require('ssb-issues') |
5 | |
6 | function readNext(fn) { |
7 | var next |
8 | return function (end, cb) { |
9 | if (next) return next(end, cb) |
10 | fn(function (err, _next) { |
11 | if (err) return cb(err) |
12 | next = _next |
13 | next(null, cb) |
14 | }) |
15 | } |
16 | } |
17 | |
18 | module.exports = { |
19 | name: 'pull-requests', |
20 | version: '1.0.0', |
21 | manifest: { |
22 | get: 'async', |
23 | getRevs: 'async', |
24 | list: 'source' |
25 | }, |
26 | schemas: require('./lib/schemas'), |
27 | init: function (sbot) { |
28 | |
29 | var issues = Issues.init(sbot) |
30 | var getMsg = asyncMemo(sbot.get) |
31 | |
32 | var getPullReq = asyncMemo(function (id, cb) { |
33 | issues.get(id, function (err, issue) { |
34 | if (err) return cb(err) |
35 | var c = issue.msg.value.content |
36 | issue.baseRepo = c.repo |
37 | issue.baseBranch = c.branch |
38 | issue.headRepo = c.head_repo |
39 | issue.headBranch = c.head_branch |
40 | cb(null, issue) |
41 | }) |
42 | }) |
43 | |
44 | function getBranchLastUpdate(repoId, branch, lte, cb) { |
45 | // TODO: detect and skip updates from subsequent PR with same branch name |
46 | getMsg(repoId, function (err, msg) { |
47 | if (err) return cb(err) |
48 | var repoAuthor = msg.author |
49 | pull( |
50 | sbot.links({ |
51 | dest: repoId, |
52 | rel: 'repo', |
53 | values: true, |
54 | reverse: true |
55 | }), |
56 | pull.filter(function (link) { |
57 | return link.value.content.type == 'git-update' |
58 | }), |
59 | pull.map(function (link) { |
60 | return { |
61 | timestamp: link.value.timestamp, |
62 | rev: (link.value.content.refs || {})['refs/heads/' + branch] |
63 | } |
64 | }), |
65 | pull.filter(function (update) { |
66 | return update.rev |
67 | && (lte ? update.timestamp <= lte : true) |
68 | }), |
69 | pull.take(1), |
70 | pull.collect(function (err, links) { |
71 | cb(err, links && links[0]) |
72 | }) |
73 | ) |
74 | }) |
75 | } |
76 | |
77 | function getRevs(prId, cb) { |
78 | getPullReq(prId, function (err, pr) { |
79 | if (err) return cb(err) |
80 | // get the latest rev of the head branch before it was deleted or the |
81 | // PR closed |
82 | var lastTime = pr.open ? null : pr.updated_at |
83 | getBranchLastUpdate(pr.headRepo, pr.headBranch, lastTime, |
84 | function (err, headUpdate) { |
85 | if (err) return cb(err) |
86 | // get the rev of base when head was last updated |
87 | getBranchLastUpdate(pr.baseRepo, pr.baseBranch, |
88 | headUpdate && headUpdate.timestamp, function (err, baseUpdate) { |
89 | if (err) return cb(err) |
90 | cb(null, { |
91 | base: baseUpdate && baseUpdate.rev, |
92 | head: headUpdate && headUpdate.rev |
93 | }) |
94 | }) |
95 | }) |
96 | }) |
97 | } |
98 | |
99 | function listPullReqs(opts) { |
100 | opts = opts || {} |
101 | opts.type = 'pull-request' |
102 | return pull( |
103 | sbot.messagesByType(opts), |
104 | pull.unique('key'), |
105 | pull.filter(function (msg) { |
106 | return (!opts.repo || opts.repo == msg.value.content.repo) |
107 | && (!opts.headRepo || opts.headRepo == msg.value.content.head_repo) |
108 | && (!opts.author || opts.author == msg.value.author) |
109 | }), |
110 | paramap(function (msg, cb) { |
111 | getPullReq(msg.key, cb) |
112 | }, 8), |
113 | pull.filter(opts.open != null && function (pr) { |
114 | return pr.open == opts.open |
115 | }) |
116 | ) |
117 | } |
118 | |
119 | return { |
120 | deinit: issues.deinit, |
121 | get: getPullReq, |
122 | getRevs: getRevs, |
123 | list: listPullReqs |
124 | } |
125 | } |
126 | } |
127 |
Built with git-ssb-web