├── .github └── FUNDING.yml ├── .gitignore ├── DEVELOPMENT.md ├── LICENSE.txt ├── README.md ├── build.gradle ├── gitversioner ├── build.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── pascalwelsch │ │ │ └── gitversioner │ │ │ ├── GenerateGitVersionName.kt │ │ │ ├── GitVersioner.kt │ │ │ ├── GitVersionerPlugin.kt │ │ │ └── ShellGitInfoExtractor.kt │ └── resources │ │ └── META-INF │ │ └── gradle-plugins │ │ └── com.pascalwelsch.gitversioner.properties │ └── test │ └── java │ └── com │ └── pascalwelsch │ └── gitversioner │ ├── FeatureBranchTest.kt │ ├── GitVersionerTest.kt │ ├── LocalChangesTest.kt │ ├── MockGitRepo.kt │ ├── PrefixedBranchTest.kt │ └── ShallowCloneTest.kt ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [passsy] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/ 2 | .idea/ 3 | build/ 4 | local.properties 5 | -------------------------------------------------------------------------------- /DEVELOPMENT.md: -------------------------------------------------------------------------------- 1 | # Development 2 | 3 | ## Testing the gradle plugin in a real project 4 | 5 | 1. Add jar dependency to real project 6 | 7 | `build.gradle` 8 | ```gradle 9 | buildscript { 10 | dependencies { 11 | classpath(files("/path/to/gradle-gitVersioner-plugin/gitversioner/build/libs/gitversioner-0.4.3.jar")) 12 | } 13 | } 14 | ``` 15 | 16 | 2. build the plugin 17 | ```bash 18 | ./gradlew clean build 19 | ``` 20 | 21 | 3. build the real project 22 | 23 | ```bash 24 | ./gradlew clean gitVersion 25 | ``` 26 | 27 | ## Publish artifacts 28 | 29 | Add bintray keys to `~/.gradle/gradle.properties` 30 | ```properties 31 | bintrayUser=passsy 32 | bintrayKey=cba6a4869abc49b6ca4... 33 | ``` 34 | 35 | Publish 36 | ```bash 37 | ./gradlew clean build bintrayUpload -PdryRun=false 38 | ``` -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2017 Pascal Welsch 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Git Versioner for gradle 2 | 3 | Version numbers are hard. 4 | It was easier with SVN where the revision number got increased for every commit. 5 | Revision `342` was clearly older than revision `401`. 6 | This is not possible in git because branching is so common (and that's a good thing). 7 | `342` commits could mean multiple commits on different branches. 8 | Not even the latest common commit in history is clear. 9 | This projects aims to bring the SVN simplicity and more back to git for your gradle (android) project. 10 | 11 | ## Example 12 | 13 | On `master` branch with `1850` commits and roughly half a year of development (`526` timecomponent) 14 | ``` 15 | versionName 2376 16 | versionCode 2376 17 | ``` 18 | 19 | On your feature branch `feature/upgrade_gradle_4.4.1` with `3` additional commits/ 20 | `versionCode` stays the same and only reflects the base version on the baseBranch (`master`). 21 | ``` 22 | versionName 2376-upgrade_gradle_4.4.1+3 23 | versionCode 2376 24 | ``` 25 | 26 | While working on your features when you have uncommitted changes `files changed: 1, additions(+): 2, deletions(-): 0`. 27 | ``` 28 | versionName 2376-upgrade_gradle_4.4.1+3-SNAPSHOT(1 +2 -0) 29 | versionCode 2376 30 | ``` 31 | 32 | ## Install 33 | 34 | ```gradle 35 | // Top-level build.gradle 36 | buildscript { 37 | dependencies { 38 | classpath 'com.pascalwelsch.gitversioner:gitversioner:0.4.1' 39 | } 40 | } 41 | 42 | // https://github.com/passsy/gradle-gitVersioner-plugin 43 | apply plugin: 'com.pascalwelsch.gitversioner' 44 | gitVersioner { 45 | baseBranch 'develop' 46 | } 47 | ``` 48 | 49 | ## Usage Android 50 | 51 | ```gradle 52 | // app module build.gradle 53 | 54 | android { 55 | 56 | defaultConfig { 57 | versionCode gitVersioner.versionCode 58 | versionName gitVersioner.versionName 59 | } 60 | } 61 | ``` 62 | 63 | ## Additional gitVersioner properties 64 | 65 | Here are the default properties, you can change them. See [here](https://github.com/passsy/gradle-gitVersioner-plugin/blob/master/gitversioner/src/main/kotlin/com/pascalwelsch/gitversioner/GitVersioner.kt) for more details 66 | 67 | ```gradle 68 | gitVersioner { 69 | baseBranch 'master' 70 | yearFactor 1000 // increasing every 8.57h 71 | 72 | // Default formatter properties 73 | addSnapshot true // the "-SNAPSHOT" postfix 74 | addLocalChangesDetails true 75 | 76 | // provide a custom formatter 77 | formatter = { gitVersioner -> 78 | return "${gitVersioner.versionCode} custom generated id" 79 | } 80 | } 81 | 82 | ``` 83 | 84 | ## Gradle Tasks 85 | 86 | ### Show version output info 87 | ``` 88 | > ./gradlew gitVersion 89 | 90 | GitVersioner Plugin 91 | ------------------- 92 | VersionCode: 2118 93 | VersionName: 2118-SNAPSHOT(1 +9 -8) 94 | 95 | baseBranch: develop 96 | current branch: develop 97 | current commit: 1dd547a 98 | 99 | baseBranch commits: 1653 (423e113..1dd547a) 100 | featureBranch commits: 0 (1dd547a..1dd547a) 101 | 102 | timeComponent: 465 (yearFactor:1000) 103 | 104 | LocalChanges: files changed: 1, additions(+): 9, deletions(-): 8 105 | ``` 106 | 107 | ### write gitVersion information properties file (machine readable) 108 | 109 | ``` 110 | > ./gradlew generateGitVersionName 111 | git versionName: 2118-SNAPSHOT(1 +9 -8) 112 | gitVersion output: build/gitversion/gitversion.properties 113 | ``` 114 | 115 | `gitversion.properties` 116 | ``` 117 | #gitVersioner plugin - extracted data from git repository 118 | #Sun Jan 14 22:08:34 CET 2018 119 | localChanges=1 +9 -8 120 | timeComponent=465 121 | versionName=2118-SNAPSHOT(1 +9 -8) 122 | versionCode=2118 123 | featureBranchCommitCount=0 124 | baseBranchCommitCount=1653 125 | baseBranch=develop 126 | branchName=develop 127 | yearFactor=1000 128 | currentSha1=1dd547a910b1a1da64fd65ec4b4294030511be4b 129 | ``` 130 | 131 | 132 | # License 133 | 134 | ``` 135 | Copyright 2017 Pascal Welsch 136 | 137 | Licensed under the Apache License, Version 2.0 (the "License"); 138 | you may not use this file except in compliance with the License. 139 | You may obtain a copy of the License at 140 | 141 | http://www.apache.org/licenses/LICENSE-2.0 142 | 143 | Unless required by applicable law or agreed to in writing, software 144 | distributed under the License is distributed on an "AS IS" BASIS, 145 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 146 | See the License for the specific language governing permissions and 147 | limitations under the License. 148 | ``` 149 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/passsy/gradle-gitVersioner-plugin/fddb722e024ccaad2edf3b5bbbe0a22d43caa234/build.gradle -------------------------------------------------------------------------------- /gitversioner/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | 4 | dependencies { 5 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 6 | classpath "guru.stefma.androidartifacts:androidartifacts:1.4.0" 7 | classpath "guru.stefma.bintrayrelease:bintrayrelease:1.1.2" 8 | } 9 | repositories { 10 | google() 11 | jcenter() 12 | mavenCentral() 13 | } 14 | } 15 | 16 | apply plugin: 'kotlin' 17 | apply plugin: "guru.stefma.artifacts" 18 | 19 | group = 'com.pascalwelsch.gitversioner' 20 | version = '0.5.0' 21 | 22 | dependencies { 23 | compile gradleApi() 24 | compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" 25 | 26 | testCompile 'junit:junit:4.12' 27 | testCompile 'org.assertj:assertj-core:3.12.0' 28 | testCompile 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.0.0' 29 | } 30 | repositories { 31 | jcenter() 32 | } 33 | 34 | javaArtifact { 35 | artifactId = 'gitversioner' 36 | name = "Gitversioner gradle plugin" 37 | url = 'https://github.com/passsy/gradle-gitVersioner-plugin' 38 | license { 39 | name = "Apache License, Version 2.0" 40 | url = "https://www.apache.org/licenses/LICENSE-2.0.txt" 41 | } 42 | pom { 43 | developers { 44 | developer { 45 | id = "passsy" 46 | name = "Pascal Welsch" 47 | url = 'https://github.com/passsy' 48 | } 49 | } 50 | } 51 | } 52 | 53 | // ./gradlew bintrayUpload 54 | apply plugin: "guru.stefma.bintrayrelease" 55 | publish { 56 | userOrg = 'passsy' 57 | desc = "Extracts a useful versionCode and versionName from git history" 58 | website = 'https://github.com/passsy/gradle-gitVersioner-plugin' 59 | } 60 | 61 | 62 | task saveVersionToResources(type: WriteProperties) { 63 | comment = "gitversioner gradle plugin version" 64 | property('version', version) 65 | outputFile = file(sourceSets.main.output.resourcesDir.absolutePath + "/version.properties") 66 | } 67 | processResources.dependsOn(saveVersionToResources) -------------------------------------------------------------------------------- /gitversioner/src/main/java/com/pascalwelsch/gitversioner/GenerateGitVersionName.kt: -------------------------------------------------------------------------------- 1 | package com.pascalwelsch.gitversioner 2 | 3 | import org.gradle.api.DefaultTask 4 | import org.gradle.api.tasks.TaskAction 5 | import java.util.Properties 6 | 7 | internal open class GenerateGitVersionName : DefaultTask() { 8 | 9 | internal lateinit var gitVersioner: GitVersioner 10 | 11 | @TaskAction 12 | fun generate() { 13 | val path = "${project.buildDir}/gitversion/gitversion.properties" 14 | val file = project.file("${project.buildDir}/gitversion/version.properties") 15 | file.parentFile.mkdirs() 16 | 17 | val properties = Properties().apply { 18 | with(gitVersioner) { 19 | putWhenSet("versionCode", versionCode) 20 | putWhenSet("versionName", versionName) 21 | putWhenSet("baseBranch", baseBranch) 22 | putWhenSet("branchName", branchName) 23 | putWhenSet("currentSha1", currentSha1) 24 | putWhenSet("baseBranchCommitCount", baseBranchCommitCount) 25 | putWhenSet("featureBranchCommitCount", featureBranchCommitCount) 26 | putWhenSet("timeComponent", timeComponent) 27 | putWhenSet("yearFactor", yearFactor) 28 | putWhenSet("localChanges", localChanges) 29 | } 30 | } 31 | 32 | properties.store(file.writer(), "gitVersioner plugin - extracted data from git repository") 33 | project.logger.lifecycle("git versionName: ${gitVersioner.versionName}") 34 | project.logger.lifecycle("gitVersion output: $path") 35 | } 36 | } 37 | 38 | private fun Properties.putWhenSet(key: String, value: Any?) { 39 | if (value == null) return 40 | put(key, value.toString()) 41 | } -------------------------------------------------------------------------------- /gitversioner/src/main/java/com/pascalwelsch/gitversioner/GitVersioner.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("RedundantVisibilityModifier") 2 | 3 | package com.pascalwelsch.gitversioner 4 | 5 | import org.gradle.api.logging.Logger 6 | import java.util.concurrent.TimeUnit 7 | 8 | private val YEAR_IN_SECONDS = TimeUnit.DAYS.toSeconds(365) 9 | 10 | public val NO_CHANGES = LocalChanges(0, 0, 0) 11 | 12 | public open class GitVersioner internal constructor( 13 | private val gitInfoExtractor: GitInfoExtractor, 14 | private val logger: Logger? = null 15 | ) { 16 | 17 | public var baseBranch: String = "master" 18 | 19 | public var yearFactor: Int = 1000 20 | 21 | public var addSnapshot: Boolean = true 22 | 23 | public var addLocalChangesDetails: Boolean = true 24 | 25 | public var formatter: ((GitVersioner) -> CharSequence) = DEFAULT_FORMATTER 26 | 27 | public var shortNameFormatter: ((GitVersioner) -> CharSequence) = DEFAULT_SHORT_NAME_FORMATTER 28 | 29 | public var ciBranchNameProvider: () -> CharSequence? = { 30 | // get branch name on jenkins 31 | System.getenv("BRANCH") ?: System.getenv("BRANCH_NAME") ?: System.getenv("GITREF") 32 | } 33 | 34 | //TODO add offset 35 | /** 36 | * base branch commit count + [timeComponent] 37 | */ 38 | @Deprecated("converted to property", replaceWith = ReplaceWith("versionCode")) 39 | public fun versionCode(): Int { 40 | logger?.warn( 41 | "The GitVersioner.versionCode() method has been deprecated, " + 42 | "use the property GitVersioner.versionCode instead" 43 | ) 44 | return versionCode 45 | } 46 | 47 | /** 48 | * base branch commit count + [timeComponent] 49 | */ 50 | public val versionCode: Int by lazy { 51 | try { 52 | requireWorkingGit() 53 | requireWorkingHistory() 54 | val commitComponent = baseBranchCommits.size 55 | val code = commitComponent + timeComponent 56 | logger?.debug("git versionCode: $code") 57 | return@lazy code 58 | } catch (e: Throwable) { 59 | // fallback 60 | // must be a positive number for android projects 61 | return@lazy 1 62 | } 63 | } 64 | 65 | /** 66 | * string representation powered by [formatter] 67 | */ 68 | @Deprecated("converted to property", replaceWith = ReplaceWith("versionName")) 69 | public fun versionName(): String { 70 | logger?.warn( 71 | "The GitVersioner.versionName() method has been deprecated, " + 72 | "use the property GitVersioner.versionName instead" 73 | ) 74 | return versionName 75 | } 76 | 77 | /** 78 | * string representation powered by [formatter] 79 | */ 80 | public val versionName: String by lazy { 81 | try { 82 | requireWorkingGit() 83 | val name = try { 84 | formatter(this).toString() 85 | } catch (e: Throwable) { 86 | logger?.info("formatter failed to generate a correct name, using default formatter") 87 | DEFAULT_FORMATTER(this).toString() 88 | } 89 | logger?.debug("git versionName: $name") 90 | return@lazy name 91 | } catch (e: Throwable) { 92 | // fallback 93 | // Can't be null for android projects 94 | return@lazy "undefined" 95 | } 96 | } 97 | 98 | /** 99 | * the current local changes (files changed, additions, deletions). [NO_CHANGES] when no changes detected 100 | */ 101 | public val localChanges: LocalChanges by lazy { 102 | try { 103 | requireWorkingGit() 104 | return@lazy gitInfoExtractor.localChanges 105 | } catch (e: Throwable) { 106 | return@lazy NO_CHANGES 107 | } 108 | } 109 | 110 | /** 111 | * the name of the branch HEAD is currently on 112 | */ 113 | public val branchName: String? 114 | get() { 115 | return try { 116 | gitInfoExtractor.currentBranch ?: ciBranchNameProvider()?.toString() 117 | } catch (e: Throwable) { 118 | null 119 | } 120 | } 121 | 122 | /** 123 | * all commits in [baseBranch] without the [featureBranchCommits] 124 | */ 125 | public val baseBranchCommitCount: Int by lazy { 126 | try { 127 | requireWorkingGit() 128 | requireWorkingHistory() 129 | return@lazy baseBranchCommits.count() 130 | } catch (e: Throwable) { 131 | return@lazy 0 132 | } 133 | } 134 | 135 | /** 136 | * commits on feature branch not in [baseBranch] 137 | */ 138 | public val featureBranchCommitCount: Int by lazy { 139 | try { 140 | requireWorkingGit() 141 | requireWorkingHistory() 142 | return@lazy featureBranchCommits.count() 143 | } catch (e: Throwable) { 144 | return@lazy 0 145 | } 146 | } 147 | 148 | /** 149 | * all commits together, from initial commit to HEAD 150 | */ 151 | public val commitCount: Int by lazy { baseBranchCommitCount + featureBranchCommitCount } 152 | 153 | /** 154 | * full sha1 of current commit 155 | * 156 | * @see [currentSha1Short] 157 | */ 158 | public val currentSha1: String? by lazy { 159 | try { 160 | requireWorkingGit() 161 | return@lazy gitInfoExtractor.currentSha1 162 | } catch (e: Throwable) { 163 | return@lazy null 164 | } 165 | } 166 | 167 | /** 168 | * 7 char sha1 of current commit 169 | */ 170 | public val currentSha1Short: String? by lazy { currentSha1?.take(7) } 171 | 172 | /** 173 | * [yearFactor] based time component from initial commit to [featureBranchOriginCommit] 174 | */ 175 | public val timeComponent: Int by lazy { 176 | try { 177 | requireWorkingGit() 178 | requireWorkingHistory() 179 | val latestBaseCommit = featureBranchOriginCommit ?: return@lazy 0 180 | 181 | val timeToHead = gitInfoExtractor.commitDate(latestBaseCommit) - gitInfoExtractor.initialCommitDate 182 | return@lazy (timeToHead * yearFactor / YEAR_IN_SECONDS + 0.5).toInt() 183 | } catch (e: Throwable) { 184 | // fallback 185 | return@lazy 0 186 | } 187 | } 188 | 189 | /** 190 | * last commit in base branch which is parent of HEAD, most likely where the 191 | * feature branch was created or the last base branch commit which was merged 192 | * into the feature branch 193 | */ 194 | public val featureBranchOriginCommit: String? by lazy { baseBranchCommits.firstOrNull() } 195 | 196 | /** 197 | * sha1 of the initial commit of the git tree, first commit 198 | */ 199 | public val initialCommit: String? by lazy { 200 | try { 201 | requireWorkingGit() 202 | requireWorkingHistory() 203 | gitInfoExtractor.commitsToHead.lastOrNull() 204 | } catch (e: Throwable) { 205 | return@lazy null 206 | } 207 | } 208 | 209 | /** 210 | * whether git can be used to extract data 211 | */ 212 | public val isGitProjectCorrectlyInitialized: Boolean = gitInfoExtractor.isGitWorking 213 | 214 | @Suppress("unused") 215 | @Deprecated(message = "renamed", replaceWith = ReplaceWith("isGitProjectCorrectlyInitialized")) 216 | public val isGitInitialized 217 | get() = isGitProjectCorrectlyInitialized 218 | 219 | public val isHistoryShallowed: Boolean = gitInfoExtractor.isHistoryShallowed 220 | 221 | /** 222 | * commits of base branch in history of current commit (HEAD). 223 | */ 224 | private val baseBranchCommits: List by lazy { 225 | try { 226 | val baseCommits = gitInfoExtractor.commitsUpTo(baseBranch) 227 | val headCommits = gitInfoExtractor.commitsToHead 228 | 229 | return@lazy baseCommits.filter { it in headCommits } 230 | } catch (e: Throwable) { 231 | return@lazy emptyList() 232 | } 233 | } 234 | 235 | /** 236 | * commits on the feature branch not merged into [baseBranch] 237 | */ 238 | private val featureBranchCommits: List by lazy { 239 | try { 240 | return@lazy gitInfoExtractor.commitsToHead.filter { !baseBranchCommits.contains(it) } 241 | } catch (e: Throwable) { 242 | return@lazy emptyList() 243 | } 244 | } 245 | 246 | @Suppress("NOTHING_TO_INLINE") 247 | private inline fun requireWorkingGit() { 248 | if (!gitInfoExtractor.isGitWorking) throw IllegalStateException("Git is not working as expected. See logs for details") 249 | } 250 | 251 | @Suppress("NOTHING_TO_INLINE") 252 | private inline fun requireWorkingHistory() { 253 | if (gitInfoExtractor.isHistoryShallowed) throw IllegalStateException("Shallow clone detected, no history available to execute action") 254 | } 255 | 256 | companion object { 257 | 258 | @JvmStatic 259 | public val DEFAULT_FORMATTER: ((GitVersioner) -> CharSequence) = formatter@{ versioner -> 260 | with(versioner) { 261 | val sb = StringBuilder(if (isHistoryShallowed) "shallowed" else versioner.versionCode.toString()) 262 | val hasCommits = featureBranchCommitCount > 0 || baseBranchCommitCount > 0 263 | if (baseBranch != branchName && (hasCommits || isHistoryShallowed)) { 264 | // add branch identifier for 265 | val shortName = try { 266 | shortNameFormatter(versioner) 267 | } catch (e: Throwable) { 268 | println("shortNameFormatter failed to generate a correct name, using default formatter") 269 | DEFAULT_SHORT_NAME_FORMATTER(versioner).toString() 270 | } 271 | 272 | sb.append("-").append(shortName) 273 | } 274 | 275 | val featureCount = featureBranchCommits.count() 276 | if (featureCount > 0 && !isHistoryShallowed) { 277 | sb.append("+").append(featureCount) 278 | } 279 | if (localChanges != NO_CHANGES) { 280 | if (addSnapshot) { 281 | sb.append("-SNAPSHOT") 282 | } 283 | if (addLocalChangesDetails) { 284 | sb.append("(").append(localChanges).append(")") 285 | } 286 | } 287 | return@formatter sb.toString() 288 | } 289 | } 290 | 291 | @JvmStatic 292 | public val DEFAULT_SHORT_NAME_FORMATTER: ((GitVersioner) -> CharSequence) = formatter@{ versioner -> 293 | var name: String? = null 294 | if (name == null) { 295 | // use branch name from git 296 | val branchName = versioner.branchName 297 | if (branchName != null && branchName.isNotEmpty()) { 298 | name = branchName 299 | } 300 | } 301 | if (name == null) { 302 | // nothing found fallback to sha1 303 | name = versioner.currentSha1Short 304 | } 305 | if (name == null) { 306 | // fallback, i.e. when git not initialized 307 | name = "undefined" 308 | } 309 | 310 | // remove "feature/" and "bugfix/" prefixes (only the first one) 311 | var clean = Regex("[^\\/]*\\/(.*)").matchEntire(name)?.groups?.get(1)?.value 312 | if (clean.isNullOrBlank()) { 313 | clean = name 314 | } 315 | 316 | // remove all special characters 317 | clean = clean.replace(Regex("[^\\w_\\-]+"), "_") 318 | .replace("__", "_") 319 | .trim('_') 320 | return@formatter clean 321 | } 322 | } 323 | } 324 | 325 | public data class LocalChanges( 326 | val filesChanged: Int = 0, 327 | val additions: Int = 0, 328 | val deletions: Int = 0 329 | ) { 330 | 331 | override fun toString(): String { 332 | return "$filesChanged +$additions -$deletions" 333 | } 334 | 335 | fun shortStats(): String = if (filesChanged + additions + deletions == 0) { 336 | "no changes" 337 | } else { 338 | "files changed: $filesChanged, additions(+): $additions, deletions(-): $deletions" 339 | } 340 | } 341 | -------------------------------------------------------------------------------- /gitversioner/src/main/java/com/pascalwelsch/gitversioner/GitVersionerPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.pascalwelsch.gitversioner 2 | 3 | import org.gradle.api.Plugin 4 | import org.gradle.api.Project 5 | import java.util.Properties 6 | 7 | @Suppress("RedundantVisibilityModifier") 8 | public class GitVersionerPlugin : Plugin { 9 | 10 | override fun apply(project: Project) { 11 | val rootProject = project.rootProject 12 | if (project != rootProject) { 13 | throw IllegalStateException( 14 | "Register the 'com.pascalwelsch.gitversioner' plugin only once " + 15 | "in the root project build.gradle." 16 | ) 17 | } 18 | 19 | // add extension to root project, makes sense only once per project 20 | val gitVersionExtractor = ShellGitInfoExtractor(rootProject) 21 | val gitVersioner = rootProject.extensions.create( 22 | "gitVersioner", 23 | GitVersioner::class.java, gitVersionExtractor, project.logger 24 | ) 25 | 26 | project.task("gitVersion").apply { 27 | group = "Help" 28 | description = "Displays the version information extracted from git history" 29 | doLast { 30 | with(gitVersioner) { 31 | 32 | if (!gitVersioner.isGitProjectCorrectlyInitialized) { 33 | 34 | val why = if (gitVersioner.isHistoryShallowed) { 35 | "WARNING: Git history is incomplete (shallow clone)\n" + 36 | "The com.pascalwelsch.gitversioner gradle plugin requires the complete git history to calculate " + 37 | "the version. The history is shallowed, therefore the version code would be incorrect.\n" + 38 | "Default values versionName: 'undefined', versionCode: 1 are used instead.\n\n" + 39 | "Please fetch the complete history with:\n" + 40 | "\tgit fetch --unshallow" 41 | } else { 42 | "WARNING: git not initialized. Run:\n" + 43 | "\tgit init" 44 | } 45 | 46 | println( 47 | """ 48 | | 49 | |GitVersioner Plugin v$pluginVersion 50 | |------------------- 51 | |VersionCode: $versionCode 52 | |VersionName: $versionName 53 | | 54 | |baseBranch: $baseBranch 55 | | 56 | |$why 57 | """.replaceIndentByMargin() 58 | ) 59 | return@doLast 60 | } 61 | 62 | val baseBranchRange = (initialCommit?.take(7) ?: "") + 63 | "..${featureBranchOriginCommit?.take(7) ?: ""}" 64 | 65 | val featureBranchRange = (featureBranchOriginCommit?.take(7) ?: "") + 66 | "..${currentSha1Short ?: ""}" 67 | 68 | println( 69 | """ 70 | | 71 | |GitVersioner Plugin v$pluginVersion 72 | |------------------- 73 | |VersionCode: $versionCode 74 | |VersionName: $versionName 75 | | 76 | |baseBranch: $baseBranch 77 | |current branch: $branchName 78 | |current commit: $currentSha1Short 79 | | 80 | |baseBranch commits: $baseBranchCommitCount ($baseBranchRange) 81 | |featureBranch commits: $featureBranchCommitCount ($featureBranchRange) 82 | | 83 | |timeComponent: $timeComponent (yearFactor:$yearFactor) 84 | | 85 | |LocalChanges: ${localChanges.shortStats()} 86 | """.replaceIndentByMargin() 87 | ) 88 | } 89 | } 90 | } 91 | 92 | 93 | project.tasks.create("generateGitVersionName", GenerateGitVersionName::class.java).apply { 94 | this.gitVersioner = gitVersioner 95 | 96 | group = "Build" 97 | description = 98 | "analyzes the git history and creates a version name (generates machine readable output file)" 99 | } 100 | } 101 | 102 | val pluginVersion: String by lazy { 103 | val props = Properties() 104 | props.load(GitVersionerPlugin::class.java.getResourceAsStream("/version.properties")) 105 | props.getProperty("version") 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /gitversioner/src/main/java/com/pascalwelsch/gitversioner/ShellGitInfoExtractor.kt: -------------------------------------------------------------------------------- 1 | package com.pascalwelsch.gitversioner 2 | 3 | import org.gradle.api.GradleException 4 | import org.gradle.api.Project 5 | import java.io.ByteArrayOutputStream 6 | import java.io.File 7 | 8 | interface GitInfoExtractor { 9 | val currentSha1: String? 10 | val currentBranch: String? 11 | val localChanges: LocalChanges 12 | val initialCommitDate: Long 13 | val commitsToHead: List 14 | val isGitWorking: Boolean 15 | val isHistoryShallowed: Boolean 16 | fun commitDate(rev: String): Long 17 | fun commitsUpTo(rev: String, args: String = ""): List 18 | } 19 | 20 | /** 21 | * Executes shell commands to get information from git 22 | */ 23 | internal class ShellGitInfoExtractor(private val project: Project) : GitInfoExtractor { 24 | 25 | override val currentSha1: String? by lazy { 26 | val sha1 = "git rev-parse HEAD".execute().throwOnError().text.trim() 27 | if (sha1.isEmpty()) null else sha1 28 | } 29 | 30 | override val currentBranch: String? by lazy { 31 | when (val result = "git symbolic-ref --short -q HEAD".execute()) { 32 | is ProcessResult.Success -> { 33 | val branch = result.text.trim() 34 | if (branch.isEmpty()) null else branch 35 | } 36 | is ProcessResult.Error -> null 37 | } 38 | } 39 | 40 | override val localChanges: LocalChanges by lazy { 41 | val shortStat = "git diff HEAD --shortstat".execute().throwOnError().text.trim() 42 | if (shortStat.isEmpty()) return@lazy NO_CHANGES 43 | 44 | return@lazy parseShortStats(shortStat) 45 | } 46 | 47 | override val initialCommitDate: Long by lazy { 48 | val initialCommit: String = commitsToHead.lastOrNull() ?: return@lazy 0L 49 | val time = listOf("git", "log", "-n 1", "--pretty=format:'%at'", initialCommit).execute() 50 | .throwOnError().text.replace("\'", "").trim() 51 | 52 | return@lazy if (time.isEmpty()) 0L else time.toLong() 53 | } 54 | 55 | override fun commitDate(rev: String): Long { 56 | val time = listOf("git", "log", "--pretty=format:'%at'", "-n 1", rev).execute() 57 | .throwOnError().text.replace("\'", "").trim() 58 | return if (time.isEmpty()) 0 else time.toLong() 59 | } 60 | 61 | override val commitsToHead: List by lazy { commitsUpTo("HEAD") } 62 | 63 | override val isGitWorking: Boolean by lazy { 64 | val result = "git status".execute() 65 | if (result is ProcessResult.Error) { 66 | when (val exitCode = result.errorCode) { 67 | 69 -> { 68 | println( 69 | "git returned with error 69\n" + 70 | "If you are a mac user that message is telling you is that you need to open the " + 71 | "application XCode on your Mac OS X/macOS and since it hasn’t run since the last " + 72 | "update, you need to accept the new license EULA agreement that’s part of the " + 73 | "updated XCode.\n\n" + 74 | "tl;dr run\n" + 75 | "\txcode-select --install" 76 | ) 77 | return@lazy false 78 | } 79 | else -> { 80 | println("ERROR: can't generate a git version, this is not a git project. git status errors with error code: $exitCode") 81 | println(" -> Not a git repository (or any of the parent directories): .git") 82 | return@lazy false 83 | } 84 | } 85 | } 86 | 87 | return@lazy true 88 | } 89 | 90 | override val isHistoryShallowed: Boolean by lazy { 91 | // returns root dir of git 92 | val rootPath = "git rev-parse --show-toplevel".execute().throwOnError().text.trim() 93 | val shallowFile = File("$rootPath/.git/shallow") 94 | 95 | if (shallowFile.exists()) { 96 | println( 97 | "WARNING: Git history is incomplete\n" + 98 | "The gradle git version plugin requires the complete git history to calculate " + 99 | "the version. The history is shallowed, therefore the version code would be incorrect.\n" + 100 | "Please fetch the complete history with:\n" + 101 | "\tgit fetch --unshallow" 102 | ) 103 | return@lazy true 104 | } 105 | 106 | return@lazy false 107 | } 108 | 109 | override fun commitsUpTo(rev: String, args: String): List { 110 | val text = try { 111 | "git rev-list $rev $args".execute().throwOnError().text 112 | } catch (e: Exception) { 113 | try { 114 | "git rev-list origin/$rev $args".execute().throwOnError().text 115 | } catch (e: Exception) { 116 | "" 117 | } 118 | } 119 | 120 | return text.lines().asSequence().map { it.trim() }.filter { it.isNotBlank() }.toList() 121 | } 122 | 123 | private fun String.execute(): ProcessResult = trim().split(" ").execute() 124 | 125 | private fun List.execute(): ProcessResult { 126 | val out = ByteArrayOutputStream() 127 | val err = ByteArrayOutputStream() 128 | val task = project.exec { 129 | it.commandLine = this@execute 130 | it.standardOutput = out 131 | it.errorOutput = err 132 | it.workingDir = project.projectDir 133 | it.isIgnoreExitValue = true 134 | } 135 | val exitCode = task.exitValue 136 | return if (exitCode == 0) { 137 | ProcessResult.Success(out.toString()) 138 | } else { 139 | ProcessResult.Error(err.toString(), exitCode, this.joinToString(" ")) 140 | } 141 | } 142 | 143 | private sealed class ProcessResult { 144 | class Success(val text: String) : ProcessResult() 145 | class Error(val text: String, val errorCode: Int, val command: String) : ProcessResult() { 146 | fun errorMessage(): String = "Error $errorCode executing `$command`\n\n${text.take(100)}" 147 | } 148 | 149 | fun throwOnError(): Success { 150 | when (this) { 151 | is Success -> return this 152 | is Error -> throw GradleException(this.errorMessage()) 153 | } 154 | } 155 | } 156 | } 157 | 158 | /** 159 | * parses `git diff --shortstat` 160 | * 161 | * https://github.com/git/git/blob/69e6b9b4f4a91ce90f2c38ed2fa89686f8aff44f/diff.c#L1561 162 | */ 163 | internal fun parseShortStats(shortstat: String): LocalChanges { 164 | val parts = shortstat.split(",") 165 | 166 | var filesChanges = 0 167 | var additions = 0 168 | var deletions = 0 169 | 170 | parts.map { it.trim() }.forEach { part -> 171 | if (part.contains("changed")) { 172 | val matches: MatchResult? = "(\\d+).*".toRegex().find(part) 173 | if (matches != null && matches.groups.size >= 2) { 174 | filesChanges = matches.groupValues[1].toInt() 175 | } 176 | } 177 | if (part.contains("(+)")) { 178 | val matches: MatchResult? = "(\\d+).*".toRegex().find(part) 179 | if (matches != null && matches.groups.size >= 2) { 180 | additions = matches.groupValues[1].toInt() 181 | } 182 | } 183 | if (part.contains("(-)")) { 184 | val matches: MatchResult? = "(\\d+).*".toRegex().find(part) 185 | if (matches != null && matches.groups.size >= 2) { 186 | deletions = matches.groupValues[1].toInt() 187 | } 188 | } 189 | } 190 | 191 | return LocalChanges(filesChanges, additions, deletions) 192 | } 193 | -------------------------------------------------------------------------------- /gitversioner/src/main/resources/META-INF/gradle-plugins/com.pascalwelsch.gitversioner.properties: -------------------------------------------------------------------------------- 1 | implementation-class=com.pascalwelsch.gitversioner.GitVersionerPlugin -------------------------------------------------------------------------------- /gitversioner/src/test/java/com/pascalwelsch/gitversioner/FeatureBranchTest.kt: -------------------------------------------------------------------------------- 1 | package com.pascalwelsch.gitversioner 2 | 3 | import org.assertj.core.api.SoftAssertions 4 | import org.junit.* 5 | import org.junit.runner.* 6 | import org.junit.runners.* 7 | 8 | @RunWith(JUnit4::class) 9 | class FeatureBranchTest { 10 | 11 | @Test 12 | fun `on feature branch - few commits - local changes`() { 13 | val graph = listOf( 14 | Commit(sha1 = "X", parent = "j", date = 150_010_000), // <-- feature/bug_123, HEAD 15 | Commit(sha1 = "j", parent = "i", date = 150_009_000), 16 | Commit(sha1 = "i", parent = "h", date = 150_008_000), 17 | Commit(sha1 = "h", parent = "g", date = 150_007_000), 18 | Commit(sha1 = "g", parent = "f", date = 150_006_000), // <-- master 19 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 20 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 21 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 22 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 23 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 24 | Commit(sha1 = "a", parent = null, date = 150_000_000) 25 | ) 26 | 27 | val localChanges = LocalChanges(3, 5, 7) 28 | val git = MockGitRepo(graph, "X", listOf("g" to "master", "X" to "feature/bug_123"), localChanges) 29 | val versioner = GitVersioner(git) 30 | 31 | SoftAssertions.assertSoftly { softly -> 32 | softly.assertThat(versioner.versionCode).isEqualTo(7) 33 | softly.assertThat(versioner.versionName).isEqualTo("7-bug_123+4-SNAPSHOT(3 +5 -7)") 34 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(7) 35 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(4) 36 | softly.assertThat(versioner.branchName).isEqualTo("feature/bug_123") 37 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 38 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 39 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 40 | softly.assertThat(versioner.localChanges).isEqualTo(localChanges) 41 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 42 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 43 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("g") 44 | } 45 | } 46 | 47 | @Test 48 | fun `on feature branch - few commits - local changes - attachDiffToSnapshot false`() { 49 | val graph = listOf( 50 | Commit(sha1 = "X", parent = "j", date = 150_010_000), // <-- feature/bug_123, HEAD 51 | Commit(sha1 = "j", parent = "i", date = 150_009_000), 52 | Commit(sha1 = "i", parent = "h", date = 150_008_000), 53 | Commit(sha1 = "h", parent = "g", date = 150_007_000), 54 | Commit(sha1 = "g", parent = "f", date = 150_006_000), // <-- master 55 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 56 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 57 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 58 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 59 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 60 | Commit(sha1 = "a", parent = null, date = 150_000_000) 61 | ) 62 | 63 | val localChanges = LocalChanges(3, 5, 7) 64 | val git = MockGitRepo(graph, "X", listOf("g" to "master", "X" to "feature/bug_123"), localChanges) 65 | val versioner = GitVersioner(git) 66 | 67 | versioner.addLocalChangesDetails = false 68 | 69 | SoftAssertions.assertSoftly { softly -> 70 | softly.assertThat(versioner.versionCode).isEqualTo(7) 71 | softly.assertThat(versioner.versionName).isEqualTo("7-bug_123+4-SNAPSHOT") 72 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(7) 73 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(4) 74 | softly.assertThat(versioner.branchName).isEqualTo("feature/bug_123") 75 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 76 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 77 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 78 | softly.assertThat(versioner.localChanges).isEqualTo(localChanges) 79 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 80 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 81 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("g") 82 | } 83 | } 84 | 85 | @Test 86 | fun `on feature branch - few commits`() { 87 | val graph = listOf( 88 | Commit(sha1 = "X", parent = "j", date = 150_010_000), // <-- feature/bug_123, HEAD 89 | Commit(sha1 = "j", parent = "i", date = 150_009_000), 90 | Commit(sha1 = "i", parent = "h", date = 150_008_000), 91 | Commit(sha1 = "h", parent = "g", date = 150_007_000), 92 | Commit(sha1 = "g", parent = "f", date = 150_006_000), // <-- master 93 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 94 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 95 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 96 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 97 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 98 | Commit(sha1 = "a", parent = null, date = 150_000_000) 99 | ) 100 | 101 | val git = MockGitRepo(graph, "X", listOf("g" to "master", "X" to "feature/bug_123")) 102 | val versioner = GitVersioner(git) 103 | 104 | SoftAssertions.assertSoftly { softly -> 105 | softly.assertThat(versioner.versionCode).isEqualTo(7) 106 | softly.assertThat(versioner.versionName).isEqualTo("7-bug_123+4") 107 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(7) 108 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(4) 109 | softly.assertThat(versioner.branchName).isEqualTo("feature/bug_123") 110 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 111 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 112 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 113 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 114 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 115 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 116 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("g") 117 | } 118 | } 119 | 120 | @Test 121 | fun `on feature branch - new commits on baseBranch will not increment versioncode`() { 122 | val graph = listOf( 123 | // new commits on master way in the future 124 | Commit(sha1 = "a3", parent = "a2", date = 160_013_000), 125 | Commit(sha1 = "a2", parent = "a1", date = 160_012_000), 126 | Commit(sha1 = "a1", parent = "g", date = 160_011_000), 127 | 128 | Commit(sha1 = "X", parent = "j", date = 150_010_000), // <-- feature/bug_123, HEAD 129 | Commit(sha1 = "j", parent = "i", date = 150_009_000), 130 | Commit(sha1 = "i", parent = "h", date = 150_008_000), 131 | Commit(sha1 = "h", parent = "g", date = 150_007_000), 132 | Commit(sha1 = "g", parent = "f", date = 150_006_000), // <-- base of feature branch 133 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 134 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 135 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 136 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 137 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 138 | Commit(sha1 = "a", parent = null, date = 150_000_000) 139 | ) 140 | 141 | // with new commits on master 142 | val git = MockGitRepo(graph, "X", listOf("a3" to "master", "X" to "feature/bug_123")) 143 | val versioner = GitVersioner(git) 144 | 145 | // without new commits on master 146 | val git2 = MockGitRepo(graph, "X", listOf("g" to "master", "X" to "feature/bug_123")) 147 | val versioner2 = GitVersioner(git2) 148 | 149 | fun assertOutput(v: GitVersioner) { 150 | SoftAssertions.assertSoftly { softly -> 151 | softly.assertThat(v.versionCode).isEqualTo(7) 152 | softly.assertThat(v.versionName).isEqualTo("7-bug_123+4") 153 | softly.assertThat(v.baseBranchCommitCount).isEqualTo(7) 154 | softly.assertThat(v.featureBranchCommitCount).isEqualTo(4) 155 | softly.assertThat(v.branchName).isEqualTo("feature/bug_123") 156 | softly.assertThat(v.currentSha1).isEqualTo("X") 157 | softly.assertThat(v.baseBranch).isEqualTo("master") 158 | softly.assertThat(v.initialCommit).isEqualTo("a") 159 | softly.assertThat(v.localChanges).isEqualTo(NO_CHANGES) 160 | softly.assertThat(v.yearFactor).isEqualTo(1000) 161 | softly.assertThat(v.timeComponent).isEqualTo(0) 162 | softly.assertThat(v.featureBranchOriginCommit).isEqualTo("g") 163 | } 164 | } 165 | 166 | // output should be the same 167 | assertOutput(versioner2) 168 | assertOutput(versioner) 169 | } 170 | 171 | @Test 172 | fun `on feature branch - no commits`() { 173 | val graph = listOf( 174 | Commit(sha1 = "X", parent = "f", date = 150_006_000), // <-- master, feature/bug_123, HEAD 175 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 176 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 177 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 178 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 179 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 180 | Commit(sha1 = "a", parent = null, date = 150_000_000) 181 | ) 182 | 183 | val git = MockGitRepo(graph, "X", listOf("X" to "feature/bug_123", "X" to "master")) 184 | val versioner = GitVersioner(git) 185 | 186 | SoftAssertions.assertSoftly { softly -> 187 | softly.assertThat(versioner.versionCode).isEqualTo(7) 188 | softly.assertThat(versioner.versionName).isEqualTo("7-bug_123") 189 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(7) 190 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 191 | softly.assertThat(versioner.branchName).isEqualTo("feature/bug_123") 192 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 193 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 194 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 195 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 196 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 197 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 198 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 199 | } 200 | } 201 | 202 | @Test 203 | fun `on feature branch - no commits - local changes (additions only)`() { 204 | val graph = listOf( 205 | Commit(sha1 = "X", parent = "f", date = 150_006_000), // <-- master, feature/bug_123, HEAD 206 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 207 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 208 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 209 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 210 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 211 | Commit(sha1 = "a", parent = null, date = 150_000_000) 212 | ) 213 | 214 | val localChanges = LocalChanges(1, 2, 0) 215 | val git = MockGitRepo(graph, "X", listOf("X" to "feature/bug_123", "X" to "master"), localChanges) 216 | val versioner = GitVersioner(git) 217 | 218 | SoftAssertions.assertSoftly { softly -> 219 | softly.assertThat(versioner.versionCode).isEqualTo(7) 220 | softly.assertThat(versioner.versionName).isEqualTo("7-bug_123-SNAPSHOT(1 +2 -0)") 221 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(7) 222 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 223 | softly.assertThat(versioner.branchName).isEqualTo("feature/bug_123") 224 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 225 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 226 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 227 | softly.assertThat(versioner.localChanges).isEqualTo(localChanges) 228 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 229 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 230 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 231 | } 232 | } 233 | 234 | @Test 235 | fun `on feature branch - no commits - local changes (deletions only)`() { 236 | val graph = listOf( 237 | Commit(sha1 = "X", parent = "f", date = 150_006_000), // <-- master, feature/bug_123, HEAD 238 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 239 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 240 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 241 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 242 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 243 | Commit(sha1 = "a", parent = null, date = 150_000_000) 244 | ) 245 | 246 | val localChanges = LocalChanges(1, 0, 2) 247 | val git = MockGitRepo(graph, "X", listOf("X" to "feature/bug_123", "X" to "master"), localChanges) 248 | val versioner = GitVersioner(git) 249 | 250 | SoftAssertions.assertSoftly { softly -> 251 | softly.assertThat(versioner.versionCode).isEqualTo(7) 252 | softly.assertThat(versioner.versionName).isEqualTo("7-bug_123-SNAPSHOT(1 +0 -2)") 253 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(7) 254 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 255 | softly.assertThat(versioner.branchName).isEqualTo("feature/bug_123") 256 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 257 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 258 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 259 | softly.assertThat(versioner.localChanges).isEqualTo(localChanges) 260 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 261 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 262 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 263 | } 264 | } 265 | 266 | @Test 267 | fun `on feature branch - one commit`() { 268 | val graph = listOf( 269 | Commit(sha1 = "X", parent = "g", date = 150_006_000), // <-- feature/bug_123, HEAD 270 | Commit(sha1 = "g", parent = "f", date = 150_006_000), // <-- master 271 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 272 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 273 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 274 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 275 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 276 | Commit(sha1 = "a", parent = null, date = 150_000_000) 277 | ) 278 | 279 | val git = MockGitRepo(graph, "X", listOf("X" to "feature/bug_123", "g" to "master")) 280 | val versioner = GitVersioner(git) 281 | 282 | SoftAssertions.assertSoftly { softly -> 283 | softly.assertThat(versioner.versionCode).isEqualTo(7) 284 | softly.assertThat(versioner.versionName).isEqualTo("7-bug_123+1") 285 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(7) 286 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(1) 287 | softly.assertThat(versioner.branchName).isEqualTo("feature/bug_123") 288 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 289 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 290 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 291 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 292 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 293 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 294 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("g") 295 | } 296 | } 297 | 298 | @Test 299 | fun `no feature branch name - like a jenkins PR build`() { 300 | val graph = listOf( 301 | Commit(sha1 = "abcdefghij", parent = "g", date = 150_006_000), // <-- HEAD 302 | Commit(sha1 = "g", parent = "f", date = 150_006_000), 303 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 304 | Commit(sha1 = "e", parent = "d", date = 150_004_000), // <-- master 305 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 306 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 307 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 308 | Commit(sha1 = "a", parent = null, date = 150_000_000) 309 | ) 310 | 311 | val git = MockGitRepo(graph, "abcdefghij", listOf("e" to "master")) 312 | val versioner = GitVersioner(git) 313 | 314 | SoftAssertions.assertSoftly { softly -> 315 | softly.assertThat(versioner.versionCode).isEqualTo(5) 316 | softly.assertThat(versioner.versionName).isEqualTo("5-abcdefg+3") 317 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(5) 318 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(3) 319 | softly.assertThat(versioner.branchName).isNull() 320 | softly.assertThat(versioner.currentSha1).isEqualTo("abcdefghij") 321 | softly.assertThat(versioner.currentSha1Short).isEqualTo("abcdefg") 322 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 323 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 324 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 325 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 326 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 327 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("e") 328 | } 329 | } 330 | } -------------------------------------------------------------------------------- /gitversioner/src/test/java/com/pascalwelsch/gitversioner/GitVersionerTest.kt: -------------------------------------------------------------------------------- 1 | package com.pascalwelsch.gitversioner 2 | 3 | import org.assertj.core.api.Assertions.* 4 | import org.assertj.core.api.SoftAssertions.assertSoftly 5 | import org.junit.* 6 | import org.junit.runner.* 7 | import org.junit.runners.* 8 | import java.util.concurrent.TimeUnit 9 | 10 | @RunWith(JUnit4::class) 11 | class GitVersionerTest { 12 | 13 | @Test 14 | fun `default - clean on default branch master`() { 15 | val graph = listOf( 16 | Commit(sha1 = "X", parent = "j", date = 150_010_000), // <-- master, HEAD 17 | Commit(sha1 = "j", parent = "i", date = 150_009_000), 18 | Commit(sha1 = "i", parent = "h", date = 150_008_000), 19 | Commit(sha1 = "h", parent = "g", date = 150_007_000), 20 | Commit(sha1 = "g", parent = "f", date = 150_006_000), 21 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 22 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 23 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 24 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 25 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 26 | Commit(sha1 = "a", parent = null, date = 150_000_000) 27 | ) 28 | 29 | val git = MockGitRepo(graph, "X", listOf("X" to "master")) 30 | val versioner = GitVersioner(git) 31 | 32 | assertSoftly { softly -> 33 | softly.assertThat(versioner.versionCode).isEqualTo(11) 34 | softly.assertThat(versioner.versionName).isEqualTo("11") 35 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(11) 36 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 37 | softly.assertThat(versioner.branchName).isEqualTo("master") 38 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 39 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 40 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 41 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 42 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 43 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 44 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 45 | } 46 | } 47 | 48 | @Test 49 | fun `default - with local changes - addSnapshot false`() { 50 | val graph = listOf( 51 | Commit(sha1 = "X", parent = "j", date = 150_010_000), // <-- master, HEAD 52 | Commit(sha1 = "j", parent = "i", date = 150_009_000), 53 | Commit(sha1 = "i", parent = "h", date = 150_008_000), 54 | Commit(sha1 = "h", parent = "g", date = 150_007_000), 55 | Commit(sha1 = "g", parent = "f", date = 150_006_000), 56 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 57 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 58 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 59 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 60 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 61 | Commit(sha1 = "a", parent = null, date = 150_000_000) 62 | ) 63 | 64 | val localChanges = LocalChanges(3, 5, 7) 65 | val git = MockGitRepo(graph, "X", listOf("X" to "master"), localChanges) 66 | val versioner = GitVersioner(git) 67 | versioner.addSnapshot = false 68 | 69 | assertSoftly { softly -> 70 | softly.assertThat(versioner.versionCode).isEqualTo(11) 71 | softly.assertThat(versioner.versionName).isEqualTo("11(3 +5 -7)") 72 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(11) 73 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 74 | softly.assertThat(versioner.branchName).isEqualTo("master") 75 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 76 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 77 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 78 | softly.assertThat(versioner.localChanges).isEqualTo(localChanges) 79 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 80 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 81 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 82 | } 83 | } 84 | 85 | @Test 86 | fun `default - with local changes - addLocalChangesDetails false`() { 87 | val graph = listOf( 88 | Commit(sha1 = "X", parent = "j", date = 150_010_000), // <-- master, HEAD 89 | Commit(sha1 = "j", parent = "i", date = 150_009_000), 90 | Commit(sha1 = "i", parent = "h", date = 150_008_000), 91 | Commit(sha1 = "h", parent = "g", date = 150_007_000), 92 | Commit(sha1 = "g", parent = "f", date = 150_006_000), 93 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 94 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 95 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 96 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 97 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 98 | Commit(sha1 = "a", parent = null, date = 150_000_000) 99 | ) 100 | 101 | val localChanges = LocalChanges(3, 5, 7) 102 | val git = MockGitRepo(graph, "X", listOf("X" to "master"), localChanges) 103 | val versioner = GitVersioner(git) 104 | versioner.addLocalChangesDetails = false 105 | 106 | assertSoftly { softly -> 107 | softly.assertThat(versioner.versionCode).isEqualTo(11) 108 | softly.assertThat(versioner.versionName).isEqualTo("11-SNAPSHOT") 109 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(11) 110 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 111 | softly.assertThat(versioner.branchName).isEqualTo("master") 112 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 113 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 114 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 115 | softly.assertThat(versioner.localChanges).isEqualTo(localChanges) 116 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 117 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 118 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 119 | } 120 | } 121 | 122 | @Test 123 | fun `default - without local changes information`() { 124 | val graph = listOf( 125 | Commit(sha1 = "X", parent = "j", date = 150_010_000), // <-- master, HEAD 126 | Commit(sha1 = "j", parent = "i", date = 150_009_000), 127 | Commit(sha1 = "i", parent = "h", date = 150_008_000), 128 | Commit(sha1 = "h", parent = "g", date = 150_007_000), 129 | Commit(sha1 = "g", parent = "f", date = 150_006_000), 130 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 131 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 132 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 133 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 134 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 135 | Commit(sha1 = "a", parent = null, date = 150_000_000) 136 | ) 137 | 138 | val localChanges = LocalChanges(3, 5, 7) 139 | val git = MockGitRepo(graph, "X", listOf("X" to "master"), localChanges) 140 | val versioner = GitVersioner(git) 141 | versioner.addLocalChangesDetails = false 142 | versioner.addSnapshot = false 143 | 144 | assertSoftly { softly -> 145 | softly.assertThat(versioner.versionCode).isEqualTo(11) 146 | softly.assertThat(versioner.versionName).isEqualTo("11") 147 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(11) 148 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 149 | softly.assertThat(versioner.branchName).isEqualTo("master") 150 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 151 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 152 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 153 | softly.assertThat(versioner.localChanges).isEqualTo(localChanges) 154 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 155 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 156 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 157 | } 158 | } 159 | 160 | @Test 161 | fun `default - with local changes`() { 162 | val graph = listOf( 163 | Commit(sha1 = "X", parent = "j", date = 150_010_000), // <-- master, HEAD 164 | Commit(sha1 = "j", parent = "i", date = 150_009_000), 165 | Commit(sha1 = "i", parent = "h", date = 150_008_000), 166 | Commit(sha1 = "h", parent = "g", date = 150_007_000), 167 | Commit(sha1 = "g", parent = "f", date = 150_006_000), 168 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 169 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 170 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 171 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 172 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 173 | Commit(sha1 = "a", parent = null, date = 150_000_000) 174 | ) 175 | 176 | val localChanges = LocalChanges(3, 5, 7) 177 | val git = MockGitRepo(graph, "X", listOf("X" to "master"), localChanges) 178 | val versioner = GitVersioner(git) 179 | 180 | assertSoftly { softly -> 181 | softly.assertThat(versioner.versionCode).isEqualTo(11) 182 | softly.assertThat(versioner.versionName).isEqualTo("11-SNAPSHOT(3 +5 -7)") 183 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(11) 184 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 185 | softly.assertThat(versioner.branchName).isEqualTo("master") 186 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 187 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 188 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 189 | softly.assertThat(versioner.localChanges).isEqualTo(localChanges) 190 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 191 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 192 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 193 | } 194 | } 195 | 196 | @Test 197 | fun `base branch not in history`() { 198 | val graph = listOf( 199 | Commit(sha1 = "X", parent = "j", date = 150_010_000), // <-- master, HEAD 200 | Commit(sha1 = "j", parent = "i", date = 150_009_000), 201 | Commit(sha1 = "i", parent = "h", date = 150_008_000), 202 | Commit(sha1 = "h", parent = "g", date = 150_007_000), 203 | Commit(sha1 = "g", parent = "f", date = 150_006_000), 204 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 205 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 206 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 207 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 208 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 209 | Commit(sha1 = "a", parent = null, date = 150_000_000) 210 | ) 211 | 212 | val git = MockGitRepo(graph, "X", listOf("X" to "master")) 213 | val versioner = GitVersioner(git).apply { 214 | baseBranch = "develop" 215 | } 216 | 217 | assertSoftly { softly -> 218 | softly.assertThat(versioner.versionCode).isEqualTo(0) 219 | softly.assertThat(versioner.versionName).isEqualTo("0-master+11") 220 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 221 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(11) 222 | softly.assertThat(versioner.branchName).isEqualTo("master") 223 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 224 | softly.assertThat(versioner.baseBranch).isEqualTo("develop") 225 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 226 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 227 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 228 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 229 | 230 | // no commit in both HEAD history and develop because develop is not part of the graph 231 | softly.assertThat(versioner.featureBranchOriginCommit).isNull() 232 | } 233 | } 234 | 235 | @Test 236 | fun `on orphan initial commit`() { 237 | val graph = listOf( 238 | Commit(sha1 = "X", parent = null, date = 150_010_000), // <-- HEAD, orphan 239 | 240 | Commit(sha1 = "e", parent = "d", date = 150_004_000), // <-- master 241 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 242 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 243 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 244 | Commit(sha1 = "a", parent = null, date = 150_000_000) 245 | ) 246 | 247 | val git = MockGitRepo(graph, "X", branchHeads = listOf("e" to "master", "X" to "orphan")) 248 | val versioner = GitVersioner(git) 249 | 250 | assertSoftly { softly -> 251 | softly.assertThat(versioner.versionCode).isEqualTo(0) 252 | softly.assertThat(versioner.versionName).isEqualTo("0-orphan+1") 253 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 254 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(1) 255 | softly.assertThat(versioner.branchName).isEqualTo("orphan") 256 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 257 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 258 | softly.assertThat(versioner.initialCommit).isEqualTo("X") 259 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 260 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 261 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 262 | softly.assertThat(versioner.featureBranchOriginCommit).isNull() 263 | } 264 | } 265 | 266 | @Test 267 | fun `on orphan few commits`() { 268 | val graph = listOf( 269 | Commit(sha1 = "X", parent = "b'", date = 150_030_000), // <-- HEAD, feature/x 270 | Commit(sha1 = "b'", parent = "a'", date = 150_020_000), 271 | Commit(sha1 = "a'", parent = null, date = 150_010_000), // <-- orphan 272 | 273 | Commit(sha1 = "e", parent = "d", date = 150_004_000), // <-- master 274 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 275 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 276 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 277 | Commit(sha1 = "a", parent = null, date = 150_000_000) 278 | ) 279 | 280 | val git = MockGitRepo(graph, "X", listOf("e" to "master", "X" to "feature/x")) 281 | val versioner = GitVersioner(git) 282 | 283 | assertSoftly { softly -> 284 | softly.assertThat(versioner.versionCode).isEqualTo(0) 285 | softly.assertThat(versioner.versionName).isEqualTo("0-x+3") 286 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 287 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(3) 288 | softly.assertThat(versioner.branchName).isEqualTo("feature/x") 289 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 290 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 291 | softly.assertThat(versioner.initialCommit).isEqualTo("a'") 292 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 293 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 294 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 295 | 296 | // no commit in both HEAD history and develop because develop is not part of the graph 297 | softly.assertThat(versioner.featureBranchOriginCommit).isNull() 298 | } 299 | } 300 | 301 | @Test 302 | fun `first commit - no parent`() { 303 | val graph = listOf( 304 | Commit(sha1 = "X", parent = null, date = 150_006_000) // <-- master, HEAD 305 | ) 306 | 307 | val git = MockGitRepo(graph, "X", listOf("X" to "master")) 308 | val versioner = GitVersioner(git) 309 | 310 | assertSoftly { softly -> 311 | softly.assertThat(versioner.versionCode).isEqualTo(1) 312 | softly.assertThat(versioner.versionName).isEqualTo("1") 313 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(1) 314 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 315 | softly.assertThat(versioner.branchName).isEqualTo("master") 316 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 317 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 318 | softly.assertThat(versioner.initialCommit).isEqualTo("X") 319 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 320 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 321 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 322 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 323 | } 324 | } 325 | 326 | @Test 327 | fun `short sha1`() { 328 | val graph = listOf( 329 | Commit(sha1 = "abcdefghijkl", parent = null, date = 150_006_000) // <-- master, HEAD 330 | ) 331 | 332 | val git = MockGitRepo(graph, "abcdefghijkl", listOf("abcdefghijkl" to "master")) 333 | val versioner = GitVersioner(git) 334 | 335 | assertSoftly { softly -> 336 | softly.assertThat(versioner.versionCode).isEqualTo(1) 337 | softly.assertThat(versioner.versionName).isEqualTo("1") 338 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(1) 339 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 340 | softly.assertThat(versioner.branchName).isEqualTo("master") 341 | softly.assertThat(versioner.currentSha1).isEqualTo("abcdefghijkl") 342 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 343 | softly.assertThat(versioner.initialCommit).isEqualTo("abcdefghijkl") 344 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 345 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 346 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 347 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("abcdefghijkl") 348 | } 349 | 350 | assertThat(versioner.currentSha1Short).isEqualTo("abcdefg").hasSize(7) 351 | } 352 | 353 | @Test 354 | fun `short sha1 - edge cases`() { 355 | 356 | assertThat(GitVersioner(GitInfoExtractorStub(currentSha1 = null)).currentSha1Short) 357 | .isNull() 358 | 359 | assertThat(GitVersioner(GitInfoExtractorStub(currentSha1 = "abc")).currentSha1Short) 360 | .isEqualTo("abc") 361 | 362 | assertThat(GitVersioner(GitInfoExtractorStub(currentSha1 = "abcdefghi")).currentSha1Short) 363 | .hasSize(7).isEqualTo("abcdefg") 364 | } 365 | 366 | @Test 367 | fun `timeComponent increased by 1 after ~8h`() { 368 | val graph = listOf( 369 | Commit(sha1 = "X", parent = "a", date = 150_000_000), // <-- HEAD, master 370 | Commit(sha1 = "a", parent = null, date = 150_000_000) 371 | ) 372 | 373 | val git = MockGitRepo(graph, "X", listOf("X" to "master")) 374 | val versioner = GitVersioner(git) 375 | 376 | assertSoftly { softly -> 377 | softly.assertThat(versioner.versionCode).isEqualTo(2) 378 | softly.assertThat(versioner.versionName).isEqualTo("2") 379 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(2) 380 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 381 | softly.assertThat(versioner.branchName).isEqualTo("master") 382 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 383 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 384 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 385 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 386 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 387 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 388 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 389 | } 390 | 391 | // now the same with larger difference between commits (9h) should increase by 1 with default yearFactor 392 | val graph2 = listOf( 393 | Commit( 394 | sha1 = "X", parent = "a", 395 | date = 150_000_000 + TimeUnit.HOURS.toSeconds(9) 396 | ), // <-- HEAD, master 397 | Commit(sha1 = "a", parent = null, date = 150_000_000) 398 | ) 399 | 400 | val git2 = MockGitRepo(graph2, "X", listOf("X" to "master")) 401 | val versioner2 = GitVersioner(git2) 402 | 403 | assertSoftly { softly -> 404 | softly.assertThat(versioner2.versionCode).isEqualTo(3) 405 | softly.assertThat(versioner2.versionName).isEqualTo("3") 406 | softly.assertThat(versioner2.baseBranchCommitCount).isEqualTo(2) 407 | softly.assertThat(versioner2.featureBranchCommitCount).isEqualTo(0) 408 | softly.assertThat(versioner2.branchName).isEqualTo("master") 409 | softly.assertThat(versioner2.currentSha1).isEqualTo("X") 410 | softly.assertThat(versioner2.baseBranch).isEqualTo("master") 411 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 412 | softly.assertThat(versioner2.localChanges).isEqualTo(NO_CHANGES) 413 | softly.assertThat(versioner2.yearFactor).isEqualTo(1000) 414 | softly.assertThat(versioner2.timeComponent).isEqualTo(1) 415 | softly.assertThat(versioner2.featureBranchOriginCommit).isEqualTo("X") 416 | } 417 | } 418 | 419 | @Test 420 | fun `test yearfactor`() { 421 | val graph = listOf( 422 | Commit(sha1 = "X", parent = "a", date = 150_000_000), // <-- HEAD, master 423 | Commit(sha1 = "a", parent = null, date = 150_000_000) 424 | ) 425 | 426 | val git = MockGitRepo(graph, "X", listOf("X" to "master")) 427 | val versioner = GitVersioner(git) 428 | 429 | assertSoftly { softly -> 430 | softly.assertThat(versioner.versionCode).isEqualTo(2) 431 | softly.assertThat(versioner.versionName).isEqualTo("2") 432 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(2) 433 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 434 | softly.assertThat(versioner.branchName).isEqualTo("master") 435 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 436 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 437 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 438 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 439 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 440 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 441 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 442 | } 443 | 444 | // add one year / yearFactor 1000 445 | val graph2 = listOf( 446 | Commit( 447 | sha1 = "X", parent = "a", 448 | date = 150_000_000 + TimeUnit.DAYS.toSeconds(365) 449 | ), // <-- HEAD, master 450 | Commit(sha1 = "a", parent = null, date = 150_000_000) 451 | ) 452 | 453 | val git2 = MockGitRepo(graph2, "X", listOf("X" to "master")) 454 | val versioner2 = GitVersioner(git2) 455 | 456 | assertSoftly { softly -> 457 | softly.assertThat(versioner2.versionCode).isEqualTo(1002) 458 | softly.assertThat(versioner2.versionName).isEqualTo("1002") 459 | softly.assertThat(versioner2.baseBranchCommitCount).isEqualTo(2) 460 | softly.assertThat(versioner2.featureBranchCommitCount).isEqualTo(0) 461 | softly.assertThat(versioner2.branchName).isEqualTo("master") 462 | softly.assertThat(versioner2.currentSha1).isEqualTo("X") 463 | softly.assertThat(versioner2.baseBranch).isEqualTo("master") 464 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 465 | softly.assertThat(versioner2.localChanges).isEqualTo(NO_CHANGES) 466 | softly.assertThat(versioner2.yearFactor).isEqualTo(1000) 467 | softly.assertThat(versioner2.timeComponent).isEqualTo(1000) 468 | softly.assertThat(versioner2.featureBranchOriginCommit).isEqualTo("X") 469 | } 470 | } 471 | 472 | @Test 473 | fun `custom year factor 1200`() { 474 | val graph = listOf( 475 | Commit( 476 | sha1 = "X", parent = "a", 477 | date = 150_000_000 + TimeUnit.DAYS.toSeconds(365) 478 | ), // <-- HEAD, master 479 | Commit(sha1 = "a", parent = null, date = 150_000_000) 480 | ) 481 | 482 | val git = MockGitRepo(graph, "X", listOf("X" to "master")) 483 | val versioner = GitVersioner(git) 484 | versioner.yearFactor = 1200 485 | 486 | assertSoftly { softly -> 487 | softly.assertThat(versioner.versionCode).isEqualTo(1202) 488 | softly.assertThat(versioner.versionName).isEqualTo("1202") 489 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(2) 490 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 491 | softly.assertThat(versioner.branchName).isEqualTo("master") 492 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 493 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 494 | softly.assertThat(versioner.initialCommit).isEqualTo("a") 495 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 496 | softly.assertThat(versioner.yearFactor).isEqualTo(1200) 497 | softly.assertThat(versioner.timeComponent).isEqualTo(1200) 498 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 499 | } 500 | } 501 | 502 | @Test 503 | fun `no git repo`() { 504 | val git = MockGitRepo(isGitWorking = false) // git initialized but nothing committed 505 | val versioner = GitVersioner(git) 506 | 507 | assertSoftly { softly -> 508 | // since Android gradle plugin 3.4.0 the versionCode is expected to be positive 509 | // https://developer.android.com/studio/publish/versioning#appversioning 510 | softly.assertThat(versioner.versionCode).isEqualTo(1) 511 | softly.assertThat(versioner.versionName).isEqualTo("undefined") 512 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 513 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 514 | softly.assertThat(versioner.branchName).isNull() 515 | softly.assertThat(versioner.currentSha1).isNull() 516 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 517 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 518 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 519 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 520 | softly.assertThat(versioner.featureBranchOriginCommit).isNull() 521 | } 522 | } 523 | 524 | @Test 525 | fun `no commits`() { 526 | val git = MockGitRepo() // git initialized but nothing committed 527 | val versioner = GitVersioner(git) 528 | 529 | assertSoftly { softly -> 530 | softly.assertThat(versioner.versionCode).isEqualTo(0) 531 | softly.assertThat(versioner.versionName).isEqualTo("0") 532 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 533 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 534 | softly.assertThat(versioner.branchName).isNull() 535 | softly.assertThat(versioner.currentSha1).isNull() 536 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 537 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 538 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 539 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 540 | softly.assertThat(versioner.featureBranchOriginCommit).isNull() 541 | } 542 | } 543 | 544 | @Test 545 | fun `no commits - local changes`() { 546 | 547 | val localChanges = LocalChanges(3, 5, 7) 548 | val git = MockGitRepo(localChanges = localChanges) // git initialized but nothing committed 549 | val versioner = GitVersioner(git) 550 | 551 | assertSoftly { softly -> 552 | softly.assertThat(versioner.versionCode).isEqualTo(0) 553 | softly.assertThat(versioner.versionName).isEqualTo("0-SNAPSHOT(3 +5 -7)") 554 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 555 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 556 | softly.assertThat(versioner.branchName).isNull() 557 | softly.assertThat(versioner.currentSha1).isNull() 558 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 559 | softly.assertThat(versioner.localChanges).isEqualTo(localChanges) 560 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 561 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 562 | softly.assertThat(versioner.featureBranchOriginCommit).isNull() 563 | } 564 | } 565 | 566 | @Test 567 | fun verifyOpenVersioner() { 568 | // required because gradle generates a proxy for the versioner 569 | val extended = object : GitVersioner(MockGitRepo()) {} 570 | assertThat(extended).isNotNull() 571 | } 572 | 573 | @Test 574 | fun `custom name formatter`() { 575 | val graph = listOf( 576 | Commit( 577 | sha1 = "X", parent = "j", 578 | date = 150_010_000 579 | ), // <-- fix_ABC-12345_nothing_special, HEAD 580 | Commit(sha1 = "j", parent = "i", date = 150_009_000), 581 | Commit(sha1 = "i", parent = "h", date = 150_008_000), // <-- master 582 | Commit(sha1 = "h", parent = "g", date = 150_007_000), 583 | Commit(sha1 = "g", parent = "f", date = 150_006_000), 584 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 585 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 586 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 587 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 588 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 589 | Commit(sha1 = "a", parent = null, date = 150_000_000) 590 | ) 591 | 592 | val git = MockGitRepo( 593 | graph, "fix_ABC-12345_nothing_special", 594 | listOf("i" to "master", "X" to "fix_ABC-12345_nothing_special") 595 | ) 596 | val versioner = GitVersioner(git) 597 | versioner.shortNameFormatter = { v -> 598 | // use default formatter but only use the jira id when detected and drop rest 599 | GitVersioner.DEFAULT_SHORT_NAME_FORMATTER(v) 600 | .replace(".*(ABC-\\d*).*".toRegex()) { it.groupValues[1] } 601 | } 602 | 603 | assertSoftly { softly -> 604 | softly.assertThat(versioner.versionCode).isEqualTo(9) 605 | softly.assertThat(versioner.versionName).isEqualTo("9-ABC-12345+2") 606 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(9) 607 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(2) 608 | softly.assertThat(versioner.branchName).isEqualTo("fix_ABC-12345_nothing_special") 609 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 610 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 611 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 612 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 613 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 614 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("i") 615 | } 616 | } 617 | 618 | @Test 619 | fun `custom formatter`() { 620 | val graph = listOf( 621 | Commit( 622 | sha1 = "X", parent = "j", 623 | date = 150_010_000 624 | ), // <-- fix_ABC-12345_nothing_special, HEAD 625 | Commit(sha1 = "j", parent = "i", date = 150_009_000), 626 | Commit(sha1 = "i", parent = "h", date = 150_008_000), // <-- master 627 | Commit(sha1 = "h", parent = "g", date = 150_007_000), 628 | Commit(sha1 = "g", parent = "f", date = 150_006_000), 629 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 630 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 631 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 632 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 633 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 634 | Commit(sha1 = "a", parent = null, date = 150_000_000) 635 | ) 636 | 637 | val git = MockGitRepo( 638 | graph, "fix_ABC-12345_nothing_special", 639 | listOf("i" to "master", "X" to "fix_ABC-12345_nothing_special") 640 | ) 641 | val versioner = GitVersioner(git) 642 | versioner.formatter = { v -> 643 | "I do my own thing ${v.commitCount}" 644 | } 645 | 646 | assertSoftly { softly -> 647 | softly.assertThat(versioner.versionCode).isEqualTo(9) 648 | softly.assertThat(versioner.versionName).isEqualTo("I do my own thing 11") 649 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(9) 650 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(2) 651 | softly.assertThat(versioner.branchName).isEqualTo("fix_ABC-12345_nothing_special") 652 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 653 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 654 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 655 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 656 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 657 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("i") 658 | } 659 | } 660 | 661 | @Test 662 | fun `no branch name - sha1 fallback`() { 663 | val graph = listOf( 664 | Commit(sha1 = "X", parent = "j", date = 150_010_000), // <-- HEAD 665 | Commit(sha1 = "j", parent = "i", date = 150_009_000), 666 | Commit(sha1 = "i", parent = "h", date = 150_008_000), // <-- master 667 | Commit(sha1 = "h", parent = "g", date = 150_007_000), 668 | Commit(sha1 = "g", parent = "f", date = 150_006_000), 669 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 670 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 671 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 672 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 673 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 674 | Commit(sha1 = "a", parent = null, date = 150_000_000) 675 | ) 676 | 677 | val git = MockGitRepo(graph, "X", listOf("i" to "master")) 678 | val versioner = GitVersioner(git) 679 | 680 | assertSoftly { softly -> 681 | softly.assertThat(versioner.versionCode).isEqualTo(9) 682 | softly.assertThat(versioner.versionName).isEqualTo("9-X+2") 683 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(9) 684 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(2) 685 | softly.assertThat(versioner.branchName).isNull() 686 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 687 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 688 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 689 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 690 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 691 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("i") 692 | } 693 | } 694 | 695 | @Test 696 | fun `custom name formatter - fails`() { 697 | val graph = listOf( 698 | Commit(sha1 = "X", parent = "j", date = 150_010_000), // <-- HEAD 699 | Commit(sha1 = "j", parent = "i", date = 150_009_000), 700 | Commit(sha1 = "i", parent = "h", date = 150_008_000), // <-- master 701 | Commit(sha1 = "h", parent = "g", date = 150_007_000), 702 | Commit(sha1 = "g", parent = "f", date = 150_006_000), 703 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 704 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 705 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 706 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 707 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 708 | Commit(sha1 = "a", parent = null, date = 150_000_000) 709 | ) 710 | 711 | val git = MockGitRepo(graph, "X", listOf("i" to "master")) 712 | val versioner = GitVersioner(git) 713 | // fail will be ignored, fallback default formatter 714 | versioner.shortNameFormatter = { throw Exception("fail!") } 715 | 716 | assertSoftly { softly -> 717 | softly.assertThat(versioner.versionCode).isEqualTo(9) 718 | softly.assertThat(versioner.versionName).isEqualTo("9-X+2") 719 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(9) 720 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(2) 721 | softly.assertThat(versioner.branchName).isNull() 722 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 723 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 724 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 725 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 726 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 727 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("i") 728 | } 729 | } 730 | 731 | @Test 732 | fun `custom formatter - fails`() { 733 | val graph = listOf( 734 | Commit(sha1 = "X", parent = "j", date = 150_010_000), // <-- master, HEAD 735 | Commit(sha1 = "j", parent = "i", date = 150_009_000), 736 | Commit(sha1 = "i", parent = "h", date = 150_008_000), 737 | Commit(sha1 = "h", parent = "g", date = 150_007_000), 738 | Commit(sha1 = "g", parent = "f", date = 150_006_000), 739 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 740 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 741 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 742 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 743 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 744 | Commit(sha1 = "a", parent = null, date = 150_000_000) 745 | ) 746 | 747 | val git = MockGitRepo(graph, "X", listOf("X" to "master")) 748 | val versioner = GitVersioner(git) 749 | // fail will be ignored, fallback default formatter 750 | versioner.formatter = { throw Exception("fail!") } 751 | 752 | assertSoftly { softly -> 753 | softly.assertThat(versioner.versionCode).isEqualTo(11) 754 | softly.assertThat(versioner.versionName).isEqualTo("11") 755 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(11) 756 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 757 | softly.assertThat(versioner.branchName).isEqualTo("master") 758 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 759 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 760 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 761 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 762 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 763 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 764 | } 765 | } 766 | 767 | @Test 768 | fun `default - branchname from ci`() { 769 | val graph = listOf( 770 | Commit(sha1 = "X", parent = "j", date = 150_010_000), // <-- HEAD, master 771 | Commit(sha1 = "j", parent = "i", date = 150_009_000), 772 | Commit(sha1 = "i", parent = "h", date = 150_008_000), 773 | Commit(sha1 = "h", parent = "g", date = 150_007_000), 774 | Commit(sha1 = "g", parent = "f", date = 150_006_000), 775 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 776 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 777 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 778 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 779 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 780 | Commit(sha1 = "a", parent = null, date = 150_000_000) 781 | ) 782 | 783 | val git = object : MockGitRepo(graph, "X", listOf("X" to "master")) { 784 | // explicitly checked out sha1 not branch 785 | override val currentBranch: String? = null 786 | } 787 | val versioner = GitVersioner(git) 788 | versioner.ciBranchNameProvider = { "nameFromCi" } 789 | 790 | assertSoftly { softly -> 791 | softly.assertThat(versioner.versionCode).isEqualTo(11) 792 | softly.assertThat(versioner.versionName).isEqualTo("11-nameFromCi") 793 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(11) 794 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 795 | softly.assertThat(versioner.branchName).isEqualTo("nameFromCi") 796 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 797 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 798 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 799 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 800 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 801 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 802 | } 803 | } 804 | 805 | @Test 806 | fun `default - receive default branch name from ci`() { 807 | val graph = listOf( 808 | Commit(sha1 = "X", parent = "j", date = 150_010_000), // <-- HEAD 809 | Commit(sha1 = "j", parent = "i", date = 150_009_000), 810 | Commit(sha1 = "i", parent = "h", date = 150_008_000), 811 | Commit(sha1 = "h", parent = "g", date = 150_007_000), 812 | Commit(sha1 = "g", parent = "f", date = 150_006_000), 813 | Commit(sha1 = "f", parent = "e", date = 150_005_000), 814 | Commit(sha1 = "e", parent = "d", date = 150_004_000), 815 | Commit(sha1 = "d", parent = "c", date = 150_003_000), 816 | Commit(sha1 = "c", parent = "b", date = 150_002_000), 817 | Commit(sha1 = "b", parent = "a", date = 150_001_000), 818 | Commit(sha1 = "a", parent = null, date = 150_000_000) 819 | ) 820 | 821 | val git = object : MockGitRepo(graph, "X", listOf("X" to "master")) { 822 | // explicitly checked out sha1 not branch 823 | override val currentBranch: String? = null 824 | } 825 | val versioner = GitVersioner(git) 826 | versioner.ciBranchNameProvider = { "master" } 827 | 828 | assertSoftly { softly -> 829 | softly.assertThat(versioner.versionCode).isEqualTo(11) 830 | softly.assertThat(versioner.versionName).isEqualTo("11") 831 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(11) 832 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 833 | softly.assertThat(versioner.branchName).isEqualTo("master") 834 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 835 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 836 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 837 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 838 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 839 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 840 | } 841 | } 842 | } -------------------------------------------------------------------------------- /gitversioner/src/test/java/com/pascalwelsch/gitversioner/LocalChangesTest.kt: -------------------------------------------------------------------------------- 1 | package com.pascalwelsch.gitversioner 2 | 3 | import org.assertj.core.api.Assertions.* 4 | import org.junit.* 5 | import org.junit.runner.* 6 | import org.junit.runners.* 7 | 8 | @RunWith(JUnit4::class) 9 | class LocalChangesTest { 10 | 11 | @Test 12 | fun `parse insertions and additions`() { 13 | val diff = parseShortStats("3 files changed, 161 insertions(+), 84 deletions(-)") 14 | assertThat(diff).isEqualTo(LocalChanges(3, 161, 84)) 15 | } 16 | 17 | @Test 18 | fun `parse insertions only`() { 19 | val diff = parseShortStats("1 file changed, 13 insertions(+)") 20 | assertThat(diff).isEqualTo(LocalChanges(1, 13, 0)) 21 | } 22 | 23 | @Test 24 | fun `parse deletions only`() { 25 | val diff = parseShortStats("1 file changed, 14 deletions(-)") 26 | assertThat(diff).isEqualTo(LocalChanges(1, 0, 14)) 27 | } 28 | 29 | @Test 30 | fun `parse crap`() { 31 | val diff = parseShortStats("nothing useful") 32 | assertThat(diff).isEqualTo(NO_CHANGES) 33 | } 34 | 35 | @Test 36 | fun `parse crap 2`() { 37 | val diff = parseShortStats("2 nothing useful, 3 with commas, 4 and digits") 38 | assertThat(diff).isEqualTo(NO_CHANGES) 39 | } 40 | 41 | @Test 42 | fun `toString conversion`() { 43 | assertThat(LocalChanges(1, 0, 14).toString()).isEqualTo("1 +0 -14") 44 | assertThat(LocalChanges(0, 0, 0).toString()).isEqualTo("0 +0 -0") 45 | assertThat(LocalChanges(2, 3, 4).toString()).isEqualTo("2 +3 -4") 46 | assertThat(LocalChanges(1, 2, 0).toString()).isEqualTo("1 +2 -0") 47 | } 48 | } -------------------------------------------------------------------------------- /gitversioner/src/test/java/com/pascalwelsch/gitversioner/MockGitRepo.kt: -------------------------------------------------------------------------------- 1 | package com.pascalwelsch.gitversioner 2 | 3 | data class Commit( 4 | val sha1: String, 5 | val parent: String?, 6 | val date: Long 7 | ) 8 | 9 | /** 10 | * Mocks a real git repo with commit history and branches 11 | */ 12 | open class MockGitRepo( 13 | val graph: Collection = emptyList(), 14 | val head: String? = null, 15 | val branchHeads: List> = emptyList(), 16 | final override val localChanges: LocalChanges = NO_CHANGES, 17 | final override val isHistoryShallowed: Boolean = false, 18 | final override val isGitWorking: Boolean = true 19 | ) : GitInfoExtractor { 20 | 21 | val headCommit: Commit? = if (head == null) null else 22 | requireNotNull(commitInGraph(head)) { "head commit not in graph" } 23 | 24 | init { 25 | graph.forEach { commit -> 26 | // orphan commits are valid 27 | if (commit.parent != null) { 28 | // allow unknown parents for shallow clones 29 | if (!isHistoryShallowed) { 30 | // unknown parents are invalid 31 | requireNotNull(commit.parentCommit()) { "parent commit not in graph" } 32 | } 33 | } 34 | } 35 | 36 | branchHeads.forEach { (sha1, name) -> 37 | requireNotNull(commitInGraph(sha1)) { "$sha1 ($name) not a commit in graph" } 38 | } 39 | if (isHistoryShallowed) { 40 | require(graph.size <= 1) { "shallow clones only have one commit" } 41 | } 42 | } 43 | 44 | override val currentSha1: String? = headCommit?.sha1 45 | 46 | override val currentBranch: String? = if (headCommit == null) null else 47 | sha1ToBranch(headCommit.sha1) 48 | 49 | override val initialCommitDate: Long 50 | get() { 51 | if (headCommit == null) return 0 52 | val commits = commitsToHead 53 | if (commits.isEmpty()) return 0 54 | 55 | val initialCommit = commitInGraph(commitsToHead.last()) 56 | 57 | return initialCommit?.date ?: 0 58 | } 59 | 60 | override fun commitDate(rev: String): Long = commitInGraph(rev)?.date 61 | ?: throw IllegalStateException("commit $rev not in graph") 62 | 63 | override val commitsToHead: List 64 | get() = if (headCommit == null) emptyList() else commitsUpTo(headCommit.sha1) 65 | 66 | override fun commitsUpTo(rev: String, args: String): List { 67 | val commit = commitInGraph(rev) ?: return emptyList() 68 | val history: MutableList = mutableListOf(commit) 69 | 70 | while (true) { 71 | val parent = history.last().parentCommit() 72 | if (parent == null) { 73 | return history.map { it.sha1 } 74 | } else { 75 | history.add(parent) 76 | } 77 | } 78 | } 79 | 80 | fun commitInGraph(rev: String): Commit? { 81 | val inGraph = graph.find { it.sha1 == rev } 82 | if (inGraph != null) return inGraph 83 | 84 | // rev is branch, branchName -> sha1 85 | val sha1 = branchToSha1(rev) ?: return null 86 | return graph.find { it.sha1 == sha1 } 87 | } 88 | 89 | fun branchToSha1(branchName: String): String? = branchHeads.find { it.second == branchName }?.first 90 | fun sha1ToBranch(sha1: String): String? = branchHeads.find { it.first == sha1 }?.second 91 | 92 | fun Commit.parentCommit(): Commit? { 93 | if (parent == null) return null 94 | return graph.find { it.sha1 == parent } 95 | } 96 | } 97 | 98 | class GitInfoExtractorStub( 99 | override val currentSha1: String? = null, 100 | override val currentBranch: String? = null, 101 | override val localChanges: LocalChanges = NO_CHANGES, 102 | override val isGitWorking: Boolean = true, 103 | override val isHistoryShallowed: Boolean = false, 104 | val commits: List = emptyList() 105 | ) : GitInfoExtractor { 106 | 107 | override fun commitsUpTo(rev: String, args: String): List { 108 | return commits 109 | } 110 | 111 | override val initialCommitDate: Long 112 | get() = 0L 113 | 114 | override val commitsToHead: List 115 | get() = commits 116 | 117 | override fun commitDate(rev: String): Long { 118 | return 0L 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /gitversioner/src/test/java/com/pascalwelsch/gitversioner/PrefixedBranchTest.kt: -------------------------------------------------------------------------------- 1 | package com.pascalwelsch.gitversioner 2 | 3 | import org.assertj.core.api.Assertions.* 4 | import org.junit.* 5 | import org.junit.runner.* 6 | import org.junit.runners.* 7 | 8 | @RunWith(JUnit4::class) 9 | class PrefixedBranchTest { 10 | 11 | @Test 12 | fun `replace special characters`() { 13 | assertThat(versionNameForBranch("craz+y-n=,a^m;e")).isEqualTo("3-craz_y-n_a_m_e") 14 | } 15 | 16 | @Test 17 | fun `remove prefix + replace special characters`() { 18 | assertThat(versionNameForBranch("feature/craz+y-n=,a^m;e")).isEqualTo("3-craz_y-n_a_m_e") 19 | } 20 | 21 | @Test 22 | fun `remove prefix`() { 23 | assertThat(versionNameForBranch("bugfix/bug_123")).isEqualTo("3-bug_123") 24 | } 25 | 26 | @Test 27 | fun `remove only first prefix`() { 28 | assertThat(versionNameForBranch("bugfix/something/bug_123")).isEqualTo("3-something_bug_123") 29 | } 30 | } 31 | 32 | private fun versionNameForBranch(branchName: String): String { 33 | val versioner = GitVersioner(GitInfoExtractorStub(commits = listOf("a", "b", "c"), currentBranch = branchName)) 34 | return versioner.versionName 35 | } 36 | -------------------------------------------------------------------------------- /gitversioner/src/test/java/com/pascalwelsch/gitversioner/ShallowCloneTest.kt: -------------------------------------------------------------------------------- 1 | package com.pascalwelsch.gitversioner 2 | 3 | import org.assertj.core.api.Assertions.* 4 | import org.assertj.core.api.SoftAssertions.assertSoftly 5 | import org.junit.* 6 | import org.junit.runner.* 7 | import org.junit.runners.* 8 | 9 | @RunWith(JUnit4::class) 10 | class ShallowCloneTest { 11 | 12 | @Test 13 | fun `default - clean on default branch master`() { 14 | val graph = listOf( 15 | Commit(sha1 = "X", parent = "j", date = 150_010_000) // <-- master, HEAD 16 | ) 17 | 18 | val git = MockGitRepo(graph, "X", listOf("X" to "master"), isHistoryShallowed = true) 19 | val versioner = GitVersioner(git) 20 | 21 | assertSoftly { softly -> 22 | softly.assertThat(versioner.versionCode).isEqualTo(1) 23 | softly.assertThat(versioner.versionName).isEqualTo("shallowed") 24 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 25 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 26 | softly.assertThat(versioner.branchName).isEqualTo("master") 27 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 28 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 29 | softly.assertThat(versioner.initialCommit).isNull() 30 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 31 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 32 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 33 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 34 | } 35 | } 36 | 37 | @Test 38 | fun `default - with local changes - addSnapshot false`() { 39 | val graph = listOf( 40 | Commit(sha1 = "X", parent = "j", date = 150_010_000) // <-- master, HEAD 41 | ) 42 | 43 | val localChanges = LocalChanges(3, 5, 7) 44 | val git = MockGitRepo(graph, "X", listOf("X" to "master"), localChanges, isHistoryShallowed = true) 45 | val versioner = GitVersioner(git) 46 | versioner.addSnapshot = false 47 | 48 | assertSoftly { softly -> 49 | softly.assertThat(versioner.versionCode).isEqualTo(1) 50 | softly.assertThat(versioner.versionName).isEqualTo("shallowed(3 +5 -7)") 51 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 52 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 53 | softly.assertThat(versioner.branchName).isEqualTo("master") 54 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 55 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 56 | softly.assertThat(versioner.initialCommit).isNull() 57 | softly.assertThat(versioner.localChanges).isEqualTo(localChanges) 58 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 59 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 60 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 61 | } 62 | } 63 | 64 | @Test 65 | fun `default - with local changes - addLocalChangesDetails false`() { 66 | val graph = listOf( 67 | Commit(sha1 = "X", parent = "j", date = 150_010_000) // <-- master, HEAD 68 | ) 69 | val localChanges = LocalChanges(3, 5, 7) 70 | val git = MockGitRepo(graph, "X", listOf("X" to "master"), localChanges, isHistoryShallowed = true) 71 | val versioner = GitVersioner(git) 72 | versioner.addLocalChangesDetails = false 73 | 74 | assertSoftly { softly -> 75 | softly.assertThat(versioner.versionCode).isEqualTo(1) 76 | softly.assertThat(versioner.versionName).isEqualTo("shallowed-SNAPSHOT") 77 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 78 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 79 | softly.assertThat(versioner.branchName).isEqualTo("master") 80 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 81 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 82 | softly.assertThat(versioner.initialCommit).isNull() 83 | softly.assertThat(versioner.localChanges).isEqualTo(localChanges) 84 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 85 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 86 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 87 | } 88 | } 89 | 90 | @Test 91 | fun `default - without local changes information`() { 92 | val graph = listOf( 93 | Commit(sha1 = "X", parent = "j", date = 150_010_000) // <-- master, HEAD 94 | ) 95 | 96 | val localChanges = LocalChanges(3, 5, 7) 97 | val git = MockGitRepo(graph, "X", listOf("X" to "master"), localChanges, isHistoryShallowed = true) 98 | val versioner = GitVersioner(git) 99 | versioner.addLocalChangesDetails = false 100 | versioner.addSnapshot = false 101 | 102 | assertSoftly { softly -> 103 | softly.assertThat(versioner.versionCode).isEqualTo(1) 104 | softly.assertThat(versioner.versionName).isEqualTo("shallowed") 105 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 106 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 107 | softly.assertThat(versioner.branchName).isEqualTo("master") 108 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 109 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 110 | softly.assertThat(versioner.initialCommit).isNull() 111 | softly.assertThat(versioner.localChanges).isEqualTo(localChanges) 112 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 113 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 114 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 115 | } 116 | } 117 | 118 | @Test 119 | fun `default - with local changes`() { 120 | val graph = listOf( 121 | Commit(sha1 = "X", parent = "j", date = 150_010_000) // <-- master, HEAD 122 | ) 123 | 124 | val localChanges = LocalChanges(3, 5, 7) 125 | val git = MockGitRepo(graph, "X", listOf("X" to "master"), localChanges, isHistoryShallowed = true) 126 | val versioner = GitVersioner(git) 127 | 128 | assertSoftly { softly -> 129 | softly.assertThat(versioner.versionCode).isEqualTo(1) 130 | softly.assertThat(versioner.versionName).isEqualTo("shallowed-SNAPSHOT(3 +5 -7)") 131 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 132 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 133 | softly.assertThat(versioner.branchName).isEqualTo("master") 134 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 135 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 136 | softly.assertThat(versioner.initialCommit).isNull() 137 | softly.assertThat(versioner.localChanges).isEqualTo(localChanges) 138 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 139 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 140 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 141 | } 142 | } 143 | 144 | @Test 145 | fun `base branch not in history`() { 146 | val graph = listOf( 147 | Commit(sha1 = "X", parent = "j", date = 150_010_000) // <-- master, HEAD 148 | ) 149 | 150 | val git = MockGitRepo(graph, "X", listOf("X" to "master"), isHistoryShallowed = true) 151 | val versioner = GitVersioner(git).apply { 152 | baseBranch = "develop" 153 | } 154 | 155 | assertSoftly { softly -> 156 | softly.assertThat(versioner.versionCode).isEqualTo(1) 157 | softly.assertThat(versioner.versionName).isEqualTo("shallowed-master") 158 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 159 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 160 | softly.assertThat(versioner.branchName).isEqualTo("master") 161 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 162 | softly.assertThat(versioner.baseBranch).isEqualTo("develop") 163 | softly.assertThat(versioner.initialCommit).isNull() 164 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 165 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 166 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 167 | 168 | // no commit in both HEAD history and develop because develop is not part of the graph 169 | softly.assertThat(versioner.featureBranchOriginCommit).isNull() 170 | } 171 | } 172 | 173 | @Test 174 | fun `on orphan initial commit`() { 175 | val graph = listOf( 176 | Commit(sha1 = "X", parent = null, date = 150_010_000) // <-- HEAD, orphan 177 | ) 178 | 179 | val git = MockGitRepo(graph, "X", branchHeads = listOf("X" to "orphan"), isHistoryShallowed = true) 180 | val versioner = GitVersioner(git) 181 | 182 | assertSoftly { softly -> 183 | softly.assertThat(versioner.versionCode).isEqualTo(1) 184 | softly.assertThat(versioner.versionName).isEqualTo("shallowed-orphan") 185 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 186 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 187 | softly.assertThat(versioner.branchName).isEqualTo("orphan") 188 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 189 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 190 | softly.assertThat(versioner.initialCommit).isNull() 191 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 192 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 193 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 194 | softly.assertThat(versioner.featureBranchOriginCommit).isNull() 195 | } 196 | } 197 | 198 | @Test 199 | fun `on orphan few commits`() { 200 | val graph = listOf( 201 | Commit(sha1 = "X", parent = "b'", date = 150_030_000) // <-- HEAD, feature/x 202 | ) 203 | 204 | val git = MockGitRepo(graph, "X", listOf("X" to "feature/x"), isHistoryShallowed = true) 205 | val versioner = GitVersioner(git) 206 | 207 | assertSoftly { softly -> 208 | softly.assertThat(versioner.versionCode).isEqualTo(1) 209 | softly.assertThat(versioner.versionName).isEqualTo("shallowed-x") 210 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 211 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 212 | softly.assertThat(versioner.branchName).isEqualTo("feature/x") 213 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 214 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 215 | softly.assertThat(versioner.initialCommit).isNull() 216 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 217 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 218 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 219 | softly.assertThat(versioner.featureBranchOriginCommit).isNull() 220 | } 221 | } 222 | 223 | @Test 224 | fun `first commit - no parent`() { 225 | val graph = listOf( 226 | Commit(sha1 = "X", parent = null, date = 150_006_000) // <-- master, HEAD 227 | ) 228 | 229 | val git = MockGitRepo(graph, "X", listOf("X" to "master"), isHistoryShallowed = true) 230 | val versioner = GitVersioner(git) 231 | 232 | assertSoftly { softly -> 233 | softly.assertThat(versioner.versionCode).isEqualTo(1) 234 | softly.assertThat(versioner.versionName).isEqualTo("shallowed") 235 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 236 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 237 | softly.assertThat(versioner.branchName).isEqualTo("master") 238 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 239 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 240 | softly.assertThat(versioner.initialCommit).isNull() 241 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 242 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 243 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 244 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 245 | } 246 | } 247 | 248 | @Test 249 | fun `short sha1`() { 250 | val graph = listOf( 251 | Commit(sha1 = "abcdefghijkl", parent = null, date = 150_006_000) // <-- master, HEAD 252 | ) 253 | 254 | val git = MockGitRepo(graph, "abcdefghijkl", listOf("abcdefghijkl" to "master"), isHistoryShallowed = true) 255 | val versioner = GitVersioner(git) 256 | 257 | assertSoftly { softly -> 258 | softly.assertThat(versioner.versionCode).isEqualTo(1) 259 | softly.assertThat(versioner.versionName).isEqualTo("shallowed") 260 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 261 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 262 | softly.assertThat(versioner.branchName).isEqualTo("master") 263 | softly.assertThat(versioner.currentSha1).isEqualTo("abcdefghijkl") 264 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 265 | softly.assertThat(versioner.initialCommit).isNull() 266 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 267 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 268 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 269 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("abcdefghijkl") 270 | } 271 | 272 | assertThat(versioner.currentSha1Short).isEqualTo("abcdefg").hasSize(7) 273 | } 274 | 275 | @Test 276 | fun `no commits`() { 277 | val git = MockGitRepo(isHistoryShallowed = true) // git initialized but nothing committed 278 | val versioner = GitVersioner(git) 279 | 280 | assertSoftly { softly -> 281 | softly.assertThat(versioner.versionCode).isEqualTo(1) 282 | softly.assertThat(versioner.versionName).isEqualTo("shallowed-undefined") 283 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 284 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 285 | softly.assertThat(versioner.branchName).isNull() 286 | softly.assertThat(versioner.currentSha1).isNull() 287 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 288 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 289 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 290 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 291 | softly.assertThat(versioner.featureBranchOriginCommit).isNull() 292 | } 293 | } 294 | 295 | @Test 296 | fun `no branch name - sha1 fallback`() { 297 | val graph = listOf( 298 | Commit(sha1 = "X", parent = "j", date = 150_010_000) // <-- HEAD 299 | ) 300 | 301 | val git = MockGitRepo(graph, "X", isHistoryShallowed = true) 302 | val versioner = GitVersioner(git) 303 | 304 | assertSoftly { softly -> 305 | softly.assertThat(versioner.versionCode).isEqualTo(1) 306 | softly.assertThat(versioner.versionName).isEqualTo("shallowed-X") 307 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 308 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 309 | softly.assertThat(versioner.branchName).isNull() 310 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 311 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 312 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 313 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 314 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 315 | softly.assertThat(versioner.featureBranchOriginCommit).isNull() 316 | } 317 | } 318 | 319 | @Test 320 | fun `default - branchname from ci`() { 321 | val graph = listOf( 322 | Commit(sha1 = "X", parent = "j", date = 150_010_000) // <-- HEAD, master 323 | ) 324 | 325 | val git = object : MockGitRepo(graph, "X", listOf("X" to "master"), isHistoryShallowed = true) { 326 | // explicitly checked out sha1 not branch 327 | override val currentBranch: String? = null 328 | } 329 | val versioner = GitVersioner(git) 330 | versioner.ciBranchNameProvider = { "nameFromCi" } 331 | 332 | assertSoftly { softly -> 333 | softly.assertThat(versioner.versionCode).isEqualTo(1) 334 | softly.assertThat(versioner.versionName).isEqualTo("shallowed-nameFromCi") 335 | softly.assertThat(versioner.baseBranchCommitCount).isEqualTo(0) 336 | softly.assertThat(versioner.featureBranchCommitCount).isEqualTo(0) 337 | softly.assertThat(versioner.branchName).isEqualTo("nameFromCi") 338 | softly.assertThat(versioner.currentSha1).isEqualTo("X") 339 | softly.assertThat(versioner.baseBranch).isEqualTo("master") 340 | softly.assertThat(versioner.localChanges).isEqualTo(NO_CHANGES) 341 | softly.assertThat(versioner.yearFactor).isEqualTo(1000) 342 | softly.assertThat(versioner.timeComponent).isEqualTo(0) 343 | softly.assertThat(versioner.featureBranchOriginCommit).isEqualTo("X") 344 | } 345 | } 346 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/passsy/gradle-gitVersioner-plugin/fddb722e024ccaad2edf3b5bbbe0a22d43caa234/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin or MSYS, switch paths to Windows format before running java 129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=$((i+1)) 158 | done 159 | case $i in 160 | (0) set -- ;; 161 | (1) set -- "$args0" ;; 162 | (2) set -- "$args0" "$args1" ;; 163 | (3) set -- "$args0" "$args1" "$args2" ;; 164 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=$(save "$@") 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 184 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 185 | cd "$(dirname "$0")" 186 | fi 187 | 188 | exec "$JAVACMD" "$@" 189 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':gitversioner' --------------------------------------------------------------------------------