Skip to content
This repository has been archived by the owner on Dec 5, 2024. It is now read-only.

Commit

Permalink
Custom GitHub release body (#9)
Browse files Browse the repository at this point in the history
* Add new util class ReleaseNotesGenerator

* Set lazy github release body value with custom ReleaseBodyStrategy

The new helper class `ReleaseBodyStrategy` implements
`PublishBodyStrategy` from the `net.wooga.atlas-github` plugin.
The strategy method `getBody` will be called with the `GHRepository`
object for the current release. The method will call
`ReleaseNotesGenerator`'s method `generateReleaseNotes`
  • Loading branch information
Larusso authored Aug 15, 2017
1 parent 18e66ec commit d29aeae
Show file tree
Hide file tree
Showing 6 changed files with 492 additions and 1 deletion.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ dependencies {
compile 'org.ajoberstar:gradle-git:1.7.+'
compile 'cz.malohlava:visteg:1.0.+'
compile 'gradle.plugin.net.wooga.gradle:atlas-paket:0.7.0'
compile 'gradle.plugin.net.wooga.gradle:atlas-github:0.3.0'
compile 'gradle.plugin.net.wooga.gradle:atlas-github:0.5.0'

compile gradleApi()
compile localGroovy()
Expand Down
11 changes: 11 additions & 0 deletions src/main/groovy/wooga/gradle/release/ReleasePlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import cz.malohlava.VisTegPluginExtension
import nebula.core.ProjectType
import nebula.plugin.release.NetflixOssStrategies
import org.ajoberstar.gradle.git.release.base.ReleasePluginExtension
import org.ajoberstar.gradle.git.release.base.ReleaseVersion
import org.gradle.api.Action
import org.gradle.api.Plugin
import org.gradle.api.Project
Expand All @@ -35,13 +36,17 @@ import org.gradle.api.specs.Spec
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.Delete
import org.gradle.language.base.plugins.LifecycleBasePlugin
import org.kohsuke.github.GHRepository
import wooga.gradle.github.publish.GithubPublish
import wooga.gradle.github.publish.GithubPublishPlugin
import wooga.gradle.github.publish.PublishBodyStrategy
import wooga.gradle.paket.PaketPlugin
import wooga.gradle.paket.base.PaketBasePlugin
import wooga.gradle.paket.get.PaketGetPlugin
import wooga.gradle.paket.pack.tasks.PaketPack
import wooga.gradle.paket.unity.PaketUnityPlugin
import wooga.gradle.release.utils.ReleaseBodyStrategy
import wooga.gradle.release.utils.ReleaseNotesGenerator

class ReleasePlugin implements Plugin<Project> {

Expand Down Expand Up @@ -106,6 +111,8 @@ class ReleasePlugin implements Plugin<Project> {
postReleaseTask.dependsOn publishTask
publishTask.mustRunAfter releaseTask

ReleasePluginExtension releaseExtension = project.extensions.findByType(ReleasePluginExtension)

githubPublishTask.onlyIf(new Spec<Task>() {
@Override
boolean isSatisfiedBy(Task task) {
Expand All @@ -119,6 +126,10 @@ class ReleasePlugin implements Plugin<Project> {
githubPublishTask.dependsOn archives
githubPublishTask.tagName = "v${project.version}"
githubPublishTask.setReleaseName(project.version.toString())
//infer the ReleaseVersion in the private class DelayedVersion to be able to access the `inferredVersion` property
//the release plugin sets this object as version to all projects
project.version.toString()
githubPublishTask.body(new ReleaseBodyStrategy(project.version.inferredVersion as ReleaseVersion, releaseExtension.grgit))
}

configureVersionCode(project)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package wooga.gradle.release.utils

import org.ajoberstar.gradle.git.release.base.ReleaseVersion
import org.ajoberstar.grgit.Grgit
import org.kohsuke.github.GHRepository
import wooga.gradle.github.publish.PublishBodyStrategy

class ReleaseBodyStrategy implements PublishBodyStrategy {

private Grgit git
private ReleaseVersion version

ReleaseBodyStrategy(ReleaseVersion version, Grgit git) {
this.git = git
this.version = version
}

@Override
String getBody(GHRepository repository) {
return new ReleaseNotesGenerator(git, repository).generateReleaseNotes(version)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package wooga.gradle.release.utils

import org.ajoberstar.gradle.git.release.base.ReleaseVersion
import org.ajoberstar.grgit.Commit
import org.ajoberstar.grgit.Grgit
import org.kohsuke.github.GHPullRequest
import org.kohsuke.github.GHRepository

/**
* A generator class to create release notes from git log and pull request bodies.
*/
class ReleaseNotesGenerator {

public static final String INITAL_RELEASE_MSG = "* ![NEW] Initial Release\n"
public static final String ICON_IDS = """
<!-- START icon Id's -->
[NEW]:http://resources.atlas.wooga.com/icons/icon_new.svg "New"
[ADD]:http://resources.atlas.wooga.com/icons/icon_add.svg "Add"
[IMPROVE]:http://resources.atlas.wooga.com/icons/icon_improve.svg "IMPROVE"
[CHANGE]:http://resources.atlas.wooga.com/icons/icon_change.svg "Change"
[FIX]:http://resources.atlas.wooga.com/icons/icon_fix.svg "Fix"
[UPDATE]:http://resources.atlas.wooga.com/icons/icon_update.svg "Update"
[BREAK]:http://resources.atlas.wooga.com/icons/icon_break.svg "Remove"
[REMOVE]:http://resources.atlas.wooga.com/icons/icon_remove.svg "Remove"
[IOS]:http://resources.atlas.wooga.com/icons/icon_iOS.svg "iOS"
[ANDROID]:http://resources.atlas.wooga.com/icons/icon_android.svg "Android"
[WEBGL]:http://resources.atlas.wooga.com/icons/icon_webGL.svg "Web:GL"
<!-- END icon Id's -->
""".stripIndent()

private Grgit git
private GHRepository hub

ReleaseNotesGenerator(Grgit git, GHRepository hub) {
this.git = git
this.hub = hub
}

/**
* Generates a release note body message with given <code>version</code>.
* The generator will parse the git log from <code>HEAD</code> to previous version
* and reads change lists from referenced pull requests. If no pull requests commits
* can be found, it will list the git log.
* @param version The <code>ReleaseVersion</code> to create the release note for
* @return a <code>String</code> containing the generated release notes
*/
String generateReleaseNotes(ReleaseVersion version) {
StringBuilder builder = new StringBuilder()
List<String> includes = ['HEAD']
List<String> excludes = createExcludes(version)

if (!version.previousVersion) {
builder << INITAL_RELEASE_MSG
}

List<Commit> log = git.log(includes: includes, excludes: excludes)
List<GHPullRequest> pullRequests = fetchPullRequestsFromLog(log)

List<String> changeList = []
pullRequests.inject(changeList) { ch, pr ->
def changes = pr.body.readLines().findAll { it.trim().startsWith("* ![") }
changes = changes.collect { it + " [#${pr.number}]" }
ch << changes.join("\n")
}

if (changeList.size() == 0) {
changeList << log.collect({ "* ${it.shortMessage}" }).join("\n")
}

changeList.removeAll([""])

if (changeList.size() > 0) {
builder << changeList.join("\n")
builder << "\n"
builder << ICON_IDS
}

builder.toString().trim()
}

protected List<GHPullRequest> fetchPullRequestsFromLog(List<Commit> log) {
String pattern = /#(\d+)/
def prCommits = log.findAll { it.shortMessage =~ pattern }
def prNumbers = prCommits.collect {
def m = (it.shortMessage =~ pattern)
m[0][1].toInteger()
}
def prs = prNumbers.collect { hub.getPullRequest(it) }
prs.removeAll([null])
prs
}

private List<String> createExcludes(ReleaseVersion version) {
List<String> excludes = []
if (version.previousVersion) {
String previousVersion = "v${version.previousVersion}^{commit}"
if (tagExists(previousVersion)) {
excludes << previousVersion
}
}
excludes
}

private boolean tagExists(String revStr) {
try {
git.resolve.toCommit(revStr)
return true
} catch (e) {
return false
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package wooga.gradle.release.utils

import org.ajoberstar.gradle.git.release.base.ReleaseVersion
import org.ajoberstar.grgit.Grgit
import org.kohsuke.github.GHPullRequest
import org.kohsuke.github.GHRepository
import spock.lang.Specification

class ReleaseBodyStrategySpec extends Specification {

ReleaseBodyStrategy releaseBodyStrategy
Grgit git
GHRepository repository
ReleaseVersion version

def mockPullRequest(int number, Boolean changeSet = true) {
def bodyOut = new StringBuilder()

bodyOut << """
## Description
Yada Yada Yada Yada Yada
Yada Yada Yada Yada Yada
Yada Yada Yada Yada Yada
""".stripIndent()

if(changeSet) {
bodyOut << """
## Changes
* ![ADD] some stuff
* ![REMOVE] some stuff
* ![FIX] some stuff
Yada Yada Yada Yada Yada
Yada Yada Yada Yada Yada
Yada Yada Yada Yada Yada
""".stripIndent()
}

def pr = Mock(GHPullRequest)
pr.body >> bodyOut.toString()
pr.number >> number
return pr
}

def setup() {
git = Grgit.init(dir: File.createTempDir())
git.commit(message: 'initial commit')

repository = Mock(GHRepository)
version = new ReleaseVersion("1.1.0", "1.0.0", false)

releaseBodyStrategy = new ReleaseBodyStrategy(version, git)
}

def "verify calls ReleaseNotesGenerator to generate release notes body"() {
given: "a git log with pull requests commits and tags"

git.commit(message: 'commit')
git.commit(message: 'commit (#1)')
git.tag.add(name: 'v1.0.0')
git.commit(message: 'commit')
git.commit(message: 'commit (#2)')
git.commit(message: 'commit (#3)')
git.commit(message: 'commit')

and: "mocked pull requests"
repository.getPullRequest(1) >> mockPullRequest(1)
repository.getPullRequest(2) >> mockPullRequest(2)
repository.getPullRequest(3) >> mockPullRequest(3)

when:
def body = releaseBodyStrategy.getBody(repository)

then:
body == ("""
* ![ADD] some stuff [#3]
* ![REMOVE] some stuff [#3]
* ![FIX] some stuff [#3]
* ![ADD] some stuff [#2]
* ![REMOVE] some stuff [#2]
* ![FIX] some stuff [#2]
""".stripIndent().stripMargin() + ReleaseNotesGenerator.ICON_IDS).trim()
}
}
Loading

0 comments on commit d29aeae

Please sign in to comment.