Skip to content

Commit d339919

Browse files
committed
Adding refs/remotes/origin to the list of branches which are treated as release
1 parent 8c0d0b5 commit d339919

File tree

6 files changed

+102
-30
lines changed

6 files changed

+102
-30
lines changed

core/src/main/kotlin/com/akuleshov7/vercraft/core/Branch.kt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ public class Branch(git: Git, public val ref: Ref) {
1010
/**
1111
* Counts the number of commits (from the end) which were made in branch after the [[startCommit]]. For example:
1212
* 1 -> 2 -> 3 -> 4 -> latest
13+
* + -> + -> v0 -> v1 -> v2
1314
* commitNumberAfterThis(3) == 2
1415
*/
1516
public fun numberOfCommitsAfter(startCommit: RevCommit): Int {
1617
var count = 0
17-
gitLog.reversed().forEach { commitInBranch ->
18+
// gitLog is always reverted from the last commit to the first one
19+
gitLog.forEach { commitInBranch ->
1820
if (commitInBranch.id.name != startCommit.id.name) {
1921
++count
2022
} else {
@@ -36,9 +38,14 @@ public class Branch(git: Git, public val ref: Ref) {
3638
* The base commit is 2.
3739
*/
3840
public fun findBaseCommitIn(sourceBase: Branch): RevCommit? {
39-
this.gitLog.reversed().forEach { commitInSub ->
40-
// lastOrNull is optimized to make search from the end
41-
val thisCommitInMainBranch = sourceBase.gitLog.lastOrNull { commitInSub.id.name == it.id.name }
41+
// (!) gitLog is always in a reversed order (from last to first commit):
42+
// 4 3 2 1
43+
// 6 5 2
44+
// ^ 6 not found
45+
// ^ 5 not found
46+
// ^ 2 - is a common commit
47+
this.gitLog.forEach { commitInSub ->
48+
val thisCommitInMainBranch = sourceBase.gitLog.firstOrNull { commitInSub.id.name == it.id.name }
4249
if (thisCommitInMainBranch != null) {
4350
return thisCommitInMainBranch
4451
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.akuleshov7.vercraft.core
2+
3+
import org.eclipse.jgit.transport.CredentialItem
4+
import org.eclipse.jgit.transport.CredentialsProvider
5+
import org.eclipse.jgit.transport.URIish
6+
7+
public object LocalCredentialsProvider : CredentialsProvider() {
8+
override fun isInteractive(): Boolean = false
9+
10+
override fun supports(vararg items: CredentialItem?): Boolean = true
11+
12+
override fun get(uri: URIish?, vararg items: CredentialItem?): Boolean {
13+
// Let JGit use system credentials (e.g., SSH agent or ~/.git-credentials)
14+
return true
15+
}
16+
}

core/src/main/kotlin/com/akuleshov7/vercraft/core/Releases.kt

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ internal const val RELEASE_PREFIX = "release"
1616
*
1717
* TODO: add configuration for remotes other than 'origin'
1818
*/
19-
internal fun String.shortName() = Repository.shortenRefName(this).substringAfterLast(Constants.DEFAULT_REMOTE_NAME + "/")
19+
internal fun String.shortName() =
20+
Repository.shortenRefName(this).substringAfterLast(Constants.DEFAULT_REMOTE_NAME + "/")
21+
2022
internal fun String.removeReleasePrefix() = this.substringAfterLast("$RELEASE_PREFIX/")
2123
internal fun String.hasReleasePrefix() = this.startsWith("$RELEASE_PREFIX/")
2224

@@ -39,7 +41,7 @@ public class Releases public constructor(private val git: Git) {
3941
try {
4042
git.fetch().call()
4143
} catch (e: TransportException) {
42-
logger.warn("(!) Not able to fetch remote repository <${e.message}>, will proceed with local snapshot")
44+
logger.warn("(!) Not able to fetch remote repository <${e.message}>, will proceed with local snapshot.")
4345
}
4446
}
4547

@@ -58,6 +60,7 @@ public class Releases public constructor(private val git: Git) {
5860
public fun getLatestReleaseBranch(): ReleaseBranch? =
5961
releaseBranches.maxByOrNull { it.version }
6062

63+
// TODO: Not to create a release if we are now on main and on this commit there is already a release branch made
6164
public fun createNewRelease(releaseType: SemVerReleaseType): String {
6265
val newVersion = getLatestReleaseBranch()
6366
?.version
@@ -67,7 +70,7 @@ public class Releases public constructor(private val git: Git) {
6770
if (currentCheckoutBranch != mainBranch) {
6871
throw IllegalStateException(
6972
"(!) Branch which is currently checked out is [${currentCheckoutBranch.ref.name}], " +
70-
"but ${releaseType.name} release should be done from [${mainBranch.ref.name}] branch. " +
73+
"but ${releaseType.name} release should always be done from [${mainBranch.ref.name}] branch. " +
7174
"Because during the release VerCraft will create a new branch and tag."
7275
)
7376
} else {
@@ -79,7 +82,9 @@ public class Releases public constructor(private val git: Git) {
7982
// FIXME: need to switch to latest release branch and latest commit and set release tag there
8083
} else {
8184
createBranch(newVersion)
85+
pushBranch(newVersion)
8286
createTag(newVersion)
87+
pushTag(newVersion)
8388
}
8489
}
8590
return "$newVersion"
@@ -91,21 +96,22 @@ public class Releases public constructor(private val git: Git) {
9196
"(!) The branch with the version [$version] which was selected for " +
9297
"the new release already exists. No branches will be created, please change the version."
9398
)
94-
9599
} else {
96100
createBranch(version)
101+
pushBranch(version)
97102
createTag(version)
103+
pushTag(version)
98104
}
99105
return version.toString()
100106
}
101107

102108
private fun createTag(newVersion: SemVer) {
103109
git.tag()
104-
.setName(newVersion.toString())
110+
.setName("v${newVersion}")
105111
.setMessage("Release $newVersion")
106112
.call()
107113

108-
logger.warn("+ Created a tag [Release $newVersion]")
114+
logger.warn("+ Created a tag v$newVersion [Release $newVersion]")
109115
}
110116

111117
private fun createBranch(newVersion: SemVer) {
@@ -117,6 +123,32 @@ public class Releases public constructor(private val git: Git) {
117123
logger.warn("+ Created a branch [release/$newVersion]")
118124
}
119125

126+
private fun pushBranch(newVersion: SemVer) {
127+
try {
128+
git.push()
129+
.setCredentialsProvider(LocalCredentialsProvider)
130+
.add("release/$newVersion")
131+
.call()
132+
133+
logger.warn("+ Pushed a branch [release/$newVersion]")
134+
} catch (e: TransportException) {
135+
logger.warn("(!) Not able to push branch to remote repository <${e.message}>, please do it manually.")
136+
}
137+
}
138+
139+
private fun pushTag(newVersion: SemVer) {
140+
try {
141+
git.push()
142+
.setCredentialsProvider(LocalCredentialsProvider)
143+
.add("refs/tags/v$newVersion")
144+
.call()
145+
146+
logger.warn("+ Pushed a tag v$newVersion [Release $newVersion]")
147+
} catch (e: TransportException) {
148+
logger.warn("(!) Not able to push tag to remote repository <${e.message}>, please do it manually.")
149+
}
150+
}
151+
120152
/**
121153
* We have two sources for release branches: they can be created locally or can be taken from `remotes/origin`
122154
*/
@@ -126,16 +158,20 @@ public class Releases public constructor(private val git: Git) {
126158
val releaseBranchesFromRemote = getAndFilterReleaseBranches(git.branchList().setListMode(REMOTE))
127159
val localReleaseBranches = getAndFilterReleaseBranches(git.branchList().setListMode(null))
128160

129-
// we will union LOCAL branches with REMOTE, with a priority to LOCAL
161+
// we will make a union of LOCAL branches and REMOTE, with a priority to LOCAL
130162
val allReleaseBranches = (localReleaseBranches + releaseBranchesFromRemote)
131163
.groupBy { it.branch.ref.name.shortName() }
132164

133165
allReleaseBranches.keys.forEach {
134-
if(allReleaseBranches[it]!!.size > 1) {
135-
if(allReleaseBranches[it]!![0].branch.gitLog != allReleaseBranches[it]!![1].branch.gitLog) {
166+
val value = allReleaseBranches[it]
167+
if (value!!.size > 1) {
168+
if (value[0].branch.gitLog != value[1].branch.gitLog) {
136169
// TODO: error when release branch is checked-out (and calculating version for it) and differs from remote
137-
logger.warn("jFYI: Remote branch $it differs from the local branch $it. " +
138-
"Do you have any unpublished changes in your local branch?")
170+
logger.warn(
171+
"(!) jFYI: Remote and local branches '$it' differ. " +
172+
"Do you have any unpublished changes in your local branch? Will use " +
173+
"local branch to calculate versions."
174+
)
139175
}
140176
}
141177
}

core/src/main/kotlin/com/akuleshov7/vercraft/core/Runner.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ public fun getVersion(gitPath: File): String {
1010
Git.open(gitPath).use { git ->
1111
val releases = Releases(git)
1212
val resultedVer = releases.version.calc()
13-
logger.warn("VERsion CRAFTED: $resultedVer")
13+
logger.warn(">> VERsion CRAFTED: $resultedVer <<")
1414
return resultedVer.toString()
1515
}
1616
}
1717

1818
public fun createRelease(gitPath: File, semVerReleaseType: SemVerReleaseType): String {
1919
Git.open(gitPath).use { git ->
2020
val version = Releases(git).createNewRelease(semVerReleaseType)
21-
logger.warn("Successfully \"VerCrafted\" the release [$version]")
21+
logger.warn(">> \"VerCrafted\" the release [$version] <<")
2222
return version
2323
}
2424
}
@@ -32,5 +32,5 @@ public fun createRelease(gitPath: File, version: SemVer) {
3232

3333

3434
public fun main() {
35-
getVersion(File("../data-platform"))
35+
createRelease(File("../data-platform"), SemVerReleaseType.MINOR)
3636
}

core/src/main/kotlin/com/akuleshov7/vercraft/core/SemVer.kt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package com.akuleshov7.vercraft.core
22

33
import com.akuleshov7.vercraft.core.SemVerReleaseType.*
44

5+
internal const val NO_MAJOR = -1
6+
internal const val NO_MINOR = -1
57

68
public enum class SemVerReleaseType {
79
MAJOR,
@@ -24,6 +26,7 @@ public class SemVer : Comparable<SemVer> {
2426
public val major: Int
2527
public val minor: Int
2628
public val patch: Int
29+
public var prefix: String = ""
2730
private var postfix: String = ""
2831

2932
public constructor(ver: String) {
@@ -40,7 +43,6 @@ public class SemVer : Comparable<SemVer> {
4043
this.major = major
4144
this.minor = minor
4245
this.patch = patch
43-
4446
}
4547

4648
public override operator fun compareTo(other: SemVer): Int {
@@ -73,7 +75,12 @@ public class SemVer : Comparable<SemVer> {
7375
}
7476

7577
override fun toString(): String {
76-
return "$major.$minor.$patch${if (postfix != "") "-$postfix" else ""}"
78+
val major = if (this.major == NO_MAJOR) "" else "${this.major}."
79+
val minor = if (this.minor == NO_MINOR) "" else "${this.minor}."
80+
81+
return (if (prefix != "") "$prefix-" else "") +
82+
"$major$minor${this.patch}" +
83+
(if (postfix != "") "-$postfix" else "")
7784
}
7885

7986
public fun nextVersion(nextVersion: SemVerReleaseType): SemVer = when (nextVersion) {
@@ -89,6 +96,11 @@ public class SemVer : Comparable<SemVer> {
8996
return this
9097
}
9198

99+
public fun setPrefix(prefix: String): SemVer {
100+
this.prefix = prefix
101+
return this
102+
}
103+
92104
override fun hashCode(): Int {
93105
var result = major.hashCode()
94106
result = 31 * result + minor.hashCode()

core/src/main/kotlin/com/akuleshov7/vercraft/core/VersionCalculator.kt

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,14 @@ public class VersionCalculator(
3232
*
3333
* aaa -> bbb (release/0.1.0) -> xxx -> yyy (?)
3434
*
35-
* The version for commit yyy is derived by adding the number of commits between
36-
* commits bbb and yyy (in this case, 2 commits) to the incremented MINOR version of the
37-
* last release version (0.1.0). Therefore, the resulting version for (yyy) will be 0.2.1.
35+
* The version for commit yyy is derived by:
36+
* 1) incremented MINOR version of the last release version (0.1.0)
37+
* 2) incrementing PATCH version by the number of commits between commits bbb and yyy (in this case, 2 commits).
38+
* Therefore, the resulting version for (yyy) will be 0.2.1.
3839
*
39-
* (!) Additionally, the version will be appended with a postfix consisting of
40-
* the first 5 characters of the commit hash and "-rc". So the result will be as following:
41-
* aaa -> bbb (release/0.1.0) -> 0.2.0-hash-rc -> 0.2.1-hash-rc (?)
40+
* (!) Additionally, to avoid the confusion with releases, the version will be appended with a postfix consisting of
41+
* "-main" and the first 5 characters of the commit hash. So the result will be as following:
42+
* aaa -> bbb (release/0.1.0) -> 0.2.0-main+hash -> 0.2.1-main+hash (?)
4243
*/
4344
private fun calcVersionInMain(): SemVer {
4445
val latestRelease = releases.getLatestReleaseBranch()
@@ -54,7 +55,7 @@ public class VersionCalculator(
5455
latestRelease.version
5556
.nextVersion(SemVerReleaseType.MINOR)
5657
.incrementPatchVersion(distance)
57-
.setPostFix("rc+$shortedHashCode")
58+
.setPostFix("$MAIN_BRANCH_NAME+$shortedHashCode")
5859
}
5960
?: run { SemVer(0, 0, distance) }
6061
}
@@ -102,12 +103,12 @@ public class VersionCalculator(
102103
* (where the branch diverged from the main branch) and the current commit. This distance is used as the PATCH version,
103104
* while the MAJOR and MINOR versions are set to 0 (resulting in a version format of 0.0.x).
104105
*
105-
* (!) Additionally, the version will include a postfix composed of:
106+
* (!) Additionally, the version will include:
106107
* - The last segment of the branch name (substring after the final "/").
107108
* - The current date in "yyyy-MM-dd" format.
108109
*
109110
* For example, if the branch is "feature/blabla" and the commit distance is 1,
110-
* the version will be: "0.0.1-blabla-2024-12-24".
111+
* the version will be: "2024-12-24-blabla-1". With such version the clean-up of useless branch builds will be easier.
111112
*/
112113
private fun calcVersionInBranch(): SemVer {
113114
// replace all special symbols except letters and digits from branch name and limit it to 10 symbols
@@ -125,7 +126,7 @@ public class VersionCalculator(
125126
dateFormat.timeZone = TimeZone.getDefault()
126127
val formattedDate = dateFormat.format(Date(commit.commitTime * 1000L))
127128

128-
return SemVer(0, 0, distance + 1).setPostFix("$branch+$formattedDate")
129+
return SemVer(NO_MAJOR, NO_MINOR, distance + 1).setPrefix("$formattedDate-$branch")
129130
}
130131
}
131132

0 commit comments

Comments
 (0)