Creating release notes from a Jira query

illustrations illustrations illustrations illustrations illustrations illustrations illustrations
post-thumb
                 

Published on 5 May 2022 by Andrew Owen (6 minutes)

In this article, I’ll describe a solution to simplify the process of creating release notes in MadCap Flare from a Jira query. Jira is a popular issue tracking platform from Atlassian. But this approach can also be adapted to any other platform that can export issues in XML format and any XML-based doc tool.

Pre-requisites

We’ll be running a script from the command line to fetch the information we require from Jira, process it, and output a Flare document. To perform the fetch we’ll use a tool called cURL (Client URL). This should already be installed as part of your operating system unless you’re using a version of Windows earlier than Windows 10.

The processing is done using an XSLT (eXtensible Stylesheet Language Transformations) parser. Microsoft provides MSXSL.EXE as part of Microsoft Core XML Services (MSXML) 6.0. However, this only supports XSLT 1.0, so I recommend using Saxon, which has full XSLT 3.0 support.

You’ll probably need to install an XSLT processor. This used to be complicated, but now you can do it with node.js:

npm install -g saxon-js
npm install -g xslt3

You should probably still check with your company’s IT policy before proceeding. You may need to ask your IT department to install the software for you.

Saxon applies the instructions in an XSL file to transform the raw XML fetched by cURL into a Flare document with the required content.

You’ll need to create a Jira API key for the script:

  1. In Jira, navigate to Your profile and settings > Manage account > Security and click Create and manage API tokens.
  2. Click Create API token.
  3. Enter a Label, for example, Jira2Flare and click Create.
  4. Click Copy and paste the result into a text editor.
  5. Click Close.

Note, you should only use this API key within your script. The script should be stored where only you can access it. If you believe your security has been compromised, in Jira navigate to Create and manage API tokens, locate the token and click Revoke to deactivate it.

