Skip to content

fix: Adding a managed Maven dependency throws exception if it exists in same or higher version #779

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

Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -178,23 +178,23 @@ protected Path getTestDir() {
* @param applicableRecipes
*/
protected void assertApplicableRecipesContain(String... applicableRecipes) {
List<String> recipeNames = getRecipeNames();
List<String> recipeNames = getApplicableRecipeNames();
assertThat(recipeNames).contains(applicableRecipes);
}

@NotNull
private List<String> getRecipeNames() {
protected List<String> getApplicableRecipeNames() {
return applicableRecipeListCommand.execute(projectContextHolder.getProjectContext()).stream()
.map(r -> r.getName()).collect(Collectors.toList());
}

protected void assertRecipeApplicable(String recipeName) {
List<String> recipeNames = getRecipeNames();
List<String> recipeNames = getApplicableRecipeNames();
assertThat(recipeNames).contains(recipeName);
}

protected void assertRecipeNotApplicable(String recipeName) {
List<String> recipeNames = getRecipeNames();
List<String> recipeNames = getApplicableRecipeNames();
assertThat(recipeNames).doesNotContain(recipeName);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@
*/
package org.springframework.sbm.build.migration.actions;

import org.springframework.sbm.build.api.Module;
import org.apache.maven.artifact.versioning.ComparableVersion;
import org.jetbrains.annotations.NotNull;
import org.springframework.sbm.build.api.BuildFile;
import org.springframework.sbm.build.api.Dependency;
import org.springframework.sbm.engine.recipe.AbstractAction;
import org.springframework.sbm.engine.context.ProjectContext;
import lombok.Setter;

import java.util.Optional;

@Setter
public class AddMavenDependencyManagementAction extends AbstractAction {

Expand All @@ -33,14 +36,58 @@ public class AddMavenDependencyManagementAction extends AbstractAction {

@Override
public void apply(ProjectContext context) {
verifyNoConflictingManagedDependencyExists(context);

Dependency dependency = Dependency.builder()
.groupId(groupId)
.artifactId(artifactId)
.version(version)
.scope(scope)
.type(dependencyType)
.build();
BuildFile rootBuildFile = context.getApplicationModules().getRootModule().getBuildFile();
rootBuildFile.addToDependencyManagement(dependency);
}

@NotNull
private void verifyNoConflictingManagedDependencyExists(ProjectContext context) {
BuildFile rootBuildFile = context.getApplicationModules().getRootModule().getBuildFile();
Optional<Dependency> managedSpringDep = rootBuildFile
.getRequestedDependencyManagement()
.stream()
.filter(this::matchingDependencyManagementSection)
.findFirst();

if(managedSpringDep.isPresent()) {
Dependency managedDep = managedSpringDep.get();
int comparisonResult = compareVersions(this.version, managedDep.getVersion());
if(managedDependencyHasSameVersion(comparisonResult) || managedDependencyHasHigherVersion(comparisonResult)) {
String message = String.format(
"Failed to add a managed dependency %s with version %s. This managed dependency already exists in %s in version %s.",
this.groupId + ":" + this.artifactId,
this.version,
rootBuildFile.getAbsolutePath(),
managedDep.getVersion()
);
throw new IllegalStateException(message);
}
}
}

private boolean managedDependencyHasSameVersion(int comparisonResult) {
return comparisonResult == 0;
}

private boolean managedDependencyHasHigherVersion(int comparisonResult) {
return comparisonResult == -1;
}

private int compareVersions(String newVersion, String existingVersion) {
return new ComparableVersion(newVersion).compareTo(new ComparableVersion(existingVersion));
}

context.getApplicationModules().getRootModule().getBuildFile().addToDependencyManagement(dependency);
private boolean matchingDependencyManagementSection(Dependency dependency) {
return dependency.getGroupId().equals(groupId) &&
dependency.getArtifactId().equals(artifactId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright 2021 - 2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.sbm.build.migration.conditions;

import lombok.Setter;
import org.apache.maven.artifact.versioning.ComparableVersion;
import org.springframework.sbm.build.api.BuildFile;
import org.springframework.sbm.build.api.Dependency;
import org.springframework.sbm.build.api.Module;
import org.springframework.sbm.engine.context.ProjectContext;
import org.springframework.sbm.engine.recipe.Condition;

import java.util.List;

/**
* @author Fabian Krüger
*/
@Setter
public class NoMoreRecentManagedDependencyExists implements Condition {

private String groupId;
private String artifactId;
private String version;


@Override
public String getDescription() {
return "Check that no more recent managed dependency exists";
}

@Override
public boolean evaluate(ProjectContext context) {
return context.getApplicationModules().stream().map(Module::getBuildFile)
.noneMatch(this::hasConflictingManagedDependency);
}

private boolean hasConflictingManagedDependency(BuildFile buildFile) {
List<Dependency> requestedDependencyManagement = buildFile.getRequestedDependencyManagement();
if(requestedDependencyManagement == null || requestedDependencyManagement.isEmpty()) {
return false;
}
return buildFile.getRequestedDependencyManagement().stream()
.anyMatch(this::isConflictingDEpendency);
}

private boolean isConflictingDEpendency(Dependency dependency) {
boolean matchingGA = groupId.equals(dependency.getGroupId()) &&
artifactId.equals(dependency.getArtifactId());

if(matchingGA) {
return hasConflictingVersion(dependency);
} else {
return false;
}
}

private boolean hasConflictingVersion(Dependency dependency) {
int comparisonResult = compareVersions(version, dependency.getVersion());
return managedDependencyHasHigherVersion(comparisonResult) || managedDependencyHasSameVersion(comparisonResult);
}

private boolean managedDependencyHasSameVersion(int comparisonResult) {
return comparisonResult == 0;
}

private boolean managedDependencyHasHigherVersion(int comparisonResult) {
return comparisonResult == -1;
}

private int compareVersions(String newVersion, String existingVersion) {
return new ComparableVersion(newVersion).compareTo(new ComparableVersion(existingVersion));
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/*
* Copyright 2021 - 2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.sbm.java.exceptions;

public class UnresolvedTypeException extends RuntimeException {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/*
* Copyright 2023 the original author or authors.
* <p>
* Copyright 2021 - 2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.springframework.sbm.testhelper.common.utils.TestDiff;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;

class AddMavenDependencyManagementActionTest {

Expand Down Expand Up @@ -205,4 +206,60 @@ void shouldAddToRootPomInSingleModuleProject() {
.as(TestDiff.of(buildFile.print(), expected))
.isEqualTo(expected);
}

@Test
void shouldThrowExceptionWhenSameManagedDependencyExistsWithHigherVersion() {
String versionInPom = "2.7.5";
String versionInRecipe = "2.7.4";
testAddMavenDependencyManagementAction(versionInPom, versionInRecipe);
}

@Test
void shouldThrowExceptionWhenSameManagedDependencyExistsWithSameVersion() {
String versionInPom = "2.7.5";
String versionInRecipe = "2.7.5";
testAddMavenDependencyManagementAction(versionInPom, versionInRecipe);
}

private void testAddMavenDependencyManagementAction(String versionInPom, String versionInRecipe) {
String pom = """
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>%s</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
""".formatted(versionInPom);

ProjectContext projectContext = TestProjectContext.buildProjectContext().withMavenRootBuildFileSource(pom).build();

AddMavenDependencyManagementAction sut = new AddMavenDependencyManagementAction();
sut.setGroupId("org.springframework.boot");
sut.setArtifactId("spring-boot-dependencies");

sut.setVersion(versionInRecipe);

assertThrows(IllegalStateException.class, () -> {
sut.apply(projectContext);
}).getMessage().equals("Failed to add a managed dependency org.springframework.boot:spring-boot-dependencies with version "+ versionInRecipe +". " +
"This managed dependency already exists in " + projectContext.getApplicationModules().getRootModule().getBuildFile().getAbsolutePath().toString() + " in version "+versionInPom+".");
}
}
Loading