Hubot Phabricator Plugin
When installed this plugin will check the channels where the bot lurks, to see if someone is talking about Phabricator objects (T32 or P156 or F1526) to complement the conversation with the name of the referred item.
It also makes available some commands to interact directly with Phabricator items, like create a task, assign a task to a user. This is a work in progress and more commands will be added with time.
This plugin is used in production internally at Gandi since 2016-07-13.
Check the Changelog for a precise history of the versions.
In your hubot directory:
npm install hubot-phabs --save
Next you need to create a
bot user in Phabricator and grab its api key.
By default every action is usable by any user. But you can follow the optional permission system by using the
There are mainly 3 permissions groups:
admingroup, for which everything is permitted everywhere
phadmingroup, required for which everything is permitted on
phusergroup, which cannot use
.phab user = emailcommand
- the 'not in any group' user, which cannot
- create new task
- create new paste
- change status or permission
- assign a task to someone
- set an email or check other users
If you set the variable
y, then the 'not in any group' users can access all the features reserved for the
phuser group. Typically the
phuser role is designed to be used on public irc or gitter channels, but is not needed in closed slack channels.
PHABRICATOR_URL- main url of your Phabricator instance
PHABRICATOR_VERSION- the version of phabricatior used, in the shape
year.weekand looks like a float easy to compare. This is used for handling breaking changes between versions of phabricator.
PHABRICATOR_API_KEY- api key for the bot user
PHABRICATOR_LAST_TASK_LIFETIME- how long the last task is remembered for each user (default 60 min). If set to "0" there is memory on the last task remembered. If set to "-" the memory is never expired.
If you use
HUBOT_AUTH_ADMIN- hardcoded list of hubot admins
PHABRICATOR_TRUSTED_USERS- if set to 'y', bypasses the requirement of belonging to
phusergroup for commands restricted to users. Makes sense in places where all users are internal or invited-only and trustworthy.
You also should use
hubot-restrict-ip to limit the access to the web endpoints (api and feeds endpoints), or serve only on localhost (
EXPRESS_BIND_ADDRESS=127.0.0.1) and use a proxy to access those endpoints.
PHABRICATOR_ENABLED_ITEMS- is used with feature
hearto limit what kind of objects are commonly used in your instance of Phabricator
PHABRICATOR_FEED_EVERYTHING- if set to a value that is not '0' (like 1 or yes), then the feedall feature will not only announce tasks. Note that this option only applies to the
.ph feedall to <room>case, not to specific projects feeds.
hubot-phabs plugin has a lot of features, and some of them could be useless, or dangerous if activated under an unprotected environment. There are 2 environment variables that can be used to limit what features are loaded and active:
PHABS_ENABLED_FEATUREScan be a comma-separated list of the only plugins enabled.
PHABS_DISABLED_FEATURESis also a comma-separated list of features, to only restrict a few ones. It won't be any use if the
PHABS_ENABLED_FEATURESis declared, as it would take priority.
Typical examples of usage are:
PHABS_ENABLED_FEATURES="hear"if you only want the bot to do automatic announces
PHABS_DISABLED_FEATURES="feeds,api"if you don't want to expose http endpoints
PHABS_DISABLED_FEATURES="admin,feeds"if you don't use
hubot-auth. Note that you can do the setup with the admin feature at first, and then just disable it (and relaunch the bot in between).
Available features are loaded in that order:
There is some events available for interaction with other plugins, to chain actions or automate them. The specific use case we had was to use hubot-cron-events to create templated tasks are given times. It is making sense in our workflow. The principle is pretty useful, so there will be more events declared further on.
phab.createTask payload: - project (by name or alias) - template (null if none) - title - description - user (an object with at least a name property) - assign (as a user name) - announce (optional: the name of a room where to announce the task creation and id) It will create a task from an event, and talk on the logger when done or if it fails.
It may seem a little weird, but circumstances led us to use our hubot as an API endpoint for creating tasks from inside our internal network. Of course we could just use conduit and hit Phabricator directly but:
- we save the hassle of spreading the API key around
- we are inside a trusted network, and use hubot-restrict-ip
- we expose REST endpoints, with only very simplified payload description
To avoid exposure of that weak API endpoint, you should:
- set the env var PHABS_NO_API to any value, if it's defined, the api code is not loaded
- use hubot-restrict-ip to set up your own policy
- set your hubot to respond http calls through a well configured apache or nginx proxy
Currently the API only has one endpoint, that triggers the
POST /<robot.name>/phabs/api/:project/task where :project can be a project name or an alias that you have set with .phad the content-type has to be application/json and the payload should conform to the payload for the phab.createTask event
Commands prefixed by
.phab are here taking in account we use the
. as hubot prefix, just replace it with your prefix if it is different. Also,
phab can be shortened to
ph in the commands.
Requests can be done on arbitrary projects. Their PHID will be retrieved at first call and cached in hubot brain. Those projects can use aliases, like short names, interchangeably, for convenience (set them up using the
.phab [all] [limit] <project> <search terms> will grab the 3 newest matches in tasks matching search terms and included in project. note that there are some special rules: - non-alphanumeric chars will be mess up - the match is done on full-words: test won't match tests - if the 'all' prefix is used, it will also search in task that are not in status 'open' - if the limit is specified, it has to be a number. without limit the default is 3 remember that phabricator search api has a hard limit of 100 in any case (so '.phab 1000 <project> <term>' will only return 100 results anyways) permission: all .phab [all] [limit] search <search terms> will grab the 3 newest matches in tasks matching search terms. Same rules apply as the search per project/tag. permission: all .phab new <project> <task title> .phab new <project> <task title> = <description> creates a new task in an arbitrary project. A project alias can also be used. The new task will be created in the default column of the project board. The issuer of the command will be added in the list of subscribers for the newly created task. The <description> is optional, and will be used as description if provided NOTE: this call will record this Task id associated to you for 1 hour permission: phuser .phab new <project>:<template> <task title> .phab new <project>:<template> <task title> = <description> creates a new task using a template. if a description is provided, it will prepend the template description For the rest, it behaves like the .phab new command permission: phuser .phab paste <new paste title> creates a new paste and provide the link to edit it permission: phuser .phab T123 .phab gives the status, priority and owner of the task xxx NOTE: this call will record this Task id associated to you for 1 hour permission: all .phab T123 + <some comment> .phab + <some comment> adds a comment to task Txxx (or the one in short memory). permission: phuser .phab T123 in tag1 .phab T123 not in tag1 .phab T123 in tag1 in tag2 not in tag3 in tag4 adds or remove tags from tasks. Tags are also known as projects permission: phuser .phab T123 is open .phab T123 is broken .phab is low .phab low .phab is low = this is a reason .phab is low + this is a reason Changes status or priority for task Txxx. the 'is' is optional. If the optional '=' or '+' is used, it will add a comment to that change Available statuses are: - open, opened -> open - resolved, resolve, closed, close -> resolved - wontfix, noway -> wontfix - invalid, rejected -> invalid - spite, lame -> spite Available priorities are - broken, unbreak -> Unbreak Now! - none, unknown, triage -> Needs Triage - high, urgent -> High - normal -> Normal - low -> Low - wish, wishlist -> Whishlist NOTE: this call will record this Task id associated to you for 1 hour permission: phuser .phab T123 on <someone> .phab for <someone> assigns the given task to a user (or the given user to the task, which is exactly the same). The 'for' and 'on' conjunctions are inter-changeable. You can use 'me' as username and it will substitute your username NOTE: this call will record this Task id associated to you for 1 hour permission: phuser .phab T123 to <column> .phab to <column> .phab T123 to <column> + some comment .phab T123 to <column> = some comment moves the task on the board to the column matching the <column> the matching will take the first match. A comment can optionaly be added permission: phuser .phab T123 sub <user> .phab sub <user> .phab T123 sub <user> + some comment .phab T123 unsub <user> = some comment subscribes and unsubscribes users to tasks. A comment can optionally be added. You can use 'me' as username and it will substitute your username permission: phuser .phab T123 on <someone> is low is open to <column> starting with `v2.2.0` it's possible to combine several commands to change a task. It detects actions to be taken according to the conjunction used: - on - change owner - for - change owner (alias to on) - is - change status or priority - in - change tag/project (add a tag) - not in - change tag/project (remove a tag) - to - change column - sub - subscribes user - unsub - unsubscribes user permission: phuser .phab T123 next <term> .phab T123 next .phab next This will return the first match in the Task T123 description that begins with a [ ] (a checkbox) if a <term> is provided, it will match the first line that begins with '[ ] term' the first word on the line, just after the checkbox, is used as a keyword, but it's totally optional permission: phuser .phab T123 prev <term> .phab T123 prev .phab previous .phab prev This will return the last match in the Task T123 description that begins with a [x] (a checked checkbox) if a <term> is provided, it will match the last line that begins with '[x] term' permission: phuser .phab T123 check <term> .phab T123 check .phab check .phab check! <term> .phab check! .phab check! + <comment> This will update the description of T123 and replace the checkbox line with a checked box '[x]' If a term is provided, the first matching line will be the checked one If the '!' is added, it will also return the next unchecked checkbox If a '+' is added at the end of any above syntax, it will append a comment in the modification permission: phuser .phab T123 uncheck <term> .phab T123 uncheck .phab uncheck .phab uncheck! <term> .phab uncheck! .phab uncheck! + <comment> This will update the description of T123 and replace the checked checkbox line with a checked box '[ ]' If a term is provided, the last matching line will be the unchecked one If the '!' is added, it will also return the previous checked checkbox If a '+' is added at the end of any above syntax, it will append a comment in the modification permission: phuser .phab user <someone> will check is <someone> is linked to his Phabricator account (using email address) permission: phuser .phab me as <firstname.lastname@example.org> registers your email in the bot. You need to specify the email address registered in Phabricator permission: phuser .phab user <someone> = <email@example.com> registers email for another user, follows the same concept as .phab me as .. permission: phadmin .phab count <project> return the number of tasks in the given <project> permission: all .phab version displays the version of hubot-phabs that is installed permission: all .phid <phid> .phid <name> When provided a PHID-*, gives the name and uri for a given PHID (mostly for arcanist use) When provided an item name (ie. T123), returns the PHID permission: all
There is also a way to specify a list of templates for creating new Tasks with prefilled descriptions. Any task can be used as a template, whatever the status, as far as they are readable by the bot user. Typically those can be relevant closed Tasks form the past that we fit for templating.
The management of those templates is done with the
.pht new <name> T123 creates a new template named <name>, using the task T123 as a template permission: phadmin .pht show <name> .pht info <name> shows what task is used as a template permission: phuser .pht search <term> .pht list <term> search through templates which names contain <term> If <term> is omitted, it just retruns the whole list of all templates permission: phuser .pht remove <name> removes template named <name> from the brain memory permission: phadmin .pht update <name> T321 updated template named <name> with the new template task T321 permission: phadmin .pht rename <name> <newname> rename the template named <name> with <newname> permission: phadmin
Some configuration variables are stored the brain. They are managed by the phabs_admin module, driven with the
.phad command. note the syntax changed in v1.5.1
.phad projects lists projects listed in brain permission: all .phad delete <project> .phad del <project> removes information about <projects> from the brain (useful when a project is deleted or renamed in phabricator) permission: phadmin .phad info <project> .phad show <project> gives info about <project>, including aliases, feeds and columns permission: all .phad info <parent> / <project> .phad show <parent> / <project> gives info about <project> given that it is a subproject or milestone of <parent>, retunred information includes aliases, feeds and columns permission: all .phad refresh <project> refresh info for <project> form phabricator typically useful when there are new columns in a workboard permission: all .phad alias <project> as <alias> adds an alias <alias> to <project>. Aliases are unique permission: phadmin .phad forget <alias> removes the alias <alias> permission: phadmin .phad feed <project> to <room> .phad feeds <project> to <room> creates a feed for <project> to <room>. Feeds are comming from feed.http-hooks. Only tasks are included in this feed. permission: phadmin .phad remove <project> from <room> remove a feed permission: phadmin .phad feedall to <room> creates a catchall feed to <room>. Only tasks are included in this feed unless the var PHABRICATOR_FEED_EVERYTHING is set and is not set to '0' permission: phadmin .phad removeall from <room> remove a catchall feed permission: phadmin
A http endpoint is open for receiving feeds from
feed.http-hooks as explained in https://secure.phabricator.com/T5462
You can use the
.phad commands to associate Projects to rooms. Each Feed Story will then be dispatched on one or several rooms according to the project the task belongs to. This only works with Tasks (for now).
Note that the tasks from a subprojects are also announced in the feed for the parent project.
The feed has an optional way to limit the IP of the sender, by setting the HUBOT_AUTHORIZED_IP_REGEXP env variable. If this variable is not set, there is not access control. It's a limited soft protection, if you really need a heavy secure protection, do something on your network for it.
Since 2.4.1, users can also set private alerts on tasks they own or are subscribed to.
.phab me set alerts will send a private message for each task the caller owns or is subscribed to (note: it only works on tasks for now) permission: phuser .phab <user> set alerts same as with 'me' but with arbitrary user name, to enable their subscription to alerts permission: phadmin .phab me unset alerts will disable alerts permission: phuser .phab <user> unset alerts same as with 'me' but with arbitrary user name, to disable their subscription to alerts permission: phadmin
There is a
.hear feature that also will give information about items that are cited on channel. It tries to do precise pattern matching but sometimes there are some unfortunate coincidences. For example, we work with level3 and talk about it under L3 often. Or one of our project involves a V5. It's kind of annoying to have the bot react on those specific case, so it' possible to blacklist them.
There is possibility to only react to certain item type too, by setting the
PHABRICATOR_ENABLED_ITEMS environment variable. For example
PHABRICATOR_ENABLED_ITEMS="T,P,r" will restrict reactions to only Tasks, Pastes and Commits items. If that env var is not declared, it will react to all known types.
something about https://phabricator.example.com/T2#17207 just talking about T123. did you see that one? the plugin will watch if it sees - T[0-9]+ for tasks (of Maniphest) - P[0-9]+ for pastes - D[0-9]+ for differential revisions - F[0-9]+ for files - M[0-9]+ for mocks (of Pholio) - B[0-9]+ for builds (of Harbormaster) - L[0-9]+ for legalpads - V[0-9]+ for polls (of Slowvote) - r[A-Z]+[a-f0-9]+ for commit (of Diffusion) if it is in an url, it will reply with T2 - <title of the task> if it's not in an url it will reply with <task url> - <task title> NOTE: this call will record this Task id associated to you for 5 minutes it will just say nothing if the pattern matched is in the blacklist permission: all .phab bl T123 this will add T123 to the blacklist permission: phuser .phab unbl T123 this will remove T123 from the blacklist permission: phuser
All changes are listed in the CHANGELOG
npm install # will run make test and coffeelint npm test # or make test # or, for watch-mode make test-w # or for more documentation-style output make test-spec # and to generate coverage make test-cov # and to run the lint make lint # run the lint and the coverage make
Feel free to open a PR if you find any bug, typo, want to improve documentation, or think about a new feature.
Gandi loves Free and Open Source Software. This project is used internally at Gandi but external contributions are very welcome.
This source code is available under MIT license.
Copyright (c) 2016 - Gandi - https://gandi.net