You’ll also need the Jira query string. Explaining Jira queries is beyond the scope of this article, so I’ll assume you already have a search query that returns the release notes for a specific version of the software:

  1. Open the query in your browser and, from the Actions (…) menu, right-click Export XML and click Copy link address (or the equivalent if you’re not using Google Chrome).
  2. Paste the link into a text editor and replace any single per cent signs (%) with a double per cent sign (%%).
  3. Replace the fixversion string with %fixversion% (with single per cent signs).
  4. Add a double quote (") at the start and end of the string.

The Export XML option formats the output as an RSS feed. This determines the structure of the XML file, but you don’t really need to know anything about RSS for the purposes of this article.

Create the cURL script

In the sample script, I’m assuming you have a custom Jira field with the name Release Notes. If it’s called something else you can change the script as required. If there is no equivalent field to notify you which tickets should be included in a release note, you should ask your Jira administrator to create one.

Typically, releases in Jira are identified by a fixversion value. We can create a Windows script that takes this value as input and downloads the query results. Paste the following into a text editor and save it as jira2flare.cmd:

    @echo off
    echo Please enter a fix version:
    set /p fixversion=""
    cls
    curl -o input.xml -u user@example.com:APIkey "Jira query with the % charcters escaped as %% and the fixversion entered as %fixversion%"
    Transform input.xml j2f.xsl > output.html

Replace user@example.com with your email address, APIkey with your API key, and replace the Jira query string with the one from your text editor.

The last line of the script performs the transform. We’ll come to that in a moment. Before you do the transform, you should verify that the cURL command is working. If all the parameters are correct, a file called input.xml is created.

Transform the query into a Flare document

Paste the following into a text editor and save it as j2f.xsl in the same folder where you saved jira2flare.cmd:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
  <xsl:strip-space elements="*" />
  <xsl:template match="/">
  <html xmlns:MadCap="http://www.madcapsoftware.com/Schemas/MadCap.xsd" MadCap:onlyLocalStylesheets="True">
    <head>
      <link rel="stylesheet" type="text/css" href="../Resources/Stylesheets/yourstyles.css" />
    </head>
    <body>
      <h1>Release Notes</h1>
      <table border="1">
        <tr>
          <th>Modules</th>
          <th>Summary</th>
          <th>Ticket</th>
          <th>Category</th>
          <th>Fix Versions</th>
          </tr>
          <xsl:for-each select="rss/channel/item/customfields/customfield">
            <xsl:if test="customfieldname[text()='Release Notes']">
              <tr>
                <td>
                  <xsl:value-of select="../customfield/customfieldname[text()='Modules']/../customfieldvalues/customfieldvalue" />
                </td>
                <td>
                  <xsl:value-of select="customfieldvalues/customfieldvalue" disable-output-escaping="yes" />
                </td>
                <td>
                  <xsl:value-of select="../../key" />
                </td>
                <td>
                  <xsl:value-of select="../customfield/customfieldname[text()='Category']/../customfieldvalues/customfieldvalue" />
                </td>
                <td>
                  <xsl:value-of select="../../fixVersion" />
                </td>
              </tr>
            </xsl:if>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

The XSL file determines which information from the XML file (the Jira query) is included in the Flare document and how it is formatted. You can change this by editing the XSL file. In this example we want the Modules, Summary, Ticket, Category and Fix Versions.

Here’s a brief summary of what this transform file is instructing the XSLT processor to do:

  1. Transform the raw XML file into an HTML file using the Madcap Flare stylesheet.
  2. Create a Release Notes heading.
  3. Create a table with the headings Modules, Summary, Ticket, Category, and Fix Versions.
  4. For each entry in the source XML file where the Release Notes custom field exists, create a line in the table containing the relevant values.

The values in the XSL tags in the table are instructions to the XSLT processor on how to navigate the source XML file. If you want to learn more about transforming XML using XSLT, w3schools provides an introduction.

Now when you run the jira2flare.cmd script, in addition to the input.xml file you should get an output.html file that you can open directly in Flare.

Summary

One important thing to keep in mind is that if you normally edit your release notes in Flare, with this process you should be making your changes in Jira. This has the twofold benefit that reviews can be done in Jira, and your published release notes will match your tickets.

XSL Transformations are a powerful tool for converting XML documents from one form into another. Indeed, we have barely scratched the surface of what’s possible. If you want to take things to the next level, you can talk to your dev ops team about automating the process. But hopefully what you’ve learned here will help speed up your release note workflow.

Afterword

So, automation. Here’s a sample GitHub action:

name: RSS to Flare
on:
  workflow_displatch
jobs:
  rss2flare:
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - shell: bash
        env:
          APIKEY: ${{ secrets.JIRA_API_KEY }}
          FIXVERSION: ${{ vars.FIXVERSION }}
        run: |
          curl -o input.xml -u user.name@example.com:$APIKEY "<jira query including $FIXVERSION>"          
      - name: install Saxon and transform XML
        run: |
          npm install -g saxon-js
          npm install -g xslt3
          xslt3 -s:input.xml -xsl:rss2falre.xsl -o:output.html          
      - name: check for changes
        id: changes
        run |
          git fetch origin main
          echo "result=$(git diff -quiet origin/${{ github.base_ref }} ${{ github.sha }} - ./ || echo 'changes-found')" > $GITHUB_OUTPUT
          continue-on-error: true
      - name: No changes found
        if: steps.changes.outputs.result != 'changes-found'
        run: echo "No changes found in the '$({ env.working-directory })' folder in comparison to the 'main' branch. Skipping commit."
      - name: Commit files
        if: steps.changes.outputs.result == 'changes-found"
        run: |
          git config --local user.email "github-actions@users.noreply-github.com"
          git config --local user.name "github-actions"
          git add
          git commit -a -m "Commit changes"          
      - name: Push changes
        if: steps.changes.outputs.result == 'changes-found'
        run: git push origin main

Image: Original by Danmeil Korpai.