Skip to content

Commit

Permalink
Add ability to display reference in changelog
Browse files Browse the repository at this point in the history
Defaults to not displaying reference, but can display reference if
so configured. Users might want to generate an internal changelog
with change references, and an external one without the additional
noise.

version: 0.8.0
tag: Added
  • Loading branch information
zumhagen committed Jul 3, 2017
1 parent 475bc16 commit 7120415
Show file tree
Hide file tree
Showing 11 changed files with 145 additions and 22 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name := "sct"

organization := "com.github.bzumhagen"

version := "0.7.0"
version := "0.8.0"

scalaVersion := "2.12.1"

Expand Down
21 changes: 13 additions & 8 deletions src/main/resources/changelogTemplate.ssp
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,34 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
<%@ val latestMinorChangeGroupOption: Option[ChangeGroup] %>
<%@ val latestMajorChangeGroupOption: Option[ChangeGroup] %>
<%@ val otherMajorChangeGroupOptions: Seq[Option[ChangeGroup]] = Seq() %>
<%@ val showReference: Boolean = false %>
#if (latestPatchChangeGroupOption.isDefined)
## [${latestPatchChangeGroupOption.get.version}] - ${latestPatchChangeGroupOption.get.date}
#for ((changeType, changes) <- latestPatchChangeGroupOption.get.typeToChanges)
### ${changeType}
#for (change <- changes)
- ${change.description}
#for (change <- changes)#if (showReference)-#if (change.reference.isDefined) (${change.reference.get}) #end ${change.description}
#else- ${change.description}
#end
#end
#end
#end
#if (latestMinorChangeGroupOption.isDefined)
## [${latestMinorChangeGroupOption.get.version}] - ${latestMinorChangeGroupOption.get.date}
#for ((changeType, changes) <- latestMinorChangeGroupOption.get.typeToChanges)
### ${changeType}
#for (change <- changes)
- ${change.description}
#for (change <- changes)#if (showReference)-#if (change.reference.isDefined) (${change.reference.get}) #end ${change.description}
#else- ${change.description}
#end
#end
#end
#end
#if (latestMajorChangeGroupOption.isDefined)
## [${latestMajorChangeGroupOption.get.version}] - ${latestMajorChangeGroupOption.get.date}
#for ((changeType, changes) <- latestMajorChangeGroupOption.get.typeToChanges)
### ${changeType}
#for (change <- changes)
- ${change.description}
#for (change <- changes)#if (showReference)-#if (change.reference.isDefined) (${change.reference.get}) #end ${change.description}
#else- ${change.description}
#end
#end
#end
#end
Expand All @@ -44,8 +48,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [${changeGroupOption.get.version}] - ${changeGroupOption.get.date}
#for ((changeType, changes) <- changeGroupOption.get.typeToChanges)
### ${changeType}
#for (change <- changes)
- ${change.description}
#for (change <- changes)#if (showReference)-#if (change.reference.isDefined) (${change.reference.get}) #end ${change.description}
#else- ${change.description}
#end
#end
#end
#end
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ sct {
"Deprecated"
]
smartGrouping = true
showReference = false
}
6 changes: 5 additions & 1 deletion src/main/resources/verboseChangelogTemplate.ssp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
<% import com.github.bzumhagen.sct.ChangelogChange %>
<% import com.github.bzumhagen.sct.ChangelogChange._ %>
<%@ val changes: List[ChangelogChange] = List() %>
<%@ val showReference: Boolean = false %>
#for (change <- changes)

## [${change.version}] - ${change.date}
### ${change.changeType}
### ${change.changeType}#if (showReference)
-#if (change.reference.isDefined) (${change.reference.get}) #end ${change.description}
#else
- ${change.description}
#end
#end
6 changes: 5 additions & 1 deletion src/main/scala/com/github/bzumhagen/sct/BuildChangelog.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import better.files.File
import com.github.bzumhagen.sct.git.GitChangelog
import com.typesafe.config.ConfigFactory


/** Object for main execution of the program */
object BuildChangelog extends App {
case class Arguments(pathToRepository: String = ".", pathToConfiguration: Option[String] = None)

Expand All @@ -25,6 +25,10 @@ object BuildChangelog extends App {
}
}

