Skip to content

Commit 88630f9

Browse files
Fixed #1426 : Replace archived org.semver:api with custom SemVer implementation (#1430)
Signed-off-by: Harsh Mehta <[email protected]> Co-authored-by: harsh-mehta-sb <[email protected]>
1 parent 7af8ace commit 88630f9

File tree

9 files changed

+414
-45
lines changed

9 files changed

+414
-45
lines changed

maven-release-policies/maven-release-semver-policy/pom.xml

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -39,30 +39,6 @@ under the License.
3939
<version>${project.parent.version}</version>
4040
<scope>provided</scope>
4141
</dependency>
42-
<dependency>
43-
<groupId>org.semver</groupId>
44-
<artifactId>api</artifactId>
45-
<version>0.9.33</version>
46-
<exclusions>
47-
<!-- only one class Version from semver api is used, avoid bringing in unnecessary dependencies -->
48-
<exclusion>
49-
<groupId>junit</groupId>
50-
<artifactId>junit</artifactId>
51-
</exclusion>
52-
<exclusion>
53-
<groupId>org.ow2.asm</groupId>
54-
<artifactId>*</artifactId>
55-
</exclusion>
56-
<exclusion>
57-
<groupId>de.tototec</groupId>
58-
<artifactId>de.tototec.cmdoption</artifactId>
59-
</exclusion>
60-
<exclusion>
61-
<groupId>com.google.code.findbugs</groupId>
62-
<artifactId>jsr305</artifactId>
63-
</exclusion>
64-
</exclusions>
65-
</dependency>
6642

6743
<dependency>
6844
<groupId>javax.inject</groupId>

maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/AbstractSemVerVersionPolicy.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import org.apache.maven.shared.release.policy.version.VersionPolicyRequest;
2323
import org.apache.maven.shared.release.policy.version.VersionPolicyResult;
2424
import org.apache.maven.shared.release.versions.VersionParseException;
25-
import org.semver.Version;
2625

