How to generate a changelog from Jira for your deb/rpm/…

A changelog is a log or record of changes made to a project, such as a website or software project, usually including such records as bug fixes, new features, etc. Some open source projects include a changelog as one of the top level files in their distribution.

If you are running a RHEL distribution (Centos, Fedora, Red Hat…), you can read it via the rpm command:

rpm -q --changelog vim-enhanced.x86_64 | less

For Debian based distributions, you can do it via apt-get:

apt-get changelog vim | less

If you build rpm or deb packages, it can be usefull to generate a changelog, but how to generate it from Jira?

Jira provides a versions tab on the project home page:
We want to extract all the tickets under these versions and generate a changelog file that will be attached to the package. And this is pretty simple: Jira offers a JQL interface where you can query the underlying database with JPA-like language (, and an awesome REST API (

The format of a changelog file is simple. Start each new entry with a line with a * followed by the date, and optionnaly with your name and your email address. The date should appear in the same format that is output by: date +”%a %b %d %Y”. We will use joda-time as dateformatter rest of the section is a free text field, but should be organized in some coherent manner.

First, you need some dependencies:


Atlassian has a custom Maven repo:


Second, you have to launch an ugly piece of code like this one in order to generate a changelog for the project DATASOLR (

import java.util.Locale;
import java.util.concurrent.ExecutionException;

import org.apache.http.client.ClientProtocolException;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormatterBuilder;
import org.junit.Test;


public class Jira {

 public void monTest() throws URISyntaxException, InterruptedException,
   ExecutionException, ClientProtocolException, IOException {

  // Output
  File releaseNote = new File("/tmp/changelog");

  if (!releaseNote.exists()) {
  } else {

  BufferedWriter writer = new BufferedWriter(new FileWriter(

  // Formatter
  DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    .appendDayOfWeekShortText().appendLiteral(' ')
    .appendMonthOfYearShortText().appendLiteral(' ')
    .appendDayOfMonth(2).appendLiteral(' ').appendYear(4, 4)

  // Client
  JiraRestClientFactory factory = new AsynchronousJiraRestClientFactory();
  URI jiraServerUri = new URI("");
  JiraRestClient restClient = factory.create(jiraServerUri,
    new AnonymousAuthenticationHandler());

  SearchResult searchResult = restClient
      "project = DATASOLR and fixVersion is not null ORDER BY fixVersion desc, issuetype asc",
      1000, 0, null).get();

  // Prepare data
  String lastIssueType = null;
  String lastRelease = null;
  for (Issue issue : searchResult.getIssues()) {
   Version version = issue.getFixVersions().iterator().next();
   if (lastRelease == null || !lastRelease.equals(version.getName())) {
    lastRelease = version.getName();
    if (lastRelease == null) {
    writer.append("* ").append(fmt.print(version.getReleaseDate()))
      .append(" ").append(version.getName()).append("\n");
    lastIssueType = null;
   if (lastIssueType == null
     || !lastIssueType.equals(issue.getIssueType().getName())) {
    lastIssueType = issue.getIssueType().getName();
    writer.append("- ").append(lastIssueType).append("\n");
   writer.append("\t[").append(issue.getKey()).append("] ");




We are using a AnonymousAuthenticationHandler because most of open source projects doesn’t need an authentication on Jira. If you need it, you can switch to a BasicHttpAuthenticationHandler:

JiraRestClient restClient = factory.createWithBasicHttpAuthentication(
    jiraServerUri, "jira", "jira");

For custom authentication schemes (OAuth…), create a specific implementation of the interface AuthenticationHandler.

And finally, you will get a file /tmp/changelog containing something like:

* Thu Oct 17 2013 1.0.1
- Bug
 [DATASOLR-116] MappingSolrConverter doesn't honor Solr wildcard rules on read

* Wed Sep 11 2013 1.0 GA
- Bug
 [DATASOLR-98] MappingSolrConverter does not retain element order when reading property
 [DATASOLR-81] Cannot index Geospatial with solr4

- Improvement
 [DATASOLR-100] Support proximity or sloppy searches
 [DATASOLR-68] Add support for facet.prefix

- New Feature
 [DATASOLR-93] Solr softCommit support

- Task
 [DATASOLR-111] Release 1.0 GA


Sources and other infos:

Leave a comment

About privacy:

This site uses Akismet to reduce spam. Learn how your comment data is processed.