From 8621a3258b3cdc1e99170df3c9f48ddf89d6c483 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Fri, 3 Feb 2017 09:57:56 +0100 Subject: [PATCH] Added support for ranges of versions fixes #210 --- .../main/asciidoc/verifier/stubrunner.adoc | 20 +++++++++- .../stubrunner/AetherStubDownloader.java | 9 ++--- .../stubrunner/StubRunnerOptionsBuilder.java | 33 +++++++++++++--- .../StubRunnerOptionsBuilderSpec.groovy | 39 +++++++++++++++++++ 4 files changed, 90 insertions(+), 11 deletions(-) diff --git a/docs/src/main/asciidoc/verifier/stubrunner.adoc b/docs/src/main/asciidoc/verifier/stubrunner.adoc index 0b60564416..0359fcbac0 100644 --- a/docs/src/main/asciidoc/verifier/stubrunner.adoc +++ b/docs/src/main/asciidoc/verifier/stubrunner.adoc @@ -85,4 +85,22 @@ groupId:artifactId:version:classifier:port * If you don't provide the `classifier` then the default one will be taken. (NOTE that you can pass an empty classifier like this `groupId:artifactId:version:`) * If you don't provide the `version` then the `+` will be passed and the latest one will be downloaded -Where `port` means the port of the WireMock server. \ No newline at end of file +Where `port` means the port of the WireMock server. + +IMPORTANT: Starting from version 1.0.4 as a version you can provide a range of versions that you would like +the Stub Runner to take into consideration. You can read more about the https://wiki.eclipse.org/Aether/New_and_Noteworthy#Version_Ranges[Aether versioning ranges here]. + +Taken from http://download.eclipse.org/aether/aether-core/0.9.0/apidocs/org/eclipse/aether/util/version/GenericVersionScheme.html[Aether Docs]: + +> This scheme accepts versions of any form, interpreting a version as a sequence of numeric and alphabetic segments. The characters '-', '_', and '.' as well as the mere +> transitions from digit to letter and vice versa delimit the version segments. Delimiters are treated as equivalent. +> +> Numeric segments are compared mathematically, alphabetic segments are compared lexicographically and case-insensitively. However, the following qualifier strings are +> recognized and treated specially: "alpha" = "a" < "beta" = "b" < "milestone" = "m" < "cr" = "rc" < "snapshot" < "final" = "ga" < "sp". All of those well-known qualifiers +> are considered smaller/older than other strings. An empty segment/string is equivalent to 0. +> +> In addition to the above mentioned qualifiers, the tokens "min" and "max" may be used as final version segment to denote the smallest/greatest version having a given prefix. +> For example, "1.2.min" denotes the smallest version in the 1.2 line, "1.2.max" denotes the greatest version in the 1.2 line. A version range of the form "[M.N.*]" is short for "[M.N.min, M.N.max]". +> +> Numbers and strings are considered incomparable against each other. Where version segments of different kind would collide, comparison will instead assume that the previous +> segments are padded with trailing 0 or "ga" segments, respectively, until the kind mismatch is resolved, e.g. "1-alpha" = "1.0.0-alpha" < "1.0.1-ga" = "1.0.1". \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java index 6abc1419d6..ae2d73e3a6 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java @@ -173,10 +173,9 @@ public class AetherStubDownloader implements StubDownloader { if (!StringUtils.hasText(version) || LATEST_VERSION_IN_IVY.equals(version)) { log.info("Desired version is [" + version + "] - will try to resolve the latest version"); - return resolveHighestArtifactVersion(stubsGroup, stubsModule, classifier); + return resolveHighestArtifactVersion(stubsGroup, stubsModule, classifier, LATEST_ARTIFACT_VERSION); } - log.info("Will try to resolve version " + version); - return resolveArtifactVersion(stubsGroup, stubsModule, version, classifier); + return resolveHighestArtifactVersion(stubsGroup, stubsModule, classifier, version); } @Override @@ -198,9 +197,9 @@ public class AetherStubDownloader implements StubDownloader { } private String resolveHighestArtifactVersion(String stubsGroup, String stubsModule, - String classifier) { + String classifier, String version) { Artifact artifact = new DefaultArtifact(stubsGroup, stubsModule, classifier, - ARTIFACT_EXTENSION, LATEST_ARTIFACT_VERSION); + ARTIFACT_EXTENSION, version); VersionRangeRequest versionRangeRequest = new VersionRangeRequest(artifact, this.remoteRepos, null); VersionRangeResult rangeResult; diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilder.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilder.java index 8b050e5c69..01ed1c61e1 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilder.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilder.java @@ -16,16 +16,17 @@ package org.springframework.cloud.contract.stubrunner; -import org.springframework.cloud.contract.stubrunner.util.StubsParser; -import org.springframework.util.StringUtils; - import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import org.springframework.cloud.contract.stubrunner.util.StubsParser; +import org.springframework.util.StringUtils; + public class StubRunnerOptionsBuilder { private static final String DELIMITER = ":"; @@ -126,12 +127,34 @@ public class StubRunnerOptionsBuilder { private static List stubsToList(String[] stubIdsToPortMapping) { List list = new ArrayList<>(); - for (String stub : stubIdsToPortMapping) { - list.addAll(StringUtils.commaDelimitedListToSet(stub)); + if (stubIdsToPortMapping.length == 1 && !containsRange(stubIdsToPortMapping[0])) { + list.addAll(StringUtils.commaDelimitedListToSet(stubIdsToPortMapping[0])); + return list; + } else if (stubIdsToPortMapping.length == 1 && containsRange(stubIdsToPortMapping[0])) { + LinkedList linkedList = new LinkedList<>(); + String[] split = stubIdsToPortMapping[0].split(","); + for (String string : split) { + if (containsClosingRange(string)) { + String last = linkedList.pop(); + linkedList.push(last + "," + string); + } else { + linkedList.push(string); + } + } + list.addAll(linkedList); } + Collections.addAll(list, stubIdsToPortMapping); return list; } + private static boolean containsRange(String s) { + return s.contains("[") || s.contains("("); + } + + private static boolean containsClosingRange(String s) { + return s.contains("]") || s.contains(")"); + } + private void addStub(List notations) { for (String notation : notations) { addStub(notation); diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilderSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilderSpec.groovy index fa2b28c430..52148788b7 100644 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilderSpec.groovy +++ b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilderSpec.groovy @@ -95,4 +95,43 @@ class StubRunnerOptionsBuilderSpec extends Specification { then: options.getDependencies().toString() == '[groupId:artifactId:version:classifier]' } + + @Issue("#210") + def shouldCreateDependenciesWithVersionRange() { + + given: + builder.withStubs('groupId:artifactId:[,0.0.1]:classifier','groupId2:artifactId2:[,0.0.2]:classifier2') + + when: + StubRunnerOptions options = builder.build() + + then: + options.getDependencies().toString() == '[groupId:artifactId:[,0.0.1]:classifier, groupId2:artifactId2:[,0.0.2]:classifier2]' + } + + @Issue("#210") + def shouldCreateDependenciesWithVersionRangeWhenSingleOneWasPassed() { + + given: + builder.withStubs('groupId:artifactId:[,0.0.1]:classifier') + + when: + StubRunnerOptions options = builder.build() + + then: + options.getDependencies().toString() == '[groupId:artifactId:[,0.0.1]:classifier]' + } + + @Issue("#210") + def shouldCreateDependenciesWithVersionRangeWhenManyWerePassedInASingleLine() { + + given: + builder.withStubs('groupId:artifactId:[,0.0.1]:classifier,groupId2:artifactId2:[,0.0.2]:classifier2') + + when: + StubRunnerOptions options = builder.build() + + then: + options.getDependencies().toString() == '[groupId2:artifactId2:[,0.0.2]:classifier2, groupId:artifactId:[,0.0.1]:classifier]' + } }