2726
/**
2827
* Abstract base class for SemVer-based VersionPolicy implementations.
@@ -31,19 +30,19 @@
3130
*/
3231
abstract class AbstractSemVerVersionPolicy implements VersionPolicy {
3332

34-
protected Version createVersionFromRequest(VersionPolicyRequest request) throws VersionParseException {
33+
protected SemVer createVersionFromRequest(VersionPolicyRequest request) throws VersionParseException {
3534
try {
36-
return Version.parse(request.getVersion());
35+
return SemVer.parse(request.getVersion());
3736
} catch (IllegalArgumentException e) {
3837
throw new VersionParseException(e.getMessage());
3938
}
4039
}
4140

42-
protected VersionPolicyResult createResult(Version version) {
41+
protected VersionPolicyResult createResult(SemVer version) {
4342
return new VersionPolicyResult().setVersion(version.toString());
4443
}
4544

46-
protected VersionPolicyResult createSnapshotResult(Version version) {
47-
return new VersionPolicyResult().setVersion(version.toString() + "-SNAPSHOT");
45+
protected VersionPolicyResult createSnapshotResult(SemVer version) {
46+
return new VersionPolicyResult().setVersion(version.toSnapshotVersion().toString());
4847
}
4948
}
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.maven.shared.release.policy.semver;
20+
21+
import java.util.Objects;
22+
import java.util.regex.Matcher;
23+
import java.util.regex.Pattern;
24+
25+
/**
26+
* A simple Semantic Versioning 2.0.0 implementation.
27+
* <p>
28+
* This class provides basic parsing and manipulation of semantic version strings
29+
* following the format: MAJOR.MINOR.PATCH[-PRERELEASE][+METADATA]
30+
* </p>
31+
*
32+
* @see <a href="https://semver.org/">Semantic Versioning 2.0.0</a>
33+
*/
34+
class SemVer {
35+
36+
/**
37+
* Regex pattern for parsing semantic versions from semver.org.
38+
* Groups: 1=major, 2=minor, 3=patch, 4=prerelease, 5=metadata
39+
*
40+
* @see <a href="https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string">SemVer Regex</a>
41+
*/
42+
private static final Pattern SEMVER_PATTERN = Pattern.compile("^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)"
43+
+ "(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)"
44+
+ "(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$");
45+
46+
private final int major;
47+
private final int minor;
48+
private final int patch;
49+
private final String preRelease;
50+
private final String metadata;
51+
52+
/**
53+
* Version element types that can be incremented.
54+
*/
55+
public enum Element {
56+
MAJOR,
57+
MINOR,
58+
PATCH
59+
}
60+
61+
/**
62+
* Constructs a new SemVer instance.
63+
*
64+
* @param major the major version number
65+
* @param minor the minor version number
66+
* @param patch the patch version number
67+
* @param preRelease the pre-release identifier (can be null)
68+
* @param metadata the build metadata (can be null)
69+
*/
70+
protected SemVer(int major, int minor, int patch, String preRelease, String metadata) {
71+
if (major < 0 || minor < 0 || patch < 0) {
72+
throw new IllegalArgumentException("Version numbers must be non-negative");
73+
}
74+
this.major = major;
75+
this.minor = minor;
76+
this.patch = patch;
77+
this.preRelease = preRelease;
78+
this.metadata = metadata;
79+
}
80+
81+
/**
82+
* Parses a version string into a SemVer object.
83+
*
84+
* @param version the version string to parse
85+
* @return the parsed SemVer object
86+
* @throws IllegalArgumentException if the version string is invalid
87+
*/
88+
static SemVer parse(String version) {
89+
if (version == null || version.trim().isEmpty()) {
90+
throw new IllegalArgumentException("Version string cannot be null or empty");
91+
}
92+
93+
Matcher matcher = SEMVER_PATTERN.matcher(version.trim());
94+
if (!matcher.matches()) {
95+
throw new IllegalArgumentException("Invalid semantic version format: " + version);
96+
}
97+
98+
int major = Integer.parseInt(matcher.group(1));
99+
int minor = Integer.parseInt(matcher.group(2));
100+
int patch = Integer.parseInt(matcher.group(3));
101+
String preRelease = matcher.group(4);
102+
String metadata = matcher.group(5);
103+
104+
return new SemVer(major, minor, patch, preRelease, metadata);
105+
}
106+
107+
/**
108+
* Returns a new SemVer with the release version (removes -SNAPSHOT and any pre-release/metadata).
109+
* <p>
110+
* Examples:
111+
* <ul>
112+
* <li>1.2.3-SNAPSHOT → 1.2.3</li>
113+
* <li>1.2.3-beta+build → 1.2.3</li>
114+
* <li>1.2.3 → 1.2.3</li>
115+
* </ul>
116+
*
117+
* @return a new SemVer representing the release version
118+
*/
119+
SemVer toReleaseVersion() {
120+
return new SemVer(major, minor, patch, null, null);
121+
}
122+
123+
/**
124+
* Returns a new SemVer with -SNAPSHOT appended as pre-release identifier.
125+
* If the version already has a pre-release identifier, it will be replaced with SNAPSHOT.
126+
* Metadata is removed.
127+
* <p>
128+
* Examples:
129+
* <ul>
130+
* <li>1.2.3 → 1.2.3-SNAPSHOT</li>
131+
* <li>1.2.3-beta → 1.2.3-SNAPSHOT</li>
132+
* <li>1.2.3+build → 1.2.3-SNAPSHOT</li>
133+
* <li>1.2.3-SNAPSHOT → 1.2.3-SNAPSHOT (no change)</li>
134+
* </ul>
135+
*
136+
* @return a new SemVer with SNAPSHOT pre-release identifier, or this instance if already a SNAPSHOT version
137+
*/
138+
SemVer toSnapshotVersion() {
139+
if ("SNAPSHOT".equals(preRelease) && metadata == null) {
140+
return this;
141+
}
142+
return new SemVer(major, minor, patch, "SNAPSHOT", null);
143+
}
144+
145+
/**
146+
* Returns a new SemVer with the specified element incremented.
147+
* If the version has pre-release or metadata, returns the release version without incrementing.
148+
* Otherwise, increments the specified element and all lower elements are reset to 0.
149+
* Pre-release and metadata are always cleared in the result.
150+
*
151+
* @param element the element to increment (MAJOR, MINOR, or PATCH)
152+
* @return a new SemVer with the specified element incremented (or release version if pre-release/metadata present)
153+
*/
154+
SemVer next(Element element) {
155+
Objects.requireNonNull(element, "Element cannot be null");
156+
157+
// If version has pre-release or metadata, just return release version without incrementing
158+
if (hasPreRelease() || hasMetadata()) {
159+
return toReleaseVersion();
160+
}
161+
162+
switch (element) {
163+
case MAJOR:
164+
return new SemVer(major + 1, 0, 0, null, null);
165+
case MINOR:
166+
return new SemVer(major, minor + 1, 0, null, null);
167+
case PATCH:
168+
return new SemVer(major, minor, patch + 1, null, null);
169+
default:
170+
throw new IllegalArgumentException("Unknown element: " + element);
171+
}
172+
}
173+
174+
/**
175+
* Checks if this version has a pre-release identifier.
176+
*
177+
* @return true if pre-release identifier is present, false otherwise
178+
*/
179+
private boolean hasPreRelease() {
180+
return preRelease != null && !preRelease.isEmpty();
181+
}
182+
183+
/**
184+
* Checks if this version has build metadata.
185+
*
186+
* @return true if build metadata is present, false otherwise
187+
*/
188+
private boolean hasMetadata() {
189+
return metadata != null && !metadata.isEmpty();
190+
}
191+
192+
/**
193+
* Returns the major version number.
194+
*
195+
* @return the major version
196+
*/
197+
int getMajor() {
198+
return major;
199+
}
200+
201+
/**
202+
* Returns the minor version number.
203+
*
204+
* @return the minor version
205+
*/
206+
int getMinor() {
207+
return minor;
208+
}
209+
210+
/**
211+
* Returns the patch version number.
212+
*
213+
* @return the patch version
214+
*/
215+
int getPatch() {
216+
return patch;
217+
}
218+
219+
/**
220+
* Returns the pre-release identifier.
221+
*
222+
* @return the pre-release identifier, or null if not present
223+
*/
224+
String getPreRelease() {
225+
return preRelease;
226+
}
227+
228+
/**
229+
* Returns the build metadata.
230+
*
231+
* @return the build metadata, or null if not present
232+
*/
233+
String getMetadata() {
234+
return metadata;
235+
}
236+
237+
@Override
238+
public String toString() {
239+
StringBuilder sb = new StringBuilder();
240+
sb.append(major).append('.').append(minor).append('.').append(patch);
241+
242+
if (preRelease != null && !preRelease.isEmpty()) {
243+
sb.append('-').append(preRelease);
244+
}
245+
246+
if (metadata != null && !metadata.isEmpty()) {
247+
sb.append('+').append(metadata);
248+
}
249+
250+
return sb.toString();
251+
}
252+
}

maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMajorDevelopmentVersionPolicy.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import org.apache.maven.shared.release.policy.version.VersionPolicyRequest;
2525
import org.apache.maven.shared.release.policy.version.VersionPolicyResult;
2626
import org.apache.maven.shared.release.versions.VersionParseException;
27-
import org.semver.Version;
2827

2928
/**
3029
* Uses SemVer implementation to increase major element when resolving the development version.
@@ -37,13 +36,13 @@ class SemVerMajorDevelopmentVersionPolicy extends AbstractSemVerVersionPolicy {
3736

3837
@Override
3938
public VersionPolicyResult getReleaseVersion(VersionPolicyRequest request) throws VersionParseException {
40-
Version version = createVersionFromRequest(request).toReleaseVersion();
39+
SemVer version = createVersionFromRequest(request).toReleaseVersion();
4140
return createResult(version);
4241
}
4342

4443
@Override
4544
public VersionPolicyResult getDevelopmentVersion(VersionPolicyRequest request) throws VersionParseException {
46-
Version version = createVersionFromRequest(request).next(Version.Element.MAJOR);
45+
SemVer version = createVersionFromRequest(request).next(SemVer.Element.MAJOR);
4746
return createSnapshotResult(version);
4847
}
4948
}

maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMajorReleaseVersionPolicy.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import org.apache.maven.shared.release.policy.version.VersionPolicyRequest;
2525
import org.apache.maven.shared.release.policy.version.VersionPolicyResult;
2626
import org.apache.maven.shared.release.versions.VersionParseException;
27-
import org.semver.Version;
2827

2928
/**
3029
* Uses SemVer implementation to increase major element when resolving the release version.
@@ -37,13 +36,13 @@ class SemVerMajorReleaseVersionPolicy extends AbstractSemVerVersionPolicy {
3736

3837
@Override
3938
public VersionPolicyResult getReleaseVersion(VersionPolicyRequest request) throws VersionParseException {
40-
Version version = createVersionFromRequest(request).toReleaseVersion().next(Version.Element.MAJOR);
39+
SemVer version = createVersionFromRequest(request).toReleaseVersion().next(SemVer.Element.MAJOR);
4140
return createResult(version);
4241
}
4342

4443
@Override
4544
public VersionPolicyResult getDevelopmentVersion(VersionPolicyRequest request) throws VersionParseException {
46-
Version version = createVersionFromRequest(request).next(Version.Element.PATCH);
45+
SemVer version = createVersionFromRequest(request).next(SemVer.Element.PATCH);
4746
return createSnapshotResult(version);
4847
}
4948
}

maven-release-policies/maven-release-semver-policy/src/main/java/org/apache/maven/shared/release/policy/semver/SemVerMinorDevelopmentVersionPolicy.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import org.apache.maven.shared.release.policy.version.VersionPolicyRequest;
2525
import org.apache.maven.shared.release.policy.version.VersionPolicyResult;
2626
import org.apache.maven.shared.release.versions.VersionParseException;
27-
import org.semver.Version;
2827

2928
/**
3029
* Uses SemVer implementation to increase minor element when resolving the development version.
@@ -37,13 +36,13 @@ class SemVerMinorDevelopmentVersionPolicy extends AbstractSemVerVersionPolicy {
3736

3837
@Override
3938
public VersionPolicyResult getReleaseVersion(VersionPolicyRequest request) throws VersionParseException {
40-
Version version = createVersionFromRequest(request).toReleaseVersion();
39+
SemVer version = createVersionFromRequest(request).toReleaseVersion();
4140
return createResult(version);
4241
}
4342

4443
@Override
4544
public VersionPolicyResult getDevelopmentVersion(VersionPolicyRequest request) throws VersionParseException {
46-
Version version = createVersionFromRequest(request).next(Version.Element.MINOR);
45+
SemVer version = createVersionFromRequest(request).next(SemVer.Element.MINOR);
4746
return createSnapshotResult(version);
4847
}
4948
}

0 commit comments

Comments
 (0)