├── settings.gradle ├── src ├── main │ └── kotlin │ │ └── io │ │ └── wusa │ │ ├── Suffix.kt │ │ ├── TagType.kt │ │ ├── Version.kt │ │ ├── incrementer │ │ ├── IIncrementer.kt │ │ ├── NoVersionIncrementer.kt │ │ ├── PatchVersionIncrementer.kt │ │ ├── MinorVersionIncrementer.kt │ │ ├── MajorVersionIncrementer.kt │ │ ├── VersionIncrementer.kt │ │ └── ConventionalCommitsIncrementer.kt │ │ ├── IVersionFactory.kt │ │ ├── exception │ │ ├── GitException.kt │ │ ├── NoLastTagFoundException.kt │ │ ├── NoCurrentTagFoundException.kt │ │ ├── DirtyWorkingTreeException.kt │ │ ├── NoCurrentBranchFoundException.kt │ │ ├── NoCurrentCommitFoundException.kt │ │ ├── NoIncrementerFoundException.kt │ │ └── NoValidSemverTagFoundException.kt │ │ ├── RegexResolver.kt │ │ ├── Branch.kt │ │ ├── extension │ │ ├── Branches.kt │ │ ├── Branch.kt │ │ └── SemverGitPluginExtension.kt │ │ ├── GitCommandRunner.kt │ │ ├── SemverGitPlugin.kt │ │ ├── Info.kt │ │ ├── SemanticVersionFactory.kt │ │ ├── formatter │ │ └── SemanticVersionFormatter.kt │ │ ├── GitService.kt │ │ └── VersionService.kt └── test │ └── kotlin │ └── io │ └── wusa │ ├── SemverGitPluginExtensionTest.kt │ ├── IncrementerTest.kt │ ├── VersionIncrementerTest.kt │ ├── FunctionalBaseTest.kt │ ├── BranchTest.kt │ ├── InfoTest.kt │ ├── ConventionalCommitsIncrementerTest.kt │ ├── GitServiceTest.kt │ ├── SemanticVersionFactoryTest.kt │ ├── SemverGitPluginKotlinFunctionalTest.kt │ └── SemverGitPluginGroovyFunctionalTest.kt ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .codecov.yml ├── .travis.yml ├── LICENSE.md ├── gradlew.bat ├── CHANGELOG.md ├── .gitignore ├── gradlew └── README.md /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'semver-git-plugin' 2 | 3 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/Suffix.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | data class Suffix(var count: Int, var sha: String, var dirty: Boolean) -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilovemilk/semver-git-plugin/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/TagType.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | enum class TagType(val tagTypeName: String) { 4 | LIGHTWEIGHT("lightwweight"), 5 | ANNOTATED("annotated") 6 | } 7 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/Version.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | data class Version(var major: Int, var minor: Int, var patch: Int, var prerelease: String, var build: String, var suffix: Suffix?) -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | precision: 2 3 | round: down 4 | range: "70...100" 5 | status: 6 | project: off 7 | patch: off 8 | 9 | comment: 10 | layout: "reach,diff,flags,tree" 11 | behavior: default 12 | require_changes: no -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/incrementer/IIncrementer.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.incrementer 2 | 3 | import io.wusa.Version 4 | import org.gradle.api.Project 5 | 6 | 7 | interface IIncrementer { 8 | 9 | fun increment(version: Version, project: Project): Version 10 | } 11 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Feb 09 16:22:34 CET 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip 7 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/IVersionFactory.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import io.wusa.exception.NoValidSemverTagFoundException 4 | 5 | interface IVersionFactory { 6 | 7 | @Throws(NoValidSemverTagFoundException::class) 8 | fun createFromString(describe: String): Version 9 | } 10 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/exception/GitException.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.exception 2 | 3 | class GitException: Exception { 4 | constructor(message: String, ex: Throwable?): super(message, ex) {} 5 | constructor(message: String): super(message) {} 6 | constructor(ex: Throwable): super(ex) {} 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/exception/NoLastTagFoundException.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.exception 2 | 3 | class NoLastTagFoundException: Exception { 4 | constructor(message: String, ex: Throwable?): super(message, ex) {} 5 | constructor(message: String): super(message) {} 6 | constructor(ex: Throwable): super(ex) {} 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/exception/NoCurrentTagFoundException.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.exception 2 | 3 | class NoCurrentTagFoundException: Exception { 4 | constructor(message: String, ex: Throwable?): super(message, ex) {} 5 | constructor(message: String): super(message) {} 6 | constructor(ex: Throwable): super(ex) {} 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/exception/DirtyWorkingTreeException.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.exception 2 | 3 | class DirtyWorkingTreeException: Exception { 4 | constructor(message: String, ex: Throwable?): super(message, ex) {} 5 | constructor(message: String): super(message) {} 6 | constructor(ex: Throwable): super(ex) {} 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/exception/NoCurrentBranchFoundException.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.exception 2 | 3 | class NoCurrentBranchFoundException: Exception { 4 | constructor(message: String, ex: Throwable?): super(message, ex) {} 5 | constructor(message: String): super(message) {} 6 | constructor(ex: Throwable): super(ex) {} 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/exception/NoCurrentCommitFoundException.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.exception 2 | 3 | class NoCurrentCommitFoundException: Exception { 4 | constructor(message: String, ex: Throwable?): super(message, ex) {} 5 | constructor(message: String): super(message) {} 6 | constructor(ex: Throwable): super(ex) {} 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/exception/NoIncrementerFoundException.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.exception 2 | 3 | class NoIncrementerFoundException : Exception { 4 | constructor(message: String, ex: Throwable?) : super(message, ex) {} 5 | constructor(message: String) : super(message) {} 6 | constructor(ex: Throwable) : super(ex) {} 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/exception/NoValidSemverTagFoundException.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.exception 2 | 3 | class NoValidSemverTagFoundException : Exception { 4 | constructor(message: String, ex: Throwable?) : super(message, ex) {} 5 | constructor(message: String) : super(message) {} 6 | constructor(ex: Throwable) : super(ex) {} 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/incrementer/NoVersionIncrementer.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.incrementer 2 | 3 | import io.wusa.Version 4 | import org.gradle.api.Project 5 | 6 | class NoVersionIncrementer: IIncrementer { 7 | override fun increment(version: Version, project: Project): Version { 8 | return version 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/incrementer/PatchVersionIncrementer.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.incrementer 2 | 3 | import io.wusa.Version 4 | import org.gradle.api.Project 5 | 6 | class PatchVersionIncrementer: IIncrementer { 7 | override fun increment(version: Version, project: Project): Version { 8 | version.patch += 1 9 | return version 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/incrementer/MinorVersionIncrementer.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.incrementer 2 | 3 | import io.wusa.Version 4 | import org.gradle.api.Project 5 | 6 | 7 | class MinorVersionIncrementer: IIncrementer { 8 | override fun increment(version: Version, project: Project): Version { 9 | version.minor += 1 10 | version.patch = 0 11 | return version 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/incrementer/MajorVersionIncrementer.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.incrementer 2 | 3 | import io.wusa.Version 4 | import org.gradle.api.Project 5 | 6 | class MajorVersionIncrementer: IIncrementer { 7 | override fun increment(version: Version, project: Project): Version { 8 | version.major += 1 9 | version.minor = 0 10 | version.patch = 0 11 | return version 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/RegexResolver.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import io.wusa.extension.Branch 4 | import io.wusa.extension.Branches 5 | 6 | class RegexResolver { 7 | companion object { 8 | fun findMatchingRegex(branches: Branches, branchName: String): Branch? { 9 | return try { 10 | branches.branch.firstOrNull { 11 | it.regex.toRegex().matches(branchName) 12 | } 13 | } catch (e: Exception) { 14 | return null 15 | } 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/Branch.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import io.wusa.exception.NoCurrentBranchFoundException 4 | import org.gradle.api.Project 5 | 6 | data class Branch(private var project: Project) { 7 | val group: String 8 | get() = this.name.split("/")[0] 9 | 10 | val name: String 11 | get() { 12 | return try { 13 | GitService.currentBranch(project) 14 | } catch (ex: NoCurrentBranchFoundException) { 15 | "" 16 | } 17 | } 18 | 19 | val id: String 20 | get() = this.name.replace("/", "-") 21 | } -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/extension/Branches.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.extension 2 | 3 | import groovy.lang.Closure 4 | import org.gradle.api.Project 5 | import org.gradle.util.ConfigureUtil 6 | 7 | class Branches(val project: Project) { 8 | val branch = mutableListOf() 9 | 10 | fun branch(configure: Branch.() -> Unit) { 11 | createAndAddBranch().configure() 12 | } 13 | fun branch(closure: Closure<*>): Branch { 14 | return ConfigureUtil.configure(closure, createAndAddBranch()) 15 | } 16 | 17 | private fun createAndAddBranch() = Branch(project).apply { 18 | branch.add(this) 19 | } 20 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk11 4 | before_script: 5 | - chmod +x gradlew 6 | jobs: 7 | include: 8 | - stage: test 9 | script: "./gradlew check" 10 | - stage: report 11 | script: "./gradlew jacocoTestReport" 12 | - stage: build 13 | script: "./gradlew build" 14 | - stage: deploy 15 | script: "./gradlew publishPlugins -Pgradle.publish.key=${GRADLE_PUBLISH_KEY} -Pgradle.publish.secret=${GRADLE_PUBLISH_SECRET}" 16 | stages: 17 | - test 18 | - report 19 | - build 20 | - name: deploy 21 | if: tag =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$ 22 | after_script: 23 | - bash <(curl -s https://codecov.io/bash) -------------------------------------------------------------------------------- /src/test/kotlin/io/wusa/SemverGitPluginExtensionTest.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import io.mockk.mockkObject 4 | import io.wusa.extension.SemverGitPluginExtension 5 | import org.gradle.api.Project 6 | import org.gradle.testfixtures.ProjectBuilder 7 | import org.junit.jupiter.api.Assertions.assertEquals 8 | import org.junit.jupiter.api.BeforeEach 9 | import org.junit.jupiter.api.Test 10 | 11 | class SemverGitPluginExtensionTest { 12 | 13 | private lateinit var project: Project 14 | 15 | @BeforeEach 16 | internal fun setUp() { 17 | project = ProjectBuilder.builder().build() 18 | project.plugins.apply(SemverGitPlugin::class.java) 19 | mockkObject(GitService) 20 | } 21 | 22 | @Test 23 | fun `defaults`() { 24 | val extension = SemverGitPluginExtension(project) 25 | assertEquals(extension.dirtyMarker, "dirty") 26 | assertEquals(extension.info, Info(project)) 27 | } 28 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2019 Matthias Held 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/extension/Branch.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.extension 2 | 3 | import io.wusa.Info 4 | import org.gradle.api.Project 5 | import org.gradle.api.Transformer 6 | import org.gradle.api.provider.Property 7 | import org.gradle.api.tasks.Internal 8 | 9 | class Branch(private val project: Project) { 10 | @Internal 11 | val regexProperty: Property = project.objects.property(String::class.java) 12 | var regex: String 13 | get() = regexProperty.get() 14 | set(value) = regexProperty.set(value) 15 | 16 | @Internal 17 | val incrementerProperty: Property = project.objects.property(String::class.java) 18 | var incrementer: String 19 | get() = incrementerProperty.get() 20 | set(value) = incrementerProperty.set(value) 21 | 22 | @Internal 23 | val formatterProperty: Property = project.objects.property(Any::class.java) 24 | // Object type Any for groovy (GString) and kotlin (String) interoperability 25 | var formatter: Transformer 26 | get() = formatterProperty.get() as Transformer 27 | set(value) = formatterProperty.set(value) 28 | 29 | override fun toString(): String { 30 | return "Branch(regex=$regex, incrementer=$incrementer)" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/extension/SemverGitPluginExtension.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.extension 2 | 3 | import io.wusa.Info 4 | import io.wusa.TagType 5 | import org.gradle.api.Action 6 | import org.gradle.api.Project 7 | import org.gradle.api.Transformer 8 | 9 | open class SemverGitPluginExtension(private var project: Project) { 10 | val branches: Branches = Branches(project) 11 | fun branches(configure: Action) = configure.execute(branches) 12 | 13 | var dirtyMarker: String = DEFAULT_DIRTY_MARKER 14 | 15 | var initialVersion: String = DEFAULT_INITIAL_VERSION 16 | 17 | var snapshotSuffix: String = DEFAULT_SNAPSHOT_SUFFIX 18 | 19 | var tagPrefix: String = DEFAULT_TAG_PREFIX 20 | 21 | var tagType: TagType = DEFAULT_TAGTYPE 22 | 23 | val info: Info 24 | get() = Info(project) 25 | 26 | companion object { 27 | const val DEFAULT_SNAPSHOT_SUFFIX = "SNAPSHOT" 28 | const val DEFAULT_DIRTY_MARKER = "dirty" 29 | const val DEFAULT_INITIAL_VERSION = "0.1.0" 30 | const val DEFAULT_INCREMENTER = "MINOR_INCREMENTER" 31 | const val DEFAULT_TAG_PREFIX = "" 32 | val DEFAULT_TAGTYPE = TagType.ANNOTATED 33 | val DEFAULT_FORMATTER: Transformer = Transformer { info: Info -> "${info.version.major}.${info.version.minor}.${info.version.patch}+build.${info.count}.sha.${info.shortCommit}" } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/GitCommandRunner.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import io.wusa.exception.GitException 4 | import java.io.File 5 | import java.util.concurrent.TimeUnit 6 | 7 | class GitCommandRunner { 8 | companion object { 9 | fun execute(projectDir: File, args: Array): String { 10 | val process = startGitProcess(args, projectDir) 11 | val output = readProcessOutput(process) 12 | waitForGitProcess(process) 13 | if (processFinishedWithoutErrors(process)) return output 14 | 15 | throw GitException("Executing git command failed with " + process.exitValue()) 16 | } 17 | 18 | private fun readProcessOutput(process: Process): String { 19 | return process.inputStream.bufferedReader().use { it.readText() }.trim() 20 | } 21 | 22 | private fun processFinishedWithoutErrors(process: Process): Boolean { 23 | if (process.exitValue() == 0) { 24 | return true 25 | } 26 | return false 27 | } 28 | 29 | private fun waitForGitProcess(process: Process) { 30 | if (!process.waitFor(10, TimeUnit.SECONDS)) { 31 | process.destroy() 32 | throw RuntimeException("Execution timed out: $this") 33 | } 34 | } 35 | 36 | private fun startGitProcess(args: Array, projectDir: File): Process { 37 | return ProcessBuilder("git", *args) 38 | .directory(projectDir) 39 | .redirectOutput(ProcessBuilder.Redirect.PIPE) 40 | .redirectError(ProcessBuilder.Redirect.PIPE) 41 | .start() 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/incrementer/VersionIncrementer.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.incrementer 2 | 3 | import io.wusa.Version 4 | import io.wusa.exception.NoIncrementerFoundException 5 | import org.gradle.api.Project 6 | import java.lang.IllegalArgumentException 7 | 8 | enum class VersionIncrementer: IIncrementer { 9 | NO_VERSION_INCREMENTER { 10 | override fun increment(version: Version, project: Project): Version { 11 | return NoVersionIncrementer().increment(version, project) 12 | } 13 | }, 14 | PATCH_INCREMENTER { 15 | override fun increment(version: Version, project: Project): Version { 16 | return PatchVersionIncrementer().increment(version, project) 17 | } 18 | }, 19 | MINOR_INCREMENTER { 20 | override fun increment(version: Version, project: Project): Version { 21 | return MinorVersionIncrementer().increment(version, project) 22 | } 23 | }, 24 | MAJOR_INCREMENTER { 25 | override fun increment(version: Version, project: Project): Version { 26 | return MajorVersionIncrementer().increment(version, project) 27 | } 28 | }, 29 | CONVENTIONAL_COMMITS_INCREMENTER { 30 | override fun increment(version: Version, project: Project): Version { 31 | return ConventionalCommitsIncrementer().increment(version, project) 32 | } 33 | }; 34 | 35 | companion object { 36 | fun getVersionIncrementerByName(name: String): VersionIncrementer { 37 | try { 38 | return valueOf(name.toUpperCase()) 39 | } catch (ex: IllegalArgumentException) { 40 | throw NoIncrementerFoundException("The in the config specified incrementer was not found.") 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/kotlin/io/wusa/IncrementerTest.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import io.mockk.mockkObject 4 | import io.wusa.incrementer.MajorVersionIncrementer 5 | import io.wusa.incrementer.MinorVersionIncrementer 6 | import io.wusa.incrementer.NoVersionIncrementer 7 | import io.wusa.incrementer.PatchVersionIncrementer 8 | import org.gradle.api.Project 9 | import org.gradle.testfixtures.ProjectBuilder 10 | import org.junit.jupiter.api.Assertions 11 | import org.junit.jupiter.api.BeforeEach 12 | import org.junit.jupiter.api.Test 13 | 14 | class IncrementerTest { 15 | 16 | private lateinit var project: Project 17 | 18 | @BeforeEach 19 | internal fun setUp() { 20 | project = ProjectBuilder.builder().build() 21 | project.plugins.apply(SemverGitPlugin::class.java) 22 | mockkObject(GitService) 23 | } 24 | 25 | @Test 26 | fun `bump major version`() { 27 | val version = MajorVersionIncrementer().increment(Version(1, 1, 1, "", "", null), project) 28 | Assertions.assertEquals(version, Version(2, 0, 0, "", "", null)) 29 | } 30 | 31 | @Test 32 | fun `bump minor version`() { 33 | val version = MinorVersionIncrementer().increment(Version(1, 1, 1, "", "", null), project) 34 | Assertions.assertEquals(version, Version(1, 2, 0, "", "", null)) 35 | } 36 | 37 | @Test 38 | fun `bump patch version`() { 39 | val version = PatchVersionIncrementer().increment(Version(1, 1, 1, "", "", null), project) 40 | Assertions.assertEquals(version, Version(1, 1, 2, "", "", null)) 41 | } 42 | 43 | @Test 44 | fun `don't bump version`() { 45 | val version = NoVersionIncrementer().increment(Version(1, 1, 1, "", "", null), project) 46 | Assertions.assertEquals(version, Version(1, 1, 1, "", "", null)) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/incrementer/ConventionalCommitsIncrementer.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.incrementer 2 | 3 | import io.wusa.GitService 4 | import io.wusa.Version 5 | import io.wusa.extension.SemverGitPluginExtension 6 | import org.gradle.api.Project 7 | 8 | class ConventionalCommitsIncrementer: IIncrementer { 9 | override fun increment(version: Version, project: Project): Version { 10 | val semverGitPluginExtension = project.extensions.getByType(SemverGitPluginExtension::class.java) 11 | 12 | val listOfCommits = GitService.getCommitsSinceLastTag(project, semverGitPluginExtension.tagPrefix, semverGitPluginExtension.tagType) 13 | var major = 0 14 | var minor = 0 15 | var patch = 0 16 | val optionalScope = "(\\(.*?\\))?" 17 | val feat = "^feat$optionalScope" 18 | val fix = "^fix$optionalScope" 19 | val breakingChange = "\\bBREAKING[ _-]CHANGE\\b:" 20 | 21 | if (semverGitPluginExtension.info.dirty) patch = 1 22 | 23 | listOfCommits.forEach { 24 | when { 25 | it.contains("$feat!:".toRegex()) -> major += 1 26 | it.contains("$fix!:".toRegex()) -> major += 1 27 | it.contains(breakingChange.toRegex()) -> major += 1 28 | it.contains("$feat:".toRegex()) -> minor += 1 29 | it.contains("$fix:".toRegex()) -> patch += 1 30 | } 31 | } 32 | if (patch > 0) { 33 | version.patch += 1 34 | } 35 | if (minor > 0) { 36 | version.patch = 0 37 | version.minor += 1 38 | } 39 | if (major > 0) { 40 | version.patch = 0 41 | version.minor = 0 42 | version.major += 1 43 | } 44 | return version 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/kotlin/io/wusa/VersionIncrementerTest.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import io.wusa.exception.NoIncrementerFoundException 4 | import io.wusa.incrementer.VersionIncrementer 5 | import org.gradle.api.Project 6 | import org.gradle.testfixtures.ProjectBuilder 7 | import org.junit.jupiter.api.Assertions 8 | import org.junit.jupiter.api.BeforeEach 9 | import org.junit.jupiter.api.Test 10 | 11 | class VersionIncrementerTest { 12 | 13 | private lateinit var project: Project 14 | 15 | @BeforeEach 16 | internal fun setUp() { 17 | project = ProjectBuilder.builder().build() 18 | project.plugins.apply(SemverGitPlugin::class.java) 19 | } 20 | 21 | @Test 22 | fun `no increment`() { 23 | Assertions.assertEquals(VersionIncrementer.getVersionIncrementerByName("NO_VERSION_INCREMENTER").increment(Version(0, 0, 0, "", "", null), project), Version(0, 0, 0, "", "", null)) 24 | } 25 | 26 | @Test 27 | fun `patch increment`() { 28 | Assertions.assertEquals(VersionIncrementer.getVersionIncrementerByName("PATCH_INCREMENTER").increment(Version(0, 0, 0, "", "", null), project), Version(0, 0, 1, "", "", null)) 29 | } 30 | 31 | @Test 32 | fun `minor increment`() { 33 | Assertions.assertEquals(VersionIncrementer.getVersionIncrementerByName("MINOR_INCREMENTER").increment(Version(0, 0, 0, "", "", null), project), Version(0, 1, 0, "", "", null)) 34 | } 35 | 36 | @Test 37 | fun `major increment`() { 38 | Assertions.assertEquals(VersionIncrementer.getVersionIncrementerByName("MAJOR_INCREMENTER").increment(Version(0, 0, 0, "", "", null), project), Version(1, 0, 0, "", "", null)) 39 | } 40 | 41 | @Test 42 | fun `wrong incrementer`() { 43 | Assertions.assertThrows(NoIncrementerFoundException::class.java) { 44 | VersionIncrementer.getVersionIncrementerByName("WRONG_INCREMENTER").increment(Version(0, 0, 0, "", "", null), project) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/kotlin/io/wusa/FunctionalBaseTest.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import org.gradle.internal.impldep.org.eclipse.jgit.api.Git 4 | import java.io.File 5 | 6 | abstract class FunctionalBaseTest { 7 | 8 | fun initializeGitWithBranch(directory: File, tag: String = "0.1.0", branch: String = "develop"): Git { 9 | val gitIgnore = File(directory, ".gitignore") 10 | gitIgnore.writeText(".gradle") 11 | val git = Git.init().setDirectory(directory).call() 12 | git.add().addFilepattern(".").call() 13 | val commit = git.commit().setMessage("").call() 14 | git.checkout().setCreateBranch(true).setName(branch).call() 15 | git.tag().setName(tag).setObjectId(commit).call() 16 | return git 17 | } 18 | 19 | fun initializeGitWithoutBranchAnnotated(directory: File, tag: String = "0.1.0"): Git { 20 | val gitIgnore = File(directory, ".gitignore") 21 | gitIgnore.writeText(".gradle") 22 | val git = Git.init().setDirectory(directory).call() 23 | git.add().addFilepattern(".").call() 24 | val commit = git.commit().setMessage("").call() 25 | git.tag().setName(tag).setMessage(tag).setAnnotated(true).setObjectId(commit).call() 26 | return git 27 | } 28 | 29 | fun initializeGitWithoutBranchLightweight(directory: File, tag: String = "0.1.0"): Git { 30 | val gitIgnore = File(directory, ".gitignore") 31 | gitIgnore.writeText(".gradle") 32 | val git = Git.init().setDirectory(directory).call() 33 | git.add().addFilepattern(".").call() 34 | val commit = git.commit().setMessage("").call() 35 | git.tag().setName(tag).setObjectId(commit).setAnnotated(false).call() 36 | return git 37 | } 38 | 39 | fun initializeGitWithoutBranchAndWithoutTag(directory: File): Git { 40 | val gitIgnore = File(directory, ".gitignore") 41 | gitIgnore.writeText(".gradle") 42 | val git = Git.init().setDirectory(directory).call() 43 | git.add().addFilepattern(".").call() 44 | git.commit().setMessage("").call() 45 | return git 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/SemverGitPlugin.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import io.wusa.extension.SemverGitPluginExtension 4 | import org.gradle.api.Plugin 5 | import org.gradle.api.Project 6 | 7 | class SemverGitPlugin : Plugin { 8 | override fun apply(project: Project) { 9 | 10 | val semverGitPluginExtension = project.extensions.create("semver", SemverGitPluginExtension::class.java, project) 11 | 12 | project.task("showVersion") { 13 | it.group = "Help" 14 | it.description = "Show the project version" 15 | } 16 | project.tasks.getByName("showVersion").doLast { 17 | println("Version: " + semverGitPluginExtension.info) 18 | } 19 | 20 | project.task("showInfo") { 21 | it.group = "Help" 22 | it.description = "Show the git info" 23 | } 24 | project.tasks.getByName("showInfo").doLast { 25 | println("Branch name: " + semverGitPluginExtension.info.branch.name) 26 | println("Branch group: " + semverGitPluginExtension.info.branch.group) 27 | println("Branch id: " + semverGitPluginExtension.info.branch.id) 28 | println("Commit: " + semverGitPluginExtension.info.commit) 29 | println("Short commit: " + semverGitPluginExtension.info.shortCommit) 30 | println("Tag: " + semverGitPluginExtension.info.tag) 31 | println("Last tag: " + semverGitPluginExtension.info.lastTag) 32 | println("Dirty: " + semverGitPluginExtension.info.dirty) 33 | println("Version: " + semverGitPluginExtension.info) 34 | println("Version major: " + semverGitPluginExtension.info.version.major) 35 | println("Version minor: " + semverGitPluginExtension.info.version.minor) 36 | println("Version patch: " + semverGitPluginExtension.info.version.patch) 37 | println("Version pre release: " + if (semverGitPluginExtension.info.version.prerelease.isEmpty()) "none" else semverGitPluginExtension.info.version.prerelease) 38 | println("Version build: " + if (semverGitPluginExtension.info.version.build.isEmpty()) "none" else semverGitPluginExtension.info.version.build) 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/Info.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import io.wusa.exception.NoCurrentTagFoundException 4 | import io.wusa.exception.NoLastTagFoundException 5 | import io.wusa.extension.SemverGitPluginExtension 6 | import io.wusa.formatter.SemanticVersionFormatter 7 | import org.gradle.api.Project 8 | 9 | data class Info(private var project: Project) { 10 | private val semverGitPluginExtension: SemverGitPluginExtension = project.extensions.getByType(SemverGitPluginExtension::class.java) 11 | 12 | val branch: Branch 13 | get() = Branch(project) 14 | 15 | val commit: String 16 | get() { 17 | return try { 18 | GitService.currentCommit(project, false) 19 | } catch (ex: NoCurrentTagFoundException) { 20 | "none" 21 | } 22 | } 23 | 24 | val shortCommit: String 25 | get() { 26 | return try { 27 | GitService.currentCommit(project, true) 28 | } catch (ex: NoCurrentTagFoundException) { 29 | "none" 30 | } 31 | } 32 | 33 | val tag: String 34 | get() { 35 | return try { 36 | GitService.currentTag(project, tagType = semverGitPluginExtension.tagType) 37 | } catch (ex: NoCurrentTagFoundException) { 38 | "none" 39 | } 40 | } 41 | 42 | val lastTag: String 43 | get() { 44 | return try { 45 | GitService.lastTag(project, tagType = semverGitPluginExtension.tagType) 46 | } catch (ex: NoLastTagFoundException) { 47 | "none" 48 | } 49 | } 50 | 51 | val dirty: Boolean 52 | get() = GitService.isDirty(project) 53 | 54 | val count: Int 55 | get() = GitService.count(project) 56 | 57 | val version: Version 58 | get() = VersionService(project).getVersion() 59 | 60 | override fun toString(): String { 61 | val semverGitPluginExtension: SemverGitPluginExtension = project.extensions.getByType(SemverGitPluginExtension::class.java) 62 | 63 | return SemanticVersionFormatter.format(this, semverGitPluginExtension.branches, semverGitPluginExtension.snapshotSuffix, semverGitPluginExtension.dirtyMarker) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/SemanticVersionFactory.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import io.wusa.exception.NoValidSemverTagFoundException 4 | import org.slf4j.LoggerFactory 5 | 6 | class SemanticVersionFactory : IVersionFactory { 7 | private val LOG = LoggerFactory.getLogger(SemanticVersionFactory::class.java) 8 | 9 | private val suffixRegex = """(?:-(?[0-9]+)(?:-g(?[0-9a-f]{1,7}))(?-dirty)?)$""".toRegex() 10 | private val versionRegex = """^[vV]?(?0|[1-9]\d*)\.(?0|[1-9]\d*)\.(?0|[1-9]\d*)(?:-(?(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?[a-zA-Z0-9][a-zA-Z0-9\.-]+)?)?$""".toRegex() 11 | 12 | @Throws(NoValidSemverTagFoundException::class) 13 | override fun createFromString(describe: String): Version { 14 | try { 15 | val suffix = parseSuffix(suffixRegex, describe) 16 | val version = removeSuffixFromDescribe(describe, suffix, suffixRegex) 17 | val parsedVersion = parseVersion(version, versionRegex) 18 | 19 | parsedVersion.suffix = suffix 20 | return parsedVersion 21 | } catch (ex: IllegalArgumentException) { 22 | throw NoValidSemverTagFoundException("The last tag is not a semantic version: $describe.") 23 | } 24 | } 25 | 26 | private fun removeSuffixFromDescribe(describe: String, suffix: Suffix?, suffixRegex: Regex): String { 27 | var version = describe 28 | if (suffix != null) { 29 | version = suffixRegex.replace(describe, "") 30 | } 31 | return version 32 | } 33 | 34 | private fun parseSuffix(suffixRegex: Regex, describe: String): Suffix? { 35 | return suffixRegex.find(describe) 36 | ?.destructured 37 | ?.let { (count, sha, dirty) -> 38 | Suffix(count.toInt(), sha, dirty.isNotEmpty()) 39 | } 40 | } 41 | 42 | @Throws(IllegalArgumentException::class) 43 | private fun parseVersion(version: String, versionRegex: Regex): Version { 44 | return versionRegex.matchEntire(version) 45 | ?.destructured 46 | ?.let { (major, minor, patch, prerelease, build) -> 47 | Version(major.toInt(), minor.toInt(), patch.toInt(), prerelease, build, null) 48 | } 49 | ?: throw IllegalArgumentException("Bad input '$version'") 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [2.3.7] 8 | ### Fixed 9 | - Fix regex to match grafted branches. 10 | 11 | ## [2.3.6] 12 | ### Fixed 13 | - Fix BREAKING CHANGE regex to also accept BREAKING-CHANGE and BREAKING_CHANGE due to an incompatibility between the Conventional commit specification and the git trailers convention: 14 | git trailers only detect keywords which do not contain space character (e.g. BREAKING-CHANGE is detected but not BREAKING CHANGE) whereas Conventional commit specification specified BREAKING CHANGE with a space. 15 | 16 | ## [2.3.5] 17 | ### Fixed 18 | - Fix large process outputs could lead to a timeout in the command runner due to the reading buffer running full and blocking the process. 19 | 20 | ## [2.3.4] 21 | ### Fixed 22 | - Remove debug statements. 23 | 24 | ## [2.3.3] 25 | ### Fixed 26 | - Fix dirty working tree in the conventional commits incrementer. 27 | 28 | ## [2.3.2] 29 | ### Fixed 30 | - Fix conventional commits incrementer for BREAKING CHANGES marked by a ! after the scope. 31 | - Improve conventional commits incrementer regex parsing. 32 | - Remove `git branch --show-current` to resolve detached HEAD problems and to improve Git < 2.22.0 compatibility. 33 | 34 | ## [2.3.1] 35 | ### Fixed 36 | - Fix conventional commits incrementer for windows and annotated and lightweight tags. 37 | 38 | ## [2.3.0] 39 | ### Added 40 | - Option to use lightweight or annotated tags. 41 | 42 | ## [2.2.4] 43 | ### Fixed 44 | - Fix typo in retrieving all commits since last tags which lead to problems retrieving commits. 45 | - Fix getting current branch if the current branch is not the first one. 46 | 47 | ## [2.2.3] 48 | ### Fixed 49 | - Remove trailing dash if dirty marker is empty. 50 | - Branch parsing regex now supports / (slashes) (e.g. feature/ilovemilk/super-feature) 51 | 52 | ## [2.2.2] 53 | ### Fixed 54 | - Remove trailing dash if SNAPSHOT is empty. 55 | - Fix documentation. 56 | 57 | ## [2.2.1] 58 | ### Fixed 59 | - Branch parsing regex now supports . (dots) (e.g. hotfix/5.3.1) 60 | 61 | ## [2.2.0] 62 | ### Added 63 | - Support [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) by a special incrementer. 64 | 65 | ## [2.1.0] 66 | ### Added 67 | - Support multi module with custom tag prefix. 68 | 69 | ## [2.0.2] 70 | ### Fixed 71 | - Branch parsing regex now supports numbers [0-9] 72 | 73 | ## [2.0.1] 74 | ### Fixed 75 | - Branch parsing regex now supports camelCase 76 | 77 | ## [2.0.0] 78 | ### Added 79 | - Custom branch specific formatter 80 | 81 | ## [1.2.1] - 2019-09-13 82 | ### Fixes 83 | - Current branch returning the branch name instead of HEAD on a detached HEAD 84 | 85 | ## [1.2.0] - 2019-05-11 86 | ### Added 87 | - Detailed version info to info task 88 | 89 | ### Fixed 90 | - Regex for parsing version string 91 | 92 | ## [1.1.0] - 2019-05-07 93 | ### Added 94 | - Custom initial version. 95 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/kotlin,gradle,intellij 3 | # Edit at https://www.gitignore.io/?templates=kotlin,gradle,intellij 4 | 5 | ### Intellij ### 6 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 7 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 8 | 9 | # User-specific stuff 10 | .idea/**/workspace.xml 11 | .idea/**/tasks.xml 12 | .idea/**/usage.statistics.xml 13 | .idea/**/dictionaries 14 | .idea/**/shelf 15 | 16 | # Generated files 17 | .idea/**/contentModel.xml 18 | .idea 19 | 20 | # Sensitive or high-churn files 21 | .idea/**/dataSources/ 22 | .idea/**/dataSources.ids 23 | .idea/**/dataSources.local.xml 24 | .idea/**/sqlDataSources.xml 25 | .idea/**/dynamic.xml 26 | .idea/**/uiDesigner.xml 27 | .idea/**/dbnavigator.xml 28 | 29 | # Gradle 30 | .idea/**/gradle.xml 31 | .idea/**/libraries 32 | 33 | # Gradle and Maven with auto-import 34 | # When using Gradle or Maven with auto-import, you should exclude module files, 35 | # since they will be recreated, and may cause churn. Uncomment if using 36 | # auto-import. 37 | # .idea/modules.xml 38 | # .idea/*.iml 39 | # .idea/modules 40 | 41 | # CMake 42 | cmake-build-*/ 43 | 44 | # Mongo Explorer plugin 45 | .idea/**/mongoSettings.xml 46 | 47 | # File-based project format 48 | *.iws 49 | 50 | # IntelliJ 51 | out/ 52 | 53 | # mpeltonen/sbt-idea plugin 54 | .idea_modules/ 55 | 56 | # JIRA plugin 57 | atlassian-ide-plugin.xml 58 | 59 | # Cursive Clojure plugin 60 | .idea/replstate.xml 61 | 62 | # Crashlytics plugin (for Android Studio and IntelliJ) 63 | com_crashlytics_export_strings.xml 64 | crashlytics.properties 65 | crashlytics-build.properties 66 | fabric.properties 67 | 68 | # Editor-based Rest Client 69 | .idea/httpRequests 70 | 71 | # Android studio 3.1+ serialized cache file 72 | .idea/caches/build_file_checksums.ser 73 | 74 | ### Intellij Patch ### 75 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 76 | 77 | # *.iml 78 | # modules.xml 79 | # .idea/misc.xml 80 | # *.ipr 81 | 82 | # Sonarlint plugin 83 | .idea/sonarlint 84 | 85 | ### Kotlin ### 86 | # Compiled class file 87 | *.class 88 | 89 | # Log file 90 | *.log 91 | 92 | # BlueJ files 93 | *.ctxt 94 | 95 | # Mobile Tools for Java (J2ME) 96 | .mtj.tmp/ 97 | 98 | # Package Files # 99 | *.jar 100 | *.war 101 | *.nar 102 | *.ear 103 | *.zip 104 | *.tar.gz 105 | *.rar 106 | 107 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 108 | hs_err_pid* 109 | 110 | ### Gradle ### 111 | .gradle 112 | build/ 113 | 114 | # Ignore Gradle GUI config 115 | gradle-app.setting 116 | 117 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 118 | !gradle-wrapper.jar 119 | 120 | # Cache of project 121 | .gradletasknamecache 122 | 123 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 124 | # gradle/wrapper/gradle-wrapper.properties 125 | 126 | ### Gradle Patch ### 127 | **/build/ 128 | 129 | # End of https://www.gitignore.io/api/kotlin,gradle,intellij -------------------------------------------------------------------------------- /src/test/kotlin/io/wusa/BranchTest.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import io.mockk.every 4 | import io.mockk.mockkObject 5 | import io.mockk.unmockkObject 6 | import org.gradle.api.Project 7 | import org.gradle.testfixtures.ProjectBuilder 8 | import org.junit.jupiter.api.* 9 | 10 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 11 | class BranchTest { 12 | 13 | private lateinit var project: Project 14 | 15 | @BeforeEach 16 | internal fun setUp() { 17 | project = ProjectBuilder.builder().build() 18 | mockkObject(GitService.Companion) 19 | } 20 | 21 | @AfterEach 22 | internal fun tearDown() { 23 | unmockkObject(GitService.Companion) 24 | } 25 | 26 | @Test 27 | fun `group of master should be master`() { 28 | val branch = Branch(project) 29 | every { GitService.currentBranch(project = any()) } returns "master" 30 | Assertions.assertEquals(branch.group, "master") 31 | } 32 | 33 | @Test 34 | fun `group of develop should be develop`() { 35 | val branch = Branch(project) 36 | every { GitService.currentBranch(project = any()) } returns "develop" 37 | Assertions.assertEquals(branch.group, "develop") 38 | } 39 | 40 | @Test 41 | fun `group of feature-test should be feature`() { 42 | val branch = Branch(project) 43 | every { GitService.currentBranch(project = any()) } returns "feature/test" 44 | Assertions.assertEquals(branch.group, "feature") 45 | } 46 | 47 | @Test 48 | fun `group of feature-test-test should be feature`() { 49 | val branch = Branch(project) 50 | every { GitService.currentBranch(project = any()) } returns "feature/test/test" 51 | Assertions.assertEquals(branch.group, "feature") 52 | } 53 | 54 | @Test 55 | fun `id of feature-test should be feature-test`() { 56 | val branch = Branch(project) 57 | every { GitService.currentBranch(project = any()) } returns "feature/test" 58 | Assertions.assertEquals(branch.id, "feature-test") 59 | } 60 | 61 | @Test 62 | fun `id of feature-test_a! should be feature-test_a!`() { 63 | val branch = Branch(project) 64 | every { GitService.currentBranch(project = any()) } returns "feature/test_a!" 65 | Assertions.assertEquals(branch.id, "feature-test_a!") 66 | } 67 | 68 | @Test 69 | fun `id of feature-special-test should be feature-special-test`() { 70 | val branch = Branch(project) 71 | every { GitService.currentBranch(project = any()) } returns "feature/special-test" 72 | Assertions.assertEquals(branch.id, "feature-special-test") 73 | } 74 | 75 | @Test 76 | fun `branch group of hotfix branch should be hotfix`() { 77 | val branch = Branch(project) 78 | every { GitService.currentBranch(project = any()) } returns "hotfix/5.3.1" 79 | Assertions.assertEquals(branch.group, "hotfix") 80 | } 81 | 82 | @Test 83 | fun `branch group of release branch should be release`() { 84 | val branch = Branch(project) 85 | every { GitService.currentBranch(project = any()) } returns "release/5.3.0" 86 | Assertions.assertEquals(branch.group, "release") 87 | } 88 | } -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/formatter/SemanticVersionFormatter.kt: -------------------------------------------------------------------------------- 1 | package io.wusa.formatter 2 | 3 | import io.wusa.Info 4 | import io.wusa.RegexResolver 5 | import io.wusa.extension.Branches 6 | import io.wusa.extension.SemverGitPluginExtension 7 | import org.gradle.api.Transformer 8 | 9 | class SemanticVersionFormatter { 10 | companion object { 11 | fun format(info: Info, branches: Branches, snapshotSuffix: String, dirtyMarker: String): String { 12 | if (!hasFirstCommit(info)) return appendSuffix(buildVersionString(info), snapshotSuffix) 13 | 14 | if (hasTag(info) && !isDirty(info)) { 15 | return formatVersionWithTag(info) 16 | } 17 | 18 | val formattedVersion = formatVersion(branches, info, dirtyMarker) 19 | if (!hasTag(info) || hasTag(info) && isDirty(info)) { 20 | return appendSuffix(formattedVersion, snapshotSuffix) 21 | } 22 | return formattedVersion 23 | } 24 | 25 | private fun formatVersionWithTag(info: Info): String { 26 | var versionString = buildVersionString(info) 27 | if (hasVersionPrerelease(info)) { 28 | versionString = appendPrerelease(versionString, info) 29 | } 30 | if (hasVersionBuildInformation(info)) { 31 | versionString = appendBuildInformation(versionString, info) 32 | } 33 | return versionString 34 | } 35 | 36 | private fun appendBuildInformation(versionString: String, info: Info): String { 37 | var versionString1 = versionString 38 | versionString1 += "+${info.version.build}" 39 | return versionString1 40 | } 41 | 42 | private fun appendPrerelease(versionString: String, info: Info): String { 43 | var versionString1 = versionString 44 | versionString1 += "-${info.version.prerelease}" 45 | return versionString1 46 | } 47 | 48 | private fun buildVersionString(info: Info) = "${info.version.major}.${info.version.minor}.${info.version.patch}" 49 | 50 | private fun formatVersion(branches: Branches, info: Info, dirtyMarker: String): String { 51 | val regexFormatterPair = RegexResolver.findMatchingRegex(branches, info.branch.name) 52 | var formattedVersion = transform(SemverGitPluginExtension.DEFAULT_FORMATTER, info) 53 | if (isDirty(info)) { 54 | formattedVersion = appendDirtyMarker(formattedVersion, dirtyMarker) 55 | } 56 | regexFormatterPair?.let { 57 | formattedVersion = transform(regexFormatterPair.formatter, info) 58 | if (isDirty(info)) { 59 | formattedVersion = appendDirtyMarker(formattedVersion, dirtyMarker) 60 | } 61 | } 62 | return formattedVersion 63 | } 64 | 65 | private fun hasTag(info: Info) = info.version.suffix == null 66 | 67 | private fun isDirty(info: Info) = info.dirty 68 | 69 | private fun hasVersionBuildInformation(info: Info) = info.version.build != "" 70 | 71 | private fun hasVersionPrerelease(info: Info) = info.version.prerelease != "" 72 | 73 | private fun appendSuffix(version: String, snapshotSuffix: String): String { 74 | if (snapshotSuffix != "") { 75 | return "$version-$snapshotSuffix" 76 | } 77 | return version 78 | } 79 | 80 | private fun hasFirstCommit(info: Info): Boolean { 81 | if (info.count == 0) { 82 | return false 83 | } 84 | return true 85 | } 86 | 87 | private fun appendDirtyMarker(version: String, dirtyMarker: String): String { 88 | if (dirtyMarker != "") { 89 | return "$version-$dirtyMarker" 90 | } 91 | return version 92 | } 93 | 94 | private fun transform(transformer: Transformer, info: Info): String { 95 | return transformer.transform(info).toString() 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/GitService.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import io.wusa.exception.* 4 | import org.gradle.api.Project 5 | 6 | class GitService { 7 | companion object { 8 | 9 | @Throws(NoCurrentBranchFoundException::class) 10 | fun currentBranch(project: Project): String { 11 | return try { 12 | getCurrentBranch(project) 13 | } catch (ex: GitException) { 14 | throw NoCurrentBranchFoundException(ex) 15 | } catch (ex: KotlinNullPointerException) { 16 | throw NoCurrentBranchFoundException(ex) 17 | } 18 | } 19 | 20 | @Throws(NoCurrentCommitFoundException::class) 21 | fun currentCommit(project: Project, isShort: Boolean): String { 22 | return if (isShort) { 23 | getCurrentShortCommit(project) 24 | } else { 25 | getCurrentCommit(project) 26 | } 27 | } 28 | 29 | @Throws(NoCurrentTagFoundException::class) 30 | fun currentTag(project: Project, tagPrefix : String = "", tagType : TagType = TagType.ANNOTATED): String { 31 | var cmdArgs = arrayOf("describe", "--exact-match", "--match", "$tagPrefix*") 32 | if (tagType == TagType.LIGHTWEIGHT){ 33 | cmdArgs = arrayOf("describe", "--tags", "--exact-match", "--match", "$tagPrefix*") 34 | } 35 | return try { 36 | GitCommandRunner.execute(project.projectDir, cmdArgs) 37 | } catch (ex: GitException) { 38 | throw NoCurrentTagFoundException(ex) 39 | } 40 | } 41 | 42 | @Throws(NoLastTagFoundException::class) 43 | fun lastTag(project : Project, tagPrefix : String = "", tagType : TagType = TagType.ANNOTATED): String { 44 | var cmdArgs = arrayOf("describe", "--abbrev=7", "--match", "$tagPrefix*") 45 | if (tagType == TagType.LIGHTWEIGHT){ 46 | cmdArgs = arrayOf("describe", "--tags", "--abbrev=7", "--match", "$tagPrefix*") 47 | } 48 | return try { 49 | GitCommandRunner.execute(project.projectDir, cmdArgs) 50 | } catch (ex: GitException) { 51 | throw NoLastTagFoundException(ex) 52 | } 53 | } 54 | 55 | fun isDirty(project: Project): Boolean { 56 | return try { 57 | isGitDifferent(project) 58 | } catch (ex: GitException) { 59 | false 60 | } 61 | } 62 | 63 | fun count(project: Project): Int { 64 | return try { 65 | GitCommandRunner.execute(project.projectDir, arrayOf("rev-list", "--count", "HEAD")).toInt() 66 | } catch (ex: GitException) { 67 | 0 68 | } 69 | } 70 | 71 | fun getCommitsSinceLastTag(project: Project, tagPrefix : String = "", tagType : TagType = TagType.ANNOTATED): List { 72 | var cmdArgs = arrayOf("describe", "--abbrev=0", "--match", "$tagPrefix*") 73 | if (tagType == TagType.LIGHTWEIGHT) { 74 | cmdArgs = arrayOf("describe", "--tags", "--abbrev=0", "--match", "$tagPrefix*") 75 | } 76 | return try { 77 | val lastTag = GitCommandRunner.execute(project.projectDir, cmdArgs) 78 | GitCommandRunner.execute(project.projectDir, arrayOf("log", "--pretty=format:%s %(trailers:separator=%x2c)", "$lastTag..@")).lines() 79 | } catch (ex: GitException) { 80 | emptyList() 81 | } 82 | } 83 | 84 | private fun isGitDifferent(project: Project): Boolean { 85 | return GitCommandRunner.execute(project.projectDir, arrayOf("status", "-s")).isNotBlank() 86 | } 87 | 88 | private fun getCurrentCommit(project: Project): String { 89 | return try { 90 | GitCommandRunner.execute(project.projectDir, arrayOf("rev-parse", "HEAD")) 91 | } catch (ex: GitException) { 92 | throw NoCurrentCommitFoundException(ex) 93 | } 94 | } 95 | 96 | private fun getCurrentShortCommit(project: Project): String { 97 | return try { 98 | GitCommandRunner.execute(project.projectDir, arrayOf("rev-parse", "--short", "HEAD")) 99 | } catch (ex: GitException) { 100 | throw NoCurrentCommitFoundException(ex) 101 | } 102 | } 103 | 104 | private fun getCurrentBranch(project: Project): String { 105 | val head = GitCommandRunner.execute(project.projectDir, arrayOf("log", "-n", "1", "--pretty=%d", "HEAD")) 106 | return """\([grafted, ]{0,9}HEAD -> (.*?)[,|)]""".toRegex().find(head)!!.groupValues[1] 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/kotlin/io/wusa/VersionService.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import io.wusa.exception.* 4 | import io.wusa.extension.SemverGitPluginExtension 5 | import io.wusa.incrementer.VersionIncrementer 6 | import org.gradle.api.GradleException 7 | import org.gradle.api.Project 8 | import org.gradle.internal.impldep.org.eclipse.jgit.api.Git 9 | 10 | class VersionService(private var project: Project) { 11 | private val semverGitPluginExtension: SemverGitPluginExtension = project.extensions.getByType(SemverGitPluginExtension::class.java) 12 | 13 | @Throws(GradleException::class) 14 | fun getVersion(): Version { 15 | val versionFactory: IVersionFactory = SemanticVersionFactory() 16 | 17 | return try { 18 | getCurrentVersion(versionFactory) 19 | } catch (ex: IllegalArgumentException) { 20 | throw GradleException("The current tag is not a semantic version.") 21 | } catch (ex: NoCurrentTagFoundException) { 22 | handleNoCurrentTagFound(versionFactory, project) 23 | } catch (ex: DirtyWorkingTreeException) { 24 | handleDirtyWorkingTree(versionFactory, project) 25 | } 26 | } 27 | 28 | @Throws(GradleException::class) 29 | private fun handleDirtyWorkingTree(versionFactory: IVersionFactory, project: Project): Version { 30 | return try { 31 | val lastVersion = getLastVersion(versionFactory) 32 | incrementVersion(lastVersion, project) 33 | } catch (ex: NoValidSemverTagFoundException) { 34 | throw GradleException(ex.localizedMessage) 35 | } catch (ex: NoIncrementerFoundException) { 36 | throw GradleException(ex.localizedMessage) 37 | } catch (ex: NoLastTagFoundException) { 38 | buildInitialVersion(versionFactory) 39 | } 40 | } 41 | 42 | @Throws(GradleException::class) 43 | private fun handleNoCurrentTagFound(versionFactory: IVersionFactory, project: Project): Version { 44 | return try { 45 | val lastVersion = getLastVersion(versionFactory) 46 | incrementVersion(lastVersion, project) 47 | } catch (ex: NoValidSemverTagFoundException) { 48 | throw GradleException(ex.localizedMessage) 49 | } catch (ex: NoIncrementerFoundException) { 50 | throw GradleException(ex.localizedMessage) 51 | } catch (ex: NoLastTagFoundException) { 52 | buildInitialVersion(versionFactory) 53 | } 54 | } 55 | 56 | private fun buildInitialVersion(versionFactory: IVersionFactory): Version { 57 | return try { 58 | buildInitialVersionForTag(versionFactory) 59 | } catch (ex: NoCurrentCommitFoundException) { 60 | buildInitialVersionWithNoTag() 61 | } 62 | } 63 | 64 | private fun buildInitialVersionWithNoTag() = Version(0, 1, 0, "", "", null) 65 | 66 | private fun buildInitialVersionForTag(versionFactory: IVersionFactory): Version { 67 | val sha = GitService.currentCommit(project, true) 68 | val isDirty = GitService.isDirty(project) 69 | val count = GitService.count(project) 70 | val version = versionFactory.createFromString(semverGitPluginExtension.initialVersion) 71 | version.suffix = Suffix(count, sha, isDirty) 72 | return version 73 | } 74 | 75 | private fun getLastVersion(versionFactory : IVersionFactory): Version { 76 | val tagPrefix = semverGitPluginExtension.tagPrefix 77 | val lastTag = GitService.lastTag(project, tagPrefix, tagType = semverGitPluginExtension.tagType) 78 | if ( !lastTag.startsWith(tagPrefix)) { 79 | throw NoCurrentTagFoundException("$lastTag doesn't match $tagPrefix") 80 | } 81 | 82 | return versionFactory.createFromString(lastTag.substring(tagPrefix.length)) 83 | } 84 | 85 | private fun getCurrentVersion(versionFactory : IVersionFactory): Version { 86 | val tagPrefix = semverGitPluginExtension.tagPrefix 87 | val curTag = GitService.currentTag(project, tagPrefix, tagType = semverGitPluginExtension.tagType) 88 | if ( !curTag.startsWith(tagPrefix)) { 89 | throw NoCurrentTagFoundException("$curTag doesn't match $tagPrefix") 90 | } 91 | val isDirty = GitService.isDirty(project) 92 | if (isDirty) { 93 | throw DirtyWorkingTreeException("The current working tree is dirty.") 94 | } 95 | 96 | return versionFactory.createFromString(curTag.substring(tagPrefix.length)) 97 | } 98 | 99 | private fun incrementVersion(version: Version, project: Project): Version { 100 | val regexIncrementerPair = RegexResolver.findMatchingRegex(semverGitPluginExtension.branches, semverGitPluginExtension.info.branch.name) 101 | regexIncrementerPair?.let { 102 | return VersionIncrementer.getVersionIncrementerByName(regexIncrementerPair.incrementer).increment(version, project) 103 | } ?: run { 104 | return VersionIncrementer.getVersionIncrementerByName(SemverGitPluginExtension.DEFAULT_INCREMENTER).increment(version, project) 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/test/kotlin/io/wusa/InfoTest.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import io.mockk.every 4 | import io.mockk.mockkObject 5 | import io.mockk.unmockkObject 6 | import io.wusa.exception.NoValidSemverTagFoundException 7 | import io.wusa.extension.SemverGitPluginExtension 8 | import org.gradle.api.GradleException 9 | import org.gradle.api.Project 10 | import org.gradle.testfixtures.ProjectBuilder 11 | import org.junit.jupiter.api.* 12 | 13 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 14 | class InfoTest { 15 | 16 | private lateinit var project: Project 17 | private lateinit var semverGitPluginExtension: SemverGitPluginExtension 18 | 19 | @BeforeEach 20 | internal fun setUp() { 21 | project = ProjectBuilder.builder().build() 22 | project.plugins.apply(SemverGitPlugin::class.java) 23 | semverGitPluginExtension = project.extensions.getByType(SemverGitPluginExtension::class.java) 24 | mockkObject(GitService) 25 | } 26 | 27 | @AfterEach 28 | internal fun tearDown() { 29 | unmockkObject(GitService) 30 | semverGitPluginExtension.tagPrefix = "" 31 | } 32 | 33 | @Test 34 | fun `get dirty`() { 35 | val info = Info(project) 36 | every { GitService.isDirty(project = any()) } returns true 37 | Assertions.assertEquals(true, info.dirty) 38 | } 39 | 40 | @Test 41 | fun `get last tag`() { 42 | val info = Info(project) 43 | every { GitService.lastTag(project = any(), tagPrefix = any()) } returns "0.1.0" 44 | Assertions.assertEquals("0.1.0", info.lastTag) 45 | } 46 | 47 | @Test 48 | fun `get current tag`() { 49 | val info = Info(project) 50 | every { GitService.currentTag(project = any()) } returns "0.1.0" 51 | Assertions.assertEquals("0.1.0", info.tag) 52 | } 53 | 54 | @Test 55 | fun `get last tag with prefix`() { 56 | semverGitPluginExtension.tagPrefix = "prj_" 57 | val info = Info(project) 58 | every { GitService.lastTag(project = any(), tagPrefix = any()) } returns "prj_0.1.0" 59 | Assertions.assertEquals("prj_0.1.0", info.lastTag) 60 | } 61 | 62 | @Test 63 | fun `get current tag with prefix`() { 64 | semverGitPluginExtension.tagPrefix = "prj_" 65 | val info = Info(project) 66 | every { GitService.currentTag(project = any()) } returns "prj_0.1.0" 67 | Assertions.assertEquals("prj_0.1.0", info.tag) 68 | } 69 | 70 | @Test 71 | fun `get short commit`() { 72 | val info = Info(project) 73 | every { GitService.currentCommit(project = any(), isShort = true) } returns "1234567" 74 | Assertions.assertEquals("1234567", info.shortCommit) 75 | } 76 | 77 | @Test 78 | fun `get commit`() { 79 | val info = Info(project) 80 | every { GitService.currentCommit(project = any(), isShort = false) } returns "123456789" 81 | Assertions.assertEquals("123456789", info.commit) 82 | } 83 | 84 | @Test 85 | fun `get branch`() { 86 | val project = project 87 | val info = Info(project) 88 | Assertions.assertEquals(Branch(project), info.branch) 89 | } 90 | 91 | @Test 92 | fun `get version`() { 93 | val project = project 94 | val info = Info(project) 95 | every { GitService.currentTag(project = any()) } returns "0.1.0" 96 | Assertions.assertEquals("Version(major=0, minor=1, patch=0, prerelease=, build=, suffix=null)", info.version.toString()) 97 | } 98 | 99 | @Test 100 | fun `get version with lightweight tag`() { 101 | val project = project 102 | val info = Info(project) 103 | every { GitService.currentTag(project = any(), tagType = TagType.LIGHTWEIGHT) } returns "0.1.0" 104 | Assertions.assertEquals("Version(major=0, minor=1, patch=0, prerelease=, build=, suffix=null)", info.version.toString()) 105 | } 106 | 107 | @Test 108 | fun `current version is tagged with tag prefix`() { 109 | semverGitPluginExtension.tagPrefix = "prj_" 110 | val info = Info(project) 111 | every { GitService.currentTag(project = any()) } returns "prj_0.1.0" 112 | Assertions.assertEquals("Version(major=0, minor=1, patch=0, prerelease=, build=, suffix=null)", info.version.toString()) 113 | } 114 | 115 | @Test 116 | fun `current version has no tag with tag prefix`() { 117 | semverGitPluginExtension.tagPrefix = "prj_" 118 | val info = Info(project) 119 | every { GitService.lastTag(project = any(), tagPrefix = any()) } returns "prj_0.1.0" 120 | Assertions.assertEquals("Version(major=0, minor=2, patch=0, prerelease=, build=, suffix=null)", info.version.toString()) 121 | } 122 | 123 | @Test 124 | fun `current version has not tag with tag prefix`() { 125 | val info = Info(project) 126 | every { GitService.currentTag(project = any()) } returns "prj_0.1.0" 127 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java ) { 128 | info.version 129 | } 130 | } 131 | 132 | @Test 133 | fun `last version has not tag with tag prefix`() { 134 | val info = Info(project) 135 | every { GitService.lastTag(project = any(), tagPrefix = any()) } returns "prj_0.1.0" 136 | Assertions.assertThrows(GradleException::class.java ) { 137 | info.version 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/test/kotlin/io/wusa/ConventionalCommitsIncrementerTest.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import io.mockk.every 4 | import io.mockk.mockkObject 5 | import io.mockk.unmockkObject 6 | import io.wusa.extension.SemverGitPluginExtension 7 | import io.wusa.incrementer.ConventionalCommitsIncrementer 8 | import io.wusa.incrementer.VersionIncrementer 9 | import org.gradle.api.Project 10 | import org.gradle.testfixtures.ProjectBuilder 11 | import org.junit.jupiter.api.AfterEach 12 | import org.junit.jupiter.api.Assertions 13 | import org.junit.jupiter.api.BeforeEach 14 | import org.junit.jupiter.api.Test 15 | import org.junit.jupiter.api.TestInstance 16 | 17 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 18 | class ConventionalCommitsIncrementerTest { 19 | 20 | private lateinit var project: Project 21 | private lateinit var semverGitPluginExtension: SemverGitPluginExtension 22 | 23 | @BeforeEach 24 | internal fun setUp() { 25 | project = ProjectBuilder.builder().build() 26 | project.plugins.apply(SemverGitPlugin::class.java) 27 | semverGitPluginExtension = project.extensions.getByType(SemverGitPluginExtension::class.java) 28 | semverGitPluginExtension.tagType = TagType.ANNOTATED 29 | semverGitPluginExtension.tagPrefix = "" 30 | mockkObject(GitCommandRunner) 31 | } 32 | 33 | @AfterEach 34 | internal fun tearDown() { 35 | unmockkObject(GitCommandRunner) 36 | } 37 | 38 | @Test 39 | fun `patch should be increased by 1`() { 40 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns 41 | "fix: update gradle plugin publish due to security bugs\n" + 42 | "fix: update version an changelog\n" + 43 | "feat: Merge pull request #18 from ilovemilk/feature/support-multi-module\n" + 44 | "fix: add default tagPrefix behaviour\n" + 45 | "fix: Merge pull request #17 from jgindin/support-multi-module\n" + 46 | "fix: Merge remote-tracking branch 'origin/feature/add-more-tests' into develop\n" + 47 | "fix: Add support for multi-module projects.\n" + 48 | "fix: add test for kebab-case with numbers\n" + 49 | "fix: add more tests" 50 | 51 | Assertions.assertEquals(VersionIncrementer.getVersionIncrementerByName("CONVENTIONAL_COMMITS_INCREMENTER").increment(Version(0, 0, 0, "", "", null), project), Version(0, 1, 0, "", "", null)) 52 | } 53 | 54 | @Test 55 | fun `minor should be increased by 1`() { 56 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns 57 | "fix: update gradle plugin publish due to security bugs\n" + 58 | "fix: update version an changelog\n" + 59 | "fix: Merge pull request #18 from ilovemilk/feature/support-multi-module\n" + 60 | "fix: add default tagPrefix behaviour\n" + 61 | "fix: Merge pull request #17 from jgindin/support-multi-module\n" + 62 | "fix: Merge remote-tracking branch 'origin/feature/add-more-tests' into develop\n" + 63 | "fix: Add support for multi-module projects.\n" + 64 | "fix: add test for kebab-case with numbers\n" + 65 | "fix: add more tests" 66 | 67 | Assertions.assertEquals(VersionIncrementer.getVersionIncrementerByName("CONVENTIONAL_COMMITS_INCREMENTER").increment(Version(0, 0, 0, "", "", null), project), Version(0, 0, 1, "", "", null)) 68 | } 69 | 70 | @Test 71 | fun `major should be increased by 1`() { 72 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns 73 | "fix: update gradle plugin publish due to security bugs\n" + 74 | "BREAKING CHANGE: update version an changelog\n" + 75 | "fix: Merge pull request #18 from ilovemilk/feature/support-multi-module\n" + 76 | "feat: add default tagPrefix behaviour\n" + 77 | "fix: Merge pull request #17 from jgindin/support-multi-module\n" + 78 | "feat: Merge remote-tracking branch 'origin/feature/add-more-tests' into develop\n" + 79 | "fix: Add support for multi-module projects.\n" + 80 | "feat: add test for kebab-case with numbers\n" + 81 | "fix: add more tests" 82 | 83 | Assertions.assertEquals(VersionIncrementer.getVersionIncrementerByName("CONVENTIONAL_COMMITS_INCREMENTER").increment(Version(0, 0, 0, "", "", null), project), Version(1, 0, 0, "", "", null)) 84 | } 85 | 86 | @Test 87 | fun `issue-56 breaking change with ! after the feat scope`() { 88 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns 89 | "feat!: added semver plugin incrementer parameter\n" + 90 | "feat: added semver plugin incrementer parameter" 91 | 92 | Assertions.assertEquals(VersionIncrementer.getVersionIncrementerByName("CONVENTIONAL_COMMITS_INCREMENTER").increment(Version(0, 0, 0, "", "", null), project), Version(1, 0, 0, "", "", null)) 93 | } 94 | 95 | @Test 96 | fun `issue-56 breaking change with ! after the fix scope`() { 97 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns 98 | "fix!: added semver plugin incrementer parameter\n" + 99 | "feat: added semver plugin incrementer parameter" 100 | 101 | Assertions.assertEquals(VersionIncrementer.getVersionIncrementerByName("CONVENTIONAL_COMMITS_INCREMENTER").increment(Version(0, 0, 0, "", "", null), project), Version(1, 0, 0, "", "", null)) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # :ghost: __semver-git-plugin__ 2 | *Version your gradle projects with git tags and semantic versioning.* 3 | 4 | [![GitHub version](https://img.shields.io/github/tag/ilovemilk/semver-git-plugin.svg)](https://img.shields.io/github/tag/ilovemilk/semver-git-plugin.svg) 5 | [![License](https://img.shields.io/github/license/ilovemilk/semver-git-plugin.svg)](https://img.shields.io/github/license/ilovemilk/semver-git-plugin.svg) 6 | [![Build Status](https://travis-ci.com/ilovemilk/semver-git-plugin.svg)](https://travis-ci.com/ilovemilk/semver-git-plugin) 7 | [![codecov](https://codecov.io/gh/ilovemilk/semver-git-plugin/branch/master/graph/badge.svg)](https://codecov.io/gh/ilovemilk/semver-git-plugin) 8 | 9 | ## Apply the plugin 10 | 11 | Gradle 2.1 and higher 12 | 13 | ``` 14 | plugins { 15 | id("io.wusa.semver-git-plugin").version("2.3.7") 16 | } 17 | ``` 18 | 19 | Gradle 1.x and 2.0 20 | ``` 21 | buildscript { 22 | repositories { 23 | maven { 24 | url "https://plugins.gradle.org/m2/" 25 | } 26 | } 27 | dependencies { 28 | classpath 'io.wusa:semver-git-plugin:2.3.7' 29 | } 30 | } 31 | 32 | apply plugin: 'io.wusa.semver-git-plugin' 33 | ``` 34 | 35 | ## Configure the plugin 36 | 37 | ```groovy 38 | semver { 39 | snapshotSuffix = "SNAPSHOT" // (default) appended if the commit is without a release tag 40 | dirtyMarker = "dirty" // (default) appended if the are uncommitted changes 41 | initialVersion = "0.1.0" // (default) initial version in semantic versioning 42 | tagPrefix = "" // (default) each project can have its own tags identified by a unique prefix. 43 | tagtype = TagType.Annotated // (default) options are Annotated or Lightweight 44 | branches { // list of branch configurations 45 | branch { 46 | regex = ".+" // regex for the branch you want to configure, put this one last 47 | incrementer = "NO_VERSION_INCREMENTER" // (default) version incrementer 48 | formatter = { "${semver.info.version.major}.${semver.info.version.minor}.${semver.info.version.patch}+build.${semver.info.count}.sha.${semver.info.shortCommit}" } // (default) version formatting closure 49 | } 50 | } 51 | } 52 | ``` 53 | 54 | ### Use with a Gradle multi-module project 55 | For projects which take advantage of Gradle's multi-module projects, it is possible to specify different tags 56 | for each module. 57 | 58 | The tags for each module must be distinguished with an unambiguous prefix. For example, if you have three modules 59 | foo, bar, and blega, you may consider using the module name as the prefix. This prefix is configured in the `semver` 60 | configuration block: 61 | ```kotlin 62 | semver { 63 | tagPrefix = "foo-" 64 | } 65 | ``` 66 | 67 | Given the above configuration, the tags for the "foo" module must all begin with "foo-"; e.g., "foo-3.2.6", 68 | etc... Note that besides the prefix, the rules for the tag names must still follow all the same semver rules as 69 | apply in any other case. 70 | 71 | ## Incrementer 72 | 73 | | Incrementer | Description | 74 | |----------|-------------| 75 | | NO_VERSION_INCREMENTER | Doesn't increment the version at all. | 76 | | PATCH_INCREMENTER | Increments the patch version by one. | 77 | | MINOR_INCREMENTER | Increments the minor version by one. | 78 | | MAJOR_INCREMENTER | Increments the major version by one. | 79 | | CONVENTIONAL_COMMITS_INCREMENTER | Increments the version according to [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/). | 80 | 81 | ## Release 82 | 83 | The versions have to be stored as annotated or lightweight (depending on the configured tag type) git tags in the format of [semantic versioning](https://semver.org/). 84 | 85 | To create a new annotated release tag: 86 | 87 | ```bash 88 | git tag -a 1.0.0-alpha.1 -m "new alpha release of version 1.0.0" 89 | git push --tags 90 | ``` 91 | 92 | To create a new lightweight release tag: 93 | ```bash 94 | git tag -a 1.0.0-alpha.1 95 | git push --tags 96 | ``` 97 | 98 | Following commits without a release tag will have the `snapshotSuffix` (default `SNAPSHOT`) appended 99 | and the version number bumped according to `incrementer` (default `minor`) strategy, e.g., `1.1.0-alpha.1-SNAPSHOT`. 100 | 101 | ## Version usage 102 | 103 | Then you can access the version of your project via `semver.info`. 104 | 105 | Examples: 106 | 107 | ```kotlin 108 | allprojects { 109 | version = semver.info 110 | } 111 | ``` 112 | 113 | ```kotlin 114 | project.version = semver.info 115 | ``` 116 | 117 | ## Version information 118 | 119 | `semver.info` 120 | 121 | Access the following information via `semver.info.*` e.g., `semver.info.tag`. 122 | 123 | | Property | Description | Git: master | Git: feature/ghosty | 124 | |----------|-------------|-------------|---------------------| 125 | | info.branch.group | Group of the branch | master | feature | 126 | | info.branch.name | Name of the branch | master | feature/ghosty | 127 | | info.branch.id | Tokenized branch name | master | feature-ghosty | 128 | | info.commit | Full sha1 commit hash | 4ecabe2e8646fd0b577dcda83e5c23447e230496 | 4ecabe2e8646fd0b577dcda83e5c23447e230496 | 129 | | info.shortCommit | Short sha1 commit has | d2459d | d2459d | 130 | | info.tag | Current tag | If any name of the tag else none | If any name of the tag else none | 131 | | info.lastTag | Last tag | If any name of the tag else none | If any name of the tag else none | 132 | | info.dirty | Current state of the working copy | `true` if the working copy contains uncommitted files | `true` if the working copy contains uncommitted files | 133 | | info | Formatted version | 0.1.0 | 0.1.0 | 134 | | info.version.major | Major version of 2.0.0-rc.1+build.123 | 2 | 2 | 135 | | info.version.minor | Minor version of 2.0.0-rc.1+build.123 | 0 | 0 | 136 | | info.version.patch | Patch version of 2.0.0-rc.1+build.123 | 0 | 0 | 137 | | info.version.build | Build number of 2.0.0-rc.1+build.123 | build.123 | build.123 | 138 | | info.version.prerelease | Pre release of 2.0.0-rc.1+build.123 | rc.1 | rc.1 | 139 | 140 | ## Display version 141 | 142 | The `semver.info` is based on the current or last tag (depending on the specified tag type). 143 | 144 | * If the current commit has an tag this tag will be the version. 145 | * If the current commit has no tag the version takes the last tag and builds the new version based on: 146 | * The ordering of the branch configuration is important for the matching. 147 | * If no tag exists the initial commit will be version 0.1.0 as recommended by [Semantic Versioning 2.0.0](https://semver.org/). 148 | The following commits will be build based on this version until a tag is created. 149 | 150 | ## Tasks 151 | 152 | The semver plugin offers two tasks. 153 | 154 | ### `showVersion` 155 | 156 | Displays the version information: 157 | 158 | ```bash 159 | > Task :showVersion 160 | Version: 0.0.1 161 | ``` 162 | 163 | ### `showInfo` 164 | 165 | Displays the full info: 166 | 167 | ```bash 168 | > Task :showInfo 169 | Branch name: feature/test 170 | Branch group: feature 171 | Branch id: feature-test 172 | Commit: fd132d87d51cee610c5b273050625850e1d62a3b 173 | Short commit: fd132d8 174 | Tag: none 175 | Last tag: 0.0.1 176 | Dirty: false 177 | Version: 0.1.0-SNAPSHOT 178 | Version major: 0 179 | Version minor: 1 180 | Version patch: 0 181 | Version pre release: none 182 | Version build: none 183 | ``` 184 | 185 | ## License 186 | 187 | The MIT License (MIT) 188 | 189 | 190 | -------------------------------------------------------------------------------- /src/test/kotlin/io/wusa/GitServiceTest.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import io.mockk.every 4 | import io.mockk.mockkObject 5 | import io.mockk.unmockkObject 6 | import io.wusa.exception.* 7 | import org.gradle.api.Project 8 | import org.gradle.testfixtures.ProjectBuilder 9 | import org.junit.jupiter.api.* 10 | 11 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 12 | class GitServiceTest { 13 | 14 | private lateinit var project: Project 15 | 16 | @BeforeEach 17 | internal fun setUp() { 18 | project = ProjectBuilder.builder().build() 19 | mockkObject(GitCommandRunner) 20 | } 21 | 22 | @AfterEach 23 | internal fun tearDown() { 24 | unmockkObject(GitCommandRunner) 25 | } 26 | 27 | @Test 28 | fun `git is dirty`() { 29 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns "modified" 30 | Assertions.assertEquals(true, GitService.isDirty(project)) 31 | } 32 | 33 | @Test 34 | fun `git is not dirty`() { 35 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } throws GitException("error") 36 | Assertions.assertEquals(false, GitService.isDirty(project)) 37 | } 38 | 39 | @Test 40 | fun `get last tag`() { 41 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns "modified" 42 | Assertions.assertEquals("modified", GitService.lastTag(project)) 43 | } 44 | 45 | @Test 46 | fun `no last tag`() { 47 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } throws GitException("error") 48 | Assertions.assertThrows(NoLastTagFoundException::class.java) { 49 | GitService.lastTag(project) 50 | } 51 | } 52 | 53 | @Test 54 | fun `get current tag`() { 55 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns "modified" 56 | Assertions.assertEquals("modified", GitService.currentTag(project)) 57 | } 58 | 59 | @Test 60 | fun `no current tag`() { 61 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } throws GitException("error") 62 | Assertions.assertThrows(NoCurrentTagFoundException::class.java) { 63 | GitService.currentTag(project) 64 | } 65 | } 66 | 67 | @Test 68 | fun `get commit sha`() { 69 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns "5f68d6b1ba57fd183e2c0e6cb968c4353907fa17" 70 | Assertions.assertEquals("5f68d6b1ba57fd183e2c0e6cb968c4353907fa17", GitService.currentCommit(project, false)) 71 | } 72 | 73 | @Test 74 | fun `no current commit sha`() { 75 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } throws GitException("error") 76 | Assertions.assertThrows(NoCurrentCommitFoundException::class.java) { 77 | GitService.currentCommit(project, false) 78 | } 79 | } 80 | 81 | @Test 82 | fun `get short commit sha`() { 83 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns "916776" 84 | Assertions.assertEquals("916776", GitService.currentCommit(project, true)) 85 | } 86 | 87 | @Test 88 | fun `no current short commit sha`() { 89 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } throws GitException("error") 90 | Assertions.assertThrows(NoCurrentCommitFoundException::class.java) { 91 | GitService.currentCommit(project, true) 92 | } 93 | } 94 | 95 | @Test 96 | fun `get current branch master`() { 97 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns "(HEAD -> master)" 98 | Assertions.assertEquals("master", GitService.currentBranch(project)) 99 | } 100 | 101 | @Test 102 | fun `get current branch feature-test`() { 103 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns "(HEAD -> feature/test)" 104 | Assertions.assertEquals("feature/test", GitService.currentBranch(project)) 105 | } 106 | 107 | @Test 108 | fun `get current branch feature-test with origin`() { 109 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns 110 | "(HEAD -> feature/test, origin/feature/test)" 111 | Assertions.assertEquals("feature/test", GitService.currentBranch(project)) 112 | } 113 | 114 | @Test 115 | fun `get current branch feature-reactiveTests with origin`() { 116 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns 117 | "(HEAD -> feature/reactiveTests)" 118 | Assertions.assertEquals("feature/reactiveTests", GitService.currentBranch(project)) 119 | } 120 | 121 | @Test 122 | fun `get current branch hotfix-codePrefix with origin`() { 123 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns 124 | "(HEAD -> hotfix/codePrefix, origin/hotfix/codePrefix)" 125 | Assertions.assertEquals("hotfix/codePrefix", GitService.currentBranch(project)) 126 | } 127 | 128 | @Test 129 | fun `get current branch feature-s-version-3 with origin`() { 130 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns 131 | "(HEAD -> feature/s-version-3, origin/feature/s-version-3)" 132 | Assertions.assertEquals("feature/s-version-3", GitService.currentBranch(project)) 133 | } 134 | 135 | @Test 136 | fun `get current branch feature-abcd-10847-abcde-abc with origin`() { 137 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns 138 | "(HEAD -> feature/abcd-10847-abcde-abc, origin/feature/abcd-10847-abcde-abc)" 139 | Assertions.assertEquals("feature/abcd-10847-abcde-abc", GitService.currentBranch(project)) 140 | } 141 | 142 | @Test 143 | fun `get current branch hotfix-5-3-1 with origin`() { 144 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns 145 | "(HEAD -> hotfix/5.3.1, origin/hotfix/5.3.1)" 146 | Assertions.assertEquals("hotfix/5.3.1", GitService.currentBranch(project)) 147 | } 148 | 149 | @Test 150 | fun `issue-35 fix branch regex`() { 151 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns 152 | "(HEAD -> feature/bellini/test-branch-version, origin/feature/bellini/test-branch-version)" 153 | Assertions.assertEquals("feature/bellini/test-branch-version", GitService.currentBranch(project)) 154 | } 155 | 156 | @Test 157 | fun `camelCase branch`() { 158 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns 159 | "(HEAD -> feature/camelCase, remotes/origin/feature/camelCase)" 160 | Assertions.assertEquals("feature/camelCase", GitService.currentBranch(project)) 161 | } 162 | 163 | @Test 164 | fun `UPPER_CASE branch`() { 165 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns 166 | "(HEAD -> feature/UPPER_CASE, origin/feature/UPPER_CASE)" 167 | Assertions.assertEquals("feature/UPPER_CASE", GitService.currentBranch(project)) 168 | } 169 | 170 | @Test 171 | fun `PascalCase branch`() { 172 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns 173 | "(HEAD -> feature/PascalCase, origin/feature/PascalCase)" 174 | Assertions.assertEquals("feature/PascalCase", GitService.currentBranch(project)) 175 | } 176 | 177 | @Test 178 | fun `issue-65 grafted branch`() { 179 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns 180 | "(grafted, HEAD -> release-workflows, origin/release-workflows)" 181 | Assertions.assertEquals("release-workflows", GitService.currentBranch(project)) 182 | } 183 | 184 | @Test 185 | fun `get current branch with null pointer exception`() { 186 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } throws KotlinNullPointerException() 187 | Assertions.assertThrows(NoCurrentBranchFoundException::class.java) { 188 | GitService.currentBranch(project) 189 | } 190 | } 191 | 192 | @Test 193 | fun `no current branch`() { 194 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } throws GitException("error") 195 | Assertions.assertThrows(NoCurrentBranchFoundException::class.java) { 196 | GitService.currentBranch(project) 197 | } 198 | } 199 | 200 | @Test 201 | fun `get list of all commits since last tag`() { 202 | every { GitCommandRunner.execute(projectDir = any(), args = any()) } returns 203 | "7356414 update gradle plugin publish due to security bugs\n" + 204 | "45f65f6 update version an changelog\n" + 205 | "67f03b1 Merge pull request #18 from ilovemilk/feature/support-multi-module\n" + 206 | "fba5872 add default tagPrefix behaviour\n" + 207 | "2d03c4b Merge pull request #17 from jgindin/support-multi-module\n" + 208 | "f96697f Merge remote-tracking branch 'origin/feature/add-more-tests' into develop\n" + 209 | "73fc8b4 Add support for multi-module projects.\n" + 210 | "74e3eb1 add test for kebab-case with numbers\n" + 211 | "63ca60f add more tests" 212 | val listOfCommits = listOf( 213 | "7356414 update gradle plugin publish due to security bugs", 214 | "45f65f6 update version an changelog", 215 | "67f03b1 Merge pull request #18 from ilovemilk/feature/support-multi-module", 216 | "fba5872 add default tagPrefix behaviour", 217 | "2d03c4b Merge pull request #17 from jgindin/support-multi-module", 218 | "f96697f Merge remote-tracking branch 'origin/feature/add-more-tests' into develop", 219 | "73fc8b4 Add support for multi-module projects.", 220 | "74e3eb1 add test for kebab-case with numbers", 221 | "63ca60f add more tests") 222 | Assertions.assertEquals(GitService.getCommitsSinceLastTag(project), listOfCommits) 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /src/test/kotlin/io/wusa/SemanticVersionFactoryTest.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import io.mockk.mockkObject 4 | import io.wusa.exception.NoValidSemverTagFoundException 5 | import org.gradle.api.Project 6 | import org.gradle.testfixtures.ProjectBuilder 7 | import org.junit.jupiter.api.Assertions 8 | import org.junit.jupiter.api.BeforeEach 9 | import org.junit.jupiter.api.Test 10 | 11 | class SemanticVersionFactoryTest { 12 | 13 | private lateinit var project: Project 14 | 15 | @BeforeEach 16 | internal fun setUp() { 17 | project = ProjectBuilder.builder().build() 18 | mockkObject(GitService) 19 | } 20 | 21 | @Test 22 | fun `parse version`() { 23 | val semanticVersionFactory: IVersionFactory = SemanticVersionFactory() 24 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-0-g123-dirty"), Version(1, 0, 0, "", "", Suffix(0, "123", true))) 25 | Assertions.assertEquals(semanticVersionFactory.createFromString("0.0.1-1-gfe17e7f"), Version(0, 0, 1, "", "", Suffix(1, "fe17e7f", false))) 26 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-2-g123-dirty"), Version(1, 0, 0, "", "", Suffix(2, "123", true))) 27 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-0"), Version(1, 0, 0, "0", "", null)) 28 | Assertions.assertEquals(semanticVersionFactory.createFromString("0.0.4"), Version(0, 0, 4, "", "", null)) 29 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.2.3"), Version(1, 2, 3, "", "", null)) 30 | Assertions.assertEquals(semanticVersionFactory.createFromString("10.20.30"), Version(10, 20, 30, "", "", null)) 31 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.1.2-prerelease+meta"), Version(1, 1, 2, "prerelease", "meta", null)) 32 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.1.2+meta"), Version(1, 1, 2, "", "meta", null)) 33 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.1.2+meta-valid"), Version(1, 1, 2, "", "meta-valid", null)) 34 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-alpha"), Version(1, 0, 0, "alpha", "", null)) 35 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-beta"), Version(1, 0, 0, "beta", "", null)) 36 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-alpha.beta"), Version(1, 0, 0, "alpha.beta", "", null)) 37 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-alpha.beta.1"), Version(1, 0, 0, "alpha.beta.1", "", null)) 38 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-alpha.1"), Version(1, 0, 0, "alpha.1", "", null)) 39 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-alpha0.valid"), Version(1, 0, 0, "alpha0.valid", "", null)) 40 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-alpha.0valid"), Version(1, 0, 0, "alpha.0valid", "", null)) 41 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay"), Version(1, 0, 0, "alpha-a.b-c-somethinglong", "build.1-aef.1-its-okay", null)) 42 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-rc.1+build.1"), Version(1, 0, 0, "rc.1", "build.1", null)) 43 | Assertions.assertEquals(semanticVersionFactory.createFromString("2.0.0-rc.1+build.123"), Version(2, 0, 0, "rc.1", "build.123", null)) 44 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.2.3-beta"), Version(1, 2, 3, "beta", "", null)) 45 | Assertions.assertEquals(semanticVersionFactory.createFromString("10.2.3-DEV-SNAPSHOT"), Version(10, 2, 3, "DEV-SNAPSHOT", "", null)) 46 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.2.3-SNAPSHOT-123"), Version(1, 2, 3, "SNAPSHOT-123", "", null)) 47 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0"), Version(1, 0, 0, "", "", null)) 48 | Assertions.assertEquals(semanticVersionFactory.createFromString("2.0.0"), Version(2, 0, 0, "", "", null)) 49 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.1.7"), Version(1, 1, 7, "", "", null)) 50 | Assertions.assertEquals(semanticVersionFactory.createFromString("2.0.0+build.1848"), Version(2, 0, 0, "", "build.1848", null)) 51 | Assertions.assertEquals(semanticVersionFactory.createFromString("2.0.1-alpha.1227"), Version(2, 0, 1, "alpha.1227", "", null)) 52 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-alpha+beta"), Version(1, 0, 0, "alpha", "beta", null)) 53 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.2.3----RC-SNAPSHOT.12.9.1--.12+788"), Version(1, 2, 3, "---RC-SNAPSHOT.12.9.1--.12", "788", null)) 54 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.2.3----R-S.12.9.1--.12+meta"), Version(1, 2, 3, "---R-S.12.9.1--.12", "meta", null)) 55 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.2.3----RC-SNAPSHOT.12.9.1--.12"), Version(1, 2, 3, "---RC-SNAPSHOT.12.9.1--.12", "", null)) 56 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0+0.build.1-rc.10000aaa-kk-0.1"), Version(1, 0, 0, "", "0.build.1-rc.10000aaa-kk-0.1", null)) 57 | Assertions.assertEquals(semanticVersionFactory.createFromString("9999999.9999999.9999999"), Version(9999999, 9999999, 9999999, "", "", null)) 58 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-0A.is.legal"), Version(1, 0, 0, "0A.is.legal", "", null)) 59 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.1.1"), Version(1, 1, 1, "", "", null)) 60 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-5-g5242341-dirty"), Version(1, 0, 0, "", "", Suffix(5, "5242341", true))) 61 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-5-g5242341"), Version(1, 0, 0, "", "", Suffix(5, "5242341", false))) 62 | Assertions.assertEquals(semanticVersionFactory.createFromString("5000.1.1000000-5-g5242341-dirty"), Version(5000, 1, 1000000, "", "", Suffix(5, "5242341", true))) 63 | Assertions.assertEquals(semanticVersionFactory.createFromString("v1.0.0"), Version(1, 0, 0, "", "", null)) 64 | Assertions.assertEquals(semanticVersionFactory.createFromString("V1.0.0"), Version(1, 0, 0, "", "", null)) 65 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0--dirty-5-g5242341"), Version(1, 0, 0, "-dirty", "", Suffix(5, "5242341", false))) 66 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-dirty--5-g5242341"), Version(1, 0, 0, "dirty-", "", Suffix(5, "5242341", false))) 67 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-dirty-5--g5242341"), Version(1, 0, 0, "dirty-5--g5242341", "", null)) 68 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0--g5242341"), Version(1, 0, 0, "-g5242341", "", null)) 69 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-g"), Version(1, 0, 0, "g", "", null)) 70 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0--g"), Version(1, 0, 0, "-g", "", null)) 71 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-g123-5"), Version(1, 0, 0, "g123-5", "", null)) 72 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-5-dirty"), Version(1, 0, 0, "5-dirty", "", null)) 73 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-5"), Version(1, 0, 0, "5", "", null)) 74 | Assertions.assertEquals(semanticVersionFactory.createFromString("1.0.0-5-g"), Version(1, 0, 0, "5-g", "", null)) 75 | 76 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 77 | semanticVersionFactory.createFromString("1") 78 | } 79 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 80 | semanticVersionFactory.createFromString("1.2") 81 | } 82 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 83 | semanticVersionFactory.createFromString("1.2.3-0123") 84 | } 85 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 86 | semanticVersionFactory.createFromString("1.2.3-0123.0123") 87 | } 88 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 89 | semanticVersionFactory.createFromString("1.1.2+.123") 90 | } 91 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 92 | semanticVersionFactory.createFromString("+invalid") 93 | } 94 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 95 | semanticVersionFactory.createFromString("-invalid") 96 | } 97 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 98 | semanticVersionFactory.createFromString("-invalid+invalid") 99 | } 100 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 101 | semanticVersionFactory.createFromString("-invalid.01") 102 | } 103 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 104 | semanticVersionFactory.createFromString("alpha") 105 | } 106 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 107 | semanticVersionFactory.createFromString("alpha.beta") 108 | } 109 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 110 | semanticVersionFactory.createFromString("alpha.beta.1") 111 | } 112 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 113 | semanticVersionFactory.createFromString("alpha.1") 114 | } 115 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 116 | semanticVersionFactory.createFromString("alpha+beta") 117 | } 118 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 119 | semanticVersionFactory.createFromString("alpha_beta") 120 | } 121 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 122 | semanticVersionFactory.createFromString("alpha..") 123 | } 124 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 125 | semanticVersionFactory.createFromString("beta") 126 | } 127 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 128 | semanticVersionFactory.createFromString("1.0.0-alpha_beta") 129 | } 130 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 131 | semanticVersionFactory.createFromString("-") 132 | } 133 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 134 | semanticVersionFactory.createFromString("1.0.0-alpha..") 135 | } 136 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 137 | semanticVersionFactory.createFromString("1.0.0-alpha..1") 138 | } 139 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 140 | semanticVersionFactory.createFromString("1.0.0-alpha...1") 141 | } 142 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 143 | semanticVersionFactory.createFromString("1.0.0-alpha....1") 144 | } 145 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 146 | semanticVersionFactory.createFromString("1.0.0-alpha.....1") 147 | } 148 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 149 | semanticVersionFactory.createFromString("1.0.0-alpha......1") 150 | } 151 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 152 | semanticVersionFactory.createFromString("1.0.0-alpha.......1") 153 | } 154 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 155 | semanticVersionFactory.createFromString("01.1.1") 156 | } 157 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 158 | semanticVersionFactory.createFromString("1.01.1") 159 | } 160 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 161 | semanticVersionFactory.createFromString("1.1.01") 162 | } 163 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 164 | semanticVersionFactory.createFromString("1.2") 165 | } 166 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 167 | semanticVersionFactory.createFromString("1.2.3.DEV") 168 | } 169 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 170 | semanticVersionFactory.createFromString("1.2-SNAPSHOT") 171 | } 172 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 173 | semanticVersionFactory.createFromString("1.2.31.2.3----RC-SNAPSHOT.12.09.1--..12+788") 174 | } 175 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 176 | semanticVersionFactory.createFromString("1.2-RC-SNAPSHOT") 177 | } 178 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 179 | semanticVersionFactory.createFromString("-1.0.3-gamma+b7718") 180 | } 181 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 182 | semanticVersionFactory.createFromString("+justmeta") 183 | } 184 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 185 | semanticVersionFactory.createFromString("9.8.7+meta+meta") 186 | } 187 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 188 | semanticVersionFactory.createFromString("9.8.7-whatever+meta+meta") 189 | } 190 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 191 | semanticVersionFactory.createFromString("9999999.9999999.9999999----RC-SNAPSHOT.12.09.1--------------------------------..12") 192 | } 193 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 194 | semanticVersionFactory.createFromString("1.1.1 ") 195 | } 196 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 197 | semanticVersionFactory.createFromString("") 198 | } 199 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 200 | semanticVersionFactory.createFromString("111") 201 | } 202 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 203 | semanticVersionFactory.createFromString("a.b.c") 204 | } 205 | Assertions.assertThrows(NoValidSemverTagFoundException::class.java) { 206 | semanticVersionFactory.createFromString("1.0.0-") 207 | } 208 | } 209 | } -------------------------------------------------------------------------------- /src/test/kotlin/io/wusa/SemverGitPluginKotlinFunctionalTest.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import org.gradle.testkit.runner.GradleRunner 4 | import org.gradle.testkit.runner.UnexpectedBuildFailure 5 | import org.junit.jupiter.api.* 6 | import java.io.File 7 | 8 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 9 | class SemverGitPluginKotlinFunctionalTest : FunctionalBaseTest() { 10 | 11 | private lateinit var gradleRunner: GradleRunner 12 | 13 | @BeforeAll 14 | fun setUp() { 15 | gradleRunner = GradleRunner.create() 16 | } 17 | 18 | @AfterAll 19 | fun tearDown() { 20 | gradleRunner.projectDir.deleteRecursively() 21 | } 22 | 23 | @Test 24 | fun `version formatter`() { 25 | val testProjectDirectory = createTempDir() 26 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 27 | buildFile.writeText(""" 28 | import io.wusa.Info 29 | 30 | plugins { 31 | id("io.wusa.semver-git-plugin") 32 | } 33 | 34 | semver { 35 | branches { 36 | branch { 37 | regex = ".+" 38 | incrementer = "MINOR_INCREMENTER" 39 | formatter = Transformer{ info:Info -> "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}" } 40 | } 41 | } 42 | } 43 | """) 44 | initializeGitWithoutBranchAnnotated(testProjectDirectory) 45 | val result = gradleRunner 46 | .withProjectDir(testProjectDirectory) 47 | .withArguments("showVersion") 48 | .withPluginClasspath() 49 | .build() 50 | println(result.output) 51 | Assertions.assertTrue(result.output.contains("Version: 0.1.0")) 52 | } 53 | 54 | @Test 55 | fun `version formatter for feature branches use specific`() { 56 | val testProjectDirectory = createTempDir() 57 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 58 | buildFile.writeText(""" 59 | import io.wusa.Info 60 | 61 | plugins { 62 | id("io.wusa.semver-git-plugin") 63 | } 64 | 65 | semver { 66 | branches { 67 | branch { 68 | regex = "feature/.*" 69 | incrementer = "MINOR_INCREMENTER" 70 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}+branch.${'$'}{info.branch.id}" } 71 | } 72 | branch { 73 | regex = ".+" 74 | incrementer = "MINOR_INCREMENTER" 75 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}" } 76 | } 77 | } 78 | } 79 | """) 80 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1", "feature/test") 81 | git.commit().setMessage("").call() 82 | val result = gradleRunner 83 | .withProjectDir(testProjectDirectory) 84 | .withArguments("showVersion") 85 | .withPluginClasspath() 86 | .build() 87 | println(result.output) 88 | Assertions.assertTrue(result.output.contains("Version: 0.1.0+branch.feature-test-SNAPSHOT")) 89 | } 90 | 91 | @Test 92 | fun `version formatter for feature branches with camelCase`() { 93 | val testProjectDirectory = createTempDir() 94 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 95 | buildFile.writeText(""" 96 | import io.wusa.Info 97 | 98 | plugins { 99 | id("io.wusa.semver-git-plugin") 100 | } 101 | 102 | semver { 103 | branches { 104 | branch { 105 | regex = ".+" 106 | incrementer = "MINOR_INCREMENTER" 107 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}" } 108 | } 109 | branch { 110 | regex = "feature/.*" 111 | incrementer = "MINOR_INCREMENTER" 112 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}+branch.${'$'}{info.branch.id}" } 113 | } 114 | } 115 | } 116 | """) 117 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1", "feature/testAbc") 118 | git.commit().setMessage("").call() 119 | val result = gradleRunner 120 | .withProjectDir(testProjectDirectory) 121 | .withArguments("showVersion") 122 | .withPluginClasspath() 123 | .build() 124 | println(result.output) 125 | Assertions.assertTrue(result.output.contains("Version: 0.1.0-SNAPSHOT")) 126 | } 127 | 128 | @Test 129 | fun `version formatter for feature branches with kebab-case`() { 130 | val testProjectDirectory = createTempDir() 131 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 132 | buildFile.writeText(""" 133 | import io.wusa.Info 134 | 135 | plugins { 136 | id("io.wusa.semver-git-plugin") 137 | } 138 | 139 | semver { 140 | branches { 141 | branch { 142 | regex = ".+" 143 | incrementer = "MINOR_INCREMENTER" 144 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}" } 145 | } 146 | branch { 147 | regex = "feature/.*" 148 | incrementer = "MINOR_INCREMENTER" 149 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}+branch.${'$'}{info.branch.id}" } 150 | } 151 | } 152 | } 153 | """) 154 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1", "feature/test-abc-10") 155 | git.commit().setMessage("").call() 156 | val result = gradleRunner 157 | .withProjectDir(testProjectDirectory) 158 | .withArguments("showVersion") 159 | .withPluginClasspath() 160 | .build() 161 | println(result.output) 162 | Assertions.assertTrue(result.output.contains("Version: 0.1.0-SNAPSHOT")) 163 | } 164 | 165 | @Test 166 | fun `version formatter for feature branches with snake_case`() { 167 | val testProjectDirectory = createTempDir() 168 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 169 | buildFile.writeText(""" 170 | import io.wusa.Info 171 | 172 | plugins { 173 | id("io.wusa.semver-git-plugin") 174 | } 175 | 176 | semver { 177 | branches { 178 | branch { 179 | regex = ".+" 180 | incrementer = "MINOR_INCREMENTER" 181 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}" } 182 | } 183 | branch { 184 | regex = "feature/.*" 185 | incrementer = "MINOR_INCREMENTER" 186 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}+branch.${'$'}{info.branch.id}" } 187 | } 188 | } 189 | } 190 | """) 191 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1", "feature/test_abc_10") 192 | git.commit().setMessage("").call() 193 | val result = gradleRunner 194 | .withProjectDir(testProjectDirectory) 195 | .withArguments("showVersion") 196 | .withPluginClasspath() 197 | .build() 198 | println(result.output) 199 | Assertions.assertTrue(result.output.contains("Version: 0.1.0-SNAPSHOT")) 200 | } 201 | 202 | @Test 203 | fun `version formatter for feature branches with PascalCase`() { 204 | val testProjectDirectory = createTempDir() 205 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 206 | buildFile.writeText(""" 207 | import io.wusa.Info 208 | 209 | plugins { 210 | id("io.wusa.semver-git-plugin") 211 | } 212 | 213 | semver { 214 | branches { 215 | branch { 216 | regex = ".+" 217 | incrementer = "MINOR_INCREMENTER" 218 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}" } 219 | } 220 | branch { 221 | regex = "feature/.*" 222 | incrementer = "MINOR_INCREMENTER" 223 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}+branch.${'$'}{info.branch.id}" } 224 | } 225 | } 226 | } 227 | """) 228 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1", "feature/TestAbc10") 229 | git.commit().setMessage("").call() 230 | val result = gradleRunner 231 | .withProjectDir(testProjectDirectory) 232 | .withArguments("showVersion") 233 | .withPluginClasspath() 234 | .build() 235 | println(result.output) 236 | Assertions.assertTrue(result.output.contains("Version: 0.1.0-SNAPSHOT")) 237 | } 238 | 239 | @Test 240 | fun `version formatter for feature branches with UPPERCASE`() { 241 | val testProjectDirectory = createTempDir() 242 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 243 | buildFile.writeText(""" 244 | import io.wusa.Info 245 | 246 | plugins { 247 | id("io.wusa.semver-git-plugin") 248 | } 249 | 250 | semver { 251 | branches { 252 | branch { 253 | regex = ".+" 254 | incrementer = "MINOR_INCREMENTER" 255 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}" } 256 | } 257 | branch { 258 | regex = "feature/.*" 259 | incrementer = "MINOR_INCREMENTER" 260 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}+branch.${'$'}{info.branch.id}" } 261 | } 262 | } 263 | } 264 | """) 265 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1", "feature/TESTABC10") 266 | git.commit().setMessage("").call() 267 | val result = gradleRunner 268 | .withProjectDir(testProjectDirectory) 269 | .withArguments("showVersion") 270 | .withPluginClasspath() 271 | .build() 272 | println(result.output) 273 | Assertions.assertTrue(result.output.contains("Version: 0.1.0-SNAPSHOT")) 274 | } 275 | 276 | @Test 277 | fun `version formatter for feature branches use general`() { 278 | val testProjectDirectory = createTempDir() 279 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 280 | buildFile.writeText(""" 281 | import io.wusa.Info 282 | 283 | plugins { 284 | id("io.wusa.semver-git-plugin") 285 | } 286 | 287 | semver { 288 | branches { 289 | branch { 290 | regex = ".+" 291 | incrementer = "MINOR_INCREMENTER" 292 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}" } 293 | } 294 | branch { 295 | regex = "feature/.*" 296 | incrementer = "MINOR_INCREMENTER" 297 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}+branch.${'$'}{info.branch.id}" } 298 | } 299 | } 300 | } 301 | """) 302 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1", "feature/test") 303 | git.commit().setMessage("").call() 304 | val result = gradleRunner 305 | .withProjectDir(testProjectDirectory) 306 | .withArguments("showVersion") 307 | .withPluginClasspath() 308 | .build() 309 | println(result.output) 310 | Assertions.assertTrue(result.output.contains("Version: 0.1.0-SNAPSHOT")) 311 | } 312 | 313 | @Test 314 | fun `version wrong incrementer`() { 315 | val testProjectDirectory = createTempDir() 316 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 317 | buildFile.writeText(""" 318 | import io.wusa.Info 319 | 320 | plugins { 321 | id("io.wusa.semver-git-plugin") 322 | } 323 | 324 | semver { 325 | branches { 326 | branch { 327 | regex = ".*" 328 | incrementer = "THIS_IS_NO_INCREMENTer" 329 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}+build.${'$'}{info.count}.sha.${'$'}{info.shortCommit}" } 330 | } 331 | } 332 | } 333 | """) 334 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1") 335 | git.commit().setMessage("").call() 336 | Assertions.assertThrows(UnexpectedBuildFailure::class.java) { 337 | gradleRunner 338 | .withProjectDir(testProjectDirectory) 339 | .withArguments("showVersion") 340 | .withPluginClasspath() 341 | .build() 342 | } 343 | } 344 | 345 | @Test 346 | fun `version no increment`() { 347 | val testProjectDirectory = createTempDir() 348 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 349 | buildFile.writeText(""" 350 | import io.wusa.Info 351 | 352 | plugins { 353 | id("io.wusa.semver-git-plugin") 354 | } 355 | 356 | semver { 357 | branches { 358 | branch { 359 | regex = ".*" 360 | incrementer = "NO_VERSION_INCREMENTER" 361 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}+build.${'$'}{info.count}.sha.${'$'}{info.shortCommit}" } 362 | } 363 | } 364 | } 365 | """) 366 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1") 367 | git.commit().setMessage("").call() 368 | val result = gradleRunner 369 | .withProjectDir(testProjectDirectory) 370 | .withArguments("showVersion") 371 | .withPluginClasspath() 372 | .build() 373 | println(result.output) 374 | Assertions.assertTrue("""Version: 0\.0\.1\+build\.2\.sha\.[0-9a-f]{7}-SNAPSHOT""".toRegex().containsMatchIn(result.output)) 375 | } 376 | 377 | @Test 378 | fun `version patch increment`() { 379 | val testProjectDirectory = createTempDir() 380 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 381 | buildFile.writeText(""" 382 | import io.wusa.Info 383 | 384 | plugins { 385 | id("io.wusa.semver-git-plugin") 386 | } 387 | 388 | semver { 389 | branches { 390 | branch { 391 | regex = ".*" 392 | incrementer = "PATCH_INCREMENTER" 393 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}+build.${'$'}{info.count}.sha.${'$'}{info.shortCommit}" } 394 | } 395 | } 396 | } 397 | """) 398 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1") 399 | git.commit().setMessage("").call() 400 | val result = gradleRunner 401 | .withProjectDir(testProjectDirectory) 402 | .withArguments("showVersion") 403 | .withPluginClasspath() 404 | .build() 405 | println(result.output) 406 | Assertions.assertTrue("""Version: 0\.0\.2\+build\.2\.sha\.[0-9a-f]{7}-SNAPSHOT""".toRegex().containsMatchIn(result.output)) 407 | } 408 | 409 | @Test 410 | fun `version minor increment`() { 411 | val testProjectDirectory = createTempDir() 412 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 413 | buildFile.writeText(""" 414 | import io.wusa.Info 415 | 416 | plugins { 417 | id("io.wusa.semver-git-plugin") 418 | } 419 | 420 | semver { 421 | branches { 422 | branch { 423 | regex = ".*" 424 | incrementer = "MINOR_INCREMENTER" 425 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}+build.${'$'}{info.count}.sha.${'$'}{info.shortCommit}" } 426 | } 427 | } 428 | } 429 | """) 430 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1") 431 | git.commit().setMessage("").call() 432 | val result = gradleRunner 433 | .withProjectDir(testProjectDirectory) 434 | .withArguments("showVersion") 435 | .withPluginClasspath() 436 | .build() 437 | println(result.output) 438 | Assertions.assertTrue("""Version: 0\.1\.0\+build\.2\.sha\.[0-9a-f]{7}-SNAPSHOT""".toRegex().containsMatchIn(result.output)) 439 | } 440 | 441 | @Test 442 | fun `version major increment`() { 443 | val testProjectDirectory = createTempDir() 444 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 445 | buildFile.writeText(""" 446 | import io.wusa.Info 447 | 448 | plugins { 449 | id("io.wusa.semver-git-plugin") 450 | } 451 | 452 | semver { 453 | branches { 454 | branch { 455 | regex = ".*" 456 | incrementer = "MAJOR_INCREMENTER" 457 | formatter = Transformer{ "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}+build.${'$'}{info.count}.sha.${'$'}{info.shortCommit}" } 458 | } 459 | } 460 | } 461 | """) 462 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1") 463 | git.commit().setMessage("").call() 464 | val result = gradleRunner 465 | .withProjectDir(testProjectDirectory) 466 | .withArguments("showVersion") 467 | .withPluginClasspath() 468 | .build() 469 | println(result.output) 470 | Assertions.assertTrue("""Version: 1\.0\.0\+build\.2\.sha\.[0-9a-f]{7}-SNAPSHOT""".toRegex().containsMatchIn(result.output)) 471 | } 472 | 473 | @Test 474 | fun `version formatter with prefix`() { 475 | val testProjectDirectory = createTempDir() 476 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 477 | buildFile.writeText(""" 478 | import io.wusa.Info 479 | 480 | plugins { 481 | id("io.wusa.semver-git-plugin") 482 | } 483 | 484 | semver { 485 | tagPrefix = "prj_" 486 | branches { 487 | branch { 488 | regex = ".+" 489 | incrementer = "MINOR_INCREMENTER" 490 | formatter = Transformer{ info:Info -> "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}" } 491 | } 492 | } 493 | } 494 | """) 495 | initializeGitWithoutBranchAnnotated(testProjectDirectory, "prj_0.1.0") 496 | val result = gradleRunner 497 | .withProjectDir(testProjectDirectory) 498 | .withArguments("showVersion") 499 | .withPluginClasspath() 500 | .build() 501 | println(result.output) 502 | Assertions.assertTrue(result.output.contains("Version: 0.1.0")) 503 | } 504 | 505 | @Test 506 | fun `version formatter with prefix and multiple tags not head`() { 507 | val testProjectDirectory = createTempDir() 508 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 509 | buildFile.writeText(""" 510 | import io.wusa.Info 511 | 512 | plugins { 513 | id("io.wusa.semver-git-plugin") 514 | } 515 | 516 | semver { 517 | tagPrefix = "prj_" 518 | branches { 519 | branch { 520 | regex = ".+" 521 | incrementer = "MINOR_INCREMENTER" 522 | formatter = Transformer{ info:Info -> "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}" } 523 | } 524 | } 525 | } 526 | """) 527 | val git = initializeGitWithoutBranchAnnotated(testProjectDirectory, "prj_0.1.0") 528 | val commit = git.commit().setMessage("another commit").call() 529 | git.tag().setName("foo-1.0.0").setObjectId(commit).call() 530 | 531 | val result = gradleRunner 532 | .withProjectDir(testProjectDirectory) 533 | .withArguments("showVersion") 534 | .withPluginClasspath() 535 | .build() 536 | println(result.output) 537 | Assertions.assertTrue(result.output.contains("Version: 0.2.0-SNAPSHOT")) 538 | } 539 | 540 | @Test 541 | fun `version formatter with prefix and multiple tags from head`() { 542 | val testProjectDirectory = createTempDir() 543 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 544 | buildFile.writeText(""" 545 | import io.wusa.Info 546 | 547 | plugins { 548 | id("io.wusa.semver-git-plugin") 549 | } 550 | 551 | semver { 552 | tagPrefix = "foo-" 553 | branches { 554 | branch { 555 | regex = ".+" 556 | incrementer = "MINOR_INCREMENTER" 557 | formatter = Transformer{ info:Info -> "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}" } 558 | } 559 | } 560 | } 561 | """) 562 | val git = initializeGitWithoutBranchAnnotated(testProjectDirectory, "prj_0.1.0") 563 | val commit = git.commit().setMessage("another commit").call() 564 | git.tag().setName("foo-1.0.0").setObjectId(commit).call() 565 | 566 | val result = gradleRunner 567 | .withProjectDir(testProjectDirectory) 568 | .withArguments("showVersion") 569 | .withPluginClasspath() 570 | .build() 571 | println(result.output) 572 | Assertions.assertTrue(result.output.contains("Version: 1.0.0")) 573 | } 574 | 575 | @Test 576 | fun `issue-47 increment minor by one with a lightweight tag`() { 577 | val testProjectDirectory = createTempDir() 578 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 579 | buildFile.writeText(""" 580 | import io.wusa.Info 581 | import io.wusa.TagType 582 | 583 | plugins { 584 | id("io.wusa.semver-git-plugin") 585 | } 586 | 587 | semver { 588 | tagPrefix = "" 589 | tagType = TagType.LIGHTWEIGHT 590 | branches { 591 | branch { 592 | regex = ".+" 593 | incrementer = "CONVENTIONAL_COMMITS_INCREMENTER" 594 | formatter = Transformer{ info:Info -> "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}" } 595 | } 596 | } 597 | } 598 | """) 599 | val git = initializeGitWithoutBranchLightweight(testProjectDirectory, "2.0.42") 600 | git.commit().setMessage("feat: added semver plugin incrementer parameter").call() 601 | git.commit().setMessage("feat: added semver plugin incrementer parameter").call() 602 | git.commit().setMessage("feat: added semver plugin incrementer parameter").call() 603 | 604 | val result = gradleRunner 605 | .withProjectDir(testProjectDirectory) 606 | .withArguments("showVersion") 607 | .withPluginClasspath() 608 | .build() 609 | println(result.output) 610 | Assertions.assertTrue(result.output.contains("Version: 2.1.0-SNAPSHOT")) 611 | } 612 | 613 | @Test 614 | fun `issue-47 increment minor by one with a annotated tag`() { 615 | val testProjectDirectory = createTempDir() 616 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 617 | buildFile.writeText(""" 618 | import io.wusa.Info 619 | import io.wusa.TagType 620 | 621 | plugins { 622 | id("io.wusa.semver-git-plugin") 623 | } 624 | 625 | semver { 626 | tagPrefix = "" 627 | tagType = TagType.ANNOTATED 628 | branches { 629 | branch { 630 | regex = ".+" 631 | incrementer = "CONVENTIONAL_COMMITS_INCREMENTER" 632 | formatter = Transformer{ info:Info -> "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}" } 633 | } 634 | } 635 | } 636 | """) 637 | val git = initializeGitWithoutBranchAnnotated(testProjectDirectory, "2.0.42") 638 | val commit = git.commit().setMessage("feat: another commit").call() 639 | git.tag().setName("2.2.0").setObjectId(commit).setAnnotated(false).call() 640 | git.commit().setMessage("feat: added semver plugin incrementer parameter").call() 641 | git.commit().setMessage("feat: added semver plugin incrementer parameter").call() 642 | git.commit().setMessage("feat: added semver plugin incrementer parameter").call() 643 | 644 | val result = gradleRunner 645 | .withProjectDir(testProjectDirectory) 646 | .withArguments("showVersion") 647 | .withPluginClasspath() 648 | .build() 649 | println(result.output) 650 | Assertions.assertTrue(result.output.contains("Version: 2.1.0-SNAPSHOT")) 651 | } 652 | 653 | @Test 654 | fun `issue-59 increment minor by one with a dirty working tree`() { 655 | val testProjectDirectory = createTempDir() 656 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 657 | buildFile.writeText(""" 658 | import io.wusa.Info 659 | import io.wusa.TagType 660 | 661 | plugins { 662 | id("io.wusa.semver-git-plugin") 663 | } 664 | 665 | semver { 666 | tagPrefix = "" 667 | tagType = TagType.ANNOTATED 668 | branches { 669 | branch { 670 | regex = ".+" 671 | incrementer = "CONVENTIONAL_COMMITS_INCREMENTER" 672 | formatter = Transformer{ info:Info -> "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}" } 673 | } 674 | } 675 | } 676 | """) 677 | val git = initializeGitWithoutBranchAnnotated(testProjectDirectory, "2.0.42") 678 | git.commit().setMessage("feat: another commit").call() 679 | git.commit().setMessage("feat: added semver plugin incrementer parameter").call() 680 | git.commit().setMessage("feat: added semver plugin incrementer parameter").call() 681 | git.commit().setMessage("feat: added semver plugin incrementer parameter").call() 682 | val dirty = File(testProjectDirectory, "dirty.file") 683 | dirty.writeText("dirty") 684 | git.add().addFilepattern(".").call() 685 | 686 | val result = gradleRunner 687 | .withProjectDir(testProjectDirectory) 688 | .withArguments("showInfo") 689 | .withPluginClasspath() 690 | .build() 691 | println(result.output) 692 | Assertions.assertTrue(result.output.contains("Version: 2.1.0-dirty-SNAPSHOT")) 693 | } 694 | 695 | @Test 696 | fun `issue-59 dirty working tree with no commits`() { 697 | val testProjectDirectory = createTempDir() 698 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 699 | buildFile.writeText(""" 700 | import io.wusa.Info 701 | import io.wusa.TagType 702 | 703 | plugins { 704 | id("io.wusa.semver-git-plugin") 705 | } 706 | 707 | semver { 708 | tagPrefix = "" 709 | tagType = TagType.ANNOTATED 710 | branches { 711 | branch { 712 | regex = ".+" 713 | incrementer = "CONVENTIONAL_COMMITS_INCREMENTER" 714 | formatter = Transformer{ info:Info -> "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}" } 715 | } 716 | } 717 | } 718 | """) 719 | val git = initializeGitWithoutBranchAnnotated(testProjectDirectory, "2.0.42") 720 | val dirty = File(testProjectDirectory, "dirty.file") 721 | dirty.writeText("dirty") 722 | git.add().addFilepattern(".").call() 723 | 724 | val result = gradleRunner 725 | .withProjectDir(testProjectDirectory) 726 | .withArguments("showInfo") 727 | .withPluginClasspath() 728 | .build() 729 | println(result.output) 730 | Assertions.assertTrue(result.output.contains("Version: 2.0.43-dirty-SNAPSHOT")) 731 | } 732 | 733 | @Test 734 | fun `issue-61 large process outputs leads to timeouts`() { 735 | val testProjectDirectory = createTempDir() 736 | val buildFile = File(testProjectDirectory, "build.gradle.kts") 737 | buildFile.writeText(""" 738 | import io.wusa.Info 739 | import io.wusa.TagType 740 | 741 | plugins { 742 | id("io.wusa.semver-git-plugin") 743 | } 744 | 745 | semver { 746 | tagPrefix = "" 747 | tagType = TagType.ANNOTATED 748 | branches { 749 | branch { 750 | regex = ".+" 751 | incrementer = "CONVENTIONAL_COMMITS_INCREMENTER" 752 | formatter = Transformer{ info:Info -> "${'$'}{info.version.major}.${'$'}{info.version.minor}.${'$'}{info.version.patch}" } 753 | } 754 | } 755 | } 756 | """) 757 | val git = initializeGitWithoutBranchAnnotated(testProjectDirectory, "2.0.42") 758 | for (x in 0..600) { 759 | val dirty = File(testProjectDirectory, "dirty_$x.file") 760 | dirty.writeText("dirty") 761 | } 762 | git.add().addFilepattern(".").call() 763 | 764 | val result = gradleRunner 765 | .withProjectDir(testProjectDirectory) 766 | .withArguments("showInfo") 767 | .withPluginClasspath() 768 | .build() 769 | println(result.output) 770 | Assertions.assertTrue(result.output.contains("Version: 2.0.43-dirty-SNAPSHOT")) 771 | } 772 | } 773 | -------------------------------------------------------------------------------- /src/test/kotlin/io/wusa/SemverGitPluginGroovyFunctionalTest.kt: -------------------------------------------------------------------------------- 1 | package io.wusa 2 | 3 | import org.gradle.internal.impldep.org.eclipse.jgit.api.Git 4 | import org.gradle.testkit.runner.GradleRunner 5 | import org.gradle.testkit.runner.UnexpectedBuildFailure 6 | import org.junit.jupiter.api.* 7 | import org.junit.jupiter.api.Assertions.assertTrue 8 | import org.junit.jupiter.api.Assertions.assertFalse 9 | import java.io.File 10 | 11 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 12 | class SemverGitPluginGroovyFunctionalTest : FunctionalBaseTest() { 13 | 14 | private lateinit var gradleRunner: GradleRunner 15 | 16 | @BeforeAll 17 | fun setUp() { 18 | gradleRunner = GradleRunner.create() 19 | } 20 | 21 | @AfterAll 22 | fun tearDown() { 23 | gradleRunner.projectDir.deleteRecursively() 24 | } 25 | 26 | @Test 27 | fun defaults() { 28 | val testProjectDirectory = createTempDir() 29 | val buildFile = File(testProjectDirectory, "build.gradle") 30 | buildFile.writeText(""" 31 | plugins { 32 | id 'io.wusa.semver-git-plugin' 33 | } 34 | """) 35 | initializeGitWithoutBranchAnnotated(testProjectDirectory) 36 | val result = gradleRunner 37 | .withProjectDir(testProjectDirectory) 38 | .withArguments("showVersion") 39 | .withPluginClasspath() 40 | .build() 41 | println(result.output) 42 | assertTrue(result.output.contains("Version: 0.1.0")) 43 | } 44 | 45 | @Test 46 | fun `version formatter for all branches`() { 47 | val testProjectDirectory = createTempDir() 48 | val buildFile = File(testProjectDirectory, "build.gradle") 49 | buildFile.writeText(""" 50 | plugins { 51 | id 'io.wusa.semver-git-plugin' 52 | } 53 | 54 | semver { 55 | branches { 56 | branch { 57 | regex = ".*" 58 | incrementer = "MINOR_INCREMENTER" 59 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}" } 60 | } 61 | } 62 | } 63 | """) 64 | initializeGitWithoutBranchAnnotated(testProjectDirectory) 65 | val result = gradleRunner 66 | .withProjectDir(testProjectDirectory) 67 | .withArguments("showVersion") 68 | .withPluginClasspath() 69 | .build() 70 | println(result.output) 71 | assertTrue(result.output.contains("Version: 0.1.0")) 72 | } 73 | 74 | @Test 75 | fun `version formatter for feature branches use specific`() { 76 | val testProjectDirectory = createTempDir() 77 | val buildFile = File(testProjectDirectory, "build.gradle") 78 | buildFile.writeText(""" 79 | plugins { 80 | id 'io.wusa.semver-git-plugin' 81 | } 82 | 83 | semver { 84 | branches { 85 | branch { 86 | regex = "feature/.*" 87 | incrementer = "MINOR_INCREMENTER" 88 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+branch.${'$'}{it.branch.id}" } 89 | } 90 | branch { 91 | regex = ".+" 92 | incrementer = "MINOR_INCREMENTER" 93 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}" } 94 | } 95 | } 96 | } 97 | """) 98 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1", "feature/test") 99 | git.commit().setMessage("").call() 100 | val result = gradleRunner 101 | .withProjectDir(testProjectDirectory) 102 | .withArguments("showVersion") 103 | .withPluginClasspath() 104 | .build() 105 | println(result.output) 106 | assertTrue(result.output.contains("Version: 0.1.0+branch.feature-test-SNAPSHOT")) 107 | } 108 | 109 | @Test 110 | fun `version formatter for feature branches with camelCase`() { 111 | val testProjectDirectory = createTempDir() 112 | val buildFile = File(testProjectDirectory, "build.gradle") 113 | buildFile.writeText(""" 114 | plugins { 115 | id 'io.wusa.semver-git-plugin' 116 | } 117 | 118 | semver { 119 | branches { 120 | branch { 121 | regex = "feature/.*" 122 | incrementer = "MINOR_INCREMENTER" 123 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+branch.${'$'}{it.branch.id}" } 124 | } 125 | branch { 126 | regex = ".+" 127 | incrementer = "MINOR_INCREMENTER" 128 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}" } 129 | } 130 | } 131 | } 132 | """) 133 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1", "feature/testAbc10") 134 | git.commit().setMessage("").call() 135 | val result = gradleRunner 136 | .withProjectDir(testProjectDirectory) 137 | .withArguments("showVersion") 138 | .withPluginClasspath() 139 | .build() 140 | println(result.output) 141 | assertTrue(result.output.contains("Version: 0.1.0+branch.feature-testAbc10-SNAPSHOT")) 142 | } 143 | 144 | @Test 145 | fun `version formatter for feature branches with kebab-case`() { 146 | val testProjectDirectory = createTempDir() 147 | val buildFile = File(testProjectDirectory, "build.gradle") 148 | buildFile.writeText(""" 149 | plugins { 150 | id 'io.wusa.semver-git-plugin' 151 | } 152 | 153 | semver { 154 | branches { 155 | branch { 156 | regex = "feature/.*" 157 | incrementer = "MINOR_INCREMENTER" 158 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+branch.${'$'}{it.branch.id}" } 159 | } 160 | branch { 161 | regex = ".+" 162 | incrementer = "MINOR_INCREMENTER" 163 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}" } 164 | } 165 | } 166 | } 167 | """) 168 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1", "feature/test-abc-10") 169 | git.commit().setMessage("").call() 170 | val result = gradleRunner 171 | .withProjectDir(testProjectDirectory) 172 | .withArguments("showVersion") 173 | .withPluginClasspath() 174 | .build() 175 | println(result.output) 176 | assertTrue(result.output.contains("Version: 0.1.0+branch.feature-test-abc-10-SNAPSHOT")) 177 | } 178 | 179 | @Test 180 | fun `version formatter for feature branches with PascalCase`() { 181 | val testProjectDirectory = createTempDir() 182 | val buildFile = File(testProjectDirectory, "build.gradle") 183 | buildFile.writeText(""" 184 | plugins { 185 | id 'io.wusa.semver-git-plugin' 186 | } 187 | 188 | semver { 189 | branches { 190 | branch { 191 | regex = "feature/.*" 192 | incrementer = "MINOR_INCREMENTER" 193 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+branch.${'$'}{it.branch.id}" } 194 | } 195 | branch { 196 | regex = ".+" 197 | incrementer = "MINOR_INCREMENTER" 198 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}" } 199 | } 200 | } 201 | } 202 | """) 203 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1", "feature/TestAbc10") 204 | git.commit().setMessage("").call() 205 | val result = gradleRunner 206 | .withProjectDir(testProjectDirectory) 207 | .withArguments("showVersion") 208 | .withPluginClasspath() 209 | .build() 210 | println(result.output) 211 | assertTrue(result.output.contains("Version: 0.1.0+branch.feature-TestAbc10-SNAPSHOT")) 212 | } 213 | 214 | @Test 215 | fun `version formatter for feature branches with snake_case`() { 216 | val testProjectDirectory = createTempDir() 217 | val buildFile = File(testProjectDirectory, "build.gradle") 218 | buildFile.writeText(""" 219 | plugins { 220 | id 'io.wusa.semver-git-plugin' 221 | } 222 | 223 | semver { 224 | branches { 225 | branch { 226 | regex = "feature/.*" 227 | incrementer = "MINOR_INCREMENTER" 228 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+branch.${'$'}{it.branch.id}" } 229 | } 230 | branch { 231 | regex = ".+" 232 | incrementer = "MINOR_INCREMENTER" 233 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}" } 234 | } 235 | } 236 | } 237 | """) 238 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1", "feature/test_abc_10") 239 | git.commit().setMessage("").call() 240 | val result = gradleRunner 241 | .withProjectDir(testProjectDirectory) 242 | .withArguments("showVersion") 243 | .withPluginClasspath() 244 | .build() 245 | println(result.output) 246 | assertTrue(result.output.contains("Version: 0.1.0+branch.feature-test_abc_10-SNAPSHOT")) 247 | } 248 | 249 | @Test 250 | fun `version formatter for feature branches with UPPER_CASE`() { 251 | val testProjectDirectory = createTempDir() 252 | val buildFile = File(testProjectDirectory, "build.gradle") 253 | buildFile.writeText(""" 254 | plugins { 255 | id 'io.wusa.semver-git-plugin' 256 | } 257 | 258 | semver { 259 | branches { 260 | branch { 261 | regex = "feature/.*" 262 | incrementer = "MINOR_INCREMENTER" 263 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+branch.${'$'}{it.branch.id}" } 264 | } 265 | branch { 266 | regex = ".+" 267 | incrementer = "MINOR_INCREMENTER" 268 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}" } 269 | } 270 | } 271 | } 272 | """) 273 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1", "feature/TEST_ABC_10") 274 | git.commit().setMessage("").call() 275 | val result = gradleRunner 276 | .withProjectDir(testProjectDirectory) 277 | .withArguments("showVersion") 278 | .withPluginClasspath() 279 | .build() 280 | println(result.output) 281 | assertTrue(result.output.contains("Version: 0.1.0+branch.feature-TEST_ABC_10-SNAPSHOT")) 282 | } 283 | 284 | @Test 285 | fun `no existing tag`() { 286 | val testProjectDirectory = createTempDir() 287 | val buildFile = File(testProjectDirectory, "build.gradle") 288 | buildFile.writeText(""" 289 | plugins { 290 | id 'io.wusa.semver-git-plugin' 291 | } 292 | """) 293 | val git = Git.init().setDirectory(testProjectDirectory).call() 294 | git.commit().setMessage("").call() 295 | val result = gradleRunner 296 | .withProjectDir(testProjectDirectory) 297 | .withArguments("showVersion") 298 | .withPluginClasspath() 299 | .build() 300 | println(result.output) 301 | assertTrue(result.output.contains("-SNAPSHOT")) 302 | assertTrue(result.output.contains("Version: 0.1.0")) 303 | } 304 | 305 | @Test 306 | fun `no existing tag with custom initial version`() { 307 | val testProjectDirectory = createTempDir() 308 | val buildFile = File(testProjectDirectory, "build.gradle") 309 | buildFile.writeText(""" 310 | plugins { 311 | id 'io.wusa.semver-git-plugin' 312 | } 313 | 314 | semver { 315 | initialVersion = '1.0.0' 316 | } 317 | """) 318 | val git = Git.init().setDirectory(testProjectDirectory).call() 319 | git.commit().setMessage("").call() 320 | val result = gradleRunner 321 | .withProjectDir(testProjectDirectory) 322 | .withArguments("showVersion") 323 | .withPluginClasspath() 324 | .build() 325 | println(result.output) 326 | assertTrue(result.output.contains("-SNAPSHOT")) 327 | assertTrue(result.output.contains("Version: 1.0.0")) 328 | } 329 | 330 | @Test 331 | fun `no existing tag with configuration without commits`() { 332 | val testProjectDirectory = createTempDir() 333 | val buildFile = File(testProjectDirectory, "build.gradle") 334 | buildFile.writeText(""" 335 | plugins { 336 | id 'io.wusa.semver-git-plugin' 337 | } 338 | 339 | semver { 340 | snapshotSuffix = 'SNAPSHOT' 341 | } 342 | """) 343 | Git.init().setDirectory(testProjectDirectory).call() 344 | val result = gradleRunner 345 | .withProjectDir(testProjectDirectory) 346 | .withArguments("showVersion") 347 | .withPluginClasspath() 348 | .build() 349 | println(result.output) 350 | assertTrue("""Version: 0\.1\.0-SNAPSHOT""".toRegex().containsMatchIn(result.output)) 351 | } 352 | 353 | @Test 354 | fun `no existing tag with configuration`() { 355 | val testProjectDirectory = createTempDir() 356 | val buildFile = File(testProjectDirectory, "build.gradle") 357 | buildFile.writeText(""" 358 | plugins { 359 | id 'io.wusa.semver-git-plugin' 360 | } 361 | 362 | semver { 363 | snapshotSuffix = 'TEST' 364 | } 365 | """) 366 | val git = Git.init().setDirectory(testProjectDirectory).call() 367 | git.commit().setMessage("").call() 368 | val result = gradleRunner 369 | .withProjectDir(testProjectDirectory) 370 | .withArguments("showVersion") 371 | .withPluginClasspath() 372 | .build() 373 | println(result.output) 374 | assertTrue(result.output.contains("-TEST")) 375 | assertTrue(result.output.contains("Version: 0.1.0")) 376 | } 377 | 378 | @Test 379 | fun `patch release with custom configuration`() { 380 | val testProjectDirectory = createTempDir() 381 | val buildFile = File(testProjectDirectory, "build.gradle") 382 | buildFile.writeText(""" 383 | plugins { 384 | id 'io.wusa.semver-git-plugin' 385 | } 386 | 387 | semver { 388 | branches { 389 | branch { 390 | regex = ".*" 391 | incrementer = "MINOR_INCREMENTER" 392 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+build.${'$'}{it.count}.sha.${'$'}{it.shortCommit}" } 393 | } 394 | } 395 | } 396 | """) 397 | initializeGitWithoutBranchAnnotated(testProjectDirectory, "0.0.1") 398 | val result = gradleRunner 399 | .withProjectDir(testProjectDirectory) 400 | .withArguments("showVersion") 401 | .withPluginClasspath() 402 | .build() 403 | println(result.output) 404 | assertTrue(result.output.contains("Version: 0.0.1")) 405 | } 406 | 407 | @Test 408 | fun `minor release with custom configuration`() { 409 | val testProjectDirectory = createTempDir() 410 | val buildFile = File(testProjectDirectory, "build.gradle") 411 | buildFile.writeText(""" 412 | plugins { 413 | id 'io.wusa.semver-git-plugin' 414 | } 415 | 416 | semver { 417 | branches { 418 | branch { 419 | regex = ".*" 420 | incrementer = "MINOR_INCREMENTER" 421 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+build.${'$'}{it.count}.sha.${'$'}{it.shortCommit}" } 422 | } 423 | } 424 | } 425 | """) 426 | initializeGitWithoutBranchAnnotated(testProjectDirectory) 427 | val result = gradleRunner 428 | .withProjectDir(testProjectDirectory) 429 | .withArguments("showVersion") 430 | .withPluginClasspath() 431 | .build() 432 | println(result.output) 433 | assertTrue(result.output.contains("Version: 0.1.0")) 434 | } 435 | 436 | @Test 437 | fun `major release with custom configuration`() { 438 | val testProjectDirectory = createTempDir() 439 | val buildFile = File(testProjectDirectory, "build.gradle") 440 | buildFile.writeText(""" 441 | plugins { 442 | id 'io.wusa.semver-git-plugin' 443 | } 444 | 445 | semver { 446 | snapshotSuffix = 'SNAPSHOT' 447 | branches { 448 | branch { 449 | regex = ".*" 450 | incrementer = "MINOR_INCREMENTER" 451 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+build.${'$'}{it.count}.sha.${'$'}{it.shortCommit}" } 452 | } 453 | } 454 | } 455 | """) 456 | initializeGitWithoutBranchAnnotated(testProjectDirectory, "1.0.0") 457 | val result = gradleRunner 458 | .withProjectDir(testProjectDirectory) 459 | .withArguments("showVersion") 460 | .withPluginClasspath() 461 | .build() 462 | println(result.output) 463 | assertTrue(result.output.contains("Version: 1.0.0")) 464 | } 465 | 466 | @Test 467 | fun `release alpha with custom configuration`() { 468 | val testProjectDirectory = createTempDir() 469 | val buildFile = File(testProjectDirectory, "build.gradle") 470 | buildFile.writeText(""" 471 | plugins { 472 | id 'io.wusa.semver-git-plugin' 473 | } 474 | 475 | semver { 476 | branches { 477 | branch { 478 | regex = ".*" 479 | incrementer = "MINOR_INCREMENTER" 480 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+build.${'$'}{it.count}.sha.${'$'}{it.shortCommit}" } 481 | } 482 | } 483 | } 484 | """) 485 | initializeGitWithoutBranchAnnotated(testProjectDirectory, "0.1.0-alpha") 486 | val result = gradleRunner 487 | .withProjectDir(testProjectDirectory) 488 | .withArguments("showVersion") 489 | .withPluginClasspath() 490 | .build() 491 | println(result.output) 492 | assertTrue(result.output.contains("Version: 0.1.0-alpha")) 493 | } 494 | 495 | @Test 496 | fun `release alpha beta with custom configuration`() { 497 | val testProjectDirectory = createTempDir() 498 | val buildFile = File(testProjectDirectory, "build.gradle") 499 | buildFile.writeText(""" 500 | plugins { 501 | id 'io.wusa.semver-git-plugin' 502 | } 503 | 504 | semver { 505 | branches { 506 | branch { 507 | regex = ".*" 508 | incrementer = "MINOR_INCREMENTER" 509 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+build.${'$'}{it.count}.sha.${'$'}{it.shortCommit}" } 510 | } 511 | } 512 | } 513 | """) 514 | initializeGitWithoutBranchAnnotated(testProjectDirectory, "0.1.0-alpha.beta") 515 | val result = gradleRunner 516 | .withProjectDir(testProjectDirectory) 517 | .withArguments("showVersion") 518 | .withPluginClasspath() 519 | .build() 520 | println(result.output) 521 | assertTrue(result.output.contains("Version: 0.1.0-alpha.beta")) 522 | } 523 | 524 | @Test 525 | fun `release alpha 1 with custom configuration`() { 526 | val testProjectDirectory = createTempDir() 527 | val buildFile = File(testProjectDirectory, "build.gradle") 528 | buildFile.writeText(""" 529 | plugins { 530 | id 'io.wusa.semver-git-plugin' 531 | } 532 | 533 | semver { 534 | branches { 535 | branch { 536 | regex = ".*" 537 | incrementer = "MINOR_INCREMENTER" 538 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+build.${'$'}{it.count}.sha.${'$'}{it.shortCommit}" } 539 | } 540 | } 541 | } 542 | """) 543 | initializeGitWithoutBranchAnnotated(testProjectDirectory, "0.1.0-alpha.1") 544 | val result = gradleRunner 545 | .withProjectDir(testProjectDirectory) 546 | .withArguments("showVersion") 547 | .withPluginClasspath() 548 | .build() 549 | println(result.output) 550 | assertTrue(result.output.contains("Version: 0.1.0-alpha.1")) 551 | } 552 | 553 | @Test 554 | fun `release beta with custom configuration`() { 555 | val testProjectDirectory = createTempDir() 556 | val buildFile = File(testProjectDirectory, "build.gradle") 557 | buildFile.writeText(""" 558 | plugins { 559 | id 'io.wusa.semver-git-plugin' 560 | } 561 | 562 | semver { 563 | branches { 564 | branch { 565 | regex = ".*" 566 | incrementer = "MINOR_INCREMENTER" 567 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+build.${'$'}{it.count}.sha.${'$'}{it.shortCommit}" } 568 | } 569 | } 570 | } 571 | """) 572 | initializeGitWithoutBranchAnnotated(testProjectDirectory, "0.1.0-beta") 573 | val result = gradleRunner 574 | .withProjectDir(testProjectDirectory) 575 | .withArguments("showVersion") 576 | .withPluginClasspath() 577 | .build() 578 | println(result.output) 579 | assertTrue(result.output.contains("Version: 0.1.0-beta")) 580 | } 581 | 582 | @Test 583 | fun `release rc with custom configuration`() { 584 | val testProjectDirectory = createTempDir() 585 | val buildFile = File(testProjectDirectory, "build.gradle") 586 | buildFile.writeText(""" 587 | plugins { 588 | id 'io.wusa.semver-git-plugin' 589 | } 590 | 591 | semver { 592 | branches { 593 | branch { 594 | regex = ".*" 595 | incrementer = "MINOR_INCREMENTER" 596 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+build.${'$'}{it.count}.sha.${'$'}{it.shortCommit}" } 597 | } 598 | } 599 | } 600 | """) 601 | initializeGitWithoutBranchAnnotated(testProjectDirectory, "0.1.0-rc") 602 | val result = gradleRunner 603 | .withProjectDir(testProjectDirectory) 604 | .withArguments("showVersion") 605 | .withPluginClasspath() 606 | .build() 607 | println(result.output) 608 | assertTrue(result.output.contains("Version: 0.1.0-rc")) 609 | } 610 | 611 | @Test 612 | fun `bump patch version`() { 613 | val testProjectDirectory = createTempDir() 614 | val buildFile = File(testProjectDirectory, "build.gradle") 615 | buildFile.writeText(""" 616 | plugins { 617 | id 'io.wusa.semver-git-plugin' 618 | } 619 | 620 | semver { 621 | branches { 622 | branch { 623 | regex = ".*" 624 | incrementer = "PATCH_INCREMENTER" 625 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+build.${'$'}{it.count}.sha.${'$'}{it.shortCommit}" } 626 | } 627 | } 628 | } 629 | """) 630 | val git = initializeGitWithoutBranchAnnotated(testProjectDirectory) 631 | git.commit().setMessage("").call() 632 | val result = gradleRunner 633 | .withProjectDir(testProjectDirectory) 634 | .withArguments("showVersion") 635 | .withPluginClasspath() 636 | .build() 637 | println(result.output) 638 | assertTrue(result.output.contains("Version: 0.1.1")) 639 | } 640 | 641 | @Test 642 | fun `bump minor version`() { 643 | val testProjectDirectory = createTempDir() 644 | val buildFile = File(testProjectDirectory, "build.gradle") 645 | buildFile.writeText(""" 646 | plugins { 647 | id 'io.wusa.semver-git-plugin' 648 | } 649 | 650 | semver { 651 | branches { 652 | branch { 653 | regex = ".*" 654 | incrementer = "MINOR_INCREMENTER" 655 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+build.${'$'}{it.count}.sha.${'$'}{it.shortCommit}" } 656 | } 657 | } 658 | } 659 | """) 660 | val git = initializeGitWithoutBranchAnnotated(testProjectDirectory) 661 | git.commit().setMessage("").call() 662 | val result = gradleRunner 663 | .withProjectDir(testProjectDirectory) 664 | .withArguments("showVersion") 665 | .withPluginClasspath() 666 | .build() 667 | println(result.output) 668 | assertTrue(result.output.contains("Version: 0.2.0")) 669 | } 670 | 671 | @Test 672 | fun `bump major version`() { 673 | val testProjectDirectory = createTempDir() 674 | val buildFile = File(testProjectDirectory, "build.gradle") 675 | buildFile.writeText(""" 676 | plugins { 677 | id 'io.wusa.semver-git-plugin' 678 | } 679 | 680 | semver { 681 | branches { 682 | branch { 683 | regex = ".*" 684 | incrementer = "MAJOR_INCREMENTER" 685 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+build.${'$'}{it.count}.sha.${'$'}{it.shortCommit}" } 686 | } 687 | } 688 | } 689 | """) 690 | val git = initializeGitWithoutBranchAnnotated(testProjectDirectory) 691 | git.commit().setMessage("").call() 692 | val result = gradleRunner 693 | .withProjectDir(testProjectDirectory) 694 | .withArguments("showVersion") 695 | .withPluginClasspath() 696 | .build() 697 | println(result.output) 698 | assertTrue(result.output.contains("-SNAPSHOT")) 699 | assertTrue(result.output.contains("Version: 1.0.0")) 700 | } 701 | 702 | @Test 703 | fun `don't bump version`() { 704 | val testProjectDirectory = createTempDir() 705 | val buildFile = File(testProjectDirectory, "build.gradle") 706 | buildFile.writeText(""" 707 | plugins { 708 | id 'io.wusa.semver-git-plugin' 709 | } 710 | 711 | semver { 712 | branches { 713 | branch { 714 | regex = ".*" 715 | incrementer = "NO_VERSION_INCREMENTER" 716 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}+build.${'$'}{it.count}.sha.${'$'}{it.shortCommit}" } 717 | } 718 | } 719 | } 720 | """) 721 | val git = initializeGitWithoutBranchAnnotated(testProjectDirectory) 722 | git.commit().setMessage("").call() 723 | val result = gradleRunner 724 | .withProjectDir(testProjectDirectory) 725 | .withArguments("showVersion") 726 | .withPluginClasspath() 727 | .build() 728 | println(result.output) 729 | assertTrue(result.output.contains("Version: 0.1.0")) 730 | } 731 | 732 | @Test 733 | fun `non-semver tag`() { 734 | val testProjectDirectory = createTempDir() 735 | val buildFile = File(testProjectDirectory, "build.gradle") 736 | buildFile.writeText(""" 737 | plugins { 738 | id 'io.wusa.semver-git-plugin' 739 | } 740 | """) 741 | val git = initializeGitWithoutBranchAnnotated(testProjectDirectory) 742 | val commit = git.commit().setMessage("").call() 743 | git.tag().setName("test-tag").setObjectId(commit).call() 744 | Assertions.assertThrows(UnexpectedBuildFailure::class.java) { 745 | gradleRunner 746 | .withProjectDir(testProjectDirectory) 747 | .withArguments("showVersion") 748 | .withPluginClasspath() 749 | .build() 750 | } 751 | } 752 | 753 | @Test 754 | fun `full info of master branch with one commit after the tag`() { 755 | val testProjectDirectory = createTempDir() 756 | val buildFile = File(testProjectDirectory, "build.gradle") 757 | buildFile.writeText(""" 758 | plugins { 759 | id 'io.wusa.semver-git-plugin' 760 | } 761 | """) 762 | val git = initializeGitWithoutBranchAnnotated(testProjectDirectory) 763 | val commit = git.commit().setMessage("").call() 764 | val result = gradleRunner 765 | .withProjectDir(testProjectDirectory) 766 | .withArguments("showInfo") 767 | .withPluginClasspath() 768 | .build() 769 | println(result.output) 770 | assertTrue(result.output.contains("Branch name: master")) 771 | assertTrue(result.output.contains("Branch group: master")) 772 | assertTrue(result.output.contains("Branch id: master")) 773 | assertTrue(result.output.contains("Commit: " + commit.id.name())) 774 | assertTrue(result.output.contains("Short commit: " + commit.id.abbreviate( 7 ).name())) 775 | assertTrue(result.output.contains("Tag: none")) 776 | assertTrue(result.output.contains("Last tag: 0.1.0")) 777 | assertTrue(result.output.contains("Dirty: false")) 778 | assertTrue(result.output.contains("Version major: 0")) 779 | assertTrue(result.output.contains("Version minor: 2")) 780 | assertTrue(result.output.contains("Version patch: 0")) 781 | assertTrue(result.output.contains("Version pre release: none")) 782 | assertTrue(result.output.contains("Version build: none")) 783 | } 784 | 785 | @Test 786 | fun `full info of feature-test branch with one commit after the tag`() { 787 | val testProjectDirectory = createTempDir() 788 | val buildFile = File(testProjectDirectory, "build.gradle") 789 | buildFile.writeText(""" 790 | plugins { 791 | id 'io.wusa.semver-git-plugin' 792 | } 793 | """) 794 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1", "feature/test") 795 | val commit = git.commit().setMessage("").call() 796 | val result = gradleRunner 797 | .withProjectDir(testProjectDirectory) 798 | .withArguments("showInfo") 799 | .withPluginClasspath() 800 | .build() 801 | println(result.output) 802 | assertTrue(result.output.contains("Branch name: feature/test")) 803 | assertTrue(result.output.contains("Branch group: feature")) 804 | assertTrue(result.output.contains("Branch id: feature-test")) 805 | assertTrue(result.output.contains("Commit: " + commit.id.name())) 806 | assertTrue(result.output.contains("Short commit: " + commit.id.abbreviate( 7 ).name())) 807 | assertTrue(result.output.contains("Tag: none")) 808 | assertTrue(result.output.contains("Last tag: 0.0.1")) 809 | assertTrue(result.output.contains("Dirty: false")) 810 | assertTrue(result.output.contains("Version major: 0")) 811 | assertTrue(result.output.contains("Version minor: 1")) 812 | assertTrue(result.output.contains("Version patch: 0")) 813 | assertTrue(result.output.contains("Version pre release: none")) 814 | assertTrue(result.output.contains("Version build: none")) 815 | } 816 | 817 | @Test 818 | fun `full info of feature-test branch with no commit after the tag`() { 819 | val testProjectDirectory = createTempDir() 820 | val buildFile = File(testProjectDirectory, "build.gradle") 821 | buildFile.writeText(""" 822 | plugins { 823 | id 'io.wusa.semver-git-plugin' 824 | } 825 | """) 826 | val git = initializeGitWithBranch(testProjectDirectory, "0.0.1", "feature/test") 827 | val head = git.repository.allRefs["HEAD"] 828 | val result = gradleRunner 829 | .withProjectDir(testProjectDirectory) 830 | .withArguments("showInfo") 831 | .withPluginClasspath() 832 | .build() 833 | println(result.output) 834 | assertTrue(result.output.contains("Branch name: feature/test")) 835 | assertTrue(result.output.contains("Branch group: feature")) 836 | assertTrue(result.output.contains("Branch id: feature-test")) 837 | assertTrue(result.output.contains("Commit: " + head?.objectId?.name)) 838 | assertTrue(result.output.contains("Tag: 0.0.1")) 839 | assertTrue(result.output.contains("Last tag: 0.0.1")) 840 | assertTrue(result.output.contains("Dirty: false")) 841 | assertTrue(result.output.contains("Version major: 0")) 842 | assertTrue(result.output.contains("Version minor: 0")) 843 | assertTrue(result.output.contains("Version patch: 1")) 844 | assertTrue(result.output.contains("Version pre release: none")) 845 | assertTrue(result.output.contains("Version build: none")) 846 | } 847 | 848 | @Test 849 | fun `issues-23 fix branch logic release branch`() { 850 | val testProjectDirectory = createTempDir() 851 | val buildFile = File(testProjectDirectory, "build.gradle") 852 | buildFile.writeText(""" 853 | plugins { 854 | id 'io.wusa.semver-git-plugin' 855 | } 856 | 857 | semver { 858 | snapshotSuffix = "SNAPSHOT" 859 | dirtyMarker = "dirty" 860 | branches { 861 | branch { 862 | regex = "develop" 863 | incrementer = "MINOR_INCREMENTER" 864 | formatter = { "${'$'}{semver.info.version.major}.${'$'}{semver.info.version.minor}.${'$'}{semver.info.version.patch}-DEV.${'$'}{semver.info.count}.sha.${'$'}{semver.info.shortCommit}" } 865 | } 866 | branch { 867 | regex = "release/.+" 868 | incrementer = "MINOR_INCREMENTER" 869 | formatter = { "${'$'}{semver.info.version.major}.${'$'}{semver.info.version.minor}.${'$'}{semver.info.version.patch}-RC.${'$'}{semver.info.count}.sha.${'$'}{semver.info.shortCommit}" } 870 | } 871 | branch { 872 | regex = "hotfix/.+" 873 | incrementer = "PATCH_INCREMENTER" 874 | formatter = { "${'$'}{semver.info.version.major}.${'$'}{semver.info.version.minor}.${'$'}{semver.info.version.patch}-HOTFIX.${'$'}{semver.info.count}.sha.${'$'}{semver.info.shortCommit}" } 875 | } 876 | branch { 877 | regex = ".+" 878 | incrementer = "MINOR_INCREMENTER" 879 | formatter = { "${'$'}{semver.info.version.major}.${'$'}{semver.info.version.minor}.${'$'}{semver.info.version.patch}-BUILD.${'$'}{semver.info.count}.sha.${'$'}{semver.info.shortCommit}" } 880 | } 881 | } 882 | } 883 | """) 884 | val git = initializeGitWithBranch(testProjectDirectory, "5.2.1", "release/5.3.0") 885 | val commit = git.commit().setMessage("").call() 886 | val result = gradleRunner 887 | .withProjectDir(testProjectDirectory) 888 | .withArguments("showInfo") 889 | .withPluginClasspath() 890 | .build() 891 | println(result.output) 892 | assertTrue(result.output.contains("Branch name: release/5.3.0")) 893 | assertTrue(result.output.contains("Branch group: release")) 894 | assertTrue(result.output.contains("Branch id: release-5.3.0")) 895 | assertTrue(result.output.contains("Commit: " + commit.id.name())) 896 | assertTrue(result.output.contains("Short commit: " + commit.id.abbreviate( 7 ).name())) 897 | assertTrue(result.output.contains("Tag: none")) 898 | assertTrue(result.output.contains("Last tag: 5.2.1-1-g" + commit.id.abbreviate( 7 ).name())) 899 | assertTrue(result.output.contains("Dirty: false")) 900 | assertTrue(result.output.contains("Version: 5.3.0-RC.2.sha." + commit.id.abbreviate( 7 ).name() + "-SNAPSHOT")) 901 | assertTrue(result.output.contains("Version major: 5")) 902 | assertTrue(result.output.contains("Version minor: 3")) 903 | assertTrue(result.output.contains("Version patch: 0")) 904 | assertTrue(result.output.contains("Version pre release: none")) 905 | assertTrue(result.output.contains("Version build: none")) 906 | } 907 | 908 | @Test 909 | fun `issues-23 fix branch logic hotfix branch`() { 910 | val testProjectDirectory = createTempDir() 911 | val buildFile = File(testProjectDirectory, "build.gradle") 912 | buildFile.writeText(""" 913 | plugins { 914 | id 'io.wusa.semver-git-plugin' 915 | } 916 | 917 | semver { 918 | snapshotSuffix = "SNAPSHOT" 919 | dirtyMarker = "dirty" 920 | branches { 921 | branch { 922 | regex = "develop" 923 | incrementer = "MINOR_INCREMENTER" 924 | formatter = { "${'$'}{semver.info.version.major}.${'$'}{semver.info.version.minor}.${'$'}{semver.info.version.patch}-DEV.${'$'}{semver.info.count}.sha.${'$'}{semver.info.shortCommit}" } 925 | } 926 | branch { 927 | regex = "release/.+" 928 | incrementer = "MINOR_INCREMENTER" 929 | formatter = { "${'$'}{semver.info.version.major}.${'$'}{semver.info.version.minor}.${'$'}{semver.info.version.patch}-RC.${'$'}{semver.info.count}.sha.${'$'}{semver.info.shortCommit}" } 930 | } 931 | branch { 932 | regex = "hotfix/.+" 933 | incrementer = "PATCH_INCREMENTER" 934 | formatter = { "${'$'}{semver.info.version.major}.${'$'}{semver.info.version.minor}.${'$'}{semver.info.version.patch}-HOTFIX.${'$'}{semver.info.count}.sha.${'$'}{semver.info.shortCommit}" } 935 | } 936 | branch { 937 | regex = ".+" 938 | incrementer = "MINOR_INCREMENTER" 939 | formatter = { "${'$'}{semver.info.version.major}.${'$'}{semver.info.version.minor}.${'$'}{semver.info.version.patch}-BUILD.${'$'}{semver.info.count}.sha.${'$'}{semver.info.shortCommit}" } 940 | } 941 | } 942 | } 943 | """) 944 | val git = initializeGitWithBranch(testProjectDirectory, "5.2.1", "hotfix/5.3.1") 945 | val commit = git.commit().setMessage("").call() 946 | val result = gradleRunner 947 | .withProjectDir(testProjectDirectory) 948 | .withArguments("showInfo") 949 | .withPluginClasspath() 950 | .build() 951 | println(result.output) 952 | assertTrue(result.output.contains("Branch name: hotfix/5.3.1")) 953 | assertTrue(result.output.contains("Branch group: hotfix")) 954 | assertTrue(result.output.contains("Branch id: hotfix-5.3.1")) 955 | assertTrue(result.output.contains("Commit: " + commit.id.name())) 956 | assertTrue(result.output.contains("Short commit: " + commit.id.abbreviate( 7 ).name())) 957 | assertTrue(result.output.contains("Tag: none")) 958 | assertTrue(result.output.contains("Last tag: 5.2.1-1-g" + commit.id.abbreviate( 7 ).name())) 959 | assertTrue(result.output.contains("Dirty: false")) 960 | assertTrue(result.output.contains("Version: 5.2.2-HOTFIX.2.sha." + commit.id.abbreviate( 7 ).name() + "-SNAPSHOT")) 961 | assertTrue(result.output.contains("Version major: 5")) 962 | assertTrue(result.output.contains("Version minor: 2")) 963 | assertTrue(result.output.contains("Version patch: 2")) 964 | assertTrue(result.output.contains("Version pre release: none")) 965 | assertTrue(result.output.contains("Version build: none")) 966 | } 967 | 968 | @Test 969 | fun `issues-35 fix branch regex`() { 970 | val testProjectDirectory = createTempDir() 971 | val buildFile = File(testProjectDirectory, "build.gradle") 972 | buildFile.writeText(""" 973 | plugins { 974 | id 'io.wusa.semver-git-plugin' 975 | } 976 | 977 | semver { 978 | snapshotSuffix = "SNAPSHOT" 979 | dirtyMarker = "dirty" 980 | branches { 981 | branch { 982 | regex = "feature.+" 983 | incrementer = "PATCH_INCREMENTER" 984 | formatter = { "${'$'}{semver.info.version.major}.${'$'}{semver.info.version.minor}.${'$'}{semver.info.version.patch}-DEV.${'$'}{semver.info.count}.sha.${'$'}{semver.info.shortCommit}" } 985 | } 986 | } 987 | } 988 | """) 989 | val git = initializeGitWithBranch(testProjectDirectory, "5.2.1", "feature/bellini/test-branch-version") 990 | val commit = git.commit().setMessage("").call() 991 | val result = gradleRunner 992 | .withProjectDir(testProjectDirectory) 993 | .withArguments("showInfo") 994 | .withPluginClasspath() 995 | .build() 996 | println(result.output) 997 | assertTrue(result.output.contains("Branch name: feature/bellini/test-branch-version")) 998 | assertTrue(result.output.contains("Branch group: feature")) 999 | assertTrue(result.output.contains("Branch id: feature-bellini-test-branch-version")) 1000 | assertTrue(result.output.contains("Commit: " + commit.id.name())) 1001 | assertTrue(result.output.contains("Short commit: " + commit.id.abbreviate( 7 ).name())) 1002 | assertTrue(result.output.contains("Tag: none")) 1003 | assertTrue(result.output.contains("Last tag: 5.2.1-1-g" + commit.id.abbreviate( 7 ).name())) 1004 | assertTrue(result.output.contains("Dirty: false")) 1005 | assertTrue(result.output.contains("Version: 5.2.2-DEV.2.sha." + commit.id.abbreviate( 7 ).name() + "-SNAPSHOT")) 1006 | assertTrue(result.output.contains("Version major: 5")) 1007 | assertTrue(result.output.contains("Version minor: 2")) 1008 | assertTrue(result.output.contains("Version patch: 2")) 1009 | assertTrue(result.output.contains("Version pre release: none")) 1010 | assertTrue(result.output.contains("Version build: none")) 1011 | } 1012 | 1013 | @Test 1014 | fun `empty snapshotSuffix must not append a hyphen`() { 1015 | val testProjectDirectory = createTempDir() 1016 | val buildFile = File(testProjectDirectory, "build.gradle") 1017 | buildFile.writeText(""" 1018 | plugins { 1019 | id 'io.wusa.semver-git-plugin' 1020 | } 1021 | 1022 | semver { 1023 | snapshotSuffix = '' 1024 | branches { 1025 | branch { 1026 | regex = ".*" 1027 | incrementer = "MINOR_INCREMENTER" 1028 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}" } 1029 | } 1030 | } 1031 | } 1032 | """) 1033 | val git = initializeGitWithBranch(testProjectDirectory, "4.2.0") 1034 | git.commit().setMessage("").call() 1035 | val result = gradleRunner 1036 | .withProjectDir(testProjectDirectory) 1037 | .withArguments("showVersion") 1038 | .withPluginClasspath() 1039 | .build() 1040 | println(result.output) 1041 | assertTrue(result.output.contains("Version: 4.3.0")) 1042 | assertFalse(result.output.contains("Version: 4.3.0-")) 1043 | } 1044 | 1045 | @Test 1046 | fun `empty dirty marker must not append a hyphen`() { 1047 | val testProjectDirectory = createTempDir() 1048 | val buildFile = File(testProjectDirectory, "build.gradle") 1049 | buildFile.writeText(""" 1050 | plugins { 1051 | id 'io.wusa.semver-git-plugin' 1052 | } 1053 | 1054 | semver { 1055 | snapshotSuffix = '' 1056 | dirtyMarker = '' 1057 | branches { 1058 | branch { 1059 | regex = ".*" 1060 | incrementer = "NO_VERSION_INCREMENTER" 1061 | formatter = { "${'$'}{it.version.major}.${'$'}{it.version.minor}.${'$'}{it.version.patch}" } 1062 | } 1063 | } 1064 | } 1065 | """) 1066 | val git = initializeGitWithoutBranchAndWithoutTag(testProjectDirectory) 1067 | git.commit().setMessage("").call() 1068 | val dirtyFile = File(testProjectDirectory, "test.dirty") 1069 | dirtyFile.writeText("""not dirty!""") 1070 | git.add().addFilepattern(".").call() 1071 | git.commit().setMessage("").call() 1072 | dirtyFile.writeText("""dirty!""") 1073 | val result = gradleRunner 1074 | .withProjectDir(testProjectDirectory) 1075 | .withArguments("showInfo") 1076 | .withPluginClasspath() 1077 | .build() 1078 | println(result.output) 1079 | assertTrue(result.output.contains("Dirty: true")) 1080 | assertTrue(result.output.contains("Version: 0.1.0")) 1081 | assertFalse(result.output.contains("Version: 0.1.0-")) 1082 | } 1083 | } 1084 | --------------------------------------------------------------------------------