If I want to change even a small detail about release notes (like date format or customize the summary message) it is not possible at the moment.
Solution:
We need some kind of customization of release notes.
First question I asked myself was how flexible it should be. User should be able to customize anything they want, but on the other hand assuming a simple base structure would probably make it easier for us to implement it, and maybe also to use it. We can probably assume that most of users would like to have a file with release notes sorted by date descending, so we can only allow formatting of a single release note.
So we can have a single release-notes.tmpl file which would contain the basic structure:
/header.tmpl
/release-summary.tmpl
/improvements.tmpl
And header.tmpl can be further divided into emphasized-header.tmpl and regular-header.tmpl, etc.
On each template user would be able to access "context" which would be a map of all properties related to release note (version, date, contributions etc).
This gives user flexibility to change only a small part of the template. On the other hand it makes it a little more complex, because of the multiple files. Also template engine has to support nesting templates.
I first thought about one of the popular templating engines and I read about Mustache and Freemarker. The choice between them was based on the fact that Mustache is much smaller (95 kb vs 795 kb) and also seems to be a little more popular and supports more languages, the latter is not critical.
So I tried much more flexible templating language - Groovy. First advantage is that we already have it on the classpath. It is a fully functional programming language, so it gives the end user a lot of flexibility, and also most users (especially Shipkit/Gradle users) should be familiar with its syntax.
I tried to use SimpleTemplateEngine class. Simple "regular-header.tmpl" would look like that:
**$version (${date.format("yyyy-MM-dd")})** -
As you can see formatting the date is really simple, as would be any other simple operation on text or numbers. The first problem I encountered is lack of support for nesting templates. I have managed to implement it myself by adding a closure "resolveTemplate" to "context" map. We can use it like that:
Argument "binding.variables" is the "context", we need to pass it every time when we want to nest a template. It is not that beautiful, but seems good enough, not that much code.
@mockito/shipkit-developers
At this point I would go with Groovy, but I am interested in the thoughts of others. If you want to see more I can create a pull request with the details of my proof of concept.
Great ideas and a very nice write-up! Some feedback:
it would be nice to list the use cases and problems we want to solve. Do you have a particular release notes improvement in mind?
it feels that having 3 template files is an additional complexity that may backfire. What if someone wants to present just the header, with not details? I'd suggest a single template file.
the simplest implementation is best. Perhaps we don't even need a file, just a 'notesTemplate' property on a task.
//idea: new 'setContent' method:
updateReleaseNotes.setContent { ReleaseNotesData data ->
return """multiline String that can reach out to $data"""
}
Problem:
If I want to change even a small detail about release notes (like date format or customize the summary message) it is not possible at the moment.
Solution:
We need some kind of customization of release notes.
First question I asked myself was how flexible it should be. User should be able to customize anything they want, but on the other hand assuming a simple base structure would probably make it easier for us to implement it, and maybe also to use it. We can probably assume that most of users would like to have a file with release notes sorted by date descending, so we can only allow formatting of a single release note.
So we can have a single release-notes.tmpl file which would contain the basic structure: /header.tmpl /release-summary.tmpl /improvements.tmpl
And header.tmpl can be further divided into emphasized-header.tmpl and regular-header.tmpl, etc. On each template user would be able to access "context" which would be a map of all properties related to release note (version, date, contributions etc). This gives user flexibility to change only a small part of the template. On the other hand it makes it a little more complex, because of the multiple files. Also template engine has to support nesting templates.
I first thought about one of the popular templating engines and I read about Mustache and Freemarker. The choice between them was based on the fact that Mustache is much smaller (95 kb vs 795 kb) and also seems to be a little more popular and supports more languages, the latter is not critical.
The problem with Mustache is that there seems to be no simple way to eg. format dates (see https://javarants.com/mustache-is-logic-less-but-the-logic-has-to-go-somewhere-3e976b7a49c8). It is supposed to be logic-free. In our case it drastically limits the abilities of end users.
So I tried much more flexible templating language - Groovy. First advantage is that we already have it on the classpath. It is a fully functional programming language, so it gives the end user a lot of flexibility, and also most users (especially Shipkit/Gradle users) should be familiar with its syntax.
I tried to use SimpleTemplateEngine class. Simple "regular-header.tmpl" would look like that:
**$version (${date.format("yyyy-MM-dd")})** -
As you can see formatting the date is really simple, as would be any other simple operation on text or numbers. The first problem I encountered is lack of support for nesting templates. I have managed to implement it myself by adding a closure "resolveTemplate" to "context" map. We can use it like that:
header.tmpl
${resolveTemplate(binding.variables, emphasize ? 'emphasized-header.tmpl' : 'regular-header.tmpl')}>
Argument "binding.variables" is the "context", we need to pass it every time when we want to nest a template. It is not that beautiful, but seems good enough, not that much code.
@mockito/shipkit-developers At this point I would go with Groovy, but I am interested in the thoughts of others. If you want to see more I can create a pull request with the details of my proof of concept.