Skip to content

Commit 7b6556a

Browse files
committed
ops(ci): conventional-commits based release versions
- added enforcing of conventional commits - project version is now set by axion-release gradle plugin, configured to extract the version based on the commit history see https://axion-release-plugin.readthedocs.io/en/latest/
1 parent ff434a2 commit 7b6556a

File tree

6 files changed

+205
-13
lines changed

6 files changed

+205
-13
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: Conventional Commits
2+
3+
on:
4+
pull_request:
5+
types: [opened, edited, synchronize]
6+
7+
jobs:
8+
conventional-commits:
9+
runs-on: ubuntu-latest
10+
name: Validate Conventional Commits
11+
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v4
15+
with:
16+
fetch-depth: 0
17+
18+
- name: Validate PR title follows conventional commits
19+
uses: amannn/action-semantic-pull-request@v5
20+
env:
21+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22+
with:
23+
types: |
24+
feat
25+
fix
26+
docs
27+
style
28+
refactor
29+
perf
30+
test
31+
build
32+
ci
33+
chore
34+
requireScope: false
35+
disallowScopes: |
36+
release
37+
subjectPattern: ^(?![A-Z]).+$
38+
subjectPatternError: |
39+
The subject "{subject}" found in the pull request title "{title}"
40+
didn't match the configured pattern. Please ensure that the subject
41+
doesn't start with an uppercase character.
42+
wip: true
43+
validateSingleCommit: false
44+
45+
- name: Validate individual commit messages
46+
run: |
47+
# Get all commits in this PR
48+
git log --format="%H %s" origin/${{ github.base_ref }}..HEAD > commits.txt
49+
50+
# Check each commit message
51+
while IFS= read -r line; do
52+
commit_hash=$(echo "$line" | cut -d' ' -f1)
53+
commit_msg=$(echo "$line" | cut -d' ' -f2-)
54+
55+
echo "Checking commit: $commit_hash"
56+
echo "Message: $commit_msg"
57+
58+
# Validate conventional commit format
59+
if ! echo "$commit_msg" | grep -E '^(feat|fix|docs|style|refactor|perf|test|build|ci|chore)(\(.+\))?: .+$'; then
60+
echo "❌ Commit $commit_hash does not follow conventional commits format:"
61+
echo " Message: $commit_msg"
62+
echo " Expected: type(scope): description"
63+
echo " Example: feat(auth): add user login functionality"
64+
exit 1
65+
fi
66+
67+
echo "✅ Commit $commit_hash follows conventional commits"
68+
done < commits.txt
69+
70+
echo "🎉 All commits follow conventional commits format!"

