Skip to content
This repository was archived by the owner on Jun 8, 2023. It is now read-only.

Commit 40e738a

Browse files
author
Tom Bell
committed
Merge pull request #940 from exalted/semaphoreapp
Integration with Semaphore (semaphoreapp.com)
2 parents 23d33b2 + 058f8d3 commit 40e738a

File tree

1 file changed

+191
-0
lines changed

1 file changed

+191
-0
lines changed

src/scripts/semaphoreapp.coffee

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
# Description
2+
# Integration with Semaphore (semaphoreapp.com)
3+
#
4+
# Dependencies:
5+
# None
6+
#
7+
# Configuration:
8+
# HUBOT_SEMAPHOREAPP_TRIGGER
9+
# Comma-separated list of additional keywords that will trigger
10+
# this script (e.g., "build")
11+
#
12+
# HUBOT_SEMAPHOREAPP_AUTH_TOKEN
13+
# Your authentication token for Semaphore API
14+
#
15+
# HUBOT_SEMAPHOREAPP_NOTIFY_RULES
16+
# Comma-separated list of rules. A rule consists of a room and an
17+
# *optional* regular expression separated with a colon (i.e., ':').
18+
# Right-hand side of a rule is to match branch names, so you can do things
19+
# like notifying "The Serious Room" for master branch, and discard all other
20+
# notifications. If you omit right-hand side of a rule then room will
21+
# be notified for any branch.
22+
#
23+
# Note: If you're using the built-in Campfire adapter then a "room" would be
24+
# one of the Campfire room ids configured in HUBOT_CAMPFIRE_ROOMS.
25+
#
26+
# Examples:
27+
#
28+
# "The Internal Room"
29+
# => Notifications of any branch go to "The Internal Room".
30+
#
31+
# "The Serious Room:master"
32+
# => Notifications of master branch go to "The Serious Room",
33+
# notifications of other branches will be discarded.
34+
#
35+
# "The Serious Room:master,The Internal Room:(?!master).*"
36+
# => Notifications of master branch go to "The Serious Room",
37+
# notifications of other branches go to "The Internal Room".
38+
#
39+
# "The Developers Room:.*(test|experiment).*"
40+
# => Notifications of branches that contain "test" or "experiment"
41+
# go to "The Developers Room", notifications of other branches
42+
# will be discarded.
43+
#
44+
# Commands:
45+
# hubot semaphoreapp status [<project> [<branch>]] - Reports build status for projects' branches
46+
#
47+
# URLs:
48+
# POST /hubot/semaphoreapp
49+
# First, read http://docs.semaphoreapp.com/webhooks, then your URL to
50+
# receive the payload would be "<HUBOT_URL>:<PORT>/hubot/semaphoreapp"
51+
# or if you deployed Hubot onto Heroku: "<HEROKU_URL>/hubot/semaphoreapp".
52+
#
53+
# Author:
54+
# exalted
55+
56+
module.exports = (robot) ->
57+
if process.env.HUBOT_SEMAPHOREAPP_TRIGGER
58+
trigger = process.env.HUBOT_SEMAPHOREAPP_TRIGGER.split(',').join('|')
59+
60+
robot.respond new RegExp("(?:semaphoreapp|#{trigger})\\s+status(?:\\s+(\\S+)(?:\\s+(\\S+))?)?\\s*$", "i"), (msg) ->
61+
semaphoreapp = new SemaphoreApp msg
62+
63+
# Read parameters
64+
projectName = msg.match[1]
65+
branchName = msg.match[2]
66+
67+
semaphoreapp.getListOfAllProjects (projects) ->
68+
unless projects.length > 0
69+
msg.reply "I don't know anything really. Sorry. :cry:"
70+
return
71+
72+
# unless projectName
73+
# # TODO recall project name for current user
74+
unless branchName
75+
branchName = "master"
76+
77+
unless projectName
78+
if projects.length > 1
79+
names = (x.name for x in projects)
80+
msg.reply "I want to do so many things, trying to decide, but... :sweat: How about #{tellEitherOneOfThese names} instead?"
81+
return
82+
else
83+
project = projects[0]
84+
85+
unless project?
86+
x for x in projects when x.name is projectName
87+
for x in projects
88+
if x.name is projectName
89+
project = x
90+
break
91+
92+
unless project?
93+
if projects.length > 1
94+
names = (x.name for x in projects)
95+
butTellAlsoThis = "How about #{tellEitherOneOfThese names} instead?"
96+
else
97+
butTellAlsoThis = "Do you mean \"#{projects[0].name}\" perhaps? :wink:"
98+
99+
msg.reply "I don't know anything about \"#{projectName}\" project. Sorry. :cry: #{butTellAlsoThis}"
100+
return
101+
102+
# TODO remember last asked project name for current user
103+
104+
unless project.branches.length > 0
105+
msg.reply "I can't find no branches for \"#{projectName}\" project. Sorry. :cry:"
106+
return
107+
108+
for x in project.branches
109+
if x.branch_name is branchName
110+
branch = x
111+
break
112+
113+
unless branch?
114+
if project.branches.length > 1
115+
names = (x.branch_name for x in project.branches)
116+
butTellAlsoThis = "How about #{tellEitherOneOfThese names} instead?"
117+
else
118+
butTellAlsoThis = "Do you mean \"#{project.branches[0].branch_name}\" perhaps? :wink:"
119+
120+
msg.reply "I don't know anything about \"#{branchName}\" branch. Sorry. :cry: #{butTellAlsoThis}"
121+
return
122+
123+
msg.reply statusMessage branch
124+
125+
robot.router.post "/hubot/semaphoreapp", (req, res) ->
126+
unless process.env.HUBOT_SEMAPHOREAPP_NOTIFY_RULES
127+
message = "semaphoreapp hook warning: HUBOT_SEMAPHOREAPP_NOTIFY_RULES is empty."
128+
res.send(500, { error: message })
129+
console.log message
130+
return
131+
132+
try
133+
payload = req.body
134+
catch error
135+
message = "semaphoreapp hook error: #{error}. Payload: #{req.body}"
136+
res.send(400, message)
137+
console.log message
138+
return
139+
140+
res.send()
141+
142+
rules = process.env.HUBOT_SEMAPHOREAPP_NOTIFY_RULES.split(',')
143+
for rule in (x.split(':') for x in rules)
144+
room = rule[0]
145+
branch = rule[1]
146+
147+
try
148+
branchRegExp = new RegExp("^#{branch}$" if branch)
149+
catch error
150+
console.log "semaphoreapp error: #{error}."
151+
return
152+
153+
if branchRegExp.test(payload.branch_name)
154+
robot.messageRoom room, statusMessage payload
155+
156+
tellEitherOneOfThese = (things) ->
157+
"\"#{things[...-1].join('\", \"')}\" or \"#{things[-1..]}\""
158+
159+
statusEmoji = (status) ->
160+
switch status
161+
when "passed" then ":white_check_mark:"
162+
when "failed" then ":x:"
163+
when "pending" then ":warning:"
164+
165+
statusMessage = (branch) ->
166+
refSpec = "#{branch.project_name}/#{branch.branch_name}"
167+
result = "#{branch.result[0].toUpperCase() + branch.result[1..-1].toLowerCase()}"
168+
message = if branch.commit then " \"#{branch.commit.message.split(/\n/)[0]}\"" else ""
169+
authorName = if branch.commit then " - #{branch.commit.author_name}" else ""
170+
buildURL = "#{branch.build_url}"
171+
"#{statusEmoji branch.result} [#{refSpec}] #{result}:#{message}#{authorName} (#{buildURL})"
172+
173+
class SemaphoreApp
174+
constructor: (msg) ->
175+
@msg = msg
176+
177+
getListOfAllProjects: (callback) ->
178+
unless process.env.HUBOT_SEMAPHOREAPP_AUTH_TOKEN
179+
@msg.reply "I am not allowed to access Semaphore APIs, sorry. :cry:"
180+
return
181+
182+
@msg.robot.http("https://semaphoreapp.com/api/v1/projects")
183+
.query(auth_token: "#{process.env.HUBOT_SEMAPHOREAPP_AUTH_TOKEN}")
184+
.get() (err, res, body) ->
185+
try
186+
json = JSON.parse body
187+
catch error
188+
console.log "semaphoreapp error: #{error}."
189+
@msg.reply "Semaphore is talking gibberish right now. Try again later?! :confused:"
190+
191+
callback json

0 commit comments

Comments
 (0)