This post is a testament to Fossil's design and the ease of reading its
implementation. I've also added a Fossil patch at the bottom. I humbly
hope the devs will incorporate it into the product, or tell me what is
wrong with it so I can perhaps fix it. Otherwise, I hope the community
finds it useful or at least interesting.
Someone recommended to our team that we start using Slack (http://slack.com)
for intra-team instant messaging, file exchange, etc. One of its nice
features is that it has automated hooks from Jira (a ticket system, as you
probably know) and Bitbucket (a Git hosting blah blah whatever, as you
probably know). You change a ticket status or make a commit, you
immediately get a little IM to your team with a hyperlink to what
happened. Fancy. Slack is pretty cool in general, so it seems likely that
my team will keep using it.
I'm pushing for Fossil within my team. The size of the Git ecosystem is a
point in Git's favor and a ding on Fossil. Wishing to erode from this
vis-a-vis the Git-Slack integration, I asked myself, How fast can we hook
fossil up to this bad boy?
Answer: really fast.
It requires a little hacking of the Fossil source to expose some data to
the TH1 Transfer hooks. But basically we can just use the
Admin-Transfers-Push and Admin-Transfers-Ticket TH1 hooks to get what
we want. Slack has a nice little HTTP API for messaging, so once the data
is in TH1 you just massage it into an appropriate HTTP call.
So the idea can be easily extended to any HTTP service that accepts active
notifications.
Perhaps there is a better way to accomplish this. But a bunch of googling
mailing list scraping yielded only Andreas's 'fx' package, which seemed
slightly larger than what I was looking for. Let me know if I missed
something.
Here's my first hack at the TH1 script for publishing ticket info to the
remote HTTP API:
===
tclInvoke package require http
tclInvoke package require tls
tclInvoke http::register https 443 tls::socket
set url https://slack.com/api/chat.postMessage;
query {SELECT title, assignedTo, status, resolution, releaseGate, type,
priority, severity FROM ticket WHERE tkt_uuid=$uuid} {
set msgText *Title*:
https://anonymized/tktview?name=$uuid|$title\n\n*Type*:
$type\n*Priority*: $priority\n*Assigned To*: $assignedTo\n*Status*: $status
if {$status ne Open} {
set msgText $msgText\n*Resolution*: $resolution
}
if {$releaseGate ne } {
set msgText $msgText\n*Release Gate*: $releaseGate
}
set iconUrl http://fossil-scm.org/index.html/logo;
set quer [tclInvoke http::formatQuery token anonymized channel
#tickets username Fossil text $msgText icon_url $iconUrl]
set token [tclInvoke http::geturl $url -method POST -timeout 3 -query
$quer]
set status [tclInvoke http::status $token]
tclInvoke http::cleanup $token
tclInvoke http::unregister https
}
===
Easy enough!
The issue with this is that we need to set the $uuid variable from the C
implementation prior to invoking the script. The issue is slightly
trickier for commit notifications (the Admin-Transfers-Push case), since
we can receive multiple artifacts in one Push operation. I opted to
provide a list of UUIDs to a single invocation of the script, rather than
one UUID for each of multiple invocations. This allows the script more
flexibility. (Right now the variable is called $uuid rather than e.g.
$uuidList, which is something I can fix if the devs like the general
approach.)
Critiques are certainly welcome. Mathematicians say, never trust any
proof written after 11pm -- this probably should be extended to code. :-)
If the devs think the patch has merit, then I'll be happy to add comments
etc.
It was a pleasure as always to do a bit of work on a DRH project. DRH's
code has the all-too-rare property that what you think will work, usually
_does_ work -- the first time -- even if you are brand new to the code.
This is *way* harder than it looks.
If the patch is accepted, then I think it will more easily allow future
official support of Fossil from Slack, FWIW. See this list:
https://slack.com/integrations . It would be nice to see some little
dino-bones on that page.
Here's the patch, which is against Fossil 1.29 [3e5ebe2b90]:
===
--- fossil-src-20140612172556.orig/src/tkt.c2014-06-12
13:33:27.0 -0400
+++ fossil-src-20140612172556/src/tkt.c 2014-09-04 21:26:41.743216346 -0400
@@ -317,23 +317,24 @@
void ticket_init(void){
const char *zConfig;
Th_FossilInit(TH_INIT_DEFAULT);
zConfig = ticket_common_code();
Th_Eval(g.interp, 0, zConfig, -1);
}
/*
** Create the TH1 interpreter and load the change code.
*/
-int ticket_change(void){
+int ticket_change(const char* zUuid){
const char *zConfig;
Th_FossilInit(TH_INIT_DEFAULT);
+ Th_SetVar(g.interp, uuid, -1, zUuid, -1);
zConfig = ticket_change_code();
return Th_Eval(g.interp, 0, zConfig, -1);
}
/*
** Recreate the TICKET and TICKETCHNG tables.
*/
void ticket_create_table(int