diff --git a/README.md b/README.md
index c01006e..1bc0c1e 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ A place where I put some integration scripts for the popular Slack messaging pla
#Rally Bot
-We use this to query our Rally instance for defects, tasks and user stories. I have it configured to respond to a /rallyme slash command in Slack.
+Pushes notifications from Rally whenever a comment is added to a ticket, and queries our Rally instance for defects, tasks and user stories. I have it configured to respond to a /rallyme slash command in Slack.
E.g.:
/rallyme DE12345
diff --git a/scripts/config/rallycron.conf.php b/scripts/config/rallycron.conf.php
new file mode 100644
index 0000000..bbd2816
--- /dev/null
+++ b/scripts/config/rallycron.conf.php
@@ -0,0 +1,4 @@
+text, $payload->attachments);
-
+
if($result=='Invalid channel specified'){
die("Sorry, the rallyme command can't post messages to your private chat.\n");
}
-
+
if($result!="ok"){
print_r($result."\n");
print_r(json_encode($payload));
@@ -71,11 +72,11 @@ function postit($channel_name, $payload, $attachments){
global $config, $slackCommand;
return slack_incoming_hook_post_with_attachments(
- $config['slack']['hook'],
- $config['rally']['botname'],
- $slackCommand->ChannelName,
- $config['rally']['boticon'],
- $payload,
+ $config['slack']['hook'],
+ $config['rally']['botname'],
+ $slackCommand->ChannelName,
+ $config['rally']['boticon'],
+ $payload,
$attachments);
}
@@ -169,7 +170,7 @@ function GetDefectPayload($ref)
array_push($fields,$firstattachment);
global $slackCommand;
-
+
$userlink = BuildUserLink($slackCommand->UserName);
$user_message = "Ok, {$userlink}, here's the defect you requested.";
@@ -265,7 +266,7 @@ function GetRequirementPayload($ref)
if($blocked)
array_push($fields, MakeField("blocked",$blockedreason,true));
-
+
array_push($fields, MakeField("description",$short_description,false));
if($firstattachment!=null)
diff --git a/scripts/include/rallycron.inc.php b/scripts/include/rallycron.inc.php
new file mode 100644
index 0000000..8f09bed
--- /dev/null
+++ b/scripts/include/rallycron.inc.php
@@ -0,0 +1,95 @@
++' . $since . '))&fetch=Artifact,Text,User&order=CreationDate+asc';
+
+ $results = CallAPI($query_url);
+ $results = $results->QueryResult->Results;
+
+ $project_url = $RALLY_URL . '#/' . $RALLY_PROJECT_ID;
+
+ $items = array();
+ foreach ($results as $Result) {
+ switch ($type = $Result->Artifact->_type) {
+ case 'Defect':
+ $path = '/detail/defect/';
+ break;
+ case 'HierarchicalRequirement':
+ $type = 'User Story';
+ $path = '/detail/userstory/';
+ break;
+ default:
+ continue 2; //don't display comments attached to other artifact types
+ }
+
+ $items[] = array(
+ 'type' => $type,
+ 'title' => $Result->Artifact->_refObjectName,
+ 'url' => $project_url . $path . basename($Result->Artifact->_ref) . '/discussion',
+ 'user' => $Result->User->_refObjectName,
+ 'text' => $Result->Text
+ );
+ }
+
+ return $items;
+}
+
+function SendRallyCommentNotifications($items)
+{
+ global $SLACK_CHANNEL_FOR_RALLY_PROJECT;
+ $success = TRUE;
+
+ foreach ($items as $item) {
+ $item['title'] = SanitizeText($item['title']);
+ $item['title'] = TruncateText($item['title'], 300);
+ $slug = $item['type'] . ' ' . l($item['title'], $item['url']);
+
+ $item['text'] = SanitizeText($item['text']);
+ $item['text'] = TruncateText($item['text'], 300);
+
+ //display a preview of the comment as a message attachment
+ $pretext = em('New comment added to ' . $slug);
+ $text = '';
+ $color = '#CEC7B8'; //dove gray
+ $fields = array(MakeField($item['user'], $item['text']));
+ $fallback = $item['user'] . ' commented on ' . $slug;
+
+ $message = MakeAttachment($pretext, $text, $color, $fields, $fallback);
+ $success = SendIncomingWebHookMessage($SLACK_CHANNEL_FOR_RALLY_PROJECT, '', $message) && $success;
+ }
+
+ return $success;
+}
+
+function SendIncomingWebHookMessage($channel, $payload, $attachments)
+{
+ global $config;
+
+ //allow bot to display formatted attachment text
+ $attachments->mrkdwn_in = ['pretext', 'text', 'title', 'fields'];
+
+ $reply = slack_incoming_hook_post_with_attachments(
+ $config['slack']['hook'],
+ $config['rally']['botname'],
+ $channel,
+ $config['rally']['boticon'],
+ $payload,
+ $attachments
+ );
+
+ $success = ($reply == 'ok');
+ if (!$success) {
+ trigger_error('Unable to send Incoming WebHook message: ' . $reply);
+ }
+ return $success;
+}
+
diff --git a/scripts/include/slack.php b/scripts/include/slack.php
index 38639a2..1eb0d44 100644
--- a/scripts/include/slack.php
+++ b/scripts/include/slack.php
@@ -30,10 +30,31 @@ function BuildSlashCommand($request)
}
+//text-formatting functions
+
+function SanitizeText($text)
+{
+ $text = strtr($text, array('
' => '\n', '
' => '\n')); + return html_entity_decode(strip_tags($text), ENT_HTML401 | ENT_COMPAT, 'UTF-8'); +} + +function l($text, $url) +{ + return '<' . $url . '|' . $text . '>'; +} + +function em($text) +{ + return '_' . $text . '_'; +} + + +//posting functions + function slack_incoming_hook_post($uri, $user, $channel, $icon, $emoji, $payload){ - + $data = array( - "text" => $payload, + "text" => $payload, "channel" => "#".$channel, "username"=>$user ); @@ -53,18 +74,19 @@ function slack_incoming_hook_post($uri, $user, $channel, $icon, $emoji, $payload return curl_post($uri, $data_string); } - - function slack_incoming_hook_post_with_attachments($uri, $user, $channel, $icon, $payload, $attachments){ $data = array( - "text" => $payload, + "text" => $payload, "channel" => "#".$channel, "username"=>$user, "icon_url"=>$icon, - "attachments"=>array($attachments)); + "attachments" => array($attachments), + 'link_names' => 1 //allow bot to linkify at-mentions in attachments + ); $data_string = "payload=" . json_encode($data, JSON_HEX_AMP|JSON_HEX_APOS|JSON_NUMERIC_CHECK|JSON_PRETTY_PRINT); + $data_string = strtr($data_string, array('\\\\n' => '\n')); //unescape slashes in newline characters mylog('sent.txt',$data_string); return curl_post($uri, $data_string); } diff --git a/scripts/rallycron.php b/scripts/rallycron.php new file mode 100644 index 0000000..1dc9d3e --- /dev/null +++ b/scripts/rallycron.php @@ -0,0 +1,9 @@ +