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

From wikipedia:
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: https://jira.springsource.org/browse/DATASOLR?selectedTab=com.atlassian.jira.plugin.system.project%3Aversions-panel
 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 (https://confluence.atlassian.com/display/JIRA/Advanced+Searching), and an awesome REST API (https://docs.atlassian.com/jira/REST/latest/).

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 http://www.joda.org/joda-time/).The rest of the section is a free text field, but should be organized in some coherent manner. 

First, you need some dependencies:

<dependency>
<groupId>com.atlassian.jira</groupId>
<artifactId>jira-rest-java-client-core</artifactId>
<version>2.0.0-m25</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3</version>
</dependency>

NB: Atlassian has a custom Maven repo:

<repository>
<id>atlassian-public</id>
<url>https://m2proxy.atlassian.com/repository/public</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
<releases>
<enabled>true</enabled>
<checksumPolicy>warn</checksumPolicy>
</releases>
</repository>


Second, you have to launch an ugly piece of code like this one in order to generate a changelog for the project DATASOLR (https://jira.springsource.org/browse/DATASOLR):


import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
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;

import com.atlassian.jira.rest.client.api.JiraRestClient;
import com.atlassian.jira.rest.client.api.JiraRestClientFactory;
import com.atlassian.jira.rest.client.api.domain.Issue;
import com.atlassian.jira.rest.client.api.domain.SearchResult;
import com.atlassian.jira.rest.client.api.domain.Version;
import com.atlassian.jira.rest.client.auth.AnonymousAuthenticationHandler;
import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory;

public class Jira {

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

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

if (!releaseNote.exists()) {
releaseNote.createNewFile();
} else {
releaseNote.delete();
releaseNote.createNewFile();
}

BufferedWriter writer = new BufferedWriter(new FileWriter(
releaseNote.getAbsoluteFile()));

// Formatter
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendDayOfWeekShortText().appendLiteral(' ')
.appendMonthOfYearShortText().appendLiteral(' ')
.appendDayOfMonth(2).appendLiteral(' ').appendYear(4, 4)
.toFormatter().withLocale(Locale.US);

// Client
JiraRestClientFactory factory = new AsynchronousJiraRestClientFactory();
URI jiraServerUri = new URI("https://jira.springsource.org");
JiraRestClient restClient = factory.create(jiraServerUri,
new AnonymousAuthenticationHandler());

SearchResult searchResult = restClient
.getSearchClient()
.searchJql(
"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("\n");
}
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("] ");
writer.append(issue.getSummary());

writer.append("\n");
}

restClient.close();
writer.close();

}
}

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
....




Enjoy!

Sources and other infos:

http://www.tldp.org/HOWTO/RPM-HOWTO/build.html
http://en.wikipedia.org/wiki/Release_notes
http://www.cyberciti.biz/tips/howto-find-out-linux-rpm-package-changelog.html



Labels: , , , ,