Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

methods to increment suffix components #56

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Semver sem1 = new Semver("1.2.3-beta.4+sha899d8g79f87"); // Defaults to STRICT m
Semver sem2 = new Semver("1.2.3-beta.4+sha899d8g79f87", SemverType.NPM); // Specify the mode
```

If the version is invalid, a `SemverException` will be thrown.
If the version is invalid, a `SemverException` will be thrown.
You can access the different parts of the version using `getMajor()`, `getMinor()`, `getPatch()`, `getSuffixTokens()` or `getBuild()`.

| Type | Mandatory | Optional |
Expand Down Expand Up @@ -130,6 +130,7 @@ sem.diff("1.2.3-beta.4+sha32iddfu987"); // BUILD

If you want to check if a version satisfies a requirement, use the `satisfies` method.

- A `SemverException` is thrown if the version is not fully-qualified (containing major, minor, and patch versions).
- In `STRICT` and `LOOSE` modes, the requirement can only be another version.
- In `NPM` mode, the requirement follows [NPM versioning rules](https://github.com/npm/node-semver).

Expand Down Expand Up @@ -180,5 +181,5 @@ You can also use built-in versioning methods such as:

## Contributing

Any pull request or bug report is welcome!
Any pull request or bug report is welcome!
If you have any suggestion about new features, you can open an issue.
21 changes: 15 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.vdurmont</groupId>
<groupId>org.thshsh</groupId>
<artifactId>semver4j</artifactId>
<version>3.1.0</version>
<version>3.1.1</version>
<packaging>jar</packaging>

<name>semver4j</name>
<url>https://github.com/vdurmont/semver4j</url>
<url>https://github.com/theshoeshiner/semver4j</url>
<description>Semantic versioning for Java apps.</description>

<scm>
<connection>scm:git:git@github.com:vdurmont/semver4j.git</connection>
<developerConnection>scm:git:git@github.com:vdurmont/semver4j.git</developerConnection>
<url>git@github.com:vdurmont/semver4j.git</url>
<connection>scm:git:git@github.com:theshoeshiner/semver4j.git</connection>
<developerConnection>scm:git:git@github.com:theshoeshiner/semver4j.git</developerConnection>
<url>git@github.com:theshoeshiner/semver4j.git</url>
</scm>

<developers>
Expand All @@ -23,6 +23,10 @@
<email>vdurmont@gmail.com</email>
<url>http://www.vdurmont.com</url>
</developer>
<developer>
<name>The Shoe Shiner</name>
<email>theshoeshiner@thshsh.org</email>
</developer>
</developers>

<licenses>
Expand Down Expand Up @@ -129,6 +133,11 @@
<goals>
<goal>sign</goal>
</goals>
<configuration>
<excludes>
<exclude>*.asc</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
Expand Down
37 changes: 30 additions & 7 deletions src/main/java/com/vdurmont/semver4j/Requirement.java
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,8 @@ private static Requirement evaluateReversePolishNotation(Iterator<Tokenizer.Toke
if (token.type == Tokenizer.TokenType.VERSION) {
if ("*".equals(token.value) || (type == Semver.SemverType.NPM && "latest".equals(token.value))) {
// Special case for "*" and "latest" in NPM
return new Requirement(new Range("0.0.0", Range.RangeOperator.GTE), null, null, null);
Range range = new Range(new Semver("0.0.0", type), Range.RangeOperator.GTE);
return new Requirement(range, null, null, null);
}
Semver version = new Semver(token.value, type);
if (version.getMinor() != null && version.getPatch() != null) {
Expand Down Expand Up @@ -364,7 +365,8 @@ private static Requirement evaluateReversePolishNotation(Iterator<Tokenizer.Toke
throw new SemverException("Invalid requirement");
}

Range range = new Range(token2.value, rangeOp);
Semver version = new Semver(token2.value, type);
Range range = new Range(version, rangeOp);
return new Requirement(range, null, null, null);
} else {
// They don't call it "reverse" for nothing
Expand Down Expand Up @@ -535,6 +537,21 @@ private static Semver extrapolateVersion(Semver semver) {
return new Semver(sb.toString(), semver.getType());
}

/**
* @return Semver type
*/
public Semver.SemverType getType() {
if (this.range != null) {
return this.range.version.getType();
} else if (this.req1 != null) {
return this.req1.getType();
} else if (this.req2 != null) {
return this.req2.getType();
} else {
return Semver.SemverType.STRICT;
}
}

/**
* @see #isSatisfiedBy(Semver)
*
Expand All @@ -543,11 +560,7 @@ private static Semver extrapolateVersion(Semver semver) {
* @return true if the version satisfies the requirement
*/
public boolean isSatisfiedBy(String version) {
if (this.range != null) {
return this.isSatisfiedBy(new Semver(version, this.range.version.getType()));
} else {
return this.isSatisfiedBy(new Semver(version));
}
return this.isSatisfiedBy(new Semver(version, this.getType()));
}

/**
Expand All @@ -558,8 +571,18 @@ public boolean isSatisfiedBy(String version) {
* @return true if the version satisfies the requirement
*/
public boolean isSatisfiedBy(Semver version) {
if (version.getMinor() == null) {
throw new SemverException("Invalid version for requirement check (no minor version): " + version.getValue());
} else if (version.getPatch() == null) {
throw new SemverException("Invalid version for requirement check (no patch version): " + version.getValue());
}

if (this.range != null) {
// We are on a leaf
if (version.isPreRelease() && !this.range.version.isPreRelease()) {
// Disqualify pre-releases if this is not a pre-release range
return false;
}
return this.range.isSatisfiedBy(version);
} else {
// We have several sub-requirements
Expand Down
54 changes: 45 additions & 9 deletions src/main/java/com/vdurmont/semver4j/Semver.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.vdurmont.semver4j;

import java.util.Arrays;
import java.util.Objects;

/**
Expand Down Expand Up @@ -178,6 +179,15 @@ public boolean satisfies(String requirement) {
return this.satisfies(req);
}

/**
* Checks whether the version is a pre-release
*
* @return true if the current version is a prerelease
*/
public boolean isPreRelease() {
return suffixTokens.length > 0;
}

/**
* @see #isGreaterThan(Semver)
*
Expand Down Expand Up @@ -329,8 +339,22 @@ public boolean isEquivalentTo(String version) {
*/
public boolean isEquivalentTo(Semver version) {
// Get versions without build
Semver sem1 = this.getBuild() == null ? this : new Semver(this.getValue().replace("+" + this.getBuild(), ""));
Semver sem2 = version.getBuild() == null ? version : new Semver(version.getValue().replace("+" + version.getBuild(), ""));
Semver sem1 = this.getBuild() == null ? this : new Semver(this.getValue().replace("+" + this.getBuild(), ""), this.getType());
Semver sem2 = version.getBuild() == null ? version : new Semver(version.getValue().replace("+" + version.getBuild(), ""), version.getType());

// Ignore minor and/or patch when versions are not equally qualified
if (sem1.getType() != SemverType.STRICT) {
if (!sem1.areSameSuffixes(sem2.getSuffixTokens())) return false;

if (!Objects.equals(sem1.getMajor(), sem2.getMajor())) return false;

if (sem2.getMinor() == null) return true;
if (!Objects.equals(sem1.getMinor(), sem2.getMinor())) return false;

if (sem2.getPatch() == null) return true;
if (!Objects.equals(sem1.getPatch(), sem2.getPatch())) return false;
}

// Compare those new versions
return sem1.isEqualTo(sem2);
}
Expand All @@ -354,12 +378,6 @@ public boolean isEqualTo(String version) {
* @return true if the current version equals the provided version
*/
public boolean isEqualTo(Semver version) {
if (this.type == SemverType.NPM) {
if (this.getMajor() != version.getMajor()) return false;
if (version.getMinor() == null) return true;
if (version.getPatch() == null) return true;
}

return this.equals(version);
}

Expand Down Expand Up @@ -442,6 +460,24 @@ public Semver withIncPatch() {
public Semver withIncPatch(int increment) {
return this.withInc(0, 0, increment);
}

public Semver withIncSuffix(int index) {
return withIncSuffix(index, 1);
}

public Semver withIncSuffix(int index, int increment) {
if(suffixTokens.length <= index) throw new SemverException("No suffix at index "+index);
try {
Integer token = Integer.valueOf(suffixTokens[index]);
token+=increment;
String[] newSuffix = Arrays.copyOf(suffixTokens,suffixTokens.length);
newSuffix[index] = token.toString();
return with(major,minor,patch,newSuffix,build);
}
catch(NumberFormatException nfe) {
throw new SemverException("Suffix was not integer at index "+index);
}
}

private Semver withInc(int majorInc, int minorInc, int patchInc) {
Integer minor = this.minor;
Expand Down Expand Up @@ -542,7 +578,7 @@ private static Semver create(SemverType type, int major, Integer minor, Integer

@Override public int compareTo(Semver version) {
if (this.isGreaterThan(version)) return 1;
else if(this.isLowerThan(version)) return -1;
else if (this.isLowerThan(version)) return -1;
return 0;
}

Expand Down
71 changes: 68 additions & 3 deletions src/test/java/com/vdurmont/semver4j/NpmSemverTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ public static Iterable<Object[]> getParameters() {
// Fully-qualified versions:
{ "1.2.3", "1.2.3", true, },
{ "1.2.4", "1.2.3", false, },
{ "1.3.3", "1.2.3", false, },
{ "2.2.3", "1.2.3", false, },

// Minor versions:
{ "1.2.3", "1.2", true, },
{ "1.3.3", "1.2", false, },
{ "1.2.4", "1.3", false, },

// Major versions:
Expand All @@ -47,7 +50,7 @@ public static Iterable<Object[]> getParameters() {
{ "2.3.0-alpha", "1.2.3 - 2.3.0-beta", true, },
{ "2.3.4", "1.2.3 - 2.3", true, },
{ "2.3.4", "1.2.3 - 2", true, },
{ "4.4", "3.X - 4.X", true, },
{ "4.4.0", "3.X - 4.X", true, },
{ "1.0.0", "1.2.3 - 2.3.4", false, },
{ "3.0.0", "1.2.3 - 2.3.4", false, },
{ "2.4.3", "1.2.3 - 2.3", false, },
Expand All @@ -58,7 +61,7 @@ public static Iterable<Object[]> getParameters() {
{ "3.1.5", "", true, },
{ "3.1.5", "*", true, },
{ "0.0.0", "*", true, },
{ "1.0.0-beta", "*", true, },
{ "1.0.0-beta", "*", false, },
{ "3.1.5-beta", "3.1.x", false, },
{ "3.1.5-beta+exp.sha.5114f85", "3.1.x", false, },
{ "3.1.5+exp.sha.5114f85", "3.1.x", true, },
Expand Down Expand Up @@ -121,6 +124,8 @@ public static Iterable<Object[]> getParameters() {
{ "2.0.1", "=2.0", true, },
{ "2.0.0", "=2", true, },
{ "2.0.1", "=2", true, },
{ "3.0.0", "=2.0", false, },
{ "2.1.0", "=2.0", false, },
{ "2.0.1", "=2.0.0", false, },
{ "1.9.9", "=2.0.0", false, },
{ "1.9.9", "=2.0", false, },
Expand Down Expand Up @@ -176,6 +181,56 @@ public static Iterable<Object[]> getParameters() {
{ "3.0.0", "<=2.0", false, },
{ "3.0.0", "<=2", false, },

// Prerelease versions:
{ "2.0.0-alpha", "=2.0.0-beta", false, },
{ "2.0.0-rc.2", "=2.0.0-rc.2", true, },
{ "2.0.0-rc.2", "=2.0.0-rc.3", false, },
{ "2.0.0-rc.2", "=2.0.0-rc.2.3", false, },
{ "2.0.0-rc.2", "=2.0.0-rc.3.2", false, },
{ "2.0.0-rc.2", "=2.0.0", false, },
{ "2.0.0-rc.2", "=2.0", false, },
{ "2.0.0-rc.2", "=2", false, },

{ "2.0.0-alpha", ">2.0.0-beta", false, },
{ "2.0.0-rc.2", ">2.0.0-rc.1", true, },
{ "2.0.0-rc.2", ">2.0.0-rc.2", false, },
{ "2.0.0-rc.2", ">2.0.0-rc.3", false, },
{ "2.0.0-rc.2", ">2.0.0-rc.2.3", false, },
{ "2.0.0-rc.2", ">2.0.0-rc.3.2", false, },
{ "2.0.0-rc.2", ">2.0.0", false, },
{ "2.0.0-rc.2", ">2.0", false, },
{ "2.0.0-rc.2", ">2", false, },

{ "2.0.0-alpha", "<2.0.0-beta", true, },
{ "2.0.0-rc.2", "<2.0.0-rc.3", true, },
{ "2.0.0-rc.2", "<2.0.0-rc.2.3", true, },
{ "2.0.0-rc.2", "<2.0.0-rc.3.2", true, },
{ "2.0.0-rc.2", "<2.0.0-rc.1", false, },
{ "2.0.0-rc.2", "<2.0.0-rc.2", false, },
{ "2.0.0-rc.2", "<2.0.0", false, },
{ "2.0.0-rc.2", "<2.0", false, },
{ "2.0.0-rc.2", "<2", false, },

{ "2.0.0-alpha", ">=2.0.0-beta", false, },
{ "2.0.0-rc.2", ">=2.0.0-rc.1", true, },
{ "2.0.0-rc.2", ">=2.0.0-rc.2", true, },
{ "2.0.0-rc.2", ">=2.0.0-rc.3", false, },
{ "2.0.0-rc.2", ">=2.0.0-rc.2.3", false, },
{ "2.0.0-rc.2", ">=2.0.0-rc.3.2", false, },
{ "2.0.0-rc.2", ">=2.0.0", false, },
{ "2.0.0-rc.2", ">=2.0", false, },
{ "2.0.0-rc.2", ">=2", false, },

{ "2.0.0-alpha", "<=2.0.0-beta", true, },
{ "2.0.0-rc.2", "<=2.0.0-rc.2", true, },
{ "2.0.0-rc.2", "<=2.0.0-rc.3", true, },
{ "2.0.0-rc.2", "<=2.0.0-rc.2.3", true, },
{ "2.0.0-rc.2", "<=2.0.0-rc.3.2", true, },
{ "2.0.0-rc.2", "<=2.0.0-rc.1", false, },
{ "2.0.0-rc.2", "<=2.0.0", false, },
{ "2.0.0-rc.2", "<=2.0", false, },
{ "2.0.0-rc.2", "<=2", false, },

// AND ranges:
{ "2.0.1", ">2.0.0 <3.0.0", true, },
{ "2.0.1", ">2.0 <3.0", false, },
Expand Down Expand Up @@ -222,12 +277,22 @@ public static Iterable<Object[]> getParameters() {
{ "1.1.0", "1.2 <1.2.8 || >2.0.0", false, },
{ "1.2.9", "1.2 <1.2.8 || >2.0.0", false, },
{ "2.0.0", "1.2 <1.2.8 || >2.0.0", false, },

// Big number equality:
{ "128.0.0", "=128.0.0", true, },
{ "127.127.127", "=127.128", false, },
{ "0.128.0", "=0.128.0", true, },
{ "0.0.128", "=0.0.128", true, },
{ "127.127.127", "=127.127.127", true, },
{ "128.128.128", "=128.128.128", true, },
{ "999.999.999", "=999.999.999", true, },
{ "9999.9999.9999", "=9999.9999.9999", true, },
});
}

@Test
public void test() {
assertEquals(this.version + " , " + this.rangeExpression ,this.expected, new Semver(this.version, SemverType.NPM).satisfies(this.rangeExpression));
assertEquals(this.version + " , " + this.rangeExpression, this.expected, new Semver(this.version, SemverType.NPM).satisfies(this.rangeExpression));
}

}
13 changes: 11 additions & 2 deletions src/test/java/com/vdurmont/semver4j/RequirementTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
Expand Down Expand Up @@ -324,9 +325,9 @@ public class RequirementTest {
@Test public void isSatisfiedBy_with_a_loose_type() {
Requirement req = Requirement.buildLoose("1.3.2");

assertFalse(req.isSatisfiedBy("0.27"));
assertFalse(req.isSatisfiedBy("0.27.0"));
assertTrue(req.isSatisfiedBy("1.3.2"));
assertFalse(req.isSatisfiedBy("1.5"));
assertFalse(req.isSatisfiedBy("1.5.0"));
}

@Test public void isSatisfiedBy_with_a_complex_example() {
Expand Down Expand Up @@ -422,6 +423,14 @@ public class RequirementTest {
assertTrue(req.isSatisfiedBy("0.2.3"));
}

@Test public void isSatisfiedBy_unqualified_exception() {
Requirement req = Requirement.buildNPM("1.0");
try {
req.isSatisfiedBy("1.0");
fail("isSatisfiedBy() did not throw as expected.");
} catch (SemverException e) {}
}

@Test public void tildeRequirement_cocoapods() {
// '~> 0.1.2' Version 0.1.2 and the versions up to 0.2, not including 0.2 and higher
tildeTest("0.1.2", "0.1.2", "0.2.0", Semver.SemverType.COCOAPODS);
Expand Down
Loading