/** Generate a changelog file given some arguments.
*
* @param arguments arguments for generating a changelog file
*/
def generateChangelog(arguments: Arguments): Unit = {
val config =
if(arguments.pathToConfiguration.isDefined) {
Expand Down
8 changes: 8 additions & 0 deletions src/main/scala/com/github/bzumhagen/sct/ChangeGroup.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import java.time.LocalDate

import com.github.zafarkhaja.semver.Version

/** An object for loading changes into a change group using the latest version and date, and mapping all changes by type */
object ChangeGroup {
def load(changes: Seq[ChangelogChange]): Option[ChangeGroup] = {
if(changes.nonEmpty) {
Expand All @@ -21,4 +22,11 @@ object ChangeGroup {
}
}

/** A group of changes, grouped by type, with a group version and date
*
* @constructor create a new changelog group with a version, date, and map of change type to changes.
* @param version group version
* @param date group date
* @param typeToChanges map of changeType of a sequence of changes
*/
case class ChangeGroup(version: Version, date: LocalDate, typeToChanges: Map[String, Seq[ChangelogChange]])
8 changes: 8 additions & 0 deletions src/main/scala/com/github/bzumhagen/sct/Changelog.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ package com.github.bzumhagen.sct

import better.files.File

/** A trait defining a changelog.
*
* A changelog must implement two methods, getChanges and generateMarkdown.
* getChanges should return a sequence of changelog changes which represent the relevant changes
* retrieved from the repository.
* generateMarkdown should take a file and a sequence of changes, and produce a markdown file containing the specified
* changes.
*/
trait Changelog {
def getChanges: Seq[ChangelogChange]
def generateMarkdown(file: File, changes: Seq[ChangelogChange]): File
Expand Down
8 changes: 8 additions & 0 deletions src/main/scala/com/github/bzumhagen/sct/ChangelogChange.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,12 @@ import java.time.LocalDate

import com.github.zafarkhaja.semver.Version

/** A changelog change
*
* @param description change description
* @param version change version
* @param changeType change type (i.e. Added)
* @param reference change reference (i.e. XYZ-123)
* @param date change date
*/
case class ChangelogChange(description: String, version: Version, changeType: String, reference: Option[String], date: LocalDate)
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ object ChangelogConfiguration {
tagPattern = config.getString("sct.patterns.tag").r,
referencePattern = config.getString("sct.patterns.reference").r,
tags = config.getStringList("sct.tags").asScala.toSet,
smartGrouping = config.getBoolean("sct.smartGrouping")
smartGrouping = config.getBoolean("sct.smartGrouping"),
showReference = config.getBoolean("sct.showReference")
)
}
}
Expand All @@ -24,5 +25,6 @@ case class ChangelogConfiguration(
tagPattern: Regex,
referencePattern: Regex,
tags: Set[String],
smartGrouping: Boolean
smartGrouping: Boolean,
showReference: Boolean
)
19 changes: 17 additions & 2 deletions src/main/scala/com/github/bzumhagen/sct/git/GitChangelog.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,16 @@ import org.slf4j.LoggerFactory

import scala.util.matching.Regex

/** A changelog for a git repository.
*
* @constructor create a new git changelog with a config and directory.
* @param config changelog configuration
* @param gitDir directory containing the git repository
*/
class GitChangelog(val config: ChangelogConfiguration, val gitDir: File) extends Changelog {
private val logger = LoggerFactory.getLogger(classOf[GitChangelog])

/** Get all changes from git repository which match the mandatory criteria (i.e. contain version and specified tag) */
override def getChanges: Seq[ChangelogChange] = {
val gitRepository = Git.open(gitDir.toJava)
val gitLog = gitRepository.log().call().asScala
Expand All @@ -25,14 +32,22 @@ class GitChangelog(val config: ChangelogConfiguration, val gitDir: File) extends
gitLog.flatMap(buildChange).toSeq
}

/** Generate a markdown file given a file and a non-empty sequence of changes.
*
* @param file file to write markdown into
* @param changes sequence of changes to generate markdown for
*/
override def generateMarkdown(file: File, changes: Seq[ChangelogChange]): File = {
require(changes.nonEmpty, "Cannot generate markdown without changes")

val engine = new TemplateEngine
val changeBindings = buildChangeBindings(changes)
val nameBinding = Map("name" -> config.name)
val defaultBindings = Map(
"name" -> config.name,
"showReference" -> config.showReference
)
val template = if(config.smartGrouping) "/changelogTemplate.ssp" else "/verboseChangelogTemplate.ssp"
val output = engine.layout(template, nameBinding ++ changeBindings)
val output = engine.layout(template, defaultBindings ++ changeBindings)
file.writeText(output)
}

Expand Down
82 changes: 75 additions & 7 deletions src/test/scala/com/github/bzumhagen/sct/git/GitChangelogTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,32 @@ class GitChangelogTest extends FlatSpec with Matchers {
gitChangelog.generateMarkdown(changelogFile, actualChanges).contentAsString shouldBe expectedMarkdown
}

it should "generate a verbose markdown file properly" in {
it should "generate a smartGrouped markdown file properly with reference" in {
val (dir, repo) = initializeTemporaryGitRepo
val gitChangelog = new GitChangelog(DefaultConfiguration.copy(smartGrouping = false), dir)
val gitChangelog = new GitChangelog(DefaultConfiguration.copy(smartGrouping = true, showReference = true), dir)
val change = ChangelogChange("Ability to specify regex patterns for change elements", Version.valueOf("1.0.0"), "Added", Some("XYZ-123"), Today)
val changelogFile = File.newTemporaryFile("changelogTestFile")
val expectedMarkdown =
s"""# SCT Change Log
|All notable changes to this project will be documented in this file.
|
|The format is based on [Keep a Changelog](http://keepachangelog.com/)
|and this project adheres to [Semantic Versioning](http://semver.org/).
|
|## [${change.version}] - ${change.date}
|### ${change.changeType}
|- (${change.reference.get}) ${change.description}
|""".stripMargin

commitToRepo(repo, change.description, change.version, change.changeType, change.reference.getOrElse(""))

val actualChanges = gitChangelog.getChanges
gitChangelog.generateMarkdown(changelogFile, actualChanges).contentAsString shouldBe expectedMarkdown
}

it should "generate a verbose markdown file properly with references" in {
val (dir, repo) = initializeTemporaryGitRepo
val gitChangelog = new GitChangelog(DefaultConfiguration.copy(smartGrouping = false, showReference = true), dir)
val changes = Seq(
ChangelogChange("Create project", Version.valueOf("1.0.0"), "Added", Some("XYZ-123"), Today),
ChangelogChange("Add some functionality", Version.valueOf("1.1.0"), "Added", Some("XYZ-124"), Today),
Expand All @@ -175,23 +198,23 @@ class GitChangelogTest extends FlatSpec with Matchers {
|
|## [2.0.1] - $Today
|### Changed
|- Change some behavior
|- (XYZ-127) Change some behavior
|
|## [2.0.0] - $Today
|### Removed
|- Remove some deprecated functionality
|- (XYZ-126) Remove some deprecated functionality
|
|## [1.1.1] - $Today
|### Deprecated
|- Deprecate some functionality
|- (XYZ-125) Deprecate some functionality
|
|## [1.1.0] - $Today
|### Added
|- Add some functionality
|- (XYZ-124) Add some functionality
|
|## [1.0.0] - $Today
|### Added
|- Create project
|- (XYZ-123) Create project
|""".stripMargin

changes.foreach(change => commitToRepo(repo, change.description, change.version, change.changeType, change.reference.get))
Expand All @@ -200,6 +223,51 @@ class GitChangelogTest extends FlatSpec with Matchers {
gitChangelog.generateMarkdown(changelogFile, actualChanges).contentAsString shouldBe expectedMarkdown
}

it should "generate a verbose markdown file properly without references" in {
val (dir, repo) = initializeTemporaryGitRepo
val gitChangelog = new GitChangelog(DefaultConfiguration.copy(smartGrouping = false, showReference = false), dir)
val changes = Seq(
ChangelogChange("Create project", Version.valueOf("1.0.0"), "Added", Some("XYZ-123"), Today),
ChangelogChange("Add some functionality", Version.valueOf("1.1.0"), "Added", Some("XYZ-124"), Today),
ChangelogChange("Deprecate some functionality", Version.valueOf("1.1.1"), "Deprecated", Some("XYZ-125"), Today),
ChangelogChange("Remove some deprecated functionality", Version.valueOf("2.0.0"), "Removed", Some("XYZ-126"), Today),
ChangelogChange("Change some behavior", Version.valueOf("2.0.1"), "Changed", Some("XYZ-127"), Today)
)
val changelogFile = File.newTemporaryFile("changelogTestFile")
val expectedMarkdown =
s"""# SCT Change Log
|All notable changes to this project will be documented in this file.
|
|The format is based on [Keep a Changelog](http://keepachangelog.com/)
|and this project adheres to [Semantic Versioning](http://semver.org/).
|
|## [2.0.1] - $Today
|### Changed
|- Change some behavior
|
|## [2.0.0] - $Today
|### Removed
|- Remove some deprecated functionality
|
|## [1.1.1] - $Today
|### Deprecated
|- Deprecate some functionality
|
|## [1.1.0] - $Today
|### Added
|- Add some functionality
|
|## [1.0.0] - $Today
|### Added
|- Create project
|""".stripMargin

changes.foreach(change => commitToRepo(repo, change.description, change.version, change.changeType, change.reference.get))

val actualChanges = gitChangelog.getChanges
gitChangelog.generateMarkdown(changelogFile, actualChanges).contentAsString shouldBe expectedMarkdown
}

it should "fail if no changes are provided to markdown generation" in {
val gitChangelog = new GitChangelog(DefaultConfiguration, File.newTemporaryDirectory())
val changelogFile = File.newTemporaryFile("changelogTestFile")
Expand Down

0 comments on commit 7120415

Please sign in to comment.