|
| 1 | +const _ = require("lodash") |
| 2 | + |
| 3 | +const timeUtils = require("../utils/time") |
| 4 | + |
| 5 | +const BaseCommand = require("./BaseCommand") |
| 6 | + |
| 7 | +class Unapproved extends BaseCommand { |
| 8 | + perform = () => { |
| 9 | + const promises = this.projects.map(this.__getUnapprovedRequests) |
| 10 | + |
| 11 | + return Promise.all(promises) |
| 12 | + .then(_.flatten) |
| 13 | + .then(requests => requests.sort((a, b) => new Date(a.updated_at) - new Date(b.updated_at))) |
| 14 | + .then(this.__buildMessage) |
| 15 | + .then(message => { |
| 16 | + this.logger.info("Sending message") |
| 17 | + this.logger.info(message) |
| 18 | + return message |
| 19 | + }) |
| 20 | + .then(this.messenger.send) |
| 21 | + } |
| 22 | + |
| 23 | + __buildMessage = requests => { |
| 24 | + const list = requests.map(this.__buildRequestDescription).join("\n") |
| 25 | + const head = `#### Hey, there is a couple of requests waiting for your review` |
| 26 | + |
| 27 | + return `${head}\n\n${list}` |
| 28 | + } |
| 29 | + |
| 30 | + __buildRequestDescription = request => { |
| 31 | + const updated = new Date(request.updated_at) |
| 32 | + const reaction = this.__getEmoji(updated) |
| 33 | + |
| 34 | + const link = `[${request.title}](${request.web_url})` |
| 35 | + const author = `@${request.author.username}` |
| 36 | + const project = `[${request.project.name}](${request.project.web_url})` |
| 37 | + |
| 38 | + return `${reaction} **${link}** (${project}) by **${author}**` |
| 39 | + } |
| 40 | + |
| 41 | + __getEmoji = lastUpdate => { |
| 42 | + const emoji = _.get(this.config, "unapproved.emoji", {}) |
| 43 | + const interval = new Date().getTime() - lastUpdate.getTime() |
| 44 | + |
| 45 | + const findEmoji = _.flow( |
| 46 | + _.partialRight(_.toPairs), |
| 47 | + _.partialRight(_.map, ([key, value]) => [timeUtils.parseInterval(key), value]), |
| 48 | + _.partialRight(_.sortBy, ([time]) => -time), |
| 49 | + _.partialRight(_.find, ([time]) => time < interval), |
| 50 | + _.partialRight(_.last), |
| 51 | + ) |
| 52 | + |
| 53 | + return findEmoji(emoji) || emoji.default || "" |
| 54 | + } |
| 55 | + |
| 56 | + __getUnapprovedRequests = projectId => this.__getExtendedRequests(projectId) |
| 57 | + .then(requests => requests.filter(req => { |
| 58 | + const isCompleted = !req.work_in_progress |
| 59 | + const isUnapproved = req.approvals_left > 0 |
| 60 | + const hasUnresolvedDiscussions = req.discussions.some(dis => { |
| 61 | + return dis.notes.some(note => note.resolvable && !note.resolved) |
| 62 | + }) |
| 63 | + return isCompleted && (isUnapproved || hasUnresolvedDiscussions) |
| 64 | + })) |
| 65 | + |
| 66 | + __getExtendedRequests = projectId => this.gitlab |
| 67 | + .project(projectId) |
| 68 | + .then(project => this.gitlab.requests(project.id).then(requests => { |
| 69 | + const promises = requests.map(request => this.__getExtendedRequest(project, request)) |
| 70 | + return Promise.all(promises) |
| 71 | + })) |
| 72 | + |
| 73 | + __getExtendedRequest = (project, request) => Promise.resolve(request) |
| 74 | + .then(req => this.__appendApprovals(project, req)) |
| 75 | + .then(req => this.__appendDiscussions(project, req)) |
| 76 | + .then(req => ({ ...req, project })) |
| 77 | + |
| 78 | + __appendApprovals = (project, request) => this.gitlab |
| 79 | + .approvals(project.id, request.iid) |
| 80 | + .then(approvals => ({ ...approvals, ...request })) |
| 81 | + |
| 82 | + __appendDiscussions = (project, request) => this.gitlab |
| 83 | + .discussions(project.id, request.iid) |
| 84 | + .then(discussions => ({ ...request, discussions })) |
| 85 | +} |
| 86 | + |
| 87 | +module.exports = Unapproved |
0 commit comments