Skip to content

Commit

Permalink
Add ability to control approved by tagging (#2)
Browse files Browse the repository at this point in the history
* Add ability to controll approved by tagging
  • Loading branch information
JustSnow authored Oct 15, 2020
1 parent 7707ef9 commit 5e994cf
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 74 deletions.
3 changes: 3 additions & 0 deletions gbot.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ unapproved:
24h: ":emoji1:"
12h: ":emoji2:"
default: ":emoji3:"
tag:
approvers: false
author: false
78 changes: 4 additions & 74 deletions tasks/Unapproved.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
const _ = require("lodash")

const timeUtils = require("../utils/time")

const BaseCommand = require("./BaseCommand")
const UnapprovedRequestDescription = require("./unapproved/UnapprovedRequestDescription")

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

return `${head}\n\n${list}`
} else {
Expand All @@ -35,40 +34,9 @@ class Unapproved extends BaseCommand {
}

__buildRequestDescription = request => {
const updated = new Date(request.updated_at)
const reaction = this.__getEmoji(updated)

const link = `[${request.title}](${request.web_url})`
const author = `@${request.author.username}`
const project = `[${request.project.name}](${request.project.web_url})`
const unresolvedAuthors = this.__unresolvedAuthorsString(request)
const approvedBy = this.__approvedByString(request)

let message = [`${reaction} **${link}** (${project}) by **${author}**`]

if (unresolvedAuthors.length > 0) {
message.push(`unresolved threads by: ${unresolvedAuthors}`)
}
if (approvedBy.length > 0) {
message.push(`already approved by: ${approvedBy}`)
}

return message.join("\n")
}

__getEmoji = lastUpdate => {
const emoji = _.get(this.config, "unapproved.emoji", {})
const interval = new Date().getTime() - lastUpdate.getTime()

const findEmoji = _.flow(
_.partialRight(_.toPairs),
_.partialRight(_.map, ([key, value]) => [timeUtils.parseInterval(key), value]),
_.partialRight(_.sortBy, ([time]) => -time),
_.partialRight(_.find, ([time]) => time < interval),
_.partialRight(_.last),
)
const descriptionBuilder = new UnapprovedRequestDescription(request, this.config)

return findEmoji(emoji) || emoji.default || ""
return descriptionBuilder.build()
}

__getUnapprovedRequests = projectId => this.__getExtendedRequests(projectId)
Expand Down Expand Up @@ -100,44 +68,6 @@ class Unapproved extends BaseCommand {
__appendDiscussions = (project, request) => this.gitlab
.discussions(project.id, request.iid)
.then(discussions => ({ ...request, discussions }))

__unresolvedAuthorsString = request => {
return this.__unresolvedAuthorsFor(request).map(author => {
return `@${author.username}`
}).join(", ")
}

__approvedByString = request => {
return request.approved_by.map(approve => {
const { user } = approve

return `@${user.username}`
}).join(", ")
}

__unresolvedAuthorsFor = request => {
const { discussions } = request

const userNames = _.flow(
_.partialRight(
_.filter,
discussion => discussion.notes.some(
note => note.resolvable && !note.resolved
)
),
_.partialRight(
_.map,
discussion => discussion.notes.map(note => note.author)
),
_.partialRight(_.flatten),
_.partialRight(
_.uniqBy,
author => author.username
),
)

return userNames(discussions)
}
}

module.exports = Unapproved
108 changes: 108 additions & 0 deletions tasks/unapproved/UnapprovedRequestDescription.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
const _ = require("lodash")
const timeUtils = require("../../utils/time")
const stringUtils = require("../../utils/strings")

class UnapprovedRequestDescription {
constructor(request, config) {
this.config = config
this.request = request
}

build = () => {
const updated = new Date(this.request.updated_at)
const reaction = this.__getEmoji(updated)

const link = `[${this.request.title}](${this.request.web_url})`
const author = this.__authorString()
const project = `[${this.request.project.name}](${this.request.project.web_url})`
const unresolvedAuthors = this.__unresolvedAuthorsString()
const approvedBy = this.__approvedByString()

let message = [`${reaction} **${link}** (${project}) by **${author}**`]

if (unresolvedAuthors.length > 0) {
message.push(`unresolved threads by: ${unresolvedAuthors}`)
}
if (approvedBy.length > 0) {
message.push(`already approved by: ${approvedBy}`)
}

return message.join("\n")
}

__getConfigSetting = (settingName, defaultValue = null) => {
return _.get(this.config, settingName, defaultValue)
}

__getEmoji = lastUpdate => {
const emoji = this.__getConfigSetting("unapproved.emoji", {})
const interval = new Date().getTime() - lastUpdate.getTime()

const findEmoji = _.flow(
_.partialRight(_.toPairs),
_.partialRight(_.map, ([key, value]) => [timeUtils.parseInterval(key), value]),
_.partialRight(_.sortBy, ([time]) => -time),
_.partialRight(_.find, ([time]) => time < interval),
_.partialRight(_.last),
)

return findEmoji(emoji) || emoji.default || ""
}

__unresolvedAuthorsString = () => {
return this.__unresolvedAuthorsFor(this.request).map(author => {
return `@${author.username}`
}).join(", ")
}

__approvedByString = () => {
const tagApprovers = this.__getConfigSetting("unapproved.tag.approvers", false)

return this.request.approved_by.map(approve => {
const { user } = approve
let message = `@${user.username}`

if (!tagApprovers) {
message = stringUtils.wrapString(message)
}

return message
}).join(", ")
}

__authorString = () => {
const tagAuthor = this.__getConfigSetting("unapproved.tag.author", false)
let message = `@${this.request.author.username}`

if (!tagAuthor) {
message = stringUtils.wrapString(message)
}
return message
}

__unresolvedAuthorsFor = () => {
const { discussions } = this.request

const userNames = _.flow(
_.partialRight(
_.filter,
discussion => discussion.notes.some(
note => note.resolvable && !note.resolved
)
),
_.partialRight(
_.map,
discussion => discussion.notes.map(note => note.author)
),
_.partialRight(_.flatten),
_.partialRight(
_.uniqBy,
author => author.username
),
)

return userNames(discussions)
}
}

module.exports = UnapprovedRequestDescription
7 changes: 7 additions & 0 deletions utils/strings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const wrapString = (string, wrapper = "`") => {
return `${wrapper}${string}${wrapper}`
}

module.exports = {
wrapString,
}

0 comments on commit 5e994cf

Please sign in to comment.