Support for commercial releases.

This commit is contained in:
Oliver Drotbohm
2024-02-06 16:45:24 +01:00
parent da02529ba4
commit 5c07bc9780
70 changed files with 1148 additions and 654 deletions

1
Jenkinsfile vendored
View File

@@ -54,6 +54,7 @@ pipeline {
GITHUB = credentials('3a20bcaa-d8ad-48e3-901d-9fbc941376ee')
GITHUB_TOKEN = credentials('7b3ebbea-7001-479b-8578-b8c464dab973')
REPO_SPRING_IO = credentials('repo_spring_io-jenkins-release-token')
COMMERCIAL = credentials('repo_spring_vmware_com-jenkins-token')
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
STAGING_PROFILE_ID = credentials('spring-data-release-deployment-maven-central-staging-profile-id')
MAVEN_SIGNING_KEY = credentials('spring-gpg-private-key')

View File

@@ -18,5 +18,15 @@
<username>${env.ARTIFACTORY_USR}</username>
<password>${env.ARTIFACTORY_PSW}</password>
</server>
<server>
<id>spring-commercial-snapshot</id>
<username>${env.COMMERCIAL_USR}</username>
<password>${env.COMMERCIAL_PSW}</password>
</server>
<server>
<id>spring-commercial-release</id>
<username>${env.COMMERCIAL_USR}</username>
<password>${env.COMMERCIAL_PSW}</password>
</server>
</servers>
</settings>

View File

@@ -19,10 +19,8 @@ import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.release.model.Project;
import org.springframework.plugin.core.OrderAwarePluginRegistry;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.plugin.core.PluginRegistry;
import org.xmlbeam.XBProjector;
import org.xmlbeam.XBProjector.Flags;
import org.xmlbeam.config.DefaultXMLFactoriesConfig;
@@ -37,8 +35,8 @@ import org.xmlbeam.config.DefaultXMLFactoriesConfig.NamespacePhilosophy;
class BuildConfiguration {
@Bean
public PluginRegistry<BuildSystem, Project> buildSystems(List<? extends BuildSystem> buildSystems) {
return OrderAwarePluginRegistry.create(buildSystems);
public PluginRegistry<BuildSystem, SupportedProject> buildSystems(List<? extends BuildSystem> buildSystems) {
return PluginRegistry.of(buildSystems);
}
@Bean

View File

@@ -35,16 +35,15 @@ import java.util.function.BiFunction;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.PreDestroy;
import org.apache.commons.io.IOUtils;
import org.springframework.data.release.infra.InfrastructureOperations;
import org.springframework.data.release.io.Workspace;
import org.springframework.data.release.model.JavaVersion;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.model.ProjectAware;
import org.springframework.data.release.utils.ListWrapperCollector;
import org.springframework.data.util.Streamable;
@@ -61,8 +60,7 @@ import org.springframework.util.Assert;
@RequiredArgsConstructor
class BuildExecutor {
private final @NonNull PluginRegistry<BuildSystem, Project> buildSystems;
private final MavenProperties mavenProperties;
private final @NonNull PluginRegistry<BuildSystem, SupportedProject> buildSystems;
private final ExecutorService executor;
private final Workspace workspace;
@@ -121,13 +119,14 @@ class BuildExecutor {
if (futureResult == null) {
if (!iteration.stream().map(ProjectAware::getProject).anyMatch(project -> project.equals(dependency))) {
throw new IllegalStateException(moduleIteration.getProject().getName() + " requires "
if (!iteration.stream().map(ProjectAware::getSupportedProject)
.anyMatch(project -> project.equals(dependency))) {
throw new IllegalStateException(moduleIteration.getSupportedProject().getName() + " requires "
+ dependency.getName() + " which is not part of the Iteration. Please fix Projects/Iterations setup");
}
throw new IllegalStateException("No future result for " + dependency.getName() + ", required by "
+ moduleIteration.getProject().getName());
+ moduleIteration.getSupportedProject().getName());
}
futureResult.join();
@@ -156,16 +155,18 @@ class BuildExecutor {
.collect(toSummaryCollector());
}
private <T, M extends ProjectAware> CompletableFuture<T> run(M module, BiFunction<BuildSystem, M, T> function) {
private <T, M extends ProjectAware> CompletableFuture<T> run(M module,
BiFunction<BuildSystem, M, T> function) {
Assert.notNull(module, "Module must not be null!");
CompletableFuture<T> result = new CompletableFuture<>();
Supplier<IllegalStateException> exception = () -> new IllegalStateException(
String.format("No build system plugin found for project %s!", module.getProject()));
String.format("No build system plugin found for project %s!", module.getSupportedProject()));
BuildSystem buildSystem = buildSystems.getPluginFor(module.getProject(), exception)
.withJavaVersion(detectJavaVersion(module.getProject()));
BuildSystem buildSystem = buildSystems //
.getPluginFor(module.getSupportedProject(), exception) //
.withJavaVersion(detectJavaVersion(module.getSupportedProject()));
Runnable runnable = () -> {
@@ -183,7 +184,7 @@ class BuildExecutor {
}
@SneakyThrows
public JavaVersion detectJavaVersion(Project project) {
public JavaVersion detectJavaVersion(SupportedProject project) {
File ciProperties = workspace.getFile(InfrastructureOperations.CI_PROPERTIES, project);

View File

@@ -29,12 +29,11 @@ import java.util.stream.Collectors;
import org.assertj.core.util.VisibleForTesting;
import org.springframework.data.release.deployment.DeploymentInformation;
import org.springframework.data.release.deployment.StagingRepository;
import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.Module;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Phase;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.ProjectAware;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.model.Train;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.data.release.utils.Logger;
@@ -52,7 +51,7 @@ import org.springframework.util.Assert;
@RequiredArgsConstructor
public class BuildOperations {
private final @NonNull PluginRegistry<BuildSystem, Project> buildSystems;
private final @NonNull PluginRegistry<BuildSystem, SupportedProject> buildSystems;
private final @NonNull Logger logger;
private final @NonNull MavenProperties properties;
private final @NonNull BuildExecutor executor;
@@ -117,7 +116,7 @@ public class BuildOperations {
*/
public void open(ModuleIteration iteration) {
doWithBuildSystem(iteration, (buildSystem, moduleIteration) -> buildSystem.open());
doWithBuildSystem(iteration, (buildSystem, moduleIteration) -> buildSystem.open(iteration.getTrain()));
}
/**
@@ -131,8 +130,10 @@ public class BuildOperations {
Assert.notNull(stagingRepository, "StagingRepository must not be null");
Assert.isTrue(stagingRepository.isPresent(), "StagingRepository must be present");
Train train = iteration.getTrain();
doWithBuildSystem(iteration, (buildSystem, moduleIteration) -> {
buildSystem.close(stagingRepository);
buildSystem.close(train, stagingRepository);
return null;
});
}
@@ -145,7 +146,7 @@ public class BuildOperations {
*/
public void build(TrainIteration iteration) {
executor.doWithBuildSystemOrdered(iteration, BuildSystem::triggerBuild);
executor.doWithBuildSystemOrdered(iteration, (it, l) -> it.triggerBuild(l));
logger.log(iteration, "Build finished");
}
@@ -156,11 +157,11 @@ public class BuildOperations {
* @param iteration
* @return
*/
public StagingRepository openStagingRepository(Iteration iteration) {
public StagingRepository openStagingRepository(TrainIteration iteration) {
BuildSystem orchestrator = buildSystems.getRequiredPluginFor(Projects.BUILD);
BuildSystem orchestrator = buildSystems.getRequiredPluginFor(iteration.getSupportedProject(Projects.BUILD));
return iteration.isPublic() ? orchestrator.open() : StagingRepository.EMPTY;
return iteration.isPublic() ? orchestrator.open(iteration.getTrain()) : StagingRepository.EMPTY;
}
/**
@@ -169,27 +170,28 @@ public class BuildOperations {
* @param stagingRepository
* @return
*/
public void closeStagingRepository(StagingRepository stagingRepository) {
public void closeStagingRepository(Train train, StagingRepository stagingRepository) {
BuildSystem orchestrator = buildSystems.getRequiredPluginFor(Projects.BUILD);
BuildSystem orchestrator = buildSystems.getRequiredPluginFor(train.getSupportedProject(Projects.BUILD));
if (stagingRepository.isPresent()) {
orchestrator.close(stagingRepository);
orchestrator.close(train, stagingRepository);
}
}
/**
* Promote the staging repository.
*
* @param stagingRepository
* @param train must not be {@literal null}.
* @param stagingRepository must not be {@literal null}.
* @return
*/
public void releaseStagingRepository(StagingRepository stagingRepository) {
public void releaseStagingRepository(Train train, StagingRepository stagingRepository) {
BuildSystem orchestrator = buildSystems.getRequiredPluginFor(Projects.BUILD);
BuildSystem orchestrator = buildSystems.getRequiredPluginFor(train.getSupportedProject(Projects.BUILD));
if (stagingRepository.isPresent()) {
orchestrator.release(stagingRepository);
orchestrator.release(train, stagingRepository);
}
}
@@ -215,16 +217,19 @@ public class BuildOperations {
*/
public void release(ModuleIteration iteration, StagingRepository stagingRepository) {
Train train = iteration.getTrain();
doWithBuildSystem(iteration, (buildSystem, moduleIteration) -> {
buildSystem.release(stagingRepository);
buildSystem.release(train, stagingRepository);
return null;
});
}
public void buildDocumentation(TrainIteration iteration) {
executor.doWithBuildSystemOrdered(Streamable.of(iteration.getModulesExcept(BOM, COMMONS, BUILD)),
BuildSystem::triggerDocumentationBuild);
Streamable<ModuleIteration> of = Streamable.of(iteration.getModulesExcept(BOM, COMMONS, BUILD));
executor.doWithBuildSystemOrdered(of, BuildSystem::triggerDocumentationBuild);
logger.log(iteration, "Documentation build finished");
}
@@ -244,14 +249,17 @@ public class BuildOperations {
*/
public List<DeploymentInformation> performRelease(TrainIteration iteration) {
Iteration it = iteration.getIteration();
StagingRepository stagingRepository = it.isPublic() ? openStagingRepository(it) : StagingRepository.EMPTY;
StagingRepository stagingRepository = iteration.isPublic() //
? openStagingRepository(iteration) //
: StagingRepository.EMPTY;
BuildExecutor.Summary<DeploymentInformation> summary = executor.doWithBuildSystemOrdered(iteration,
(buildSystem, moduleIteration) -> buildSystem.deploy(moduleIteration, stagingRepository));
Train train = iteration.getTrain();
if (stagingRepository.isPresent()) {
closeStagingRepository(stagingRepository);
closeStagingRepository(train, stagingRepository);
}
smokeTests(iteration, stagingRepository);
@@ -259,10 +267,12 @@ public class BuildOperations {
logger.log(iteration, "Release: %s", summary);
if (stagingRepository.isPresent()) {
releaseStagingRepository(stagingRepository);
releaseStagingRepository(train, stagingRepository);
}
return summary.getExecutions().stream().map(BuildExecutor.ExecutionResult::getResult).collect(Collectors.toList());
return summary.getExecutions().stream()
.map(BuildExecutor.ExecutionResult::getResult)
.collect(Collectors.toList());
}
/**
@@ -296,8 +306,7 @@ public class BuildOperations {
Assert.notNull(train, "Train must not be null!");
BuildExecutor.Summary<Module> summary = executor.doWithBuildSystemAnyOrder(train,
BuildSystem::triggerDistributionBuild);
BuildExecutor.Summary<?> summary = executor.doWithBuildSystemAnyOrder(train, BuildSystem::triggerDistributionBuild);
logger.log(train, "Distribution build: %s", summary);
}
@@ -357,24 +366,30 @@ public class BuildOperations {
/**
* Verifies Java version presence and that the project can be build using Maven.
*
* @param train must not be {@literal null}.
*/
public void verify() {
public void verify(Train train) {
Project project = Projects.BUILD;
SupportedProject project = train.getSupportedProject(Projects.BUILD);
BuildSystem buildSystem = buildSystems.getRequiredPluginFor(project);
buildSystem.withJavaVersion(executor.detectJavaVersion(project)).verify();
buildSystem.verify(train);
// buildSystem.withJavaVersion(executor.detectJavaVersion(project)).verify(train);
}
/**
* Verifies Maven staging authentication.
*
* @param train must not be {@literal null}.
*/
public void verifyStagingAuthentication() {
public void verifyStagingAuthentication(Train train) {
Project project = Projects.BUILD;
SupportedProject project = train.getSupportedProject(Projects.BUILD);
BuildSystem buildSystem = buildSystems.getRequiredPluginFor(project);
buildSystem.withJavaVersion(executor.detectJavaVersion(project)).verifyStagingAuthentication();
buildSystem.verifyStagingAuthentication(train);
// buildSystem.withJavaVersion(executor.detectJavaVersion(project)).verifyStagingAuthentication(train);
}
/**
@@ -385,15 +400,17 @@ public class BuildOperations {
* @param function must not be {@literal null}.
* @return
*/
private <T> T doWithBuildSystem(ModuleIteration module, BiFunction<BuildSystem, ModuleIteration, T> function) {
private <T, S extends ProjectAware> T doWithBuildSystem(S module,
BiFunction<BuildSystem, S, T> function) {
Assert.notNull(module, "ModuleIteration must not be null!");
Supplier<IllegalStateException> exception = () -> new IllegalStateException(
String.format("No build system plugin found for project %s!", module.getProject()));
String.format("No build system plugin found for project %s!", module.getSupportedProject()));
BuildSystem buildSystem = buildSystems.getPluginFor(module.getProject(), exception);
BuildSystem buildSystem = buildSystems.getPluginFor(module.getSupportedProject(), exception);
return function.apply(buildSystem.withJavaVersion(executor.detectJavaVersion(module.getProject())), module);
return function.apply(buildSystem.withJavaVersion(executor.detectJavaVersion(module.getSupportedProject())),
module);
}
}

View File

@@ -20,8 +20,9 @@ import org.springframework.data.release.deployment.StagingRepository;
import org.springframework.data.release.model.JavaVersion;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Phase;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.model.ProjectAware;
import org.springframework.data.release.model.Train;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.plugin.core.Plugin;
@@ -32,7 +33,7 @@ import org.springframework.plugin.core.Plugin;
* @author Mark Paluch
* @author Greg Turnquist
*/
interface BuildSystem extends Plugin<Project> {
interface BuildSystem extends Plugin<SupportedProject> {
/**
* Updates the project descriptors for the given {@link ModuleIteration} using the given {@link UpdateInformation}.
@@ -61,18 +62,24 @@ interface BuildSystem extends Plugin<Project> {
/**
* Open a remote repository for staging artifacts.
*
* @param train must not be {@literal null}.
*/
StagingRepository open();
StagingRepository open(Train train);
/**
* Close a remote repository for staging artifacts.
*
* @param train must not be {@literal null}.
*/
void close(StagingRepository stagingRepository);
void close(Train train, StagingRepository stagingRepository);
/**
* Release a remote repository of staged artifacts.
*
* @param train must not be {@literal null}.
*/
void release(StagingRepository stagingRepository);
void release(Train train, StagingRepository stagingRepository);
<M extends ProjectAware> M triggerBuild(M module);
@@ -113,13 +120,17 @@ interface BuildSystem extends Plugin<Project> {
/**
* Verify general functionality and correctness of the build setup.
*
* @param train must not be {@literal null}.
*/
void verify();
void verify(Train train);
/**
* Verify general functionality and correctness of the build setup.
*
* @param train must not be {@literal null}.
*/
void verifyStagingAuthentication();
void verifyStagingAuthentication(Train train);
/**
* Prepare the build system with a Java version.

View File

@@ -47,7 +47,7 @@ public class MavenArtifact {
Assert.notNull(module, "Module iteration must not be null!");
this.project = module.getModule().getProject();
this.project = module.getProject();
this.version = ArtifactVersion.of(module);
}

View File

@@ -48,18 +48,11 @@ import org.springframework.data.release.build.Pom.Artifact;
import org.springframework.data.release.deployment.DefaultDeploymentInformation;
import org.springframework.data.release.deployment.DeploymentInformation;
import org.springframework.data.release.deployment.DeploymentProperties;
import org.springframework.data.release.deployment.DeploymentProperties.Authentication;
import org.springframework.data.release.deployment.DeploymentProperties.MavenCentral;
import org.springframework.data.release.deployment.StagingRepository;
import org.springframework.data.release.io.Workspace;
import org.springframework.data.release.model.ArtifactVersion;
import org.springframework.data.release.model.Gpg;
import org.springframework.data.release.model.JavaVersion;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Phase;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.ProjectAware;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.data.release.model.Version;
import org.springframework.data.release.model.*;
import org.springframework.data.release.utils.Logger;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@@ -107,17 +100,18 @@ class MavenBuildSystem implements BuildSystem {
@Override
public <M extends ProjectAware> M updateProjectDescriptors(M module, UpdateInformation information) {
PomUpdater updater = new PomUpdater(logger, information, module.getProject());
PomUpdater updater = new PomUpdater(logger, information, module.getSupportedProject());
TrainIteration train = information.getTrain();
if (updater.isBuildProject()) {
if (information.isBomInBuildProject()) {
updateBom(updater, information, "bom/pom.xml", BUILD);
updateBom(updater, information, "bom/pom.xml", train.getSupportedProject(BUILD));
}
updateParentPom(updater, information);
} else if (updater.isBomProject()) {
updateBom(updater, information, "bom/pom.xml", BOM);
updateBom(updater, information, "bom/pom.xml", train.getSupportedProject(BOM));
} else {
doWithProjection(workspace.getFile(POM_XML, updater.getProject()), pom -> {
@@ -138,12 +132,12 @@ class MavenBuildSystem implements BuildSystem {
@Override
public ModuleIteration prepareVersion(ModuleIteration module, Phase phase) {
Project project = module.getProject();
SupportedProject project = module.getSupportedProject();
UpdateInformation information = UpdateInformation.of(module.getTrainIteration(), phase);
CommandLine goals = CommandLine.of(goal("versions:set"), goal("versions:commit"));
if (BOM.equals(project)) {
if (BOM.equals(module.getProject())) {
mvn.execute(project, goals.and(arg("newVersion").withValue(information.getReleaseTrainVersion())) //
.and(arg("generateBackupPoms").withValue("false")));
@@ -154,11 +148,12 @@ class MavenBuildSystem implements BuildSystem {
.and(Argument.of("-pl").withValue("bom")));
} else {
mvn.execute(project, goals.and(arg("newVersion").withValue(information.getProjectVersionToSet(project)))
.and(arg("generateBackupPoms").withValue("false")));
mvn.execute(project,
goals.and(arg("newVersion").withValue(information.getProjectVersionToSet(project.getProject())))
.and(arg("generateBackupPoms").withValue("false")));
}
if (BUILD.equals(project)) {
if (BUILD.equals(module.getProject())) {
if (!module.getTrain().usesCalver()) {
mvn.execute(project, goals.and(arg("newVersion").withValue(information.getReleaseTrainVersion())) //
@@ -179,7 +174,7 @@ class MavenBuildSystem implements BuildSystem {
*/
public <M extends ProjectAware> M triggerPreReleaseCheck(M module) {
mvn.execute(module.getProject(), CommandLine.of(Goal.CLEAN, Goal.VALIDATE, profile("pre-release")));
mvn.execute(module.getSupportedProject(), CommandLine.of(Goal.CLEAN, Goal.VALIDATE, profile("pre-release")));
return module;
}
@@ -188,7 +183,7 @@ class MavenBuildSystem implements BuildSystem {
* Perform a {@literal nexus-staging:rc-open} and extract the {@code stagingProfileId} from the results.
*/
@Override
public StagingRepository open() {
public StagingRepository open(Train train) {
Assert.notNull(properties.getMavenCentral(), "Maven Central properties must not be null");
Assert.hasText(properties.getMavenCentral().getStagingProfileId(), "Staging Profile Identifier must not be empty");
@@ -199,7 +194,7 @@ class MavenBuildSystem implements BuildSystem {
arg("openedRepositoryMessageFormat").withValue("'" + REPO_OPENING_TAG + "%s" + REPO_CLOSING_TAG + "'"))
.andIf(!ObjectUtils.isEmpty(properties.getSettingsXml()), () -> settingsXml(properties.getSettingsXml()));
MavenRuntime.MavenInvocationResult invocationResult = mvn.execute(BUILD, arguments);
MavenRuntime.MavenInvocationResult invocationResult = mvn.execute(train.getSupportedProject(BUILD), arguments);
List<String> rcOpenLogContents = invocationResult.getLog();
@@ -220,7 +215,7 @@ class MavenBuildSystem implements BuildSystem {
* Perform a {@literal nexus-staging:rc-close}.
*/
@Override
public void close(StagingRepository stagingRepository) {
public void close(Train train, StagingRepository stagingRepository) {
Assert.notNull(stagingRepository, "StagingRepository must not be null");
Assert.isTrue(stagingRepository.isPresent(), "StagingRepository must be present");
@@ -230,7 +225,7 @@ class MavenBuildSystem implements BuildSystem {
arg("stagingRepositoryId").withValue(stagingRepository.getId()))
.andIf(!ObjectUtils.isEmpty(properties.getSettingsXml()), () -> settingsXml(properties.getSettingsXml()));
mvn.execute(BUILD, arguments);
mvn.execute(train.getSupportedProject(BUILD), arguments);
}
/*
@@ -241,10 +236,10 @@ class MavenBuildSystem implements BuildSystem {
public <M extends ProjectAware> M triggerBuild(M module) {
CommandLine arguments = CommandLine.of(Goal.CLEAN, Goal.INSTALL)//
.and(profile("ci,release")).andIf(module.getProject().skipTests(), SKIP_TESTS)
.and(profile("ci,release")).andIf(module.getSupportedProject().getProject().skipTests(), SKIP_TESTS)
.andIf(!ObjectUtils.isEmpty(properties.getSettingsXml()), settingsXml(properties.getSettingsXml()));
mvn.execute(module.getProject(), arguments);
mvn.execute(module.getSupportedProject(), arguments);
return module;
}
@@ -299,24 +294,31 @@ class MavenBuildSystem implements BuildSystem {
Assert.notNull(module, "Module iteration must not be null!");
Assert.notNull(information, "Deployment information must not be null!");
if (!module.getIteration().isPreview()) {
logger.log(module, "Not a preview version (milestone or release candidate). Skipping Artifactory deployment.");
boolean isCommercialRelease = module.isCommercial();
if (!module.getIteration().isPreview() && !isCommercialRelease) {
logger.log(module,
"Not a preview version (milestone or release candidate) or commercial release. Skipping Artifactory deployment.");
return;
}
logger.log(module, "Deploying artifacts to Spring Artifactory…");
logger.log(module,
String.format("Deploying artifacts to Spring %sArtifactory…", isCommercialRelease ? "Commercial " : ""));
Authentication authentication = properties.getAuthentication(module);
CommandLine arguments = CommandLine.of(Goal.CLEAN, Goal.DEPLOY, //
profile("ci,release,artifactory"), //
SKIP_TESTS, //
arg("artifactory.server").withValue(properties.getServer().getUri()),
arg("artifactory.staging-repository").withValue(properties.getStagingRepository()),
arg("artifactory.username").withValue(properties.getUsername()),
arg("artifactory.password").withValue(properties.getPassword()),
arg("artifactory.server").withValue(authentication.getServer().getUri()),
arg("artifactory.staging-repository").withValue(authentication.getStagingRepository()),
arg("artifactory.username").withValue(authentication.getUsername()),
arg("artifactory.password").withValue(authentication.getPassword()),
arg("artifactory.build-name").withQuotedValue(information.getBuildName()),
arg("artifactory.build-number").withValue(information.getBuildNumber()));
arg("artifactory.build-number").withValue(information.getBuildNumber()),
arg("artifactory.project").withValue(information.getProject()));
mvn.execute(module.getProject(), arguments);
mvn.execute(module.getSupportedProject(), arguments);
}
/**
@@ -331,9 +333,8 @@ class MavenBuildSystem implements BuildSystem {
Assert.notNull(module, "Module iteration must not be null!");
Assert.notNull(deploymentInformation, "DeploymentInformation iteration must not be null!");
if (!module.getIteration().isPublic()) {
logger.log(module, "Skipping deployment to Maven Central as it's not a public version!");
if (!module.isPublic()) {
logger.log(module, "Skipping deployment to Maven Central as it's not a public version or a commercial release!");
return;
}
@@ -352,7 +353,7 @@ class MavenBuildSystem implements BuildSystem {
() -> arg("stagingRepositoryId").withValue(deploymentInformation.getStagingRepositoryId()))
.andIf(gpg.hasSecretKeyring(), () -> arg("gpg.secretKeyring").withValue(gpg.getSecretKeyring()));
mvn.execute(module.getProject(), arguments);
mvn.execute(module.getSupportedProject(), arguments);
}
@Override
@@ -363,12 +364,13 @@ class MavenBuildSystem implements BuildSystem {
logger.log(iteration, "🚬 Running smoke test…");
boolean mavenCentral = iteration.getIteration().isPublic();
boolean mavenCentral = iteration.isPublic();
String profile = mavenCentral ? "maven-central" : "artifactory";
ModuleIteration module = iteration.getModule(BUILD);
doWithProjection(workspace.getFile(POM_XML, SMOKE_TESTS), pom -> {
SupportedProject smokeTests = iteration.getSupportedProject(SMOKE_TESTS);
doWithProjection(workspace.getFile(POM_XML, smokeTests), pom -> {
Version version = module.getVersion();
String targetBootVersion = version.getMajor() == 2 ? "2.7.8" : "3.0.2";
@@ -381,7 +383,7 @@ class MavenBuildSystem implements BuildSystem {
arg("spring-data-bom.version").withValue(iteration.getReleaseTrainNameAndVersion())) //
.andIf(mavenCentral, arg("stagingRepository").withValue(stagingRepository.getId()));
mvn.execute(SMOKE_TESTS, arguments);
mvn.execute(smokeTests, arguments);
logger.log(iteration, "✅ Smoke tests passed. Do not smoke 🚭. It's unhealthy.");
}
@@ -390,7 +392,7 @@ class MavenBuildSystem implements BuildSystem {
* Perform a {@literal nexus-staging:rc-release}.
*/
@Override
public void release(StagingRepository stagingRepository) {
public void release(Train train, StagingRepository stagingRepository) {
Assert.notNull(stagingRepository, "StagingRepository must not be null");
Assert.isTrue(stagingRepository.isPresent(), "StagingRepository must be present");
@@ -400,17 +402,17 @@ class MavenBuildSystem implements BuildSystem {
arg("stagingRepositoryId").withValue(stagingRepository.getId()))
.andIf(!ObjectUtils.isEmpty(properties.getSettingsXml()), () -> settingsXml(properties.getSettingsXml()));
mvn.execute(BUILD, arguments);
mvn.execute(train.getSupportedProject(BUILD), arguments);
}
@Override
public <M extends ProjectAware> M triggerDocumentationBuild(M module) {
Project project = module.getProject();
SupportedProject project = module.getSupportedProject();
mvn.execute(project, CommandLine.of(Goal.CLEAN, Goal.INSTALL, SKIP_TESTS, profile("distribute")));
logger.log(project, "Successfully finished documentation build.");
return module;
}
@@ -431,33 +433,38 @@ class MavenBuildSystem implements BuildSystem {
return module;
}
if (!isMavenProject(project)) {
SupportedProject supportedProject = module.getSupportedProject();
if (!isMavenProject(supportedProject)) {
logger.log(project, "Skipping project as no pom.xml could be found in the working directory!");
return module;
}
logger.log(project, "Triggering distribution build…");
mvn.execute(project, CommandLine.of(Goal.CLEAN, Goal.DEPLOY, //
SKIP_TESTS, profile("distribute"), Argument.of("-B"),
arg("artifactory.server").withValue(properties.getServer().getUri()),
arg("artifactory.distribution-repository").withValue(properties.getDistributionRepository()),
arg("artifactory.username").withValue(properties.getUsername()),
arg("artifactory.password").withValue(properties.getPassword())));
Authentication authentication = properties.getAuthentication(module);
mvn.execute(project, CommandLine.of(Goal.CLEAN, Goal.DEPLOY, //
mvn.execute(supportedProject, CommandLine.of(Goal.CLEAN, Goal.DEPLOY, //
SKIP_TESTS, profile("distribute"), Argument.of("-B"),
arg("artifactory.server").withValue(authentication.getServer().getUri()),
arg("artifactory.distribution-repository").withValue(authentication.getDistributionRepository()),
arg("artifactory.username").withValue(authentication.getUsername()),
arg("artifactory.password").withValue(authentication.getPassword())));
mvn.execute(supportedProject, CommandLine.of(Goal.CLEAN, Goal.DEPLOY, //
SKIP_TESTS, profile("distribute-schema"), Argument.of("-B"),
arg("artifactory.server").withValue(properties.getServer().getUri()),
arg("artifactory.distribution-repository").withValue(properties.getDistributionRepository()),
arg("artifactory.username").withValue(properties.getUsername()),
arg("artifactory.password").withValue(properties.getPassword())));
arg("artifactory.server").withValue(authentication.getServer().getUri()),
arg("artifactory.distribution-repository").withValue(authentication.getDistributionRepository()),
arg("artifactory.username").withValue(authentication.getUsername()),
arg("artifactory.password").withValue(authentication.getPassword())));
logger.log(project, "Successfully finished distribution build!");
return module;
}
private void updateBom(PomUpdater updater, UpdateInformation updateInformation, String file, Project project) {
private void updateBom(PomUpdater updater, UpdateInformation updateInformation, String file,
SupportedProject project) {
TrainIteration iteration = updateInformation.getTrain();
@@ -506,23 +513,22 @@ class MavenBuildSystem implements BuildSystem {
private void updateParentPom(PomUpdater updater, UpdateInformation information) {
// Fix version of shared resources to to-be-released version.
doWithProjection(workspace.getFile("parent/pom.xml", BUILD), ParentPom.class, pom -> {
doWithProjection(workspace.getFile("parent/pom.xml", information.getSupportedProject(BUILD)), ParentPom.class,
pom -> {
logger.log(BUILD, "Setting shared resources version to %s.", information.getParentVersionToSet());
pom.setSharedResourcesVersion(information.getParentVersionToSet());
logger.log(BUILD, "Setting shared resources version to %s.", information.getParentVersionToSet());
pom.setSharedResourcesVersion(information.getParentVersionToSet());
logger.log(BUILD, "Setting releasetrain property to %s.", information.getReleaseTrainVersion());
pom.setReleaseTrain(information.getReleaseTrainVersion());
logger.log(BUILD, "Setting releasetrain property to %s.", information.getReleaseTrainVersion());
pom.setReleaseTrain(information.getReleaseTrainVersion());
updater.updateRepository(pom);
});
updater.updateRepository(pom);
});
}
public boolean isMavenProject(ModuleIteration module) {
Project project = module.getProject();
if (!isMavenProject(project)) {
if (!isMavenProject(module.getSupportedProject())) {
logger.log(module, "No pom.xml file found, skipping project.");
return false;
}
@@ -535,7 +541,7 @@ class MavenBuildSystem implements BuildSystem {
* @see org.springframework.data.release.build.BuildSystem#verify()
*/
@Override
public void verify() {
public void verify(Train train) {
logger.log(BUILD, "Verifying Maven Build System…");
@@ -549,21 +555,26 @@ class MavenBuildSystem implements BuildSystem {
arg("gpg.passphrase").withValue(gpg.getPassphrase())) //
.andIf(gpg.hasSecretKeyring(), () -> arg("gpg.secretKeyring").withValue(gpg.getSecretKeyring()));
mvn.execute(BUILD, arguments);
mvn.execute(train.getSupportedProject(BUILD), arguments);
}
@Override
public void verifyStagingAuthentication() {
public void verifyStagingAuthentication(Train train) {
logger.log(BUILD, "Verifying Maven Staging Authentication…");
if (train.isOpenSource()) {
mvn.execute(BUILD, CommandLine.of(goal("nexus-staging:rc-list-profiles"), //
profile("central")));
logger.log(BUILD, "Verifying Maven Staging Authentication…");
Assert.notNull(properties.getMavenCentral(),
"Maven Central properties are not set (deployment.maven-central.staging-profile-id=…)");
Assert.hasText(properties.getMavenCentral().getStagingProfileId(),
"Staging Profile Id is not set (deployment.maven-central.staging-profile-id=…)");
mvn.execute(train.getSupportedProject(BUILD), //
CommandLine.of(goal("nexus-staging:rc-list-profiles"), //
profile("central")));
Assert.notNull(properties.getMavenCentral(),
"Maven Central properties are not set (deployment.maven-central.staging-profile-id=…)");
Assert.hasText(properties.getMavenCentral().getStagingProfileId(),
"Staging Profile Id is not set (deployment.maven-central.staging-profile-id=…)");
return;
}
}
/*
@@ -571,11 +582,11 @@ class MavenBuildSystem implements BuildSystem {
* @see org.springframework.plugin.core.Plugin#supports(java.lang.Object)
*/
@Override
public boolean supports(Project project) {
public boolean supports(SupportedProject project) {
return isMavenProject(project);
}
private boolean isMavenProject(Project project) {
private boolean isMavenProject(SupportedProject project) {
return workspace.getFile(POM_XML, project).exists();
}

View File

@@ -50,7 +50,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.release.io.JavaRuntimes;
import org.springframework.data.release.io.Workspace;
import org.springframework.data.release.model.JavaVersion;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.Named;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.utils.Logger;
import org.springframework.lang.Nullable;
import org.springframework.shell.support.util.StringUtils;
@@ -155,8 +156,7 @@ public class MavenRuntime {
return matcher.group(1);
}
public MavenInvocationResult execute(Project project, CommandLine arguments) {
public MavenInvocationResult execute(SupportedProject project, CommandLine arguments) {
logger.log(project, "📦 Executing mvn %s", arguments.toString());
@@ -173,7 +173,8 @@ public class MavenRuntime {
mavenLogger.info(String.format("Java Home: %s", jdk));
mavenLogger.info(String.format("Executing: mvn %s", arguments));
CommandLine disabledGradleBuildCache = arguments.and(arg("gradle.cache.local.enabled=false")).and(arg("gradle.cache.remote.enabled=false"));
CommandLine disabledGradleBuildCache = arguments.and(arg("gradle.cache.local.enabled=false"))
.and(arg("gradle.cache.remote.enabled=false"));
mvn.setGoals(disabledGradleBuildCache.toCommandLine(it -> properties.getFullyQualifiedPlugin(it.getGoal())));
});
@@ -221,7 +222,7 @@ public class MavenRuntime {
return jdk.getHome().getAbsoluteFile();
}
private MavenLogger getLogger(Project project, List<CommandLine.Goal> goals) {
private MavenLogger getLogger(Named project, List<CommandLine.Goal> goals) {
if (this.properties.isConsoleLogger()) {
return new SlfLogger(log, project);
@@ -258,7 +259,7 @@ public class MavenRuntime {
private final String logPrefix;
private final List<String> contents;
SlfLogger(org.slf4j.Logger logger, Project project) {
SlfLogger(org.slf4j.Logger logger, Named project) {
this.logger = logger;
this.logPrefix = StringUtils.padRight(project.getName(), 10);
this.contents = new ArrayList<>();
@@ -295,7 +296,7 @@ public class MavenRuntime {
private final FileOutputStream outputStream;
private final List<String> contents = new ArrayList<>();
FileLogger(org.slf4j.Logger logger, Project project, File logsDirectory, List<CommandLine.Goal> goals) {
FileLogger(org.slf4j.Logger logger, Named project, File logsDirectory, List<CommandLine.Goal> goals) {
if (!logsDirectory.exists()) {
logsDirectory.mkdirs();

View File

@@ -24,7 +24,7 @@ import java.util.List;
import org.springframework.data.release.build.Pom.RepositoryElementFactory;
import org.springframework.data.release.model.ArtifactVersion;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.utils.Logger;
import org.springframework.util.Assert;
@@ -37,26 +37,26 @@ class PomUpdater {
private final Logger logger;
private final UpdateInformation information;
private final @Getter Project project;
private final @Getter SupportedProject project;
public boolean isBuildProject() {
return BUILD.equals(project);
return BUILD.equals(project.getProject());
}
public boolean isBomProject() {
return BOM.equals(project);
return BOM.equals(project.getProject());
}
public void updateArtifactVersion(Pom pom) {
ArtifactVersion version = information.getProjectVersionToSet(project);
ArtifactVersion version = information.getProjectVersionToSet(project.getProject());
logger.log(project, "Updated project version to %s.", version);
pom.setVersion(version);
}
public void updateDependencyProperties(Pom pom) {
project.getDependencies().forEach(dependency -> {
project.getProject().getDependencies().forEach(dependency -> {
String dependencyProperty = dependency.getDependencyProperty();

View File

@@ -27,9 +27,12 @@ public class Repository {
static Repository SNAPSHOT = new Repository("spring-snapshot", "https://repo.spring.io/snapshot", true, false);
static Repository MILESTONE = new Repository("spring-milestone", "https://repo.spring.io/milestone", null, null);
static Repository COMMERCIAL_SNAPSHOT = new Repository("spring-commercial-snapshot",
"https://repo.spring.vmware.com/artifactory/spring-commercial-snapshot-local", true, false);
static Repository COMMERCIAL_RELEASE = new Repository("spring-commercial-release",
"https://repo.spring.vmware.com/artifactory/spring-commercial", false, true);
String id, url;
Boolean snapshots;
Boolean releases;
}

View File

@@ -29,6 +29,7 @@ import org.springframework.data.release.model.ArtifactVersion;
import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.Phase;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.util.Assert;
@@ -93,16 +94,20 @@ public class UpdateInformation {
if (phase == Phase.PREPARE) {
Iteration iteration = train.getIteration();
if (iteration.isMilestone() || iteration.isReleaseCandidate()) {
return Collections.singletonList(Repository.MILESTONE);
}
}
if (phase == Phase.CLEANUP || phase == Phase.MAINTENANCE) {
return Arrays.asList(Repository.SNAPSHOT, Repository.MILESTONE);
return train.isCommercial()
? Arrays.asList(Repository.COMMERCIAL_SNAPSHOT, Repository.COMMERCIAL_RELEASE)
: Arrays.asList(Repository.SNAPSHOT, Repository.MILESTONE);
}
return Collections.emptyList();
return train.isCommercial() ? Arrays.asList(Repository.COMMERCIAL_RELEASE) : Collections.emptyList();
}
/**
@@ -142,4 +147,8 @@ public class UpdateInformation {
public boolean isBomInBuildProject() {
return !train.getTrain().usesCalver();
}
public SupportedProject getSupportedProject(Project project) {
return train.getSupportedProject(project);
}
}

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.release.cli;
import static org.springframework.data.release.model.Projects.*;
import lombok.AccessLevel;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@@ -36,13 +34,10 @@ import org.springframework.data.release.git.GitOperations;
import org.springframework.data.release.issues.IssueTrackerCommands;
import org.springframework.data.release.issues.github.GitHubCommands;
import org.springframework.data.release.misc.ReleaseOperations;
import org.springframework.data.release.model.ArtifactVersion;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Phase;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.ReleaseTrains;
import org.springframework.data.release.model.Train;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
@@ -64,14 +59,6 @@ class ReleaseCommands extends TimedCommand {
@NonNull IssueTrackerCommands tracker;
@NonNull GitHubCommands gitHub;
@CliCommand("release predict")
public String predictTrainAndIteration() {
return git.getTags(COMMONS).getLatest().toArtifactVersion().//
map(ReleaseCommands::getTrainNameForCommonsVersion).//
orElse(null);
}
/**
* Composite command to prepare a release.
*
@@ -140,7 +127,7 @@ class ReleaseCommands extends TimedCommand {
@CliCommand(value = "repository open")
public void repositoryOpen(@CliOption(key = "", mandatory = true) TrainIteration iteration) {
if (iteration.getIteration().isPublic()) {
if (iteration.isPublic()) {
build.open(iteration.getModule(Projects.BUILD));
}
}
@@ -149,7 +136,7 @@ class ReleaseCommands extends TimedCommand {
public void repositoryClose(@CliOption(key = "", mandatory = true) TrainIteration iteration,
@CliOption(key = "stagingRepositoryId", mandatory = true) String stagingRepositoryId) {
if (iteration.getIteration().isPublic()) {
if (iteration.isPublic()) {
build.close(iteration.getModule(Projects.BUILD), StagingRepository.of(stagingRepositoryId));
}
}
@@ -158,7 +145,7 @@ class ReleaseCommands extends TimedCommand {
public void repositoryRelease(@CliOption(key = "", mandatory = true) TrainIteration iteration,
@CliOption(key = "stagingRepositoryId", mandatory = true) String stagingRepositoryId) {
if (iteration.getIteration().isPublic()) {
if (iteration.isPublic()) {
build.release(iteration.getModule(Projects.BUILD), StagingRepository.of(stagingRepositoryId));
}
}
@@ -169,8 +156,8 @@ class ReleaseCommands extends TimedCommand {
git.checkout(iteration);
if (!iteration.getIteration().isPublic()) {
deployment.verifyAuthentication();
if (!iteration.isPublic()) {
deployment.verifyAuthentication(iteration);
}
if (projectName != null) {
@@ -293,11 +280,4 @@ class ReleaseCommands extends TimedCommand {
build.distributeResources(iteration);
}
}
private static String getTrainNameForCommonsVersion(ArtifactVersion version) {
return ReleaseTrains.TRAINS.stream().//
filter(train -> version.toString().startsWith(train.getModule(COMMONS).getVersion().toString())).//
findFirst().map(Train::getName).orElse(null);
}
}

View File

@@ -23,7 +23,6 @@ import org.springframework.data.release.git.VersionTags;
import org.springframework.data.release.model.ArtifactVersion;
import org.springframework.data.release.model.DocumentationMetadata;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Project;
/**
* @author Oliver Gierke
@@ -40,8 +39,7 @@ public class StaticResources {
this.metadata = DocumentationMetadata.of(module, ArtifactVersion.of(module), false);
Project project = module.getProject();
GitProject gitProject = GitProject.of(project);
GitProject gitProject = GitProject.of(module);
Tag tag = VersionTags.empty(module.getProject()).createTag(module);
this.releaseUrl = String.format("%s/releases/tag/%s", gitProject.getProjectUri(), tag.getName());

View File

@@ -26,6 +26,7 @@ import org.springframework.data.release.build.BuildOperations;
import org.springframework.data.release.deployment.DeploymentOperations;
import org.springframework.data.release.git.GitOperations;
import org.springframework.data.release.issues.github.GitHub;
import org.springframework.data.release.model.Train;
import org.springframework.data.release.projectservice.ProjectService;
import org.springframework.data.release.utils.Logger;
import org.springframework.shell.core.annotation.CliCommand;
@@ -50,18 +51,20 @@ class VerifyCommands extends TimedCommand {
@NonNull Logger logger;
@CliCommand("verify")
public void verifyReleaseTools(@CliOption(key = "", mandatory = false) String mode) {
public void verifyReleaseTools(
@CliOption(key = "", mandatory = false) String mode,
@CliOption(key = "train", mandatory = true) Train train) {
if ("local".equals(mode)) {
// Git checkout build
git.verify();
git.verify(train);
// Maven interaction
build.verify();
build.verify(train);
// GitHub verification
github.verifyAuthentication();
github.verifyAuthentication(train);
// Projects Service Verification
projectService.verifyAuthentication();
@@ -72,23 +75,23 @@ class VerifyCommands extends TimedCommand {
if (ObjectUtils.isEmpty(mode) || "git".equals(mode)) {
// Git checkout build
git.verify();
git.verify(train);
}
if (ObjectUtils.isEmpty(mode) || "build".equals(mode)) {
// Maven interaction
build.verify();
build.verifyStagingAuthentication();
build.verify(train);
build.verifyStagingAuthentication(train);
}
if (ObjectUtils.isEmpty(mode) || "deployment".equals(mode)) {
// Artifactory verification
deployment.verifyAuthentication();
deployment.verifyAuthentication(train);
}
if (ObjectUtils.isEmpty(mode) || "github".equals(mode)) {
// GitHub verification
github.verifyAuthentication();
github.verifyAuthentication(train);
}
if (ObjectUtils.isEmpty(mode) || "projects".equals(mode)) {
@@ -98,5 +101,4 @@ class VerifyCommands extends TimedCommand {
logger.log("Verify", "All settings are verified. You can ship a release now.");
}
}

View File

@@ -22,7 +22,9 @@ import java.io.IOException;
import java.net.URI;
import java.util.function.Consumer;
import org.springframework.data.release.deployment.DeploymentProperties.Authentication;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.SupportStatusAware;
import org.springframework.data.release.utils.Logger;
import org.springframework.util.Assert;
import org.springframework.web.client.HttpClientErrorException;
@@ -39,9 +41,9 @@ import com.fasterxml.jackson.databind.ObjectMapper;
@RequiredArgsConstructor
class ArtifactoryClient {
private final RestOperations template;
private final Logger logger;
private final DeploymentProperties properties;
private final RestOperations operations;
/**
* Triggers the promotion of the artifacts identified by the given {@link DeploymentInformation}.
@@ -53,28 +55,35 @@ class ArtifactoryClient {
Assert.notNull(information, "DeploymentInformation must not be null!");
ModuleIteration module = information.getModule();
URI uri = properties.getServer().getPromotionResource(information);
URI uri = information.getPromotionResource();
Authentication authentication = properties.getAuthentication(module);
logger.log(module, "Promoting %s %s from %s to %s.", information.getBuildName(), information.getBuildNumber(),
properties.getStagingRepository(), information.getTargetRepository());
authentication.getStagingRepository(), authentication.getTargetRepository());
try {
template.postForEntity(uri,
new PromotionRequest(information.getTargetRepository(), properties.getStagingRepository()), String.class);
PromotionRequest request = new PromotionRequest(information.getTargetRepository(),
authentication.getStagingRepository());
operations.postForEntity(uri, request, String.class);
} catch (HttpClientErrorException o_O) {
handle(message -> logger.warn(information.getModule(), message), "Promotion failed!", o_O);
}
}
public void verify() {
public void verify(SupportStatusAware status) {
URI verificationResource = properties.getServer().getVerificationResource();
URI verificationResource = properties
.getAuthentication(status)
.getServer()
.getVerificationResource();
try {
logger.log("Artifactory", "Verifying authentication using a GET call to %s.", verificationResource);
template.getForEntity(verificationResource, String.class);
operations.getForEntity(verificationResource, String.class);
logger.log("Artifactory", "Authentication verified!");
@@ -101,7 +110,8 @@ class ArtifactoryClient {
}
public void deleteArtifacts(DeploymentInformation information) {
template.delete(properties.getServer().getDeleteBuildResource(information));
operations.delete(information.getDeleteBuildResource());
}
@Value

View File

@@ -18,8 +18,11 @@ package org.springframework.data.release.deployment;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import java.util.stream.Stream;
import org.springframework.data.release.CliComponent;
import org.springframework.data.release.TimedCommand;
import org.springframework.data.release.model.SupportStatus;
import org.springframework.shell.core.annotation.CliCommand;
/**
@@ -35,6 +38,8 @@ class ArtifactoryCommands extends TimedCommand {
@CliCommand(value = "artifactory verify", help = "Verifies authentication at Artifactory.")
public void verify() {
deployment.verifyAuthentication();
Stream.of(SupportStatus.OSS, SupportStatus.COMMERCIAL)
.forEach(deployment::verifyAuthentication);
}
}

View File

@@ -20,11 +20,13 @@ import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import java.net.URI;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.Map;
import org.springframework.data.release.deployment.DeploymentProperties.Authentication;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.web.util.UriTemplate;
@@ -44,6 +46,8 @@ public class DefaultDeploymentInformation implements DeploymentInformation {
private final @Getter String buildNumber;
private final @Getter StagingRepository stagingRepositoryId;
private final Authentication authentication;
public DefaultDeploymentInformation(ModuleIteration module, DeploymentProperties properties) {
this(module, properties, StagingRepository.EMPTY);
}
@@ -51,17 +55,18 @@ public class DefaultDeploymentInformation implements DeploymentInformation {
public DefaultDeploymentInformation(ModuleIteration module, DeploymentProperties properties,
String stagingRepositoryId) {
this(module, properties, String.valueOf(LocalDateTime.now().toEpochSecond(ZoneOffset.UTC)),
StagingRepository.of(stagingRepositoryId));
StagingRepository.of(stagingRepositoryId), properties.getAuthentication(module));
}
public DefaultDeploymentInformation(ModuleIteration module, DeploymentProperties properties,
StagingRepository stagingRepository) {
this(module, properties, String.valueOf(LocalDateTime.now().toEpochSecond(ZoneOffset.UTC)), stagingRepository);
this(module, properties, String.valueOf(LocalDateTime.now().toEpochSecond(ZoneOffset.UTC)), stagingRepository,
properties.getAuthentication(module));
}
@Override
public DeploymentInformation withModule(ModuleIteration module) {
return new DefaultDeploymentInformation(module, properties, buildNumber, stagingRepositoryId);
return new DefaultDeploymentInformation(module, properties, buildNumber, stagingRepositoryId, authentication);
}
/*
@@ -73,14 +78,22 @@ public class DefaultDeploymentInformation implements DeploymentInformation {
return module.getProject().getFullName().concat(" - Release");
}
/*
* (non-Javadoc)
* @see org.springframework.data.release.deployment.DeploymentInformation#getProject()
*/
@Override
public String getProject() {
return authentication.getProject();
}
/*
* (non-Javadoc)
* @see org.springframework.data.release.deployment.DeploymentInformation#getTargetRepository()
*/
@Override
public String getTargetRepository() {
return properties.getRepositoryPrefix()
.concat(module.getIteration().isPublic() ? "libs-release-local" : "libs-milestone-local");
return authentication.getRepositoryPrefix().concat(authentication.getTargetRepository());
}
/*
@@ -91,7 +104,7 @@ public class DefaultDeploymentInformation implements DeploymentInformation {
public String getDeploymentTargetUrl() {
Map<String, Object> parameters = new HashMap<>();
parameters.put("server", properties.getStagingRepositoryUrl());
parameters.put("server", authentication.getTargetRepository());
parameters.putAll(getBuildInfoParameters());
return REPOSITORY_TEMPLATE.expand(parameters).toString();
@@ -110,4 +123,33 @@ public class DefaultDeploymentInformation implements DeploymentInformation {
return parameters;
}
/*
* (non-Javadoc)
* @see org.springframework.data.release.deployment.DeploymentInformation#getPromotionResource()
*/
@Override
public URI getPromotionResource() {
return authentication.getServer().getPromotionResource(this);
}
/*
* (non-Javadoc)
* @see org.springframework.data.release.deployment.DeploymentInformation#getDeleteBuildResource()
*/
@Override
public URI getDeleteBuildResource() {
return authentication.getServer().getDeleteBuildResource(this);
}
/*
* (non-Javadoc)
* @see org.springframework.data.release.deployment.DeploymentInformation#isMavenCentral()
*/
@Override
public boolean isMavenCentral() {
return !module.isCommercial()
&& module.getIteration().isPublic();
}
}

View File

@@ -18,11 +18,12 @@ package org.springframework.data.release.deployment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.release.deployment.DeploymentProperties.Authentication;
import org.springframework.data.release.model.Password;
import org.springframework.data.release.utils.HttpBasicCredentials;
import org.springframework.data.release.utils.HttpComponentsClientHttpRequestFactoryBuilder;
import org.springframework.data.release.utils.Logger;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;
/**
@@ -36,23 +37,30 @@ class DeploymentConfiguration {
@Autowired DeploymentProperties properties;
@Bean
public ArtifactoryClient client(Logger logger, RestTemplate artifactoryRestTemplate) {
return new ArtifactoryClient(artifactoryRestTemplate, logger, properties);
ArtifactoryClient client(Logger logger, RestOperations operations) {
return new ArtifactoryClient(logger, properties, operations);
}
@Bean
public RestTemplate artifactoryRestTemplate() {
RestTemplate artifactoryRestTemplateFactory(DeploymentProperties properties, Logger logger) {
RestTemplate template = new RestTemplate();
HttpComponentsClientHttpRequestFactoryBuilder builder = HttpComponentsClientHttpRequestFactoryBuilder.builder();
HttpComponentsClientHttpRequestFactory factory = HttpComponentsClientHttpRequestFactoryBuilder.builder()
.withAuthentication(properties.getServer().getUri(),
new HttpBasicCredentials(properties.getUsername(), Password.of(properties.getApiKey())))
.build();
for (Authentication authentication : properties.getAuthentications()) {
template.setRequestFactory(factory);
String uri = authentication.getServer().getUri();
return template;
if (authentication.hasCredentials()) {
HttpBasicCredentials credentials = new HttpBasicCredentials(authentication.getUsername(),
Password.of(authentication.getApiKey()));
builder = builder.withAuthentication(uri, credentials);
} else {
logger.warn("Infrastructure", "No credentials configured for repository %s!", uri);
}
}
return new RestTemplate(builder.build());
}
}

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.release.deployment;
import java.net.URI;
import java.util.Map;
import org.springframework.data.release.model.ModuleIteration;
@@ -39,6 +40,14 @@ public interface DeploymentInformation {
*/
String getBuildNumber();
/**
* A project assignment on the server. JFrog uses this to group different builds into build info repositories in
* Artifactory.
*
* @return
*/
String getProject();
/**
* Returns the full URL to be used as deployment target.
*
@@ -53,6 +62,10 @@ public interface DeploymentInformation {
*/
String getTargetRepository();
URI getPromotionResource();
URI getDeleteBuildResource();
/**
* Staging repository identifier.
*
@@ -75,4 +88,6 @@ public interface DeploymentInformation {
Map<String, Object> getBuildInfoParameters();
DeploymentInformation withModule(ModuleIteration module);
boolean isMavenCentral();
}

View File

@@ -17,6 +17,7 @@ package org.springframework.data.release.deployment;
import lombok.RequiredArgsConstructor;
import org.springframework.data.release.model.SupportStatusAware;
import org.springframework.data.release.utils.Logger;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@@ -34,8 +35,8 @@ public class DeploymentOperations {
private final ArtifactoryClient client;
private final Logger logger;
public void verifyAuthentication() {
client.verify();
public void verifyAuthentication(SupportStatusAware status) {
client.verify(status);
}
/**
@@ -47,7 +48,7 @@ public class DeploymentOperations {
Assert.notNull(information, "DeploymentInformation must not be null!");
if (information.getModule().getIteration().isPublic()) {
if (information.isMavenCentral()) {
logger.log(information.getModule(),
"Skipping build promotion as it's a public version and was staged to OSS Sonatype.");
return;

View File

@@ -15,18 +15,20 @@
*/
package org.springframework.data.release.deployment;
import lombok.Data;
import java.net.URI;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.data.release.model.Gpg;
import org.springframework.data.release.model.Password;
import org.springframework.data.release.utils.HttpBasicCredentials;
import org.springframework.data.release.model.SupportStatusAware;
import org.springframework.data.util.Streamable;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriTemplate;
import lombok.Data;
/**
* @author Oliver Gierke
* @author Mark Paluch
@@ -36,54 +38,16 @@ import lombok.Data;
@ConfigurationProperties(prefix = "deployment")
public class DeploymentProperties {
/**
* The Artifactory host.
*/
private Server server;
/**
* The deployer's username.
*/
private String username;
private String apiKey;
/**
* The deployer's password.
*/
private Password password;
/**
* The repository to deploy the artifacts to.
*/
private String stagingRepository;
/**
* The repository to deploy docs/schemas to.
*/
private String distributionRepository;
private String settingsXml;
private String repositoryPrefix = "";
private MavenCentral mavenCentral;
private Authentication opensource, commercial;
public String getStagingRepository() {
return repositoryPrefix.concat(stagingRepository);
public Authentication getAuthentication(SupportStatusAware status) {
return status.isOpenSource() ? opensource : commercial;
}
public String getDistributionRepository() {
return repositoryPrefix.concat(distributionRepository);
}
/**
* Returns the URI of the staging repository.
*
* @return
*/
public String getStagingRepositoryUrl() {
return server.getUri().concat("/").concat(stagingRepository);
public Streamable<Authentication> getAuthentications() {
return Streamable.of(opensource, commercial);
}
@Data
@@ -91,9 +55,10 @@ public class DeploymentProperties {
private static final String PROMOTION_RESOURCE = "/api/build/promote/{buildName}/{buildNumber}";
private static final String DELETE_BUILD_RESOURCE = "/api/build/{buildName}?buildNumbers={buildNumber}&artifacts=1";
private static final String VERIFICATION_RESOURCE = "/api/storage/temp-private-local";
private static final String VERIFICATION_RESOURCE = "/api/storage/{verificationResource}";
private String uri;
private String verificationResource;
/**
* Returns the URI to the resource that a promotion can be triggered at.
@@ -114,7 +79,7 @@ public class DeploymentProperties {
}
public URI getVerificationResource() {
return URI.create(uri.concat(VERIFICATION_RESOURCE));
return new UriTemplate(uri.concat(VERIFICATION_RESOURCE)).expand(verificationResource);
}
}
@@ -130,4 +95,37 @@ public class DeploymentProperties {
}
}
@Data
public static class Authentication {
Server server;
String stagingRepository, targetRepository;
String distributionRepository;
String project;
String username;
Password password;
String apiKey;
String repositoryPrefix = "";
public boolean hasCredentials() {
return StringUtils.hasText(username) && password != null;
}
/**
* Returns the URI of the staging repository.
*
* @return
*/
public String getStagingRepositoryUrl() {
return server.getUri().concat("/").concat(stagingRepository);
}
public String getStagingRepository() {
return repositoryPrefix.concat(stagingRepository);
}
public String getDistributionRepository() {
return repositoryPrefix.concat(distributionRepository);
}
}
}

View File

@@ -100,7 +100,7 @@ public class DocumentationCommands extends TimedCommand {
if (preview) {
buildOperations.buildDocumentation(module);
File projectDirectory = workspace.getProjectDirectory(module.getProject());
File projectDirectory = workspace.getProjectDirectory(module.getSupportedProject());
if (!projectDirectory.exists()) {
logger.warn(module, "Unable to locate project directory");
@@ -171,9 +171,9 @@ public class DocumentationCommands extends TimedCommand {
HttpStatus status = checkedLink.getResult();
if (status.is2xxSuccessful()) {
ansi.fg(Color.GREEN);
} else if (status.is4xxClientError())
} else if (status.is4xxClientError()) {
ansi.fg(Color.RED);
else if (status.is3xxRedirection()) {
} else if (status.is3xxRedirection()) {
ansi.fg(Color.YELLOW);
}

View File

@@ -45,7 +45,8 @@ class BackportTargets implements Iterable<Branch> {
this.source = Branch.from(module);
Stream<Branch> branches = targets.stream().map(target -> target.getModuleIfAvailable(module.getProject()))//
Stream<Branch> branches = targets.stream() //
.map(target -> target.getModuleIfAvailable(module.getSupportedProject().getProject()))//
.flatMap(o -> o.map(Stream::of).orElse(Stream.empty()))//
.map(Branch::from);

View File

@@ -36,6 +36,7 @@ import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.ReleaseTrains;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.model.Train;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.data.release.utils.ExecutionUtils;
@@ -54,7 +55,7 @@ import org.springframework.util.StringUtils;
@RequiredArgsConstructor
class GitCommands extends TimedCommand {
private final PluginRegistry<IssueTracker, Project> trackers;
private final PluginRegistry<IssueTracker, SupportedProject> trackers;
private final @NonNull GitOperations git;
private final @NonNull Executor executor;
@@ -75,11 +76,13 @@ class GitCommands extends TimedCommand {
}
@CliCommand("git tags")
public String tags(@CliOption(key = { "project" }, mandatory = true) String projectName) throws Exception {
public String tags(
@CliOption(key = { "project" }, mandatory = true) String projectName,
@CliOption(key = { "", "train" }, mandatory = true) Train train) throws Exception {
Project project = ReleaseTrains.getProjectByName(projectName);
return StringUtils.collectionToDelimitedString(git.getTags(project).asList(), "\n");
return StringUtils.collectionToDelimitedString(git.getTags(train.getSupportedProject(project)).asList(), "\n");
}
@CliCommand("git previous")
@@ -96,7 +99,7 @@ class GitCommands extends TimedCommand {
if (StringUtils.hasText(moduleName)) {
ModuleIteration module = iteration.getModule(Projects.requiredByName(moduleName));
List<TicketReference> ticketRefs = git.getTicketReferencesBetween(module.getProject(), previousIteration,
List<TicketReference> ticketRefs = git.getTicketReferencesBetween(module.getSupportedProject(), previousIteration,
iteration);
Changelog changelog = Changelog.of(module, toTickets(module, ticketRefs));
@@ -105,15 +108,16 @@ class GitCommands extends TimedCommand {
}
return ExecutionUtils
.runAndReturn(executor, iteration, module -> changelog(iteration, module.getModule().getProject().getName())) //
.runAndReturn(executor, iteration,
module -> changelog(iteration, module.getModule().getProject().getName())) //
.stream() //
.collect(Collectors.joining("\n"));
}
private Tickets toTickets(ModuleIteration module, List<TicketReference> ticketReferences) {
IssueTracker issueTracker = trackers.getRequiredPluginFor(module.getProject(),
() -> String.format("No issue tracker found for project %s!", module.getProject()));
IssueTracker issueTracker = trackers.getRequiredPluginFor(module.getSupportedProject(),
() -> String.format("No issue tracker found for project %s!", module.getSupportedProject()));
List<String> ticketIds = ticketReferences.stream().map(TicketReference::getId).collect(Collectors.toList());
@@ -174,12 +178,14 @@ class GitCommands extends TimedCommand {
* @throws Exception
*/
@CliCommand("git issuebranches")
public Table issuebranches(@CliOption(key = { "" }, mandatory = true) String projectName,
public Table issuebranches(
@CliOption(key = "", mandatory = true) String projectName,
@CliOption(key = "train", mandatory = true) Train train,
@CliOption(key = "resolved", unspecifiedDefaultValue = "false", specifiedDefaultValue = "true") Boolean resolved)
throws Exception {
Project project = ReleaseTrains.getProjectByName(projectName);
TicketBranches ticketBranches = git.listTicketBranches(project);
TicketBranches ticketBranches = git.listTicketBranches(train.getSupportedProject(project));
Table table = new Table();
table.addHeader(1, new TableHeader("Branch"));

View File

@@ -38,8 +38,10 @@ import org.eclipse.jgit.api.CheckoutCommand;
import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.GitCommand;
import org.eclipse.jgit.api.LogCommand;
import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.eclipse.jgit.api.TransportCommand;
import org.eclipse.jgit.api.errors.EmptyCommitException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
@@ -65,6 +67,7 @@ import org.springframework.data.release.issues.Ticket;
import org.springframework.data.release.issues.TicketReference;
import org.springframework.data.release.issues.TicketStatus;
import org.springframework.data.release.model.*;
import org.springframework.data.release.model.Module;
import org.springframework.data.release.utils.ExecutionUtils;
import org.springframework.data.release.utils.Logger;
import org.springframework.data.util.Pair;
@@ -92,20 +95,10 @@ public class GitOperations {
Executor executor;
Workspace workspace;
Logger logger;
PluginRegistry<IssueTracker, Project> issueTracker;
PluginRegistry<IssueTracker, SupportedProject> issueTracker;
GitProperties gitProperties;
Gpg gpg;
/**
* Returns the {@link GitProject} for the given {@link Project}.
*
* @param project
* @return
*/
public GitProject getGitProject(Project project) {
return new GitProject(project, server);
}
/**
* Resets the repositories for all modules of the given {@link Train}.
*
@@ -116,7 +109,7 @@ public class GitOperations {
Assert.notNull(train, "Train must not be null!");
ExecutionUtils.run(executor, train, module -> {
reset(module.getProject(), Branch.from(module));
reset(module.getSupportedProject(), Branch.from(module));
});
}
@@ -149,9 +142,9 @@ public class GitOperations {
update(train);
}
ExecutionUtils.run(executor, train, module -> {
ExecutionUtils.run(executor, train.getModules(), module -> {
Project project = module.getProject();
SupportedProject project = train.getSupportedProject(module);
doWithGit(project, git -> {
@@ -168,9 +161,9 @@ public class GitOperations {
}
private Branch getBranch(Train train, Module module, Project project) {
private Branch getBranch(Train train, Module module, SupportedProject project) {
ModuleIteration gaIteration = train.getModuleIteration(project, Iteration.GA);
ModuleIteration gaIteration = train.getModuleIteration(project.getProject(), Iteration.GA);
Optional<Tag> gaTag = findTagFor(project, ArtifactVersion.of(gaIteration));
if (!gaTag.isPresent()) {
@@ -180,7 +173,7 @@ public class GitOperations {
return gaTag.isPresent() ? Branch.from(module) : Branch.MAIN;
}
private void checkoutBranch(Project project, Git git, Branch branch) throws GitAPIException {
private void checkoutBranch(SupportedProject project, Git git, Branch branch) throws GitAPIException {
CheckoutCommand command = git.checkout().setName(branch.toString()).setForced(true);
@@ -208,8 +201,9 @@ public class GitOperations {
ExecutionUtils.run(executor, iteration, module -> {
Project project = module.getProject();
SupportedProject project = module.getSupportedProject();
ArtifactVersion artifactVersion = ArtifactVersion.of(module);
Tag tag = findTagFor(project, artifactVersion).orElseThrow(() -> new IllegalStateException(
String.format("No tag found for version %s of project %s, aborting.", artifactVersion, project)));
@@ -227,7 +221,7 @@ public class GitOperations {
ExecutionUtils.run(executor, iteration, module -> {
Project project = module.getProject();
SupportedProject project = module.getSupportedProject();
Branch branch = Branch.from(module);
update(project);
@@ -238,9 +232,8 @@ public class GitOperations {
doWithGit(project, git -> {
logger.log(project, "git pull origin %s", branch);
git.pull()//
.setRebase(true)//
.call();
call(git.pull().setRebase(true));
});
logger.log(project, "Pulling updates done!", branch);
@@ -250,7 +243,7 @@ public class GitOperations {
}
public void update(Train train) {
ExecutionUtils.run(executor, train, module -> update(module.getProject()));
ExecutionUtils.run(executor, train, this::update);
}
public void push(TrainIteration iteration) {
@@ -262,21 +255,21 @@ public class GitOperations {
Branch branch = Branch.from(module);
logger.log(module, "git push origin %s", branch);
if (!branchExists(module.getProject(), branch)) {
SupportedProject project = module.getSupportedProject();
logger.log(module, "No branch %s in %s, skip push", branch, module.getProject().getName());
if (!branchExists(project, branch)) {
logger.log(module, "No branch %s in %s, skip push", branch, project.getName());
return;
}
doWithGit(module.getProject(), git -> {
doWithGit(project, git -> {
Ref ref = git.getRepository().findRef(branch.toString());
git.push()//
.setRemote("origin")//
.setRefSpecs(new RefSpec(ref.getName()))//
.setCredentialsProvider(gitProperties.getCredentials())//
.call();
call(git.push() //
.setRemote("origin") //
.setRefSpecs(new RefSpec(ref.getName())));
});
}
@@ -284,15 +277,15 @@ public class GitOperations {
ExecutionUtils.run(executor, train.getModules(), module -> {
logger.log(module.getProject(), "git push --tags origin");
SupportedProject project = train.getSupportedProject(module);
doWithGit(module.getProject(), git -> {
logger.log(project, "git push --tags origin");
git.push()//
.setRemote("origin")//
.setPushTags()//
.setCredentialsProvider(gitProperties.getCredentials())//
.call();
doWithGit(project, git -> {
call(git.push() //
.setRemote("origin") //
.setPushTags());
});
});
}
@@ -303,16 +296,16 @@ public class GitOperations {
*
* @param project must not be {@literal null}.
*/
public void update(Project project) {
public void update(SupportedProject project) {
Assert.notNull(project, "Project must not be null!");
logger.log(project, "Updating project…");
GitProject gitProject = new GitProject(project, server);
GitProject gitProject = getGitProject(project);
String repositoryName = gitProject.getRepositoryName();
doWithGit(project, git -> {
doWithGit(gitProject.getProject(), git -> {
if (workspace.hasProjectDirectory(project)) {
@@ -321,10 +314,12 @@ public class GitOperations {
checkout(project, Branch.MAIN);
logger.log(project, "git fetch --tags");
git.fetch().setTagOpt(TagOpt.FETCH_TAGS).call();
call(git.fetch() //
.setTagOpt(TagOpt.FETCH_TAGS));
} else {
clone(project);
clone(gitProject);
}
});
@@ -336,35 +331,44 @@ public class GitOperations {
*
* @param project must not be {@literal null}.
*/
public void fetchTags(Project project) {
public void fetchTags(Project project, Train train) {
Assert.notNull(project, "Project must not be null!");
logger.log(project, "Updating project tags…");
GitProject gitProject = new GitProject(project, server);
GitProject gitProject = getGitProject(train.getSupportedProject(project));
String repositoryName = gitProject.getRepositoryName();
doWithGit(project, git -> {
doWithGit(gitProject.getProject(), git -> {
if (workspace.hasProjectDirectory(project)) {
if (workspace.hasProjectDirectory(train.getSupportedProject(project))) {
logger.log(project, "Found existing repository %s. Obtaining tags…", repositoryName);
logger.log(project, "git fetch --tags");
git.fetch().setTagOpt(TagOpt.FETCH_TAGS).call();
call(git.fetch() //
.setTagOpt(TagOpt.FETCH_TAGS));
} else {
clone(project);
clone(gitProject);
}
});
logger.log(project, "Project tags update done!");
}
public VersionTags getTags(Project project) {
private GitProject getGitProject(SupportedProject project) {
return new GitProject(project, server);
}
public VersionTags getTags(SupportedProject project) {
return doWithGit(project, git -> {
return new VersionTags(project, git.tagList().call().stream()//
git.tagList().call();
return new VersionTags(project.getProject(), git.tagList().call().stream()//
.map(ref -> {
RevCommit commit = getCommit(git.getRepository(), ref);
@@ -403,7 +407,7 @@ public class GitOperations {
* @param project must not be {@literal null}.
* @return
*/
public TicketBranches listTicketBranches(Project project) {
public TicketBranches listTicketBranches(SupportedProject project) {
Assert.notNull(project, "Project must not be null!");
@@ -415,7 +419,7 @@ public class GitOperations {
update(project);
Map<String, Branch> ticketIds = getRemoteBranches(project)//
.filter(branch -> branch.isIssueBranch(project.getTracker()))//
.filter(branch -> branch.isIssueBranch(project.getProject().getTracker()))//
.collect(Collectors.toMap(Branch::toString, branch -> branch));
Collection<Ticket> tickets = tracker.findTickets(project, ticketIds.keySet());
@@ -442,7 +446,9 @@ public class GitOperations {
return trainToUse.getIteration(Iteration.GA);
}
Optional<TrainIteration> mostRecentBefore = getTags(Projects.BUILD) //
SupportedProject build = trainIteration.getSupportedProject(Projects.BUILD);
Optional<TrainIteration> mostRecentBefore = getTags(build) //
.filter((tag, ti) -> ti.getTrain().equals(trainIteration.getTrain())) //
.find((tag, iteration) -> iteration.getIteration().compareTo(trainIteration.getIteration()) < 0,
Pair::getSecond);
@@ -451,7 +457,8 @@ public class GitOperations {
"Cannot determine previous iteration for " + trainIteration.getReleaseTrainNameAndVersion()));
}
public List<TicketReference> getTicketReferencesBetween(Project project, TrainIteration from, TrainIteration to) {
public List<TicketReference> getTicketReferencesBetween(SupportedProject project, TrainIteration from,
TrainIteration to) {
VersionTags tags = getTags(project);
@@ -459,8 +466,8 @@ public class GitOperations {
Repository repo = git.getRepository();
ModuleIteration toModuleIteration = to.getModule(project);
ObjectId fromTag = resolveLowerBoundary(project, from, tags, repo);
ModuleIteration toModuleIteration = to.getModule(project.getProject());
ObjectId fromTag = resolveLowerBoundary(project.getProject(), from, tags, repo);
ObjectId toTag = resolveUpperBoundary(toModuleIteration, tags, repo);
Iterable<RevCommit> commits = git.log().addRange(fromTag, toTag).call();
@@ -526,9 +533,13 @@ public class GitOperations {
}
private static String getFirstCommit(Repository repo) throws IOException {
return getFirstCommit(repo, Branch.MAIN);
}
private static String getFirstCommit(Repository repo, Branch branch) throws IOException {
try (RevWalk revWalk = new RevWalk(repo)) {
return revWalk.parseCommit(repo.resolve("main")).getName();
return revWalk.parseCommit(repo.resolve(branch.toString())).getName();
}
}
@@ -547,10 +558,10 @@ public class GitOperations {
}
private static boolean isGaOrFirstMilestone(Iteration iteration) {
return iteration.isGAIteration() || (iteration.isMilestone() && iteration.getIterationValue() == 1);
return iteration.isGAIteration() || iteration.isMilestone() && iteration.getIterationValue() == 1;
}
private Stream<Branch> getRemoteBranches(Project project) {
private Stream<Branch> getRemoteBranches(SupportedProject project) {
return doWithGit(project, git -> {
@@ -576,7 +587,7 @@ public class GitOperations {
ExecutionUtils.run(executor, iteration, module -> {
Project project = module.getProject();
SupportedProject project = module.getSupportedProject();
ObjectId hash = getReleaseHash(module);
Tag tag = getTags(project).createTag(module);
@@ -646,7 +657,7 @@ public class GitOperations {
Assert.notNull(module, "Module iteration must not be null!");
Assert.hasText(summary, "Summary must not be null or empty!");
Project project = module.getProject();
SupportedProject project = module.getSupportedProject();
IssueTracker tracker = issueTracker.getRequiredPluginFor(project,
() -> String.format("No issue tracker found for project %s!", project));
Ticket ticket = tracker.getReleaseTicketFor(module);
@@ -667,7 +678,7 @@ public class GitOperations {
Assert.notNull(module, "Module iteration must not be null!");
Assert.hasText(summary, "Summary must not be null or empty!");
Project project = module.getProject();
SupportedProject project = module.getSupportedProject();
IssueTracker tracker = issueTracker.getRequiredPluginFor(project,
() -> String.format("No issue tracker found for project %s!", project));
Ticket ticket = tracker.getReleaseTicketFor(module);
@@ -683,11 +694,12 @@ public class GitOperations {
* @param summary must not be {@literal null} or empty.
* @param details can be {@literal null} or empty.
*/
public void commit(ProjectAware module, Ticket ticket, String summary, Optional<String> details, boolean all) {
public void commit(ProjectAware module, Ticket ticket, String summary, Optional<String> details,
boolean all) {
Assert.notNull(module, "ProjectAware must not be null!");
commit(module.getProject(), ticket, summary, details, all);
commit(module.getSupportedProject(), ticket, summary, details, all);
}
/**
@@ -698,7 +710,7 @@ public class GitOperations {
* @param summary must not be {@literal null} or empty.
* @param details can be {@literal null} or empty.
*/
public void commit(Project project, Ticket ticket, String summary, Optional<String> details, boolean all) {
public void commit(SupportedProject project, Ticket ticket, String summary, Optional<String> details, boolean all) {
Assert.notNull(project, "Project must not be null!");
Assert.hasText(summary, "Summary must not be null or empty!");
@@ -745,7 +757,7 @@ public class GitOperations {
* @param project must not be {@literal null}.
* @param filepattern must not be {@literal null} or empty.
*/
public void add(Project project, String filepattern) {
public void add(SupportedProject project, String filepattern) {
Assert.notNull(project, "Project must not be null!");
@@ -761,14 +773,14 @@ public class GitOperations {
}
/**
* Checks out the given {@link Branch} of the given {@link Project}. If the given branch doesn't exist yet, a tracking
* branch is created assuming the branch exists in the {@code origin} remote. Pulls the latest changes from the
* checked out branch will be pulled to make sure we see them.
* Checks out the given {@link Branch} of the given {@link SupportedProject}. If the given branch doesn't exist yet, a
* tracking branch is created assuming the branch exists in the {@code origin} remote. Pulls the latest changes from
* the checked out branch will be pulled to make sure we see them.
*
* @param project must not be {@literal null}.
* @param branch must not be {@literal null}.
*/
public void checkout(Project project, Branch branch) {
public void checkout(SupportedProject project, Branch branch) {
checkout(project, branch, BranchCheckoutMode.CREATE_AND_UPDATE);
}
@@ -782,7 +794,7 @@ public class GitOperations {
* @param branch must not be {@literal null}.
* @param mode must not be {@literal null}.
*/
private void checkout(Project project, Branch branch, BranchCheckoutMode mode) {
private void checkout(SupportedProject project, Branch branch, BranchCheckoutMode mode) {
Assert.notNull(project, "Project must not be null!");
Assert.notNull(branch, "Branch must not be null!");
@@ -822,11 +834,11 @@ public class GitOperations {
// Pull latest changes to make sure the branch is up to date
logger.log(project, "git pull origin %s", branch);
git.pull()//
.setRemote("origin")//
call(git.pull() //
.setRemote("origin") //
.setRebase(true) //
.setRemoteBranchName(branch.toString())//
.call();
.setRemoteBranchName(branch.toString()));
break;
}
});
@@ -845,7 +857,7 @@ public class GitOperations {
ExecutionUtils.run(executor, iteration, module -> {
Branch branch = createMaintenanceBranch(module);
checkout(module.getProject(), branch, BranchCheckoutMode.CREATE_ONLY);
checkout(module.getSupportedProject(), branch, BranchCheckoutMode.CREATE_ONLY);
});
}
@@ -853,7 +865,7 @@ public class GitOperations {
ExecutionUtils.run(executor, iteration, module -> {
Project project = module.getProject();
SupportedProject project = module.getSupportedProject();
ArtifactVersion artifactVersion = ArtifactVersion.of(module);
Optional<Tag> tag = findTagFor(project, artifactVersion);
@@ -875,10 +887,12 @@ public class GitOperations {
* Verify general Git operations.
*/
@SneakyThrows
public void verify() {
public void verify(Train train) {
SupportedProject project = train.getSupportedProject(Projects.BUILD);
Project project = Projects.BUILD;
File projectDirectory = workspace.getProjectDirectory(project);
if (projectDirectory.exists()) {
FileUtils.deleteDirectory(projectDirectory);
}
@@ -891,7 +905,7 @@ public class GitOperations {
reset(project, Branch.MAIN);
}
private void commitRandomFile(Project project, File projectDirectory) throws IOException {
private void commitRandomFile(SupportedProject project, File projectDirectory) throws IOException {
String randomFileName = UUID.randomUUID() + ".txt";
File randomFile = new File(projectDirectory, randomFileName);
@@ -925,7 +939,7 @@ public class GitOperations {
Branch branch = Branch.from(module.getVersion());
doWithGit(module.getProject(), git -> {
doWithGit(module.getSupportedProject(), git -> {
logger.log(module, "git checkout -b %s", branch);
git.branchCreate().setName(branch.toString()).call();
});
@@ -952,14 +966,15 @@ public class GitOperations {
Predicate<RevCommit> trigger = calculateFilter(module, summary);
return findCommit(module, summary).orElseThrow(() -> new IllegalStateException(String
.format("Did not find a commit with summary starting with '%s' for project %s", module.getProject(), trigger)));
.format("Did not find a commit with summary starting with '%s' for project %s", module.getSupportedProject(),
trigger)));
}
private Optional<ObjectId> findCommit(ModuleIteration module, String summary) {
return findCommit(module.getProject(), calculateFilter(module, summary));
return findCommit(module.getSupportedProject(), calculateFilter(module, summary));
}
private Optional<ObjectId> findCommit(Project project, Predicate<RevCommit> filter) {
private Optional<ObjectId> findCommit(SupportedProject project, Predicate<RevCommit> filter) {
return doWithGit(project, git -> {
@@ -976,7 +991,7 @@ public class GitOperations {
private Predicate<RevCommit> calculateFilter(ModuleIteration module, String summary) {
Project project = module.getProject();
SupportedProject project = module.getSupportedProject();
Ticket releaseTicket = issueTracker
.getRequiredPluginFor(project, () -> String.format("No issue tracker found for project %s!", project))//
.getReleaseTicketFor(module);
@@ -999,14 +1014,14 @@ public class GitOperations {
* @return
* @throws IOException
*/
private Optional<Tag> findTagFor(Project project, ArtifactVersion version) {
private Optional<Tag> findTagFor(SupportedProject project, ArtifactVersion version) {
return getTags(project).stream()//
.filter(tag -> tag.toArtifactVersion().map(it -> it.equals(version)).orElse(false))//
.findFirst();
}
private Repository getRepository(Project project) throws IOException {
private Repository getRepository(SupportedProject project) throws IOException {
Repository repository = FileRepositoryBuilder.create(workspace.getFile(".git", project));
@@ -1017,25 +1032,24 @@ public class GitOperations {
return repository;
}
private void clone(Project project) throws Exception {
private void clone(GitProject gitProject) throws Exception {
GitProject gitProject = getGitProject(project);
SupportedProject project = gitProject.getProject();
logger.log(project, "No repository found! Cloning from %s…", gitProject.getProjectUri());
Git git = Git.cloneRepository()//
.setURI(gitProject.getProjectUri())//
.setDirectory(workspace.getProjectDirectory(project))//
.call();
Git git = call(Git.cloneRepository() //
.setURI(gitProject.getProjectUri()) //
.setDirectory(workspace.getProjectDirectory(project)));
git.checkout()//
.setName(Branch.MAIN.toString())//
git.checkout() //
.setName(Branch.MAIN.toString()) //
.call();
logger.log(project, "Cloning done!", project);
}
private boolean branchExists(Project project, Branch branch) {
private boolean branchExists(SupportedProject project, Branch branch) {
try (Git git = new Git(getRepository(project))) {
@@ -1046,7 +1060,7 @@ public class GitOperations {
}
}
private void reset(Project project, Branch branch) {
private void reset(SupportedProject project, Branch branch) {
logger.log(project, "git reset --hard origin/%s", branch);
@@ -1063,7 +1077,7 @@ public class GitOperations {
return summary.contains("%s") ? String.format(summary, module.getMediumVersionString()) : summary;
}
private <T> T doWithGit(Project project, GitCallback<T> callback) {
private <T> T doWithGit(SupportedProject project, GitCallback<T> callback) {
try (Git git = new Git(getRepository(project))) {
return callback.doWithGit(git);
@@ -1081,7 +1095,7 @@ public class GitOperations {
}
}
private void doWithGit(Project project, VoidGitCallback callback) {
private void doWithGit(SupportedProject project, VoidGitCallback callback) {
doWithGit(project, (GitCallback<Void>) git -> {
callback.doWithGit(git);
@@ -1106,6 +1120,13 @@ public class GitOperations {
return gpg;
}
private <T, C extends GitCommand<T>> T call(TransportCommand<C, T> command) throws GitAPIException {
return command
.setCredentialsProvider(gitProperties.getCredentials())
.call();
}
/**
* {@link CredentialsProvider} for GPG Keys used with JGit Commit Signing.
*/

View File

@@ -17,35 +17,44 @@ package org.springframework.data.release.git;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.SupportedProject;
/**
* @author Oliver Gierke
*/
@EqualsAndHashCode
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
public class GitProject {
private static final String PROJECT_PREFIX = "spring-data";
private final Project project;
private final @Getter SupportedProject project;
private final GitServer server;
public static GitProject of(Project project) {
public static GitProject of(SupportedProject project) {
return new GitProject(project, GitServer.INSTANCE);
}
public static GitProject of(ModuleIteration module) {
return new GitProject(module.getSupportedProject(), GitServer.INSTANCE);
}
/**
* Returns the name of the repository the project is using.
*
* @return
*/
public String getRepositoryName() {
return String.format("%s-%s", PROJECT_PREFIX,
project == Projects.JDBC ? "relational" : project.getName().toLowerCase());
String logicalName = String.format("%s-%s", PROJECT_PREFIX,
project.getProject() == Projects.JDBC ? "relational" : project.getName().toLowerCase());
return project.isCommercial() ? logicalName + "-commercial" : logicalName;
}
/**

View File

@@ -91,7 +91,7 @@ public class VersionTags implements Streamable<Tag> {
public Tag createTag(ModuleIteration iteration) {
if (iteration.getProject().equals(Projects.BOM)) {
if (iteration.getSupportedProject().equals(Projects.BOM)) {
return Tag.of(iteration.getTrainIteration().getReleaseTrainNameAndVersion());
}

View File

@@ -34,8 +34,8 @@ import org.springframework.data.release.TimedCommand;
import org.springframework.data.release.git.GitOperations;
import org.springframework.data.release.issues.Tickets;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.data.release.utils.Logger;
import org.springframework.shell.core.annotation.CliCommand;
@@ -79,13 +79,14 @@ public class DependencyCommands extends TimedCommand {
git.prepare(iteration);
List<Project> projects = Projects.all().stream()
List<SupportedProject> projects = Projects.all().stream()
.filter(it -> it != Projects.BOM && it != Projects.BUILD && it != Projects.COMMONS)
.map(iteration::getSupportedProject)
.collect(Collectors.toList());
Map<Dependency, DependencyVersion> dependencies = new TreeMap<>();
for (Project project : projects) {
for (SupportedProject project : projects) {
operations.getCurrentDependencies(project).forEach(dependencies::put);
}
@@ -113,7 +114,7 @@ public class DependencyCommands extends TimedCommand {
ModuleIteration module = iteration.getModule(Projects.BUILD);
DependencyVersions dependencyVersions = loadDependencyUpgrades(module);
DependencyVersions upgradesToApply = operations.getDependencyUpgradesToApply(module.getProject(),
DependencyVersions upgradesToApply = operations.getDependencyUpgradesToApply(module.getSupportedProject(),
dependencyVersions);
if (upgradesToApply.isEmpty()) {
@@ -151,12 +152,14 @@ public class DependencyCommands extends TimedCommand {
String propertiesFile = "dependency-upgrade-modules.properties";
List<Project> projects = Projects.all().stream().filter(it -> it != Projects.BOM && it != Projects.BUILD)
List<SupportedProject> projects = Projects.all().stream()
.filter(it -> it != Projects.BOM && it != Projects.BUILD)
.map(iteration::getSupportedProject)
.collect(Collectors.toList());
DependencyUpgradeProposals proposals = DependencyUpgradeProposals.empty();
for (Project project : projects) {
for (SupportedProject project : projects) {
proposals = proposals.mergeWith(operations.getDependencyUpgradeProposals(project, iteration.getIteration()));
}
@@ -172,7 +175,8 @@ public class DependencyCommands extends TimedCommand {
String propertiesFile = BUILD_PROPERTIES;
DependencyUpgradeProposals proposals = operations.getDependencyUpgradeProposals(Projects.BUILD,
SupportedProject project = iteration.getSupportedProject(Projects.BUILD);
DependencyUpgradeProposals proposals = operations.getDependencyUpgradeProposals(project,
iteration.getIteration());
Files.write(Paths.get(propertiesFile), proposals.asProperties(iteration).getBytes());

View File

@@ -55,6 +55,7 @@ import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.data.release.utils.ExecutionUtils;
import org.springframework.data.release.utils.Logger;
@@ -65,7 +66,6 @@ import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestOperations;
import org.xmlbeam.ProjectionFactory;
import org.xmlbeam.annotation.XBRead;
import org.xmlbeam.io.FileIO;
@@ -102,7 +102,7 @@ public class DependencyOperations {
* @param iteration
* @return
*/
public DependencyUpgradeProposals getDependencyUpgradeProposals(Project project, Iteration iteration) {
public DependencyUpgradeProposals getDependencyUpgradeProposals(SupportedProject project, Iteration iteration) {
DependencyVersions currentDependencies = getCurrentDependencies(project);
Map<Dependency, DependencyUpgradeProposal> proposals = Collections.synchronizedMap(new LinkedHashMap<>());
@@ -132,10 +132,12 @@ public class DependencyOperations {
for (ModuleIteration moduleIteration : iteration) {
// ensure we have Maven Wrapper for each project.
getMavenWrapperVersion(moduleIteration.getProject());
getMavenWrapperVersion(moduleIteration.getSupportedProject());
}
return getDependencyUpgradeProposals(Projects.BUILD, DependencyUpgradePolicy.LATEST_STABLE, Dependencies.MAVEN,
SupportedProject build = iteration.getSupportedProject(Projects.BUILD);
return getDependencyUpgradeProposals(build, DependencyUpgradePolicy.LATEST_STABLE, Dependencies.MAVEN,
this::getMavenWrapperVersion);
}
@@ -154,7 +156,7 @@ public class DependencyOperations {
}
return doWithDependencyVersionsAndCommit(tickets, module, dependencyVersions, (dependency, version) -> {
upgradeMavenWrapperVersion(module.getProject(), version);
upgradeMavenWrapperVersion(module.getSupportedProject(), version);
});
}
@@ -164,17 +166,17 @@ public class DependencyOperations {
for (ModuleIteration moduleIteration : iteration) {
DependencyVersion currentVersion = getMavenWrapperVersion(moduleIteration.getProject());
DependencyVersion currentVersion = getMavenWrapperVersion(moduleIteration.getSupportedProject());
if (targetVersion.isNewer(currentVersion)) {
projectsToUpgrade.add(moduleIteration.getProject());
projectsToUpgrade.add(moduleIteration.getSupportedProject().getProject());
}
}
return projectsToUpgrade;
}
private DependencyVersion getMavenWrapperVersion(Project project) {
private DependencyVersion getMavenWrapperVersion(SupportedProject project) {
try {
@@ -191,8 +193,8 @@ public class DependencyOperations {
}
Pattern versionPattern = Pattern.compile(".*/maven2/org/apache/maven/apache-maven/([\\d\\.]+)/.*");
Matcher matcher = versionPattern.matcher(distributionUrl);
if (!matcher.find()) {
throw new IllegalStateException(
String.format("Invalid distribution URL in %s: %s", project.getName(), distributionUrl));
@@ -204,7 +206,7 @@ public class DependencyOperations {
}
}
private void upgradeMavenWrapperVersion(Project project, DependencyVersion dependencyVersion) {
private void upgradeMavenWrapperVersion(SupportedProject project, DependencyVersion dependencyVersion) {
String distributionUrlTemplate = "https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/%s/apache-maven-%s-bin.zip";
@@ -229,7 +231,7 @@ public class DependencyOperations {
}
}
private File getMavenWrapperProperties(Project project) throws FileNotFoundException {
private File getMavenWrapperProperties(SupportedProject project) throws FileNotFoundException {
File file = workspace.getFile(".mvn/wrapper/maven-wrapper.properties", project);
if (!file.exists()) {
@@ -238,8 +240,9 @@ public class DependencyOperations {
return file;
}
public DependencyUpgradeProposals getDependencyUpgradeProposals(Project project, DependencyUpgradePolicy policy,
Dependency dependency, Function<Project, DependencyVersion> currentVersionExtractor) {
public DependencyUpgradeProposals getDependencyUpgradeProposals(SupportedProject project,
DependencyUpgradePolicy policy, Dependency dependency,
Function<SupportedProject, DependencyVersion> currentVersionExtractor) {
DependencyVersions currentDependencies = new DependencyVersions(
Collections.singletonMap(dependency, currentVersionExtractor.apply(project)));
@@ -280,7 +283,7 @@ public class DependencyOperations {
*/
public Tickets upgradeDependencies(Tickets tickets, ModuleIteration module, DependencyVersions dependencyVersions) {
Project project = module.getProject();
SupportedProject project = module.getSupportedProject();
ProjectDependencies dependencies = ProjectDependencies.get(project);
if (dependencyVersions.isEmpty()) {
@@ -290,7 +293,7 @@ public class DependencyOperations {
return doWithDependencyVersionsAndCommit(tickets, module, dependencyVersions, (dependency, version) -> {
String versionProperty = dependencies.getVersionPropertyFor(dependency);
File pom = getPomFile(project);
File pom = getPomFile(module.getSupportedProject());
update(pom, Pom.class, it -> {
it.setProperty(versionProperty, version.getIdentifier());
});
@@ -333,7 +336,8 @@ public class DependencyOperations {
this.tickets.closeTickets(module, tickets);
}
public DependencyVersions getDependencyUpgradesToApply(Project project, DependencyVersions dependencyVersions) {
public DependencyVersions getDependencyUpgradesToApply(SupportedProject project,
DependencyVersions dependencyVersions) {
DependencyVersions currentDependencies = getCurrentDependencies(project);
Map<Dependency, DependencyVersion> upgrades = new LinkedHashMap<>();
@@ -452,14 +456,16 @@ public class DependencyOperations {
.max(DependencyVersion::compareTo);
}
DependencyVersions getCurrentDependencies(Project project) {
DependencyVersions getCurrentDependencies(SupportedProject supportedProject) {
Project project = supportedProject.getProject();
if (!ProjectDependencies.containsProject(project)) {
return DependencyVersions.empty();
}
File pom = getPomFile(project);
ProjectDependencies dependencies = ProjectDependencies.get(project);
File pom = getPomFile(supportedProject);
ProjectDependencies dependencies = ProjectDependencies.get(supportedProject);
return doWithPom(pom, Pom.class, it -> {
@@ -469,7 +475,7 @@ public class DependencyOperations {
Dependency dependency = projectDependency.getDependency();
if (!((project == Projects.MONGO_DB && projectDependency.getProperty().equals("mongo.reactivestreams"))
if (!(project == Projects.MONGO_DB && projectDependency.getProperty().equals("mongo.reactivestreams")
|| project == Projects.NEO4J || project == Projects.BUILD)) {
if (it.getDependencyVersion(dependency.getArtifactId()) == null
@@ -489,8 +495,8 @@ public class DependencyOperations {
});
}
private File getPomFile(Project project) {
return workspace.getFile(project == Projects.BUILD ? "parent/pom.xml" : "pom.xml", project);
private File getPomFile(SupportedProject project) {
return workspace.getFile(project.getProject().getProjectDescriptor(), project);
}
@SneakyThrows
@@ -560,7 +566,7 @@ public class DependencyOperations {
try {
T pom = (T) io.read(type);
T pom = io.read(type);
return callback.apply(pom);
} catch (Exception o_O) {
@@ -574,7 +580,7 @@ public class DependencyOperations {
try {
T pom = (T) io.read(type);
T pom = io.read(type);
callback.accept(pom);
io.write(pom);

View File

@@ -30,16 +30,15 @@ import java.util.Properties;
import java.util.concurrent.ExecutorService;
import org.apache.commons.io.FileUtils;
import org.springframework.data.release.TimedCommand;
import org.springframework.data.release.git.Branch;
import org.springframework.data.release.git.GitOperations;
import org.springframework.data.release.io.Workspace;
import org.springframework.data.release.issues.Tickets;
import org.springframework.data.release.model.Module;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.model.Train;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.data.release.utils.ExecutionUtils;
@@ -72,7 +71,7 @@ public class InfrastructureOperations extends TimedCommand {
*/
void distributeCiProperties(TrainIteration iteration) {
File master = workspace.getFile(CI_PROPERTIES, Projects.BUILD);
File master = workspace.getFile(CI_PROPERTIES, iteration.getSupportedProject(Projects.BUILD));
if (!master.exists()) {
throw new IllegalStateException(String.format("CI Properties file %s does not exist", master));
@@ -80,7 +79,7 @@ public class InfrastructureOperations extends TimedCommand {
ExecutionUtils.run(executor, iteration, module -> {
Project project = module.getProject();
SupportedProject project = module.getSupportedProject();
Branch branch = Branch.from(module);
git.update(project);
@@ -91,12 +90,12 @@ public class InfrastructureOperations extends TimedCommand {
ExecutionUtils.run(executor, Streamable.of(iteration.getModulesExcept(Projects.BUILD)), module -> {
File target = workspace.getFile(CI_PROPERTIES, module.getProject());
File target = workspace.getFile(CI_PROPERTIES, module.getSupportedProject());
target.delete();
FileUtils.copyFile(master, target);
git.add(module.getProject(), CI_PROPERTIES);
git.add(module.getSupportedProject(), CI_PROPERTIES);
git.commit(module, "Update CI properties.", Optional.empty(), false);
git.push(module);
});
@@ -104,8 +103,9 @@ public class InfrastructureOperations extends TimedCommand {
private void verifyExistingPropertyFiles(Train train, File master) {
for (Module module : train) {
File target = workspace.getFile(CI_PROPERTIES, module.getProject());
for (SupportedProject project : train) {
File target = workspace.getFile(CI_PROPERTIES, project);
if (!target.exists()) {
throw new IllegalStateException(String.format("CI Properties file %s does not exist", master));

View File

@@ -38,7 +38,6 @@ import org.apache.commons.io.filefilter.AbstractFileFilter;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.NameFileFilter;
import org.apache.commons.io.filefilter.NotFileFilter;
import org.springframework.data.release.CliComponent;
import org.springframework.data.release.TimedCommand;
import org.springframework.data.release.git.GitOperations;
@@ -49,6 +48,7 @@ import org.springframework.data.release.issues.TicketOperations;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.data.release.utils.ExecutionUtils;
import org.springframework.data.release.utils.Logger;
@@ -95,7 +95,7 @@ public class LicenseHeaderCommands extends TimedCommand {
if (projectName != null) {
Project project = Projects.requiredByName(projectName);
modules = modules.filter(it -> it.getProject().equals(project));
modules = modules.filter(it -> it.getSupportedProject().equals(project));
}
ExecutionUtils.run(executor, modules, module -> {
@@ -110,7 +110,7 @@ public class LicenseHeaderCommands extends TimedCommand {
private int updateLicense(int year, ModuleIteration module) {
return replaceInFiles(module.getProject(), (file, content) -> {
return replaceInFiles(module.getSupportedProject(), (file, content) -> {
String contentToUse = content;
@@ -154,7 +154,7 @@ public class LicenseHeaderCommands extends TimedCommand {
* @param contentFunction
* @return
*/
private int replaceInFiles(Project project, Function<String, String> contentFunction) {
private int replaceInFiles(SupportedProject project, Function<String, String> contentFunction) {
return replaceInFiles(project, (file, s) -> contentFunction.apply(s));
}
@@ -165,7 +165,7 @@ public class LicenseHeaderCommands extends TimedCommand {
* @param contentFunction
* @return
*/
private int replaceInFiles(Project project, BiFunction<File, String, String> contentFunction) {
private int replaceInFiles(SupportedProject project, BiFunction<File, String, String> contentFunction) {
File projectDirectory = workspace.getProjectDirectory(project);
IOFileFilter fileFilter = new AntPathFileFilter(projectDirectory, filePatterns);

View File

@@ -22,6 +22,7 @@ import java.util.List;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.util.Streamable;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
@@ -104,19 +105,19 @@ public class ProjectDependencies implements Streamable<ProjectDependencies.Proje
}
/**
* Retrieve upgradable dependencies for a {@link Project}.
* Retrieve upgradable dependencies for a {@link SupportedProject}.
*
* @param project
* @return
* @throws IllegalArgumentException if the project has no upgradable dependencies.
*/
public static ProjectDependencies get(Project project) {
public static ProjectDependencies get(SupportedProject project) {
if (!containsProject(project)) {
if (!containsProject(project.getProject())) {
throw new IllegalArgumentException(String.format("No dependency configuration for %s!", project));
}
return new ProjectDependencies(config.get(project));
return new ProjectDependencies(config.get(project.getProject()));
}
/**

View File

@@ -42,8 +42,8 @@ import javax.annotation.PostConstruct;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.utils.Logger;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@@ -149,11 +149,11 @@ public class Workspace {
* @param project must not be {@literal null}.
* @return
*/
public File getProjectDirectory(Project project) {
public File getProjectDirectory(SupportedProject project) {
Assert.notNull(project, "Project must not be null!");
if (project == Projects.SMOKE_TESTS) {
if (project.getProject() == Projects.SMOKE_TESTS) {
return new File("smoke-tests");
}
@@ -166,7 +166,7 @@ public class Workspace {
* @param project must not be {@literal null}.
* @return
*/
public boolean hasProjectDirectory(Project project) {
public boolean hasProjectDirectory(SupportedProject project) {
Assert.notNull(project, "Project must not be null!");
return getProjectDirectory(project).exists();
@@ -179,7 +179,7 @@ public class Workspace {
* @param project must not be {@literal null}.
* @return
*/
public File getFile(String name, Project project) {
public File getFile(String name, SupportedProject project) {
Assert.hasText(name, "Filename must not be null or empty!");
Assert.notNull(project, "Project must not be null!");
@@ -187,7 +187,7 @@ public class Workspace {
return new File(getProjectDirectory(project), name);
}
public Stream<File> getFiles(String pattern, Project project) {
public Stream<File> getFiles(String pattern, SupportedProject project) {
File projectDirectory = getProjectDirectory(project);
String patternToLookup = String.format("file:%s/%s", projectDirectory.getAbsolutePath(), pattern);
@@ -199,7 +199,7 @@ public class Workspace {
}
}
public boolean processFile(String filename, Project project, LineCallback callback) {
public boolean processFile(String filename, SupportedProject project, LineCallback callback) {
File file = getFile(filename, project);
@@ -226,7 +226,7 @@ public class Workspace {
return true;
}
private void writeContentToFile(String name, Project project, String content) throws IOException {
private void writeContentToFile(String name, SupportedProject project, String content) throws IOException {
File file = getFile(name, project);
Files.write(file.toPath(), Collections.singleton(content), UTF_8);

View File

@@ -19,10 +19,8 @@ import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.Train;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.plugin.core.Plugin;
@@ -32,7 +30,7 @@ import org.springframework.plugin.core.Plugin;
* @author Oliver Gierke
* @author Mark Paluch
*/
public interface IssueTracker extends Plugin<Project> {
public interface IssueTracker extends Plugin<SupportedProject> {
/**
* Reset internal state (cache, etc).
@@ -80,7 +78,7 @@ public interface IssueTracker extends Plugin<Project> {
* @param ticketIds collection of {@link Ticket#id ticket Ids}, must not be {@literal null}.
* @return
*/
Collection<Ticket> findTickets(Project project, Collection<String> ticketIds);
Collection<Ticket> findTickets(SupportedProject project, Collection<String> ticketIds);
/**
* Query the issue tracker for multiple {@link Ticket#id ticket Ids}. Tickets that are not found are not returned. The
@@ -133,7 +131,7 @@ public interface IssueTracker extends Plugin<Project> {
* @param project must not be {@literal null}.
* @param ticket must not be {@literal null}.
*/
Ticket assignTicketToMe(Project project, Ticket ticket);
Ticket assignTicketToMe(SupportedProject project, Ticket ticket);
/**
* Assigns the release ticket for the given {@link ModuleIteration} to the current user.

View File

@@ -33,6 +33,7 @@ import org.springframework.data.release.model.Module;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.data.release.utils.ExecutionUtils;
import org.springframework.data.util.Streamable;
@@ -50,7 +51,7 @@ import org.springframework.util.StringUtils;
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
public class IssueTrackerCommands extends TimedCommand {
@NonNull PluginRegistry<IssueTracker, Project> tracker;
@NonNull PluginRegistry<IssueTracker, SupportedProject> tracker;
@NonNull Executor executor;
@CliCommand("tracker evict")
@@ -199,13 +200,19 @@ public class IssueTrackerCommands extends TimedCommand {
}
private static Streamable<ModuleIteration> withReleaseProject(TrainIteration iteration) {
if (iteration.isCommercial()) {
return iteration;
}
ModuleIteration bom = iteration.getModule(Projects.BOM);
return iteration.and(new ModuleIteration(new Module(Projects.RELEASE, bom.getVersion()), iteration));
}
private IssueTracker getTrackerFor(ModuleIteration moduleIteration) {
return tracker.getRequiredPluginFor(moduleIteration.getProject(),
return tracker.getRequiredPluginFor(moduleIteration.getSupportedProject(),
() -> String.format("No issue tracker found for module %s!", moduleIteration));
}
}

View File

@@ -15,22 +15,8 @@
*/
package org.springframework.data.release.issues;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cache.CacheManager;
@@ -39,16 +25,11 @@ import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.release.issues.github.GitHubProperties;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.utils.HttpBasicCredentials;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.utils.HttpComponentsClientHttpRequestFactoryBuilder;
import org.springframework.data.util.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.plugin.core.OrderAwarePluginRegistry;
import org.springframework.plugin.core.PluginRegistry;
import com.fasterxml.jackson.annotation.JsonCreator.Mode;
@@ -106,8 +87,8 @@ class IssueTrackerConfiguration {
}
@Bean
PluginRegistry<IssueTracker, Project> issueTrackers(List<? extends IssueTracker> plugins) {
return OrderAwarePluginRegistry.of(plugins);
PluginRegistry<IssueTracker, SupportedProject> issueTrackers(List<? extends IssueTracker> plugins) {
return PluginRegistry.of(plugins);
}
/**

View File

@@ -25,7 +25,7 @@ import java.util.List;
import java.util.Optional;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.utils.Logger;
import org.springframework.plugin.core.PluginRegistry;
import org.springframework.stereotype.Component;
@@ -40,7 +40,7 @@ public class TicketOperations {
Logger logger;
PluginRegistry<IssueTracker, Project> tracker;
PluginRegistry<IssueTracker, SupportedProject> tracker;
/**
* Create or look up ticket with a particular summary.
@@ -65,8 +65,7 @@ public class TicketOperations {
public Tickets getOrCreateTicketsWithSummary(ModuleIteration module, IssueTracker.TicketType ticketType,
List<String> summaries) {
Project project = module.getProject();
SupportedProject project = module.getSupportedProject();
IssueTracker tracker = this.tracker.getRequiredPluginFor(project);
Tickets tickets = tracker.getTicketsFor(module);
List<Ticket> results = new ArrayList<>();
@@ -109,7 +108,7 @@ public class TicketOperations {
public void closeTickets(ModuleIteration module, Tickets tickets) {
IssueTracker tracker = this.tracker.getRequiredPluginFor(module.getProject());
IssueTracker tracker = this.tracker.getRequiredPluginFor(module.getSupportedProject());
for (Ticket ticket : tickets) {
tracker.closeTicket(module, ticket);

View File

@@ -36,14 +36,7 @@ import org.springframework.data.release.issues.IssueTracker;
import org.springframework.data.release.issues.Ticket;
import org.springframework.data.release.issues.Tickets;
import org.springframework.data.release.issues.github.GitHubWorkflows.GitHubWorkflow;
import org.springframework.data.release.model.ArtifactVersion;
import org.springframework.data.release.model.DocumentationMetadata;
import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.Tracker;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.data.release.model.*;
import org.springframework.data.release.utils.Logger;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
@@ -128,7 +121,7 @@ public class GitHub extends GitHubSupport implements IssueTracker {
*/
@Override
@Cacheable("tickets")
public Collection<Ticket> findTickets(Project project, Collection<String> ticketIds) {
public Collection<Ticket> findTickets(SupportedProject project, Collection<String> ticketIds) {
String repositoryName = GitProject.of(project).getRepositoryName();
List<Ticket> tickets = new ArrayList<>();
@@ -173,8 +166,8 @@ public class GitHub extends GitHubSupport implements IssueTracker {
* @see org.springframework.plugin.core.Plugin#supports(java.lang.Object)
*/
@Override
public boolean supports(Project project) {
return project.uses(Tracker.GITHUB);
public boolean supports(SupportedProject project) {
return project.getProject().uses(Tracker.GITHUB);
}
@Override
@@ -196,7 +189,7 @@ public class GitHub extends GitHubSupport implements IssueTracker {
}
Tickets tickets = trainIteration.stream(). //
filter(moduleIteration -> supports(moduleIteration.getProject())). //
filter(moduleIteration -> supports(moduleIteration.getSupportedProject())). //
flatMap(moduleIteration -> getTicketsFor(moduleIteration, forCurrentUser).stream()). //
collect(Tickets.toTicketsCollector());
@@ -212,7 +205,7 @@ public class GitHub extends GitHubSupport implements IssueTracker {
Assert.notNull(moduleIteration, "ModuleIteration must not be null.");
String repositoryName = GitProject.of(moduleIteration.getProject()).getRepositoryName();
String repositoryName = GitProject.of(moduleIteration).getRepositoryName();
Optional<Milestone> milestone = findMilestone(moduleIteration);
if (milestone.isPresent()) {
@@ -271,7 +264,7 @@ public class GitHub extends GitHubSupport implements IssueTracker {
private Ticket doCreateTicket(ModuleIteration moduleIteration, String text, TicketType ticketType,
boolean assignToCurrentUser) {
String repositoryName = GitProject.of(moduleIteration.getProject()).getRepositoryName();
String repositoryName = GitProject.of(moduleIteration).getRepositoryName();
Milestone milestone = getMilestone(moduleIteration);
Label label = TICKET_LABELS.get(ticketType);
@@ -298,10 +291,10 @@ public class GitHub extends GitHubSupport implements IssueTracker {
/*
* (non-Javadoc)
* @see org.springframework.data.release.jira.IssueTracker#assignTicketToMe(org.springframework.data.release.jira.Ticket)
* @see org.springframework.data.release.issues.IssueTracker#assignTicketToMe(org.springframework.data.release.model.SupportedProject, org.springframework.data.release.issues.Ticket)
*/
@Override
public Ticket assignTicketToMe(Project project, Ticket ticket) {
public Ticket assignTicketToMe(SupportedProject project, Ticket ticket) {
Assert.notNull(ticket, "Ticket must not be null.");
@@ -332,7 +325,7 @@ public class GitHub extends GitHubSupport implements IssueTracker {
Assert.notNull(module, "ModuleIteration must not be null.");
return assignTicketToMe(module.getProject(), getReleaseTicketFor(module));
return assignTicketToMe(module.getSupportedProject(), getReleaseTicketFor(module));
}
/*
@@ -362,7 +355,7 @@ public class GitHub extends GitHubSupport implements IssueTracker {
private GitHubReadIssue close(ModuleIteration module, Ticket ticket) {
String repositoryName = GitProject.of(module.getProject()).getRepositoryName();
String repositoryName = GitProject.of(module).getRepositoryName();
Map<String, Object> parameters = newUrlTemplateVariables();
parameters.put("repoName", repositoryName);
@@ -390,10 +383,10 @@ public class GitHub extends GitHubSupport implements IssueTracker {
Optional<Milestone> milestone = milestoneCache.get(moduleIteration);
if (milestone == null) {
String repositoryName = GitProject.of(moduleIteration.getProject()).getRepositoryName();
String repositoryName = GitProject.of(moduleIteration).getRepositoryName();
milestone = doFindMilestone(moduleIteration, repositoryName, m -> m.matches(moduleIteration));
if(milestone.isPresent()) {
if (milestone.isPresent()) {
milestoneCache.put(moduleIteration, milestone);
}
}
@@ -419,12 +412,12 @@ public class GitHub extends GitHubSupport implements IssueTracker {
milestones -> {
Optional<Milestone> milestone = milestones.stream(). //
filter(milestonePredicate). //
findFirst(). //
map(m -> {
logger.log(moduleIteration, "Found milestone %s.", m);
return m;
});
filter(milestonePredicate). //
findFirst(). //
map(m -> {
logger.log(moduleIteration, "Found milestone %s.", m);
return m;
});
if (milestone.isPresent()) {
milestoneRef.set(milestone.get());
@@ -460,7 +453,7 @@ public class GitHub extends GitHubSupport implements IssueTracker {
HttpHeaders httpHeaders = new HttpHeaders();
GitProject project = GitProject.of(module.getProject());
GitProject project = GitProject.of(module);
findMilestone(module) //
.filter(Milestone::isOpen) //
@@ -496,7 +489,7 @@ public class GitHub extends GitHubSupport implements IssueTracker {
Map<String, GitHubReadIssue> issues = getIssuesFor(moduleIteration, false, true)
.collect(Collectors.toMap(GitHubIssue::getId, Function.identity()));
String repositoryName = GitProject.of(moduleIteration.getProject()).getRepositoryName();
String repositoryName = GitProject.of(moduleIteration).getRepositoryName();
logger.log(moduleIteration, "Looking up GitHub issues …");
Collection<GitHubReadIssue> foundIssues = ticketIds.stream().filter(it -> it.startsWith("#")).flatMap(it -> {
@@ -602,23 +595,23 @@ public class GitHub extends GitHubSupport implements IssueTracker {
private String createParticipatingModules(TrainIteration iteration) {
Comparator<ModuleIteration> comparator = Comparator
.comparing(moduleIteration -> moduleIteration.getProject().getName());
.comparing(moduleIteration -> moduleIteration.getSupportedProject().getName());
return iteration.stream().sorted(comparator).map(module -> {
Tag tag = VersionTags.empty(module.getProject()).createTag(module);
return String.format("* [Spring Data %s %s](%s%s/releases/tag/%s)%n", module.getProject().getName(),
tag.getName(), GitServer.INSTANCE.getUri(), module.getProject().getFolderName(), tag.getName());
return String.format("* [Spring Data %s %s](%s%s/releases/tag/%s)%n", module.getSupportedProject().getName(),
tag.getName(), GitServer.INSTANCE.getUri(), module.getSupportedProject().getFolderName(), tag.getName());
}).collect(Collectors.joining());
}
/**
* Verify GitHub authentication.
*/
public void verifyAuthentication() {
public void verifyAuthentication(Train train) {
logger.log("GitHub", "Verifying GitHub Authentication…");
String repositoryName = GitProject.of(Projects.BUILD).getRepositoryName();
String repositoryName = GitProject.of(train.getSupportedProject(Projects.BUILD)).getRepositoryName();
Map<String, Object> parameters = newUrlTemplateVariables();
parameters.put("repoName", repositoryName);
@@ -693,7 +686,8 @@ public class GitHub extends GitHubSupport implements IssueTracker {
String referenceDocUrl = documentation.getReferenceDocUrl();
String apiDocUrl = documentation.getApiDocUrl();
String reference = String.format("* [%s %s Reference documentation](%s)", module.getProject().getFullName(),
String reference = String.format("* [%s %s Reference documentation](%s)",
module.getProject().getFullName(),
module.getVersion().toString(), referenceDocUrl);
String apidoc = String.format("* [%s %s Javadoc](%s)", module.getProject().getFullName(),
@@ -704,7 +698,7 @@ public class GitHub extends GitHubSupport implements IssueTracker {
private void createOrUpdateRelease(ModuleIteration module, String body) {
String repositoryName = GitProject.of(module.getProject()).getRepositoryName();
String repositoryName = GitProject.of(module).getRepositoryName();
Tag tag = VersionTags.empty(module.getProject()).createTag(module);
logger.log(module, "Looking up GitHub Release …");
@@ -764,7 +758,7 @@ public class GitHub extends GitHubSupport implements IssueTracker {
private Stream<GitHubReadIssue> getIssuesFor(ModuleIteration moduleIteration, boolean forCurrentUser,
boolean ignoreMissingMilestone) {
String repositoryName = GitProject.of(moduleIteration.getProject()).getRepositoryName();
String repositoryName = GitProject.of(moduleIteration).getRepositoryName();
Optional<Milestone> optionalMilestone = findMilestone(moduleIteration);

View File

@@ -31,7 +31,9 @@ import org.springframework.data.release.issues.IssueTracker;
import org.springframework.data.release.issues.TicketReference;
import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.model.Tracker;
import org.springframework.data.release.model.Train;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.data.release.utils.ExecutionUtils;
import org.springframework.plugin.core.PluginRegistry;
@@ -48,15 +50,17 @@ import org.springframework.shell.core.annotation.CliOption;
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
public class GitHubCommands extends TimedCommand {
@NonNull PluginRegistry<IssueTracker, Project> tracker;
@NonNull PluginRegistry<IssueTracker, SupportedProject> tracker;
@NonNull GitHub gitHub;
@NonNull GitOperations git;
@NonNull GitHubLabels gitHubLabels;
@NonNull Executor executor;
@CliCommand(value = "github update labels")
public void createOrUpdateLabels(@CliOption(key = "", mandatory = true) Project project) {
gitHubLabels.createOrUpdateLabels(project);
public void createOrUpdateLabels(
@CliOption(key = "", mandatory = true) Project project,
@CliOption(key = "train", mandatory = true) Train train) {
gitHubLabels.createOrUpdateLabels(train.getSupportedProject(project));
}
@CliCommand(value = "github push")
@@ -81,9 +85,9 @@ public class GitHubCommands extends TimedCommand {
ExecutionUtils.run(executor, iteration, it -> {
if (it.getProject().getTracker() == Tracker.GITHUB) {
if (it.getSupportedProject().getProject().getTracker() == Tracker.GITHUB) {
List<String> ticketReferences = git.getTicketReferencesBetween(it.getProject(), previousIteration, iteration)
List<String> ticketReferences = git.getTicketReferencesBetween(it.getSupportedProject(), previousIteration, iteration)
.stream().map(TicketReference::getId).collect(Collectors.toList());
gitHub.createOrUpdateRelease(iteration, it, ticketReferences);
}

View File

@@ -26,7 +26,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.data.release.git.GitProject;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.utils.Logger;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
@@ -63,13 +63,15 @@ public class GitHubLabels extends GitHubSupport {
*
* @param project the project to process.
*/
public void createOrUpdateLabels(Project project) {
public void createOrUpdateLabels(SupportedProject project) {
logger.log(project, "Obtaining labels…");
Map<String, Object> parameters = Collections.singletonMap("repoName", GitProject.of(project).getRepositoryName());
Map<String, Object> parameters = Collections.singletonMap("repoName",
GitProject.of(project).getRepositoryName());
List<Label> existsOnGitHub = getLabelsFromGitHub(parameters);
LabelConfiguration configuration = ProjectLabelConfiguration.forProject(project);
LabelConfiguration configuration = ProjectLabelConfiguration.forProject(project.getProject());
List<Label> newLabels = configuration.getNewLabels(existsOnGitHub);
List<Label> existingLabels = configuration.getExistingLabels(existsOnGitHub);
List<Label> additionalLabels = configuration.getAdditionalLabels(existsOnGitHub);

View File

@@ -41,7 +41,9 @@ class GithubMilestone {
*/
@Override
public String toString() {
return module.getProject().isUseShortVersionMilestones() ? module.getReleaseVersionString()
return module.getSupportedProject().getProject().isUseShortVersionMilestones()
? module.getReleaseVersionString()
: module.getMediumVersionString();
}
}

View File

@@ -37,11 +37,9 @@ class Milestone {
public boolean matches(ModuleIteration moduleIteration) {
if (moduleIteration.getProject().isUseShortVersionMilestones()) {
return title.equals(moduleIteration.getReleaseVersionString());
}
return title.contains(moduleIteration.getShortVersionString());
return moduleIteration.getSupportedProject().getProject().isUseShortVersionMilestones()
? title.equals(moduleIteration.getReleaseVersionString())
: title.contains(moduleIteration.getShortVersionString());
}
@JsonIgnore

View File

@@ -39,7 +39,7 @@ public class ReleaseOperations {
iteration.stream().forEach(module -> {
boolean processed = workspace.processFile("src/main/resources/notice.txt", module.getProject(),
boolean processed = workspace.processFile("src/main/resources/notice.txt", module.getSupportedProject(),
(line, number) -> Optional.of(number != 0 ? line : module.toString()));
if (processed) {

View File

@@ -0,0 +1,24 @@
/*
* Copyright 2024 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.data.release.model;
/**
* @author Oliver Drotbohm
*/
public interface IterationAware {
Iteration getIteration();
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2024 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.data.release.model;
/**
* @author Oliver Drotbohm
*/
public interface Lifecycle extends IterationAware, SupportStatusAware {
default boolean isPublic() {
return getIteration().isPublic()
&& getSupportStatus().isOpenSource();
}
}

View File

@@ -27,7 +27,7 @@ import org.springframework.util.Assert;
*/
@Value
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Module implements VersionAware, ProjectAware, Comparable<Module> {
public class Module implements VersionAware, Comparable<Module> {
Project project;
Version version;

View File

@@ -25,7 +25,7 @@ import lombok.RequiredArgsConstructor;
*/
@RequiredArgsConstructor
@EqualsAndHashCode
public class ModuleIteration implements IterationVersion, ProjectAware {
public class ModuleIteration implements IterationVersion, ProjectAware, Lifecycle {
private final @Getter Module module;
private final @Getter TrainIteration trainIteration;
@@ -42,8 +42,8 @@ public class ModuleIteration implements IterationVersion, ProjectAware {
}
@Override
public Project getProject() {
return module.getProject();
public SupportedProject getSupportedProject() {
return trainIteration.getSupportedProject(module);
}
/*
@@ -152,6 +152,10 @@ public class ModuleIteration implements IterationVersion, ProjectAware {
return result.concat(" (").concat(trainIteration.toString()).concat(")");
}
public SupportStatus getSupportStatus() {
return getTrain().getSupportStatus();
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()

View File

@@ -0,0 +1,24 @@
/*
* Copyright 2024 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.data.release.model;
/**
* @author Oliver Drotbohm
*/
public interface Named {
String getName();
}

View File

@@ -35,7 +35,7 @@ import org.springframework.util.Assert;
*/
@ToString
@EqualsAndHashCode
public class Project implements Comparable<Project> {
public class Project implements Comparable<Project>, Named {
private final @Getter ProjectKey key;
private final @Getter String name;
@@ -125,6 +125,10 @@ public class Project implements Comparable<Project> {
.collect(Collectors.toSet());
}
public String getProjectDescriptor() {
return this == Projects.BUILD ? "parent/pom.xml" : "pom.xml";
}
/*
* (non-Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 the original author or authors.
* Copyright 2019-2024 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.
@@ -19,9 +19,13 @@ package org.springframework.data.release.model;
* An object that is aware of a {@link Project}. Typically implemented by {@link Module} or {@link ModuleIteration}.
*
* @author Mark Paluch
* @author Oliver Drotbohm
*/
public interface ProjectAware {
public interface ProjectAware extends SupportStatusAware {
Project getProject();
SupportedProject getSupportedProject();
default Project getProject() {
return getSupportedProject().getProject();
}
}

View File

@@ -34,20 +34,40 @@ public class ReleaseTrains {
static {
CODD = codd();
DIJKSTRA = dijkstra();
EVANS = DIJKSTRA.next("Evans", Transition.MINOR);
FOWLER = EVANS.next("Fowler", Transition.MINOR);
GOSLING = FOWLER.next("Gosling", Transition.MINOR, new Module(KEY_VALUE, "1.0"));
HOPPER = GOSLING.next("Hopper", Transition.MINOR, new Module(SOLR, "2.0"), new Module(ENVERS, "1.0"),
new Module(NEO4J, "4.1"), new Module(COUCHBASE, "2.1"), new Module(ELASTICSEARCH, "2.0"));
INGALLS = HOPPER.next("Ingalls", Transition.MINOR, new Module(LDAP, "1.0"));
CODD = codd()
.withSupportStatus(SupportStatus.EOL);
DIJKSTRA = dijkstra()
.withSupportStatus(SupportStatus.EOL);
EVANS = DIJKSTRA.next("Evans", Transition.MINOR)
.withSupportStatus(SupportStatus.EOL);
FOWLER = EVANS.next("Fowler", Transition.MINOR)
.withSupportStatus(SupportStatus.EOL);
GOSLING = FOWLER.next("Gosling", Transition.MINOR,
new Module(KEY_VALUE, "1.0"))
.withSupportStatus(SupportStatus.EOL);
HOPPER = GOSLING.next("Hopper", Transition.MINOR,
new Module(SOLR, "2.0"),
new Module(ENVERS, "1.0"),
new Module(NEO4J, "4.1"),
new Module(COUCHBASE, "2.1"),
new Module(ELASTICSEARCH, "2.0"))
.withSupportStatus(SupportStatus.EOL);
KAY = INGALLS.next("Kay", Transition.MAJOR, new Module(GEODE, "2.0"));
INGALLS = HOPPER.next("Ingalls", Transition.MINOR,
new Module(LDAP, "1.0"))
.withSupportStatus(SupportStatus.EOL);
LOVELACE = KAY.next("Lovelace", Transition.MINOR, new Module(JDBC, "1.0"), new Module(SOLR, "4.0"));
KAY = INGALLS.next("Kay", Transition.MAJOR,
new Module(GEODE, "2.0")) //
.withSupportStatus(SupportStatus.EOL);
MOORE = LOVELACE.next("Moore", Transition.MINOR);
LOVELACE = KAY.next("Lovelace", Transition.MINOR, //
new Module(JDBC, "1.0"), //
new Module(SOLR, "4.0")) //
.withSupportStatus(SupportStatus.EOL);
MOORE = LOVELACE.next("Moore", Transition.MINOR)
.withSupportStatus(SupportStatus.EOL);
NEUMANN = MOORE.next("Neumann", Transition.MINOR, //
new Module(COUCHBASE, "4.0"), //
@@ -56,21 +76,28 @@ public class ReleaseTrains {
new Module(MONGO_DB, "3.0"), //
new Module(JDBC, "2.0"), //
new Module(R2DBC, "1.1")) //
.filterModules(module -> !module.getProject().getName().equalsIgnoreCase("GemFire"));
.filterModules(module -> !module.getProject().getName().equalsIgnoreCase("GemFire"))
.withSupportStatus(SupportStatus.EOL);
OCKHAM = NEUMANN.next("Ockham", Transition.MINOR, //
new Module(BOM, "2020.0.0"), //
new Module(NEO4J, "6.0") //
).withIterations(Train.Iterations.DEFAULT).withCalver("2020.0");
).withIterations(Train.Iterations.DEFAULT)
.withCalver("2020.0") //
.withSupportStatus(SupportStatus.EOL);
PASCAL = OCKHAM.next("Pascal", Transition.MINOR) //
.filterModules(module -> !module.getProject().equals(SOLR)).withCalver("2021.0");
.filterModules(module -> !module.getProject().equals(SOLR)) //
.withCalver("2021.0") //
.withSupportStatus(SupportStatus.EOL);
Q = PASCAL.next("Q", Transition.MINOR) //
.withCalver("2021.1");
.withCalver("2021.1") //
.withSupportStatus(SupportStatus.EOL);
RAJ = Q.next("Raj", Transition.MINOR) //
.withCalver("2021.2");
.withCalver("2021.2") //
.withSupportStatus(SupportStatus.COMMERCIAL);
TURING = PASCAL.next("Turing", Transition.MAJOR, //
new Module(RELATIONAL, "3.0")) //
@@ -78,7 +105,8 @@ public class ReleaseTrains {
.filterModules(module -> !module.getProject().equals(ENVERS))
.filterModules(module -> !module.getProject().equals(GEODE))
.filterModules(module -> !module.getProject().equals(R2DBC))
.filterModules(module -> !module.getProject().equals(JDBC)); // filter "old" JDBC without R2DBC submodule
.filterModules(module -> !module.getProject().equals(JDBC)) // filter "old" JDBC without R2DBC submodule
.withSupportStatus(SupportStatus.COMMERCIAL);
ULLMAN = TURING.next("Ullman", Transition.MINOR) //
.withCalver("2023.0");
@@ -157,4 +185,8 @@ public class ReleaseTrains {
public static List<Train> trains() {
return TRAINS;
}
public static Train latest() {
return TRAINS.get(TRAINS.size() - 1);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2024 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.data.release.model;
/**
* @author Oliver Drotbohm
*/
public enum SupportStatus implements SupportStatusAware {
OSS, COMMERCIAL, EOL;
public boolean isOpenSource() {
return this == OSS;
}
public boolean isCommercial() {
return this == COMMERCIAL;
}
public boolean isEndOfLife() {
return this == EOL;
}
/*
* (non-Javadoc)
* @see org.springframework.data.release.model.SupportStatusAware#getSupportStatus()
*/
@Override
public SupportStatus getSupportStatus() {
return this;
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2024 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.data.release.model;
/**
* @author Oliver Drotbohm
*/
public interface SupportStatusAware {
SupportStatus getSupportStatus();
default boolean isOpenSource() {
return getSupportStatus().isOpenSource();
}
default boolean isCommercial() {
return getSupportStatus().isCommercial();
}
default boolean isEndOfLife() {
return getSupportStatus().isEndOfLife();
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2024 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.data.release.model;
import lombok.Value;
/**
* @author Oliver Drotbohm
*/
@Value(staticConstructor = "of")
public class SupportedProject implements Named, ProjectAware {
Project project;
SupportStatus status;
public String getFolderName() {
return status.name().toLowerCase() + "/" + project.getFolderName();
}
public String getName() {
return project.getName();
}
@Override
public String toString() {
return project.getFullName() + " (" + status.name() + ")";
}
@Override
public SupportedProject getSupportedProject() {
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.release.model.SupportStatusAware#getSupportStatus()
*/
@Override
public SupportStatus getSupportStatus() {
return status;
}
}

View File

@@ -46,7 +46,7 @@ import org.springframework.util.Assert;
@Value
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@EqualsAndHashCode(of = "name")
public class Train implements Streamable<Module> {
public class Train implements Streamable<SupportedProject>, SupportStatusAware {
private final String name;
private final Modules modules;
@@ -54,7 +54,7 @@ public class Train implements Streamable<Module> {
private @With Iterations iterations;
private @With boolean alwaysUseBranch;
private JavaVersion javaVersion;
private @With SupportStatus supportStatus;
private @With DocumentationFormat documentationFormat;
public Train(String name, Module... modules) {
@@ -63,16 +63,7 @@ public class Train implements Streamable<Module> {
public Train(String name, Collection<Module> modules) {
this(name, Modules.of(modules), null, Iterations.DEFAULT, false, JavaVersion.VERSION_1_8,
DocumentationFormat.ASCIIDOC);
}
/*
* (non-Javadoc)
* @see java.lang.Iterable#iterator()
*/
@Override
public Iterator<Module> iterator() {
return modules.iterator();
SupportStatus.OSS, DocumentationFormat.ASCIIDOC);
}
public boolean contains(Project project) {
@@ -107,7 +98,9 @@ public class Train implements Streamable<Module> {
Assert.notNull(project, "Project must not be null!");
return modules.stream().filter(module -> module.getProject().equals(project)).findFirst();
return modules.stream() //
.filter(module -> module.getProject().equals(project)) //
.findFirst();
}
/**
@@ -127,12 +120,13 @@ public class Train implements Streamable<Module> {
(it, additionalModule) -> it.hasSameProjectAs(additionalModule) ? additionalModule : it))
.collect(Collectors.toSet());
return new Train(name, Modules.of(modules), calver, iterations, false, javaVersion, documentationFormat);
return new Train(name, Modules.of(modules), calver, iterations, false, javaVersion, SupportStatus.OSS,
documentationFormat);
}
public Train filterModules(Predicate<Module> filterPredicate) {
return new Train(name, Modules.of(getModules().stream().filter(filterPredicate).collect(Collectors.toList())),
calver, iterations, alwaysUseBranch, javaVersion, documentationFormat);
calver, iterations, alwaysUseBranch, javaVersion, supportStatus, documentationFormat);
}
/**
@@ -193,7 +187,8 @@ public class Train implements Streamable<Module> {
}).collect(Collectors.toSet());
return new Train(name, Modules.of(modules), calver, iterations, alwaysUseBranch, javaVersion, documentationFormat);
return new Train(name, Modules.of(modules), calver, iterations, alwaysUseBranch, javaVersion, supportStatus,
documentationFormat);
}
/**
@@ -256,10 +251,36 @@ public class Train implements Streamable<Module> {
return doGetTrainIteration(iteration);
}
public SupportedProject getSupportedProject(Project project) {
return SupportedProject.of(project, supportStatus);
}
public SupportedProject getSupportedProject(Module module) {
return SupportedProject.of(module.getProject(), supportStatus);
}
protected TrainIteration doGetTrainIteration(Iteration iteration) {
return new TrainIteration(this, iteration);
}
/**
* Returns all {@link SupportedProject} instances part of the current {@link Train}.
*
* @return will never be {@literal null}.
*/
public Streamable<SupportedProject> allProjects() {
return modules.map(this::getSupportedProject);
}
/*
* (non-Javadoc)
* @see java.lang.Iterable#iterator()
*/
@Override
public Iterator<SupportedProject> iterator() {
return modules.map(this::getSupportedProject).iterator();
}
/**
* Value object to represent a set of {@link Iteration}s.
*

View File

@@ -28,7 +28,7 @@ import org.springframework.data.util.Streamable;
*/
@Value
@RequiredArgsConstructor
public class TrainIteration implements Streamable<ModuleIteration> {
public class TrainIteration implements Streamable<ModuleIteration>, Lifecycle {
private final Train train;
private final Iteration iteration;
@@ -84,11 +84,19 @@ public class TrainIteration implements Streamable<ModuleIteration> {
return getCalver().toMajorMinorBugfix();
}
if (iteration.isGAIteration()) {
return String.format("%s-RELEASE", getTrain().getName());
}
String trainName = getTrain().getName();
return String.format("%s-%s", getTrain().getName(), iteration);
return iteration.isGAIteration()
? String.format("%s-RELEASE", trainName)
: String.format("%s-%s", trainName, iteration);
}
public SupportedProject getSupportedProject(Project project) {
return train.getSupportedProject(project);
}
public SupportedProject getSupportedProject(Module module) {
return train.getSupportedProject(module);
}
/*
@@ -124,4 +132,13 @@ public class TrainIteration implements Streamable<ModuleIteration> {
return version.toMajorMinorBugfix();
}
/*
* (non-Javadoc)
* @see org.springframework.data.release.model.SupportStatusAware#getSupportStatus()
*/
@Override
public SupportStatus getSupportStatus() {
return train.getSupportStatus();
}
}

View File

@@ -96,6 +96,7 @@ class MaintainedVersion implements Comparable<MaintainedVersion> {
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return String.format("%s - %s - %s", project.getName(), train.getName(), version);
}

View File

@@ -19,9 +19,7 @@ import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -29,7 +27,6 @@ import java.util.stream.Stream;
import org.springframework.data.release.CliComponent;
import org.springframework.data.release.TimedCommand;
import org.springframework.data.release.git.GitOperations;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.ReleaseTrains;
import org.springframework.data.release.model.Train;
import org.springframework.data.release.utils.ExecutionUtils;
@@ -63,15 +60,10 @@ class ProjectServiceCommands extends TimedCommand {
public void updateProjectInformation(@CliOption(key = "", mandatory = true) String trainNames) {
List<Train> trains = Stream.of(trainNames.split(","))//
.map(ReleaseTrains::getTrainByName) //
.map(ReleaseTrains::getTrainByName)
.collect(Collectors.toList());
// ensure we have all git repositories available
Set<Project> affectedProjects = new HashSet<>();
trains.stream() //
.flatMap(Streamable::stream) //
.forEach(it -> affectedProjects.add(it.getProject()));
ExecutionUtils.run(executor, Streamable.of(affectedProjects), git::update);
ExecutionUtils.run(executor, Streamable.of(trains), git::update);
projects.updateProjectMetadata(trains);
}

View File

@@ -36,6 +36,7 @@ import org.springframework.data.release.git.Tag;
import org.springframework.data.release.model.Module;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.model.Train;
import org.springframework.data.release.model.Version;
import org.springframework.data.release.utils.ExecutionUtils;
@@ -76,7 +77,15 @@ class ProjectServiceOperations {
Assert.notNull(trains, "Trains must not be null!");
Map<Project, MaintainedVersions> versions = findVersions(trains);
List<Train> openSourceTrains = trains.stream()
.filter(it -> it.getSupportStatus().isOpenSource())
.collect(Collectors.toList());
if (openSourceTrains.isEmpty()) {
return;
}
Map<Project, MaintainedVersions> versions = findVersions(openSourceTrains);
Streamable<Entry<Project, MaintainedVersions>> stream = Streamable.of(versions.entrySet()) //
.filter(entry -> {
@@ -118,17 +127,21 @@ class ProjectServiceOperations {
Assert.notNull(trains, "Trains must not be null!");
Map<Project, MaintainedVersions> versions = ExecutionUtils.runAndReturn(executor, Streamable.of(trains), train -> {
return ExecutionUtils.runAndReturn(executor,
Streamable.of(() -> train.stream().filter(module -> !TO_FILTER.contains(module.getProject()))), module -> {
return getLatestVersion(module, train);
});
}).stream().flatMap(Collection::stream).flatMap(Collection::stream).collect(
Collectors.groupingBy(MaintainedVersion::getProject, ListWrapperCollector.collectInto(MaintainedVersions::of)));
train.getModules().filter(module -> !TO_FILTER.contains(module.getProject())),
module -> getLatestVersion(module, train));
}).stream()
.flatMap(Collection::stream)
.flatMap(Collection::stream)
.collect(
Collectors.groupingBy(MaintainedVersion::getProject,
ListWrapperCollector.collectInto(MaintainedVersions::of)));
// Migration because of the R2DBC merge into Spring Data Relational and project rename to Relational
versions.put(Projects.R2DBC, MaintainedVersions.of(getR2dbcVersions(versions)));
versions.put(Projects.RELATIONAL, MaintainedVersions.of(getRelationalVersions(versions)));
versions.remove(Projects.JDBC);
return versions;
@@ -181,12 +194,13 @@ class ProjectServiceOperations {
private List<MaintainedVersion> getLatestVersion(Module module, Train train) {
Project project = module.getProject();
SupportedProject project = train.getSupportedProject(module);
List<MaintainedVersion> version = git.getTags(project).stream()//
.filter(tag -> matches(tag, module.getVersion())).max(Comparator.naturalOrder()) //
.map(it -> {
MaintainedVersion maintainedVersion = MaintainedVersion.of(module.getProject(), it.toArtifactVersion().get(),
MaintainedVersion maintainedVersion = MaintainedVersion.of(module.getProject(),
it.toArtifactVersion().get(),
train, it.getCreationDate().toLocalDate(), it.getCreationDate().toLocalDate());
return Arrays.asList(maintainedVersion, maintainedVersion.nextDevelopmentVersion());
}) //

View File

@@ -16,7 +16,9 @@
package org.springframework.data.release.utils;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Named;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.model.Train;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.shell.support.logging.HandlerUtils;
@@ -34,7 +36,11 @@ public class Logger {
private final java.util.logging.Logger LOGGER = HandlerUtils.getLogger(getClass());
public void log(ModuleIteration module, Object template, Object... args) {
log(module.getProject(), template, args);
log(module.getSupportedProject(), template, args);
}
public void log(SupportedProject project, Object template, Object... args) {
log(project.getProject(), template, args);
}
public void log(Project project, Object template, Object... args) {
@@ -54,10 +60,10 @@ public class Logger {
}
public void warn(ModuleIteration module, Object template, Object... args) {
warn(module.getProject(), template, args);
warn(module.getSupportedProject(), template, args);
}
public void warn(Project project, Object template, Object... args) {
public void warn(Named project, Object template, Object... args) {
warn(project.getName(), template, args);
}

View File

@@ -6,11 +6,17 @@ git.gpg.keyname=300E596E
git.gpg.passphrase=${GIT_SIGNING_KEY_PASSWORD}
#git.gpg.executable=/usr/bin/gpg
deployment.username=${REPO_SPRING_IO_USR}
deployment.password=${REPO_SPRING_IO_PSW}
deployment.api-key=${REPO_SPRING_IO_PSW}
# Spring OpenSource Artifactory
deployment.opensource.username=${REPO_SPRING_IO_USR}
deployment.opensource.password=${REPO_SPRING_IO_PSW}
deployment.opensource.api-key=${REPO_SPRING_IO_PSW}
deployment.settings-xml=${SETTINGS_XML}
# Spring Commercial Artifactory
deployment.commercial.username=${COMMERCIAL_USR}
deployment.commercial.password=${COMMERCIAL_PSW}
deployment.commercial.api-key=${COMMERCIAL_PSW}
deployment.maven-central.stagingProfileId=${STAGING_PROFILE_ID}
deployment.maven-central.gpg.keyname=003C0425

View File

@@ -4,13 +4,41 @@ io.logs=logs
# Maven setup
maven.local-repository=~/temp/spring-data-shell/repository
maven.plugins.versions=org.codehaus.mojo:versions-maven-plugin:2.2
maven.plugins.versions=org.codehaus.mojo:versions-maven-plugin:2.16.2
maven.console-logger=true
deployment.server.uri=https://repo.spring.io
deployment.staging-repository=libs-staging-local
deployment.distribution-repository=temp-private-local
deployment.username=buildmaster
#deployment.password <- local
# Spring OpenSource Artifactory
deployment.opensource.server.uri=https://repo.spring.io
deployment.opensource.server.verification-resource=temp-private-local
deployment.opensource.staging-repository=libs-staging-local
deployment.opensource.target-repository=libs-milestone-local
deployment.opensource.distribution-repository=temp-private-local
# deployment.opensource.username <- local, for build
# deployment.opensource.password <- local, for build
# deployment.opensource.api-key <- local, for promotion
# Spring Commercial Artifactory
# Test
# deployment.commercial.server.uri=https://repo.spring.vmware.com
# deployment.commercial.staging-repository=test-staging-local
# deployment.commercial.target-repository=test-release-local
# deployment.commercial.project=test
# deployment.commercial.distribution-repository=
# deployment.commercial.username <- local, for build
# deployment.commercial.password <- local, for build
# deployment.commercial.api-key <- local, for promotion
# Prod
deployment.commercial.server.uri=https://repo.spring.vmware.com
deployment.commercial.server.verification-resource=test-staging-local
deployment.commercial.staging-repository=spring-commercial-staging-local
deployment.commercial.target-repository=spring-commercial-release-local
deployment.commercial.project=spring
# deployment.commercial.distribution-repository=
# deployment.commercial.username <- local, for build
# deployment.commercial.password <- local, for build
# deployment.commercial.api-key <- local, for promotion
github.team=christophstrobl,gregturn,jxblum,mp911de,odrotbohm,schauder,meistermeier,michael-simons,sothawo,daschl,mikereiche,davidkelly,sxhinzvc
# GPG setup
gpg.executable=/usr/local/bin/gpg2

View File

@@ -26,7 +26,6 @@ import java.net.URLConnection;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.release.AbstractIntegrationTests;
@@ -34,7 +33,7 @@ import org.springframework.data.release.git.GitOperations;
import org.springframework.data.release.io.Workspace;
import org.springframework.data.release.model.ArtifactVersion;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.ReleaseTrains;
import org.xmlbeam.ProjectionFactory;
import org.xmlbeam.evaluation.XPathEvaluator;
import org.xmlbeam.io.FileIO;
@@ -92,7 +91,7 @@ class MavenIntegrationTests extends AbstractIntegrationTests {
@Test
void findsSnapshotDependencies() throws Exception {
File file = workspace.getFile("pom.xml", Projects.BUILD);
File file = workspace.getFile("pom.xml", ReleaseTrains.latest().getSupportedProject(Projects.BUILD));
assumeThat(file).exists();

View File

@@ -15,7 +15,6 @@
*/
package org.springframework.data.release.cli;
import static org.assertj.core.api.Assertions.*;
import static org.assertj.core.api.Assumptions.*;
import java.io.IOException;
@@ -24,12 +23,9 @@ import java.net.URLConnection;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.release.AbstractIntegrationTests;
import org.springframework.data.release.git.GitOperations;
import org.springframework.data.release.model.ReleaseTrains;
/**
* @author Oliver Gierke
@@ -52,12 +48,4 @@ class ReleaseCommandsIntegrationTests extends AbstractIntegrationTests {
assumeThat(false).as("Test requires connectivity to GitHub:" + e.toString()).isTrue();
}
}
@Test
void predictsReleaseTrainCorrectly() throws Exception {
git.update(ReleaseTrains.MOORE);
assertThat(releaseCommands.predictTrainAndIteration()).isEqualTo("Neumann");
}
}

View File

@@ -26,12 +26,12 @@ import java.net.URLConnection;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.release.AbstractIntegrationTests;
import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.ReleaseTrains;
import org.springframework.data.release.model.TestReleaseTrains;
import org.springframework.data.release.model.Train;
import org.springframework.data.release.model.TrainIteration;
/**
@@ -41,6 +41,8 @@ import org.springframework.data.release.model.TrainIteration;
@Disabled
class GitOperationsIntegrationTests extends AbstractIntegrationTests {
private static Train LATEST = ReleaseTrains.latest();
@Autowired GitOperations gitOperations;
@BeforeAll
@@ -66,7 +68,7 @@ class GitOperationsIntegrationTests extends AbstractIntegrationTests {
gitOperations.update(TestReleaseTrains.SAMPLE);
assertThat(gitOperations.getTags(BUILD).asList()).isNotEmpty();
assertThat(gitOperations.getTags(LATEST.getSupportedProject(BUILD)).asList()).isNotEmpty();
}
@Test
@@ -76,7 +78,7 @@ class GitOperationsIntegrationTests extends AbstractIntegrationTests {
@Test
void obtainsVersionTagsForRepoThatAlsoHasOtherTags() {
gitOperations.getTags(MONGO_DB);
gitOperations.getTags(LATEST.getSupportedProject(MONGO_DB));
}
@Test

View File

@@ -18,9 +18,7 @@ package org.springframework.data.release.git;
import static org.assertj.core.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.springframework.data.release.model.Module;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.ReleaseTrains;
import org.springframework.data.release.model.Train;
@@ -38,9 +36,8 @@ class GitProjectUnitTests {
Train codd = ReleaseTrains.CODD;
GitServer server = new GitServer();
Module module = codd.getModule(Projects.COMMONS);
Project project = module.getProject();
GitProject gitProject = new GitProject(project, server);
GitProject gitProject = GitProject.of(codd.getSupportedProject(module));
String projectUri = gitProject.getProjectUri();

View File

@@ -26,13 +26,13 @@ import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.release.AbstractIntegrationTests;
import org.springframework.data.release.git.GitOperations;
import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.ReleaseTrains;
import org.springframework.data.release.model.Train;
/**
* Integration tests for {@link DependencyOperations}.
@@ -42,6 +42,8 @@ import org.springframework.data.release.model.ReleaseTrains;
@Disabled
class DependencyOperationsIntegrationTests extends AbstractIntegrationTests {
private static final Train LATEST = ReleaseTrains.latest();
@Autowired GitOperations git;
@Autowired DependencyOperations operations;
@@ -69,19 +71,22 @@ class DependencyOperationsIntegrationTests extends AbstractIntegrationTests {
@Test
void shouldReportExistingDependencyVersions() {
assertThat(operations.getCurrentDependencies(Projects.BUILD).isEmpty()).isFalse();
assertThat(operations.getCurrentDependencies(LATEST.getSupportedProject(Projects.BUILD)).isEmpty()).isFalse();
}
@Test
void shouldReportExistingOptionalDependencies() {
assertThat(operations.getCurrentDependencies(Projects.CASSANDRA).getVersions()).hasSize(1);
assertThat(operations.getCurrentDependencies(Projects.MONGO_DB).getVersions()).hasSize(2);
assertThat(operations.getCurrentDependencies(Projects.NEO4J).getVersions()).hasSize(1);
assertThat(operations.getCurrentDependencies(LATEST.getSupportedProject(Projects.CASSANDRA)).getVersions())
.hasSize(1);
assertThat(operations.getCurrentDependencies(LATEST.getSupportedProject(Projects.MONGO_DB)).getVersions())
.hasSize(2);
assertThat(operations.getCurrentDependencies(LATEST.getSupportedProject(Projects.NEO4J)).getVersions()).hasSize(1);
}
@Test
void getUpgradeProposals() {
System.out.println(operations.getDependencyUpgradeProposals(Projects.BUILD, Iteration.M1));
System.out
.println(operations.getDependencyUpgradeProposals(LATEST.getSupportedProject(Projects.BUILD), Iteration.M1));
}
}

View File

@@ -26,7 +26,6 @@ import java.util.Collections;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.release.AbstractIntegrationTests;
import org.springframework.data.release.WireMockExtension;
@@ -35,6 +34,7 @@ import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.ReleaseTrains;
import org.springframework.data.release.model.Train;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.util.UriComponents;
@@ -55,6 +55,7 @@ class GitHubIssueTrackerIntegrationTests extends AbstractIntegrationTests {
static final String MILESTONES_URI = "/repos/spring-projects/spring-data-build/milestones";
static final ModuleIteration BUILD_HOPPER_RC1 = ReleaseTrains.HOPPER.getModuleIteration(Projects.BUILD,
Iteration.RC1);
static final Train LATEST = ReleaseTrains.latest();
@RegisterExtension WireMockExtension mockService = new WireMockExtension(
wireMockConfig().port(8888).fileSource(new ClasspathFileSource("integration/github")));
@@ -76,21 +77,25 @@ class GitHubIssueTrackerIntegrationTests extends AbstractIntegrationTests {
mockGetIssueWith("issue.json", 233);
Collection<Ticket> tickets = github.findTickets(Projects.BUILD, Collections.singletonList("233"));
Collection<Ticket> tickets = github.findTickets(LATEST.getSupportedProject(Projects.BUILD),
Collections.singletonList("233"));
assertThat(tickets).hasSize(1);
}
@Test // #5
void ignoresUnknownTicketsByTicketId() {
Collection<Ticket> tickets = github.findTickets(Projects.BUILD, Collections.singletonList("123"));
Collection<Ticket> tickets = github.findTickets(LATEST.getSupportedProject(Projects.BUILD),
Collections.singletonList("123"));
assertThat(tickets).isEmpty();
}
@Test // #5
void emptyResultWithEmptyTicketIds() {
Collection<Ticket> tickets = github.findTickets(Projects.COMMONS, Collections.emptyList());
Collection<Ticket> tickets = github.findTickets(LATEST.getSupportedProject(Projects.COMMONS),
Collections.emptyList());
assertThat(tickets).isEmpty();
}

View File

@@ -22,7 +22,6 @@ import java.util.stream.Collectors;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.release.AbstractIntegrationTests;
import org.springframework.data.release.git.GitOperations;
@@ -30,9 +29,9 @@ import org.springframework.data.release.issues.IssueTracker;
import org.springframework.data.release.issues.TicketReference;
import org.springframework.data.release.issues.Tickets;
import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.Projects;
import org.springframework.data.release.model.ReleaseTrains;
import org.springframework.data.release.model.SupportedProject;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.plugin.core.PluginRegistry;
@@ -44,7 +43,7 @@ import org.springframework.plugin.core.PluginRegistry;
@Disabled("Requires changes to application-test.properties to enable remote GitHub/Jira access")
class ReleaseOperationsIntegrationTests extends AbstractIntegrationTests {
@Autowired PluginRegistry<IssueTracker, Project> trackers;
@Autowired PluginRegistry<IssueTracker, SupportedProject> trackers;
@Autowired GitOperations gitOperations;
@@ -54,8 +53,10 @@ class ReleaseOperationsIntegrationTests extends AbstractIntegrationTests {
TrainIteration from = ReleaseTrains.OCKHAM.getIteration(Iteration.M1);
TrainIteration to = ReleaseTrains.OCKHAM.getIteration(Iteration.M2);
List<TicketReference> ticketReferences = gitOperations.getTicketReferencesBetween(Projects.MONGO_DB, from, to);
IssueTracker tracker = trackers.getRequiredPluginFor(Projects.MONGO_DB);
SupportedProject project = from.getSupportedProject(Projects.MONGO_DB);
List<TicketReference> ticketReferences = gitOperations.getTicketReferencesBetween(project, from, to);
IssueTracker tracker = trackers.getRequiredPluginFor(project);
Tickets tickets = tracker.findTickets(to.getModule(Projects.MONGO_DB),
ticketReferences.stream().map(TicketReference::getId).collect(Collectors.toList()));
@@ -69,8 +70,10 @@ class ReleaseOperationsIntegrationTests extends AbstractIntegrationTests {
TrainIteration from = ReleaseTrains.OCKHAM.getIteration(Iteration.M1);
TrainIteration to = ReleaseTrains.OCKHAM.getIteration(Iteration.M2);
List<TicketReference> ticketReferences = gitOperations.getTicketReferencesBetween(Projects.R2DBC, from, to);
IssueTracker tracker = trackers.getRequiredPluginFor(Projects.R2DBC);
SupportedProject project = from.getSupportedProject(Projects.R2DBC);
List<TicketReference> ticketReferences = gitOperations.getTicketReferencesBetween(project, from, to);
IssueTracker tracker = trackers.getRequiredPluginFor(project);
Tickets tickets = tracker.findTickets(to.getModule(Projects.R2DBC),
ticketReferences.stream().map(TicketReference::getId).collect(Collectors.toList()));