.github/workflows/release.yml

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,20 @@ jobs:
2222
steps:
2323
- name: Checkout
2424
uses: actions/checkout@v4
25+
with:
26+
fetch-depth: 0 # Required for axion-release to read git history
27+
28+
- name: Determine version and create release
29+
run: |
30+
CURRENT_VERSION=$(./gradlew -q currentVersion)
31+
echo "Current version: $CURRENT_VERSION"
32+
33+
if [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" ]]; then
34+
echo "📋 Manual trigger - creating new release"
35+
./gradlew markNextVersion
36+
else
37+
echo "🏷️ Tag trigger - version already determined by tag"
38+
fi
2539
2640
- name: Setup Java
2741
uses: actions/setup-java@v4
@@ -69,10 +83,6 @@ jobs:
6983
# Use the built-in GitHub token for GitHub release
7084
echo "JRELEASER_GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV
7185
72-
# Build the project & publish Gradle publications (if you have a local repo configured)
73-
- name: Build
74-
run: ./gradlew --no-daemon clean build
75-
7686
# sanity checks before the real release
7787
- name: JReleaser dry run checks
7888
run: ./gradlew --no-daemon jreleaserConfig jreleaserAssemble jreleaserChangelog

.github/workflows/update-gradle-wrapper.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Update Gradle Wrapper
33
on:
44
workflow_dispatch:
55
schedule:
6-
- cron: "0 0 * * *"
6+
# - cron: "0 0 * * *" disabled for now, very noisey
77

88
jobs:
99
update-gradle-wrapper:

build.gradle.kts

Lines changed: 115 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import org.gradle.api.tasks.testing.logging.TestLogEvent.PASSED
77
import org.gradle.api.tasks.testing.logging.TestLogEvent.SKIPPED
88
import org.gradle.api.tasks.testing.logging.TestLogging
99
import org.gradle.api.tasks.testing.logging.TestStackTraceFilter
10+
import pl.allegro.tech.build.axion.release.domain.VersionConfig
1011
import ru.vyarus.gradle.plugin.python.PythonExtension
1112

1213
plugins {
@@ -21,7 +22,120 @@ plugins {
2122
.get()
2223
.pluginId,
2324
)
24-
id("ru.vyarus.mkdocs-build") version "3.0.0"
25+
alias(libs.plugins.mkdocs.build)
26+
alias(libs.plugins.axion.release)
27+
}
28+
29+
// set version based on conventional commit history
30+
scmVersion {
31+
tag {
32+
prefix.set("v")
33+
versionSeparator.set("")
34+
}
35+
36+
// Use predefined version creator that handles SNAPSHOT automatically
37+
versionCreator("simple")
38+
39+
// Custom version incrementer based on conventional commits
40+
versionIncrementer { context ->
41+
val git =
42+
org.eclipse.jgit.api.Git
43+
.open(project.rootDir)
44+
try {
45+
val lastTagDesc =
46+
try {
47+
git.describe().setTags(true).call()
48+
} catch (_: Exception) {
49+
null
50+
}
51+
val lastTagName = lastTagDesc?.substringBefore("-")
52+
val repo = git.repository
53+
val head = repo.resolve("HEAD")
54+
val lastTagCommit = lastTagName?.let { repo.resolve("refs/tags/$it^{commit}") }
55+
56+
val commits =
57+
if (lastTagCommit != null && head != null) {
58+
git
59+
.log()
60+
.addRange(lastTagCommit, head)
61+
.call()
62+
.toList()
63+
} else {
64+
// If no tag exists yet, use all commits but guard against empty repo
65+
if (head != null) {
66+
git
67+
.log()
68+
.add(head)
69+
.call()
70+
.toList()
71+
} else {
72+
emptyList()
73+
}
74+
}
75+
76+
var hasMajor = false
77+
var hasMinor = false
78+
var hasPatch = false
79+
80+
val typeRegex = Regex("""^(?<type>\w+)(\([^)]*\))?(?<bang>!)?:\s""", RegexOption.IGNORE_CASE)
81+
val breakingFooter = Regex("""(?im)^BREAKING[ -]CHANGE:""")
82+
83+
for (commit in commits) {
84+
val full = commit.fullMessage.trim()
85+
val subject = full.lineSequence().firstOrNull().orEmpty()
86+
val m = typeRegex.find(subject)
87+
val type =
88+
m
89+
?.groups
90+
?.get("type")
91+
?.value
92+
?.lowercase()
93+
val bang = m?.groups?.get("bang") != null
94+
val breaking = bang || breakingFooter.containsMatchIn(full)
95+
96+
when {
97+
breaking -> hasMajor = true
98+
type == "feat" -> hasMinor = true
99+
type in
100+
setOf(
101+
"fix",
102+
"perf",
103+
"refactor",
104+
"revert",
105+
"docs",
106+
"build",
107+
"chore",
108+
"test",
109+
"style",
110+
"ci",
111+
"task",
112+
)
113+
-> hasPatch = true
114+
}
115+
}
116+
117+
val v = context.currentVersion
118+
if (commits.isEmpty()) {
119+
// No commits since last tag → no bump (leave as-is)
120+
return@versionIncrementer v
121+
}
122+
123+
when {
124+
hasMajor -> if (v.majorVersion() == 0L) v.nextMinorVersion() else v.nextMajorVersion()
125+
hasMinor -> v.nextMinorVersion()
126+
hasPatch -> v.nextPatchVersion()
127+
else -> v.nextPatchVersion() // commits present, but no signal → patch
128+
}
129+
} finally {
130+
git.close()
131+
}
132+
}
133+
}
134+
version = scmVersion.version
135+
136+
allprojects {
137+
group = "io.github.flaxoos"
138+
version = rootProject.version
25139
}
26140

27141
jreleaser {
@@ -114,11 +228,6 @@ tasks.jreleaserAssemble {
114228
)
115229
}
116230

117-
allprojects {
118-
group = "io.github.flaxoos"
119-
version = project.property("version") as String
120-
}
121-
122231
subprojects {
123232
tasks.find { it.name == "build" }?.dependsOn(tasks.named("ktlintFormat"))
124233

gradle.properties

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ github.repository.name=extra-ktor-plugins
33
kotlin.native.cacheKind.linuxX64=none
44
kotlin.native.ignoreDisabledTargets=true
55
gradle.publish.enable.module-metadata=true
6-
version=2.2.2
76
gpr.user=flaxoos
87
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=2g
98
kotlin.mpp.applyDefaultHierarchyTemplate=false

gradle/libs.versions.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ gradle-release = "3.0.2"
7272
# Publishing
7373
nexusPublish = "2.0.0"
7474
jreleaser = "1.20.0"
75+
axion-release = "1.20.1"
76+
mkdocs-build = "3.0.0"
7577

7678
# Miscellaneous
7779
krontab = "2.7.2"
@@ -232,5 +234,7 @@ kmock = { id = "tech.antibytes.kmock.kmock-gradle", version.ref = "kmock" }
232234
# Github
233235
gradle-release = { id = "net.researchgate.release", version.ref = "gradle-release" }
234236

235-
# Nexus
237+
# Publishing and Release
236238
jreleaser = { id = "org.jreleaser", version.ref = "jreleaser" }
239+
axion-release = { id = "pl.allegro.tech.build.axion-release", version.ref = "axion-release" }
240+
mkdocs-build = { id = "ru.vyarus.mkdocs-build", version.ref = "mkdocs-build" }

0 commit comments

Comments
 (0)