JIRA Integration

Atlassian provides a REST API which can be used to interact with Jira instances (both on-premise and cloud). This API can be utilized to automate ticket creation and updates directly from Connexion. This is a quick sample showing how a Jira ticket can be created when Connexion logs an event.

This feature leverages the Custom Alerting feature, which lets you inject your own logic within Connexion’s alerting/eventing pipeline.

This sample uses the Atlassian.Jira assembly (and dependencies) which wrap the JIRA REST API. The goal of this sample is to trap a specific event (error number 5440), check to see if there is an existing open ticket, and if not, create a new one. This is the test code:

using System; using Connexion.Core; using System.Threading.Tasks; using System.Collections.Generic; using Atlassian.Jira; using System.Linq; namespace Connexion.Device { public class CustomAlerting : BaseCustomAlerting { private readonly string _jiraUrl = "https://conevity.atlassian.net"; private readonly string _jiraUser = "youremail@yourdomain.com"; private readonly string _jiraToken = "Your_Token_Here"; private readonly string _jiraProject = "CNXN"; private readonly HashSet<int> _trackedEventIds = new HashSet<int>(new [] {5440}); // event ids to track public override async Task OnAlertReceivedAsync(AlertReceivedEventArgs arg) { if(!arg.DeviceKey.HasValue && string.IsNullOrWhiteSpace(arg.ChannelName)) return; if(!arg.Event.EventId.HasValue || !_trackedEventIds.Contains(arg.Event.EventId.Value)) return; // not tracking this event id // uri which can be used to launch CXN and navigate to the correct channel var uri = $"cxn://{Environment.MachineName}/{arg.DeviceKey:N}"; var summary = $"{arg.Event.EventId.Value}: {arg.GroupName} > {arg.TabName} > {arg.ChannelName}"; try { await CreateJiraIssueAsync(summary, arg.Event.Event, "Task", uri, arg.ChannelKey.Value.ToString("N")).ConfigureAwait(false); } catch(Exception ex) { MessageChannel.Logger.Write(EventSeverity.Error, $"Unexpected error in JIRA communication: {ex}"); } } private async Task CreateJiraIssueAsync(string summary, string description, string type, string uri, string channelKey) { try { var settings = new JiraRestClientSettings(); settings.EnableUserPrivacyMode = true; var jira = Jira.CreateRestClient(_jiraUrl, _jiraUser, _jiraToken); var existingIssue = jira.Issues.Queryable.FirstOrDefault(i => i.Project == new LiteralMatch(_jiraProject) && i.Summary == summary && (i.Status == "To Do" || i.Status == "In Progress")); if(existingIssue != null) { MessageChannel.Logger.Write(EventSeverity.Info, $"JIRA issue {existingIssue.Key} already exists"); return; } var issue = jira.CreateIssue(_jiraProject); issue.Type = type; issue.Summary = summary; issue.Description = description; issue["ConnexionUri"] = uri; // custom field in jira issue["ChannelKey"] = channelKey; // custom field in jira await issue.SaveChangesAsync().ConfigureAwait(false); } catch (Exception ex) { MessageChannel.Logger.Write(EventSeverity.Error, "Failed to create JIRA issue: {0}", ex); } } } }

The above code first searches JIRA for an existing ticket with a matching summary (and a non-closed status). If one is found, no new ticket is created; otherwise a new ticket is created. Two custom fields have been added to JIRA:

ConnexionUri is a uri which can be clicked on within the JIRA web page to launch and/or navigate the Connexion UI to the channel associated with this ticket.

ChannelKey is a GUID which identifies the target channel. This field can be used by other custom workflows (in JIRA and Connexion) to query and track tickets.