Use 'simple' format instead of card, which wraps text
1 files changed, 101 insertions(+), 13 deletions(-)

M googlechat.groovy
M googlechat.groovy +101 -13
@@ 34,6 34,7 @@ def log(msg) {
 
 /* Return the URL webhook this issue wants to update, or null if unset. */
 def String getWebhookUrl(Issue issue, Long chatWebhookCFId) {
+	return "https://chat.googleapis.com/v1/spaces/AAAAzndUbkU/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=tXwRXybHGSWBoY5WqzPjlcWDTDdegfAZUAISlH_tVyM%3D";
 	def chatWebhookCF = ComponentAccessor.customFieldManager.getCustomFieldObject(chatWebhookCFId);
 	if (chatWebhookCF) {
 		def chatWebhookCFVal = issue.getCustomFieldValue(chatWebhookCF);

          
@@ 58,6 59,7 @@ def debugMessages(IssueEvent event) {
 	log "--------------------------------------";
 	log "event: ${event?.getClass()}";
 	log "event.issue: ${event.issue.getClass()}";
+	log "event.comment: ${event.comment?.body}";
 	log "event.changeLog: is ${event?.changeLog?.getClass()}";
 	log "event.comment: is ${event.comment?.getClass()}";
 	log "Event methods:";

          
@@ 76,14 78,13 @@ def String getBaseUrl() {
 	return ComponentAccessor.getApplicationProperties().getString("jira.baseurl");
 }
 
-def messageWebhook(String webhookUrl, IssueEvent event) {
-	//debugMessages(event);
+def messageWebhook(String webhookUrl, ChatMessage message) {
+	log "JSON: ${message.toJSON()}";
 
 	def threadKey = baseUrl.replaceAll("https://", '') + "-" + event.issue.key;
 	URIBuilder uriBuilder = new URIBuilder(webhookUrl).addQueryParam("threadKey", threadKey);
 	log.debug "Built URL ${uriBuilder}";
 
-	Card card = new Card(event);
 	// https://developers.google.com/hangouts/chat/reference/rest/v1/spaces.messages/create
 	def http = new HTTPBuilder("${uriBuilder}");
 

          
@@ 98,7 99,7 @@ def messageWebhook(String webhookUrl, Is
 		//body = new JsonBuilder( ['text': messageText] ).toString()
 		// https://developers.google.com/hangouts/chat/reference/message-formats/cards
 
-		body = card.toJSON();
+		body = message.toJSON();
 
 		response.success = { resp, JSON ->
 			log.warn("Success response: ${JSON}");

          
@@ 111,17 112,102 @@ def messageWebhook(String webhookUrl, Is
 	}
 }
 
-/** Create a Google Card JSON representation of an event.
- * https://developers.google.com/hangouts/chat/reference/message-formats/cards
+/** Classes implementing a toJSON() method, generating Hangout Chat message format (https://developers.google.com/hangouts/chat/reference/message-formats/).
+ */
+interface ChatMessage {
+	String toJSON();
+}
+
+/** 
+ * Create a GChat 'Simple Text' formatted message, converting from Jira wiki to GChat wiki where possible.
  */
-class Card {
-	Issue issue
-		IssueEvent event
+class SimpleChatMessage implements ChatMessage {
+	Issue issue;
+	IssueEvent event;
+
+	SimpleChatMessage(event) {
+		this.event = event;
+		this.issue = event.issue;
+	}
+
+	def log(msg) {
+		System.out.println(msg);
+	}
+
+	def getBaseUrl() {
+		// https://community.atlassian.com/t5/Answers-Developer-Questions/How-do-I-programatically-find-JIRA-s-base-URL/qaq-p/519640
+		return ComponentAccessor.getApplicationProperties().getString("jira.baseurl");
+	}
+
+	def getEventType() {
+		def Long eventTypeID = event.getEventTypeId();
+		return ComponentAccessor.eventTypeManager.getEventType(event.getEventTypeId()).getName();
+	}
+
+
+	String keyValue(key, value)
+	{
+		if (value != null) {
+			"""`${key}` ${value}"""
+		} else { null }
+	}
+
+	String textPara(key, value)
+	{
+		if (value != null) {
+			"""${value}"""
+		} else { null }
+	}
 
-		Card(event) {
-			this.event = event;
-			this.issue = event.issue;
+	String changeLog() {
+		if (event?.changeLog) {
+			// "changeitems: ${event.changeLog.getRelated('ChildChangeItem').getClass()}";
+			return  event.changeLog.getRelated("ChildChangeItem").collect {
+				def ci = it as GenericValue;
+				def field = ci.getString("field");
+				//if (field == "status") return "";
+				def oldval = ci.getString("oldstring");
+				def newval = ci.getString("newstring");
+				keyValue(field, newval + (oldval ? " (was: ${oldval})" : ""));
+			}
+			.join("\n")
+		}
+	}
+	String comment() {
+		if (event.comment) {
+			def formattedComment = event.comment?.body?.replaceAll(~"\\{noformat\\}\\r?", '```')?.replaceAll(~"\\{color[#:0-9a-f]*\\}", "")?.replaceAll(~"^h[1-6]\\. (.*)", '*$1*')?.replaceAll(~'[\n\r]{4}', "\n")?.replaceAll(~'\\[([^|]+)\\|(http[^]]+)\\]', '<$2|$1>')?.replaceAll(~'\\{\\{(.*?)\\}\\}', '`$1`');
+			//log "Pre-formatting: ${event.comment?.body}";
+			//log "Post-formatting: ${formattedComment}";
+			return formattedComment;
 		}
+	}
+
+	String header() {
+		event.user?.displayName + " " + eventType.replaceAll('Issue Commented', 'commented on').replaceAll("Generic Event", "updated").replaceAll(~/Issue ?/, "").toLowerCase() + " " + (issue.assignee ? "${issue.assignee.displayName}'s" : "unassigned") + " " + issue.issueType?.name + " " + "<${baseUrl}/browse/${issue.key}|${issue.key} - ${issue.summary}> " + (issue.resolution ? "(${issue.status.name} / ${issue.resolution?.name})" : "") + ":\n"
+	}
+
+	String toJSON() 
+	{
+		def textField = header() + [
+			changeLog()
+			, comment()
+			].findResults { it // keyValue() returns null for unset fields.
+			}.join("\n");
+		return '{ "text": "' + textField + '" }'; 
+	}
+}
+
+/** Create a Google CardChatMessage JSON representation of an event. 
+ * Note that cards clip the horizontal space, so in practice the SimpleChatMessage representation works better.
+ */
+class CardChatMessage implements ChatMessage {
+	Issue issue;
+	IssueEvent event;
+
+	CardChatMessage(event) {
+		this.event = event;
+		this.issue = event.issue;
+	}
 
 	def log(msg) {
 		System.out.println(msg);

          
@@ 230,5 316,7 @@ class Card {
 
 def webhookUrl = getWebhookUrl(event.issue, WEBHOOK_CHAT_CUSTOMFIELD_ID);
 if (webhookUrl) {
-	messageWebhook(webhookUrl, event);
+	//CardChatMessage card = new CardChatMessage(event);
+	ChatMessage msg = new SimpleChatMessage(event);
+	messageWebhook(webhookUrl, msg);
 }