Skip to content

Commit 5e994cf

Browse files
authored
Add ability to control approved by tagging (#2)
* Add ability to controll approved by tagging
1 parent 7707ef9 commit 5e994cf

File tree

4 files changed

+122
-74
lines changed

4 files changed

+122
-74
lines changed

gbot.example.yml

+3
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,6 @@ unapproved:
1616
24h: ":emoji1:"
1717
12h: ":emoji2:"
1818
default: ":emoji3:"
19+
tag:
20+
approvers: false
21+
author: false

tasks/Unapproved.js

+4-74
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
const _ = require("lodash")
22

3-
const timeUtils = require("../utils/time")
4-
53
const BaseCommand = require("./BaseCommand")
4+
const UnapprovedRequestDescription = require("./unapproved/UnapprovedRequestDescription")
65

76
class Unapproved extends BaseCommand {
87
perform = () => {
@@ -23,7 +22,7 @@ class Unapproved extends BaseCommand {
2322
__buildMessage = requests => {
2423
if (requests.length) {
2524
const list = requests.map(this.__buildRequestDescription).join("\n")
26-
const head = "#### Hey, there is a couple of requests waiting for your review"
25+
const head = "#### Hey, there are a couple of requests waiting for your review"
2726

2827
return `${head}\n\n${list}`
2928
} else {
@@ -35,40 +34,9 @@ class Unapproved extends BaseCommand {
3534
}
3635

3736
__buildRequestDescription = request => {
38-
const updated = new Date(request.updated_at)
39-
const reaction = this.__getEmoji(updated)
40-
41-
const link = `[${request.title}](${request.web_url})`
42-
const author = `@${request.author.username}`
43-
const project = `[${request.project.name}](${request.project.web_url})`
44-
const unresolvedAuthors = this.__unresolvedAuthorsString(request)
45-
const approvedBy = this.__approvedByString(request)
46-
47-
let message = [`${reaction} **${link}** (${project}) by **${author}**`]
48-
49-
if (unresolvedAuthors.length > 0) {
50-
message.push(`unresolved threads by: ${unresolvedAuthors}`)
51-
}
52-
if (approvedBy.length > 0) {
53-
message.push(`already approved by: ${approvedBy}`)
54-
}
55-
56-
return message.join("\n")
57-
}
58-
59-
__getEmoji = lastUpdate => {
60-
const emoji = _.get(this.config, "unapproved.emoji", {})
61-
const interval = new Date().getTime() - lastUpdate.getTime()
62-
63-
const findEmoji = _.flow(
64-
_.partialRight(_.toPairs),
65-
_.partialRight(_.map, ([key, value]) => [timeUtils.parseInterval(key), value]),
66-
_.partialRight(_.sortBy, ([time]) => -time),
67-
_.partialRight(_.find, ([time]) => time < interval),
68-
_.partialRight(_.last),
69-
)
37+
const descriptionBuilder = new UnapprovedRequestDescription(request, this.config)
7038

71-
return findEmoji(emoji) || emoji.default || ""
39+
return descriptionBuilder.build()
7240
}
7341

7442
__getUnapprovedRequests = projectId => this.__getExtendedRequests(projectId)
@@ -100,44 +68,6 @@ class Unapproved extends BaseCommand {
10068
__appendDiscussions = (project, request) => this.gitlab
10169
.discussions(project.id, request.iid)
10270
.then(discussions => ({ ...request, discussions }))
103-
104-
__unresolvedAuthorsString = request => {
105-
return this.__unresolvedAuthorsFor(request).map(author => {
106-
return `@${author.username}`
107-
}).join(", ")
108-
}
109-
110-
__approvedByString = request => {
111-
return request.approved_by.map(approve => {
112-
const { user } = approve
113-
114-
return `@${user.username}`
115-
}).join(", ")
116-
}
117-
118-
__unresolvedAuthorsFor = request => {
119-
const { discussions } = request
120-
121-
const userNames = _.flow(
122-
_.partialRight(
123-
_.filter,
124-
discussion => discussion.notes.some(
125-
note => note.resolvable && !note.resolved
126-
)
127-
),
128-
_.partialRight(
129-
_.map,
130-
discussion => discussion.notes.map(note => note.author)
131-
),
132-
_.partialRight(_.flatten),
133-
_.partialRight(
134-
_.uniqBy,
135-
author => author.username
136-
),
137-
)
138-
139-
return userNames(discussions)
140-
}
14171
}
14272

14373
module.exports = Unapproved
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
const _ = require("lodash")
2+
const timeUtils = require("../../utils/time")
3+
const stringUtils = require("../../utils/strings")
4+
5+
class UnapprovedRequestDescription {
6+
constructor(request, config) {
7+
this.config = config
8+
this.request = request
9+
}
10+
11+
build = () => {
12+
const updated = new Date(this.request.updated_at)
13+
const reaction = this.__getEmoji(updated)
14+
15+
const link = `[${this.request.title}](${this.request.web_url})`
16+
const author = this.__authorString()
17+
const project = `[${this.request.project.name}](${this.request.project.web_url})`
18+
const unresolvedAuthors = this.__unresolvedAuthorsString()
19+
const approvedBy = this.__approvedByString()
20+
21+
let message = [`${reaction} **${link}** (${project}) by **${author}**`]
22+
23+
if (unresolvedAuthors.length > 0) {
24+
message.push(`unresolved threads by: ${unresolvedAuthors}`)
25+
}
26+
if (approvedBy.length > 0) {
27+
message.push(`already approved by: ${approvedBy}`)
28+
}
29+
30+
return message.join("\n")
31+
}
32+
33+
__getConfigSetting = (settingName, defaultValue = null) => {
34+
return _.get(this.config, settingName, defaultValue)
35+
}
36+
37+
__getEmoji = lastUpdate => {
38+
const emoji = this.__getConfigSetting("unapproved.emoji", {})
39+
const interval = new Date().getTime() - lastUpdate.getTime()
40+
41+
const findEmoji = _.flow(
42+
_.partialRight(_.toPairs),
43+
_.partialRight(_.map, ([key, value]) => [timeUtils.parseInterval(key), value]),
44+
_.partialRight(_.sortBy, ([time]) => -time),
45+
_.partialRight(_.find, ([time]) => time < interval),
46+
_.partialRight(_.last),
47+
)
48+
49+
return findEmoji(emoji) || emoji.default || ""
50+
}
51+
52+
__unresolvedAuthorsString = () => {
53+
return this.__unresolvedAuthorsFor(this.request).map(author => {
54+
return `@${author.username}`
55+
}).join(", ")
56+
}
57+
58+
__approvedByString = () => {
59+
const tagApprovers = this.__getConfigSetting("unapproved.tag.approvers", false)
60+
61+
return this.request.approved_by.map(approve => {
62+
const { user } = approve
63+
let message = `@${user.username}`
64+
65+
if (!tagApprovers) {
66+
message = stringUtils.wrapString(message)
67+
}
68+
69+
return message
70+
}).join(", ")
71+
}
72+
73+
__authorString = () => {
74+
const tagAuthor = this.__getConfigSetting("unapproved.tag.author", false)
75+
let message = `@${this.request.author.username}`
76+
77+
if (!tagAuthor) {
78+
message = stringUtils.wrapString(message)
79+
}
80+
return message
81+
}
82+
83+
__unresolvedAuthorsFor = () => {
84+
const { discussions } = this.request
85+
86+
const userNames = _.flow(
87+
_.partialRight(
88+
_.filter,
89+
discussion => discussion.notes.some(
90+
note => note.resolvable && !note.resolved
91+
)
92+
),
93+
_.partialRight(
94+
_.map,
95+
discussion => discussion.notes.map(note => note.author)
96+
),
97+
_.partialRight(_.flatten),
98+
_.partialRight(
99+
_.uniqBy,
100+
author => author.username
101+
),
102+
)
103+
104+
return userNames(discussions)
105+
}
106+
}
107+
108+
module.exports = UnapprovedRequestDescription

utils/strings.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const wrapString = (string, wrapper = "`") => {
2+
return `${wrapper}${string}${wrapper}`
3+
}
4+
5+
module.exports = {
6+
wrapString,
7+
}

0 commit comments

Comments
 (0)