Ensures that no "lower" level of dependencies are present

without this change we only assert that snapshot versions are not present when doing any type of a release
with this change for snapshots we do nothing, for milestone / rc we verify if snapshots are not present, for ga / sr we verify snapshots and milestone and rcs

fixes gh-119
This commit is contained in:
Marcin Grzejszczak
2019-01-24 16:00:47 +01:00
parent edd12d85e5
commit 02bbd93a81
5 changed files with 119 additions and 44 deletions

View File

@@ -8,10 +8,13 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -37,22 +40,22 @@ public class GradleUpdater implements ReleaserPropertiesAware {
* For the given root folder (typically the working directory) performs the whole
* flow of updating {@code gradle.properties} with values from BOM project.
* Remember to pass the mapping from a property name inside {@code gradle.properties} to
* the project name via {@link ReleaserProperties.Gradle#gradlePropsSubstitution}
* the project name via {@link ReleaserProperties.Gradle#getGradlePropsSubstitution}
* @param projectRoot - root folder with project to update
* @param projects - versions of projects used to update poms
* @param versionFromBom - version for the project from Spring Cloud Release
* @param assertSnapshots - should snapshots presence be asserted
* @param assertVersions - should snapshots / milestone / rc presence be asserted
*/
public void updateProjectFromBom(File projectRoot, Projects projects,
ProjectVersion versionFromBom, boolean assertSnapshots) {
processAllGradleProps(projectRoot, projects, versionFromBom, assertSnapshots);
ProjectVersion versionFromBom, boolean assertVersions) {
processAllGradleProps(projectRoot, projects, versionFromBom, assertVersions);
}
private void processAllGradleProps(File projectRoot, Projects projects,
ProjectVersion versionFromScRelease, boolean assertSnapshots) {
ProjectVersion versionFromScRelease, boolean assertVersions) {
try {
Files.walkFileTree(projectRoot.toPath(),
new GradlePropertiesWalker(this.properties, projects, versionFromScRelease, assertSnapshots));
new GradlePropertiesWalker(this.properties, projects, versionFromScRelease, assertVersions));
}
catch (IOException e) {
throw new IllegalStateException(e);
@@ -69,15 +72,18 @@ public class GradleUpdater implements ReleaserPropertiesAware {
private final ReleaserProperties properties;
private final Projects projects;
private final boolean snapshotVersion;
private final boolean assertSnapshots;
private final boolean skipVersionAssert;
private final boolean assertVersions;
private final List<Pattern> unacceptableVersionPatterns;
private GradlePropertiesWalker(ReleaserProperties properties, Projects projects,
ProjectVersion versionFromScRelease, boolean assertSnapshots) {
ProjectVersion versionFromScRelease, boolean assertVersions) {
this.properties = properties;
this.projects = projects;
this.snapshotVersion = !assertSnapshots || versionFromScRelease.isSnapshot();
this.assertSnapshots = assertSnapshots;
List<Pattern> unacceptableVersionPatterns = versionFromScRelease.unacceptableVersionPatterns();
this.unacceptableVersionPatterns = unacceptableVersionPatterns;
this.skipVersionAssert = !assertVersions || unacceptableVersionPatterns.isEmpty();
this.assertVersions = assertVersions;
}
@Override
@@ -115,20 +121,23 @@ public class GradleUpdater implements ReleaserPropertiesAware {
}
private void assertNoSnapshotsArePresent(Path path) {
if (this.assertSnapshots && !this.snapshotVersion) {
log.debug("Update is a non-snapshot one. Checking if no snapshot versions remained in the gradle prop");
if (this.assertVersions && !this.skipVersionAssert) {
log.debug("Update should check if no wrong versions remained in the gradle prop. List of wrong patterns: {}",
this.unacceptableVersionPatterns.stream().map(Pattern::pattern).collect(Collectors
.toList()));
Scanner scanner = new Scanner(asString(path));
int lineNumber = 0;
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
lineNumber++;
boolean containsSnapshot = line.contains("SNAPSHOT");
if (containsSnapshot) {
throw new IllegalStateException("The file [" + path + "] contains a SNAPSHOT "
+ "version for a non snapshot release in line number [" + lineNumber + "]\n\n" + line);
Pattern matchingPattern = this.unacceptableVersionPatterns.stream()
.filter(pattern -> pattern.matcher(line).matches())
.findFirst().orElse(null);
if (matchingPattern != null) {
throw new IllegalStateException("The file [" + path + "] matches the [ " + matchingPattern.pattern() + "] pattern in line number [" + lineNumber + "]\n\n" + line);
}
}
log.info("No snapshot versions remained in the pom");
log.info("No invalid versions remained in the gradle properties");
}
}
@@ -145,7 +154,7 @@ public class GradleUpdater implements ReleaserPropertiesAware {
private boolean pathIgnored(File file) {
String path = file.getPath();
return this.assertSnapshots &&
return this.assertVersions &&
this.properties.getGradle().getIgnoredGradleRegex().stream().anyMatch(path::matches);
}

View File

@@ -26,6 +26,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.slf4j.Logger;
@@ -99,20 +100,20 @@ public class ProjectPomUpdater implements ReleaserPropertiesAware {
* @param projects - versions of projects used to update poms
* @param versionFromReleaseTrain - version for the built project taken
* from release train (e.g. Spring Cloud Release project)
* @param assertSnapshots - should snapshots present be asserted
* @param assertVersions - should version assertion take place
*/
public void updateProjectFromReleaseTrain(File projectRoot, Projects projects,
ProjectVersion versionFromReleaseTrain, boolean assertSnapshots) {
ProjectVersion versionFromReleaseTrain, boolean assertVersions) {
Versions versions = new Versions(projects, this.properties);
if (!this.pomUpdater.shouldProjectBeUpdated(projectRoot, versions)) {
log.info("Skipping project updating");
return;
}
updatePoms(projectRoot, projects, versionFromReleaseTrain, assertSnapshots);
updatePoms(projectRoot, projects, versionFromReleaseTrain, assertVersions);
}
private void updatePoms(File projectRoot, Projects projects,
ProjectVersion versionFromScRelease, boolean assertSnapshots) {
ProjectVersion versionFromScRelease, boolean assertVersions) {
File rootPom = new File(projectRoot, "pom.xml");
if (!rootPom.exists()) {
log.info("No pom.xml present, skipping!");
@@ -120,7 +121,7 @@ public class ProjectPomUpdater implements ReleaserPropertiesAware {
}
ModelWrapper rootPomModel = this.pomUpdater.readModel(rootPom);
processAllPoms(projectRoot, new PomWalker(rootPomModel, projects, this.pomUpdater,
this.properties, versionFromScRelease, assertSnapshots));
this.properties, versionFromScRelease, assertVersions));
}
private void processAllPoms(File projectRoot, PomWalker pomWalker) {
@@ -144,18 +145,21 @@ public class ProjectPomUpdater implements ReleaserPropertiesAware {
private final Versions versions;
private final PomUpdater pomUpdater;
private final ReleaserProperties properties;
private final boolean snapshotVersion;
private final boolean assertSnapshots;
private final boolean skipVersionAssert;
private final boolean assertVersions;
private final List<Pattern> unacceptableVersionPatterns;
private PomWalker(ModelWrapper rootPom, Projects projects, PomUpdater pomUpdater,
ReleaserProperties properties, ProjectVersion versionFromScRelease,
boolean assertSnapshots) {
boolean assertVersions) {
this.rootPom = rootPom;
this.versions = new Versions(projects, properties);
this.pomUpdater = pomUpdater;
this.properties = properties;
this.snapshotVersion = !assertSnapshots || versionFromScRelease.isSnapshot();
this.assertSnapshots = assertSnapshots;
List<Pattern> unacceptableVersionPatterns = versionFromScRelease.unacceptableVersionPatterns();
this.unacceptableVersionPatterns = unacceptableVersionPatterns;
this.skipVersionAssert = !assertVersions || unacceptableVersionPatterns.isEmpty();
this.assertVersions = assertVersions;
}
@Override
@@ -168,21 +172,23 @@ public class ProjectPomUpdater implements ReleaserPropertiesAware {
}
ModelWrapper model = this.pomUpdater.updateModel(this.rootPom, file, this.versions);
this.pomUpdater.overwritePomIfDirty(model, this.versions, file);
if (this.assertSnapshots && !this.snapshotVersion && !this.pomUpdater.hasSkipDeployment(model.model)) {
if (this.assertVersions && !this.skipVersionAssert && !this.pomUpdater.hasSkipDeployment(model.model)) {
log.debug("Update is a non-snapshot one. Checking if no snapshot versions remained in the pom");
Scanner scanner = new Scanner(asString(path));
int lineNumber = 0;
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
lineNumber++;
boolean containsSnapshot = line.contains("SNAPSHOT") &&
IGNORED_SNAPSHOT_LINE_PATTERNS.stream().noneMatch(line::matches);
if (containsSnapshot) {
throw new IllegalStateException("The file [" + path + "] contains a SNAPSHOT "
+ "version for a non snapshot release in line number [" + lineNumber + "]\n\n" + line);
Pattern matchingPattern = this.unacceptableVersionPatterns.stream()
.filter(pattern ->
IGNORED_SNAPSHOT_LINE_PATTERNS.stream().noneMatch(line::matches) &&
pattern.matcher(line).matches())
.findFirst().orElse(null);
if (matchingPattern != null) {
throw new IllegalStateException("The file [" + path + "] matches the [ " + matchingPattern.pattern() + "] pattern in line number [" + lineNumber + "]\n\n" + line);
}
}
log.info("No snapshot versions remained in the pom");
log.info("No invalid versions remained in the pom");
}
}
return FileVisitResult.CONTINUE;
@@ -190,7 +196,7 @@ public class ProjectPomUpdater implements ReleaserPropertiesAware {
private boolean pathIgnored(File file) {
String path = file.getPath();
return this.assertSnapshots &&
return this.assertVersions &&
this.properties.getPom().getIgnoredPomRegex().stream().anyMatch(path::matches);
}

View File

@@ -1,9 +1,14 @@
package org.springframework.cloud.release.internal.pom;
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import org.apache.maven.model.Model;
import org.springframework.util.StringUtils;
/**
@@ -14,6 +19,9 @@ import org.springframework.util.StringUtils;
*/
public class ProjectVersion {
private static final Pattern SNAPSHOT_PATTERN = Pattern.compile("^.*\\.(BUILD-)?SNAPSHOT.*$");
private static final String MILESTONE_REGEX = ".*\\.M[0-9]+";
private static final String RC_REGEX = "^.*\\.RC.*$";
public final String projectName;
public final String version;
private final Model model;
@@ -134,11 +142,11 @@ public class ProjectVersion {
}
public boolean isRc() {
return this.version != null && this.version.contains("RC");
return this.version != null && this.version.matches(RC_REGEX);
}
public boolean isMilestone() {
return this.version != null && this.version.matches(".*M[0-9]+");
return this.version != null && this.version.matches(MILESTONE_REGEX);
}
public boolean isRelease() {
@@ -207,6 +215,16 @@ public class ProjectVersion {
@Override public int hashCode() {
return Objects.hash(this.projectName);
}
public List<Pattern> unacceptableVersionPatterns() {
if (isSnapshot()) {
return Collections.emptyList();
} else if (isMilestone() || isRc()) {
return Collections.singletonList(SNAPSHOT_PATTERN);
}
// treat like GA
return Arrays.asList(SNAPSHOT_PATTERN, Pattern.compile(MILESTONE_REGEX), Pattern.compile(RC_REGEX));
}
}
class VersionNumber implements Comparable<VersionNumber> {

View File

@@ -1,8 +1,5 @@
package org.springframework.cloud.release.internal.gradle;
import static org.assertj.core.api.BDDAssertions.then;
import static org.assertj.core.api.BDDAssertions.thenThrownBy;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
@@ -14,11 +11,15 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.cloud.release.internal.ReleaserProperties;
import org.springframework.cloud.release.internal.pom.ProjectVersion;
import org.springframework.cloud.release.internal.pom.Projects;
import org.springframework.util.FileSystemUtils;
import static org.assertj.core.api.BDDAssertions.then;
import static org.assertj.core.api.BDDAssertions.thenThrownBy;
/**
* @author Marcin Grzejszczak
*/
@@ -70,8 +71,8 @@ public class GradleUpdaterTests {
);
thenThrownBy(() -> new GradleUpdater(properties).updateProjectFromBom(projectRoot,
projects, new ProjectVersion("spring-cloud-contract", "1.0.0"), true))
.hasMessageContaining("contains a SNAPSHOT version for a non snapshot release in line number");
projects, new ProjectVersion("spring-cloud-contract", "1.0.0.RELEASE"), true))
.hasMessageContaining("matches the [ ^.*\\.(BUILD-)?SNAPSHOT.*$] pattern in line number [1]");
}
private File file(String relativePath) throws URISyntaxException {

View File

@@ -3,6 +3,8 @@ package org.springframework.cloud.release.internal.pom;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.regex.Pattern;
import org.junit.Before;
import org.junit.Test;
@@ -360,6 +362,45 @@ public class ProjectVersionTests {
then(projectVersion(thisVersion).compareToReleaseTrainName(thatVersion)).isPositive();
}
@Test
public void should_return_no_unacceptable_patterns_for_a_snapshot_version() {
then(projectVersion("1.0.0.BUILD-SNAPSHOT").unacceptableVersionPatterns()).isEmpty();
then(projectVersion("1.0.0.SNAPSHOT").unacceptableVersionPatterns()).isEmpty();
}
@Test
public void should_return_snapshot_unacceptable_patterns_for_a_milestone_or_rc_version() {
List<Pattern> milestonePatterns = projectVersion("1.0.0.M1").unacceptableVersionPatterns();
then(milestonePatterns).isNotEmpty();
then(milestonePatterns.get(0).pattern()).contains("SNAPSHOT");
List<Pattern> rcPatterns = projectVersion("1.0.0.RC1").unacceptableVersionPatterns();
then(rcPatterns).isNotEmpty();
then(rcPatterns.get(0).pattern()).contains("SNAPSHOT");
}
@Test
public void should_return_snapshot_milestone_rc_unacceptable_patterns_for_a_ga_or_sr_version() {
List<Pattern> gaPatterns = projectVersion("1.0.0.RELEASE").unacceptableVersionPatterns();
thenPatternsForSnapshotMilestoneAndReleaseCandidateArePresent(gaPatterns);
gaPatterns = projectVersion("1.0.0").unacceptableVersionPatterns();
thenPatternsForSnapshotMilestoneAndReleaseCandidateArePresent(gaPatterns);
List<Pattern> srPatterns = projectVersion("1.0.0.SR1").unacceptableVersionPatterns();
thenPatternsForSnapshotMilestoneAndReleaseCandidateArePresent(srPatterns);
List<Pattern> unknownTypeOfVersion = projectVersion("1.0.0.SOMETHING").unacceptableVersionPatterns();
thenPatternsForSnapshotMilestoneAndReleaseCandidateArePresent(unknownTypeOfVersion);
}
private void thenPatternsForSnapshotMilestoneAndReleaseCandidateArePresent(List<Pattern> unknownTypeOfVersion) {
then(unknownTypeOfVersion).isNotEmpty();
then(unknownTypeOfVersion.get(0).pattern()).contains("SNAPSHOT");
then(unknownTypeOfVersion.get(1).pattern()).contains("M[0-9]");
then(unknownTypeOfVersion.get(2).pattern()).contains("RC");
}
private ProjectVersion projectVersion(String version) {
return new ProjectVersion("foo", version);
}