/
Jira Extraction API v2 (Tableau Edition)

Jira Extraction API v2 (Tableau Edition)

Motivation

JQL is the standard query language Atlassian supports for accessing JIRA issues. Here are some of important features of JQL

  • there is broad and active community where people exchange ideas and tricks.
  • it's portable across JIRA versions
  • it's portable across underneath databases (Oracle, MySQL, etc.)
  • average JIRA users are used to it
  • it's fairly simple and very powerful

Would be great if Tableau users have easy, intuitive way to access JIRA data via JQL. "JqlTableauExtractService" web service would interrogate JIRA on your behalf and serve back a Tableau native TDE/hyper (Tableau Data Extract) file.

Development process

To get data from Jira into Tableau, users need:

  • To know which Jira to pull data from - LabopsJIRA, GPInfoJIRA, broadinstitute.atlassian.net (Cloud JIRA)

  • A JQL query in plain text (project = BQMS) or a known filter ID (filter=22038) that contains all the issues to be reported on.

  • A list of fields to report on (e.g. assignee, status, summary, resolution, any custom fields). The CodeAssistant can generate a copy/pasteable list of fields for you if you click "Show all fields from [labopsjira/gpinfojira/broadinstitute.atlassian.net]" near the top of the page.

    • Any optional transformations done to these fields (e.g. if you want a comma separated list to be exploded out on new lines)

Directions:

  1. Paste the JQL into the "Plain jqlQuery" fieldin the CodeAssistant. Your browser will automatically replace spaces (and other special characters) with proper web-friendly sequences (for example space -> %20)

  2. Enter a comma separated list of Fields and their transformations. e.g key, Summary, Assignee

  3. Select a number of records to preview to make sure your query works. The CodeAssistant will automatically insert code friendly field names next to the field names you provided.

  4. If the results look like what you want, use the code assistant's output of your choice. (e.g. use the "Normalized URL" for a one time downloadable TDE, or use the value in the Double encoded Url to set up a scheduled batch file to continuously update a TDE extract, or use the WebDataConnector SQL which can provide live data - Oracle 12 only.)

  5. If you've created a TDE, add &agentName=XYZ to the end of the URL where XYZ is the agent name that will show up in the ETL dashboard.

  6. Set up automating this TDE as mentioned below in the "Schedule a curl extract script" section.

Automation (curl)

Use curl scripts to automatically generate these extracts and deposit them on your Tableau server.

curl.exe "http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key%3DCR-3597&fields=key(key),customfield_10169(Instrument):concat(%3E)" -o c:\temp\test2.tde
curl.exe "http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key%3DCR-3597&fields=key(key),customfield_10169(Instrument):concat(+%3E+)" -o c:\temp\test2.tde


Curl Installation for Windows (this needs to be done only once and has already been installed on Tableau-TS

 
  1. Login to the server designated for curl extract scripts.
  2. Download (right click -> Save As) curl736.exe into folder you have write access to. (Curl for all kinds of OS can be found here http://curl.haxx.se/download.html but some of newer versions may not be as polished)
 

Schedule a curl extract script

  1. Run "Task Scheduler"
  2. Choose "Create Task" and follow the Wizard. Name your schedule
  3. Provide a "trigger" meeting your needs.
  4. In Action tab, in "Program/script" field paste the full path to your curl executable (for example "C:\Program Files (x86)\Utils\curl.exe"). In "Arguments" provide entire URL wrapped in double quotes.
  5. Run the new schedule manually and check if file has been properly generated and deposited.
 

For geeks: you can manage all your scheduled tasks via command line as well http://www.howtogeek.com/51236/how-to-create-modify-and-delete-scheduled-tasks-from-the-command-line/


Tableau Command Line Interpreter (CLI) installation for Windows (this needs to be done only once and has already been installed on Tableau-TS

Example CURL+CLI batch file for Windows

NOTE: it isn't always possible to edit an existing batch file. You can usually rename it, though, so you can edit a duplicate and then change the names to archive the old one.

:: Windows batch file for JQL to TDE conversions
@echo off
 
set TDE=TableauJQL_PFDemo
set TDEPATH=C:\Local\%TDE%.tde
 
:: call JQL, convert to TDE
echo Using curl to call JQL Extract Service...
 
:: Updated using code assistant 20180108
"C:\Program Files (x86)\Utils\curl.exe" -o %TDEPATH% "http://analytics:8090/api/v2/JqlTableauExtractService?domain=broadinstitute.atlassian.net&jqlQuery=project+%%3D+%%22POAMs+and+Findings%%22&fields=summary(Summary),reporter(Reporter),customfield_13911(Recommendation):concat"
 
if ERRORLEVEL 1 (echo Error with JqlTableauExtractService, aborting. & goto :eof)
 
:: upload TDE to Tableau Server
echo. & echo Uploading to Tableau...

::older 9.3 version tab command
::set TABCMD="C:\tabcmd\Command Line Utility\tabcmd" 
set TABCMD="C:\Program Files\Tableau\Tableau Server\2018.1\extras\Command Line Utility\tabcmd"

set TableauServer=https://tableau.broadinstitute.org
set TableauUser=charles\tableau-reports
::%TABCMD% version
echo. & echo Logging into Tableau Server...
%TABCMD% login -s %TableauServer% -u %TableauUser% --password-file ts_password.txt
echo. & echo Publishing TDE...
%TABCMD% publish %TDEPATH% -n %TDE% --overwrite --project "GP Operations"
echo. & echo Logging out of Tableau Server...
%TABCMD% logout
 
:eof
echo. & echo Script finished.

Monitoring

You can see how your agent performed in Etl Dashboard service (you name your etl by adding an "agentName=???" parameter in the URL). In case of failure an email is automatically sent to reportingerrors@broadinstitute.org, etc.

Custom fields

JIRA keeps record of custom fields by their internal names which look like this "customfield_12345". And unfortunately this is the column name which JqlTableauExtractService expects you to provide. Luckily the CodeAssistant can do all these tedious lookups, Url-encoding (and much more) for you.

Other interesting services:

Security considerations

This service utilize "analytics" user so anything not visible to "analytics" would not be visible to you either.

JqlTableauExtractService VS JIRA datamarts VS JiraWebConnector

Features

JqlTableauExtractService 

JIRA datamarts

JiraWebConnector
realtimeNo (data as old as your last extract)YesYes
skills necessaryJQL, curlingSQL and familiarity with JIRA datamartsJQL
Atlassian supportYesNoYes
Portability (across DBs and JIRA versions)ExcellentNo (may require rewrites as internal structures change)Excellent
Avg cost per featureLow (parsing XML is relatively easy)

High (working around Jira's DB schema might be time consuming)

Low (parsing XML is relatively easy)
Is JIRA UI requred to be runningYesNo (only JIRA DB is needed)Yes
Advanced features


TransitionsNoYesNo
Issue AncestryNoYesNo
CLOBs handling and parsingSomewhatYesSomewhat
Overall versatilityReasonable (primarily focused on list of issues)Very good (can query many kinds of JIRA data like transitions)Reasonable (primarily focused on list of issues)
App Lockworks only with Tableauany app can use them via SQLNo lock - any app can consume it via DB-connection
Securityrespects whatever permissions are granted to "analytics" userread any data from any project, no limitationsrespects whatever permissions are granted to "analytics" user

Examples

Cascading field → one delimited string 

Extract CascadingSelect Custom Field "Instrument" and collapse the 2 levels into a " > " separated String value

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=CR-3597&fields=key(key),customfield_10169(Instrument)

Expose what's the actual delimiter in a multi-value string

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=LCSET-9883+&fields=key(key),reporter(Reporter),created(Created):toDate,customfield_10162(Number+of+Samples):concat:toDouble,customfield_10010(GSSR+ID(s)):concat:expose

\x0A refers to LF-character, which is the same as \n (if you dare to check more RegEx magic try this)

Samples, Dates and Doubles

Extract samples, Dates and Doubles

  1. Convert a custom field "Number of Samples" into a Double
  2. Convert "created" into a Date
  3. Parse sample names (separated by <br/>\x0A) and convert them back into a ';' delimited string

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=LCSET-9883&fields=key(key),reporter(Reporter),created(Created):toDate,customfield_10162(Number+of+Samples):concat:toDouble,customfield_10010(GSSR+ID(s)):concat:split(<br/>\x0A):concat(;)


Explode a delimited text field

E.g. Extract Samples and leave them "exploded" so that you can JOIN with other LIMS data sources

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=project+=+BQMS+and+key+=+BQMS-557&fields=key(key),summary(Summary),reporter(Reporter),customfield_12662(Sample+IDs):concat:split(\n<br/>\n):stripHtml

Fieldsinput: key(key),summary(Summary),reporter(Reporter),customfield_12662(Sample IDs):concat:split(\n<br/>\n):stripHtml

New development: more natural way to extract samples would be to just say "grab everything starting with SM- followed by 5 alphanumerics". This is what findAllMatch transformation is doing: findAllMatch(SM-(\p{Alnum}){5}). Eg, enter the following in fields to explode the sample IDs of BQMS tickets.

Note the regex needs <CM> to encode a comma (to return either 4 or 5 length alphanumeric strings).

key(key),summary(Summary),reporter(Reporter),customfield_12662(Sample IDs):concat:findAllMatch(SM-(\p{Alnum}){4<CM>5})

Name or Rename a field

Enforce a user-defined fieldName (so that column names are provided even if no data is available)

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=LCSET-9883&fields=key(key),reporter(Reporter),created(Created):toDate,customfield_10162(Number+of+Samples):concat:toDouble,customfield_10010(Samples):concat:split(<br/>\n):concat(;)

Multi-value fields (labels, etc.)

Extract Labels

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=LCSET-10393&fields=key(key),labels(Labels):concat,reporter(Reporter)


Labels → Multiple columns (Bits, boolean)

Extract Labels and turn them into Bits (Boolean columns)

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=LCSET-10393+or+key=LCSET-10258&fields=key(key),labels(Labels):toBits(Nextera;Exome;High_Priority),reporter(Reporter)

Labels → Multiple columns (Bits, integer)

Extract Labels, turn them into Bits and then into Ints

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=LCSET-10393+or+key=LCSET-10258&fields=key(key),labels(Labels):toBits(Nextera;Exome;High_Priority):toInt

Links: Explode & return all columns 

Extract Links and leave them "exploded"

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=LCSET-10393+or+key=PDO-10544&fields=key(key),issuelinks(Linked+Issues),reporter(Reporter)

Links: Explode & return selected column

Extract Links, then select 5th column (linked issue name) and leave them "exploded"

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=LCSET-10393+or+key=PDO-10544&fields=key(key),issuelinks(Linked+Issues):select(5),reporter(Reporter)

Links: selected column → String

Extract Links, then select 1st column (linked issue narrative) and collapse them into a String

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=LCSET-10393+or+key=PDO-10544&fields=key(key),issuelinks(Linked+Issues):select(1):toList:concat,reporter(Reporter)

HTML → rich text (w/HTML)

Extract rich text in HTML custom field

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=LCSET-10261&fields=key(key),reporter(Reporter),customfield_13065(LIMS+Activity+Stream):concat


HTML → stripped rich text

Extract rich text in HTML custom field but strip HTML tags

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=LCSET-10261&fields=key(key),reporter(Reporter),customfield_13065(LIMS+Activity+Stream):stripHtml


Extract to Boolean

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=CR-389&fields=key(key),reporter(Reporter),customfield_12264(IRB+Not+Engaged?):concat:toBoolean

MultiSelect field → CSV field

Extract MultiSelect custom field, strip Html tags and collapse it back into a CSV value (to prevent a data 'explosion')

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=FCT-10036+or+key=FCT-7121+or+key=FCT-1672&fields=key(key),customfield_10090(1st+Cycle+QC):stripHtml:concat


View unextracted JIRA XML

Look at raw XML response from JIRA before any extraction is performed by Tiger

http://analytics:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=FCT-10036&fields=key,customfield_10090:stripHtml:concat&output=XML


Explode subtasks 

Multi-value field → collapsed CSV

Extract Subtasks and collapse them into a CSV

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=gpinfojira&jqlQuery=key=AS-106&fields=key(key),subtasks(Sub-Tasks):concat

Extract Components and collapse them into a CSV

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=gpinfojira&jqlQuery=key=GPLIM-4426+or+key=GPLIM-3917+or+key=GPLIM-3188&fields=key(key),components(Component/s):concat

Explode Comments

Extract Comments (along with author and created) and leave them "exploded"

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=LCSET-10393+or+key=PDO-10544&fields=key(key),comments(comments)

Collapse comments (CRLF-separated string)

Extract Comments and collapse them into a Carriage-return-line-format separated String

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=LCSET-10393+or+key=PDO-10544&fields=key(key),comments(comments):toList:stripHtml:concat(\n\n)


Extract large (>1000) datasets 

Extract all LCSETs created in 2016.

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=project="Illumina+Library+Construction+Tracking"+and+created+>+"2016/01/01"+and+created+<+"2017/01/01"&fields=key(key),status(Status),resolution(Resolution),created(Created):toDate

Extract properly-structured data from a html-table

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=FCT-35063&fields=key(key),customfield_16164(Lane+Info):concat:parseHtmlTable(Lane;Loading+Vessel;Loading+Concentration)


Preserve JOINability on sample-name by getting rid of trailing comments

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=LCSET-9868&fields=key(key),customfield_10010(GSSR+ID(s)):concat:split((\s.*)*<br/>(\x0A)*)

Parse out not only the Sample-name but also capture the trailing comment in a separate column (viva la regex)

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=LCSET-10703&fields=key(key),customfield_10010(GSSR+ID(s)):concat:regexTable((SM-\w\w\w\w\w)(\s)?(.*)<br/>+(\n)*;1;sample;3;comment)


Parse sample-names scattered across Text-field

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=labopsjira&jqlQuery=key=LCSET-10694&fields=key(key),customfield_10022(Important):concat:regexTable((SM-\w\w\w\w\w)(\s)?(.*)<br/>+(\n)*;1;sample))

Extract data from Broad's Cloud Jira and transparently consume it as a relational table within the DB

http://analytics.broadinstitute.org:8090/api/v2/JqlTableauExtractService?domain=broadinstitute.atlassian.net&jqlQuery=project = DSDEGP and status = open&fields=assignee(Assignee),created(Created):toDate,key(key),reporter(Reporter),status(Status),resolution(Resolution),customfield_17670(# Samples):concat,updated(Updated):toDate

CodeAssistant helps you build the URL by consulting to Jira metadata.

http://analytics:8090/api/v2/codeAssistant

Example

*NOTE: Comma (,) has a special meaning - it separates field-descriptions. If you need a comma in regular expressions (for example in commands like split, findAllMatch) you will have to encode comma with <CM>