Last active
January 26, 2020 20:04
-
-
Save joegaudet/18b4020082e8b7ef0861c2ee30e76de7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "foodee-slack-jira", | |
"version": "1.0.0", | |
"description": "", | |
"main": "index.js", | |
"scripts": { | |
"test": "echo \"Error: no test specified\" && exit 1" | |
}, | |
"author": "", | |
"license": "ISC", | |
"dependencies": { | |
"async-redis": "^1.1.7", | |
"body-parser": "^1.19.0", | |
"express": "^4.17.1", | |
"jira-connector": "^2.16.1", | |
"redis": "^2.8.0", | |
"slack": "^11.0.2" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
web: node index.js |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Infra | |
const express = require('express'); | |
const bodyParser = require('body-parser'); | |
const app = express(); | |
app.use(bodyParser.json()); | |
app.use(bodyParser.urlencoded({extended: false})); | |
const port = process.env.PORT || 4000; | |
const redis = require('async-redis'); | |
const client = redis.createClient({url: process.env['REDIS_URL']}); | |
// Slack | |
const token = ''; | |
const Slack = require('slack'); | |
const bot = new Slack({token}); | |
// Jira | |
let jira; | |
const HOST = "foodee.atlassian.net"; | |
const PROJECT = 'DEV'; | |
const BUG_REPORTS_TESTING = ''; | |
const BUG_REPORTS = ''; | |
try { | |
const JiraClient = require("jira-connector"); | |
jira = new JiraClient({ | |
host: HOST, | |
basic_auth: { | |
email: "", | |
api_token: "" | |
} | |
}); | |
} catch (e) { | |
throw 'Could not connect to jira' | |
} | |
const BUG_FORM = { | |
title: 'Submit a bug', | |
submit_label: 'Submit', | |
callback_id: 'file_bug', | |
elements: [ | |
{ | |
type: 'text', | |
label: 'Summary', | |
name: 'summary' | |
}, | |
{ | |
type: 'select', | |
label: 'Severity', | |
name: 'priority', | |
value: 'Low', | |
placeholder: 'How severe is this issue', | |
options: [ | |
{ | |
label: 'Critical', | |
value: 'Highest' | |
}, | |
{ | |
label: 'High', | |
value: 'High' | |
}, | |
{ | |
label: 'Medium', | |
value: 'Medium' | |
}, | |
{ | |
label: 'Low', | |
value: 'Low' | |
}, | |
{ | |
label: 'Lowest', | |
value: 'Lowest' | |
}, | |
] | |
}, | |
{ | |
type: 'textarea', | |
label: 'Description', | |
name: 'description', | |
hint: 'Describe the issue in as much detail as possible' | |
}, | |
{ | |
type: 'text', | |
label: 'URL', | |
optional: true, | |
name: 'customfield_11215', | |
subtype: 'url' | |
}, | |
{ | |
type: 'text', | |
label: 'Order Number', | |
optional: true, | |
name: 'customfield_11216', | |
subtype: 'number' | |
}, | |
{ | |
type: 'select', | |
label: 'Affected User Type', | |
name: 'customfield_11217', | |
value: 'Client', | |
options: [ | |
{ | |
label: 'Client', | |
value: 'Client' | |
}, | |
{ | |
label: 'Restaurant', | |
value: 'Restaurant' | |
}, | |
{ | |
label: 'Internal', | |
value: 'Internal' | |
} | |
] | |
}, | |
{ | |
type: 'text', | |
label: 'Affected User ID', | |
hint: 'User/Client/Restaurant ID if applicable', | |
name: 'customfield_11218', | |
optional: true, | |
}, | |
{ | |
type: 'select', | |
label: 'Browser/Device', | |
name: 'customfield_11219', | |
options: [ | |
{ | |
label: 'StarFox - Chrome', | |
value: 'StarFox - Chrome' | |
}, | |
{ | |
label: 'SwiftFox - Chrome', | |
value: 'SwiftFox - Chrome' | |
}, | |
{ | |
label: 'SwiftFox - Internet Explorer', | |
value: 'SwiftFox - Internet Explorer' | |
}, | |
{ | |
label: 'SwiftFox - Safari', | |
value: 'SwiftFox - Safari' | |
}, | |
{ | |
label: 'SwiftFox - Phone (iOS/Android)', | |
value: 'SwiftFox - Phone (iOS/Android)', | |
}, | |
{ | |
label: 'FleetFox - iOS', | |
value: 'FleetFox - iOS', | |
}, | |
{ | |
label: 'FleetFox - Android', | |
value: 'FleetFox - Android', | |
}, | |
{ | |
label: 'Unknown', | |
value: 'Unknown', | |
} | |
] | |
} | |
], | |
labelFor(name) { | |
return this.elements.find(_ => _.name === name).label; | |
} | |
}; | |
async function put(key, object) { | |
return await client.set(key, JSON.stringify(object)); | |
} | |
async function get(key) { | |
const val = await client.get(key); | |
return val ? JSON.parse(val) : null; | |
} | |
app.post('/slack/commands/report-bug', async (req, res) => { | |
console.log('GET /slack/commands/report-bug'); | |
const {trigger_id} = req.body; | |
try { | |
console.log('Triggering bug report form'); | |
await bot.dialog.open({ | |
trigger_id: trigger_id, | |
dialog: BUG_FORM | |
}); | |
} catch (e) { | |
console.log(e) | |
} | |
res.end(); | |
}); | |
app.post('/slack/actions', async (req, res) => { | |
console.log('POST /slack/actions'); | |
const {callback_id, submission, user} = JSON.parse(req.body.payload); | |
if (callback_id === 'file_bug') { | |
console.log(submission); | |
const text = Object | |
.entries(submission) | |
.filter(([k, v]) => v !== null) | |
.map(([k, v]) => `> *${BUG_FORM.labelFor(k)}*: ${v}`) | |
.join('\n'); | |
console.log('Posting to bug room'); | |
const {channel, ts} = await bot.chat.postMessage({ | |
channel: BUG_REPORTS, | |
text, | |
link_names: 1, | |
mrkdwn: true | |
}); | |
const {permalink} = await bot.chat.getPermalink({channel, message_ts: ts}); | |
const userInfo = await bot.users.info({user: user.id}); | |
const userName = userInfo.user.real_name; | |
// TODO move this coercion to the DIALOG Constant | |
submission.priority = {name: submission.priority}; | |
submission.customfield_11216 = parseInt(submission.customfield_11216, 10); | |
submission.customfield_11218 = parseInt(submission.customfield_11218, 10); | |
submission.customfield_11217 = {value: submission.customfield_11217}; | |
submission.customfield_11219 = {value: submission.customfield_11219}; | |
console.log('Creating Jira Issue'); | |
const {key} = await jira.issue.createIssue({ | |
fields: Object.assign(submission, { | |
project: {key: PROJECT}, | |
issuetype: { | |
"name": "Bug" | |
}, | |
customfield_11223: userName, | |
customfield_11224: permalink | |
}) | |
}); | |
console.log('Posting to thread'); | |
await bot.chat.postMessage({ | |
channel, | |
text: `Thanks for reporting <@${user.id}> I've created issue <https://${HOST}/browse/${key}|${key}>. Please upload any screenshots you might find helpful.`, | |
thread_ts: ts, | |
link_names: 1 | |
} | |
); | |
await put(key, { | |
channel, | |
thread_ts: ts, | |
status: 'TODO', | |
priority: submission.priority.name | |
}); | |
} | |
res.send({}); | |
}); | |
app.get('/slack', (req, res) => { | |
console.log('GET /slack'); | |
res.send({}); | |
}); | |
app.post('/ping', (req, res) => { | |
console.log('POST /ping'); | |
res.send({message: 'pong'}); | |
}); | |
app.get('/', (req, res) => { | |
console.log('GET /'); | |
res.send({message: 'Hello from foodee bot'}); | |
}); | |
app.post('/jira/events', async (req, res) => { | |
console.log('POST /jira/events'); | |
if (req.body.webhookEvent === 'jira:issue_updated') { | |
const key = req.body.issue.key; | |
const storedIssue = (await get(key)) || {}; | |
const {channel, thread_ts} = storedIssue; | |
const {assignee, priority, status} = req.body.issue.fields; | |
if (assignee !== null && assignee.emailAddress !== storedIssue.assignee) { | |
storedIssue.assignee = assignee.emailAddress; | |
if (storedIssue.assignee) { | |
const {user: {id}} = await bot.users.lookupByEmail({email: storedIssue.assignee}); | |
if (channel && thread_ts) { | |
await bot.chat.postMessage({ | |
channel, | |
text: `<https://${HOST}/browse/${key}|${key}> assigned to <@${id}>`, | |
thread_ts, | |
link_names: 1 | |
} | |
); | |
try { | |
console.log(`Adding :investigating-issue: to ${thread_ts}`); | |
await bot.reactions.add({ | |
channel, | |
name: 'investigating-issue', | |
timestamp: thread_ts | |
} | |
); | |
} catch (e) { | |
console.log(e); | |
} | |
} | |
} | |
} | |
if (priority.name !== storedIssue.priority) { | |
storedIssue.priority = priority.name; | |
if (channel && thread_ts) { | |
await bot.chat.postMessage({ | |
channel, | |
text: `<https://${HOST}/browse/${key}|${key}> priority changed to: ${priority.name}`, | |
thread_ts, | |
link_names: 1 | |
} | |
); | |
} | |
} | |
if (status.name !== storedIssue.status) { | |
storedIssue.status = status.name; | |
if (channel && thread_ts) { | |
await bot.chat.postMessage({ | |
channel, | |
text: `<https://${HOST}/browse/${key}|${key}> status changed to: ${status.name}`, | |
thread_ts, | |
link_names: 1 | |
} | |
); | |
if (status.name === 'DONE') { | |
try { | |
await bot.reactions.add({ | |
channel, | |
name: 'white_check_mark', | |
timestamp: thread_ts | |
} | |
); | |
} catch (e) { | |
console.log(e); | |
} | |
} | |
} | |
} | |
put(key, storedIssue) | |
} | |
res.send({}); | |
} | |
); | |
app.listen(port, () => console.log(`Lady Bug Man listening on port ${port}!`)); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment