mirror of
https://gitee.com/dcren/initializr.git
synced 2025-07-15 14:04:30 +08:00
Provide support for resolving versions from Maven boms
This commit introduces a new module, initializer-version-resolver, that provides support for resolving versions from the dependency management of a Maven bom. Providing with the bom's coordinates (groupId, artifactId, and version) a map of groupId:artifactId to version, derived from the bom's <dependencyManagement>, is returned. Closes gh-934
This commit is contained in:
parent
1c7a73c29f
commit
ab8b1158fa
42
initializr-version-resolver/pom.xml
Normal file
42
initializr-version-resolver/pom.xml
Normal file
@ -0,0 +1,42 @@
|
||||
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>io.spring.initializr</groupId>
|
||||
<artifactId>initializr</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<artifactId>initializr-version-resolver</artifactId>
|
||||
<name>Spring Initializr :: Version Resolver</name>
|
||||
|
||||
<properties>
|
||||
<main.basedir>${basedir}/..</main.basedir>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-resolver-provider</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.resolver</groupId>
|
||||
<artifactId>maven-resolver-connector-basic</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.resolver</groupId>
|
||||
<artifactId>maven-resolver-transport-http</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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 io.spring.initializr.versionresolver;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A {@code DependencyManagementVersionResolver} is used to resolve the versions in the
|
||||
* managed dependencies of a Maven bom. Implementations must be thread-safe.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public interface DependencyManagementVersionResolver {
|
||||
|
||||
/**
|
||||
* Resolves the versions in the managed dependencies of the bom identified by the
|
||||
* given {@code groupId}, {@code artifactId}, and {@code version}.
|
||||
* @param groupId bom group ID
|
||||
* @param artifactId bom artifact ID
|
||||
* @param version bom version
|
||||
* @return the managed dependencies as a map of {@code groupId:artifactId} to
|
||||
* {@code version}
|
||||
*/
|
||||
Map<String, String> resolve(String groupId, String artifactId, String version);
|
||||
|
||||
/**
|
||||
* Creates a new {@code DependencyManagementVersionResolver} that uses the given
|
||||
* {@code location} for its local cache. To avoid multiple instances attempting to
|
||||
* write to the same location cache, callers should ensure that a unique location is
|
||||
* used. The returned resolver can then be used concurrently by multiple threads.
|
||||
* @param location cache location
|
||||
* @return the resolver
|
||||
*/
|
||||
static DependencyManagementVersionResolver withCacheLocation(Path location) {
|
||||
return new MavenResolverDependencyManagementVersionResolver(location);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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 io.spring.initializr.versionresolver;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
|
||||
import org.eclipse.aether.DefaultRepositorySystemSession;
|
||||
import org.eclipse.aether.RepositorySystem;
|
||||
import org.eclipse.aether.RepositorySystemSession;
|
||||
import org.eclipse.aether.artifact.DefaultArtifact;
|
||||
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
|
||||
import org.eclipse.aether.impl.DefaultServiceLocator;
|
||||
import org.eclipse.aether.internal.impl.DefaultRepositorySystem;
|
||||
import org.eclipse.aether.repository.LocalRepository;
|
||||
import org.eclipse.aether.repository.LocalRepositoryManager;
|
||||
import org.eclipse.aether.repository.RemoteRepository;
|
||||
import org.eclipse.aether.resolution.ArtifactDescriptorException;
|
||||
import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
|
||||
import org.eclipse.aether.resolution.ArtifactDescriptorResult;
|
||||
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
|
||||
import org.eclipse.aether.spi.connector.transport.TransporterFactory;
|
||||
import org.eclipse.aether.spi.locator.ServiceLocator;
|
||||
import org.eclipse.aether.transport.http.HttpTransporterFactory;
|
||||
import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy;
|
||||
|
||||
/**
|
||||
* A {@link DependencyManagementVersionResolver} that resolves versions using Maven
|
||||
* Resolver. Maven's default {@link LocalRepositoryManager} implementation is not
|
||||
* thread-safe. To avoid corruption of the local repository, interaction with the
|
||||
* {@link RepositorySystem} is single-threaded.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class MavenResolverDependencyManagementVersionResolver implements DependencyManagementVersionResolver {
|
||||
|
||||
private static final RemoteRepository mavenCentral = new RemoteRepository.Builder("central", "default",
|
||||
"https://repo1.maven.org/maven2").build();
|
||||
|
||||
private static final RemoteRepository springMilestones = new RemoteRepository.Builder("spring-milestones",
|
||||
"default", "https://repo.spring.io/milestone").build();
|
||||
|
||||
private static final RemoteRepository springSnapshots = new RemoteRepository.Builder("spring-snapshots", "default",
|
||||
"https://repo.spring.io/snapshot").build();
|
||||
|
||||
private static final List<RemoteRepository> repositories = Arrays.asList(mavenCentral, springMilestones,
|
||||
springSnapshots);
|
||||
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final RepositorySystemSession repositorySystemSession;
|
||||
|
||||
private final RepositorySystem repositorySystem;
|
||||
|
||||
MavenResolverDependencyManagementVersionResolver(Path cacheLocation) {
|
||||
ServiceLocator serviceLocator = createServiceLocator();
|
||||
DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
|
||||
session.setArtifactDescriptorPolicy(new SimpleArtifactDescriptorPolicy(false, false));
|
||||
LocalRepository localRepository = new LocalRepository(cacheLocation.toFile());
|
||||
this.repositorySystem = serviceLocator.getService(RepositorySystem.class);
|
||||
session.setLocalRepositoryManager(this.repositorySystem.newLocalRepositoryManager(session, localRepository));
|
||||
session.setReadOnly();
|
||||
this.repositorySystemSession = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> resolve(String groupId, String artifactId, String version) {
|
||||
ArtifactDescriptorResult bom = resolveBom(groupId, artifactId, version);
|
||||
Map<String, String> managedVersions = new HashMap<>();
|
||||
bom.getManagedDependencies().stream().map((dependency) -> dependency.getArtifact())
|
||||
.forEach((artifact) -> managedVersions
|
||||
.putIfAbsent(artifact.getGroupId() + ":" + artifact.getArtifactId(), artifact.getVersion()));
|
||||
return managedVersions;
|
||||
}
|
||||
|
||||
private ArtifactDescriptorResult resolveBom(String groupId, String artifactId, String version) {
|
||||
synchronized (this.monitor) {
|
||||
try {
|
||||
return this.repositorySystem.readArtifactDescriptor(this.repositorySystemSession,
|
||||
new ArtifactDescriptorRequest(new DefaultArtifact(groupId, artifactId, "pom", version),
|
||||
repositories, null));
|
||||
}
|
||||
catch (ArtifactDescriptorException ex) {
|
||||
throw new IllegalStateException(
|
||||
"Bom '" + groupId + ":" + artifactId + ":" + version + "' could not be resolved", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ServiceLocator createServiceLocator() {
|
||||
DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
|
||||
locator.addService(RepositorySystem.class, DefaultRepositorySystem.class);
|
||||
locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);
|
||||
locator.addService(TransporterFactory.class, HttpTransporterFactory.class);
|
||||
return locator;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Classes relating to version resolution.
|
||||
*/
|
||||
package io.spring.initializr.versionresolver;
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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 io.spring.initializr.versionresolver;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link MavenResolverDependencyManagementVersionResolver}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class MavenResolverDependencyManagementVersionResolverTests {
|
||||
|
||||
private DependencyManagementVersionResolver resolver;
|
||||
|
||||
@BeforeEach
|
||||
void createResolver(@TempDir Path temp) {
|
||||
this.resolver = new MavenResolverDependencyManagementVersionResolver(temp);
|
||||
}
|
||||
|
||||
@Test
|
||||
void springBootDependencies() {
|
||||
Map<String, String> versions = this.resolver.resolve("org.springframework.boot", "spring-boot-dependencies",
|
||||
"2.1.5.RELEASE");
|
||||
assertThat(versions).containsEntry("org.flywaydb:flyway-core", "5.2.4");
|
||||
}
|
||||
|
||||
@Test
|
||||
void springCloudDependencies() {
|
||||
Map<String, String> versions = this.resolver.resolve("org.springframework.cloud", "spring-cloud-dependencies",
|
||||
"Greenwich.SR1");
|
||||
assertThat(versions).containsEntry("com.netflix.ribbon:ribbon", "2.3.0");
|
||||
}
|
||||
|
||||
@Test
|
||||
void milestoneBomCanBeResolved() {
|
||||
Map<String, String> versions = this.resolver.resolve("org.springframework.boot", "spring-boot-dependencies",
|
||||
"2.2.0.M3");
|
||||
assertThat(versions).containsEntry("org.flywaydb:flyway-core", "5.2.4");
|
||||
}
|
||||
|
||||
@Test
|
||||
void snapshotBomCanBeResolved() {
|
||||
Map<String, String> versions = this.resolver.resolve("org.springframework.boot", "spring-boot-dependencies",
|
||||
"2.2.0.BUILD-SNAPSHOT");
|
||||
assertThat(versions).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void nonExistentDependency() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> this.resolver.resolve("org.springframework.boot", "spring-boot-bom", "1.0"))
|
||||
.withMessage("Bom 'org.springframework.boot:spring-boot-bom:1.0' could not be resolved");
|
||||
}
|
||||
|
||||
}
|
18
pom.xml
18
pom.xml
@ -42,6 +42,8 @@
|
||||
<main.basedir>${basedir}</main.basedir>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<junit-jupiter.version>5.4.2</junit-jupiter.version>
|
||||
<maven.version>3.6.1</maven.version>
|
||||
<maven-resolver.version>1.3.3</maven-resolver.version>
|
||||
<spring-boot.version>2.1.6.RELEASE</spring-boot.version>
|
||||
<spring-cloud-contract.version>2.1.1.RELEASE</spring-cloud-contract.version>
|
||||
<spring-javaformat.version>0.0.12</spring-javaformat.version>
|
||||
@ -54,6 +56,7 @@
|
||||
<module>initializr-generator-spring</module>
|
||||
<module>initializr-metadata</module>
|
||||
<module>initializr-service-sample</module>
|
||||
<module>initializr-version-resolver</module>
|
||||
<module>initializr-web</module>
|
||||
</modules>
|
||||
|
||||
@ -102,6 +105,21 @@
|
||||
<version>${revision}</version>
|
||||
<type>test-jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-resolver-provider</artifactId>
|
||||
<version>${maven.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.resolver</groupId>
|
||||
<artifactId>maven-resolver-connector-basic</artifactId>
|
||||
<version>${maven-resolver.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.resolver</groupId>
|
||||
<artifactId>maven-resolver-transport-http</artifactId>
|
||||
<version>${maven-resolver.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit</groupId>
|
||||
<artifactId>junit-bom</artifactId>
|
||||
|
Loading…
Reference in New Issue
Block a user