scripts/phabs_commands.coffee
# Description:
# enable communication with Phabricator via Conduit api
#
# Dependencies:
#
# Configuration:
# PHABRICATOR_URL
# PHABRICATOR_API_KEY
#
# Commands:
# hubot phab version - give the version of hubot-phabs loaded
# hubot phab new <project>[:<template>] <name of the task> - creates a new task
# hubot phab paste <name of the paste> - creates a new paste
# hubot phab count <project> - counts how many tasks a project has
# hubot phab bl <id> - blacklists an id from phabs_hear
# hubot phab unbl <id> - removes an id from blacklist
# hubot phab Txx - gives information about task Txx
# hubot phab Txx + <some comment> - add a comment to task Txx
# hubot phab Txx in <project-tag> - add a tag to task Txx
# hubot phab Txx to [project:]<columns> - move task Txx to columns
# hubot phab Txx is <status> - modifies task Txx status
# hubot phab Txx is <priority> - modifies task Txx priority
# hubot phab assign Txx to <user> - assigns task Txx to comeone
# hubot phab Txx next [<key>] - outputs next checkbox found in task Txx
# hubot phab Txx prev [<key>] - outputs last checked checkbox found in task Txx
# hubot phab Txx check [<key>] - update task Txx description by checking a box
# hubot phab Txx uncheck [<key>] - update task Txx description by unchecking a box
# hubot phab user <user> - checks if user is known or not
# hubot phab me as <email> - makes caller known with <email>
# hubot phab user <user> = <email> - associates user to email
# hubot phab search [all] search terms - searches for terms in tasks ([all] to search non-open)
# hubot phab [all] <project> search terms - searches terms in project ([all] to search non-open)
# hubot phid <phid> - returns info about an arbitrary phid
#
# Author:
# mose
Phabricator = require '../lib/phabricator'
moment = require 'moment'
path = require 'path'
module.exports = (robot) ->
robot.phab ?= new Phabricator robot, process.env
phab = robot.phab
# hubot phab version - give the version of hubot-phabs loaded
robot.respond /ph(?:ab)? version *$/, (msg) ->
pkg = require path.join __dirname, '..', 'package.json'
msg.send "hubot-phabs module is version #{pkg.version}"
msg.finish()
# hubot phab new <project>[:<template>] <name of the task>
robot.respond (
/ph(?:ab)? new ([-_a-zA-Z0-9]+)(?::([-_a-zA-Z0-9]+))? ([^=]+)(?: = (.*))? *$/
), (msg) ->
data = {
project: msg.match[1]
template: msg.match[2]
title: msg.match[3]
description: msg.match[4]
user: msg.envelope.user
}
phab.getPermission(msg.envelope.user, 'phuser')
.then ->
phab.createTask(data)
.then (res) ->
phab.recordId res.user, res.id
msg.send "Task T#{res.id} created = #{res.url}"
.catch (e) ->
msg.send e
msg.finish()
# hubot phab paste <name of the paste> - creates a new paste
robot.respond /ph(?:ab)? paste (.*)$/, (msg) ->
title = msg.match[1]
phab.getPermission(msg.envelope.user, 'phuser')
.then ->
phab.createPaste(msg.envelope.user, title)
.then (id) ->
url = process.env.PHABRICATOR_URL + "/paste/edit/#{id}"
msg.send "Paste P#{id} created = edit on #{url}"
.catch (e) ->
msg.send e
msg.finish()
# hubot phab count <project> - counts how many tasks a project has
robot.respond (/ph(?:ab)? count ([-_a-zA-Z0-9]+) *$/), (msg) ->
project = msg.match[1]
name = null
phab.getProject(project)
.then (proj) ->
name = proj.data.name
phab.listTasks(proj.data.phid)
.then (body) ->
if Object.keys(body['result']).length is 0
msg.send "#{name} has no tasks."
else
msg.send "#{name} has #{Object.keys(body['result']).length} tasks."
.catch (e) ->
msg.send e
msg.finish()
# hubot phab bl <id> - blacklists <id> from auto-resopnses
robot.respond /ph(?:ab)? bl ((?:T|F|P|M|B|Q|L|V|D)(?:[0-9]+)|(?:r[A-Z]+[a-f0-9]{10,}))/, (msg) ->
phab.getPermission(msg.envelope.user, 'phuser')
.then ->
phab.blacklist msg.match[1]
msg.send "Ok. #{msg.match[1]} won't react anymore to auto-detection."
.catch (e) ->
msg.send e
msg.finish()
# hubot phab unbl <id> - blacklists <id> from auto-resopnses
robot.respond /ph(?:ab)? unbl ((?:T|F|P|M|B|Q|L|V|D)(?:[0-9]+)|(?:r[A-Z]+[a-f0-9]{10,}))/, (msg) ->
phab.getPermission(msg.envelope.user, 'phuser')
.then ->
phab.unblacklist msg.match[1]
msg.send "Ok. #{msg.match[1]} now will react to auto-detection."
.catch (e) ->
msg.send e
msg.finish()
# hubot phab Txx - gives information about task Txxx
robot.respond /ph(?:ab)?(?: T([0-9]+)| (last))? *$/, (msg) ->
what = msg.match[1] or msg.match[2]
id = null
body = null
phab.getId(msg.envelope.user, what)
.bind(id)
.bind(body)
.then (@id) ->
phab.getTask(@id)
.then (@body) ->
phab.getUserByPhid(@body.result.ownerPHID)
.then (owner) ->
status = @body.result.status
priority = @body.result.priority
title = @body.result.title
if @body.result.status is 'open'
ago = moment(@body.result.dateCreated, 'X').fromNow()
else
ago = moment(@body.result.dateModified, 'X').fromNow()
phab.recordId msg.envelope.user, @id
msg.send "T#{@id} - #{title} (#{status} #{ago}, #{priority}, owner #{owner})"
.catch (e) ->
msg.send e
msg.finish()
# hubot phab Txx + <some comment> - add a comment to task Txx
robot.respond /ph(?:ab)?(?: T([0-9]+)| (last))? \+ (.+) *$/, (msg) ->
what = msg.match[1] or msg.match[2]
comment = msg.match[3]
id = null
phab.getPermission(msg.envelope.user, 'phuser')
.then ->
phab.getId(msg.envelope.user, what)
.then (id) ->
phab.addComment(msg.envelope.user, id, comment)
.then (id) ->
msg.send "Ok. Added comment \"#{comment}\" to T#{id}."
.catch (e) ->
msg.send e
msg.finish()
# hubot phab Txx <status> - modifies task Txxx status
robot.respond new RegExp(
"ph(?:ab)?(?: T([0-9]+)| (last))? (?:is )?(#{Object.keys(phab.statuses).join('|')})" +
'(?: (?:=|\\+) (.+))? *$'
), (msg) ->
what = msg.match[1] or msg.match[2]
status = msg.match[3]
comment = msg.match[4]
phab.getPermission(msg.envelope.user, 'phuser')
.then ->
phab.getId(msg.envelope.user, what)
.then (id) ->
phab.doActions(msg.envelope.user, id, "is #{status}", comment)
.then (back) ->
if back.message? and back.message isnt ''
msg.send "Ok, T#{back.id} now has #{back.message}."
if back.notices.length > 0
for notice in back.notices
msg.send notice
.catch (e) ->
msg.send e
msg.finish()
# hubot phab Txx <priority> - modifies task Txxx priority
robot.respond new RegExp(
"ph(?:ab)?(?: T([0-9]+)| (last))? (?:is )?(#{Object.keys(phab.priorities).join('|')})" +
'(?: (?:=|\\+) (.+))? *$'
), (msg) ->
what = msg.match[1] or msg.match[2]
priority = msg.match[3]
comment = msg.match[4]
phab.getPermission(msg.envelope.user, 'phuser')
.then ->
phab.getId(msg.envelope.user, what)
.then (id) ->
phab.doActions(msg.envelope.user, id, "is #{priority}", comment)
.then (back) ->
if back.message? and back.message isnt ''
msg.send "Ok, T#{back.id} now has #{back.message}."
if back.notices.length > 0
for notice in back.notices
msg.send notice
.catch (e) ->
msg.send e
msg.finish()
robot.respond new RegExp(
'ph(?:ab)?(?: T([0-9]+)| (last))?((?:' +
' is [^ ]+|' +
' on [^ ]+|' +
' for [^ ]+|' +
' to [^ ]+|' +
' sub [^ ]+|' +
' unsub [^ ]+|' +
' in [^ ]+|' +
' not in [^ ]+)*)' +
'(?: (?:=|\\+) (.+))? *$'
), (msg) ->
what = msg.match[1] or msg.match[2]
commands = msg.match[3]
comment = msg.match[4]
phab.getPermission(msg.envelope.user, 'phuser')
.then ->
phab.getId(msg.envelope.user, what)
.then (id) ->
phab.doActions(msg.envelope.user, id, commands, comment)
.then (back) ->
if back.message? and back.message isnt ''
msg.send "Ok, T#{back.id} now has #{back.message}."
if back.notices.length > 0
for notice in back.notices
msg.send notice
.catch (e) ->
msg.send e
msg.finish()
# hubot phab Txx next [<key>]- outputs the next checkbox in a given task
robot.respond /ph(?:ab)?(?: T([0-9]+)| (last))? next(?: (.+))? *$/, (msg) ->
what = msg.match[1] or msg.match[2]
key = msg.match[3]
id = null
phab.getPermission(msg.envelope.user, 'phuser')
.bind(id)
.then ->
phab.getId(msg.envelope.user, what)
.then (@id) ->
phab.nextCheckbox(msg.envelope.user, @id, key)
.then (line) ->
msg.send "Next on T#{@id} is: #{line}"
.catch (e) ->
msg.send e
msg.finish()
# hubot phab Txx prev [<key>]- outputs the last checked checkbox in a given task
robot.respond /ph(?:ab)?(?: T([0-9]+)| (last))? prev(?:ious)?(?: (.+))? *$/, (msg) ->
what = msg.match[1] or msg.match[2]
key = msg.match[3]
id = null
phab.getPermission(msg.envelope.user, 'phuser')
.bind(id)
.then ->
phab.getId(msg.envelope.user, what)
.then (@id) ->
phab.prevCheckbox(msg.envelope.user, @id, key)
.then (line) ->
msg.send "Previous on T#{@id} is: #{line}"
.catch (e) ->
msg.send e
msg.finish()
# hubot phab Txx check [<key>] - update task Txx description by checking a box
robot.respond /ph(?:ab)?(?: T([0-9]+)| (last))? check(!)?(?: ([^\+]+))?(?: \+ (.+))? *$/, (msg) ->
what = msg.match[1] or msg.match[2]
withNext = msg.match[3]
key = msg.match[4]
comment = msg.match[5]
id = null
phab.getPermission(msg.envelope.user, 'phuser')
.bind(id)
.then ->
phab.getId(msg.envelope.user, what)
.then (@id) ->
phab.checkCheckbox(msg.envelope.user, @id, key, withNext, comment)
.then (line) ->
msg.send "Checked on T#{@id}: #{line[0]}"
if line[1]?
msg.send "Next on T#{@id}: #{line[1]}"
.catch (e) ->
msg.send e
msg.finish()
# hubot phab Txx uncheck [<key>] - update task Txx description by unchecking a box
robot.respond /ph(?:ab)?(?: T([0-9]+)| (last))? uncheck(!)?(?: ([^\+]+))?(?: \+ (.+))? *$/
, (msg) ->
what = msg.match[1] or msg.match[2]
withNext = msg.match[3]
key = msg.match[4]
comment = msg.match[5]
id = null
phab.getPermission(msg.envelope.user, 'phuser')
.bind(id)
.then ->
phab.getId(msg.envelope.user, what)
.then (@id) ->
phab.uncheckCheckbox(msg.envelope.user, @id, key, withNext, comment)
.then (line) ->
msg.send "Unchecked on T#{@id}: #{line[0]}"
if line[1]?
msg.send "Previous on T#{@id}: #{line[1]}"
.catch (e) ->
msg.send e
msg.finish()
# hubot phab user <user> - checks if user is known or not
robot.respond /ph(?:ab)? (?:user|who) ([^ ]*) *$/, (msg) ->
assignee = { name: msg.match[1] }
phab.getPermission(msg.envelope.user, 'phuser')
.then ->
phab.getUser(msg.envelope.user, assignee)
.then (userPhid) ->
msg.send "Hey I know #{assignee.name}, he's #{userPhid}"
.catch (e) ->
msg.send e
msg.finish()
# hubot phab me as <email> - makes caller known with <email>
robot.respond /ph(?:ab)? me as (.*@.*) *$/, (msg) ->
email = msg.match[1]
phab.getPermission(msg.envelope.user, 'phuser')
.then ->
msg.envelope.user.email_address = msg.match[1]
phab.getUser(msg.envelope.user, msg.envelope.user)
.then (userPhid) ->
msg.send "Now I know you, you are #{userPhid}"
.catch (e) ->
msg.send e
msg.finish()
# hubot phab user <user> = <email> - associates user to email
robot.respond /ph(?:ab)? user ([^ ]*) *?= *?([^ ]*@.*) *$/, (msg) ->
assignee = { name: msg.match[1], email_address: msg.match[2] }
phab.getPermission(msg.envelope.user, 'phuser')
.then ->
phab.getUser(msg.envelope.user, assignee)
.then (userPhid) ->
msg.send "Now I know #{assignee.name}, he's #{userPhid}"
.catch (e) ->
msg.send e
msg.finish()
# hubot phab [all] [limit] search <search terms> - searches for terms in project
robot.respond /ph(?:ab)?( all)?(?: (\d+))? search (.+)$/, (msg) ->
status = if msg.match[1]?
undefined
else
'open'
limit = msg.match[2] or 3
terms = msg.match[3]
phab.searchAllTask(terms, status, limit)
.then (payload) ->
if payload.result.data.length is 0
msg.send "There is no task matching '#{terms}'."
else
for task in payload.result.data
if task.fields.status.name is 'Open'
ago = moment(task.fields.dateCreated, 'X').fromNow()
else
ago = moment(task.fields.dateModified, 'X').fromNow()
msg.send "#{process.env.PHABRICATOR_URL}/T#{task.id} - #{task.fields['name']}" +
" (#{task.fields.status.name} #{ago})"
if payload.result.cursor.after?
msg.send '... and there is more.'
.catch (e) ->
msg.send e
msg.finish()
# hubot phab [all] [limit] <project> <search terms> - searches for terms in project
robot.respond /ph(?:ab)?( all)?(?: (\d+))? ([^ ]+) (.+)$/, (msg) ->
status = if msg.match[1]?
undefined
else
'open'
limit = msg.match[2] or 3
project = msg.match[3]
terms = msg.match[4]
name = null
phab.getProject(project)
.then (proj) ->
name = proj.data.name
phab.searchTask(proj.data.phid, terms, status, limit)
.then (payload) ->
if payload.result.data.length is 0
msg.send "There is no task matching '#{terms}' in project '#{name}'."
else
for task in payload.result.data
if task.fields.status.name is 'Open'
ago = moment(task.fields.dateCreated, 'X').fromNow()
else
ago = moment(task.fields.dateModified, 'X').fromNow()
msg.send "#{process.env.PHABRICATOR_URL}/T#{task.id} - #{task.fields['name']}" +
" (#{task.fields.status.name} #{ago})"
if payload.result.cursor.after?
msg.send '... and there is more.'
.catch (e) ->
msg.send e
msg.finish()
# hubot phid <phid> - returns info about an arbitrary phid
robot.respond /phid ([^ ]+) *$/, (msg) ->
item = msg.match[1]
if /^PHID-/.test item
phab.getPHID(item)
.then (data) ->
msg.send "#{item} is #{data.name} - #{data.uri} (#{data.status})"
.catch (e) ->
msg.send e
msg.finish()
else
phab.genericInfo(item)
.then (body) ->
if Object.keys(body.result).length < 1
msg.send "#{item} not found."
else
msg.send "#{item} is #{body.result[item].phid}"
.catch (e) ->
msg.send e
msg.finish()