From b6d95f647132e1b612a552f2cc9d9b83b7dd88a8 Mon Sep 17 00:00:00 2001
From: Rene R
Date: Mon, 2 Feb 2026 18:13:42 +0100
Subject: [PATCH 1/4] :recycle: refactor model to records in addtional project
---
coverage/pom.xml | 5 +
pom.xml | 1 +
semver-analyzer-api/pom.xml | 2 +-
.../semver/analyzer/CommitAnalyzer.java | 4 +-
.../semver/analyzer/model/AnalyzedCommit.java | 36 ---
.../semver/analyzer/model/Configuration.java | 1 +
.../analyzer/model/ConfigurationTest.java | 31 +-
.../analyzer/ConventionalCommitAnalyzer.java | 77 +++--
.../ConventionalCommitAnalyzerTest.java | 142 ++++-----
.../analyzer/GitMojiCommitAnalyzer.java | 81 ++---
.../analyzer/GitMojiCommitAnalyzerTest.java | 129 ++++----
.../semver/changelog/ChangelogRenderer.java | 4 +-
.../sam42r/semver/changelog/HtmlRenderer.java | 4 +-
.../semver/changelog/HtmlRendererTest.java | 93 ++++--
.../semver/changelog/MarkupRenderer.java | 8 +-
.../semver/changelog/MarkupRendererTest.java | 47 +--
semver-maven-model/pom.xml | 41 +++
.../semver/model/analyze/AnalyzedCommit.java | 26 ++
.../semver/model/analyze}/ChangeCategory.java | 2 +-
.../sam42r/semver/model/analyze/Issue.java | 4 +
.../model/analyze}/SemVerChangeLevel.java | 2 +-
.../semver/model/changelog}/VersionInfo.java | 2 +-
.../semver/model/release/ReleaseInfo.java | 6 +
.../sam42r/semver/model/scm/Commit.java | 6 +
.../sam42r/semver/model/scm/Remote.java | 34 +--
.../github/sam42r/semver/model/scm/Tag.java | 4 +
.../sam42r/semver/model/scm/RemoteTest.java | 33 ++
semver-maven-plugin/pom.xml | 6 +
.../sam42r/semver/SemanticReleaseMojo.java | 36 +--
.../semver/util/TagVersionComparator.java | 6 +-
.../sam42r/semver/util/BundleHelper.java | 1 +
.../semver/util/TagVersionComparatorTest.java | 20 +-
semver-release-api/pom.xml | 5 +
.../semver/release/ReleasePublisher.java | 2 +-
.../semver/release/model/ReleaseInfo.java | 20 --
.../release/DefaultGithubPublisher.java | 8 +-
.../semver/release/GithubPublisherTest.java | 28 +-
.../semver/release/GitlabPublisher.java | 8 +-
.../semver/release/GitlabPublisherTest.java | 26 +-
semver-scm-api/pom.xml | 6 +
.../semver/scm/AbstractScmProvider.java | 29 +-
.../github/sam42r/semver/scm/SCMProvider.java | 6 +-
.../sam42r/semver/scm/model/Commit.java | 20 --
.../sam42r/semver/scm/model/Remote.java | 19 --
.../github/sam42r/semver/scm/model/Tag.java | 16 -
.../semver/scm/util/RemoteUtilTest.java | 44 ---
.../github/sam42r/semver/scm/GitProvider.java | 281 ------------------
.../sam42r/semver/scm/GitProviderFactory.java | 22 --
.../semver/scm/AbstractGitProviderTest.java | 130 --------
.../semver/scm/DefaultGitProviderTest.java | 126 +++++++-
.../sam42r/semver/scm/GitProviderTest.java | 29 --
.../github/sam42r/semver/scm/HgProvider.java | 6 +-
.../github/sam42r/semver/scm/SvnProvider.java | 6 +-
53 files changed, 677 insertions(+), 1054 deletions(-)
delete mode 100644 semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/model/AnalyzedCommit.java
create mode 100644 semver-maven-model/pom.xml
create mode 100644 semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/AnalyzedCommit.java
rename {semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/model => semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze}/ChangeCategory.java (66%)
create mode 100644 semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/Issue.java
rename {semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/model => semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze}/SemVerChangeLevel.java (88%)
rename {semver-changelog-api/src/main/java/io/github/sam42r/semver/changelog/model => semver-maven-model/src/main/java/io/github/sam42r/semver/model/changelog}/VersionInfo.java (60%)
create mode 100644 semver-maven-model/src/main/java/io/github/sam42r/semver/model/release/ReleaseInfo.java
create mode 100644 semver-maven-model/src/main/java/io/github/sam42r/semver/model/scm/Commit.java
rename semver-scm-api/src/main/java/io/github/sam42r/semver/scm/util/RemoteUtil.java => semver-maven-model/src/main/java/io/github/sam42r/semver/model/scm/Remote.java (50%)
create mode 100644 semver-maven-model/src/main/java/io/github/sam42r/semver/model/scm/Tag.java
create mode 100644 semver-maven-model/src/test/java/io/github/sam42r/semver/model/scm/RemoteTest.java
delete mode 100644 semver-release-api/src/main/java/io/github/sam24r/semver/release/model/ReleaseInfo.java
delete mode 100644 semver-scm-api/src/main/java/io/github/sam42r/semver/scm/model/Commit.java
delete mode 100644 semver-scm-api/src/main/java/io/github/sam42r/semver/scm/model/Remote.java
delete mode 100644 semver-scm-api/src/main/java/io/github/sam42r/semver/scm/model/Tag.java
delete mode 100644 semver-scm-api/src/test/java/io/github/sam42r/semver/scm/util/RemoteUtilTest.java
delete mode 100644 semver-scm-git/src/main/java/io/github/sam42r/semver/scm/GitProvider.java
delete mode 100644 semver-scm-git/src/main/java/io/github/sam42r/semver/scm/GitProviderFactory.java
delete mode 100644 semver-scm-git/src/test/java/io/github/sam42r/semver/scm/AbstractGitProviderTest.java
delete mode 100644 semver-scm-git/src/test/java/io/github/sam42r/semver/scm/GitProviderTest.java
diff --git a/coverage/pom.xml b/coverage/pom.xml
index ae2ee7a..29bd859 100644
--- a/coverage/pom.xml
+++ b/coverage/pom.xml
@@ -19,6 +19,11 @@
+
+ io.github.sam42r
+ semver-maven-model
+ ${project.version}
+
io.github.sam42r
semver-scm-api
diff --git a/pom.xml b/pom.xml
index 73e9064..b75c1ff 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,6 +15,7 @@
https://github.com/Sam42R/semver-maven-plugin
+ semver-maven-model
semver-scm-api
semver-scm-git
semver-scm-subversion
diff --git a/semver-analyzer-api/pom.xml b/semver-analyzer-api/pom.xml
index f990a94..484c578 100644
--- a/semver-analyzer-api/pom.xml
+++ b/semver-analyzer-api/pom.xml
@@ -22,7 +22,7 @@
io.github.sam42r
- semver-scm-api
+ semver-maven-model
${project.version}
diff --git a/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/CommitAnalyzer.java b/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/CommitAnalyzer.java
index 85dbb42..08be05e 100644
--- a/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/CommitAnalyzer.java
+++ b/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/CommitAnalyzer.java
@@ -1,7 +1,7 @@
package io.github.sam42r.semver.analyzer;
-import io.github.sam42r.semver.analyzer.model.AnalyzedCommit;
-import io.github.sam42r.semver.scm.model.Commit;
+import io.github.sam42r.semver.model.analyze.AnalyzedCommit;
+import io.github.sam42r.semver.model.scm.Commit;
import lombok.NonNull;
import java.util.List;
diff --git a/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/model/AnalyzedCommit.java b/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/model/AnalyzedCommit.java
deleted file mode 100644
index 99864d3..0000000
--- a/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/model/AnalyzedCommit.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package io.github.sam42r.semver.analyzer.model;
-
-import io.github.sam42r.semver.scm.model.Commit;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.NoArgsConstructor;
-import lombok.experimental.SuperBuilder;
-
-import java.util.List;
-import java.util.function.Predicate;
-
-@Data
-@SuperBuilder
-@EqualsAndHashCode(callSuper = false)
-@NoArgsConstructor
-public class AnalyzedCommit extends Commit {
-
- private String header;
- private String body;
- private String footer;
-
- private String type;
- private ChangeCategory category;
- private String scope;
- private String subject;
- private SemVerChangeLevel level;
-
- private List issues;
-
- public static final Predicate isBugfix = analyzedCommit ->
- SemVerChangeLevel.PATCH.equals(analyzedCommit.getLevel());
- public static final Predicate isFeature = analyzedCommit ->
- SemVerChangeLevel.MINOR.equals(analyzedCommit.getLevel());
- public static final Predicate isBreaking = analyzedCommit ->
- SemVerChangeLevel.MAJOR.equals(analyzedCommit.getLevel());
-}
diff --git a/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/model/Configuration.java b/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/model/Configuration.java
index 53bdf75..fc24854 100644
--- a/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/model/Configuration.java
+++ b/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/model/Configuration.java
@@ -2,6 +2,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import io.github.sam42r.semver.model.analyze.AnalyzedCommit;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
diff --git a/semver-analyzer-api/src/test/java/io/github/sam42r/semver/analyzer/model/ConfigurationTest.java b/semver-analyzer-api/src/test/java/io/github/sam42r/semver/analyzer/model/ConfigurationTest.java
index e90f595..4f82c49 100644
--- a/semver-analyzer-api/src/test/java/io/github/sam42r/semver/analyzer/model/ConfigurationTest.java
+++ b/semver-analyzer-api/src/test/java/io/github/sam42r/semver/analyzer/model/ConfigurationTest.java
@@ -1,5 +1,8 @@
package io.github.sam42r.semver.analyzer.model;
+import io.github.sam42r.semver.model.analyze.AnalyzedCommit;
+import io.github.sam42r.semver.model.analyze.ChangeCategory;
+import io.github.sam42r.semver.model.analyze.SemVerChangeLevel;
import org.junit.jupiter.api.Test;
import java.util.List;
@@ -17,13 +20,13 @@ void shouldReadConfigFromClasspath() {
Configuration::getRelease, Configuration::getItems)
.containsExactly(
"R0", List.of(
- AnalyzedCommit.builder().type("D1").category(ChangeCategory.DEPRECATED).level(SemVerChangeLevel.NONE).build(),
- AnalyzedCommit.builder().type("R1").category(ChangeCategory.REMOVED).level(SemVerChangeLevel.NONE).build(),
- AnalyzedCommit.builder().type("F1").category(ChangeCategory.FIXED).level(SemVerChangeLevel.PATCH).build(),
- AnalyzedCommit.builder().type("S1").category(ChangeCategory.SECURITY).level(SemVerChangeLevel.PATCH).build(),
- AnalyzedCommit.builder().type("A1").category(ChangeCategory.ADDED).level(SemVerChangeLevel.MINOR).build(),
- AnalyzedCommit.builder().type("C1").category(ChangeCategory.CHANGED).level(SemVerChangeLevel.MINOR).build(),
- AnalyzedCommit.builder().type("B1").category(ChangeCategory.OTHER).level(SemVerChangeLevel.MAJOR).build()
+ new AnalyzedCommit(null, null, null, null, "D1", ChangeCategory.DEPRECATED, null, null, SemVerChangeLevel.NONE, null),
+ new AnalyzedCommit(null, null, null, null, "R1", ChangeCategory.REMOVED, null, null, SemVerChangeLevel.NONE, null),
+ new AnalyzedCommit(null, null, null, null, "F1", ChangeCategory.FIXED, null, null, SemVerChangeLevel.PATCH, null),
+ new AnalyzedCommit(null, null, null, null, "S1", ChangeCategory.SECURITY, null, null, SemVerChangeLevel.PATCH, null),
+ new AnalyzedCommit(null, null, null, null, "A1", ChangeCategory.ADDED, null, null, SemVerChangeLevel.MINOR, null),
+ new AnalyzedCommit(null, null, null, null, "C1", ChangeCategory.CHANGED, null, null, SemVerChangeLevel.MINOR, null),
+ new AnalyzedCommit(null, null, null, null, "B1", ChangeCategory.OTHER, null, null, SemVerChangeLevel.MAJOR, null)
)
);
}
@@ -38,13 +41,13 @@ void shouldReadConfigFromFile() {
Configuration::getRelease, Configuration::getItems)
.containsExactly(
"R0", List.of(
- AnalyzedCommit.builder().type("D1").category(ChangeCategory.DEPRECATED).level(SemVerChangeLevel.NONE).build(),
- AnalyzedCommit.builder().type("R1").category(ChangeCategory.REMOVED).level(SemVerChangeLevel.NONE).build(),
- AnalyzedCommit.builder().type("F1").category(ChangeCategory.FIXED).level(SemVerChangeLevel.PATCH).build(),
- AnalyzedCommit.builder().type("S1").category(ChangeCategory.SECURITY).level(SemVerChangeLevel.PATCH).build(),
- AnalyzedCommit.builder().type("A1").category(ChangeCategory.ADDED).level(SemVerChangeLevel.MINOR).build(),
- AnalyzedCommit.builder().type("C1").category(ChangeCategory.CHANGED).level(SemVerChangeLevel.MINOR).build(),
- AnalyzedCommit.builder().type("B1").category(ChangeCategory.OTHER).level(SemVerChangeLevel.MAJOR).build()
+ new AnalyzedCommit(null, null, null, null, "D1", ChangeCategory.DEPRECATED, null, null, SemVerChangeLevel.NONE, null),
+ new AnalyzedCommit(null, null, null, null, "R1", ChangeCategory.REMOVED, null, null, SemVerChangeLevel.NONE, null),
+ new AnalyzedCommit(null, null, null, null, "F1", ChangeCategory.FIXED, null, null, SemVerChangeLevel.PATCH, null),
+ new AnalyzedCommit(null, null, null, null, "S1", ChangeCategory.SECURITY, null, null, SemVerChangeLevel.PATCH, null),
+ new AnalyzedCommit(null, null, null, null, "A1", ChangeCategory.ADDED, null, null, SemVerChangeLevel.MINOR, null),
+ new AnalyzedCommit(null, null, null, null, "C1", ChangeCategory.CHANGED, null, null, SemVerChangeLevel.MINOR, null),
+ new AnalyzedCommit(null, null, null, null, "B1", ChangeCategory.OTHER, null, null, SemVerChangeLevel.MAJOR, null)
)
);
}
diff --git a/semver-analyzer-conventional/src/main/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzer.java b/semver-analyzer-conventional/src/main/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzer.java
index 7750804..b493840 100644
--- a/semver-analyzer-conventional/src/main/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzer.java
+++ b/semver-analyzer-conventional/src/main/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzer.java
@@ -1,10 +1,10 @@
package io.github.sam42r.semver.analyzer;
-import io.github.sam42r.semver.analyzer.model.AnalyzedCommit;
-import io.github.sam42r.semver.analyzer.model.ChangeCategory;
import io.github.sam42r.semver.analyzer.model.Configuration;
-import io.github.sam42r.semver.analyzer.model.SemVerChangeLevel;
-import io.github.sam42r.semver.scm.model.Commit;
+import io.github.sam42r.semver.model.analyze.AnalyzedCommit;
+import io.github.sam42r.semver.model.analyze.ChangeCategory;
+import io.github.sam42r.semver.model.analyze.SemVerChangeLevel;
+import io.github.sam42r.semver.model.scm.Commit;
import lombok.AccessLevel;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@@ -41,16 +41,10 @@ public class ConventionalCommitAnalyzer implements CommitAnalyzer {
@SuppressWarnings("MismatchedQueryAndUpdateOfStringBuilder")
private AnalyzedCommit analyzeCommit(@NonNull Commit commit) {
- var analyzedCommitBuilder = AnalyzedCommit.builder()
- .id(commit.getId())
- .timestamp(commit.getTimestamp())
- .author(commit.getAuthor())
- .message(commit.getMessage());
-
var headerBuilder = new StringBuilder();
var bodyBuilder = new StringBuilder();
var footerBuilder = new StringBuilder();
- try (var reader = new BufferedReader(new StringReader(commit.getMessage()))) {
+ try (var reader = new BufferedReader(new StringReader(commit.message()))) {
String line;
int emptyLinesCounter = 0;
while ((line = reader.readLine()) != null) {
@@ -74,47 +68,44 @@ private AnalyzedCommit analyzeCommit(@NonNull Commit commit) {
var header = headerBuilder.toString().trim();
var body = bodyBuilder.toString().trim();
var footer = footerBuilder.toString().trim();
- analyzedCommitBuilder
- .header(header)
- .body(body)
- .footer(footer);
-
- if (!header.isEmpty()) {
- var pattern = Pattern.compile(COMMIT_HEADER_PATTERN);
- var matcher = pattern.matcher(header);
- if (matcher.find()) {
- var type = matcher.group("TYPE");
- var scope = Optional.ofNullable(matcher.group("SCOPE"))
- .map(v -> v.replace("(", ""))
- .map(v -> v.replace(")", ""))
- .orElse(null);
- var breaking = Optional.ofNullable(matcher.group("BREAKING"));
- var description = matcher.group("DESCRIPTION").replaceFirst(":", "").trim();
-
- analyzedCommitBuilder
- .type(type)
- .scope(scope)
- .subject(description)
- .category(getCategory(type))
- .level(breaking.isPresent() ? SemVerChangeLevel.MAJOR : getLevel(type));
- }
- }
- if (footer.contains("BREAKING CHANGE")) {
- analyzedCommitBuilder.level(SemVerChangeLevel.MAJOR);
+ var pattern = Pattern.compile(COMMIT_HEADER_PATTERN);
+ var matcher = pattern.matcher(header);
+
+ if (header.isEmpty() || !matcher.find()) {
+ return new AnalyzedCommit(commit, null, null, null, null, null, null, null, null, null);
}
+ var type = matcher.group("TYPE");
+ var scope = Optional.ofNullable(matcher.group("SCOPE"))
+ .map(v -> v.replace("(", ""))
+ .map(v -> v.replace(")", ""))
+ .orElse(null);
+ var breaking = Optional.ofNullable(matcher.group("BREAKING"));
+ var description = matcher.group("DESCRIPTION").replaceFirst(":", "").trim();
+
// TODO search for issues in footer
- return analyzedCommitBuilder.build();
+ return new AnalyzedCommit(
+ commit,
+ header,
+ body,
+ footer,
+ type,
+ getCategory(type),
+ scope,
+ description,
+ breaking.isPresent() || footer.contains("BREAKING CHANGE") ? SemVerChangeLevel.MAJOR : getLevel(type),
+ null
+ );
}
private ChangeCategory getCategory(String type) {
if (type != null) {
return configuration.getItems().stream()
- .filter(v -> v.getType().equals(type))
+ .filter(v -> v.type().equals(type))
.findAny()
- .map(AnalyzedCommit::getCategory)
+ .map(AnalyzedCommit::category)
.orElse(ChangeCategory.OTHER);
}
return ChangeCategory.OTHER;
@@ -123,9 +114,9 @@ private ChangeCategory getCategory(String type) {
private SemVerChangeLevel getLevel(String type) {
if (type != null) {
return configuration.getItems().stream()
- .filter(v -> v.getType().equals(type))
+ .filter(v -> v.type().equals(type))
.findAny()
- .map(AnalyzedCommit::getLevel)
+ .map(AnalyzedCommit::level)
.orElse(SemVerChangeLevel.NONE);
}
return SemVerChangeLevel.NONE;
diff --git a/semver-analyzer-conventional/src/test/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzerTest.java b/semver-analyzer-conventional/src/test/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzerTest.java
index 63c170c..ff8af23 100644
--- a/semver-analyzer-conventional/src/test/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzerTest.java
+++ b/semver-analyzer-conventional/src/test/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzerTest.java
@@ -1,9 +1,9 @@
package io.github.sam42r.semver.analyzer;
-import io.github.sam42r.semver.analyzer.model.AnalyzedCommit;
-import io.github.sam42r.semver.analyzer.model.ChangeCategory;
-import io.github.sam42r.semver.analyzer.model.SemVerChangeLevel;
-import io.github.sam42r.semver.scm.model.Commit;
+import io.github.sam42r.semver.model.analyze.AnalyzedCommit;
+import io.github.sam42r.semver.model.analyze.ChangeCategory;
+import io.github.sam42r.semver.model.analyze.SemVerChangeLevel;
+import io.github.sam42r.semver.model.scm.Commit;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -24,103 +24,85 @@ void setup() {
@Test
void shouldFindFix() {
var actual = uut.analyzeCommits(List.of(
- Commit.builder()
- .id("42")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .message("""
+ new Commit("42", Instant.EPOCH, "JUnit",
+ """
fix(scm): set clean commit message
-
+
* added scope for commit messages
-
+
refs #42
""")
- .build()
));
assertThat(actual).containsExactly(
- AnalyzedCommit.builder()
- .id("42")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .message("""
- fix(scm): set clean commit message
-
- * added scope for commit messages
-
- refs #42
- """)
- .category(ChangeCategory.FIXED)
- .level(SemVerChangeLevel.PATCH)
- .header("fix(scm): set clean commit message")
- .body("* added scope for commit messages")
- .footer("refs #42")
- .type("fix")
- .scope("scm")
- .subject("set clean commit message")
- .build()
+ new AnalyzedCommit(
+ new Commit("42", Instant.EPOCH, "JUnit",
+ """
+ fix(scm): set clean commit message
+
+ * added scope for commit messages
+
+ refs #42
+ """),
+ "fix(scm): set clean commit message",
+ "* added scope for commit messages",
+ "refs #42",
+ "fix",
+ ChangeCategory.FIXED,
+ "scm",
+ "set clean commit message",
+ SemVerChangeLevel.PATCH,
+ null)
);
}
@Test
void shouldFindBreakingChanges() {
var actual = uut.analyzeCommits(List.of(
- Commit.builder()
- .id("42")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .message("""
+ new Commit("42", Instant.EPOCH, "JUnit",
+ """
fix(scm): set clean commit message
-
+
* added scope for commit messages
BREAKING CHANGE: breaks everything
refs #42
- """)
- .build(),
- Commit.builder()
- .id("42")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .message("fix(scm)!: set clean commit message")
- .build()
+ """),
+ new Commit("42", Instant.EPOCH, "JUnit",
+ "fix(scm)!: set clean commit message")
));
assertThat(actual).containsExactly(
- AnalyzedCommit.builder()
- .id("42")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .message("""
- fix(scm): set clean commit message
-
- * added scope for commit messages
-
- refs #42
- """)
- .category(ChangeCategory.FIXED)
- .level(SemVerChangeLevel.MAJOR)
- .header("fix(scm): set clean commit message")
- .body("* added scope for commit messages")
- .footer("BREAKING CHANGE: breaks everything%srefs #42".formatted(System.lineSeparator()))
- .type("fix")
- .scope("scm")
- .subject("set clean commit message")
- .build(),
- AnalyzedCommit.builder()
- .id("42")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .message("")
- .category(ChangeCategory.FIXED)
- .level(SemVerChangeLevel.MAJOR)
- .header("fix(scm)!: set clean commit message")
- .body("")
- .footer("")
- .type("fix")
- .scope("scm")
- .subject("set clean commit message")
- .build()
+ new AnalyzedCommit(
+ new Commit("42", Instant.EPOCH, "JUnit",
+ """
+ fix(scm): set clean commit message
+
+ * added scope for commit messages
+
+ BREAKING CHANGE: breaks everything
+ refs #42
+ """),
+ "fix(scm): set clean commit message",
+ "* added scope for commit messages",
+ "BREAKING CHANGE: breaks everything%srefs #42".formatted(System.lineSeparator()),
+ "fix",
+ ChangeCategory.FIXED,
+ "scm",
+ "set clean commit message",
+ SemVerChangeLevel.MAJOR,
+ null),
+ new AnalyzedCommit(
+ new Commit("42", Instant.EPOCH, "JUnit", "fix(scm)!: set clean commit message"),
+ "fix(scm)!: set clean commit message",
+ "",
+ "",
+ "fix",
+ ChangeCategory.FIXED,
+ "scm",
+ "set clean commit message",
+ SemVerChangeLevel.MAJOR,
+ null)
);
}
}
diff --git a/semver-analyzer-gitmoji/src/main/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzer.java b/semver-analyzer-gitmoji/src/main/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzer.java
index 34a871e..56bed3d 100644
--- a/semver-analyzer-gitmoji/src/main/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzer.java
+++ b/semver-analyzer-gitmoji/src/main/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzer.java
@@ -1,14 +1,16 @@
package io.github.sam42r.semver.analyzer;
-import io.github.sam42r.semver.analyzer.model.AnalyzedCommit;
-import io.github.sam42r.semver.analyzer.model.ChangeCategory;
import io.github.sam42r.semver.analyzer.model.Configuration;
-import io.github.sam42r.semver.analyzer.model.SemVerChangeLevel;
-import io.github.sam42r.semver.scm.model.Commit;
+import io.github.sam42r.semver.model.analyze.AnalyzedCommit;
+import io.github.sam42r.semver.model.analyze.ChangeCategory;
+import io.github.sam42r.semver.model.analyze.Issue;
+import io.github.sam42r.semver.model.analyze.SemVerChangeLevel;
+import io.github.sam42r.semver.model.scm.Commit;
import lombok.AccessLevel;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
+import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;
@@ -35,48 +37,47 @@ public class GitMojiCommitAnalyzer implements CommitAnalyzer {
}
private AnalyzedCommit analyzeCommit(@NonNull Commit commit) {
- var analyzedCommitBuilder = AnalyzedCommit.builder()
- .id(commit.getId())
- .timestamp(commit.getTimestamp())
- .author(commit.getAuthor())
- .header(commit.getMessage().trim())
- .message(commit.getMessage());
+ var pattern = Pattern.compile(COMMIT_MESSAGE_PATTERN);
+ var matcher = pattern.matcher(commit.message());
- if (commit.getMessage().startsWith(":")) {
- var pattern = Pattern.compile(COMMIT_MESSAGE_PATTERN);
- var matcher = pattern.matcher(commit.getMessage());
- if (matcher.find()) {
- var intention = matcher.group("INTENTION");
- var scope = Optional.ofNullable(matcher.group("SCOPE"))
- .map(v -> v.replace("(", ""))
- .map(v -> v.replace(")", ""))
- .map(v -> v.replace(":", ""))
- .map(String::trim)
- .orElse(null);
- var message = matcher.group("MESSAGE").trim();
- var ref = Optional.ofNullable(matcher.group("REF"))
- .map(v -> v.replace("#", ""))
- .map(String::trim)
- .map(List::of)
- .orElse(null);
- analyzedCommitBuilder
- .type(intention)
- .scope(scope)
- .subject(message)
- .issues(ref)
- .category(getCategory(intention))
- .level(getLevel(intention));
- }
+ if (!commit.message().startsWith(":") || !matcher.find()) {
+ return new AnalyzedCommit(commit, null, null, null, null, null, null, null, null, null);
}
- return analyzedCommitBuilder.build();
+
+ var intention = matcher.group("INTENTION");
+ var scope = Optional.ofNullable(matcher.group("SCOPE"))
+ .map(v -> v.replace("(", ""))
+ .map(v -> v.replace(")", ""))
+ .map(v -> v.replace(":", ""))
+ .map(String::trim)
+ .orElse(null);
+ var message = matcher.group("MESSAGE").trim();
+ var ref = Optional.ofNullable(matcher.group("REF"))
+ .map(v -> v.replace("#", ""))
+ .map(String::trim)
+ .map(List::of)
+ .orElse(Collections.emptyList());
+
+ return new AnalyzedCommit(
+ commit,
+ commit.message(),
+ null,
+ null,
+ intention,
+ getCategory(intention),
+ scope,
+ message,
+ getLevel(intention),
+ ref.stream().map(v -> new Issue(v, "")).toList()
+ );
}
private ChangeCategory getCategory(String intention) {
if (intention != null) {
return configuration.getItems().stream()
- .filter(v -> v.getType().equals(intention))
+ .filter(v -> v.type().equals(intention))
.findAny()
- .map(AnalyzedCommit::getCategory)
+ .map(AnalyzedCommit::category)
.orElse(ChangeCategory.OTHER);
}
return ChangeCategory.OTHER;
@@ -85,9 +86,9 @@ private ChangeCategory getCategory(String intention) {
private SemVerChangeLevel getLevel(String intention) {
if (intention != null) {
return configuration.getItems().stream()
- .filter(v -> v.getType().equals(intention))
+ .filter(v -> v.type().equals(intention))
.findAny()
- .map(AnalyzedCommit::getLevel)
+ .map(AnalyzedCommit::level)
.orElse(SemVerChangeLevel.NONE);
}
return SemVerChangeLevel.NONE;
diff --git a/semver-analyzer-gitmoji/src/test/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzerTest.java b/semver-analyzer-gitmoji/src/test/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzerTest.java
index e1886db..e758bd5 100644
--- a/semver-analyzer-gitmoji/src/test/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzerTest.java
+++ b/semver-analyzer-gitmoji/src/test/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzerTest.java
@@ -1,9 +1,10 @@
package io.github.sam42r.semver.analyzer;
-import io.github.sam42r.semver.analyzer.model.AnalyzedCommit;
-import io.github.sam42r.semver.analyzer.model.ChangeCategory;
-import io.github.sam42r.semver.analyzer.model.SemVerChangeLevel;
-import io.github.sam42r.semver.scm.model.Commit;
+import io.github.sam42r.semver.model.analyze.AnalyzedCommit;
+import io.github.sam42r.semver.model.analyze.ChangeCategory;
+import io.github.sam42r.semver.model.analyze.Issue;
+import io.github.sam42r.semver.model.analyze.SemVerChangeLevel;
+import io.github.sam42r.semver.model.scm.Commit;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -24,99 +25,75 @@ void setup() {
@Test
void shouldFindFixAndFeat() {
var actual = uut.analyzeCommits(List.of(
- Commit.builder()
- .id("42.1")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .message(":bug: (scm) set clean commit message #42")
- .build(),
- Commit.builder()
- .id("42.2")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .message(":sparkles: add awesome things")
- .build()
+ new Commit("42.1", Instant.EPOCH, "JUnit", ":bug: (scm) set clean commit message #42"),
+ new Commit("42.2", Instant.EPOCH, "JUnit", ":sparkles: add awesome things")
));
assertThat(actual).containsExactlyInAnyOrder(
- AnalyzedCommit.builder()
- .id("42.1")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .header(":bug: (scm) set clean commit message #42")
- .message(":bug: (scm) set clean commit message #42")
- .type(":bug:")
- .scope("scm")
- .subject("set clean commit message")
- .issues(List.of("42"))
- .category(ChangeCategory.FIXED)
- .level(SemVerChangeLevel.PATCH)
- .build(),
- AnalyzedCommit.builder()
- .id("42.2")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .header(":sparkles: add awesome things")
- .message(":sparkles: add awesome things")
- .type(":sparkles:")
- .subject("add awesome things")
- .category(ChangeCategory.ADDED)
- .level(SemVerChangeLevel.MINOR)
- .build()
+ new AnalyzedCommit(
+ new Commit("42.1", Instant.EPOCH, "JUnit", ":bug: (scm) set clean commit message #42"),
+ ":bug: (scm) set clean commit message #42",
+ null,
+ null,
+ ":bug:",
+ ChangeCategory.FIXED,
+ "scm",
+ "set clean commit message",
+ SemVerChangeLevel.PATCH,
+ List.of(new Issue("42", ""))),
+ new AnalyzedCommit(
+ new Commit("42.2", Instant.EPOCH, "JUnit", ":sparkles: add awesome things"),
+ ":sparkles: add awesome things",
+ null,
+ null,
+ ":sparkles:",
+ ChangeCategory.ADDED,
+ null,
+ "add awesome things",
+ SemVerChangeLevel.MINOR,
+ null)
);
}
@Test
void shouldFindBreaking() {
var actual = uut.analyzeCommits(List.of(
- Commit.builder()
- .id("42.3")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .message(":boom: (void): break some glass #42")
- .build()
+ new Commit("42.3", Instant.EPOCH, "JUnit", ":boom: (void): break some glass #42")
));
assertThat(actual).containsExactly(
- AnalyzedCommit.builder()
- .id("42.3")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .header(":boom: (void): break some glass #42")
- .message(":boom: (void): break some glass #42")
- .type(":boom:")
- .scope("void")
- .subject("break some glass")
- .issues(List.of("42"))
- .category(ChangeCategory.ADDED)
- .level(SemVerChangeLevel.MAJOR)
- .build()
+ new AnalyzedCommit(
+ new Commit("42.3", Instant.EPOCH, "JUnit", ":boom: (void): break some glass #42"),
+ ":boom: (void): break some glass #42",
+ null,
+ null,
+ ":boom:",
+ ChangeCategory.ADDED,
+ "void",
+ "break some glass",
+ SemVerChangeLevel.MAJOR,
+ List.of(new Issue("42","")))
);
}
@Test
void shouldFindOther() {
var actual = uut.analyzeCommits(List.of(
- Commit.builder()
- .id("42.4")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .message(":white_check_mark: add test for something")
- .build()
+ new Commit("42.4", Instant.EPOCH, "JUnit", ":white_check_mark: add test for something")
));
assertThat(actual).containsExactly(
- AnalyzedCommit.builder()
- .id("42.4")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .header(":white_check_mark: add test for something")
- .message(":white_check_mark: add test for something")
- .type(":white_check_mark:")
- .subject("add test for something")
- .category(ChangeCategory.OTHER)
- .level(SemVerChangeLevel.NONE)
- .build()
+ new AnalyzedCommit(
+ new Commit("42.4", Instant.EPOCH, "JUnit", ":white_check_mark: add test for something"),
+ ":white_check_mark: add test for something",
+ null,
+ null,
+ ":white_check_mark:",
+ ChangeCategory.OTHER,
+ null,
+ "add test for something",
+ SemVerChangeLevel.NONE,
+ null)
);
}
}
diff --git a/semver-changelog-api/src/main/java/io/github/sam42r/semver/changelog/ChangelogRenderer.java b/semver-changelog-api/src/main/java/io/github/sam42r/semver/changelog/ChangelogRenderer.java
index d21d5f3..fda4cff 100644
--- a/semver-changelog-api/src/main/java/io/github/sam42r/semver/changelog/ChangelogRenderer.java
+++ b/semver-changelog-api/src/main/java/io/github/sam42r/semver/changelog/ChangelogRenderer.java
@@ -1,7 +1,7 @@
package io.github.sam42r.semver.changelog;
-import io.github.sam42r.semver.analyzer.model.AnalyzedCommit;
-import io.github.sam42r.semver.changelog.model.VersionInfo;
+import io.github.sam42r.semver.model.changelog.VersionInfo;
+import io.github.sam42r.semver.model.analyze.AnalyzedCommit;
import lombok.NonNull;
import java.io.InputStream;
diff --git a/semver-changelog-html/src/main/java/io/github/sam42r/semver/changelog/HtmlRenderer.java b/semver-changelog-html/src/main/java/io/github/sam42r/semver/changelog/HtmlRenderer.java
index 0b80a0e..3a485d7 100644
--- a/semver-changelog-html/src/main/java/io/github/sam42r/semver/changelog/HtmlRenderer.java
+++ b/semver-changelog-html/src/main/java/io/github/sam42r/semver/changelog/HtmlRenderer.java
@@ -1,7 +1,7 @@
package io.github.sam42r.semver.changelog;
-import io.github.sam42r.semver.analyzer.model.AnalyzedCommit;
-import io.github.sam42r.semver.changelog.model.VersionInfo;
+import io.github.sam42r.semver.model.changelog.VersionInfo;
+import io.github.sam42r.semver.model.analyze.AnalyzedCommit;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.apache.commons.codec.digest.DigestUtils;
diff --git a/semver-changelog-html/src/test/java/io/github/sam42r/semver/changelog/HtmlRendererTest.java b/semver-changelog-html/src/test/java/io/github/sam42r/semver/changelog/HtmlRendererTest.java
index e885cee..b502c0b 100644
--- a/semver-changelog-html/src/test/java/io/github/sam42r/semver/changelog/HtmlRendererTest.java
+++ b/semver-changelog-html/src/test/java/io/github/sam42r/semver/changelog/HtmlRendererTest.java
@@ -1,8 +1,11 @@
package io.github.sam42r.semver.changelog;
-import io.github.sam42r.semver.analyzer.model.AnalyzedCommit;
-import io.github.sam42r.semver.analyzer.model.ChangeCategory;
-import io.github.sam42r.semver.changelog.model.VersionInfo;
+import io.github.sam42r.semver.model.analyze.Issue;
+import io.github.sam42r.semver.model.changelog.VersionInfo;
+import io.github.sam42r.semver.model.analyze.AnalyzedCommit;
+import io.github.sam42r.semver.model.analyze.ChangeCategory;
+import io.github.sam42r.semver.model.analyze.SemVerChangeLevel;
+import io.github.sam42r.semver.model.scm.Commit;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
@@ -69,33 +72,63 @@ private VersionInfo release(String version) {
private List analyzedCommits() {
return List.of(
- AnalyzedCommit.builder()
- .id("42")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .header("feat(scm): Lorem ipsum")
- .body("* Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam")
- .footer("refs #42")
- .category(ChangeCategory.ADDED)
- .build(),
- AnalyzedCommit.builder()
- .id("42")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .header("fix(scm): Lorem ipsum")
- .body("* Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam")
- .footer("refs #42")
- .category(ChangeCategory.FIXED)
- .build(),
- AnalyzedCommit.builder()
- .id("42")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .header("chore(scm): Lorem ipsum")
- .body("* Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam")
- .footer("refs #42")
- .category(ChangeCategory.CHANGED)
- .build()
+ new AnalyzedCommit(
+ new Commit("42", Instant.EPOCH, "JUnit",
+ """
+ feat(scm): Lorem ipsum
+
+ * Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam
+
+ refs #42
+ """),
+ "feat(scm): Lorem ipsum",
+ "* Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam",
+ "refs #42",
+ "feat",
+ ChangeCategory.ADDED,
+ "scm",
+ "Lorem ipsum",
+ SemVerChangeLevel.MINOR,
+ null
+ ),
+ new AnalyzedCommit(
+ new Commit("42", Instant.EPOCH, "JUnit",
+ """
+ fix(scm): Lorem ipsum
+
+ * Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam
+
+ refs #42
+ """),
+ "fix(scm): Lorem ipsum",
+ "* Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam",
+ "refs #42",
+ "fix",
+ ChangeCategory.FIXED,
+ "scm",
+ "Lorem ipsum",
+ SemVerChangeLevel.PATCH,
+ null
+ ),
+ new AnalyzedCommit(
+ new Commit("42", Instant.EPOCH, "JUnit",
+ """
+ chore(scm): Lorem ipsum
+
+ * Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam
+
+ refs #42
+ """),
+ "chore(scm): Lorem ipsum",
+ "* Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam",
+ "refs #42",
+ "chore",
+ ChangeCategory.CHANGED,
+ "scm",
+ "Lorem ipsum",
+ SemVerChangeLevel.NONE,
+ List.of(new Issue("42", "https://junit.org/test/42"))
+ )
);
}
}
diff --git a/semver-changelog-markup/src/main/java/io/github/sam42r/semver/changelog/MarkupRenderer.java b/semver-changelog-markup/src/main/java/io/github/sam42r/semver/changelog/MarkupRenderer.java
index 16e7f86..1fab652 100644
--- a/semver-changelog-markup/src/main/java/io/github/sam42r/semver/changelog/MarkupRenderer.java
+++ b/semver-changelog-markup/src/main/java/io/github/sam42r/semver/changelog/MarkupRenderer.java
@@ -1,9 +1,9 @@
package io.github.sam42r.semver.changelog;
import com.github.mustachejava.DefaultMustacheFactory;
-import io.github.sam42r.semver.analyzer.model.AnalyzedCommit;
-import io.github.sam42r.semver.analyzer.model.ChangeCategory;
-import io.github.sam42r.semver.changelog.model.VersionInfo;
+import io.github.sam42r.semver.model.changelog.VersionInfo;
+import io.github.sam42r.semver.model.analyze.AnalyzedCommit;
+import io.github.sam42r.semver.model.analyze.ChangeCategory;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.apache.commons.codec.digest.DigestUtils;
@@ -55,7 +55,7 @@ public class MarkupRenderer implements ChangelogRenderer {
) {
var categorizedCommits = analyzedCommits.stream()
.collect(Collectors.toMap(
- AnalyzedCommit::getCategory,
+ AnalyzedCommit::category,
List::of,
(v1, v2) -> Stream.of(v1, v2).flatMap(List::stream).toList()
));
diff --git a/semver-changelog-markup/src/test/java/io/github/sam42r/semver/changelog/MarkupRendererTest.java b/semver-changelog-markup/src/test/java/io/github/sam42r/semver/changelog/MarkupRendererTest.java
index e38191c..2195d26 100644
--- a/semver-changelog-markup/src/test/java/io/github/sam42r/semver/changelog/MarkupRendererTest.java
+++ b/semver-changelog-markup/src/test/java/io/github/sam42r/semver/changelog/MarkupRendererTest.java
@@ -1,8 +1,11 @@
package io.github.sam42r.semver.changelog;
-import io.github.sam42r.semver.analyzer.model.AnalyzedCommit;
-import io.github.sam42r.semver.analyzer.model.ChangeCategory;
-import io.github.sam42r.semver.changelog.model.VersionInfo;
+import io.github.sam42r.semver.model.analyze.AnalyzedCommit;
+import io.github.sam42r.semver.model.analyze.ChangeCategory;
+import io.github.sam42r.semver.model.analyze.Issue;
+import io.github.sam42r.semver.model.analyze.SemVerChangeLevel;
+import io.github.sam42r.semver.model.changelog.VersionInfo;
+import io.github.sam42r.semver.model.scm.Commit;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@@ -50,15 +53,15 @@ void shouldUpdateChangelog(@TempDir Path tempDir) throws IOException {
changelog,
"""
# Changelog
-
+
header text
-
+
-
+
## v0.9.0 - 2024-01-01
-
+
## Disclaimer
-
+
footer text
""",
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING
@@ -81,15 +84,25 @@ private VersionInfo release(String version) {
private List analyzedCommits() {
return List.of(
- AnalyzedCommit.builder()
- .id("42")
- .timestamp(Instant.EPOCH)
- .author("JUnit")
- .header("fix(scm): set clean commit message")
- .body("* added scope for commit messages")
- .footer("refs #42")
- .category(ChangeCategory.FIXED)
- .build()
+ new AnalyzedCommit(
+ new Commit("42", Instant.EPOCH, "JUnit",
+ """
+ fix(scm): set clean commit message
+
+ * added scope for commit messages
+
+ refs #42
+ """),
+ "fix(scm): set clean commit message",
+ "* added scope for commit messages",
+ "refs #42",
+ "fix",
+ ChangeCategory.FIXED,
+ "scm",
+ "set clean commit message",
+ SemVerChangeLevel.PATCH,
+ List.of(new Issue("42", "https://junit.org/test/42"))
+ )
);
}
}
diff --git a/semver-maven-model/pom.xml b/semver-maven-model/pom.xml
new file mode 100644
index 0000000..3b274f6
--- /dev/null
+++ b/semver-maven-model/pom.xml
@@ -0,0 +1,41 @@
+
+
+ 4.0.0
+
+
+ io.github.sam42r
+ semver-parent
+ 1.8.0
+
+
+ semver-maven-model
+ ${project.groupId}:${project.artifactId}
+
+
+ 19
+ 19
+ UTF-8
+
+
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
+
+
+
\ No newline at end of file
diff --git a/semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/AnalyzedCommit.java b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/AnalyzedCommit.java
new file mode 100644
index 0000000..5764dfa
--- /dev/null
+++ b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/AnalyzedCommit.java
@@ -0,0 +1,26 @@
+package io.github.sam42r.semver.model.analyze;
+
+import io.github.sam42r.semver.model.scm.Commit;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+public record AnalyzedCommit(
+ Commit commit,
+ String header,
+ String body,
+ String footer,
+ String type,
+ ChangeCategory category,
+ String scope,
+ String subject,
+ SemVerChangeLevel level,
+ List issues
+) {
+ public static final Predicate isBugfix = analyzedCommit ->
+ SemVerChangeLevel.PATCH.equals(analyzedCommit.level());
+ public static final Predicate isFeature = analyzedCommit ->
+ SemVerChangeLevel.MINOR.equals(analyzedCommit.level());
+ public static final Predicate isBreaking = analyzedCommit ->
+ SemVerChangeLevel.MAJOR.equals(analyzedCommit.level());
+}
diff --git a/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/model/ChangeCategory.java b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/ChangeCategory.java
similarity index 66%
rename from semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/model/ChangeCategory.java
rename to semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/ChangeCategory.java
index 28c26e0..5949a8d 100644
--- a/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/model/ChangeCategory.java
+++ b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/ChangeCategory.java
@@ -1,4 +1,4 @@
-package io.github.sam42r.semver.analyzer.model;
+package io.github.sam42r.semver.model.analyze;
public enum ChangeCategory {
ADDED, CHANGED, DEPRECATED, REMOVED, FIXED, SECURITY, OTHER;
diff --git a/semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/Issue.java b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/Issue.java
new file mode 100644
index 0000000..a3801fc
--- /dev/null
+++ b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/Issue.java
@@ -0,0 +1,4 @@
+package io.github.sam42r.semver.model.analyze;
+
+public record Issue(String id, String url) {
+}
diff --git a/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/model/SemVerChangeLevel.java b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/SemVerChangeLevel.java
similarity index 88%
rename from semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/model/SemVerChangeLevel.java
rename to semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/SemVerChangeLevel.java
index d1e7503..49e0ec7 100644
--- a/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/model/SemVerChangeLevel.java
+++ b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/SemVerChangeLevel.java
@@ -1,4 +1,4 @@
-package io.github.sam42r.semver.analyzer.model;
+package io.github.sam42r.semver.model.analyze;
/**
* The semantic versioning change level.
diff --git a/semver-changelog-api/src/main/java/io/github/sam42r/semver/changelog/model/VersionInfo.java b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/changelog/VersionInfo.java
similarity index 60%
rename from semver-changelog-api/src/main/java/io/github/sam42r/semver/changelog/model/VersionInfo.java
rename to semver-maven-model/src/main/java/io/github/sam42r/semver/model/changelog/VersionInfo.java
index 8291cfe..7040066 100644
--- a/semver-changelog-api/src/main/java/io/github/sam42r/semver/changelog/model/VersionInfo.java
+++ b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/changelog/VersionInfo.java
@@ -1,4 +1,4 @@
-package io.github.sam42r.semver.changelog.model;
+package io.github.sam42r.semver.model.changelog;
public record VersionInfo(String version, String date, String message) {
}
diff --git a/semver-maven-model/src/main/java/io/github/sam42r/semver/model/release/ReleaseInfo.java b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/release/ReleaseInfo.java
new file mode 100644
index 0000000..eea7b1f
--- /dev/null
+++ b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/release/ReleaseInfo.java
@@ -0,0 +1,6 @@
+package io.github.sam42r.semver.model.release;
+
+import java.time.LocalDateTime;
+
+public record ReleaseInfo(String tagName, String name, String description, LocalDateTime time) {
+}
diff --git a/semver-maven-model/src/main/java/io/github/sam42r/semver/model/scm/Commit.java b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/scm/Commit.java
new file mode 100644
index 0000000..93365ff
--- /dev/null
+++ b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/scm/Commit.java
@@ -0,0 +1,6 @@
+package io.github.sam42r.semver.model.scm;
+
+import java.time.Instant;
+
+public record Commit(String id, Instant timestamp, String author, String message) {
+}
diff --git a/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/util/RemoteUtil.java b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/scm/Remote.java
similarity index 50%
rename from semver-scm-api/src/main/java/io/github/sam42r/semver/scm/util/RemoteUtil.java
rename to semver-maven-model/src/main/java/io/github/sam42r/semver/model/scm/Remote.java
index e968e10..1cfb7a5 100644
--- a/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/util/RemoteUtil.java
+++ b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/scm/Remote.java
@@ -1,20 +1,14 @@
-package io.github.sam42r.semver.scm.util;
-
-import io.github.sam42r.semver.scm.model.Remote;
-import lombok.AccessLevel;
-import lombok.NoArgsConstructor;
-import lombok.NonNull;
+package io.github.sam42r.semver.model.scm;
import java.net.URI;
-@NoArgsConstructor(access = AccessLevel.PRIVATE)
-public final class RemoteUtil {
+public record Remote(String url, String scheme, String host, String group, String project) {
- public static @NonNull Remote parseUrl(@NonNull String url) {
- return url.startsWith("http") ? parseHttpRemoteUrl(url) : parseSshRemoteUrl(url);
+ public static Remote of(String url) {
+ return url.startsWith("http") ? parseHttpUrl(url) : parseSshUrl(url);
}
- private static @NonNull Remote parseHttpRemoteUrl(@NonNull String url) {
+ private static Remote parseHttpUrl(String url) {
var uri = URI.create(url);
var lastSlashIndex = uri.getPath().lastIndexOf("/");
@@ -28,16 +22,10 @@ public final class RemoteUtil {
var hostAndPort = uri.getHost().concat(uri.getPort() > 0 ? ":%d".formatted(uri.getPort()) : "");
- return Remote.builder()
- .url(url)
- .scheme(uri.getScheme())
- .host(hostAndPort)
- .group(group)
- .project(project)
- .build();
+ return new Remote(url, uri.getScheme(), hostAndPort, group, project);
}
- private static @NonNull Remote parseSshRemoteUrl(@NonNull String url) {
+ private static Remote parseSshUrl(String url) {
var startIndex = url.contains("@") ? url.indexOf("@") + 1 : 0;
var lastColonIndex = url.lastIndexOf(":");
@@ -53,12 +41,6 @@ public final class RemoteUtil {
project = project.substring(0, project.lastIndexOf("."));
}
- return Remote.builder()
- .url(url)
- .scheme("https")
- .host(hostAndPort)
- .group(group)
- .project(project)
- .build();
+ return new Remote(url, "https", hostAndPort, group, project);
}
}
diff --git a/semver-maven-model/src/main/java/io/github/sam42r/semver/model/scm/Tag.java b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/scm/Tag.java
new file mode 100644
index 0000000..f310b9b
--- /dev/null
+++ b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/scm/Tag.java
@@ -0,0 +1,4 @@
+package io.github.sam42r.semver.model.scm;
+
+public record Tag(String name, String commitId) {
+}
diff --git a/semver-maven-model/src/test/java/io/github/sam42r/semver/model/scm/RemoteTest.java b/semver-maven-model/src/test/java/io/github/sam42r/semver/model/scm/RemoteTest.java
new file mode 100644
index 0000000..0813a1d
--- /dev/null
+++ b/semver-maven-model/src/test/java/io/github/sam42r/semver/model/scm/RemoteTest.java
@@ -0,0 +1,33 @@
+package io.github.sam42r.semver.model.scm;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class RemoteTest {
+
+ @ParameterizedTest
+ @ValueSource(strings = {
+ "git@github.com:JUnit/test.git",
+ "https://github.com/JUnit/test.git"
+ })
+ void shouldReadRemoteGithub(String url) {
+ var actual = Remote.of(url);
+
+ assertThat(actual).isEqualTo(
+ new Remote(url, "https", "github.com", "JUnit", "test"));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {
+ "git@gitlab.local:10022:JUnit/subgroup/test.git",
+ "https://gitlab.local:10022/JUnit/subgroup/test.git"
+ })
+ void shouldReadRemoteGitlab(String url) {
+ var actual = Remote.of(url);
+
+ assertThat(actual).isEqualTo(
+ new Remote(url, "https", "gitlab.local:10022", "JUnit/subgroup", "test"));
+ }
+}
diff --git a/semver-maven-plugin/pom.xml b/semver-maven-plugin/pom.xml
index 26f3ef4..6d52e34 100644
--- a/semver-maven-plugin/pom.xml
+++ b/semver-maven-plugin/pom.xml
@@ -22,6 +22,12 @@
+
+ io.github.sam42r
+ semver-maven-model
+ ${project.version}
+
+
io.github.sam42r
semver-scm-api
diff --git a/semver-maven-plugin/src/main/java/io/github/sam42r/semver/SemanticReleaseMojo.java b/semver-maven-plugin/src/main/java/io/github/sam42r/semver/SemanticReleaseMojo.java
index eacb425..f132dad 100644
--- a/semver-maven-plugin/src/main/java/io/github/sam42r/semver/SemanticReleaseMojo.java
+++ b/semver-maven-plugin/src/main/java/io/github/sam42r/semver/SemanticReleaseMojo.java
@@ -3,19 +3,19 @@
import io.github.sam24r.semver.release.ReleaseException;
import io.github.sam24r.semver.release.ReleasePublisher;
import io.github.sam24r.semver.release.ReleasePublisherFactory;
-import io.github.sam24r.semver.release.model.ReleaseInfo;
import io.github.sam42r.semver.analyzer.CommitAnalyzer;
import io.github.sam42r.semver.analyzer.CommitAnalyzerFactory;
-import io.github.sam42r.semver.analyzer.model.AnalyzedCommit;
import io.github.sam42r.semver.changelog.ChangelogRenderer;
import io.github.sam42r.semver.changelog.ChangelogRendererFactory;
-import io.github.sam42r.semver.changelog.model.VersionInfo;
import io.github.sam42r.semver.model.Version;
+import io.github.sam42r.semver.model.analyze.AnalyzedCommit;
+import io.github.sam42r.semver.model.changelog.VersionInfo;
+import io.github.sam42r.semver.model.release.ReleaseInfo;
+import io.github.sam42r.semver.model.scm.Commit;
+import io.github.sam42r.semver.model.scm.Tag;
import io.github.sam42r.semver.scm.SCMException;
import io.github.sam42r.semver.scm.SCMProvider;
import io.github.sam42r.semver.scm.SCMProviderFactory;
-import io.github.sam42r.semver.scm.model.Commit;
-import io.github.sam42r.semver.scm.model.Tag;
import io.github.sam42r.semver.util.PomHelper;
import io.github.sam42r.semver.util.TagVersionComparator;
import lombok.NonNull;
@@ -236,11 +236,11 @@ private LatestReleaseInfo getLatestRelease(SCMProvider scmProvider) throws MojoE
var commits = scmProvider.readCommits(null);
var latestTagOpt = tags.max(new TagVersionComparator(tagFormat));
- var latestCommitOpt = latestTagOpt.map(Tag::getCommitId)
- .or(() -> commits.min(Comparator.comparing(Commit::getTimestamp)).map(Commit::getId));
+ var latestCommitOpt = latestTagOpt.map(Tag::commitId)
+ .or(() -> commits.min(Comparator.comparing(Commit::timestamp)).map(Commit::id));
return new LatestReleaseInfo(
- latestTagOpt.map(Tag::getName),
+ latestTagOpt.map(Tag::name),
latestCommitOpt
);
} catch (SCMException e) {
@@ -320,16 +320,16 @@ private void notify(
var remote = scmProvider.getRemote();
releasePublisher.publish(
- remote.getScheme(),
- remote.getHost(),
- remote.getGroup(),
- remote.getProject(),
- ReleaseInfo.builder()
- .time(LocalDateTime.now().truncatedTo(ChronoUnit.DAYS))
- .tagName(version.toTag())
- .name(version.toString())
- //.description("TODO")
- .build()
+ remote.scheme(),
+ remote.host(),
+ remote.group(),
+ remote.project(),
+ new ReleaseInfo(
+ version.toTag(),
+ version.toString(),
+ null, // TODO
+ LocalDateTime.now().truncatedTo(ChronoUnit.DAYS)
+ )
);
} catch (SCMException | ReleaseException e) {
throw new MojoExecutionException(e.getMessage(), e.getCause());
diff --git a/semver-maven-plugin/src/main/java/io/github/sam42r/semver/util/TagVersionComparator.java b/semver-maven-plugin/src/main/java/io/github/sam42r/semver/util/TagVersionComparator.java
index 3d9007c..a6ae38d 100644
--- a/semver-maven-plugin/src/main/java/io/github/sam42r/semver/util/TagVersionComparator.java
+++ b/semver-maven-plugin/src/main/java/io/github/sam42r/semver/util/TagVersionComparator.java
@@ -1,7 +1,7 @@
package io.github.sam42r.semver.util;
import io.github.sam42r.semver.model.Version;
-import io.github.sam42r.semver.scm.model.Tag;
+import io.github.sam42r.semver.model.scm.Tag;
import lombok.RequiredArgsConstructor;
import java.util.Comparator;
@@ -17,8 +17,8 @@ public int compare(Tag o1, Tag o2) {
.thenComparingInt(Version::getMinor)
.thenComparingInt(Version::getPatch)
.compare(
- Version.of(o1.getName(), tagFormat),
- Version.of(o2.getName(), tagFormat)
+ Version.of(o1.name(), tagFormat),
+ Version.of(o2.name(), tagFormat)
);
}
}
diff --git a/semver-maven-plugin/src/test/java/io/github/sam42r/semver/util/BundleHelper.java b/semver-maven-plugin/src/test/java/io/github/sam42r/semver/util/BundleHelper.java
index 9723ad0..c80b279 100644
--- a/semver-maven-plugin/src/test/java/io/github/sam42r/semver/util/BundleHelper.java
+++ b/semver-maven-plugin/src/test/java/io/github/sam42r/semver/util/BundleHelper.java
@@ -13,6 +13,7 @@
public class BundleHelper {
private static final String[] MODULES = new String[]{
+ "semver-maven-model",
"semver-analyzer-api",
"semver-analyzer-conventional",
"semver-analyzer-gitmoji",
diff --git a/semver-maven-plugin/src/test/java/io/github/sam42r/semver/util/TagVersionComparatorTest.java b/semver-maven-plugin/src/test/java/io/github/sam42r/semver/util/TagVersionComparatorTest.java
index d8e800e..ab2f167 100644
--- a/semver-maven-plugin/src/test/java/io/github/sam42r/semver/util/TagVersionComparatorTest.java
+++ b/semver-maven-plugin/src/test/java/io/github/sam42r/semver/util/TagVersionComparatorTest.java
@@ -1,7 +1,7 @@
package io.github.sam42r.semver.util;
import io.github.sam42r.semver.model.Version;
-import io.github.sam42r.semver.scm.model.Tag;
+import io.github.sam42r.semver.model.scm.Tag;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -22,18 +22,18 @@ void setUp() {
@Test
void shouldGetMax() {
var tags = List.of(
- Tag.builder().name("v0.10.0").build(),
- Tag.builder().name("v0.9.0").build(),
- Tag.builder().name("v0.1.0").build(),
- Tag.builder().name("v0.0.10").build(),
- Tag.builder().name("v0.0.9").build(),
- Tag.builder().name("v0.0.1").build()
+ new Tag("v0.10.0", null),
+ new Tag("v0.9.0", null),
+ new Tag("v0.1.0", null),
+ new Tag("v0.0.10", null),
+ new Tag("v0.0.9", null),
+ new Tag("v0.0.1", null)
);
- var alphabeticMax = tags.stream().max(Comparator.comparing(Tag::getName));
- assertThat(alphabeticMax).contains(Tag.builder().name("v0.9.0").build());
+ var alphabeticMax = tags.stream().max(Comparator.comparing(Tag::name));
+ assertThat(alphabeticMax).contains(new Tag("v0.9.0", null));
var semanticVersionMax = tags.stream().max(uut);
- assertThat(semanticVersionMax).contains(Tag.builder().name("v0.10.0").build());
+ assertThat(semanticVersionMax).contains(new Tag("v0.10.0", null));
}
}
diff --git a/semver-release-api/pom.xml b/semver-release-api/pom.xml
index 8fd16fb..72a4292 100644
--- a/semver-release-api/pom.xml
+++ b/semver-release-api/pom.xml
@@ -20,6 +20,11 @@
+
+ io.github.sam42r
+ semver-maven-model
+ ${project.version}
+
org.projectlombok
lombok
diff --git a/semver-release-api/src/main/java/io/github/sam24r/semver/release/ReleasePublisher.java b/semver-release-api/src/main/java/io/github/sam24r/semver/release/ReleasePublisher.java
index 42e4f34..4b2932a 100644
--- a/semver-release-api/src/main/java/io/github/sam24r/semver/release/ReleasePublisher.java
+++ b/semver-release-api/src/main/java/io/github/sam24r/semver/release/ReleasePublisher.java
@@ -1,6 +1,6 @@
package io.github.sam24r.semver.release;
-import io.github.sam24r.semver.release.model.ReleaseInfo;
+import io.github.sam42r.semver.model.release.ReleaseInfo;
import lombok.NonNull;
public interface ReleasePublisher {
diff --git a/semver-release-api/src/main/java/io/github/sam24r/semver/release/model/ReleaseInfo.java b/semver-release-api/src/main/java/io/github/sam24r/semver/release/model/ReleaseInfo.java
deleted file mode 100644
index 5ae8ace..0000000
--- a/semver-release-api/src/main/java/io/github/sam24r/semver/release/model/ReleaseInfo.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package io.github.sam24r.semver.release.model;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import java.time.LocalDateTime;
-
-@Data
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class ReleaseInfo {
-
- private String tagName;
- private String name;
- private String description;
- private LocalDateTime time;
-}
diff --git a/semver-release-github/src/main/java/io/github/sam42r/semver/release/DefaultGithubPublisher.java b/semver-release-github/src/main/java/io/github/sam42r/semver/release/DefaultGithubPublisher.java
index a250696..8a43751 100644
--- a/semver-release-github/src/main/java/io/github/sam42r/semver/release/DefaultGithubPublisher.java
+++ b/semver-release-github/src/main/java/io/github/sam42r/semver/release/DefaultGithubPublisher.java
@@ -2,7 +2,7 @@
import io.github.sam24r.semver.release.ReleaseException;
import io.github.sam24r.semver.release.ReleasePublisher;
-import io.github.sam24r.semver.release.model.ReleaseInfo;
+import io.github.sam42r.semver.model.release.ReleaseInfo;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -39,9 +39,9 @@ public void publish(
var repository = gitHub.getRepository("%s/%s".formatted(group, project));
- var release = repository.createRelease(releaseInfo.getTagName())
- .name(releaseInfo.getName())
- .body(releaseInfo.getDescription())
+ var release = repository.createRelease(releaseInfo.tagName())
+ .name(releaseInfo.name())
+ .body(releaseInfo.description())
.create();
log.debug("Released {}", release.getHtmlUrl());
diff --git a/semver-release-github/src/test/java/io/github/sam42r/semver/release/GithubPublisherTest.java b/semver-release-github/src/test/java/io/github/sam42r/semver/release/GithubPublisherTest.java
index 33c2c62..10805e5 100644
--- a/semver-release-github/src/test/java/io/github/sam42r/semver/release/GithubPublisherTest.java
+++ b/semver-release-github/src/test/java/io/github/sam42r/semver/release/GithubPublisherTest.java
@@ -2,7 +2,7 @@
import io.github.sam24r.semver.release.ReleaseException;
import io.github.sam24r.semver.release.ReleasePublisher;
-import io.github.sam24r.semver.release.model.ReleaseInfo;
+import io.github.sam42r.semver.model.release.ReleaseInfo;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -84,12 +84,12 @@ void shouldCreateRelease(MockServerClient client) throws ReleaseException {
""")
);
- var release = ReleaseInfo.builder()
- .tagName("v1.0.0")
- .name("v1.0.0")
- .description("# Release v1.0.0")
- .time(LocalDateTime.now())
- .build();
+ var release = new ReleaseInfo(
+ "v1.0.0",
+ "v1.0.0",
+ "# Release v1.0.0",
+ LocalDateTime.now()
+ );
uut.publish(
"http",
@@ -150,12 +150,12 @@ void shouldThrowOnHttp422(MockServerClient client) {
.withBody("endpoint has been spammed")
);
- var release = ReleaseInfo.builder()
- .tagName("v1.0.0")
- .name("v1.0.0")
- .description("# Release v1.0.0")
- .time(LocalDateTime.now())
- .build();
+ var release = new ReleaseInfo(
+ "v1.0.0",
+ "v1.0.0",
+ "# Release v1.0.0",
+ LocalDateTime.now()
+ );
assertThatThrownBy(() -> uut.publish(
"http",
@@ -181,7 +181,7 @@ void shouldThrowOnHttp422(MockServerClient client) {
"http,localhost:42,JUnit,,project"
})
void shouldThrowOnNullValue(String scheme, String instance, String group, String project, String field) {
- var releaseInfo = ReleaseInfo.builder().build();
+ var releaseInfo = new ReleaseInfo(null,null,null,null);
assertThatThrownBy(() -> uut.publish(scheme, instance, group, project, releaseInfo))
.isInstanceOf(NullPointerException.class)
.hasMessage("%s is marked non-null but is null".formatted(field));
diff --git a/semver-release-gitlab/src/main/java/io/github/sam42r/semver/release/GitlabPublisher.java b/semver-release-gitlab/src/main/java/io/github/sam42r/semver/release/GitlabPublisher.java
index 68ba331..0d583f9 100644
--- a/semver-release-gitlab/src/main/java/io/github/sam42r/semver/release/GitlabPublisher.java
+++ b/semver-release-gitlab/src/main/java/io/github/sam42r/semver/release/GitlabPublisher.java
@@ -3,7 +3,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.sam24r.semver.release.ReleaseException;
import io.github.sam24r.semver.release.ReleasePublisher;
-import io.github.sam24r.semver.release.model.ReleaseInfo;
+import io.github.sam42r.semver.model.release.ReleaseInfo;
import io.github.sam42r.semver.release.model.GitlabRelease;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@@ -69,9 +69,9 @@ public void publish(
private GitlabRelease generatePayload(ReleaseInfo releaseInfo) {
return GitlabRelease.builder()
- .tagName(releaseInfo.getTagName())
- .name(releaseInfo.getName())
- .description(releaseInfo.getDescription())
+ .tagName(releaseInfo.tagName())
+ .name(releaseInfo.name())
+ .description(releaseInfo.description())
.build();
}
}
diff --git a/semver-release-gitlab/src/test/java/io/github/sam42r/semver/release/GitlabPublisherTest.java b/semver-release-gitlab/src/test/java/io/github/sam42r/semver/release/GitlabPublisherTest.java
index 3822639..0161f2b 100644
--- a/semver-release-gitlab/src/test/java/io/github/sam42r/semver/release/GitlabPublisherTest.java
+++ b/semver-release-gitlab/src/test/java/io/github/sam42r/semver/release/GitlabPublisherTest.java
@@ -2,7 +2,7 @@
import io.github.sam24r.semver.release.ReleaseException;
import io.github.sam24r.semver.release.ReleasePublisher;
-import io.github.sam24r.semver.release.model.ReleaseInfo;
+import io.github.sam42r.semver.model.release.ReleaseInfo;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -47,12 +47,12 @@ void shouldCreateRelease(MockServerClient client) throws ReleaseException {
""")
);
- var release = ReleaseInfo.builder()
- .tagName("v1.0.0")
- .name("v1.0.0")
- .description("# Release v1.0.0")
- .time(LocalDateTime.now())
- .build();
+ var release = new ReleaseInfo(
+ "v1.0.0",
+ "v1.0.0",
+ "# Release v1.0.0",
+ LocalDateTime.now()
+ );
uut.publish(
"http",
@@ -76,12 +76,12 @@ void shouldThrowOnHttp500(MockServerClient client) {
.withBody("Internal server error")
);
- var release = ReleaseInfo.builder()
- .tagName("v1.0.0")
- .name("v1.0.0")
- .description("# Release v1.0.0")
- .time(LocalDateTime.now())
- .build();
+ var release = new ReleaseInfo(
+ "v1.0.0",
+ "v1.0.0",
+ "# Release v1.0.0",
+ LocalDateTime.now()
+ );
assertThatThrownBy(() -> uut.publish(
"http",
diff --git a/semver-scm-api/pom.xml b/semver-scm-api/pom.xml
index 5b75c5c..e4c841e 100644
--- a/semver-scm-api/pom.xml
+++ b/semver-scm-api/pom.xml
@@ -20,6 +20,12 @@
+
+ io.github.sam42r
+ semver-maven-model
+ ${project.version}
+
+
org.apache.maven.scm
maven-scm-api
diff --git a/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/AbstractScmProvider.java b/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/AbstractScmProvider.java
index 951d562..726429a 100644
--- a/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/AbstractScmProvider.java
+++ b/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/AbstractScmProvider.java
@@ -1,9 +1,8 @@
package io.github.sam42r.semver.scm;
-import io.github.sam42r.semver.scm.model.Commit;
-import io.github.sam42r.semver.scm.model.Remote;
-import io.github.sam42r.semver.scm.model.Tag;
-import io.github.sam42r.semver.scm.util.RemoteUtil;
+import io.github.sam42r.semver.model.scm.Commit;
+import io.github.sam42r.semver.model.scm.Remote;
+import io.github.sam42r.semver.model.scm.Tag;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
@@ -77,12 +76,11 @@ protected AbstractScmProvider(
var changeLogScmResult = scmManager.changeLog(changeLogScmRequest);
return changeLogScmResult.getChangeLog().getChangeSets().stream()
- .map(v -> Commit.builder()
- .id(v.getRevision())
- .timestamp(v.getDate().toInstant())
- .author(v.getAuthor())
- .message(v.getComment())
- .build());
+ .map(v -> new Commit(
+ v.getRevision(),
+ v.getDate().toInstant(),
+ v.getAuthor(),
+ v.getComment()));
} catch (ScmException e) {
throw new SCMException(e);
}
@@ -98,10 +96,9 @@ protected AbstractScmProvider(
return changeLogScmResult.getChangeLog().getChangeSets().stream()
.filter(hasTag)
- .map(v -> Tag.builder()
- .name(v.getTags().get(0))
- .commitId(v.getRevision())
- .build());
+ .map(v -> new Tag(
+ v.getTags().get(0),
+ v.getRevision()));
} catch (ScmException e) {
throw new SCMException(e);
}
@@ -141,7 +138,7 @@ public void addFile(@NonNull Path file) throws SCMException {
var tagScmResult = scmManager.tag(repository, new ScmFileSet(path.toFile()), name);
assert tagScmResult.isSuccess();
- return readTags().filter(v -> name.equals(v.getName())).findFirst().orElseThrow();
+ return readTags().filter(v -> name.equals(v.name())).findFirst().orElseThrow();
} catch (ScmException e) {
throw new SCMException(e);
}
@@ -149,7 +146,7 @@ public void addFile(@NonNull Path file) throws SCMException {
@Override
public @NonNull Remote getRemote() throws SCMException {
- return RemoteUtil.parseUrl(getRemoteUrl().orElseThrow());
+ return Remote.of(getRemoteUrl().orElseThrow());
}
protected ScmRepository getScmRepository() throws SCMException {
diff --git a/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/SCMProvider.java b/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/SCMProvider.java
index b9b7112..140217d 100644
--- a/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/SCMProvider.java
+++ b/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/SCMProvider.java
@@ -1,8 +1,8 @@
package io.github.sam42r.semver.scm;
-import io.github.sam42r.semver.scm.model.Commit;
-import io.github.sam42r.semver.scm.model.Remote;
-import io.github.sam42r.semver.scm.model.Tag;
+import io.github.sam42r.semver.model.scm.Commit;
+import io.github.sam42r.semver.model.scm.Remote;
+import io.github.sam42r.semver.model.scm.Tag;
import lombok.NonNull;
import java.nio.file.Path;
diff --git a/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/model/Commit.java b/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/model/Commit.java
deleted file mode 100644
index 735ba00..0000000
--- a/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/model/Commit.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package io.github.sam42r.semver.scm.model;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import lombok.experimental.SuperBuilder;
-
-import java.time.Instant;
-
-@Data
-@SuperBuilder
-@NoArgsConstructor
-@AllArgsConstructor
-public class Commit {
-
- private String id;
- private Instant timestamp;
- private String author;
- private String message;
-}
diff --git a/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/model/Remote.java b/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/model/Remote.java
deleted file mode 100644
index f0498b9..0000000
--- a/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/model/Remote.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package io.github.sam42r.semver.scm.model;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-@Data
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class Remote {
-
- private String url;
- private String scheme;
- private String host;
- private String group;
- private String project;
-}
diff --git a/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/model/Tag.java b/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/model/Tag.java
deleted file mode 100644
index 15a592a..0000000
--- a/semver-scm-api/src/main/java/io/github/sam42r/semver/scm/model/Tag.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package io.github.sam42r.semver.scm.model;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-@Data
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class Tag {
-
- private String name;
- private String commitId;
-}
diff --git a/semver-scm-api/src/test/java/io/github/sam42r/semver/scm/util/RemoteUtilTest.java b/semver-scm-api/src/test/java/io/github/sam42r/semver/scm/util/RemoteUtilTest.java
deleted file mode 100644
index de964ec..0000000
--- a/semver-scm-api/src/test/java/io/github/sam42r/semver/scm/util/RemoteUtilTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package io.github.sam42r.semver.scm.util;
-
-import io.github.sam42r.semver.scm.model.Remote;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.ValueSource;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-class RemoteUtilTest {
-
- @ParameterizedTest
- @ValueSource(strings = {
- "git@github.com:JUnit/test.git",
- "https://github.com/JUnit/test.git"
- })
- void shouldReadRemoteGithub(String url) {
- var actual = RemoteUtil.parseUrl(url);
-
- assertThat(actual).isEqualTo(Remote.builder()
- .url(url)
- .scheme("https")
- .host("github.com")
- .group("JUnit")
- .project("test")
- .build());
- }
-
- @ParameterizedTest
- @ValueSource(strings = {
- "git@gitlab.local:10022:JUnit/subgroup/test.git",
- "https://gitlab.local:10022/JUnit/subgroup/test.git"
- })
- void shouldReadRemoteGitlab(String url) {
- var actual = RemoteUtil.parseUrl(url);
-
- assertThat(actual).isEqualTo(Remote.builder()
- .url(url)
- .scheme("https")
- .host("gitlab.local:10022")
- .group("JUnit/subgroup")
- .project("test")
- .build());
- }
-}
diff --git a/semver-scm-git/src/main/java/io/github/sam42r/semver/scm/GitProvider.java b/semver-scm-git/src/main/java/io/github/sam42r/semver/scm/GitProvider.java
deleted file mode 100644
index d9fafda..0000000
--- a/semver-scm-git/src/main/java/io/github/sam42r/semver/scm/GitProvider.java
+++ /dev/null
@@ -1,281 +0,0 @@
-package io.github.sam42r.semver.scm;
-
-
-import com.jcraft.jsch.JSch;
-import com.jcraft.jsch.JSchException;
-import com.jcraft.jsch.Session;
-import io.github.sam42r.semver.scm.model.Commit;
-import io.github.sam42r.semver.scm.model.Remote;
-import io.github.sam42r.semver.scm.model.Tag;
-import io.github.sam42r.semver.scm.util.RemoteUtil;
-import lombok.AccessLevel;
-import lombok.NonNull;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.SystemUtils;
-import org.eclipse.jgit.api.Git;
-import org.eclipse.jgit.api.errors.GitAPIException;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
-import org.eclipse.jgit.transport.*;
-import org.eclipse.jgit.transport.ssh.jsch.JschConfigSessionFactory;
-import org.eclipse.jgit.transport.ssh.jsch.OpenSshConfig;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.time.Instant;
-import java.util.List;
-import java.util.Optional;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-
-/**
- * {@link SCMProvider} for git.
- *
- * @author Sam42R
- * @deprecated since switching to Maven-SCM {@link DefaultGitProvider} is used instead
- */
-@Slf4j
-@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
-@Deprecated(since = "1.5.0", forRemoval = true)
-public class GitProvider implements SCMProvider {
-
- private final Path repositoryPath;
- private final String username;
- private final String password;
-
- private Repository repository;
-
- @Override
- public @NonNull Stream readCommits(String fromCommitId) throws SCMException {
- var repository = getRepository();
- try (var git = new Git(repository)) {
- var logCommand = git.log();
-
- if (fromCommitId != null) {
- logCommand = logCommand.addRange(
- ObjectId.fromString(fromCommitId),
- git.getRepository().resolve("HEAD"));
- }
-
- return StreamSupport.stream(logCommand.call().spliterator(), false)
- .map(v -> Commit.builder()
- .id(v.getId().getName())
- .timestamp(Instant.ofEpochSecond(v.getCommitTime()))
- .author(v.getAuthorIdent().getName())
- .message(v.getFullMessage())
- .build());
- } catch (IOException | GitAPIException e) {
- throw new SCMException(e.getMessage(), e);
- }
- }
-
- @Override
- public @NonNull Stream readTags() throws SCMException {
- var repository = getRepository();
- try (var git = new Git(repository)) {
- return git.tagList().call().stream()
- .map(v -> Tag.builder()
- .name(v.getName().replace("refs/tags/", ""))
- .commitId(getObjectId(repository, v).getName())
- .build());
- } catch (GitAPIException e) {
- throw new SCMException(e);
- }
- }
-
- @Override
- public void addFile(@NonNull Path file) throws SCMException {
- var repository = getRepository();
- try (var git = new Git(repository)) {
- // note: jGit seems to accept slash as file separator only; therefore we have to replace the platform file
- // separator to make it run on windows also
- git.add().addFilepattern(repositoryPath.relativize(file).toString().replace(File.separatorChar, '/')).call();
- } catch (GitAPIException e) {
- throw new SCMException(e);
- }
- }
-
- @Override
- public @NonNull Commit commit(@NonNull String message) throws SCMException {
- var repository = getRepository();
- try (var git = new Git(repository)) {
- var commit = git.commit().setMessage(message).call();
- return Commit.builder()
- .id(commit.getId().getName())
- .timestamp(Instant.ofEpochSecond(commit.getCommitTime()))
- .author(commit.getAuthorIdent().getName())
- .message(commit.getFullMessage())
- .build();
- } catch (GitAPIException e) {
- throw new SCMException(e);
- }
- }
-
- @Override
- public @NonNull Tag tag(@NonNull String name) throws SCMException {
- var repository = getRepository();
- try (var git = new Git(repository)) {
- var tag = git.tag().setName(name).call();
- return Tag.builder()
- .name(tag.getName().replace("refs/tags/", ""))
- .commitId(getObjectId(repository, tag).getName())
- .build();
- } catch (GitAPIException e) {
- throw new SCMException(e);
- }
- }
-
- @Override
- public String push(boolean force) throws SCMException {
- var repository = getRepository();
- try (var git = new Git(repository)) {
- var pushBranchResults = git.push()
- .setTransportConfigCallback(this::configureTransport)
- .setRemote("origin")
- .setForce(force)
- .call();
-
- var pushTagResults = git.push()
- .setTransportConfigCallback(this::configureTransport)
- .setRemote("origin")
- .setForce(force)
- .setPushTags() // pushes tags only
- .call();
-
- return Stream.concat(
- StreamSupport.stream(pushBranchResults.spliterator(), false),
- StreamSupport.stream(pushTagResults.spliterator(), false)
- )
- .map(PushResult::getMessages)
- .collect(Collectors.joining(System.lineSeparator()));
- } catch (GitAPIException e) {
- throw new SCMException(e);
- }
- }
-
- @Override
- public @NonNull Remote getRemote() throws SCMException {
- var repository = getRepository();
- try (var git = new Git(repository)) {
- var remoteConfigs = git.remoteList().call();
- var url = remoteConfigs.stream()
- .filter(v -> "origin".equals(v.getName()))
- .map(RemoteConfig::getURIs)
- .flatMap(List::stream)
- .map(URIish::toString)
- .findAny()
- .orElseThrow();
- return RemoteUtil.parseUrl(url);
- } catch (GitAPIException e) {
- throw new SCMException(e);
- }
- }
-
- private Repository getRepository() throws SCMException {
- if (repository == null) {
- try {
- var gitDirectory = repositoryPath.resolve(".git");
- if (Files.notExists(gitDirectory) || !Files.isDirectory(gitDirectory) || !Files.isReadable(gitDirectory)) {
- throw new SCMException("Could not find git repository");
- }
- repository = FileRepositoryBuilder.create(gitDirectory.toFile());
- } catch (IOException e) {
- throw new SCMException(e);
- }
- }
- return repository;
- }
-
- private ObjectId getObjectId(Repository repository, Ref ref) {
- try {
- var peel = repository.getRefDatabase().peel(ref);
- return Optional.ofNullable(peel.getPeeledObjectId()).orElse(ref.getObjectId());
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-
- private void configureTransport(@NonNull Transport transport) {
- if (transport instanceof SshTransport sshTransport) {
- configureSshTransport(sshTransport);
- } else if (transport instanceof HttpTransport httpTransport) {
- configureHttpTransport(httpTransport);
- } else {
- log.warn("Could not configure transport '{}'", transport.getClass().getSimpleName());
- }
- }
-
- private void configureSshTransport(@NonNull SshTransport sshTransport) {
- log.debug("Configure SshTransport with SSH keys");
-
- var jschConfigSessionFactory = new JschConfigSessionFactory() {
- @Override
- protected void configureJSch(JSch jsch) {
- super.configureJSch(jsch);
-
- Predicate isKeyFile = path -> path.getFileName().toString().toLowerCase().startsWith("id_");
- Predicate isPublicKeyFile = path -> path.getFileName().toString().toLowerCase().endsWith(".pub");
-
- var sshDirectory = SystemUtils.getUserHome().toPath().resolve(".ssh");
- try (var sshConfigFiles = Files.walk(sshDirectory)) {
- var sshKeyFiles = sshConfigFiles.filter(isKeyFile).toList();
-
- var publicKeyPath = sshKeyFiles.stream()
- .filter(isPublicKeyFile)
- .sorted()
- .findFirst();
- var publicKeyBytes = publicKeyPath.map(this::readAllBytes)
- .orElseThrow(() -> new IllegalStateException("Could not find public key file"));
-
- var privateKeyPath = sshKeyFiles.stream()
- .filter(Predicate.not(isPublicKeyFile))
- .sorted()
- .findFirst();
- var privateKeyBytes = privateKeyPath.map(this::readAllBytes)
- .orElseThrow(() -> new IllegalStateException("Could not find private key file"));
-
- var privateKeyPassword = Optional.ofNullable(password).map(String::getBytes).orElse(null);
-
- jsch.addIdentity(null, privateKeyBytes, publicKeyBytes, privateKeyPassword);
- } catch (IOException | JSchException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- protected void configure(OpenSshConfig.Host hc, Session session) {
- // do nothing
- // session.setPassword("***"); // NOT supported by GitHub
- }
-
- private byte[] readAllBytes(@NonNull Path path) {
- try {
- return Files.readAllBytes(path);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
- };
- sshTransport.setSshSessionFactory(jschConfigSessionFactory);
- }
-
-
- private void configureHttpTransport(@NonNull HttpTransport httpTransport) {
- log.debug("Configure HttpTransport with username and password");
-
- var usernameToSet = Optional.ofNullable(username).orElse(SystemUtils.getUserName());
- var passwordToSet = Optional.ofNullable(password).orElse("");
-
- httpTransport.setCredentialsProvider(
- new UsernamePasswordCredentialsProvider(usernameToSet, passwordToSet)
- );
- }
-}
diff --git a/semver-scm-git/src/main/java/io/github/sam42r/semver/scm/GitProviderFactory.java b/semver-scm-git/src/main/java/io/github/sam42r/semver/scm/GitProviderFactory.java
deleted file mode 100644
index 7fa6346..0000000
--- a/semver-scm-git/src/main/java/io/github/sam42r/semver/scm/GitProviderFactory.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package io.github.sam42r.semver.scm;
-
-import lombok.NoArgsConstructor;
-import lombok.NonNull;
-
-import javax.inject.Named;
-import java.nio.file.Path;
-
-
-/**
- * @deprecated since switching to Maven-SCM {@link DefaultGitProviderFactory} is used instead
- */
-@Named("Git(deprecated)")
-@NoArgsConstructor
-@Deprecated(since = "1.5.0", forRemoval = true)
-public class GitProviderFactory implements SCMProviderFactory {
-
- @Override
- public @NonNull GitProvider getInstance(@NonNull Path path, String username, String password) {
- return new GitProvider(path, username, password);
- }
-}
diff --git a/semver-scm-git/src/test/java/io/github/sam42r/semver/scm/AbstractGitProviderTest.java b/semver-scm-git/src/test/java/io/github/sam42r/semver/scm/AbstractGitProviderTest.java
deleted file mode 100644
index 255d198..0000000
--- a/semver-scm-git/src/test/java/io/github/sam42r/semver/scm/AbstractGitProviderTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package io.github.sam42r.semver.scm;
-
-import io.github.sam42r.semver.scm.model.Commit;
-import io.github.sam42r.semver.scm.model.Remote;
-import io.github.sam42r.semver.scm.model.Tag;
-import org.eclipse.jgit.api.Git;
-import org.eclipse.jgit.api.errors.GitAPIException;
-import org.eclipse.jgit.lib.UserConfig;
-import org.eclipse.jgit.transport.URIish;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.io.TempDir;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.ValueSource;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.time.Instant;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-abstract class AbstractGitProviderTest {
-
- @TempDir
- private Path tempDirectory;
- private SCMProvider uut;
-
- @BeforeEach
- void setup() {
- uut = getUut(tempDirectory);
- }
-
- abstract SCMProvider getUut(Path tempDirectory);
-
- @Test
- void shouldReadCommits() throws GitAPIException, IOException, SCMException {
- try (var git = Git.init().setDirectory(tempDirectory.toFile()).call()) {
- Files.writeString(tempDirectory.resolve("README.md"), "#JUnit");
- git.add().addFilepattern("README.md").call();
- var expected = git.commit().setMessage("Test commit").call();
-
- var actual = uut.readCommits(null);
- assertThat(actual).containsExactly(
- Commit.builder()
- .id(expected.getId().getName())
- .author(git.getRepository().getConfig().get(UserConfig.KEY).getAuthorName())
- .timestamp(Instant.ofEpochSecond(expected.getCommitTime()))
- .message("Test commit")
- .build()
- );
- }
- }
-
- @Test
- void shouldReadTags() throws GitAPIException, IOException, SCMException {
- try (var git = Git.init().setDirectory(tempDirectory.toFile()).call()) {
- Files.writeString(tempDirectory.resolve("README.md"), "#JUnit");
- git.add().addFilepattern("README.md").call();
- var expected = git.commit().setMessage("Test commit").call();
- git.tag().setName("v1.0.0").call();
-
- var actual = uut.readTags();
- assertThat(actual).containsExactly(
- Tag.builder()
- .name("v1.0.0")
- .commitId(expected.getId().getName())
- .build()
- );
- }
- }
-
- @Test
- void shouldAddFiles() throws GitAPIException, IOException, SCMException {
- try (var git = Git.init().setDirectory(tempDirectory.toFile()).call()) {
- var file = Files.writeString(tempDirectory.resolve("README.md"), "#JUnit");
- var directory = Files.createDirectory(tempDirectory.resolve("directory"));
- var anotherFile = Files.writeString(directory.resolve("file.dat"), "JUnit");
-
- uut.addFile(file);
- uut.addFile(anotherFile);
-
- var actual = git.status().call();
- assertThat(actual.getAdded()).hasSize(2);
- }
- }
-
- @ParameterizedTest
- @ValueSource(strings = {
- "git@github.com:JUnit/test.git",
- "https://github.com/JUnit/test.git"
- })
- void shouldReadGithubRemote(String url) throws GitAPIException, URISyntaxException, SCMException {
- try (var git = Git.init().setDirectory(tempDirectory.toFile()).call()) {
- git.remoteAdd().setName("origin").setUri(new URIish(url)).call();
-
- var actual = uut.getRemote();
-
- assertThat(actual).isEqualTo(Remote.builder()
- .url(url)
- .scheme("https")
- .host("github.com")
- .group("JUnit")
- .project("test")
- .build());
- }
- }
-
- @ParameterizedTest
- @ValueSource(strings = {
- "git@gitlab.local:10022:JUnit/subgroup/test.git",
- "https://gitlab.local:10022/JUnit/subgroup/test.git"
- })
- void shouldReadGitlabRemote(String url) throws GitAPIException, URISyntaxException, SCMException {
- try (var git = Git.init().setDirectory(tempDirectory.toFile()).call()) {
- git.remoteAdd().setName("origin").setUri(new URIish(url)).call();
-
- var actual = uut.getRemote();
-
- assertThat(actual).isEqualTo(Remote.builder()
- .url(url)
- .scheme("https")
- .host("gitlab.local:10022")
- .group("JUnit/subgroup")
- .project("test")
- .build());
- }
- }
-}
diff --git a/semver-scm-git/src/test/java/io/github/sam42r/semver/scm/DefaultGitProviderTest.java b/semver-scm-git/src/test/java/io/github/sam42r/semver/scm/DefaultGitProviderTest.java
index b655e26..51b3921 100644
--- a/semver-scm-git/src/test/java/io/github/sam42r/semver/scm/DefaultGitProviderTest.java
+++ b/semver-scm-git/src/test/java/io/github/sam42r/semver/scm/DefaultGitProviderTest.java
@@ -1,12 +1,128 @@
package io.github.sam42r.semver.scm;
+import io.github.sam42r.semver.model.scm.Commit;
+import io.github.sam42r.semver.model.scm.Remote;
+import io.github.sam42r.semver.model.scm.Tag;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.lib.UserConfig;
+import org.eclipse.jgit.transport.URIish;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
import java.nio.file.Path;
+import java.time.Instant;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class DefaultGitProviderTest {
+
+ @TempDir
+ private Path tempDirectory;
+ private SCMProvider uut;
+
+ @BeforeEach
+ void setup() {
+ uut = new DefaultGitProviderFactory().getInstance(tempDirectory, null, null);
+ }
+
+ @Test
+ void shouldReadCommits() throws GitAPIException, IOException, SCMException {
+ try (var git = Git.init().setDirectory(tempDirectory.toFile()).call()) {
+ Files.writeString(tempDirectory.resolve("README.md"), "#JUnit");
+ git.add().addFilepattern("README.md").call();
+ var expected = git.commit().setMessage("Test commit").call();
+
+ var actual = uut.readCommits(null);
+ assertThat(actual).containsExactly(
+ new Commit(
+ expected.getId().getName(),
+ Instant.ofEpochSecond(expected.getCommitTime()),
+ git.getRepository().getConfig().get(UserConfig.KEY).getAuthorName(),
+ "Test commit")
+ );
+ }
+ }
+
+ @Test
+ void shouldReadTags() throws GitAPIException, IOException, SCMException {
+ try (var git = Git.init().setDirectory(tempDirectory.toFile()).call()) {
+ Files.writeString(tempDirectory.resolve("README.md"), "#JUnit");
+ git.add().addFilepattern("README.md").call();
+ var expected = git.commit().setMessage("Test commit").call();
+ git.tag().setName("v1.0.0").call();
+
+ var actual = uut.readTags();
+ assertThat(actual).containsExactly(
+ new Tag(
+ "v1.0.0",
+ expected.getId().getName())
+ );
+ }
+ }
+
+ @Test
+ void shouldAddFiles() throws GitAPIException, IOException, SCMException {
+ try (var git = Git.init().setDirectory(tempDirectory.toFile()).call()) {
+ var file = Files.writeString(tempDirectory.resolve("README.md"), "#JUnit");
+ var directory = Files.createDirectory(tempDirectory.resolve("directory"));
+ var anotherFile = Files.writeString(directory.resolve("file.dat"), "JUnit");
+
+ uut.addFile(file);
+ uut.addFile(anotherFile);
+
+ var actual = git.status().call();
+ assertThat(actual.getAdded()).hasSize(2);
+ }
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {
+ "git@github.com:JUnit/test.git",
+ "https://github.com/JUnit/test.git"
+ })
+ void shouldReadGithubRemote(String url) throws GitAPIException, URISyntaxException, SCMException {
+ try (var git = Git.init().setDirectory(tempDirectory.toFile()).call()) {
+ git.remoteAdd().setName("origin").setUri(new URIish(url)).call();
+
+ var actual = uut.getRemote();
+
+ assertThat(actual).isEqualTo(
+ new Remote(
+ url,
+ "https",
+ "github.com",
+ "JUnit",
+ "test")
+ );
+ }
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {
+ "git@gitlab.local:10022:JUnit/subgroup/test.git",
+ "https://gitlab.local:10022/JUnit/subgroup/test.git"
+ })
+ void shouldReadGitlabRemote(String url) throws GitAPIException, URISyntaxException, SCMException {
+ try (var git = Git.init().setDirectory(tempDirectory.toFile()).call()) {
+ git.remoteAdd().setName("origin").setUri(new URIish(url)).call();
-class DefaultGitProviderTest extends AbstractGitProviderTest {
+ var actual = uut.getRemote();
- @Override
- SCMProvider getUut(Path tempDirectory) {
- return new DefaultGitProviderFactory()
- .getInstance(tempDirectory, null, null);
+ assertThat(actual).isEqualTo(
+ new Remote(
+ url,
+ "https",
+ "gitlab.local:10022",
+ "JUnit/subgroup",
+ "test")
+ );
+ }
}
}
diff --git a/semver-scm-git/src/test/java/io/github/sam42r/semver/scm/GitProviderTest.java b/semver-scm-git/src/test/java/io/github/sam42r/semver/scm/GitProviderTest.java
deleted file mode 100644
index ccfffde..0000000
--- a/semver-scm-git/src/test/java/io/github/sam42r/semver/scm/GitProviderTest.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package io.github.sam42r.semver.scm;
-
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
-
-import java.io.IOException;
-import java.nio.file.Path;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-class GitProviderTest extends AbstractGitProviderTest {
-
- @Override
- SCMProvider getUut(Path tempDirectory) {
- return new GitProviderFactory()
- .getInstance(tempDirectory, null, null);
- }
-
- @Test
- @Disabled("local testing only")
- void shouldPushToRemote() throws IOException, SCMException {
- var path = Path.of("..").toRealPath();
-
- var scmProvider = new GitProvider(path, null, "***");
-
- var actual = scmProvider.push(false);
- assertThat(actual).isNotNull();
- }
-}
diff --git a/semver-scm-mercurial/src/main/java/io/github/sam42r/semver/scm/HgProvider.java b/semver-scm-mercurial/src/main/java/io/github/sam42r/semver/scm/HgProvider.java
index 5efc2fe..fd6d99a 100644
--- a/semver-scm-mercurial/src/main/java/io/github/sam42r/semver/scm/HgProvider.java
+++ b/semver-scm-mercurial/src/main/java/io/github/sam42r/semver/scm/HgProvider.java
@@ -1,8 +1,8 @@
package io.github.sam42r.semver.scm;
-import io.github.sam42r.semver.scm.model.Commit;
-import io.github.sam42r.semver.scm.model.Remote;
-import io.github.sam42r.semver.scm.model.Tag;
+import io.github.sam42r.semver.model.scm.Commit;
+import io.github.sam42r.semver.model.scm.Remote;
+import io.github.sam42r.semver.model.scm.Tag;
import lombok.NonNull;
import org.apache.commons.lang3.NotImplementedException;
diff --git a/semver-scm-subversion/src/main/java/io/github/sam42r/semver/scm/SvnProvider.java b/semver-scm-subversion/src/main/java/io/github/sam42r/semver/scm/SvnProvider.java
index 2705dd6..2f09205 100644
--- a/semver-scm-subversion/src/main/java/io/github/sam42r/semver/scm/SvnProvider.java
+++ b/semver-scm-subversion/src/main/java/io/github/sam42r/semver/scm/SvnProvider.java
@@ -1,8 +1,8 @@
package io.github.sam42r.semver.scm;
-import io.github.sam42r.semver.scm.model.Commit;
-import io.github.sam42r.semver.scm.model.Remote;
-import io.github.sam42r.semver.scm.model.Tag;
+import io.github.sam42r.semver.model.scm.Commit;
+import io.github.sam42r.semver.model.scm.Remote;
+import io.github.sam42r.semver.model.scm.Tag;
import lombok.NonNull;
import org.apache.commons.lang3.NotImplementedException;
From 5893676877b8b67f86596cb4cb5658501a8f9569 Mon Sep 17 00:00:00 2001
From: Rene R
Date: Sat, 31 Jan 2026 18:51:09 +0100
Subject: [PATCH 2/4] :sparkles: generate issue links #41
---
.../semver/analyzer/CommitAnalyzer.java | 4 +-
.../analyzer/ConventionalCommitAnalyzer.java | 39 ++++++++-----
.../ConventionalCommitAnalyzerTest.java | 57 +++++++++++--------
.../analyzer/GitMojiCommitAnalyzer.java | 18 +++---
.../analyzer/GitMojiCommitAnalyzerTest.java | 33 +++++++----
.../resources/templates/default/default.html | 7 ++-
.../resources/templates/missive/missive.html | 8 ++-
.../resources/templates/spinal/spinal.html | 8 ++-
.../semver/changelog/changelog.mustache | 14 ++---
.../semver/model/release/ProviderSpec.java | 10 ++++
.../sam42r/semver/SemanticReleaseMojo.java | 5 +-
.../semver/SemanticReleaseMojoTest.java | 21 +++++--
.../semver/release/ReleasePublisher.java | 3 +
.../release/DefaultGithubPublisher.java | 8 +++
.../semver/release/GitlabPublisher.java | 8 +++
15 files changed, 165 insertions(+), 78 deletions(-)
create mode 100644 semver-maven-model/src/main/java/io/github/sam42r/semver/model/release/ProviderSpec.java
diff --git a/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/CommitAnalyzer.java b/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/CommitAnalyzer.java
index 08be05e..24030cd 100644
--- a/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/CommitAnalyzer.java
+++ b/semver-analyzer-api/src/main/java/io/github/sam42r/semver/analyzer/CommitAnalyzer.java
@@ -1,7 +1,9 @@
package io.github.sam42r.semver.analyzer;
import io.github.sam42r.semver.model.analyze.AnalyzedCommit;
+import io.github.sam42r.semver.model.release.ProviderSpec;
import io.github.sam42r.semver.model.scm.Commit;
+import io.github.sam42r.semver.model.scm.Remote;
import lombok.NonNull;
import java.util.List;
@@ -12,7 +14,7 @@
*/
public interface CommitAnalyzer {
- @NonNull List analyzeCommits(@NonNull List commits);
+ @NonNull List analyzeCommits(@NonNull List commits, @NonNull Remote remote, ProviderSpec providerSpec);
@NonNull String generateReleaseCommitMessage(@NonNull String version);
}
diff --git a/semver-analyzer-conventional/src/main/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzer.java b/semver-analyzer-conventional/src/main/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzer.java
index b493840..0611c9a 100644
--- a/semver-analyzer-conventional/src/main/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzer.java
+++ b/semver-analyzer-conventional/src/main/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzer.java
@@ -3,8 +3,11 @@
import io.github.sam42r.semver.analyzer.model.Configuration;
import io.github.sam42r.semver.model.analyze.AnalyzedCommit;
import io.github.sam42r.semver.model.analyze.ChangeCategory;
+import io.github.sam42r.semver.model.analyze.Issue;
import io.github.sam42r.semver.model.analyze.SemVerChangeLevel;
+import io.github.sam42r.semver.model.release.ProviderSpec;
import io.github.sam42r.semver.model.scm.Commit;
+import io.github.sam42r.semver.model.scm.Remote;
import lombok.AccessLevel;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@@ -13,6 +16,7 @@
import java.io.IOException;
import java.io.StringReader;
import java.io.UncheckedIOException;
+import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;
@@ -25,6 +29,7 @@
public class ConventionalCommitAnalyzer implements CommitAnalyzer {
private static final String COMMIT_HEADER_PATTERN = "(?([a-z]*))(?(\\([a-z]*\\)))?(?(!))?(?(: .*))";
+ private static final String COMMIT_FOOTER_PATTERN = "(?[(#\\d*))";
private final Configuration configuration;
@@ -34,13 +39,12 @@ public class ConventionalCommitAnalyzer implements CommitAnalyzer {
}
@Override
- public @NonNull List analyzeCommits(@NonNull List commits) {
- return commits.stream().map(this::analyzeCommit).toList();
+ public @NonNull List analyzeCommits(@NonNull List commits, @NonNull Remote remote, ProviderSpec providerSpec) {
+ return commits.stream().map(commit -> analyzeCommit(commit, remote, providerSpec)).toList();
}
-
@SuppressWarnings("MismatchedQueryAndUpdateOfStringBuilder")
- private AnalyzedCommit analyzeCommit(@NonNull Commit commit) {
+ private AnalyzedCommit analyzeCommit(@NonNull Commit commit, @NonNull Remote remote, ProviderSpec providerSpec) {
var headerBuilder = new StringBuilder();
var bodyBuilder = new StringBuilder();
var footerBuilder = new StringBuilder();
@@ -69,22 +73,29 @@ private AnalyzedCommit analyzeCommit(@NonNull Commit commit) {
var body = bodyBuilder.toString().trim();
var footer = footerBuilder.toString().trim();
- var pattern = Pattern.compile(COMMIT_HEADER_PATTERN);
- var matcher = pattern.matcher(header);
+ var headerMatcher = Pattern.compile(COMMIT_HEADER_PATTERN).matcher(header);
- if (header.isEmpty() || !matcher.find()) {
+ if (header.isEmpty() || !headerMatcher.find()) {
return new AnalyzedCommit(commit, null, null, null, null, null, null, null, null, null);
}
- var type = matcher.group("TYPE");
- var scope = Optional.ofNullable(matcher.group("SCOPE"))
+ var type = headerMatcher.group("TYPE");
+ var scope = Optional.ofNullable(headerMatcher.group("SCOPE"))
.map(v -> v.replace("(", ""))
.map(v -> v.replace(")", ""))
.orElse(null);
- var breaking = Optional.ofNullable(matcher.group("BREAKING"));
- var description = matcher.group("DESCRIPTION").replaceFirst(":", "").trim();
+ var breaking = Optional.ofNullable(headerMatcher.group("BREAKING"));
+ var description = headerMatcher.group("DESCRIPTION").replaceFirst(":", "").trim();
+
+ var footerMatcher = Pattern.compile(COMMIT_FOOTER_PATTERN).matcher(footer);
- // TODO search for issues in footer
+ var refs = footerMatcher.find() ?
+ Optional.ofNullable(footerMatcher.group("REF"))
+ .map(v -> v.replace("#", ""))
+ .map(String::trim)
+ .map(List::of)
+ .orElse(Collections.emptyList()) :
+ Collections.emptyList();
return new AnalyzedCommit(
commit,
@@ -96,7 +107,9 @@ private AnalyzedCommit analyzeCommit(@NonNull Commit commit) {
scope,
description,
breaking.isPresent() || footer.contains("BREAKING CHANGE") ? SemVerChangeLevel.MAJOR : getLevel(type),
- null
+ refs.stream()
+ .map(ref -> new Issue(ref, providerSpec.issueUrl(remote, ref)))
+ .toList()
);
}
diff --git a/semver-analyzer-conventional/src/test/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzerTest.java b/semver-analyzer-conventional/src/test/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzerTest.java
index ff8af23..87441ed 100644
--- a/semver-analyzer-conventional/src/test/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzerTest.java
+++ b/semver-analyzer-conventional/src/test/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzerTest.java
@@ -2,8 +2,11 @@
import io.github.sam42r.semver.model.analyze.AnalyzedCommit;
import io.github.sam42r.semver.model.analyze.ChangeCategory;
+import io.github.sam42r.semver.model.analyze.Issue;
import io.github.sam42r.semver.model.analyze.SemVerChangeLevel;
+import io.github.sam42r.semver.model.release.ProviderSpec;
import io.github.sam42r.semver.model.scm.Commit;
+import io.github.sam42r.semver.model.scm.Remote;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -24,15 +27,18 @@ void setup() {
@Test
void shouldFindFix() {
var actual = uut.analyzeCommits(List.of(
- new Commit("42", Instant.EPOCH, "JUnit",
- """
- fix(scm): set clean commit message
-
- * added scope for commit messages
-
- refs #42
- """)
- ));
+ new Commit("42", Instant.EPOCH, "JUnit",
+ """
+ fix(scm): set clean commit message
+
+ * added scope for commit messages
+
+ refs #42
+ """)
+ ),
+ Remote.of("git@github.com:Sam42R/semver-maven-plugin.git"),
+ new ProviderSpec("%s://%s/%s/%s/%s")
+ );
assertThat(actual).containsExactly(
new AnalyzedCommit(
@@ -52,25 +58,28 @@ void shouldFindFix() {
"scm",
"set clean commit message",
SemVerChangeLevel.PATCH,
- null)
+ List.of(new Issue("42", "https://github.com/Sam42R/semver-maven-plugin/42")))
);
}
@Test
void shouldFindBreakingChanges() {
var actual = uut.analyzeCommits(List.of(
- new Commit("42", Instant.EPOCH, "JUnit",
- """
- fix(scm): set clean commit message
-
- * added scope for commit messages
-
- BREAKING CHANGE: breaks everything
- refs #42
- """),
- new Commit("42", Instant.EPOCH, "JUnit",
- "fix(scm)!: set clean commit message")
- ));
+ new Commit("42", Instant.EPOCH, "JUnit",
+ """
+ fix(scm): set clean commit message
+
+ * added scope for commit messages
+
+ BREAKING CHANGE: breaks everything
+ refs #42
+ """),
+ new Commit("42", Instant.EPOCH, "JUnit",
+ "fix(scm)!: set clean commit message")
+ ),
+ Remote.of("git@github.com:Sam42R/semver-maven-plugin.git"),
+ new ProviderSpec("%s://%s/%s/%s/%s")
+ );
assertThat(actual).containsExactly(
new AnalyzedCommit(
@@ -91,7 +100,7 @@ void shouldFindBreakingChanges() {
"scm",
"set clean commit message",
SemVerChangeLevel.MAJOR,
- null),
+ List.of(new Issue("42", "https://github.com/Sam42R/semver-maven-plugin/42"))),
new AnalyzedCommit(
new Commit("42", Instant.EPOCH, "JUnit", "fix(scm)!: set clean commit message"),
"fix(scm)!: set clean commit message",
@@ -102,7 +111,7 @@ void shouldFindBreakingChanges() {
"scm",
"set clean commit message",
SemVerChangeLevel.MAJOR,
- null)
+ List.of())
);
}
}
diff --git a/semver-analyzer-gitmoji/src/main/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzer.java b/semver-analyzer-gitmoji/src/main/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzer.java
index 56bed3d..c35fa27 100644
--- a/semver-analyzer-gitmoji/src/main/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzer.java
+++ b/semver-analyzer-gitmoji/src/main/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzer.java
@@ -5,7 +5,9 @@
import io.github.sam42r.semver.model.analyze.ChangeCategory;
import io.github.sam42r.semver.model.analyze.Issue;
import io.github.sam42r.semver.model.analyze.SemVerChangeLevel;
+import io.github.sam42r.semver.model.release.ProviderSpec;
import io.github.sam42r.semver.model.scm.Commit;
+import io.github.sam42r.semver.model.scm.Remote;
import lombok.AccessLevel;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@@ -27,16 +29,16 @@ public class GitMojiCommitAnalyzer implements CommitAnalyzer {
private final Configuration configuration;
@Override
- public @NonNull List analyzeCommits(@NonNull List commits) {
- return commits.stream().map(this::analyzeCommit).toList();
+ public @NonNull String generateReleaseCommitMessage(@NonNull String version) {
+ return "%s: bump version %s".formatted(configuration.getRelease(), version);
}
@Override
- public @NonNull String generateReleaseCommitMessage(@NonNull String version) {
- return "%s: bump version %s".formatted(configuration.getRelease(), version);
+ public @NonNull List analyzeCommits(@NonNull List commits, @NonNull Remote remote, ProviderSpec providerSpec) {
+ return commits.stream().map(commit -> analyzeCommit(commit, remote, providerSpec)).toList();
}
- private AnalyzedCommit analyzeCommit(@NonNull Commit commit) {
+ private AnalyzedCommit analyzeCommit(@NonNull Commit commit, @NonNull Remote remote, ProviderSpec providerSpec) {
var pattern = Pattern.compile(COMMIT_MESSAGE_PATTERN);
var matcher = pattern.matcher(commit.message());
@@ -52,7 +54,7 @@ private AnalyzedCommit analyzeCommit(@NonNull Commit commit) {
.map(String::trim)
.orElse(null);
var message = matcher.group("MESSAGE").trim();
- var ref = Optional.ofNullable(matcher.group("REF"))
+ var refs = Optional.ofNullable(matcher.group("REF"))
.map(v -> v.replace("#", ""))
.map(String::trim)
.map(List::of)
@@ -68,7 +70,9 @@ private AnalyzedCommit analyzeCommit(@NonNull Commit commit) {
scope,
message,
getLevel(intention),
- ref.stream().map(v -> new Issue(v, "")).toList()
+ refs.stream()
+ .map(ref -> new Issue(ref, providerSpec.issueUrl(remote, ref)))
+ .toList()
);
}
diff --git a/semver-analyzer-gitmoji/src/test/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzerTest.java b/semver-analyzer-gitmoji/src/test/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzerTest.java
index e758bd5..590afad 100644
--- a/semver-analyzer-gitmoji/src/test/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzerTest.java
+++ b/semver-analyzer-gitmoji/src/test/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzerTest.java
@@ -4,7 +4,9 @@
import io.github.sam42r.semver.model.analyze.ChangeCategory;
import io.github.sam42r.semver.model.analyze.Issue;
import io.github.sam42r.semver.model.analyze.SemVerChangeLevel;
+import io.github.sam42r.semver.model.release.ProviderSpec;
import io.github.sam42r.semver.model.scm.Commit;
+import io.github.sam42r.semver.model.scm.Remote;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -25,9 +27,12 @@ void setup() {
@Test
void shouldFindFixAndFeat() {
var actual = uut.analyzeCommits(List.of(
- new Commit("42.1", Instant.EPOCH, "JUnit", ":bug: (scm) set clean commit message #42"),
- new Commit("42.2", Instant.EPOCH, "JUnit", ":sparkles: add awesome things")
- ));
+ new Commit("42.1", Instant.EPOCH, "JUnit", ":bug: (scm) set clean commit message #42"),
+ new Commit("42.2", Instant.EPOCH, "JUnit", ":sparkles: add awesome things")
+ ),
+ Remote.of("git@github.com:Sam42R/semver-maven-plugin.git"),
+ new ProviderSpec("%s://%s/%s/%s/%s")
+ );
assertThat(actual).containsExactlyInAnyOrder(
new AnalyzedCommit(
@@ -40,7 +45,7 @@ void shouldFindFixAndFeat() {
"scm",
"set clean commit message",
SemVerChangeLevel.PATCH,
- List.of(new Issue("42", ""))),
+ List.of(new Issue("42", "https://github.com/Sam42R/semver-maven-plugin/42"))),
new AnalyzedCommit(
new Commit("42.2", Instant.EPOCH, "JUnit", ":sparkles: add awesome things"),
":sparkles: add awesome things",
@@ -51,15 +56,18 @@ void shouldFindFixAndFeat() {
null,
"add awesome things",
SemVerChangeLevel.MINOR,
- null)
+ List.of())
);
}
@Test
void shouldFindBreaking() {
var actual = uut.analyzeCommits(List.of(
- new Commit("42.3", Instant.EPOCH, "JUnit", ":boom: (void): break some glass #42")
- ));
+ new Commit("42.3", Instant.EPOCH, "JUnit", ":boom: (void): break some glass #42")
+ ),
+ Remote.of("git@github.com:Sam42R/semver-maven-plugin.git"),
+ new ProviderSpec("%s://%s/%s/%s/%s")
+ );
assertThat(actual).containsExactly(
new AnalyzedCommit(
@@ -72,15 +80,18 @@ void shouldFindBreaking() {
"void",
"break some glass",
SemVerChangeLevel.MAJOR,
- List.of(new Issue("42","")))
+ List.of(new Issue("42", "https://github.com/Sam42R/semver-maven-plugin/42")))
);
}
@Test
void shouldFindOther() {
var actual = uut.analyzeCommits(List.of(
- new Commit("42.4", Instant.EPOCH, "JUnit", ":white_check_mark: add test for something")
- ));
+ new Commit("42.4", Instant.EPOCH, "JUnit", ":white_check_mark: add test for something")
+ ),
+ Remote.of("git@github.com:Sam42R/semver-maven-plugin.git"),
+ new ProviderSpec("%s://%s/%s/%s/%s")
+ );
assertThat(actual).containsExactly(
new AnalyzedCommit(
@@ -93,7 +104,7 @@ void shouldFindOther() {
null,
"add test for something",
SemVerChangeLevel.NONE,
- null)
+ List.of())
);
}
}
diff --git a/semver-changelog-html/src/main/resources/templates/default/default.html b/semver-changelog-html/src/main/resources/templates/default/default.html
index 72f82d2..638cad0 100644
--- a/semver-changelog-html/src/main/resources/templates/default/default.html
+++ b/semver-changelog-html/src/main/resources/templates/default/default.html
@@ -47,8 +47,11 @@ ]Changelog
- -
- Lorem ipsum
+
-
+ Lorem ipsum
+
+ ()
+
diff --git a/semver-changelog-html/src/main/resources/templates/missive/missive.html b/semver-changelog-html/src/main/resources/templates/missive/missive.html
index 924483c..96d3f3c 100644
--- a/semver-changelog-html/src/main/resources/templates/missive/missive.html
+++ b/semver-changelog-html/src/main/resources/templates/missive/missive.html
@@ -62,9 +62,11 @@ Changelog
- |
- Lorem ipsum
+ |
+ Lorem ipsum
+
+ ()
+
|
diff --git a/semver-changelog-html/src/main/resources/templates/spinal/spinal.html b/semver-changelog-html/src/main/resources/templates/spinal/spinal.html
index f3222cc..7192a78 100644
--- a/semver-changelog-html/src/main/resources/templates/spinal/spinal.html
+++ b/semver-changelog-html/src/main/resources/templates/spinal/spinal.html
@@ -54,9 +54,11 @@
-
- Lorem ipsum
+
+ Lorem ipsum
+
+ ()
+
diff --git a/semver-changelog-markup/src/main/resources/io/github/sam42r/semver/changelog/changelog.mustache b/semver-changelog-markup/src/main/resources/io/github/sam42r/semver/changelog/changelog.mustache
index 2a34b52..c9913aa 100644
--- a/semver-changelog-markup/src/main/resources/io/github/sam42r/semver/changelog/changelog.mustache
+++ b/semver-changelog-markup/src/main/resources/io/github/sam42r/semver/changelog/changelog.mustache
@@ -9,43 +9,43 @@
### Added
{{/hasAdded}}
{{#added}}
-- {{header}}
+- {{header}} {{#issues}}([#{{id}}]({{url}})){{/issues}}
{{/added}}
{{#hasChanges}}
### Changed
{{/hasChanges}}
{{#changes}}
-- {{header}}
+- {{header}} {{#issues}}([#{{id}}]({{url}})){{/issues}}
{{/changes}}
{{#hasDeprecated}}
### Deprecated
{{/hasDeprecated}}
{{#deprecated}}
-- {{header}}
+- {{header}} {{#issues}}([#{{id}}]({{url}})){{/issues}}
{{/deprecated}}
{{#hasRemoved}}
### Removed
{{/hasRemoved}}
{{#removed}}
-- {{header}}
+- {{header}} {{#issues}}([#{{id}}]({{url}})){{/issues}}
{{/removed}}
{{#hasPatches}}
### Fixed
{{/hasPatches}}
{{#patches}}
-- {{header}}
+- {{header}} {{#issues}}([#{{id}}]({{url}})){{/issues}}
{{/patches}}
{{#hasSecurity}}
### Security
{{/hasSecurity}}
{{#securities}}
-- {{header}}
+- {{header}} {{#issues}}([#{{id}}]({{url}})){{/issues}}
{{/securities}}
{{#hasOthers}}
### Others
{{/hasOthers}}
{{#others}}
-- {{header}}
+- {{header}} {{#issues}}([#{{id}}]({{url}})){{/issues}}
{{/others}}
{{#renderFooter}}
diff --git a/semver-maven-model/src/main/java/io/github/sam42r/semver/model/release/ProviderSpec.java b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/release/ProviderSpec.java
new file mode 100644
index 0000000..d08a484
--- /dev/null
+++ b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/release/ProviderSpec.java
@@ -0,0 +1,10 @@
+package io.github.sam42r.semver.model.release;
+
+import io.github.sam42r.semver.model.scm.Remote;
+
+public record ProviderSpec(String issuePattern) {
+
+ public String issueUrl(Remote remote, String id) {
+ return issuePattern().formatted(remote.scheme(), remote.host(), remote.group(), remote.project(), id);
+ }
+}
diff --git a/semver-maven-plugin/src/main/java/io/github/sam42r/semver/SemanticReleaseMojo.java b/semver-maven-plugin/src/main/java/io/github/sam42r/semver/SemanticReleaseMojo.java
index f132dad..b18ba02 100644
--- a/semver-maven-plugin/src/main/java/io/github/sam42r/semver/SemanticReleaseMojo.java
+++ b/semver-maven-plugin/src/main/java/io/github/sam42r/semver/SemanticReleaseMojo.java
@@ -131,7 +131,7 @@ public void execute() throws MojoExecutionException, MojoFailureException {
.orElse(Version.of(0, 0, 0, tagFormat));
getLog().debug("Actual version: '%s'".formatted(latestVersion.toString()));
- var analyzedCommits = analyzeCommits(scmProvider, commitAnalyzer, latestCommit);
+ var analyzedCommits = analyzeCommits(scmProvider, commitAnalyzer, releasePublisher, latestCommit);
var majorCount = analyzedCommits.stream().filter(AnalyzedCommit.isBreaking).count();
var minorCount = analyzedCommits.stream().filter(AnalyzedCommit.isFeature).count();
@@ -251,11 +251,12 @@ private LatestReleaseInfo getLatestRelease(SCMProvider scmProvider) throws MojoE
private List analyzeCommits(
SCMProvider scmProvider,
CommitAnalyzer commitAnalyzer,
+ ReleasePublisher releasePublisher,
String latestCommit
) throws MojoExecutionException {
try {
var commits = scmProvider.readCommits(latestCommit);
- return commitAnalyzer.analyzeCommits(commits.toList());
+ return commitAnalyzer.analyzeCommits(commits.toList(), scmProvider.getRemote(), releasePublisher.providerSpec());
} catch (SCMException e) {
throw new MojoExecutionException(e.getMessage(), e.getCause());
}
diff --git a/semver-maven-plugin/src/test/java/io/github/sam42r/semver/SemanticReleaseMojoTest.java b/semver-maven-plugin/src/test/java/io/github/sam42r/semver/SemanticReleaseMojoTest.java
index 71f03fb..8e62369 100644
--- a/semver-maven-plugin/src/test/java/io/github/sam42r/semver/SemanticReleaseMojoTest.java
+++ b/semver-maven-plugin/src/test/java/io/github/sam42r/semver/SemanticReleaseMojoTest.java
@@ -12,12 +12,14 @@
import org.apache.maven.project.MavenProject;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.transport.URIish;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.IOException;
+import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
@@ -72,7 +74,7 @@ void setup() throws IOException {
@Test
@SuppressWarnings("unchecked")
- void shouldFindNoLatestRelease() throws GitAPIException, MojoExecutionException, MojoFailureException {
+ void shouldFindNoLatestRelease() throws GitAPIException, MojoExecutionException, MojoFailureException, URISyntaxException {
try (var git = initializeGitRepository(tmp)) {
git.add().addFilepattern("pom.xml").call();
git.commit().setMessage("Initial commit").call();
@@ -85,7 +87,7 @@ void shouldFindNoLatestRelease() throws GitAPIException, MojoExecutionException,
@Test
@SuppressWarnings("unchecked")
- void shouldFindLatestRelease() throws IOException, GitAPIException, MojoExecutionException, MojoFailureException {
+ void shouldFindLatestRelease() throws IOException, GitAPIException, MojoExecutionException, MojoFailureException, URISyntaxException {
try (var git = initializeGitRepository(tmp)) {
git.add().addFilepattern("pom.xml").call();
git.commit().setMessage("Initial commit").call();
@@ -102,7 +104,7 @@ void shouldFindLatestRelease() throws IOException, GitAPIException, MojoExecutio
}
@Test
- void shouldThrowWithEmptyGitRepository() throws GitAPIException {
+ void shouldThrowWithEmptyGitRepository() throws GitAPIException, URISyntaxException {
try (var ignored = initializeGitRepository(tmp)) {
assertThatThrownBy(() -> uut.execute())
.isInstanceOf(MojoExecutionException.class)
@@ -117,8 +119,17 @@ void shouldThrowWithMissingGitRepository() {
.hasMessageStartingWith("Could not find git configuration");
}
- private Git initializeGitRepository(Path path) throws GitAPIException {
- return Git.init().setDirectory(path.toFile()).call();
+ private Git initializeGitRepository(Path path) throws GitAPIException, URISyntaxException {
+ var git = Git.init()
+ .setDirectory(path.toFile())
+ .call();
+
+ git.remoteAdd()
+ .setName("origin")
+ .setUri(new URIish("https://junit.org/test/project"))
+ .call();
+
+ return git;
}
private Path createFile(Path path, String filename, String content) throws IOException {
diff --git a/semver-release-api/src/main/java/io/github/sam24r/semver/release/ReleasePublisher.java b/semver-release-api/src/main/java/io/github/sam24r/semver/release/ReleasePublisher.java
index 4b2932a..df970c1 100644
--- a/semver-release-api/src/main/java/io/github/sam24r/semver/release/ReleasePublisher.java
+++ b/semver-release-api/src/main/java/io/github/sam24r/semver/release/ReleasePublisher.java
@@ -1,5 +1,6 @@
package io.github.sam24r.semver.release;
+import io.github.sam42r.semver.model.release.ProviderSpec;
import io.github.sam42r.semver.model.release.ReleaseInfo;
import lombok.NonNull;
@@ -12,4 +13,6 @@ void publish(
@NonNull String project,
@NonNull ReleaseInfo releaseInfo
) throws ReleaseException;
+
+ ProviderSpec providerSpec();
}
diff --git a/semver-release-github/src/main/java/io/github/sam42r/semver/release/DefaultGithubPublisher.java b/semver-release-github/src/main/java/io/github/sam42r/semver/release/DefaultGithubPublisher.java
index 8a43751..c025500 100644
--- a/semver-release-github/src/main/java/io/github/sam42r/semver/release/DefaultGithubPublisher.java
+++ b/semver-release-github/src/main/java/io/github/sam42r/semver/release/DefaultGithubPublisher.java
@@ -2,6 +2,7 @@
import io.github.sam24r.semver.release.ReleaseException;
import io.github.sam24r.semver.release.ReleasePublisher;
+import io.github.sam42r.semver.model.release.ProviderSpec;
import io.github.sam42r.semver.model.release.ReleaseInfo;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@@ -49,4 +50,11 @@ public void publish(
throw new ReleaseException(e);
}
}
+
+ @Override
+ public ProviderSpec providerSpec() {
+ return new ProviderSpec(
+ "%s://%s/%s/%s/issues/%s"
+ );
+ }
}
diff --git a/semver-release-gitlab/src/main/java/io/github/sam42r/semver/release/GitlabPublisher.java b/semver-release-gitlab/src/main/java/io/github/sam42r/semver/release/GitlabPublisher.java
index 0d583f9..ce446af 100644
--- a/semver-release-gitlab/src/main/java/io/github/sam42r/semver/release/GitlabPublisher.java
+++ b/semver-release-gitlab/src/main/java/io/github/sam42r/semver/release/GitlabPublisher.java
@@ -3,6 +3,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.sam24r.semver.release.ReleaseException;
import io.github.sam24r.semver.release.ReleasePublisher;
+import io.github.sam42r.semver.model.release.ProviderSpec;
import io.github.sam42r.semver.model.release.ReleaseInfo;
import io.github.sam42r.semver.release.model.GitlabRelease;
import lombok.NonNull;
@@ -74,4 +75,11 @@ private GitlabRelease generatePayload(ReleaseInfo releaseInfo) {
.description(releaseInfo.description())
.build();
}
+
+ @Override
+ public ProviderSpec providerSpec() {
+ return new ProviderSpec(
+ "%s://%s/%s/%s/-/issues/%s"
+ );
+ }
}
From 1b5862e3a614b2253a5ee5018de648c0a1ac4229 Mon Sep 17 00:00:00 2001
From: Rene R
Date: Mon, 9 Feb 2026 10:42:26 +0100
Subject: [PATCH 3/4] :sparkles: generate commit links #41
---
.../analyzer/model/ConfigurationTest.java | 28 +++++-----
.../analyzer/ConventionalCommitAnalyzer.java | 3 +-
.../ConventionalCommitAnalyzerTest.java | 7 ++-
.../analyzer/GitMojiCommitAnalyzer.java | 3 +-
.../analyzer/GitMojiCommitAnalyzerTest.java | 10 +++-
.../resources/templates/default/default.html | 4 ++
.../resources/templates/missive/missive.html | 4 ++
.../resources/templates/spinal/spinal.html | 4 ++
.../semver/changelog/HtmlRendererTest.java | 10 +++-
.../semver/changelog/MarkupRenderer.java | 56 ++++++++++++++++---
.../sam42r/semver/changelog/model/Link.java | 4 ++
.../changelog/model/RenderedCommit.java | 6 ++
.../semver/changelog/changelog.mustache | 14 ++---
.../semver/changelog/MarkupRendererTest.java | 4 +-
.../semver/model/analyze/AnalyzedCommit.java | 16 ++++++
.../semver/model/release/ProviderSpec.java | 6 +-
.../release/DefaultGithubPublisher.java | 3 +-
.../semver/release/GitlabPublisher.java | 3 +-
18 files changed, 142 insertions(+), 43 deletions(-)
create mode 100644 semver-changelog-markup/src/main/java/io/github/sam42r/semver/changelog/model/Link.java
create mode 100644 semver-changelog-markup/src/main/java/io/github/sam42r/semver/changelog/model/RenderedCommit.java
diff --git a/semver-analyzer-api/src/test/java/io/github/sam42r/semver/analyzer/model/ConfigurationTest.java b/semver-analyzer-api/src/test/java/io/github/sam42r/semver/analyzer/model/ConfigurationTest.java
index 4f82c49..74de068 100644
--- a/semver-analyzer-api/src/test/java/io/github/sam42r/semver/analyzer/model/ConfigurationTest.java
+++ b/semver-analyzer-api/src/test/java/io/github/sam42r/semver/analyzer/model/ConfigurationTest.java
@@ -20,13 +20,13 @@ void shouldReadConfigFromClasspath() {
Configuration::getRelease, Configuration::getItems)
.containsExactly(
"R0", List.of(
- new AnalyzedCommit(null, null, null, null, "D1", ChangeCategory.DEPRECATED, null, null, SemVerChangeLevel.NONE, null),
- new AnalyzedCommit(null, null, null, null, "R1", ChangeCategory.REMOVED, null, null, SemVerChangeLevel.NONE, null),
- new AnalyzedCommit(null, null, null, null, "F1", ChangeCategory.FIXED, null, null, SemVerChangeLevel.PATCH, null),
- new AnalyzedCommit(null, null, null, null, "S1", ChangeCategory.SECURITY, null, null, SemVerChangeLevel.PATCH, null),
- new AnalyzedCommit(null, null, null, null, "A1", ChangeCategory.ADDED, null, null, SemVerChangeLevel.MINOR, null),
- new AnalyzedCommit(null, null, null, null, "C1", ChangeCategory.CHANGED, null, null, SemVerChangeLevel.MINOR, null),
- new AnalyzedCommit(null, null, null, null, "B1", ChangeCategory.OTHER, null, null, SemVerChangeLevel.MAJOR, null)
+ new AnalyzedCommit(null, null, null, null, null, "D1", ChangeCategory.DEPRECATED, null, null, SemVerChangeLevel.NONE, null),
+ new AnalyzedCommit(null, null, null, null, null, "R1", ChangeCategory.REMOVED, null, null, SemVerChangeLevel.NONE, null),
+ new AnalyzedCommit(null, null, null, null, null, "F1", ChangeCategory.FIXED, null, null, SemVerChangeLevel.PATCH, null),
+ new AnalyzedCommit(null, null, null, null, null, "S1", ChangeCategory.SECURITY, null, null, SemVerChangeLevel.PATCH, null),
+ new AnalyzedCommit(null, null, null, null, null, "A1", ChangeCategory.ADDED, null, null, SemVerChangeLevel.MINOR, null),
+ new AnalyzedCommit(null, null, null, null, null, "C1", ChangeCategory.CHANGED, null, null, SemVerChangeLevel.MINOR, null),
+ new AnalyzedCommit(null, null, null, null, null, "B1", ChangeCategory.OTHER, null, null, SemVerChangeLevel.MAJOR, null)
)
);
}
@@ -41,13 +41,13 @@ void shouldReadConfigFromFile() {
Configuration::getRelease, Configuration::getItems)
.containsExactly(
"R0", List.of(
- new AnalyzedCommit(null, null, null, null, "D1", ChangeCategory.DEPRECATED, null, null, SemVerChangeLevel.NONE, null),
- new AnalyzedCommit(null, null, null, null, "R1", ChangeCategory.REMOVED, null, null, SemVerChangeLevel.NONE, null),
- new AnalyzedCommit(null, null, null, null, "F1", ChangeCategory.FIXED, null, null, SemVerChangeLevel.PATCH, null),
- new AnalyzedCommit(null, null, null, null, "S1", ChangeCategory.SECURITY, null, null, SemVerChangeLevel.PATCH, null),
- new AnalyzedCommit(null, null, null, null, "A1", ChangeCategory.ADDED, null, null, SemVerChangeLevel.MINOR, null),
- new AnalyzedCommit(null, null, null, null, "C1", ChangeCategory.CHANGED, null, null, SemVerChangeLevel.MINOR, null),
- new AnalyzedCommit(null, null, null, null, "B1", ChangeCategory.OTHER, null, null, SemVerChangeLevel.MAJOR, null)
+ new AnalyzedCommit(null, null, null, null, null, "D1", ChangeCategory.DEPRECATED, null, null, SemVerChangeLevel.NONE, null),
+ new AnalyzedCommit(null, null, null, null, null, "R1", ChangeCategory.REMOVED, null, null, SemVerChangeLevel.NONE, null),
+ new AnalyzedCommit(null, null, null, null, null, "F1", ChangeCategory.FIXED, null, null, SemVerChangeLevel.PATCH, null),
+ new AnalyzedCommit(null, null, null, null, null, "S1", ChangeCategory.SECURITY, null, null, SemVerChangeLevel.PATCH, null),
+ new AnalyzedCommit(null, null, null, null, null, "A1", ChangeCategory.ADDED, null, null, SemVerChangeLevel.MINOR, null),
+ new AnalyzedCommit(null, null, null, null, null, "C1", ChangeCategory.CHANGED, null, null, SemVerChangeLevel.MINOR, null),
+ new AnalyzedCommit(null, null, null, null, null, "B1", ChangeCategory.OTHER, null, null, SemVerChangeLevel.MAJOR, null)
)
);
}
diff --git a/semver-analyzer-conventional/src/main/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzer.java b/semver-analyzer-conventional/src/main/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzer.java
index 0611c9a..74e7c67 100644
--- a/semver-analyzer-conventional/src/main/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzer.java
+++ b/semver-analyzer-conventional/src/main/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzer.java
@@ -76,7 +76,7 @@ private AnalyzedCommit analyzeCommit(@NonNull Commit commit, @NonNull Remote rem
var headerMatcher = Pattern.compile(COMMIT_HEADER_PATTERN).matcher(header);
if (header.isEmpty() || !headerMatcher.find()) {
- return new AnalyzedCommit(commit, null, null, null, null, null, null, null, null, null);
+ return new AnalyzedCommit(commit, null, null, null, null, null, null, null, null, null, null);
}
var type = headerMatcher.group("TYPE");
@@ -99,6 +99,7 @@ private AnalyzedCommit analyzeCommit(@NonNull Commit commit, @NonNull Remote rem
return new AnalyzedCommit(
commit,
+ providerSpec.issueUrl(remote, commit.id()),
header,
body,
footer,
diff --git a/semver-analyzer-conventional/src/test/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzerTest.java b/semver-analyzer-conventional/src/test/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzerTest.java
index 87441ed..897dcd8 100644
--- a/semver-analyzer-conventional/src/test/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzerTest.java
+++ b/semver-analyzer-conventional/src/test/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzerTest.java
@@ -37,7 +37,7 @@ void shouldFindFix() {
""")
),
Remote.of("git@github.com:Sam42R/semver-maven-plugin.git"),
- new ProviderSpec("%s://%s/%s/%s/%s")
+ new ProviderSpec("%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s")
);
assertThat(actual).containsExactly(
@@ -50,6 +50,7 @@ void shouldFindFix() {
refs #42
"""),
+ "https://github.com/Sam42R/semver-maven-plugin/42",
"fix(scm): set clean commit message",
"* added scope for commit messages",
"refs #42",
@@ -78,7 +79,7 @@ void shouldFindBreakingChanges() {
"fix(scm)!: set clean commit message")
),
Remote.of("git@github.com:Sam42R/semver-maven-plugin.git"),
- new ProviderSpec("%s://%s/%s/%s/%s")
+ new ProviderSpec("%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s")
);
assertThat(actual).containsExactly(
@@ -92,6 +93,7 @@ void shouldFindBreakingChanges() {
BREAKING CHANGE: breaks everything
refs #42
"""),
+ "https://github.com/Sam42R/semver-maven-plugin/42",
"fix(scm): set clean commit message",
"* added scope for commit messages",
"BREAKING CHANGE: breaks everything%srefs #42".formatted(System.lineSeparator()),
@@ -103,6 +105,7 @@ void shouldFindBreakingChanges() {
List.of(new Issue("42", "https://github.com/Sam42R/semver-maven-plugin/42"))),
new AnalyzedCommit(
new Commit("42", Instant.EPOCH, "JUnit", "fix(scm)!: set clean commit message"),
+ "https://github.com/Sam42R/semver-maven-plugin/42",
"fix(scm)!: set clean commit message",
"",
"",
diff --git a/semver-analyzer-gitmoji/src/main/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzer.java b/semver-analyzer-gitmoji/src/main/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzer.java
index c35fa27..ed0ba03 100644
--- a/semver-analyzer-gitmoji/src/main/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzer.java
+++ b/semver-analyzer-gitmoji/src/main/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzer.java
@@ -43,7 +43,7 @@ private AnalyzedCommit analyzeCommit(@NonNull Commit commit, @NonNull Remote rem
var matcher = pattern.matcher(commit.message());
if (!commit.message().startsWith(":") || !matcher.find()) {
- return new AnalyzedCommit(commit, null, null, null, null, null, null, null, null, null);
+ return new AnalyzedCommit(commit, null, null, null, null, null, null, null, null, null, null);
}
var intention = matcher.group("INTENTION");
@@ -62,6 +62,7 @@ private AnalyzedCommit analyzeCommit(@NonNull Commit commit, @NonNull Remote rem
return new AnalyzedCommit(
commit,
+ providerSpec.commitUrl(remote, commit.id()),
commit.message(),
null,
null,
diff --git a/semver-analyzer-gitmoji/src/test/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzerTest.java b/semver-analyzer-gitmoji/src/test/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzerTest.java
index 590afad..a601b27 100644
--- a/semver-analyzer-gitmoji/src/test/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzerTest.java
+++ b/semver-analyzer-gitmoji/src/test/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzerTest.java
@@ -31,12 +31,13 @@ void shouldFindFixAndFeat() {
new Commit("42.2", Instant.EPOCH, "JUnit", ":sparkles: add awesome things")
),
Remote.of("git@github.com:Sam42R/semver-maven-plugin.git"),
- new ProviderSpec("%s://%s/%s/%s/%s")
+ new ProviderSpec("%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s")
);
assertThat(actual).containsExactlyInAnyOrder(
new AnalyzedCommit(
new Commit("42.1", Instant.EPOCH, "JUnit", ":bug: (scm) set clean commit message #42"),
+ "https://github.com/Sam42R/semver-maven-plugin/42.1",
":bug: (scm) set clean commit message #42",
null,
null,
@@ -48,6 +49,7 @@ void shouldFindFixAndFeat() {
List.of(new Issue("42", "https://github.com/Sam42R/semver-maven-plugin/42"))),
new AnalyzedCommit(
new Commit("42.2", Instant.EPOCH, "JUnit", ":sparkles: add awesome things"),
+ "https://github.com/Sam42R/semver-maven-plugin/42.2",
":sparkles: add awesome things",
null,
null,
@@ -66,12 +68,13 @@ void shouldFindBreaking() {
new Commit("42.3", Instant.EPOCH, "JUnit", ":boom: (void): break some glass #42")
),
Remote.of("git@github.com:Sam42R/semver-maven-plugin.git"),
- new ProviderSpec("%s://%s/%s/%s/%s")
+ new ProviderSpec("%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s")
);
assertThat(actual).containsExactly(
new AnalyzedCommit(
new Commit("42.3", Instant.EPOCH, "JUnit", ":boom: (void): break some glass #42"),
+ "https://github.com/Sam42R/semver-maven-plugin/42.3",
":boom: (void): break some glass #42",
null,
null,
@@ -90,12 +93,13 @@ void shouldFindOther() {
new Commit("42.4", Instant.EPOCH, "JUnit", ":white_check_mark: add test for something")
),
Remote.of("git@github.com:Sam42R/semver-maven-plugin.git"),
- new ProviderSpec("%s://%s/%s/%s/%s")
+ new ProviderSpec("%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s")
);
assertThat(actual).containsExactly(
new AnalyzedCommit(
new Commit("42.4", Instant.EPOCH, "JUnit", ":white_check_mark: add test for something"),
+ "https://github.com/Sam42R/semver-maven-plugin/42.4",
":white_check_mark: add test for something",
null,
null,
diff --git a/semver-changelog-html/src/main/resources/templates/default/default.html b/semver-changelog-html/src/main/resources/templates/default/default.html
index 638cad0..2d709dc 100644
--- a/semver-changelog-html/src/main/resources/templates/default/default.html
+++ b/semver-changelog-html/src/main/resources/templates/default/default.html
@@ -52,6 +52,10 @@ Changelog
()
+
+
+
diff --git a/semver-changelog-html/src/main/resources/templates/missive/missive.html b/semver-changelog-html/src/main/resources/templates/missive/missive.html
index 96d3f3c..79f5417 100644
--- a/semver-changelog-html/src/main/resources/templates/missive/missive.html
+++ b/semver-changelog-html/src/main/resources/templates/missive/missive.html
@@ -66,6 +66,10 @@ Changelog
Lorem ipsum
()
+
+
+
|
diff --git a/semver-changelog-html/src/main/resources/templates/spinal/spinal.html b/semver-changelog-html/src/main/resources/templates/spinal/spinal.html
index 7192a78..7e120e8 100644
--- a/semver-changelog-html/src/main/resources/templates/spinal/spinal.html
+++ b/semver-changelog-html/src/main/resources/templates/spinal/spinal.html
@@ -59,6 +59,10 @@
()
+
+
+
diff --git a/semver-changelog-html/src/test/java/io/github/sam42r/semver/changelog/HtmlRendererTest.java b/semver-changelog-html/src/test/java/io/github/sam42r/semver/changelog/HtmlRendererTest.java
index b502c0b..97591ad 100644
--- a/semver-changelog-html/src/test/java/io/github/sam42r/semver/changelog/HtmlRendererTest.java
+++ b/semver-changelog-html/src/test/java/io/github/sam42r/semver/changelog/HtmlRendererTest.java
@@ -6,6 +6,7 @@
import io.github.sam42r.semver.model.analyze.ChangeCategory;
import io.github.sam42r.semver.model.analyze.SemVerChangeLevel;
import io.github.sam42r.semver.model.scm.Commit;
+import org.apache.commons.codec.digest.DigestUtils;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
@@ -73,7 +74,7 @@ private VersionInfo release(String version) {
private List analyzedCommits() {
return List.of(
new AnalyzedCommit(
- new Commit("42", Instant.EPOCH, "JUnit",
+ new Commit(DigestUtils.sha256Hex("42.1"), Instant.EPOCH, "JUnit",
"""
feat(scm): Lorem ipsum
@@ -81,6 +82,7 @@ private List analyzedCommits() {
refs #42
"""),
+ null,
"feat(scm): Lorem ipsum",
"* Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam",
"refs #42",
@@ -92,7 +94,7 @@ private List analyzedCommits() {
null
),
new AnalyzedCommit(
- new Commit("42", Instant.EPOCH, "JUnit",
+ new Commit(DigestUtils.sha256Hex("42.2"), Instant.EPOCH, "JUnit",
"""
fix(scm): Lorem ipsum
@@ -100,6 +102,7 @@ private List analyzedCommits() {
refs #42
"""),
+ null,
"fix(scm): Lorem ipsum",
"* Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam",
"refs #42",
@@ -111,7 +114,7 @@ private List analyzedCommits() {
null
),
new AnalyzedCommit(
- new Commit("42", Instant.EPOCH, "JUnit",
+ new Commit(DigestUtils.sha256Hex("42.3"), Instant.EPOCH, "JUnit",
"""
chore(scm): Lorem ipsum
@@ -119,6 +122,7 @@ private List analyzedCommits() {
refs #42
"""),
+ "https://junit.org/test/%s".formatted(DigestUtils.sha256Hex("42.3")),
"chore(scm): Lorem ipsum",
"* Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam",
"refs #42",
diff --git a/semver-changelog-markup/src/main/java/io/github/sam42r/semver/changelog/MarkupRenderer.java b/semver-changelog-markup/src/main/java/io/github/sam42r/semver/changelog/MarkupRenderer.java
index 1fab652..a1da05e 100644
--- a/semver-changelog-markup/src/main/java/io/github/sam42r/semver/changelog/MarkupRenderer.java
+++ b/semver-changelog-markup/src/main/java/io/github/sam42r/semver/changelog/MarkupRenderer.java
@@ -1,17 +1,21 @@
package io.github.sam42r.semver.changelog;
import com.github.mustachejava.DefaultMustacheFactory;
-import io.github.sam42r.semver.model.changelog.VersionInfo;
+import io.github.sam42r.semver.changelog.model.Link;
+import io.github.sam42r.semver.changelog.model.RenderedCommit;
import io.github.sam42r.semver.model.analyze.AnalyzedCommit;
import io.github.sam42r.semver.model.analyze.ChangeCategory;
+import io.github.sam42r.semver.model.changelog.VersionInfo;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
+import org.apache.commons.codec.binary.StringUtils;
import org.apache.commons.codec.digest.DigestUtils;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
@@ -65,25 +69,32 @@ public class MarkupRenderer implements ChangelogRenderer {
context.put("release", versionInfo);
context.put("hasAdded", categorizedCommits.containsKey(ChangeCategory.ADDED));
- context.put("added", categorizedCommits.get(ChangeCategory.ADDED));
+ context.put("added", categorizedCommits.getOrDefault(ChangeCategory.ADDED, Collections.emptyList())
+ .stream().map(this::renderedCommit).toList());
context.put("hasChanges", categorizedCommits.containsKey(ChangeCategory.CHANGED));
- context.put("changes", categorizedCommits.get(ChangeCategory.CHANGED));
+ context.put("changes", categorizedCommits.getOrDefault(ChangeCategory.CHANGED, Collections.emptyList())
+ .stream().map(this::renderedCommit).toList());
context.put("hasDeprecated", categorizedCommits.containsKey(ChangeCategory.DEPRECATED));
- context.put("deprecated", categorizedCommits.get(ChangeCategory.DEPRECATED));
+ context.put("deprecated", categorizedCommits.getOrDefault(ChangeCategory.DEPRECATED, Collections.emptyList())
+ .stream().map(this::renderedCommit).toList());
context.put("hasRemoved", categorizedCommits.containsKey(ChangeCategory.REMOVED));
- context.put("removed", categorizedCommits.get(ChangeCategory.REMOVED));
+ context.put("removed", categorizedCommits.getOrDefault(ChangeCategory.REMOVED, Collections.emptyList())
+ .stream().map(this::renderedCommit).toList());
context.put("hasPatches", categorizedCommits.containsKey(ChangeCategory.FIXED));
- context.put("patches", categorizedCommits.get(ChangeCategory.FIXED));
+ context.put("patches", categorizedCommits.getOrDefault(ChangeCategory.FIXED, Collections.emptyList())
+ .stream().map(this::renderedCommit).toList());
context.put("hasSecurity", categorizedCommits.containsKey(ChangeCategory.SECURITY));
- context.put("securities", categorizedCommits.get(ChangeCategory.SECURITY));
+ context.put("securities", categorizedCommits.getOrDefault(ChangeCategory.SECURITY, Collections.emptyList())
+ .stream().map(this::renderedCommit).toList());
context.put("hasOthers", categorizedCommits.containsKey(ChangeCategory.OTHER));
- context.put("others", categorizedCommits.get(ChangeCategory.OTHER));
+ context.put("others", categorizedCommits.getOrDefault(ChangeCategory.OTHER, Collections.emptyList())
+ .stream().map(this::renderedCommit).toList());
context.put("renderHeader", !alreadyExists);
context.put("renderFooter", !alreadyExists);
@@ -106,4 +117,33 @@ public class MarkupRenderer implements ChangelogRenderer {
throw new UncheckedIOException(e);
}
}
+
+ /**
+ * Transform {@link AnalyzedCommit} to Mustache compliant {@link RenderedCommit}.
+ * (Since Mustache is more or less logic less we have to use rendering optimized model)
+ *
+ * @param analyzedCommit the {@link AnalyzedCommit} to transform
+ * @return Mustache compliant {@link RenderedCommit}
+ */
+ private RenderedCommit renderedCommit(AnalyzedCommit analyzedCommit) {
+ return new RenderedCommit(
+ analyzedCommit.header(),
+ analyzedCommit.url() == null || analyzedCommit.url().isBlank() ?
+ null :
+ new Link(trimToLength(analyzedCommit.commit().id(), 7), analyzedCommit.url()),
+ analyzedCommit.issues() == null || analyzedCommit.issues().isEmpty() ?
+ Collections.emptyList() :
+ analyzedCommit.issues().stream()
+ .filter(v -> v.url() != null && !v.url().isBlank())
+ .map(v -> new Link(v.id(), v.url()))
+ .toList()
+ );
+ }
+
+ private String trimToLength(String string, int length) {
+ if (string != null && string.length() > length) {
+ return string.substring(0, length);
+ }
+ return string;
+ }
}
diff --git a/semver-changelog-markup/src/main/java/io/github/sam42r/semver/changelog/model/Link.java b/semver-changelog-markup/src/main/java/io/github/sam42r/semver/changelog/model/Link.java
new file mode 100644
index 0000000..3d4a51d
--- /dev/null
+++ b/semver-changelog-markup/src/main/java/io/github/sam42r/semver/changelog/model/Link.java
@@ -0,0 +1,4 @@
+package io.github.sam42r.semver.changelog.model;
+
+public record Link(String name, String href) {
+}
diff --git a/semver-changelog-markup/src/main/java/io/github/sam42r/semver/changelog/model/RenderedCommit.java b/semver-changelog-markup/src/main/java/io/github/sam42r/semver/changelog/model/RenderedCommit.java
new file mode 100644
index 0000000..1205f66
--- /dev/null
+++ b/semver-changelog-markup/src/main/java/io/github/sam42r/semver/changelog/model/RenderedCommit.java
@@ -0,0 +1,6 @@
+package io.github.sam42r.semver.changelog.model;
+
+import java.util.List;
+
+public record RenderedCommit(String message, Link reference, List issues) {
+}
diff --git a/semver-changelog-markup/src/main/resources/io/github/sam42r/semver/changelog/changelog.mustache b/semver-changelog-markup/src/main/resources/io/github/sam42r/semver/changelog/changelog.mustache
index c9913aa..711885e 100644
--- a/semver-changelog-markup/src/main/resources/io/github/sam42r/semver/changelog/changelog.mustache
+++ b/semver-changelog-markup/src/main/resources/io/github/sam42r/semver/changelog/changelog.mustache
@@ -9,43 +9,43 @@
### Added
{{/hasAdded}}
{{#added}}
-- {{header}} {{#issues}}([#{{id}}]({{url}})){{/issues}}
+- {{message}} {{#issues}}([#{{name}}]({{href}})){{/issues}} {{#reference}}[{{name}}]({{href}}){{/reference}}
{{/added}}
{{#hasChanges}}
### Changed
{{/hasChanges}}
{{#changes}}
-- {{header}} {{#issues}}([#{{id}}]({{url}})){{/issues}}
+- {{message}} {{#issues}}([#{{name}}]({{href}})){{/issues}} {{#reference}}[{{name}}]({{href}}){{/reference}}
{{/changes}}
{{#hasDeprecated}}
### Deprecated
{{/hasDeprecated}}
{{#deprecated}}
-- {{header}} {{#issues}}([#{{id}}]({{url}})){{/issues}}
+- {{message}} {{#issues}}([#{{name}}]({{href}})){{/issues}} {{#reference}}[{{name}}]({{href}}){{/reference}}
{{/deprecated}}
{{#hasRemoved}}
### Removed
{{/hasRemoved}}
{{#removed}}
-- {{header}} {{#issues}}([#{{id}}]({{url}})){{/issues}}
+- {{message}} {{#issues}}([#{{name}}]({{href}})){{/issues}} {{#reference}}[{{name}}]({{href}}){{/reference}}
{{/removed}}
{{#hasPatches}}
### Fixed
{{/hasPatches}}
{{#patches}}
-- {{header}} {{#issues}}([#{{id}}]({{url}})){{/issues}}
+- {{message}} {{#issues}}([#{{name}}]({{href}})){{/issues}} {{#reference}}[{{name}}]({{href}}){{/reference}}
{{/patches}}
{{#hasSecurity}}
### Security
{{/hasSecurity}}
{{#securities}}
-- {{header}} {{#issues}}([#{{id}}]({{url}})){{/issues}}
+- {{message}} {{#issues}}([#{{name}}]({{href}})){{/issues}} {{#reference}}[{{name}}]({{href}}){{/reference}}
{{/securities}}
{{#hasOthers}}
### Others
{{/hasOthers}}
{{#others}}
-- {{header}} {{#issues}}([#{{id}}]({{url}})){{/issues}}
+- {{message}} {{#issues}}([#{{name}}]({{href}})){{/issues}} {{#reference}}[{{name}}]({{href}}){{/reference}}
{{/others}}
{{#renderFooter}}
diff --git a/semver-changelog-markup/src/test/java/io/github/sam42r/semver/changelog/MarkupRendererTest.java b/semver-changelog-markup/src/test/java/io/github/sam42r/semver/changelog/MarkupRendererTest.java
index 2195d26..3a95ed3 100644
--- a/semver-changelog-markup/src/test/java/io/github/sam42r/semver/changelog/MarkupRendererTest.java
+++ b/semver-changelog-markup/src/test/java/io/github/sam42r/semver/changelog/MarkupRendererTest.java
@@ -6,6 +6,7 @@
import io.github.sam42r.semver.model.analyze.SemVerChangeLevel;
import io.github.sam42r.semver.model.changelog.VersionInfo;
import io.github.sam42r.semver.model.scm.Commit;
+import org.apache.commons.codec.digest.DigestUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@@ -85,7 +86,7 @@ private VersionInfo release(String version) {
private List analyzedCommits() {
return List.of(
new AnalyzedCommit(
- new Commit("42", Instant.EPOCH, "JUnit",
+ new Commit(DigestUtils.sha256Hex("42"), Instant.EPOCH, "JUnit",
"""
fix(scm): set clean commit message
@@ -93,6 +94,7 @@ private List analyzedCommits() {
refs #42
"""),
+ "https://junit.org/test/%s".formatted(DigestUtils.sha256Hex("42")),
"fix(scm): set clean commit message",
"* added scope for commit messages",
"refs #42",
diff --git a/semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/AnalyzedCommit.java b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/AnalyzedCommit.java
index 5764dfa..78b1147 100644
--- a/semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/AnalyzedCommit.java
+++ b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/analyze/AnalyzedCommit.java
@@ -5,8 +5,24 @@
import java.util.List;
import java.util.function.Predicate;
+/**
+ * Analyzed {@link Commit} based on commit-message analysis.
+ *
+ * @param commit scm {@link Commit}
+ * @param url provider specific commit URL
+ * @param header commit header
+ * @param body commit body
+ * @param footer commit footer
+ * @param type commit type
+ * @param category commit {@link ChangeCategory}
+ * @param scope commit scope
+ * @param subject commit subject
+ * @param level commit {@link SemVerChangeLevel}
+ * @param issues list of referenced {@link Issue}'s
+ */
public record AnalyzedCommit(
Commit commit,
+ String url,
String header,
String body,
String footer,
diff --git a/semver-maven-model/src/main/java/io/github/sam42r/semver/model/release/ProviderSpec.java b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/release/ProviderSpec.java
index d08a484..b9f37a4 100644
--- a/semver-maven-model/src/main/java/io/github/sam42r/semver/model/release/ProviderSpec.java
+++ b/semver-maven-model/src/main/java/io/github/sam42r/semver/model/release/ProviderSpec.java
@@ -2,9 +2,13 @@
import io.github.sam42r.semver.model.scm.Remote;
-public record ProviderSpec(String issuePattern) {
+public record ProviderSpec(String issuePattern, String commitPattern) {
public String issueUrl(Remote remote, String id) {
return issuePattern().formatted(remote.scheme(), remote.host(), remote.group(), remote.project(), id);
}
+
+ public String commitUrl(Remote remote, String id) {
+ return commitPattern().formatted(remote.scheme(), remote.host(), remote.group(), remote.project(), id);
+ }
}
diff --git a/semver-release-github/src/main/java/io/github/sam42r/semver/release/DefaultGithubPublisher.java b/semver-release-github/src/main/java/io/github/sam42r/semver/release/DefaultGithubPublisher.java
index c025500..375d44a 100644
--- a/semver-release-github/src/main/java/io/github/sam42r/semver/release/DefaultGithubPublisher.java
+++ b/semver-release-github/src/main/java/io/github/sam42r/semver/release/DefaultGithubPublisher.java
@@ -54,7 +54,8 @@ public void publish(
@Override
public ProviderSpec providerSpec() {
return new ProviderSpec(
- "%s://%s/%s/%s/issues/%s"
+ "%s://%s/%s/%s/issues/%s",
+ "%s://%s/%s/%s/commit/%s"
);
}
}
diff --git a/semver-release-gitlab/src/main/java/io/github/sam42r/semver/release/GitlabPublisher.java b/semver-release-gitlab/src/main/java/io/github/sam42r/semver/release/GitlabPublisher.java
index ce446af..28b8672 100644
--- a/semver-release-gitlab/src/main/java/io/github/sam42r/semver/release/GitlabPublisher.java
+++ b/semver-release-gitlab/src/main/java/io/github/sam42r/semver/release/GitlabPublisher.java
@@ -79,7 +79,8 @@ private GitlabRelease generatePayload(ReleaseInfo releaseInfo) {
@Override
public ProviderSpec providerSpec() {
return new ProviderSpec(
- "%s://%s/%s/%s/-/issues/%s"
+ "%s://%s/%s/%s/-/issues/%s",
+ "%s://%s/%s/%s@%s"
);
}
}
From 585024289fdccf29c194038797cf766a7fbf961d Mon Sep 17 00:00:00 2001
From: Rene R
Date: Mon, 9 Feb 2026 11:54:23 +0100
Subject: [PATCH 4/4] :sparkles: generate tag-compare links #41
---
.../ConventionalCommitAnalyzerTest.java | 4 +-
.../analyzer/GitMojiCommitAnalyzerTest.java | 6 +--
.../resources/templates/default/default.html | 5 +--
.../resources/templates/missive/missive.html | 4 +-
.../resources/templates/spinal/spinal.html | 5 +--
.../semver/changelog/HtmlRendererTest.java | 7 +++-
.../semver/changelog/MarkupRenderer.java | 1 -
.../semver/changelog/changelog.mustache | 2 +-
.../semver/changelog/MarkupRendererTest.java | 11 ++++--
.../semver/model/changelog/VersionInfo.java | 2 +-
.../semver/model/release/ProviderSpec.java | 6 ++-
.../sam42r/semver/SemanticReleaseMojo.java | 37 +++++++++++++------
.../github/sam42r/semver/model/Version.java | 4 ++
.../release/DefaultGithubPublisher.java | 3 +-
.../semver/release/GitlabPublisher.java | 3 +-
15 files changed, 65 insertions(+), 35 deletions(-)
diff --git a/semver-analyzer-conventional/src/test/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzerTest.java b/semver-analyzer-conventional/src/test/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzerTest.java
index 897dcd8..4b9984f 100644
--- a/semver-analyzer-conventional/src/test/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzerTest.java
+++ b/semver-analyzer-conventional/src/test/java/io/github/sam42r/semver/analyzer/ConventionalCommitAnalyzerTest.java
@@ -37,7 +37,7 @@ void shouldFindFix() {
""")
),
Remote.of("git@github.com:Sam42R/semver-maven-plugin.git"),
- new ProviderSpec("%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s")
+ new ProviderSpec("%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s...%s")
);
assertThat(actual).containsExactly(
@@ -79,7 +79,7 @@ void shouldFindBreakingChanges() {
"fix(scm)!: set clean commit message")
),
Remote.of("git@github.com:Sam42R/semver-maven-plugin.git"),
- new ProviderSpec("%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s")
+ new ProviderSpec("%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s...%s")
);
assertThat(actual).containsExactly(
diff --git a/semver-analyzer-gitmoji/src/test/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzerTest.java b/semver-analyzer-gitmoji/src/test/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzerTest.java
index a601b27..cd2d0a7 100644
--- a/semver-analyzer-gitmoji/src/test/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzerTest.java
+++ b/semver-analyzer-gitmoji/src/test/java/io/github/sam42r/semver/analyzer/GitMojiCommitAnalyzerTest.java
@@ -31,7 +31,7 @@ void shouldFindFixAndFeat() {
new Commit("42.2", Instant.EPOCH, "JUnit", ":sparkles: add awesome things")
),
Remote.of("git@github.com:Sam42R/semver-maven-plugin.git"),
- new ProviderSpec("%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s")
+ new ProviderSpec("%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s...%s")
);
assertThat(actual).containsExactlyInAnyOrder(
@@ -68,7 +68,7 @@ void shouldFindBreaking() {
new Commit("42.3", Instant.EPOCH, "JUnit", ":boom: (void): break some glass #42")
),
Remote.of("git@github.com:Sam42R/semver-maven-plugin.git"),
- new ProviderSpec("%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s")
+ new ProviderSpec("%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s...%s")
);
assertThat(actual).containsExactly(
@@ -93,7 +93,7 @@ void shouldFindOther() {
new Commit("42.4", Instant.EPOCH, "JUnit", ":white_check_mark: add test for something")
),
Remote.of("git@github.com:Sam42R/semver-maven-plugin.git"),
- new ProviderSpec("%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s")
+ new ProviderSpec("%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s", "%s://%s/%s/%s/%s...%s")
);
assertThat(actual).containsExactly(
diff --git a/semver-changelog-html/src/main/resources/templates/default/default.html b/semver-changelog-html/src/main/resources/templates/default/default.html
index 2d709dc..fc0b6f3 100644
--- a/semver-changelog-html/src/main/resources/templates/default/default.html
+++ b/semver-changelog-html/src/main/resources/templates/default/default.html
@@ -20,9 +20,8 @@ Changelog