diff --git a/release-tools/application-local.template b/release-tools/application-local.template
new file mode 100644
index 0000000..57d53ff
--- /dev/null
+++ b/release-tools/application-local.template
@@ -0,0 +1,11 @@
+# Git
+git.username=
+git.author=
+git.email=
+git.password=
+
+# Maven
+maven.mavenHome=
+
+# Deployment
+deployment.password=
diff --git a/release-tools/lombok.config b/release-tools/lombok.config
new file mode 100644
index 0000000..71bb610
--- /dev/null
+++ b/release-tools/lombok.config
@@ -0,0 +1 @@
+lombok.nonNull.exceptionType = IllegalArgumentException
diff --git a/release-tools/pom.xml b/release-tools/pom.xml
index bc65060..56efef4 100644
--- a/release-tools/pom.xml
+++ b/release-tools/pom.xml
@@ -8,12 +8,13 @@
org.springframework.boot
spring-boot-starter-parent
- 1.3.0.RELEASE
+ 1.3.2.RELEASE
1.8
org.springframework.data.release.Application
+ 1.3.0.BUILD-SNAPSHOT
@@ -50,9 +51,9 @@
- org.xmlbeam
- xmlprojector
- 1.4.7
+ org.xmlbeam
+ xmlprojector
+ 1.4.7
@@ -64,7 +65,7 @@
org.projectlombok
lombok
- 1.16.4
+ 1.16.6
provided
@@ -81,7 +82,7 @@
org.eclipse.jgit
org.eclipse.jgit
- 4.0.1.201506240215-r
+ 4.2.0.201601211800-r
@@ -89,6 +90,19 @@
spring-boot-configuration-processor
true
+
+
+ org.apache.maven.shared
+ maven-invoker
+ 2.2
+
+
+
+ org.jgrapht
+ jgrapht-core
+ 0.9.1
+
+
diff --git a/release-tools/readme.md b/release-tools/readme.md
index 8d34a9a..b3cc1a4 100644
--- a/release-tools/readme.md
+++ b/release-tools/readme.md
@@ -1,8 +1,11 @@
1. Add an `application-local.properties` to the project root and add the following properties:
- `git.username` - Your GitHub username.
-- `git.password` - Your GitHub password.
+- `git.password` - Your GitHub password or API key.
- `git.author` - Your full name (used for preparing commits).
- `git.email` - Your email (used for preparing commits).
+- `maven.mavenHome` - Pointing to the location of your Maven installation.
+- `deployment.api-key` - The API key to use for artifact promotion.
+- `deployment.password` - The password of the deployment user (buildmaster).
2. Run `mvn package appassembler:assemble && sh target/appassembler/bin/spring-data-release-shell`
diff --git a/release-tools/src/main/java/org/springframework/data/release/Streamable.java b/release-tools/src/main/java/org/springframework/data/release/Streamable.java
new file mode 100644
index 0000000..701cb77
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/Streamable.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 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
+ *
+ * http://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;
+
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * SImple interface to ease streamability of {@link Iterable}s.
+ *
+ * @author Oliver Gierke
+ */
+public interface Streamable extends Iterable {
+
+ /**
+ * Creates a non-parallel {@link Stream} of the underlying {@link Iterable}.
+ *
+ * @return will never be {@literal null}.
+ */
+ public default Stream stream() {
+ return StreamSupport.stream(spliterator(), false);
+ }
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/announcement/AnnouncementCommands.java b/release-tools/src/main/java/org/springframework/data/release/announcement/AnnouncementCommands.java
new file mode 100644
index 0000000..61536ed
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/announcement/AnnouncementCommands.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2015 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
+ *
+ * http://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.announcement;
+
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.release.CliComponent;
+import org.springframework.data.release.model.TrainIteration;
+import org.springframework.shell.core.CommandMarker;
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+
+/**
+ * Commands to create markup to be used in announcing blog posts.
+ *
+ * @author Oliver Gierke
+ */
+@CliComponent
+@RequiredArgsConstructor(onConstructor = @__(@Autowired) )
+public class AnnouncementCommands implements CommandMarker {
+
+ private final @NonNull AnnouncementOperations operations;
+
+ @CliCommand("announcement")
+ public void distribute(@CliOption(key = "", mandatory = true) TrainIteration iteration) throws Exception {
+ System.out.println(operations.getProjectBulletpoints(iteration));
+ }
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/announcement/AnnouncementOperations.java b/release-tools/src/main/java/org/springframework/data/release/announcement/AnnouncementOperations.java
index 41c6b47..9e3bf08 100644
--- a/release-tools/src/main/java/org/springframework/data/release/announcement/AnnouncementOperations.java
+++ b/release-tools/src/main/java/org/springframework/data/release/announcement/AnnouncementOperations.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2014-2016 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.
@@ -17,26 +17,22 @@ package org.springframework.data.release.announcement;
import static org.springframework.data.release.model.Projects.*;
+import org.springframework.data.release.build.MavenArtifact;
import org.springframework.data.release.cli.StaticResources;
-import org.springframework.data.release.maven.Artifact;
-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.ReleaseTrains;
-import org.springframework.data.release.model.Train;
import org.springframework.data.release.model.TrainIteration;
+import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
/**
* @author Oliver Gierke
*/
+@Component
public class AnnouncementOperations {
/**
- * Returns the project list and links to be included in the release announcement for the given {@link Train} and
- * {@link Iteration}.
+ * Returns the project list and links to be included in the release announcement for the given {@link TrainIteration}.
*
- * @param train must not be {@literal null}.
* @param iteration must not be {@literal null}.
* @return
*/
@@ -46,16 +42,16 @@ public class AnnouncementOperations {
StringBuilder builder = new StringBuilder();
- for (ModuleIteration module : iteration.getModulesExcept(BUILD)) {
+ iteration.getModulesExcept(BUILD).forEach(module -> {
Project project = module.getProject();
builder.append("* ");
builder.append(project.getFullName()).append(" ");
- builder.append(module.getVersionString());
+ builder.append(module.getShortVersionString());
builder.append(" - ");
- Artifact artifact = new Artifact(module);
+ MavenArtifact artifact = new MavenArtifact(module);
builder.append(getMarkDownLink("Artifacts", artifact.getRootUrl()));
builder.append(" - ");
@@ -67,18 +63,12 @@ public class AnnouncementOperations {
builder.append(getMarkDownLink("Changelog", resources.getChangelogUrl()));
builder.append("\n");
- }
+ });
return builder.toString();
}
- private String getMarkDownLink(String name, String url) {
+ private static String getMarkDownLink(String name, String url) {
return String.format("[%s](%s)", name, url);
}
-
- public static void main(String[] args) {
-
- AnnouncementOperations operations = new AnnouncementOperations();
- System.out.println(operations.getProjectBulletpoints(new TrainIteration(ReleaseTrains.GOSLING, Iteration.SR1)));
- }
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/maven/MavenConfig.java b/release-tools/src/main/java/org/springframework/data/release/build/BuildConfiguration.java
similarity index 66%
rename from release-tools/src/main/java/org/springframework/data/release/maven/MavenConfig.java
rename to release-tools/src/main/java/org/springframework/data/release/build/BuildConfiguration.java
index 7e10646..e5d5ca7 100644
--- a/release-tools/src/main/java/org/springframework/data/release/maven/MavenConfig.java
+++ b/release-tools/src/main/java/org/springframework/data/release/build/BuildConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2016 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.
@@ -13,10 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.data.release.maven;
+package org.springframework.data.release.build;
+
+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.plugin.core.PluginRegistry;
import org.xmlbeam.ProjectionFactory;
import org.xmlbeam.XBProjector;
import org.xmlbeam.XBProjector.Flags;
@@ -24,10 +29,17 @@ import org.xmlbeam.config.DefaultXMLFactoriesConfig;
import org.xmlbeam.config.DefaultXMLFactoriesConfig.NamespacePhilosophy;
/**
+ * Spring configuration for build related components.
+ *
* @author Oliver Gierke
*/
@Configuration
-class MavenConfig {
+class BuildConfiguration {
+
+ @Bean
+ public PluginRegistry buildSystems(List extends BuildSystem> buildSystems) {
+ return OrderAwarePluginRegistry.create(buildSystems);
+ }
@Bean
public ProjectionFactory projectionFactory() {
@@ -36,8 +48,6 @@ class MavenConfig {
config.setNamespacePhilosophy(NamespacePhilosophy.AGNOSTIC);
config.setOmitXMLDeclaration(false);
- XBProjector projector = new XBProjector(config, Flags.TO_STRING_RENDERS_XML);
-
- return projector;
+ return new XBProjector(config, Flags.TO_STRING_RENDERS_XML);
}
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/build/BuildOperations.java b/release-tools/src/main/java/org/springframework/data/release/build/BuildOperations.java
new file mode 100644
index 0000000..2ab0e5e
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/build/BuildOperations.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2016 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
+ *
+ * http://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.build;
+
+import lombok.RequiredArgsConstructor;
+
+import java.util.List;
+import java.util.function.BiFunction;
+import java.util.stream.Collectors;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.release.deployment.DeploymentInformation;
+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.TrainIteration;
+import org.springframework.data.release.model.UpdateInformation;
+import org.springframework.plugin.core.PluginRegistry;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
+
+/**
+ * @author Oliver Gierke
+ */
+@Component
+@RequiredArgsConstructor(onConstructor = @__(@Autowired) )
+public class BuildOperations {
+
+ private final PluginRegistry buildSystems;
+
+ /**
+ * Updates all inter-project dependencies based on the given {@link TrainIteration} and release {@link Phase}.
+ *
+ * @param iteration must not be {@literal null}.
+ * @param phase must not be {@literal null}.
+ * @throws Exception
+ */
+ public void updateProjectDescriptors(TrainIteration iteration, Phase phase) throws Exception {
+
+ Assert.notNull(iteration, "Train iteration must not be null!");
+ Assert.notNull(phase, "Phase must not be null!");
+
+ UpdateInformation updateInformation = new UpdateInformation(iteration, phase);
+
+ doWithBuildSystem(iteration, (system, it) -> system.updateProjectDescriptors(it, updateInformation));
+ }
+
+ /**
+ * Triggers the distribution builds for all modules particitpating in the given {@link TrainIteration}.
+ *
+ * @param iteration must not be {@literal null}.
+ */
+ public void distributeResources(TrainIteration iteration) {
+
+ Assert.notNull(iteration, "Train iteration must not be null!");
+
+ doWithBuildSystem(iteration, BuildSystem::triggerDistributionBuild);
+ }
+
+ /**
+ * Performs the release build for all modules in the given {@link TrainIteration}.
+ *
+ * @param iteration must not be {@literal null}.
+ * @return
+ */
+ public List performRelease(TrainIteration iteration) {
+ return iteration.stream().map(this::performRelease).collect(Collectors.toList());
+ }
+
+ /**
+ * Performs the release build for the given {@link ModuleIteration}.
+ *
+ * @param module must not be {@literal null}.
+ * @return
+ */
+ public DeploymentInformation performRelease(ModuleIteration module) {
+
+ prepareVersion(module, Phase.PREPARE);
+ return buildAndDeployRelease(module);
+ }
+
+ /**
+ * Prepares the versions of the given {@link TrainIteration} depending on the given {@link Phase}.
+ *
+ * @param iteration must not be {@literal null}.
+ * @param phase must not be {@literal null}.
+ */
+ public void prepareVersions(TrainIteration iteration, Phase phase) {
+
+ Assert.notNull(iteration, "Train iteration must not be null!");
+ Assert.notNull(phase, "Phase must not be null!");
+
+ doWithBuildSystem(iteration, (system, module) -> system.prepareVersion(module, phase));
+ }
+
+ /**
+ * Prepares the version of the given {@link ModuleIteration} depending on the given {@link Phase}.
+ *
+ * @param iteration must not be {@literal null}.
+ * @param phase must not be {@literal null}.
+ * @return
+ */
+ public ModuleIteration prepareVersion(ModuleIteration iteration, Phase phase) {
+
+ Assert.notNull(iteration, "Module iteration must not be null!");
+ Assert.notNull(phase, "Phase must not be null!");
+
+ return doWithBuildSystem(iteration, (system, module) -> system.prepareVersion(module, phase));
+ }
+
+ /**
+ * Builds the release for the given {@link ModuleIteration} and deploys it to the staging repository.
+ *
+ * @param module must not be {@literal null}.
+ * @return
+ */
+ public DeploymentInformation buildAndDeployRelease(ModuleIteration module) {
+ return doWithBuildSystem(module, BuildSystem::deploy);
+ }
+
+ /**
+ * Selects the build system for each {@link ModuleIteration} contained in the given {@link TrainIteration} and
+ * executes the given function for it.
+ *
+ * @param iteration must not be {@literal null}.
+ * @param function must not be {@literal null}.
+ * @return
+ */
+ private List doWithBuildSystem(TrainIteration iteration,
+ BiFunction function) {
+
+ return iteration.stream()//
+ .map(module -> doWithBuildSystem(module, function))//
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Selects the build system for the module contained in the given {@link ModuleIteration} and executes the given
+ * function with it.
+ *
+ * @param module must not be {@literal null}.
+ * @param function must not be {@literal null}.
+ * @return
+ */
+ private T doWithBuildSystem(ModuleIteration module, BiFunction function) {
+ return function.apply(buildSystems.getPluginFor(module.getProject(), () -> new IllegalStateException(
+ String.format("No build system plugin found for project %s!", module.getProject()))), module);
+ }
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/build/BuildSystem.java b/release-tools/src/main/java/org/springframework/data/release/build/BuildSystem.java
new file mode 100644
index 0000000..133d56e
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/build/BuildSystem.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016 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
+ *
+ * http://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.build;
+
+import org.springframework.data.release.deployment.DeploymentInformation;
+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.UpdateInformation;
+import org.springframework.plugin.core.Plugin;
+
+/**
+ * Plugin interface to back different build systems.
+ *
+ * @author Oliver Gierke
+ */
+interface BuildSystem extends Plugin {
+
+ /**
+ * @param iteration
+ * @param train
+ * @param phase
+ * @throws Exception
+ */
+ ModuleIteration updateProjectDescriptors(ModuleIteration iteration, UpdateInformation updateInformation);
+
+ ModuleIteration prepareVersion(ModuleIteration module, Phase phase);
+
+ ModuleIteration triggerDistributionBuild(ModuleIteration module);
+
+ DeploymentInformation deploy(ModuleIteration module);
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/build/GradleBuildSystem.java b/release-tools/src/main/java/org/springframework/data/release/build/GradleBuildSystem.java
new file mode 100644
index 0000000..42ebb6c
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/build/GradleBuildSystem.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2014 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
+ *
+ * http://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.build;
+
+import static org.springframework.data.release.model.Projects.*;
+
+import lombok.RequiredArgsConstructor;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.annotation.Order;
+import org.springframework.data.release.deployment.DeploymentInformation;
+import org.springframework.data.release.deployment.DeploymentProperties;
+import org.springframework.data.release.io.Workspace;
+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.TrainIteration;
+import org.springframework.data.release.model.UpdateInformation;
+import org.springframework.data.release.utils.Logger;
+import org.springframework.stereotype.Component;
+
+/**
+ * Gradle specific operations.
+ *
+ * @author Oliver Gierke
+ */
+@Component
+@Order(200)
+@RequiredArgsConstructor(onConstructor = @__(@Autowired) )
+class GradleBuildSystem implements BuildSystem {
+
+ private static final String BUILD_GRADLE = "build.gradle";
+ private static final String GRADLE_PROPERTIES = "gradle.properties";
+ private static final String COMMONS_PROPERTY = "springDataCommonsVersion";
+ private static final String BUILD_PROPERTY = "springDataBuildVersion";
+
+ private final Workspace workspace;
+ private final Logger logger;
+ private final DeploymentProperties properties;
+
+ /**
+ * Updates all Gradle projects contained in the release.
+ *
+ * @param iteration
+ * @param phase
+ * @throws Exception
+ */
+ public void updateProject(TrainIteration iteration, final Phase phase) throws Exception {
+
+ UpdateInformation updateInformation = new UpdateInformation(iteration, phase);
+
+ for (ModuleIteration module : iteration.getModulesExcept(BUILD)) {
+ updateProjectDescriptors(module, updateInformation);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.release.build.BuildSystem#updateProjectDescriptors(org.springframework.data.release.model.ModuleIteration, org.springframework.data.release.model.UpdateInformation)
+ */
+ @Override
+ public ModuleIteration updateProjectDescriptors(ModuleIteration iteration, UpdateInformation updateInformation) {
+
+ Project project = iteration.getProject();
+ Repository repository = new Repository(iteration.getIteration());
+ ArtifactVersion commonsVersion = updateInformation.getIteration().getModuleVersion(COMMONS);
+ ArtifactVersion buildVersion = updateInformation.getIteration().getModuleVersion(BUILD);
+
+ workspace.processFile(GRADLE_PROPERTIES, project, (line, number) -> {
+
+ if (line.contains(COMMONS_PROPERTY)) {
+
+ ArtifactVersion version = updateInformation.getPhase().equals(Phase.PREPARE) ? commonsVersion
+ : commonsVersion.getNextDevelopmentVersion();
+
+ logger.log(project, "Setting Spring Data Commons version in %s to %s.", GRADLE_PROPERTIES, version);
+ return String.format("%s=%s", COMMONS_PROPERTY, version);
+ }
+
+ if (line.contains(BUILD_PROPERTY)) {
+
+ ArtifactVersion version = updateInformation.getPhase().equals(Phase.PREPARE) ? buildVersion
+ : buildVersion.getNextDevelopmentVersion();
+
+ logger.log(project, "Setting Spring Data Build version in %s to %s.", GRADLE_PROPERTIES, version);
+ return String.format("%s=%s", BUILD_PROPERTY, version);
+ }
+
+ return line;
+ });
+
+ workspace.processFile(BUILD_GRADLE, project, (line, number) -> {
+
+ String snapshotUrl = repository.getSnapshotUrl();
+ String releaseUrl = repository.getUrl();
+ String message = "Switching to Spring repository %s";
+
+ switch (updateInformation.getPhase()) {
+ case CLEANUP:
+ logger.log(project, message, snapshotUrl);
+ return line.contains(releaseUrl) ? line.replace(releaseUrl, snapshotUrl) : line;
+ case PREPARE:
+ default:
+ logger.log(project, message, releaseUrl);
+ return line.contains(snapshotUrl) ? line.replace(snapshotUrl, releaseUrl) : line;
+ }
+ });
+
+ return iteration;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.release.build.BuildSystem#prepareVersion(org.springframework.data.release.model.ModuleIteration, org.springframework.data.release.model.Phase)
+ */
+ @Override
+ public ModuleIteration prepareVersion(ModuleIteration module, Phase phase) {
+ return module;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.release.build.BuildSystem#triggerDistributionBuild(org.springframework.data.release.model.ModuleIteration)
+ */
+ @Override
+ public ModuleIteration triggerDistributionBuild(ModuleIteration module) {
+ return module;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.release.build.BuildSystem#deploy(org.springframework.data.release.model.ModuleIteration)
+ */
+ @Override
+ public DeploymentInformation deploy(ModuleIteration module) {
+ return new DeploymentInformation(module, properties);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.plugin.core.Plugin#supports(java.lang.Object)
+ */
+ @Override
+ public boolean supports(Project project) {
+ return isGradleProject(project);
+ }
+
+ /**
+ * Returns whether the given project is a Gradle project (checks for the presence of a build.gradle file).
+ *
+ * @param project
+ * @return
+ */
+ private boolean isGradleProject(Project project) {
+ return workspace.getFile(BUILD_GRADLE, project).exists();
+ }
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/maven/GroupId.java b/release-tools/src/main/java/org/springframework/data/release/build/GroupId.java
similarity index 91%
rename from release-tools/src/main/java/org/springframework/data/release/maven/GroupId.java
rename to release-tools/src/main/java/org/springframework/data/release/build/GroupId.java
index 1f47335..e9d4892 100644
--- a/release-tools/src/main/java/org/springframework/data/release/maven/GroupId.java
+++ b/release-tools/src/main/java/org/springframework/data/release/build/GroupId.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.data.release.maven;
+package org.springframework.data.release.build;
import lombok.Value;
@@ -22,7 +22,7 @@ import lombok.Value;
*
* @author Oliver Gierke
*/
-@Value
+@Value(staticConstructor = "of")
class GroupId {
private final String value;
diff --git a/release-tools/src/main/java/org/springframework/data/release/maven/Artifact.java b/release-tools/src/main/java/org/springframework/data/release/build/MavenArtifact.java
similarity index 83%
rename from release-tools/src/main/java/org/springframework/data/release/maven/Artifact.java
rename to release-tools/src/main/java/org/springframework/data/release/build/MavenArtifact.java
index e033592..0dde854 100644
--- a/release-tools/src/main/java/org/springframework/data/release/maven/Artifact.java
+++ b/release-tools/src/main/java/org/springframework/data/release/build/MavenArtifact.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2014-2016 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.
@@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.data.release.maven;
+package org.springframework.data.release.build;
import static org.springframework.data.release.model.Projects.*;
+
import lombok.EqualsAndHashCode;
import lombok.Getter;
@@ -24,25 +25,25 @@ import org.springframework.data.release.model.ModuleIteration;
import org.springframework.util.Assert;
/**
- * Value object to represent a Maven {@link Artifact}.
+ * Value object to represent a Maven artifact.
*
* @author Oliver Gierke
*/
@EqualsAndHashCode
-public class Artifact {
+public class MavenArtifact {
- private static final GroupId GROUP_ID = new GroupId("org.springframework.data");
+ private static final GroupId GROUP_ID = GroupId.of("org.springframework.data");
private final ModuleIteration module;
private final Repository repository;
private final @Getter ArtifactVersion version;
/**
- * Creates a new {@link Artifact} for the given {@link ModuleIteration}.
+ * Creates a new {@link MavenArtifact} for the given {@link ModuleIteration}.
*
* @param module must not be {@literal null}.
*/
- public Artifact(ModuleIteration module) {
+ public MavenArtifact(ModuleIteration module) {
Assert.notNull(module, "Module iteration must not be null!");
diff --git a/release-tools/src/main/java/org/springframework/data/release/build/MavenBuildSystem.java b/release-tools/src/main/java/org/springframework/data/release/build/MavenBuildSystem.java
new file mode 100644
index 0000000..6ef0a67
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/build/MavenBuildSystem.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2014 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
+ *
+ * http://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.build;
+
+import static org.springframework.data.release.model.Projects.*;
+
+import lombok.RequiredArgsConstructor;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.annotation.Order;
+import org.springframework.data.release.deployment.DeploymentInformation;
+import org.springframework.data.release.deployment.DeploymentProperties;
+import org.springframework.data.release.io.Workspace;
+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.Train;
+import org.springframework.data.release.model.TrainIteration;
+import org.springframework.data.release.model.UpdateInformation;
+import org.springframework.data.release.utils.ExecutionUtils;
+import org.springframework.data.release.utils.Logger;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
+import org.xmlbeam.ProjectionFactory;
+import org.xmlbeam.io.XBFileIO;
+
+/**
+ * @author Oliver Gierke
+ */
+@Component
+@Order(100)
+@RequiredArgsConstructor(onConstructor = @__(@Autowired) )
+class MavenBuildSystem implements BuildSystem {
+
+ private static final String POM_XML = "pom.xml";
+
+ private final Workspace workspace;
+ private final ProjectionFactory projectionFactory;
+ private final Logger logger;
+ private final MavenRuntime mvn;
+ private final DeploymentProperties properties;
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.release.build.BuildSystem#updateProjectDescriptors(org.springframework.data.release.model.ModuleIteration, org.springframework.data.release.model.TrainIteration, org.springframework.data.release.model.Phase)
+ */
+ @Override
+ public ModuleIteration updateProjectDescriptors(ModuleIteration module, UpdateInformation information) {
+
+ PomUpdater updater = new PomUpdater(logger, information, module.getProject());
+
+ if (updater.isBuildProject()) {
+
+ updateBom(information);
+ updateParentPom(information);
+
+ } else {
+
+ execute(workspace.getFile(POM_XML, updater.getProject()), pom -> {
+
+ updater.updateDependencyProperties(pom);
+ updater.updateParentVersion(pom);
+ updater.updateRepository(pom);
+ });
+ }
+
+ return module;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.release.build.BuildSystem#triggerDistributionBuild(org.springframework.data.release.model.ModuleIteration)
+ */
+ @Override
+ public ModuleIteration triggerDistributionBuild(ModuleIteration module) {
+
+ Project project = module.getProject();
+
+ if (BUILD.equals(project)) {
+ return module;
+ }
+
+ if (!isMavenProject(project)) {
+ logger.log(project, "Skipping project as no pom.xml could be found in the working directory!");
+ return module;
+ }
+
+ logger.log(project, "Triggering distribution build…");
+
+ ArtifactVersion version = ArtifactVersion.of(module);
+
+ String profile = "-Pdistribute";
+
+ if (version.isMilestoneVersion()) {
+ profile = profile.concat(",milestone");
+ } else if (version.isReleaseVersion()) {
+ profile = profile.concat(",release");
+ }
+
+ mvn.execute(project, "clean", "deploy", "-DskipTests", profile);
+
+ logger.log(project, "Successfully finished distribution build!");
+
+ return module;
+ }
+
+ private void updateBom(UpdateInformation updateInformation) {
+
+ TrainIteration iteration = updateInformation.getIteration();
+
+ logger.log(BUILD, "Updating BOM pom.xml…");
+
+ execute(workspace.getFile("bom/pom.xml", BUILD), pom -> {
+
+ for (ModuleIteration module : iteration.getModulesExcept(BUILD)) {
+
+ ArtifactVersion version = updateInformation.getProjectVersionToSet(module.getProject());
+
+ logger.log(BUILD, "%s", module);
+
+ pom.setDependencyManagementVersion(new MavenArtifact(module).getArtifactId(), version);
+
+ module.getProject().doWithAdditionalArtifacts(
+ additionalArtifact -> pom.setDependencyManagementVersion(additionalArtifact.getArtifactId(), version));
+ }
+ });
+ }
+
+ private void updateParentPom(UpdateInformation information) {
+
+ // Fix version of shared resources to to-be-released version.
+ execute(workspace.getFile("parent/pom.xml", BUILD), ParentPom.class, pom -> {
+
+ 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());
+ });
+ }
+
+ public boolean isMavenProject(ModuleIteration module) {
+
+ Project project = module.getProject();
+
+ if (!isMavenProject(project)) {
+ logger.log(module, "No pom.xml file found, skipping project.");
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Triggers building the distribution artifacts for all Maven projects of the given {@link Train}.
+ *
+ * @param iteration
+ * @throws Exception
+ */
+ public void triggerDistributionBuild(TrainIteration iteration) throws Exception {
+
+ ExecutionUtils.run(iteration, module -> {
+
+ Project project = module.getProject();
+
+ if (BUILD.equals(project)) {
+ return;
+ }
+
+ if (!isMavenProject(project)) {
+ logger.log(project, "Skipping project as no pom.xml could be found in the working directory!");
+ return;
+ }
+
+ logger.log(project, "Triggering distribution build…");
+
+ ArtifactVersion version = ArtifactVersion.of(module);
+
+ String profile = "-Pdistribute";
+
+ if (version.isMilestoneVersion()) {
+ profile = profile.concat(",milestone");
+ } else if (version.isReleaseVersion()) {
+ profile = profile.concat(",release");
+ }
+
+ mvn.execute(project, "clean", "deploy", "-DskipTests", profile);
+
+ logger.log(project, "Successfully finished distribution build!");
+ });
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.release.build.BuildSystem#prepareVersion(org.springframework.data.release.model.ModuleIteration, org.springframework.data.release.model.Phase)
+ */
+ @Override
+ public ModuleIteration prepareVersion(ModuleIteration module, Phase phase) {
+
+ Project project = module.getProject();
+ UpdateInformation information = new UpdateInformation(module.getTrainIteration(), phase);
+
+ mvn.execute(project, "versions-set",
+ "-DnewVersion=".concat(information.getProjectVersionToSet(project).toString()));
+
+ if (BUILD.equals(project)) {
+
+ mvn.execute(project, "versions-set", //
+ "-DnewVersion=".concat(information.getReleaseTrainVersion()), //
+ "-DgroupId=org.springframework.data", //
+ "-DartifactId=spring-data-releasetrain");
+ }
+
+ return module;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.release.build.BuildSystem#deploy(org.springframework.data.release.model.ModuleIteration)
+ */
+ @Override
+ public DeploymentInformation deploy(ModuleIteration module) {
+
+ Assert.notNull(module, "Module must not be null!");
+
+ DeploymentInformation information = new DeploymentInformation(module, properties);
+
+ List arguments = new ArrayList<>();
+ arguments.add("clean");
+ arguments.add("deploy");
+ arguments.add("-Prelease");
+
+ arguments.add("-DskipTests");
+
+ arguments.add("-Dartifactory.server=".concat(properties.getServer().getUri()));
+ arguments.add("-Dartifactory.staging-repository=".concat(properties.getStagingRepository()));
+ arguments.add("-Dartifactory.username=".concat(properties.getUsername()));
+ arguments.add("-Dartifactory.password=".concat(properties.getPassword()));
+ arguments.add("-Dartifactory.build-name=\"".concat(information.getBuildName()).concat("\""));
+ arguments.add("-Dartifactory.build-number=".concat(information.getBuildNumber()));
+
+ mvn.execute(module.getProject(), arguments);
+
+ return information;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.plugin.core.Plugin#supports(java.lang.Object)
+ */
+ @Override
+ public boolean supports(Project project) {
+ return isMavenProject(project);
+ }
+
+ private void updateVersion(ModuleIteration iteration, File workingDirectory) {
+
+ ArtifactVersion version = ArtifactVersion.of(iteration);
+
+ mvn.execute(iteration.getProject(), "versions-set", "-DnewVersion=".concat(version.toString()));
+ }
+
+ private boolean isMavenProject(Project project) {
+ return workspace.getFile(POM_XML, project).exists();
+ }
+
+ private void execute(File file, Consumer callback) {
+ execute(file, Pom.class, callback);
+ }
+
+ private void execute(File file, Class type, Consumer callback) {
+
+ XBFileIO io = projectionFactory.io().file(file);
+
+ try {
+
+ T pom = (T) io.read(type);
+ callback.accept(pom);
+ io.write(pom);
+
+ } catch (Exception o_O) {
+ throw new RuntimeException(o_O);
+ }
+ }
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/build/MavenProperties.java b/release-tools/src/main/java/org/springframework/data/release/build/MavenProperties.java
new file mode 100644
index 0000000..7c7460b
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/build/MavenProperties.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2015 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
+ *
+ * http://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.build;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.File;
+import java.util.Map;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
+
+/**
+ * Maven configuration properties.
+ *
+ * @author Oliver Gierke
+ */
+@Slf4j
+@Data
+@Component
+@ConfigurationProperties(prefix = "maven")
+class MavenProperties {
+
+ private File mavenHome;
+ private File localRepository;
+ private Map plugins;
+
+ /**
+ * Configures the local Maven repository location to use. In case the given folder does not already exists it's
+ * created.
+ *
+ * @param localRepository must not be {@literal null} or empty.
+ */
+ public void setLocalRepository(String localRepository) {
+
+ Assert.hasText(localRepository, "Local repository must not be null!");
+
+ log.info("Using {} as local Maven repository!", localRepository);
+
+ this.localRepository = new File(localRepository.replace("~", System.getProperty("user.home")));
+
+ if (!this.localRepository.exists()) {
+ this.localRepository.mkdirs();
+ }
+ }
+
+ /**
+ * Returns the fully-qualified plugin goal for the given local one.
+ *
+ * @param goal must not be {@literal null} or empty.
+ * @return
+ */
+ public String getFullyQualifiedPlugin(String goal) {
+
+ Assert.hasText(goal, "Goal must not be null or empty!");
+ return plugins.containsKey(goal) ? plugins.get(goal) : goal;
+ }
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/build/MavenRuntime.java b/release-tools/src/main/java/org/springframework/data/release/build/MavenRuntime.java
new file mode 100644
index 0000000..9127240
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/build/MavenRuntime.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2015 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
+ *
+ * http://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.build;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.maven.shared.invoker.DefaultInvocationRequest;
+import org.apache.maven.shared.invoker.DefaultInvoker;
+import org.apache.maven.shared.invoker.InvocationResult;
+import org.apache.maven.shared.invoker.Invoker;
+import org.apache.maven.shared.invoker.MavenInvocationException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.release.io.OsOperations;
+import org.springframework.data.release.io.Workspace;
+import org.springframework.data.release.model.Project;
+import org.springframework.data.release.utils.Logger;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Oliver Gierke
+ */
+@Slf4j
+@Component
+class MavenRuntime {
+
+ private final Invoker invoker;
+ private final Workspace workspace;
+ private final OsOperations os;
+ private final Logger logger;
+ private final MavenProperties properties;
+
+ /**
+ * Creates a new {@link MavenRuntime} for the given {@link Workspace} and Maven home.
+ *
+ * @param workspace must not be {@literal null}.
+ * @param os must not be {@literal null}.
+ * @param logger must not be {@literal null}.
+ * @param properties must not be {@literal null}.
+ */
+ @Autowired
+ public MavenRuntime(Workspace workspace, OsOperations os, Logger logger, MavenProperties properties) {
+
+ this.workspace = workspace;
+ this.os = os;
+ this.logger = logger;
+ this.properties = properties;
+
+ this.invoker = new DefaultInvoker();
+ this.invoker.setMavenHome(properties.getMavenHome());
+ this.invoker.setOutputHandler(line -> log.info(line));
+ this.invoker.setErrorHandler(line -> log.info(line));
+
+ File localRepository = properties.getLocalRepository();
+
+ if (localRepository != null) {
+ this.invoker.setLocalRepositoryDirectory(localRepository);
+ }
+ }
+
+ public void execute(Project project, String... arguments) {
+ execute(project, Arrays.asList(arguments));
+ }
+
+ public void execute(Project project, List arguments) {
+
+ DefaultInvocationRequest request = new DefaultInvocationRequest();
+ request.setJavaHome(os.getJavaHome());
+ request.setShellEnvironmentInherited(true);
+ request.setBaseDirectory(workspace.getProjectDirectory(project));
+
+ List goals = new ArrayList<>();
+ goals.add(properties.getFullyQualifiedPlugin(arguments.get(0)));
+ goals.addAll(arguments.subList(1, arguments.size()));
+
+ request.setGoals(goals);
+
+ logger.log(project, "Executing mvn %s", goals.stream().collect(Collectors.joining(" ")));
+
+ try {
+
+ InvocationResult result = invoker.execute(request);
+
+ if (result.getExitCode() != 0) {
+ throw new RuntimeException(result.getExecutionException());
+ }
+
+ } catch (MavenInvocationException o_O) {
+ throw new RuntimeException(o_O);
+ }
+ }
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/maven/ParentPom.java b/release-tools/src/main/java/org/springframework/data/release/build/ParentPom.java
similarity index 87%
rename from release-tools/src/main/java/org/springframework/data/release/maven/ParentPom.java
rename to release-tools/src/main/java/org/springframework/data/release/build/ParentPom.java
index c632da6..44d8024 100644
--- a/release-tools/src/main/java/org/springframework/data/release/maven/ParentPom.java
+++ b/release-tools/src/main/java/org/springframework/data/release/build/ParentPom.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.data.release.maven;
+package org.springframework.data.release.build;
import org.springframework.data.release.model.ArtifactVersion;
import org.xmlbeam.annotation.XBValue;
@@ -24,6 +24,9 @@ import org.xmlbeam.annotation.XBWrite;
*/
public interface ParentPom extends Pom {
+ @XBWrite("/project/properties/releasetrain")
+ void setReleaseTrain(@XBValue String releaseTrain);
+
@XBWrite("/project/profiles/profile[id=\"distribute\"]/dependencies/dependency/version")
void setSharedResourcesVersion(@XBValue ArtifactVersion value);
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/maven/Pom.java b/release-tools/src/main/java/org/springframework/data/release/build/Pom.java
similarity index 85%
rename from release-tools/src/main/java/org/springframework/data/release/maven/Pom.java
rename to release-tools/src/main/java/org/springframework/data/release/build/Pom.java
index 0687c2e..63deca5 100644
--- a/release-tools/src/main/java/org/springframework/data/release/maven/Pom.java
+++ b/release-tools/src/main/java/org/springframework/data/release/build/Pom.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.data.release.maven;
+package org.springframework.data.release.build;
import org.springframework.data.release.model.ArtifactVersion;
import org.xmlbeam.annotation.XBRead;
@@ -26,13 +26,16 @@ import org.xmlbeam.annotation.XBWrite;
public interface Pom {
@XBRead("/project")
- Artifact getArtifactId();
+ Artifact getArtifact();
+
+ @XBRead("/project/version")
+ String getRawVersion();
@XBRead("/project/version")
ArtifactVersion getVersion();
@XBWrite("/project/version")
- void setVersion(String version);
+ void setVersion(ArtifactVersion version);
@XBWrite("/project/parent/version")
void setParentVersion(ArtifactVersion version);
@@ -73,12 +76,20 @@ public interface Pom {
public interface Artifact {
@XBRead("child::groupId")
- String getGroupId();
+ GroupId getGroupId();
@XBRead("child::artifactId")
String getArtifactId();
@XBRead("child::version")
String getVersion();
+
+ default String getArtifactPath() {
+ return "/".concat(getGroupId().asPath()).concat("/").concat(getArtifactId());
+ }
+
+ default String getPath() {
+ return getArtifactPath().concat(getVersion());
+ }
}
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/build/PomUpdater.java b/release-tools/src/main/java/org/springframework/data/release/build/PomUpdater.java
new file mode 100644
index 0000000..56e2e04
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/build/PomUpdater.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2015 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
+ *
+ * http://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.build;
+
+import static org.springframework.data.release.model.Phase.*;
+import static org.springframework.data.release.model.Projects.*;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import org.springframework.data.release.model.ArtifactVersion;
+import org.springframework.data.release.model.Project;
+import org.springframework.data.release.model.UpdateInformation;
+import org.springframework.data.release.utils.Logger;
+import org.springframework.util.Assert;
+
+/**
+ * @author Oliver Gierke
+ */
+@RequiredArgsConstructor
+class PomUpdater {
+
+ private final Logger logger;
+ private final UpdateInformation information;
+ private final @Getter Project project;
+
+ public boolean isBuildProject() {
+ return BUILD.equals(project);
+ }
+
+ public void updateArtifactVersion(Pom pom) {
+
+ ArtifactVersion version = information.getProjectVersionToSet(project);
+ logger.log(project, "Updated project version to %s.", version);
+ pom.setVersion(version);
+ }
+
+ public void updateDependencyProperties(Pom pom) {
+
+ project.getDependencies().forEach(dependency -> {
+
+ String dependencyProperty = dependency.getDependencyProperty();
+
+ if (pom.getProperty(dependencyProperty) == null) {
+ return;
+ }
+
+ ArtifactVersion version = information.getProjectVersionToSet(dependency);
+
+ logger.log(project, "Updating %s dependency version property %s to %s.", dependency.getFullName(),
+ dependencyProperty, version);
+ pom.setProperty(dependencyProperty, version);
+ });
+ }
+
+ /**
+ * Updates the version of the parent project in the given {@link Pom}.
+ *
+ * @param pom must not be {@literal null}.
+ */
+ public void updateParentVersion(Pom pom) {
+
+ Assert.notNull(pom, "Pom must not be null!");
+
+ ArtifactVersion version = information.getParentVersionToSet();
+
+ logger.log(project, "Updating Spring Data Build Parent version to %s.", version);
+ pom.setParentVersion(version);
+ }
+
+ /**
+ * Updates the repository section in the given {@link Pom}.
+ *
+ * @param pom must not be {@literal null}.
+ */
+ public void updateRepository(Pom pom) {
+
+ Assert.notNull(pom, "Pom must not be null!");
+
+ String message = "Switching to Spring repository %s (%s).";
+ Repository repository = information.getRepository();
+
+ if (PREPARE.equals(information.getPhase())) {
+
+ logger.log(project, message, repository.getId(), repository.getUrl());
+
+ pom.setRepositoryId(repository.getSnapshotId(), repository.getId());
+ pom.setRepositoryUrl(repository.getId(), repository.getUrl());
+
+ } else {
+
+ logger.log(project, message, repository.getSnapshotId(), repository.getSnapshotUrl());
+
+ pom.setRepositoryId(repository.getId(), repository.getSnapshotId());
+ pom.setRepositoryUrl(repository.getSnapshotId(), repository.getSnapshotUrl());
+ }
+ }
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/maven/Repository.java b/release-tools/src/main/java/org/springframework/data/release/build/Repository.java
similarity index 68%
rename from release-tools/src/main/java/org/springframework/data/release/maven/Repository.java
rename to release-tools/src/main/java/org/springframework/data/release/build/Repository.java
index d8a8e93..5119163 100644
--- a/release-tools/src/main/java/org/springframework/data/release/maven/Repository.java
+++ b/release-tools/src/main/java/org/springframework/data/release/build/Repository.java
@@ -13,35 +13,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.data.release.maven;
+package org.springframework.data.release.build;
+
+import lombok.Value;
import org.springframework.data.release.model.Iteration;
+import org.springframework.util.Assert;
/**
* @author Oliver Gierke
*/
+
+@Value
public class Repository {
+ private static final String ID_BASE = "spring-libs-";
private static final String BASE = "https://repo.spring.io/libs-";
- private final String id;
- private final String url;
+ String id, url;
public Repository(Iteration iteration) {
- this.id = iteration.isPublic() ? "spring-libs-release" : "spring-libs-milestone";
- this.url = iteration.isPublic() ? BASE.concat("release") : BASE.concat("milestone");
- }
- public String getId() {
- return id;
+ Assert.notNull(iteration, "Iteration must not be null!");
+
+ this.id = ID_BASE.concat(iteration.isPublic() ? "release" : "milestone");
+ this.url = BASE.concat(iteration.isPublic() ? "release" : "milestone");
}
public String getSnapshotId() {
- return "spring-libs-snapshot";
- }
-
- public String getUrl() {
- return url;
+ return ID_BASE.concat("snapshot");
}
public String getSnapshotUrl() {
diff --git a/release-tools/src/main/java/org/springframework/data/release/cli/IssueTrackerCommands.java b/release-tools/src/main/java/org/springframework/data/release/cli/IssueTrackerCommands.java
index f2c0ebd..6d4742a 100644
--- a/release-tools/src/main/java/org/springframework/data/release/cli/IssueTrackerCommands.java
+++ b/release-tools/src/main/java/org/springframework/data/release/cli/IssueTrackerCommands.java
@@ -45,8 +45,9 @@ public class IssueTrackerCommands implements CommandMarker {
private final Credentials credentials;
/**
- * @param tracker
- * @param environment
+ * @param tracker must not be {@literal null}.
+ * @param jira must not be {@literal null}.
+ * @param environment must not be {@literal null}.
*/
@Autowired
public IssueTrackerCommands(PluginRegistry tracker, JiraConnector jira,
diff --git a/release-tools/src/main/java/org/springframework/data/release/cli/ReleaseCommands.java b/release-tools/src/main/java/org/springframework/data/release/cli/ReleaseCommands.java
index a8b4268..952dd07 100644
--- a/release-tools/src/main/java/org/springframework/data/release/cli/ReleaseCommands.java
+++ b/release-tools/src/main/java/org/springframework/data/release/cli/ReleaseCommands.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2014-2016 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,35 +19,39 @@ import static org.springframework.data.release.model.Projects.*;
import lombok.RequiredArgsConstructor;
+import java.util.List;
+
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.release.docs.DocumentationOperations;
+import org.springframework.data.release.CliComponent;
+import org.springframework.data.release.build.BuildOperations;
+import org.springframework.data.release.deployment.DeploymentInformation;
+import org.springframework.data.release.deployment.DeploymentOperations;
import org.springframework.data.release.git.GitOperations;
-import org.springframework.data.release.git.VersionTags;
-import org.springframework.data.release.gradle.GradleOperations;
-import org.springframework.data.release.maven.MavenOperations;
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.CommandMarker;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
-import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
/**
* @author Oliver Gierke
*/
-@Component
+@CliComponent
@RequiredArgsConstructor(onConstructor = @__(@Autowired) )
public class ReleaseCommands implements CommandMarker {
- private final MavenOperations maven;
- private final GradleOperations gradle;
private final GitOperations git;
private final ReleaseOperations misc;
- private final DocumentationOperations docs;
+ private final DeploymentOperations deployment;
+ private final BuildOperations build;
@CliCommand("release predict")
public String predictTrainAndIteration() throws Exception {
@@ -64,20 +68,6 @@ public class ReleaseCommands implements CommandMarker {
findFirst().map(Train::getName).orElse(null);
}
- /**
- * Triggers the distribution of release artifacts for all projects.
- *
- * @param trainName
- * @param iterationName
- * @throws Exception
- */
- @CliCommand("release distribute")
- public void distribute(@CliOption(key = "", mandatory = true) TrainIteration iteration) throws Exception {
-
- git.checkout(iteration);
- maven.triggerDistributionBuild(iteration);
- }
-
/**
* Prepares the release of the given iteration of the given train.
*
@@ -92,22 +82,73 @@ public class ReleaseCommands implements CommandMarker {
misc.prepareChangelogs(iteration);
misc.updateResources(iteration);
- docs.updateDockbookIncludes(iteration);
- maven.updatePom(iteration, Phase.PREPARE);
- gradle.updateProject(iteration, Phase.PREPARE);
+ build.updateProjectDescriptors(iteration, Phase.PREPARE);
- git.commit(iteration, "Prepare %s.", null);
+ git.commit(iteration, "Prepare %s.");
}
+ @CliCommand(value = "release build")
+ public void buildRelease(@CliOption(key = "", mandatory = true) TrainIteration iteration, //
+ @CliOption(key = "project", mandatory = false) String projectName) throws Exception {
+
+ if (projectName != null) {
+
+ Project project = Projects.byName(projectName);
+ ModuleIteration module = iteration.getModule(project);
+
+ DeploymentInformation information = build.performRelease(module);
+ deployment.promote(information);
+
+ } else {
+
+ List deploymentInformation = build.performRelease(iteration);
+ git.commit(iteration, "Release version %s.");
+ deploymentInformation.forEach(deployment::promote);
+
+ build.prepareVersions(iteration, Phase.CLEANUP);
+ git.commit(iteration, "Prepare next development iteration.");
+ }
+ }
+
+ /**
+ * Concludes the release of the given {@link TrainIteration}.
+ *
+ * @param iteration
+ * @throws Exception
+ */
@CliCommand(value = "release conclude")
public void conclude(@CliOption(key = "", mandatory = true) TrainIteration iteration) throws Exception {
+ Assert.notNull(iteration, "Train iteration must not be null!");
+
+ // Tag release
git.tagRelease(iteration);
- maven.updatePom(iteration, Phase.CLEANUP);
- gradle.updateProject(iteration, Phase.CLEANUP);
+ // Prepare master branch
+ build.updateProjectDescriptors(iteration, Phase.CLEANUP);
+ git.commit(iteration, "After release cleanups.");
- git.commit(iteration, "After release cleanups.", null);
+ // Prepare maintenance branches
+ git.checkout(iteration);
+ git.createMaintenanceBranches(iteration);
+
+ build.updateProjectDescriptors(iteration, Phase.MAINTENANCE);
+ build.prepareVersions(iteration, Phase.MAINTENANCE);
+ git.commit(iteration, "Prepare next development iteration.");
+ }
+
+ /**
+ * Triggers the distribution of release artifacts for all projects.
+ *
+ * @param trainName
+ * @param iterationName
+ * @throws Exception
+ */
+ @CliCommand("release distribute")
+ public void distribute(@CliOption(key = "", mandatory = true) TrainIteration iteration) throws Exception {
+
+ git.checkout(iteration);
+ build.distributeResources(iteration);
}
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/cli/TrainIterationConverter.java b/release-tools/src/main/java/org/springframework/data/release/cli/TrainIterationConverter.java
index 6850c2a..5856ecd 100644
--- a/release-tools/src/main/java/org/springframework/data/release/cli/TrainIterationConverter.java
+++ b/release-tools/src/main/java/org/springframework/data/release/cli/TrainIterationConverter.java
@@ -70,6 +70,6 @@ public class TrainIterationConverter implements Converter {
}
}
- return false;
+ return true;
}
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/deployment/ArtifactoryClient.java b/release-tools/src/main/java/org/springframework/data/release/deployment/ArtifactoryClient.java
new file mode 100644
index 0000000..5d7cffa
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/deployment/ArtifactoryClient.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2015-2016 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
+ *
+ * http://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.deployment;
+
+import lombok.RequiredArgsConstructor;
+import lombok.Value;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.springframework.data.release.model.ModuleIteration;
+import org.springframework.data.release.utils.Logger;
+import org.springframework.util.Assert;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.RestOperations;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * A client to interact with Artifactory.
+ *
+ * @author Oliver Gierke
+ */
+@RequiredArgsConstructor
+class ArtifactoryClient {
+
+ private final RestOperations template;
+ private final Logger logger;
+ private final DeploymentProperties properties;
+
+ /**
+ * Triggers the promotion of the artifacts identified by the given {@link DeploymentInformation}.
+ *
+ * @param information must not be {@literal null}.
+ */
+ public void promote(DeploymentInformation information) {
+
+ Assert.notNull(information, "DeploymentInformation must not be null!");
+
+ ModuleIteration module = information.getModule();
+ URI uri = properties.getServer().getPromotionResource(information);
+
+ logger.log(module, "Promoting %s %s from %s to %s.", information.getBuildName(), information.getBuildNumber(),
+ properties.getStagingRepository(), information.getTargetRepository());
+
+ try {
+ template.postForEntity(uri, new PromotionRequest(information.getTargetRepository()), String.class);
+ } catch (HttpClientErrorException o_O) {
+ handle(o_O, module);
+ }
+ }
+
+ private void handle(HttpClientErrorException o_O, ModuleIteration module) {
+
+ try {
+
+ logger.log(module, "Promotion failed!");
+
+ Errors errors = new ObjectMapper().readValue(o_O.getResponseBodyAsByteArray(), Errors.class);
+ errors.getErrors().forEach(error -> logger.log(module, error));
+ errors.getMessages().forEach(message -> logger.log(module, message));
+
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void deleteArtifacts(DeploymentInformation information) {
+ template.delete(properties.getServer().getDeleteBuildResource(information));
+ }
+
+ @Value
+ private static class PromotionRequest {
+ String targetRepo;
+ }
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/deployment/DeploymentConfiguration.java b/release-tools/src/main/java/org/springframework/data/release/deployment/DeploymentConfiguration.java
new file mode 100644
index 0000000..634a471
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/deployment/DeploymentConfiguration.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2015-2016 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
+ *
+ * http://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.deployment;
+
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.release.utils.Logger;
+import org.springframework.http.HttpRequest;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * Configuration to set up deployment components.
+ *
+ * @author Oliver Gierke
+ */
+@Configuration
+class DeploymentConfiguration {
+
+ @Autowired DeploymentProperties properties;
+
+ @Bean
+ public ArtifactoryClient client(Logger logger) {
+ return new ArtifactoryClient(artifactoryRestTemplate(), logger, properties);
+ }
+
+ @Bean
+ public RestTemplate artifactoryRestTemplate() {
+
+ RestTemplate template = new RestTemplate();
+ template.setInterceptors(Arrays.asList(new AuthenticatingClientHttpRequestInterceptor(properties.getApiKey())));
+
+ return template;
+ }
+
+ @RequiredArgsConstructor
+ private static class AuthenticatingClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
+
+ private final @NonNull String apiKey;
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.http.client.ClientHttpRequestInterceptor#intercept(org.springframework.http.HttpRequest, byte[], org.springframework.http.client.ClientHttpRequestExecution)
+ */
+ @Override
+ public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
+ throws IOException {
+
+ request.getHeaders().add("X-Api-Key", apiKey);
+
+ return execution.execute(request, body);
+ }
+ }
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/deployment/DeploymentInformation.java b/release-tools/src/main/java/org/springframework/data/release/deployment/DeploymentInformation.java
new file mode 100644
index 0000000..4d0d380
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/deployment/DeploymentInformation.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2015-2016 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
+ *
+ * http://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.deployment;
+
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.data.release.model.ModuleIteration;
+import org.springframework.web.util.UriTemplate;
+
+/**
+ * Information about a deployment.
+ *
+ * @author Oliver Gierke
+ */
+@RequiredArgsConstructor
+public class DeploymentInformation {
+
+ private static UriTemplate REPOSITORY_TEMPLATE = new UriTemplate(
+ "artifactory::default::{server};build.number={buildNumber};build.name={buildName}");
+
+ private final @Getter @NonNull ModuleIteration module;
+ private final @NonNull DeploymentProperties properties;
+
+ /**
+ * Returns a unique build number for this particular deployment.
+ */
+ private final @Getter String buildNumber = String.valueOf(LocalDateTime.now().toEpochSecond(ZoneOffset.UTC));
+
+ /**
+ * Returns the name of the build.
+ *
+ * @return
+ */
+ public String getBuildName() {
+ return module.getProject().getFullName().concat(" - Release");
+ }
+
+ /**
+ * Returns the name of the repository to deploy to.
+ *
+ * @return
+ */
+ public String getTargetRepository() {
+ return properties.getRepositoryPrefix()
+ .concat(module.getIteration().isPublic() ? "libs-release-local" : "libs-milestone-local");
+ }
+
+ /**
+ * Returns the full URL to be used as deployment target.
+ *
+ * @return
+ */
+ public String getDeploymentTargetUrl() {
+
+ Map parameters = new HashMap<>();
+ parameters.put("server", properties.getStagingRepositoryUrl());
+ parameters.putAll(getBuildInfoParameters());
+
+ return REPOSITORY_TEMPLATE.expand(parameters).toString();
+ }
+
+ /**
+ * Returns a {@link Map} to expand a URI template to access the build information.
+ *
+ * @return
+ */
+ public Map getBuildInfoParameters() {
+
+ Map parameters = new HashMap<>();
+ parameters.put("buildNumber", buildNumber);
+ parameters.put("buildName", getBuildName());
+
+ return parameters;
+ }
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/deployment/DeploymentOperations.java b/release-tools/src/main/java/org/springframework/data/release/deployment/DeploymentOperations.java
new file mode 100644
index 0000000..eab57cd
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/deployment/DeploymentOperations.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2015-2016 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
+ *
+ * http://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.deployment;
+
+import lombok.RequiredArgsConstructor;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
+
+/**
+ * Deployment functionality.
+ *
+ * @author Oliver Gierke
+ */
+@Component
+@RequiredArgsConstructor(onConstructor = @__(@Autowired) )
+public class DeploymentOperations {
+
+ private final ArtifactoryClient client;
+
+ /**
+ * Promotes the artifacts identified by the given {@link DeploymentInformation}.
+ *
+ * @param information must not be {@literal null}.
+ */
+ public void promote(DeploymentInformation information) {
+
+ Assert.notNull(information, "DeploymentInformation must not be null!");
+
+ client.promote(information);
+ }
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/deployment/DeploymentProperties.java b/release-tools/src/main/java/org/springframework/data/release/deployment/DeploymentProperties.java
new file mode 100644
index 0000000..fad0f0a
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/deployment/DeploymentProperties.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2015-2016 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
+ *
+ * http://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.deployment;
+
+import lombok.Data;
+
+import java.net.URI;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
+import org.springframework.web.util.UriTemplate;
+
+/**
+ * @author Oliver Gierke
+ */
+@Data
+@Component
+@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 String password;
+
+ /**
+ * The repository to deploy the artifacts to.
+ */
+ private String stagingRepository;
+
+ private String repositoryPrefix = "";
+
+ public String getStagingRepository() {
+ return repositoryPrefix.concat(stagingRepository);
+ }
+
+ /**
+ * Returns the URI of the staging repository.
+ *
+ * @return
+ */
+ public String getStagingRepositoryUrl() {
+ return server.getUri().toString().concat("/").concat(stagingRepository);
+ }
+
+ @Data
+ public static class Server {
+
+ 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 String uri;
+
+ /**
+ * Returns the URI to the resource that a promotion can be triggered at.
+ *
+ * @param information must not be {@literal null}.
+ * @return
+ */
+ public URI getPromotionResource(DeploymentInformation information) {
+
+ Assert.notNull(information, "DeploymentInformation must not be null!");
+
+ return new UriTemplate(uri.concat(PROMOTION_RESOURCE)).expand(information.getBuildInfoParameters());
+ }
+
+ public URI getDeleteBuildResource(DeploymentInformation information) {
+
+ return new UriTemplate(uri.concat(DELETE_BUILD_RESOURCE)).expand(information.getBuildInfoParameters());
+ }
+ }
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/deployment/Errors.java b/release-tools/src/main/java/org/springframework/data/release/deployment/Errors.java
new file mode 100644
index 0000000..92f0d3d
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/deployment/Errors.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015 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
+ *
+ * http://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.deployment;
+
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Oliver Gierke
+ */
+@Data
+public class Errors {
+
+ private List errors = new ArrayList<>();
+ private List messages = new ArrayList<>();
+
+ public List getErrors(Errors this) {
+ return errors;
+ }
+
+ @Data
+ static class Error {
+
+ private String message;
+ private int status;
+
+ public String toString() {
+ return String.format("%s - %s", status, message);
+ }
+ }
+
+ @Data
+ static class Message {
+
+ private String level, message;
+
+ public String toString() {
+ return String.format("%s - %s", level, message);
+ }
+ }
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/docs/DocumentationOperations.java b/release-tools/src/main/java/org/springframework/data/release/docs/DocumentationOperations.java
index 2ac390d..9025d19 100644
--- a/release-tools/src/main/java/org/springframework/data/release/docs/DocumentationOperations.java
+++ b/release-tools/src/main/java/org/springframework/data/release/docs/DocumentationOperations.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2014-2016 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.
@@ -16,6 +16,7 @@
package org.springframework.data.release.docs;
import static org.springframework.data.release.model.Projects.*;
+
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
@@ -24,7 +25,6 @@ import org.springframework.data.release.git.GitProject;
import org.springframework.data.release.git.Tag;
import org.springframework.data.release.git.VersionTags;
import org.springframework.data.release.io.Workspace;
-import org.springframework.data.release.io.Workspace.LineCallback;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.TrainIteration;
@@ -34,7 +34,7 @@ import org.springframework.stereotype.Component;
* @author Oliver Gierke
*/
@Component
-@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+@RequiredArgsConstructor(onConstructor = @__(@Autowired) )
public class DocumentationOperations {
private static final String INDEX_LOCATION = "/src/docbkx/index.xml";
@@ -61,16 +61,12 @@ public class DocumentationOperations {
continue;
}
- workspace.processFile(INDEX_LOCATION, project, new LineCallback() {
+ workspace.processFile(INDEX_LOCATION, project, (line, number) -> {
- @Override
- public String doWith(String line, long number) {
+ boolean isInclude = line.contains("xi:include");
+ boolean containsGitRepo = line.contains(gitProject.getRepositoryName());
- boolean isInclude = line.contains("xi:include");
- boolean containsGitRepo = line.contains(gitProject.getRepositoryName());
-
- return isInclude && containsGitRepo ? line.replace(previousTag.toString(), newTag.toString()) : line;
- }
+ return isInclude && containsGitRepo ? line.replace(previousTag.toString(), newTag.toString()) : line;
});
}
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/git/Branch.java b/release-tools/src/main/java/org/springframework/data/release/git/Branch.java
index b71988a..ec42c29 100644
--- a/release-tools/src/main/java/org/springframework/data/release/git/Branch.java
+++ b/release-tools/src/main/java/org/springframework/data/release/git/Branch.java
@@ -15,11 +15,13 @@
*/
package org.springframework.data.release.git;
+import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
import org.springframework.data.release.model.IterationVersion;
import org.springframework.data.release.model.Version;
+import org.springframework.data.release.model.VersionAware;
import org.springframework.util.Assert;
/**
@@ -27,8 +29,8 @@ import org.springframework.util.Assert;
*
* @author Oliver Gierke
*/
-@RequiredArgsConstructor
@EqualsAndHashCode
+@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
class Branch {
public static final Branch MASTER = new Branch("master");
@@ -43,17 +45,30 @@ class Branch {
*/
public static Branch from(IterationVersion iterationVersion) {
- Assert.notNull(iterationVersion, "Iteration versoin must not be null!");
+ Assert.notNull(iterationVersion, "Iteration version must not be null!");
- Version version = iterationVersion.getVersion();
-
- if (iterationVersion.getIteration().isServiceIteration()) {
- return new Branch(version.toString().concat(".x"));
+ if (iterationVersion.isServiceIteration()) {
+ return from((VersionAware) iterationVersion);
}
return MASTER;
}
+ public static Branch from(VersionAware versioned) {
+ return from(versioned.getVersion());
+ }
+
+ private static Branch from(Version version) {
+ return from(version.toString().concat(".x"));
+ }
+
+ private static Branch from(String name) {
+
+ int slashIndex = name.lastIndexOf('/');
+
+ return new Branch(slashIndex != -1 ? name.substring(slashIndex + 1) : name);
+ }
+
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
diff --git a/release-tools/src/main/java/org/springframework/data/release/git/Commit.java b/release-tools/src/main/java/org/springframework/data/release/git/Commit.java
index d7bfd98..b063881 100644
--- a/release-tools/src/main/java/org/springframework/data/release/git/Commit.java
+++ b/release-tools/src/main/java/org/springframework/data/release/git/Commit.java
@@ -18,6 +18,8 @@ package org.springframework.data.release.git;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
+import java.util.Optional;
+
import org.springframework.data.release.jira.Ticket;
/**
@@ -29,7 +31,7 @@ public class Commit {
private final Ticket ticket;
private final String summary;
- private final String details;
+ private final Optional details;
/*
* (non-Javadoc)
@@ -42,10 +44,10 @@ public class Commit {
builder.append(ticket.getId()).append(" - ").append(summary).append("\n");
- if (details != null) {
+ details.ifPresent(it -> {
builder.append("\n");
- builder.append(details).append("\n");
- }
+ builder.append(it).append("\n");
+ });
return builder.toString();
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/git/GitCommands.java b/release-tools/src/main/java/org/springframework/data/release/git/GitCommands.java
index 62f4cfb..bb25caf 100644
--- a/release-tools/src/main/java/org/springframework/data/release/git/GitCommands.java
+++ b/release-tools/src/main/java/org/springframework/data/release/git/GitCommands.java
@@ -37,7 +37,12 @@ public class GitCommands implements CommandMarker {
private final GitOperations git;
- @CliCommand("git checkout")
+ @CliCommand("git co train")
+ public void checkout(@CliOption(key = "", mandatory = true) Train train) throws Exception {
+ git.checkout(train);
+ }
+
+ @CliCommand("git co")
public void checkout(@CliOption(key = "", mandatory = true) TrainIteration iteration) throws Exception {
git.checkout(iteration);
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/git/GitOperations.java b/release-tools/src/main/java/org/springframework/data/release/git/GitOperations.java
index 9db5f6b..f903188 100644
--- a/release-tools/src/main/java/org/springframework/data/release/git/GitOperations.java
+++ b/release-tools/src/main/java/org/springframework/data/release/git/GitOperations.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2015 the original author or authors.
+ * Copyright 2014-2016 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,8 +19,8 @@ import lombok.RequiredArgsConstructor;
import java.io.File;
import java.io.IOException;
+import java.util.Optional;
import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
import org.eclipse.jgit.api.CheckoutCommand;
import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
@@ -86,14 +86,49 @@ public class GitOperations {
logger.log(module, "git reset --hard origin/%s", branch);
- git.reset().//
- setMode(ResetType.HARD).//
- setRef("origin/".concat(branch.toString())).//
- call();
+ reset(git, branch.toString());
}
});
}
+ /**
+ * Checks out all projects of the given {@link TrainIteration}.
+ *
+ * @param iteration
+ * @throws Exception
+ */
+ public void checkout(Train train) {
+
+ update(train);
+
+ ExecutionUtils.run(train, module -> {
+
+ try (Git git = new Git(getRepository(module.getProject()))) {
+
+ Branch branch = Branch.from(module);
+ CheckoutCommand command = git.checkout().setName(branch.toString());
+
+ if (!branchExists(module.getProject(), branch)) {
+
+ logger.log(module.getProject(), "git checkout -b %s --track origin/%s", branch, branch);
+ command.setCreateBranch(true).//
+ setStartPoint("origin/".concat(branch.toString())).//
+ call();
+
+ } else {
+
+ logger.log(module.getProject(), "git checkout %s", branch);
+ command.call();
+ }
+
+ logger.log(module.getProject(), "git reset --hard origin/%s", branch);
+ reset(git, branch.toString());
+ }
+ });
+
+ logger.log(train, "Successfully checked out projects.");
+ }
+
/**
* Checks out all projects of the given {@link TrainIteration}.
*
@@ -120,7 +155,7 @@ public class GitOperations {
logger.log(module, "git checkout %s", tag);
- git.checkout().setStartPoint(tag.toString());
+ git.checkout().setStartPoint(tag.toString()).call();
}
});
@@ -197,12 +232,13 @@ public class GitOperations {
if (workspace.hasProjectDirectory(project)) {
logger.log(project, "Found existing repository %s. Obtaining latest changes…", repositoryName);
- logger.log(project, "git checkout master && git reset --hard && git fetch --tags && git pull origin master");
+ logger.log(project,
+ "git checkout master && git reset --hard origin/master && git fetch --tags && git pull origin master");
checkout(project, Branch.MASTER);
- git.reset().setMode(ResetType.HARD).call();
- git.fetch().setTagOpt(TagOpt.FETCH_TAGS);
+ reset(git, "master");
+ git.fetch().setTagOpt(TagOpt.FETCH_TAGS).call();
git.pull().call();
} else {
@@ -256,6 +292,18 @@ public class GitOperations {
});
}
+ /**
+ * Commits all changes currently made to all modules of the given {@link TrainIteration}. The summary can contain a
+ * single {@code %s} placeholder which the version of the current module will get replace into.
+ *
+ * @param iteration must not be {@literal null}.
+ * @param summary must not be {@literal null} or empty.
+ * @throws Exception
+ */
+ public void commit(TrainIteration iteration, String summary) throws Exception {
+ commit(iteration, summary, Optional.empty());
+ }
+
/**
* Commits all changes currently made to all modules of the given {@link TrainIteration}. The summary can contain a
* single {@code %s} placeholder which the version of the current module will get replace into.
@@ -265,7 +313,7 @@ public class GitOperations {
* @param details can be {@literal null} or empty.
* @throws Exception
*/
- public void commit(TrainIteration iteration, String summary, String details) throws Exception {
+ public void commit(TrainIteration iteration, String summary, Optional details) throws Exception {
Assert.notNull(iteration, "Train iteration must not be null!");
Assert.hasText(summary, "Summary must not be null or empty!");
@@ -273,19 +321,22 @@ public class GitOperations {
ExecutionUtils.run(iteration, module -> commit(module, expandSummary(summary, module, iteration), details));
}
- private static String expandSummary(String summary, ModuleIteration module, TrainIteration iteration) {
-
- if (!summary.contains("%s")) {
- return summary;
- }
-
- return String.format(summary,
- ArtifactVersion.of(module).toString().concat(String.format(" (%s)", iteration.toString())));
+ /**
+ * Commits the given files for the given {@link ModuleIteration} using the given summary for the commit message. If no
+ * files are given, all pending changes are committed.
+ *
+ * @param module must not be {@literal null}.
+ * @param summary must not be {@literal null} or empty.
+ * @param files can be empty.
+ * @throws Exception
+ */
+ public void commit(ModuleIteration module, String summary, File... files) throws Exception {
+ commit(module, summary, Optional.empty(), files);
}
/**
* Commits the given files for the given {@link ModuleIteration} using the given summary and details for the commit
- * message. If no files are given, all pending changes are commited.
+ * message. If no files are given, all pending changes are committed.
*
* @param module must not be {@literal null}.
* @param summary must not be {@literal null} or empty.
@@ -293,7 +344,7 @@ public class GitOperations {
* @param files can be empty.
* @throws Exception
*/
- public void commit(ModuleIteration module, String summary, String details, File... files) throws Exception {
+ public void commit(ModuleIteration module, String summary, Optional details, File... files) throws Exception {
Assert.notNull(module, "Module iteration must not be null!");
Assert.hasText(summary, "Summary must not be null or empty!");
@@ -318,6 +369,55 @@ public class GitOperations {
}
}
+ public void checkout(Project project, Branch branch) throws Exception {
+
+ try (Git git = new Git(getRepository(project))) {
+
+ Ref ref = git.getRepository().getRef(branch.toString());
+ CheckoutCommand checkout = git.checkout().setName(branch.toString());
+
+ if (ref == null) {
+
+ checkout.setCreateBranch(true).//
+ setUpstreamMode(SetupUpstreamMode.TRACK).//
+ setStartPoint("origin/".concat(branch.toString()));
+ }
+
+ checkout.call();
+ }
+ }
+
+ public void createMaintenanceBranches(TrainIteration iteration) throws Exception {
+
+ checkout(iteration);
+
+ ExecutionUtils.run(iteration, module -> {
+ Branch branch = createMaintenanceBranch(module);
+ checkout(module.getProject(), branch);
+ });
+ }
+
+ private Branch createMaintenanceBranch(ModuleIteration module) throws Exception {
+
+ try (Git git = new Git(getRepository(module.getProject()))) {
+
+ Branch branch = Branch.from(module);
+ git.branchCreate().setName(branch.toString()).call();
+
+ return branch;
+ }
+ }
+
+ /**
+ * Returns the {@link ObjectId} of the commit that is considered the release commit. It is identified by the summary
+ * starting with the release ticket identifier, followed by a dash separated by spaces and the key word
+ * {@code Release}. To prevent skimming through the entire Git history, we expect such a commit to be found within the
+ * 50 most recent commits.
+ *
+ * @param module
+ * @return
+ * @throws Exception
+ */
private ObjectId getReleaseHash(ModuleIteration module) throws Exception {
Project project = module.getProject();
@@ -329,9 +429,7 @@ public class GitOperations {
for (RevCommit commit : git.log().setMaxCount(50).call()) {
- String summary = commit.getShortMessage();
-
- if (summary.startsWith(trigger)) {
+ if (commit.getShortMessage().startsWith(trigger)) {
return commit.getId();
}
}
@@ -351,36 +449,17 @@ public class GitOperations {
*/
private Tag findTagFor(Project project, ArtifactVersion version) {
- return StreamSupport.stream(getTags(project).spliterator(), false).//
+ return getTags(project).stream().//
filter(tag -> tag.toArtifactVersion().map(it -> it.equals(version)).orElse(false)).//
findFirst().orElseThrow(() -> new IllegalArgumentException(
String.format("No tag found for version %s of project %s!", version, project)));
}
- public void checkout(Project project, Branch branch) throws Exception {
-
- try (Git git = new Git(getRepository(project))) {
-
- Ref ref = git.getRepository().getRef(branch.toString());
- CheckoutCommand checkout = git.checkout().setName(branch.toString());
-
- if (ref == null) {
-
- checkout.setCreateBranch(true).//
- setUpstreamMode(SetupUpstreamMode.TRACK).//
- setStartPoint("origin/".concat(branch.toString()));
- }
-
- checkout.call();
-
- }
- }
-
private Repository getRepository(Project project) throws IOException {
return FileRepositoryBuilder.create(workspace.getFile(".git", project));
}
- public void clone(Project project) throws Exception {
+ private void clone(Project project) throws Exception {
Git git = Git.cloneRepository().//
setURI(getGitProject(project).getProjectUri()).//
@@ -390,4 +469,23 @@ public class GitOperations {
git.checkout().setName(Branch.MASTER.toString()).//
call();
}
+
+ private boolean branchExists(Project project, Branch branch) {
+
+ try (Git git = new Git(getRepository(project))) {
+
+ return git.getRepository().getRef(branch.toString()) != null;
+
+ } catch (Exception o_O) {
+ throw new RuntimeException(o_O);
+ }
+ }
+
+ private static void reset(Git git, String name) throws Exception {
+ git.reset().setMode(ResetType.HARD).setRef("origin/".concat(name)).call();
+ }
+
+ private static String expandSummary(String summary, ModuleIteration module, TrainIteration iteration) {
+ return summary.contains("%s") ? String.format(summary, module.getMediumVersionString()) : summary;
+ }
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/git/GitProperties.java b/release-tools/src/main/java/org/springframework/data/release/git/GitProperties.java
index fa73c59..c35f460 100644
--- a/release-tools/src/main/java/org/springframework/data/release/git/GitProperties.java
+++ b/release-tools/src/main/java/org/springframework/data/release/git/GitProperties.java
@@ -57,4 +57,8 @@ public class GitProperties {
public CredentialsProvider getCredentials() {
return new UsernamePasswordCredentialsProvider(username, password);
}
+
+ public String getAuthenticationHeader() {
+ return username.concat(":").concat(password);
+ }
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/git/VersionTags.java b/release-tools/src/main/java/org/springframework/data/release/git/VersionTags.java
index 635e3a0..2b77eb3 100644
--- a/release-tools/src/main/java/org/springframework/data/release/git/VersionTags.java
+++ b/release-tools/src/main/java/org/springframework/data/release/git/VersionTags.java
@@ -21,6 +21,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
+import org.springframework.data.release.Streamable;
import org.springframework.data.release.model.ArtifactVersion;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.util.Assert;
@@ -31,7 +32,7 @@ import org.springframework.util.Assert;
* @author Oliver Gierke
*/
@EqualsAndHashCode
-public class VersionTags implements Iterable {
+public class VersionTags implements Streamable {
private final List tags;
diff --git a/release-tools/src/main/java/org/springframework/data/release/gradle/GradleOperations.java b/release-tools/src/main/java/org/springframework/data/release/gradle/GradleOperations.java
deleted file mode 100644
index 4198b87..0000000
--- a/release-tools/src/main/java/org/springframework/data/release/gradle/GradleOperations.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright 2014 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
- *
- * http://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.gradle;
-
-import static org.springframework.data.release.model.Projects.*;
-
-import lombok.RequiredArgsConstructor;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.release.io.Workspace;
-import org.springframework.data.release.io.Workspace.LineCallback;
-import org.springframework.data.release.maven.Repository;
-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.TrainIteration;
-import org.springframework.data.release.utils.Logger;
-import org.springframework.stereotype.Component;
-
-/**
- * Gradle specific operations.
- *
- * @author Oliver Gierke
- */
-@Component
-@RequiredArgsConstructor(onConstructor = @__(@Autowired) )
-public class GradleOperations {
-
- private static final String BUILD_GRADLE = "build.gradle";
- private static final String GRADLE_PROPERTIES = "gradle.properties";
- private static final String COMMONS_PROPERTY = "springDataCommonsVersion";
- private static final String BUILD_PROPERTY = "springDataBuildVersion";
-
- private final Workspace workspace;
- private final Logger logger;
-
- /**
- * Updates all Gradle projects contained in the release.
- *
- * @param iteration
- * @param phase
- * @throws Exception
- */
- public void updateProject(TrainIteration iteration, final Phase phase) throws Exception {
-
- final Repository repository = new Repository(iteration.getIteration());
- final ArtifactVersion commonsVersion = iteration.getModuleVersion(COMMONS);
- final ArtifactVersion buildVersion = iteration.getModuleVersion(BUILD);
-
- for (ModuleIteration module : iteration.getModulesExcept(BUILD)) {
-
- final Project project = module.getProject();
-
- if (!isGradleProject(project)) {
- continue;
- }
-
- workspace.processFile(GRADLE_PROPERTIES, project, new LineCallback() {
-
- /*
- * (non-Javadoc)
- * @see org.springframework.data.release.io.Workspace.LineCallback#doWith(java.lang.String, long)
- */
- @Override
- public String doWith(String line, long number) {
-
- if (line.contains(COMMONS_PROPERTY)) {
-
- ArtifactVersion version = phase.equals(Phase.PREPARE) ? commonsVersion
- : commonsVersion.getNextDevelopmentVersion();
-
- logger.log(project, "Setting Spring Data Commons version in %s to %s.", GRADLE_PROPERTIES, version);
- return String.format("%s=%s", COMMONS_PROPERTY, version);
- }
-
- if (line.contains(BUILD_PROPERTY)) {
-
- ArtifactVersion version = phase.equals(Phase.PREPARE) ? buildVersion
- : buildVersion.getNextDevelopmentVersion();
-
- logger.log(project, "Setting Spring Data Build version in %s to %s.", GRADLE_PROPERTIES, version);
- return String.format("%s=%s", BUILD_PROPERTY, version);
- }
-
- return line;
- }
- });
-
- workspace.processFile(BUILD_GRADLE, project, new LineCallback() {
-
- /*
- * (non-Javadoc)
- * @see org.springframework.data.release.io.Workspace.LineCallback#doWith(java.lang.String, long)
- */
- @Override
- public String doWith(String line, long number) {
-
- String snapshotUrl = repository.getSnapshotUrl();
- String releaseUrl = repository.getUrl();
- String message = "Switching to Spring repository %s";
-
- switch (phase) {
- case CLEANUP:
- logger.log(project, message, snapshotUrl);
- return line.contains(releaseUrl) ? line.replace(releaseUrl, snapshotUrl) : line;
- case PREPARE:
- default:
- logger.log(project, message, releaseUrl);
- return line.contains(snapshotUrl) ? line.replace(snapshotUrl, releaseUrl) : line;
- }
- }
- });
- }
- }
-
- /**
- * Returns whether the given project is a Gradle project (checks for the presence of a build.gradle file).
- *
- * @param project
- * @return
- */
- private boolean isGradleProject(Project project) {
- return workspace.getFile(BUILD_GRADLE, project).exists();
- }
-}
diff --git a/release-tools/src/main/java/org/springframework/data/release/io/CommonsExecOsCommandOperations.java b/release-tools/src/main/java/org/springframework/data/release/io/CommonsExecOsCommandOperations.java
index 4eed8fa..674c807 100644
--- a/release-tools/src/main/java/org/springframework/data/release/io/CommonsExecOsCommandOperations.java
+++ b/release-tools/src/main/java/org/springframework/data/release/io/CommonsExecOsCommandOperations.java
@@ -15,8 +15,6 @@
*/
package org.springframework.data.release.io;
-import lombok.RequiredArgsConstructor;
-
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
@@ -35,22 +33,35 @@ import org.springframework.data.release.utils.Logger;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
/**
- * Implementation of {@link OsCommandOperations} interface.
+ * Implementation of {@link OsOperations} interface.
*
* @author Stefan Schmidt
* @author Oliver Gierke
* @since 1.2.0
*/
@Component
-@RequiredArgsConstructor(onConstructor = @__(@Autowired) )
-class CommonsExecOsCommandOperations implements OsCommandOperations {
+class CommonsExecOsCommandOperations implements OsOperations {
private static final Map ENVIRONMENT = new HashMap<>();
private final Workspace workspace;
private final Logger logger;
+ private final File javaHome;
+
+ @Autowired
+ public CommonsExecOsCommandOperations(Workspace workspace, Logger logger, IoProperties properties) throws Exception {
+
+ this.workspace = workspace;
+ this.logger = logger;
+ this.javaHome = detectJavaHome(properties);
+
+ Assert.isTrue(javaHome.exists(), String.format("Java home %s does not exist!", javaHome.getAbsolutePath()));
+
+ ENVIRONMENT.put("JAVA_HOME", javaHome.getAbsolutePath());
+ }
/*
* (non-Javadoc)
@@ -133,20 +144,24 @@ class CommonsExecOsCommandOperations implements OsCommandOperations {
new CommandResult(resultHandler.getExitValue(), writer.toString(), resultHandler.getException()));
}
- /**
- * Adds {@code JAVA_HOME} to the ENVIRONMENT variables looking up the path to a Java 7.
- *
- * @throws Exception
- */
- // @PostConstruct
- public void initialize() throws Exception {
+ public File getJavaHome() {
+ return javaHome;
+ }
- String javaHome = executeCommand("/usr/libexec/java_home -F -v 1.8 -a x86_64 -d64").get().getOutput();
+ private File detectJavaHome(IoProperties properties) throws Exception {
- if (javaHome.endsWith("\n")) {
- javaHome = javaHome.substring(0, javaHome.length() - 1);
+ File javaHome = properties.getJavaHome();
+
+ if (javaHome != null) {
+ return javaHome;
}
- ENVIRONMENT.put("JAVA_HOME", javaHome);
+ String javaHomePath = executeCommand("/usr/libexec/java_home -F -v 1.8 -a x86_64 -d64").get().getOutput();
+
+ if (javaHomePath.endsWith("\n")) {
+ javaHomePath = javaHomePath.substring(0, javaHomePath.length() - 1);
+ }
+
+ return new File(javaHomePath);
}
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/io/IoProperties.java b/release-tools/src/main/java/org/springframework/data/release/io/IoProperties.java
index aca10cd..fdb5a71 100644
--- a/release-tools/src/main/java/org/springframework/data/release/io/IoProperties.java
+++ b/release-tools/src/main/java/org/springframework/data/release/io/IoProperties.java
@@ -30,17 +30,19 @@ import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "io")
-public class IoProperties {
+class IoProperties {
- private String workDir;
+ private File workDir, javaHome;
public void setWorkDir(String workDir) {
- this.workDir = workDir.replace("~", System.getProperty("user.home"));
log.info(String.format("Using %s as working directory!", workDir));
+ this.workDir = new File(workDir.replace("~", System.getProperty("user.home")));
}
- public File getWorkDir() {
- return new File(workDir);
+ public void setJavaHome(String javaHome) {
+
+ log.info(String.format("Using %s as Java home!", javaHome));
+ this.workDir = new File(javaHome.replace("~", System.getProperty("user.home")));
}
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/io/OsCommandOperations.java b/release-tools/src/main/java/org/springframework/data/release/io/OsOperations.java
similarity index 95%
rename from release-tools/src/main/java/org/springframework/data/release/io/OsCommandOperations.java
rename to release-tools/src/main/java/org/springframework/data/release/io/OsOperations.java
index 8d18e35..6ef74a2 100644
--- a/release-tools/src/main/java/org/springframework/data/release/io/OsCommandOperations.java
+++ b/release-tools/src/main/java/org/springframework/data/release/io/OsOperations.java
@@ -15,6 +15,7 @@
*/
package org.springframework.data.release.io;
+import java.io.File;
import java.io.IOException;
import java.util.concurrent.Future;
@@ -26,7 +27,7 @@ import org.springframework.data.release.model.Project;
* @author Stefan Schmidt
* @since 1.2.0
*/
-public interface OsCommandOperations {
+public interface OsOperations {
/**
* Attempts the execution of a commands and delegates the output to the standard logger.
@@ -41,4 +42,6 @@ public interface OsCommandOperations {
Future executeWithOutput(String command, Project project) throws IOException;
String executeForResult(String command, Project project) throws Exception;
+
+ File getJavaHome();
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/io/Workspace.java b/release-tools/src/main/java/org/springframework/data/release/io/Workspace.java
index dfdeed3..3f4f292 100644
--- a/release-tools/src/main/java/org/springframework/data/release/io/Workspace.java
+++ b/release-tools/src/main/java/org/springframework/data/release/io/Workspace.java
@@ -15,17 +15,23 @@
*/
package org.springframework.data.release.io;
+import static org.springframework.data.release.utils.StreamUtils.*;
+
import lombok.RequiredArgsConstructor;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Path;
+import java.util.Arrays;
import java.util.Scanner;
+import java.util.stream.Stream;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.data.release.model.Project;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@@ -44,6 +50,7 @@ public class Workspace {
private static final Charset UTF_8 = Charset.forName("UTF-8");
private final IoProperties ioProperties;
+ private final ResourcePatternResolver resolver;
/**
* Returns the current working directory.
@@ -93,7 +100,23 @@ public class Workspace {
return new File(getProjectDirectory(project), name);
}
- public boolean processFile(String filename, Project project, LineCallback callback) throws Exception {
+ public Stream getFiles(String pattern, Project project) {
+
+ File projectDirectory = getProjectDirectory(project);
+ String patternToLookup = String.format("file:%s/%s", projectDirectory.getAbsolutePath(), pattern);
+
+ try {
+ return Arrays.stream(resolver.getResources(patternToLookup)).map(wrap(Resource::getFile));
+ } catch (IOException o_O) {
+ throw new RuntimeException(o_O);
+ }
+ }
+
+ public boolean processFiles(String pattern, Project project, LineCallback callback) {
+ return false;
+ }
+
+ public boolean processFile(String filename, Project project, LineCallback callback) {
File file = getFile(filename, project);
@@ -115,9 +138,13 @@ public class Workspace {
builder.append(result).append("\n");
}
}
+
+ writeContentToFile(filename, project, builder.toString());
+
+ } catch (Exception o_O) {
+ throw new RuntimeException(o_O);
}
- writeContentToFile(filename, project, builder.toString());
return true;
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/jira/GitHubIssue.java b/release-tools/src/main/java/org/springframework/data/release/jira/GitHubIssue.java
index 10578d5..3a8f738 100644
--- a/release-tools/src/main/java/org/springframework/data/release/jira/GitHubIssue.java
+++ b/release-tools/src/main/java/org/springframework/data/release/jira/GitHubIssue.java
@@ -33,6 +33,6 @@ class GitHubIssue {
}
public boolean isReleaseTicket(ModuleIteration module) {
- return title.contains("Release") && title.contains(module.getVersionString());
+ return title.contains("Release") && title.contains(module.getShortVersionString());
}
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/jira/GitHubIssueTracker.java b/release-tools/src/main/java/org/springframework/data/release/jira/GitHubIssueTracker.java
index 540b1bb..54bbc04 100644
--- a/release-tools/src/main/java/org/springframework/data/release/jira/GitHubIssueTracker.java
+++ b/release-tools/src/main/java/org/springframework/data/release/jira/GitHubIssueTracker.java
@@ -18,18 +18,20 @@ package org.springframework.data.release.jira;
import lombok.RequiredArgsConstructor;
import java.net.URI;
+import java.nio.charset.Charset;
import java.util.Arrays;
+import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.data.release.git.GitProject;
+import org.springframework.data.release.git.GitProperties;
import org.springframework.data.release.git.GitServer;
import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.ModuleIteration;
@@ -39,16 +41,16 @@ import org.springframework.data.release.model.ReleaseTrains;
import org.springframework.data.release.model.Tracker;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.data.release.utils.Logger;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
-import org.springframework.stereotype.Component;
import org.springframework.web.client.RestOperations;
import org.springframework.web.util.UriTemplate;
/**
* @author Oliver Gierke
*/
-@Component
-@RequiredArgsConstructor(onConstructor = @__(@Autowired) )
+@RequiredArgsConstructor
class GitHubIssueTracker implements IssueTracker {
private static final String MILESTONE_URI = "https://api.github.com/repos/spring-projects/{repoName}/milestones?state={state}";
@@ -59,6 +61,7 @@ class GitHubIssueTracker implements IssueTracker {
private final RestOperations operations;
private final Logger logger;
+ private final GitProperties properties;
/*
* (non-Javadoc)
@@ -112,7 +115,9 @@ class GitHubIssueTracker implements IssueTracker {
parameters.put("repoName", repositoryName);
parameters.put("id", milestone.getNumber());
- return operations.exchange(URI_TEMPLATE, HttpMethod.GET, null, ISSUES_TYPE, parameters).getBody();
+ return operations
+ .exchange(URI_TEMPLATE, HttpMethod.GET, new HttpEntity<>(getAuthenticationHeaders()), ISSUES_TYPE, parameters)
+ .getBody();
}
private GitHubMilestone findMilestone(ModuleIteration module, String repositoryName) {
@@ -127,13 +132,13 @@ class GitHubIssueTracker implements IssueTracker {
logger.log(module, "Looking up milestone from %s…", milestoneUri);
- List exchange = operations
- .exchange(MILESTONE_URI, HttpMethod.GET, null, MILESTONES_TYPE, parameters).getBody();
+ List exchange = operations.exchange(MILESTONE_URI, HttpMethod.GET,
+ new HttpEntity<>(getAuthenticationHeaders()), MILESTONES_TYPE, parameters).getBody();
GitHubMilestone milestone = null;
for (GitHubMilestone candidate : exchange) {
- if (candidate.getTitle().contains(module.getVersionString())) {
+ if (candidate.getTitle().contains(module.getShortVersionString())) {
milestone = candidate;
}
}
@@ -144,7 +149,19 @@ class GitHubIssueTracker implements IssueTracker {
}
}
- throw new IllegalStateException(String.format("No milestone found containing %s!", module.getVersionString()));
+ throw new IllegalStateException(String.format("No milestone found containing %s!", module.getShortVersionString()));
+ }
+
+ private HttpHeaders getAuthenticationHeaders() {
+
+ byte[] encodedAuth = Base64.getEncoder()
+ .encode(properties.getAuthenticationHeader().getBytes(Charset.forName("US-ASCII")));
+ String authHeader = "Basic " + new String(encodedAuth);
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.set("Authorization", authHeader);
+
+ return headers;
}
public static void main(String[] args) {
diff --git a/release-tools/src/main/java/org/springframework/data/release/jira/JiraConfiguration.java b/release-tools/src/main/java/org/springframework/data/release/jira/IssueTrackerConfiguration.java
similarity index 73%
rename from release-tools/src/main/java/org/springframework/data/release/jira/JiraConfiguration.java
rename to release-tools/src/main/java/org/springframework/data/release/jira/IssueTrackerConfiguration.java
index 6a87c67..5b92b03 100644
--- a/release-tools/src/main/java/org/springframework/data/release/jira/JiraConfiguration.java
+++ b/release-tools/src/main/java/org/springframework/data/release/jira/IssueTrackerConfiguration.java
@@ -23,10 +23,13 @@ import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.PropertySource;
+import org.springframework.data.release.git.GitProperties;
+import org.springframework.data.release.model.Project;
+import org.springframework.data.release.utils.Logger;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
-import org.springframework.plugin.core.config.EnablePluginRegistries;
+import org.springframework.plugin.core.OrderAwarePluginRegistry;
+import org.springframework.plugin.core.PluginRegistry;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.DeserializationFeature;
@@ -37,15 +40,18 @@ import com.fasterxml.jackson.databind.ObjectMapper;
*/
@Configuration
@EnableCaching
-@PropertySource(value = "file:jira.properties", ignoreResourceNotFound = true)
-@EnablePluginRegistries({ IssueTracker.class })
-class JiraConfiguration {
+class IssueTrackerConfiguration {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
+ @Bean
+ public PluginRegistry issueTrackers(List extends IssueTracker> plugins) {
+ return OrderAwarePluginRegistry.create(plugins);
+ }
+
@Bean
public ObjectMapper jacksonObjectMapper() {
@@ -69,4 +75,14 @@ class JiraConfiguration {
return template;
}
+
+ @Bean
+ public Jira jira(Logger logger) {
+ return new Jira(restTemplate(), logger);
+ }
+
+ @Bean
+ public GitHubIssueTracker github(Logger logger, GitProperties properties) {
+ return new GitHubIssueTracker(restTemplate(), logger, properties);
+ }
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/jira/Jira.java b/release-tools/src/main/java/org/springframework/data/release/jira/Jira.java
index ca50090..10c02d3 100644
--- a/release-tools/src/main/java/org/springframework/data/release/jira/Jira.java
+++ b/release-tools/src/main/java/org/springframework/data/release/jira/Jira.java
@@ -24,7 +24,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
@@ -40,15 +39,13 @@ import org.springframework.data.release.utils.Logger;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
-import org.springframework.stereotype.Component;
import org.springframework.web.client.RestOperations;
import org.springframework.web.util.UriTemplate;
/**
* @author Oliver Gierke
*/
-@Component
-@RequiredArgsConstructor(onConstructor = @__(@Autowired) )
+@RequiredArgsConstructor
class Jira implements JiraConnector {
private static final String JIRA_HOST = "https://jira.spring.io";
diff --git a/release-tools/src/main/java/org/springframework/data/release/jira/JiraVersion.java b/release-tools/src/main/java/org/springframework/data/release/jira/JiraVersion.java
index 5928d33..3e08b41 100644
--- a/release-tools/src/main/java/org/springframework/data/release/jira/JiraVersion.java
+++ b/release-tools/src/main/java/org/springframework/data/release/jira/JiraVersion.java
@@ -17,10 +17,7 @@ package org.springframework.data.release.jira;
import lombok.Value;
-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.Train;
/**
* @author Oliver Gierke
@@ -28,16 +25,7 @@ import org.springframework.data.release.model.Train;
@Value
class JiraVersion {
- private final Module module;
- private final Train train;
- private final Iteration iteration;
-
- public JiraVersion(ModuleIteration moduleIteration) {
-
- this.module = moduleIteration.getModule();
- this.iteration = moduleIteration.getIteration();
- this.train = moduleIteration.getTrain();
- }
+ private ModuleIteration module;
/*
* (non-Javadoc)
@@ -45,15 +33,6 @@ class JiraVersion {
*/
@Override
public String toString() {
-
- Iteration iteration = this.iteration.isInitialIteration() && module.hasCustomFirstIteration() ? module
- .getCustomFirstIteration() : this.iteration;
-
- if (iteration.isServiceIteration()) {
- return String.format("%s.%s (%s %s)", module.getVersion(), iteration.getBugfixValue(), train.getName(),
- iteration.getName());
- }
-
- return String.format("%s %s (%s)", module.getVersion(), iteration.getName(), train.getName());
+ return module.getMediumVersionString();
}
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/jira/JqlQuery.java b/release-tools/src/main/java/org/springframework/data/release/jira/JqlQuery.java
index d54d1c6..b8dd9e2 100644
--- a/release-tools/src/main/java/org/springframework/data/release/jira/JqlQuery.java
+++ b/release-tools/src/main/java/org/springframework/data/release/jira/JqlQuery.java
@@ -17,11 +17,11 @@ package org.springframework.data.release.jira;
import static org.springframework.data.release.model.Projects.*;
+import lombok.Value;
+
import java.util.ArrayList;
import java.util.List;
-import lombok.Value;
-
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.util.StringUtils;
diff --git a/release-tools/src/main/java/org/springframework/data/release/maven/MavenOperations.java b/release-tools/src/main/java/org/springframework/data/release/maven/MavenOperations.java
deleted file mode 100644
index 7de4df7..0000000
--- a/release-tools/src/main/java/org/springframework/data/release/maven/MavenOperations.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright 2014 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
- *
- * http://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.maven;
-
-import static org.springframework.data.release.model.Phase.*;
-import static org.springframework.data.release.model.Projects.*;
-
-import lombok.RequiredArgsConstructor;
-
-import java.io.File;
-import java.io.IOException;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.core.GenericTypeResolver;
-import org.springframework.data.release.io.CommandResult;
-import org.springframework.data.release.io.OsCommandOperations;
-import org.springframework.data.release.io.Workspace;
-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.Train;
-import org.springframework.data.release.model.TrainIteration;
-import org.springframework.data.release.utils.ExecutionUtils;
-import org.springframework.data.release.utils.Logger;
-import org.springframework.stereotype.Component;
-import org.springframework.util.Assert;
-import org.xmlbeam.ProjectionFactory;
-import org.xmlbeam.io.XBFileIO;
-
-/**
- * @author Oliver Gierke
- */
-@Component
-@RequiredArgsConstructor(onConstructor = @__(@Autowired) )
-public class MavenOperations {
-
- private static final String POM_XML = "pom.xml";
-
- private final Workspace workspace;
- private final ProjectionFactory projectionFactory;
- private final OsCommandOperations os;
- private final Logger logger;
-
- public Pom getMavenProject(Project project) throws IOException {
-
- File file = workspace.getFile(POM_XML, project);
- return projectionFactory.io().file(file).read(Pom.class);
- }
-
- /**
- * Updates the POM files for all Maven projects contained in the iteration:
- *
- * - Updates the BOM POM.
- * - Updates the dependency version to Spring Data Commons to the current release version for all projects depending
- * on it.
- * - Switches to the Spring release Maven repository.
- *
- * If {@link Phase} is {@link Phase#CLEANUP} the changes will be rolled back.
- *
- * @param iteration must not be {@literal null}.
- * @param phase must not be {@literal null}.
- * @throws Exception
- */
- public void updatePom(TrainIteration iteration, final Phase phase) throws Exception {
-
- Assert.notNull(iteration, "Train iteration must not be null!");
- Assert.notNull(phase, "Phase must not be null!");
-
- updateBomPom(iteration, phase);
-
- final Repository repository = new Repository(iteration.getIteration());
- final ArtifactVersion buildVersion = iteration.getModuleVersion(BUILD);
- final ArtifactVersion nextBuildVersion = buildVersion.getNextDevelopmentVersion();
-
- // Fix version of shared resources to to-be-released version.
- execute(workspace.getFile("parent/pom.xml", BUILD), new PomCallback() {
-
- @Override
- public void doWith(ParentPom pom) {
- pom.setSharedResourcesVersion(phase.equals(PREPARE) ? buildVersion : nextBuildVersion);
- }
- });
-
- for (ModuleIteration module : iteration.getModulesExcept(BUILD)) {
-
- final Project project = module.getProject();
-
- if (!isMavenProject(project)) {
- logger.log(module, "No pom.xml file found, skipping project.");
- continue;
- }
-
- execute(workspace.getFile(POM_XML, project), new PomCallback() {
-
- @Override
- public void doWith(Pom pom) {
-
- for (Project dependency : project.getDependencies()) {
-
- String dependencyProperty = dependency.getDependencyProperty();
-
- if (pom.getProperty(dependencyProperty) == null) {
- continue;
- }
-
- ArtifactVersion dependencyVersion = iteration.getModuleVersion(dependency);
- ArtifactVersion version = CLEANUP.equals(phase) ? dependencyVersion.getNextDevelopmentVersion()
- : dependencyVersion;
-
- logger.log(project, "Updating %s dependency version property %s to %s.", dependency.getFullName(),
- dependencyProperty, version);
- pom.setProperty(dependencyProperty, version);
- }
-
- ArtifactVersion version = CLEANUP.equals(phase) ? nextBuildVersion : buildVersion;
- logger.log(project, "Updating Spring Data Build Parent version to %s.", version);
- pom.setParentVersion(version);
-
- updateRepository(project, pom, repository, phase);
- }
- });
- }
- }
-
- /**
- * Triggers building the distribution artifacts for all Maven projects of the given {@link Train}.
- *
- * @param train
- * @param iteration
- * @throws IOException
- * @throws InterruptedException
- */
- public void triggerDistributionBuild(TrainIteration iteration) throws Exception {
-
- ExecutionUtils.run(iteration, module -> {
-
- Project project = module.getProject();
-
- if (BUILD.equals(project)) {
- return;
- }
-
- if (!isMavenProject(project)) {
- logger.log(project, "Skipping project as no pom.xml could be found in the working directory!");
- return;
- }
-
- logger.log(project, "Triggering distribution build…");
-
- ArtifactVersion version = ArtifactVersion.of(module);
-
- String command = "mvn clean deploy -DskipTests -Pdistribute";
-
- if (version.isMilestoneVersion()) {
- command = command.concat(",milestone");
- } else if (version.isReleaseVersion()) {
- command = command.concat(",release");
- }
-
- CommandResult result = os.executeWithOutput(command, module.getProject()).get();
-
- if (result.hasError()) {
- throw result.getException();
- }
-
- logger.log(project, "Successfully finished distribution build!");
- });
- }
-
- private boolean isMavenProject(Project project) {
- return workspace.getFile(POM_XML, project).exists();
- }
-
- private void updateBomPom(final TrainIteration iteration, final Phase phase) throws Exception {
-
- File bomPomFile = workspace.getFile("bom/pom.xml", BUILD);
-
- logger.log(BUILD, "Updating BOM pom.xml…");
-
- execute(bomPomFile, new PomCallback() {
-
- @Override
- public void doWith(Pom pom) {
-
- for (ModuleIteration module : iteration.getModulesExcept(BUILD)) {
-
- Artifact artifact = new Artifact(module);
- ArtifactVersion version = artifact.getVersion();
- version = PREPARE.equals(phase) ? version : version.getNextDevelopmentVersion();
-
- logger.log(BUILD, "%s", module);
-
- pom.setDependencyManagementVersion(artifact.getArtifactId(), version);
-
- for (String additionalArtifact : module.getProject().getAdditionalArtifacts()) {
- pom.setDependencyManagementVersion(additionalArtifact, version);
- }
- }
- }
- });
- }
-
- private void updateRepository(Project project, Pom pom, Repository repository, Phase phase) {
-
- String message = "Switching to Spring repository %s (%s).";
-
- if (PREPARE.equals(phase)) {
-
- logger.log(project, message, repository.getId(), repository.getUrl());
-
- pom.setRepositoryId(repository.getSnapshotId(), repository.getId());
- pom.setRepositoryUrl(repository.getId(), repository.getUrl());
-
- } else {
-
- logger.log(project, message, repository.getSnapshotId(), repository.getSnapshotUrl());
-
- pom.setRepositoryId(repository.getId(), repository.getSnapshotId());
- pom.setRepositoryUrl(repository.getSnapshotId(), repository.getSnapshotUrl());
- }
- }
-
- @SuppressWarnings("unchecked")
- private void execute(File file, PomCallback callback) throws Exception {
-
- XBFileIO io = projectionFactory.io().file(file);
- Class> typeArgument = GenericTypeResolver.resolveTypeArgument(callback.getClass(), PomCallback.class);
-
- T pom = (T) io.read(typeArgument);
- callback.doWith(pom);
- io.write(pom);
- }
-
- private interface PomCallback {
- public void doWith(T pom);
- }
-}
diff --git a/release-tools/src/main/java/org/springframework/data/release/misc/ReleaseOperations.java b/release-tools/src/main/java/org/springframework/data/release/misc/ReleaseOperations.java
index 04a9013..b270720 100644
--- a/release-tools/src/main/java/org/springframework/data/release/misc/ReleaseOperations.java
+++ b/release-tools/src/main/java/org/springframework/data/release/misc/ReleaseOperations.java
@@ -24,7 +24,6 @@ import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.release.git.GitOperations;
import org.springframework.data.release.io.Workspace;
-import org.springframework.data.release.io.Workspace.LineCallback;
import org.springframework.data.release.jira.Changelog;
import org.springframework.data.release.jira.IssueTracker;
import org.springframework.data.release.model.Iteration;
@@ -77,27 +76,23 @@ public class ReleaseOperations {
for (String location : CHANGELOG_LOCATIONS) {
- boolean processed = workspace.processFile(location, module.getProject(), new LineCallback() {
+ boolean processed = workspace.processFile(location, module.getProject(), (line, number) -> {
- @Override
- public String doWith(String line, long number) {
+ if (line.startsWith("=")) {
- if (line.startsWith("=")) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(line).append("\n\n");
+ builder.append(changelog.toString());
- StringBuilder builder = new StringBuilder();
- builder.append(line).append("\n\n");
- builder.append(changelog.toString());
-
- return builder.toString();
- } else {
- return line;
- }
+ return builder.toString();
+ } else {
+ return line;
}
});
if (processed) {
- git.commit(module, "Updated changelog.", null);
+ git.commit(module, "Updated changelog.");
logger.log(module.getProject(), "Updated changelog %s.", location);
}
@@ -107,25 +102,14 @@ public class ReleaseOperations {
public void updateResources(TrainIteration iteration) throws Exception {
- for (final ModuleIteration module : iteration) {
+ iteration.stream().forEach(module -> {
boolean processed = workspace.processFile("src/main/resources/notice.txt", module.getProject(),
- new LineCallback() {
-
- @Override
- public String doWith(String line, long number) {
-
- if (number != 0) {
- return line;
- }
-
- return module.toString();
- }
- });
+ (line, number) -> number != 0 ? line : module.toString());
if (processed) {
logger.log(module, "Updated notice.txt.");
}
- }
+ });
}
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/maven/MavenProject.java b/release-tools/src/main/java/org/springframework/data/release/model/ArtifactCoordinate.java
similarity index 52%
rename from release-tools/src/main/java/org/springframework/data/release/maven/MavenProject.java
rename to release-tools/src/main/java/org/springframework/data/release/model/ArtifactCoordinate.java
index c010c31..46f8693 100644
--- a/release-tools/src/main/java/org/springframework/data/release/maven/MavenProject.java
+++ b/release-tools/src/main/java/org/springframework/data/release/model/ArtifactCoordinate.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2015 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.
@@ -13,30 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.data.release.maven;
+package org.springframework.data.release.model;
import lombok.Value;
-import org.springframework.data.release.model.ArtifactVersion;
-import org.springframework.data.release.model.Module;
-
/**
* @author Oliver Gierke
*/
-@Value
-class MavenProject {
+@Value(staticConstructor = "of")
+public class ArtifactCoordinate {
- private final Module module;
+ String groupId, artifactId;
- public String getGroupId() {
- return "org.springframework.data";
- }
+ public static ArtifactCoordinate from(String coordinate) {
- public String getArtifactId() {
- return String.format("spring-data-%s", module.getProject().getName().toLowerCase());
- }
-
- public ArtifactVersion getReleaseVersion() {
- return ArtifactVersion.of(module.getVersion());
+ String[] parts = coordinate.split(":");
+ return new ArtifactCoordinate(parts[0], parts[1]);
}
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/model/ArtifactCoordinates.java b/release-tools/src/main/java/org/springframework/data/release/model/ArtifactCoordinates.java
new file mode 100644
index 0000000..b46f9d8
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/model/ArtifactCoordinates.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2015 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
+ *
+ * http://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.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author Oliver Gierke
+ */
+@RequiredArgsConstructor
+public class ArtifactCoordinates {
+
+ public static ArtifactCoordinates NONE = forGroupId("org.springframework.data");
+
+ private final String groupId;
+ private final @Getter(AccessLevel.PACKAGE) List coordinates;
+
+ public static ArtifactCoordinates forGroupId(String groupId) {
+ return new ArtifactCoordinates(groupId, new ArrayList<>());
+ }
+
+ public ArtifactCoordinates artifacts(String... artifactIds) {
+
+ return new ArtifactCoordinates(groupId,
+ Arrays.stream(artifactIds)//
+ .map(artifactId -> ArtifactCoordinate.of(groupId, artifactId))//
+ .collect(Collectors.toList()));
+ }
+
+ public ArtifactCoordinates artifact(ArtifactCoordinate coordinate) {
+
+ List artifacts = new ArrayList<>(coordinates);
+ artifacts.add(coordinate);
+
+ return new ArtifactCoordinates(groupId, artifacts);
+ }
+
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/model/IterationVersion.java b/release-tools/src/main/java/org/springframework/data/release/model/IterationVersion.java
index 09ee3bc..9016003 100644
--- a/release-tools/src/main/java/org/springframework/data/release/model/IterationVersion.java
+++ b/release-tools/src/main/java/org/springframework/data/release/model/IterationVersion.java
@@ -20,9 +20,9 @@ package org.springframework.data.release.model;
*
* @author Oliver Gierke
*/
-public interface IterationVersion {
-
- Version getVersion();
+public interface IterationVersion extends VersionAware {
Iteration getIteration();
+
+ boolean isServiceIteration();
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/model/Module.java b/release-tools/src/main/java/org/springframework/data/release/model/Module.java
index 73bc537..84e9b31 100644
--- a/release-tools/src/main/java/org/springframework/data/release/model/Module.java
+++ b/release-tools/src/main/java/org/springframework/data/release/model/Module.java
@@ -23,7 +23,7 @@ import org.springframework.util.Assert;
* @author Oliver Gierke
*/
@Value
-public class Module {
+public class Module implements VersionAware {
private final Project project;
private final Version version;
diff --git a/release-tools/src/main/java/org/springframework/data/release/model/ModuleIteration.java b/release-tools/src/main/java/org/springframework/data/release/model/ModuleIteration.java
index 815be00..eaec3c4 100644
--- a/release-tools/src/main/java/org/springframework/data/release/model/ModuleIteration.java
+++ b/release-tools/src/main/java/org/springframework/data/release/model/ModuleIteration.java
@@ -27,8 +27,14 @@ import lombok.RequiredArgsConstructor;
public class ModuleIteration implements IterationVersion {
private final @Getter Module module;
- private final Iteration iteration;
- private final @Getter Train train;
+ private final @Getter TrainIteration trainIteration;
+
+ /**
+ * @return the train
+ */
+ public Train getTrain() {
+ return trainIteration.getTrain();
+ }
public ProjectKey getProjectKey() {
return module.getProject().getKey();
@@ -52,20 +58,33 @@ public class ModuleIteration implements IterationVersion {
* @see org.springframework.data.release.model.IterationVersion#getIteration()
*/
public Iteration getIteration() {
- return this.iteration.isInitialIteration() && this.module.hasCustomFirstIteration() ? module
- .getCustomFirstIteration() : this.iteration;
+
+ return trainIteration.getIteration().isInitialIteration() && this.module.hasCustomFirstIteration()
+ ? module.getCustomFirstIteration() : this.trainIteration.getIteration();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.release.model.IterationVersion#isServiceIteration()
+ */
+ @Override
+ public boolean isServiceIteration() {
+ return getIteration().isServiceIteration();
}
/**
- * Returns the {@link String} representation of the logical version of the {@link ModuleIteration}.
+ * Returns the {@link String} representation of the logical version of the {@link ModuleIteration}. This will
+ * abbreviate trailing zeros and not include the release train name.
*
* @return
*/
- public String getVersionString() {
+ public String getShortVersionString() {
StringBuilder builder = new StringBuilder();
builder.append(ArtifactVersion.of(this).toShortString());
+ Iteration iteration = trainIteration.getIteration();
+
if (!iteration.isServiceIteration()) {
builder.append(" ").append(iteration.getName());
}
@@ -73,12 +92,41 @@ public class ModuleIteration implements IterationVersion {
return builder.toString();
}
+ public String getMediumVersionString() {
+
+ StringBuilder builder = new StringBuilder();
+ builder.append(ArtifactVersion.of(this).toShortString());
+
+ Iteration iteration = trainIteration.getIteration();
+
+ if (iteration.isServiceIteration()) {
+ builder.append(" (").append(trainIteration.toString());
+ } else {
+ builder.append(" ").append(iteration.getName()).append(" (");
+ builder.append(trainIteration.getTrain().getName());
+ }
+
+ return builder.append(")").toString();
+ }
+
+ /**
+ * Returns the {@link String} representation of the logical version of the {@link ModuleIteration}. This will use the
+ * technical version string and append the train iteration.
+ *
+ * @return
+ */
+ public String getFullVersionString() {
+
+ String result = ArtifactVersion.of(this).toString();
+ return result.concat(" (").concat(trainIteration.toString()).concat(")");
+ }
+
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
- return String.format("%s %s", module.getProject().getFullName(), getVersionString());
+ return String.format("%s %s", module.getProject().getFullName(), getShortVersionString());
}
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/model/Modules.java b/release-tools/src/main/java/org/springframework/data/release/model/Modules.java
new file mode 100644
index 0000000..4965380
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/model/Modules.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 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
+ *
+ * http://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.RequiredArgsConstructor;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.springframework.data.release.Streamable;
+
+/**
+ * @author Oliver Gierke
+ */
+@RequiredArgsConstructor
+public class Modules implements Streamable {
+
+ private final Collection modules;
+
+ public Iterator iterator() {
+ return modules.iterator();
+ }
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/model/Phase.java b/release-tools/src/main/java/org/springframework/data/release/model/Phase.java
index e35b9fa..65d13c0 100644
--- a/release-tools/src/main/java/org/springframework/data/release/model/Phase.java
+++ b/release-tools/src/main/java/org/springframework/data/release/model/Phase.java
@@ -20,5 +20,5 @@ package org.springframework.data.release.model;
*/
public enum Phase {
- PREPARE, CLEANUP;
+ PREPARE, CLEANUP, MAINTENANCE;
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/model/Project.java b/release-tools/src/main/java/org/springframework/data/release/model/Project.java
index 9df3281..a1919b3 100644
--- a/release-tools/src/main/java/org/springframework/data/release/model/Project.java
+++ b/release-tools/src/main/java/org/springframework/data/release/model/Project.java
@@ -19,8 +19,8 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
-import java.util.Collections;
import java.util.List;
+import java.util.function.Consumer;
import org.springframework.util.Assert;
@@ -35,17 +35,18 @@ public class Project {
private final @Getter String name;
private final @Getter List dependencies;
private final Tracker tracker;
- private final @Getter List additionalArtifacts;
+ private final @Getter ArtifactCoordinates additionalArtifacts;
Project(String key, String name, List dependencies) {
- this(key, name, Tracker.JIRA, dependencies, Collections.emptyList());
+ this(key, name, Tracker.JIRA, dependencies, ArtifactCoordinates.NONE);
}
- Project(String key, String name, List dependencies, List additionalArtifacts) {
+ Project(String key, String name, List dependencies, ArtifactCoordinates additionalArtifacts) {
this(key, name, Tracker.JIRA, dependencies, additionalArtifacts);
}
- Project(String key, String name, Tracker tracker, List dependencies, List additionalArtifacts) {
+ Project(String key, String name, Tracker tracker, List dependencies,
+ ArtifactCoordinates additionalArtifacts) {
this.key = new ProjectKey(key);
this.name = name;
@@ -66,6 +67,10 @@ public class Project {
return "springdata.".concat(name.toLowerCase());
}
+ public void doWithAdditionalArtifacts(Consumer consumer) {
+ additionalArtifacts.getCoordinates().forEach(consumer);
+ }
+
/**
* Returns whether the current project depends on the given one.
*
@@ -75,6 +80,7 @@ public class Project {
public boolean dependsOn(Project project) {
Assert.notNull(project, "Project must not be null!");
- return dependencies.contains(project);
+
+ return dependencies.stream().anyMatch(dependency -> dependency.equals(project) || dependency.dependsOn(project));
}
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/model/Projects.java b/release-tools/src/main/java/org/springframework/data/release/model/Projects.java
index 351cfcd..dc18ae9 100644
--- a/release-tools/src/main/java/org/springframework/data/release/model/Projects.java
+++ b/release-tools/src/main/java/org/springframework/data/release/model/Projects.java
@@ -15,10 +15,16 @@
*/
package org.springframework.data.release.model;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
+import org.jgrapht.graph.DefaultDirectedGraph;
+import org.jgrapht.graph.DefaultEdge;
+import org.jgrapht.traverse.TopologicalOrderIterator;
+
/**
* @author Oliver Gierke
*/
@@ -30,26 +36,60 @@ public class Projects {
static {
- BUILD = new Project("DATABUILD", "Build", Tracker.GITHUB, Collections.emptyList(), Collections.emptyList());
+ BUILD = new Project("DATABUILD", "Build", Tracker.GITHUB, Collections.emptyList(),
+ ArtifactCoordinates.forGroupId("org.springframework.data.build")
+ .artifacts("spring-data-build-parent", "spring-data-build-resources")
+ .artifact(ArtifactCoordinate.of("org.springframework.data", "spring-data-releasetrain")));
COMMONS = new Project("DATACMNS", "Commons", Arrays.asList(BUILD));
JPA = new Project("DATAJPA", "JPA", Arrays.asList(COMMONS));
MONGO_DB = new Project("DATAMONGO", "MongoDB", Arrays.asList(COMMONS),
- Arrays.asList("spring-data-mongodb-cross-store", "spring-data-mongodb-log4j"));
+ ArtifactCoordinates.NONE.artifacts("spring-data-mongodb-cross-store", "spring-data-mongodb-log4j"));
NEO4J = new Project("DATAGRAPH", "Neo4j", Arrays.asList(COMMONS));
SOLR = new Project("DATASOLR", "Solr", Arrays.asList(COMMONS));
COUCHBASE = new Project("DATACOUCH", "Couchbase", Arrays.asList(COMMONS));
- CASSANDRA = new Project("DATACASS", "Cassandra", Arrays.asList(COMMONS), Arrays.asList("spring-cql"));
+ CASSANDRA = new Project("DATACASS", "Cassandra", Arrays.asList(COMMONS),
+ ArtifactCoordinates.NONE.artifacts("spring-cql"));
ELASTICSEARCH = new Project("DATAES", "Elasticsearch", Arrays.asList(COMMONS));
REDIS = new Project("DATAREDIS", "Redis", Collections.emptyList());
GEMFIRE = new Project("SGF", "Gemfire", Arrays.asList(COMMONS));
REST = new Project("DATAREST", "REST", Arrays.asList(COMMONS, JPA, MONGO_DB, NEO4J, GEMFIRE, SOLR, CASSANDRA),
- Arrays.asList("spring-data-rest-core", "spring-data-rest-core", "spring-data-rest-hal-browser"));
+ ArtifactCoordinates.NONE.artifacts("spring-data-rest-core", "spring-data-rest-core",
+ "spring-data-rest-hal-browser"));
KEY_VALUE = new Project("DATAKV", "KeyValue", Arrays.asList(COMMONS));
- ENVERS = new Project("DATAENV", "Envers", Arrays.asList(JPA, COMMONS));
+ ENVERS = new Project("DATAENV", "Envers", Tracker.GITHUB, Arrays.asList(JPA, COMMONS), ArtifactCoordinates.NONE);
- PROJECTS = Arrays.asList(BUILD, COMMONS, JPA, MONGO_DB, NEO4J, SOLR, COUCHBASE, CASSANDRA, ELASTICSEARCH, REDIS,
- GEMFIRE, REST, KEY_VALUE, ENVERS);
+ List projects = Arrays.asList(BUILD, COMMONS, JPA, MONGO_DB, NEO4J, SOLR, COUCHBASE, CASSANDRA,
+ ELASTICSEARCH, REDIS, GEMFIRE, REST, KEY_VALUE, ENVERS);
+
+ DefaultDirectedGraph graph = new DefaultDirectedGraph<>(DefaultEdge.class);
+
+ projects.forEach(project -> {
+
+ graph.addVertex(project);
+
+ project.getDependencies().forEach(dependency -> {
+ graph.addEdge(project, dependency);
+ });
+ });
+
+ Iterator iterator = new TopologicalOrderIterator<>(graph);
+ List intermediate = new ArrayList<>(projects.size());
+
+ while (iterator.hasNext()) {
+ intermediate.add(iterator.next());
+ }
+
+ Collections.reverse(intermediate);
+
+ PROJECTS = Collections.unmodifiableList(intermediate);
+ }
+
+ public static Project byName(String name) {
+
+ return PROJECTS.stream().//
+ filter(project -> project.getName().equalsIgnoreCase(name)).//
+ findFirst().orElseThrow(() -> new IllegalArgumentException("No project named %s available!"));
}
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/model/ReleaseTrains.java b/release-tools/src/main/java/org/springframework/data/release/model/ReleaseTrains.java
index 21489f7..3f560a5 100644
--- a/release-tools/src/main/java/org/springframework/data/release/model/ReleaseTrains.java
+++ b/release-tools/src/main/java/org/springframework/data/release/model/ReleaseTrains.java
@@ -36,8 +36,8 @@ public class ReleaseTrains {
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(NEO4J, "4.1"), new Module(COUCHBASE, "2.1"),
- new Module(ENVERS, "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"));
// Trains
diff --git a/release-tools/src/main/java/org/springframework/data/release/model/Train.java b/release-tools/src/main/java/org/springframework/data/release/model/Train.java
index 788a724..1cc23b3 100644
--- a/release-tools/src/main/java/org/springframework/data/release/model/Train.java
+++ b/release-tools/src/main/java/org/springframework/data/release/model/Train.java
@@ -23,13 +23,13 @@ import lombok.Value;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import org.springframework.data.release.Streamable;
import org.springframework.shell.support.util.OsUtils;
import org.springframework.util.Assert;
@@ -37,23 +37,20 @@ import org.springframework.util.Assert;
* @author Oliver Gierke
*/
@Value
-public class Train implements Iterable {
+public class Train implements Streamable {
private final String name;;
- private final Collection modules;
+ private final Modules modules;
private final Iterations iterations;
public Train(String name, Module... modules) {
-
- this.name = name;
- this.modules = Arrays.asList(modules);
- this.iterations = Iterations.DEFAULT;
+ this(name, Arrays.asList(modules));
}
public Train(String name, Collection modules) {
this.name = name;
- this.modules = Collections.unmodifiableCollection(modules);
+ this.modules = new Modules(modules);
this.iterations = Iterations.DEFAULT;
}
@@ -66,6 +63,12 @@ public class Train implements Iterable {
return modules.iterator();
}
+ public boolean contains(Project project) {
+
+ return modules.stream().//
+ anyMatch(module -> module.getProject().equals(project));
+ }
+
public Module getModule(String name) {
return modules.stream().//
@@ -98,7 +101,7 @@ public class Train implements Iterable {
return modules.stream().//
filter(module -> module.hasName(moduleName)).//
findFirst().//
- map(module -> new ModuleIteration(module, iteration, this)).//
+ map(module -> new ModuleIteration(module, new TrainIteration(this, iteration))).//
orElseThrow(
() -> new IllegalArgumentException(String.format("No module found with module name %s!", moduleName)));
}
@@ -113,7 +116,8 @@ public class Train implements Iterable {
return modules.stream().//
filter(module -> !exclusionList.contains(module.getProject())).//
- map(module -> new ModuleIteration(module, iteration, this)).//
+ map(module -> new ModuleIteration(module, new TrainIteration(this, iteration))).//
+ sorted().//
collect(Collectors.toList());
}
@@ -125,7 +129,7 @@ public class Train implements Iterable {
Module module = getModule(project);
- return ArtifactVersion.of(new ModuleIteration(module, iteration, this));
+ return ArtifactVersion.of(new ModuleIteration(module, new TrainIteration(this, iteration)));
}
/*
diff --git a/release-tools/src/main/java/org/springframework/data/release/model/TrainIteration.java b/release-tools/src/main/java/org/springframework/data/release/model/TrainIteration.java
index 7c5ae52..71b5f61 100644
--- a/release-tools/src/main/java/org/springframework/data/release/model/TrainIteration.java
+++ b/release-tools/src/main/java/org/springframework/data/release/model/TrainIteration.java
@@ -18,12 +18,15 @@ package org.springframework.data.release.model;
import lombok.Value;
import java.util.Iterator;
+import java.util.List;
+
+import org.springframework.data.release.Streamable;
/**
* @author Oliver Gierke
*/
@Value
-public class TrainIteration implements Iterable {
+public class TrainIteration implements Streamable {
private final Train train;
private final Iteration iteration;
@@ -49,16 +52,29 @@ public class TrainIteration implements Iterable {
return train.getModuleIteration(iteration, project.getName());
}
- public Iterable getModulesExcept(Project... exclusions) {
+ public List getModulesExcept(Project... exclusions) {
return train.getModuleIterations(iteration, exclusions);
}
+ public boolean contains(Project project) {
+ return train.contains(project);
+ }
+
public ModuleIteration getPreviousIteration(ModuleIteration module) {
Iteration previousIteration = train.getIterations().getPreviousIteration(iteration);
return train.getModuleIteration(previousIteration, module.getProject().getName());
}
+ /**
+ * Returns the version string to be used for the train iteration.
+ *
+ * @return
+ */
+ public String toVersionString() {
+ return toString().replace(' ', '-');
+ }
+
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
@@ -67,4 +83,5 @@ public class TrainIteration implements Iterable {
public String toString() {
return String.format("%s %s", train.getName(), iteration.getName());
}
+
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/model/UpdateInformation.java b/release-tools/src/main/java/org/springframework/data/release/model/UpdateInformation.java
new file mode 100644
index 0000000..0e40d90
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/model/UpdateInformation.java
@@ -0,0 +1,94 @@
+package org.springframework.data.release.model;
+
+import static org.springframework.data.release.model.Projects.*;
+
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+
+import org.springframework.data.release.build.Repository;
+import org.springframework.util.Assert;
+
+/**
+ * Value object to expose update information for a given {@link TrainIteration} and phase.
+ *
+ * @author Oliver Gierke
+ */
+@RequiredArgsConstructor
+public class UpdateInformation {
+
+ private final @NonNull @Getter TrainIteration iteration;
+ private final @NonNull @Getter Phase phase;
+
+ /**
+ * Returns the {@link ArtifactVersion} to be set for the given {@link Project}.
+ *
+ * @param dependency must not be {@literal null}.
+ * @return will never be {@literal null}.
+ */
+ public ArtifactVersion getProjectVersionToSet(Project dependency) {
+
+ Assert.notNull(dependency, "Project must not be null!");
+
+ ArtifactVersion dependencyVersion = iteration.getModuleVersion(dependency);
+
+ switch (phase) {
+ case PREPARE:
+ return dependencyVersion;
+ case CLEANUP:
+ return dependencyVersion.getNextDevelopmentVersion();
+ case MAINTENANCE:
+ return dependencyVersion.getNextBugfixVersion();
+ }
+
+ throw new IllegalStateException("Unexpected phase detected " + phase + " detected!");
+ }
+
+ /**
+ * Returns the {@link ArtifactVersion} to be set for the parent reference.
+ *
+ * @return will never be {@literal null}.
+ */
+ public ArtifactVersion getParentVersionToSet() {
+
+ ArtifactVersion version = iteration.getModuleVersion(BUILD);
+
+ switch (phase) {
+ case PREPARE:
+ return version;
+ case CLEANUP:
+ return version.getNextDevelopmentVersion();
+ case MAINTENANCE:
+ return version.getNextBugfixVersion();
+ }
+
+ throw new IllegalStateException("Unexpected phase detected " + phase + " detected!");
+ }
+
+ /**
+ * Returns the {@link Repository} to use (milestone or release).
+ *
+ * @return will never be {@literal null}.
+ */
+ public Repository getRepository() {
+ return new Repository(iteration.getIteration());
+ }
+
+ /**
+ * Returns the version {@link String} to be used to describe the release train.
+ *
+ * @return will never be {@literal null}.
+ */
+ public String getReleaseTrainVersion() {
+
+ switch (phase) {
+ case PREPARE:
+ return iteration.toVersionString();
+ case CLEANUP:
+ case MAINTENANCE:
+ return iteration.getTrain().getName().concat("-BUILD-SNAPSHOT");
+ }
+
+ throw new IllegalStateException("Unexpected phase detected " + phase + " detected!");
+ }
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/model/VersionAware.java b/release-tools/src/main/java/org/springframework/data/release/model/VersionAware.java
new file mode 100644
index 0000000..17a4c88
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/model/VersionAware.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015 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
+ *
+ * http://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 Gierke
+ */
+public interface VersionAware {
+
+ Version getVersion();
+}
diff --git a/release-tools/src/main/java/org/springframework/data/release/utils/ExecutionUtils.java b/release-tools/src/main/java/org/springframework/data/release/utils/ExecutionUtils.java
index 840e182..cc05c98 100644
--- a/release-tools/src/main/java/org/springframework/data/release/utils/ExecutionUtils.java
+++ b/release-tools/src/main/java/org/springframework/data/release/utils/ExecutionUtils.java
@@ -19,8 +19,8 @@ import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
+import org.springframework.data.release.Streamable;
import org.springframework.util.Assert;
/**
@@ -35,15 +35,15 @@ public class ExecutionUtils {
* all executions to complete before returning. Exceptions being thrown in the {@link ConsumerWithException} will be
* converted into {@link RuntimeException}s.
*
- * @param iterable must not be {@literal null}.
+ * @param streamable must not be {@literal null}.
* @param consumer must not be {@literal null}.
*/
- public static void run(Iterable iterable, ConsumerWithException consumer) {
+ public static void run(Streamable streamable, ConsumerWithException consumer) {
- Assert.notNull(iterable, "Iterable must not be null!");
+ Assert.notNull(streamable, "Streamable must not be null!");
Assert.notNull(consumer, "Consumer must not be null!");
- StreamSupport.stream(iterable.spliterator(), false).//
+ streamable.stream().//
map(it -> CompletableFuture.runAsync(() -> {
try {
consumer.accept(it);
@@ -55,19 +55,19 @@ public class ExecutionUtils {
}
/**
- * Runs the given {@link Function} for each element in the given {@link Iterable} in parallel waiting for all
+ * Runs the given {@link Function} for each element in the given {@link Streamable} in parallel waiting for all
* executions to complete before returning the results.
*
- * @param iterable must not be {@literal null}.
+ * @param streamable must not be {@literal null}.
* @param function must not be {@literal null}.
* @return
*/
- public static Collection runAndReturn(Iterable iterable, Function function) {
+ public static Collection runAndReturn(Streamable streamable, Function function) {
- Assert.notNull(iterable, "Iterable must not be null!");
+ Assert.notNull(streamable, "Iterable must not be null!");
Assert.notNull(function, "Consumer must not be null!");
- return StreamSupport.stream(iterable.spliterator(), false).//
+ return streamable.stream().//
map(it -> CompletableFuture.supplyAsync(() -> function.apply(it))).//
collect(Collectors.toList()).//
stream().//
diff --git a/release-tools/src/main/java/org/springframework/data/release/utils/Logger.java b/release-tools/src/main/java/org/springframework/data/release/utils/Logger.java
index cd357b3..fdbd384 100644
--- a/release-tools/src/main/java/org/springframework/data/release/utils/Logger.java
+++ b/release-tools/src/main/java/org/springframework/data/release/utils/Logger.java
@@ -32,23 +32,23 @@ public class Logger {
private final java.util.logging.Logger LOGGER = HandlerUtils.getLogger(getClass());
- public void log(ModuleIteration module, String template, Object... args) {
+ public void log(ModuleIteration module, Object template, Object... args) {
log(module.getProject(), template, args);
}
- public void log(Project project, String template, Object... args) {
+ public void log(Project project, Object template, Object... args) {
log(project.getName(), template, args);
}
- public void log(TrainIteration iteration, String template, Object... args) {
+ public void log(TrainIteration iteration, Object template, Object... args) {
log(iteration.toString(), template, args);
}
- public void log(Train train, String template, Object... args) {
+ public void log(Train train, Object template, Object... args) {
log(train.getName(), template, args);
}
- private void log(String context, String template, Object... args) {
- LOGGER.info(String.format(PREFIX_TEMPLATE, context, String.format(template, args)));
+ private void log(String context, Object template, Object... args) {
+ LOGGER.info(String.format(PREFIX_TEMPLATE, context, String.format(template.toString(), args)));
}
}
diff --git a/release-tools/src/main/java/org/springframework/data/release/utils/StreamUtils.java b/release-tools/src/main/java/org/springframework/data/release/utils/StreamUtils.java
new file mode 100644
index 0000000..33b3fc6
--- /dev/null
+++ b/release-tools/src/main/java/org/springframework/data/release/utils/StreamUtils.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016 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
+ *
+ * http://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.utils;
+
+import java.util.function.Function;
+
+/**
+ * @author Oliver Gierke
+ */
+public interface StreamUtils {
+
+ public static Function wrap(FunctionWithException function) {
+ return it -> {
+ try {
+ return function.apply(it);
+ } catch (Exception o_O) {
+ throw new RuntimeException(o_O);
+ }
+ };
+ }
+
+ public interface FunctionWithException {
+ S apply(T source) throws Exception;
+ }
+}
diff --git a/release-tools/src/main/resources/application.properties b/release-tools/src/main/resources/application.properties
index f759759..40e639e 100644
--- a/release-tools/src/main/resources/application.properties
+++ b/release-tools/src/main/resources/application.properties
@@ -1 +1,12 @@
io.work-dir=~/temp/spring-data-shell
+
+maven.release-command=install -DskipTests
+
+#maven.plugins.deploy=org.apache.maven.plugins:maven-deploy-plugin:2.8.2:deploy
+maven.plugins.versions-set=org.codehaus.mojo:versions-maven-plugin:2.2:set
+maven.plugins.artifactory-deploy=org.jfrog.buildinfo:artifactory-maven-plugin:2.4.0:publish
+
+deployment.server.uri=https://repo.spring.io
+deployment.staging-repository=libs-staging-local
+deployment.username=buildmaster
+#deployment.password <- local
\ No newline at end of file
diff --git a/release-tools/src/test/java/org/springframework/data/release/AbstractIntegrationTests.java b/release-tools/src/test/java/org/springframework/data/release/AbstractIntegrationTests.java
index 9faa6c4..ccb79c1 100644
--- a/release-tools/src/test/java/org/springframework/data/release/AbstractIntegrationTests.java
+++ b/release-tools/src/test/java/org/springframework/data/release/AbstractIntegrationTests.java
@@ -23,7 +23,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Oliver Gierke
*/
-@ActiveProfiles({ "test", "local" })
+@ActiveProfiles({ "local", "test" })
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public abstract class AbstractIntegrationTests {}
diff --git a/release-tools/src/test/java/org/springframework/data/release/ApplicationTests.java b/release-tools/src/test/java/org/springframework/data/release/ApplicationTests.java
new file mode 100644
index 0000000..a269533
--- /dev/null
+++ b/release-tools/src/test/java/org/springframework/data/release/ApplicationTests.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2016 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
+ *
+ * http://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;
+
+import org.junit.Test;
+
+/**
+ * @author Oliver Gierke
+ */
+public class ApplicationTests extends AbstractIntegrationTests {
+
+ @Test
+ public void bootstrapsApplication() {}
+}
diff --git a/release-tools/src/test/java/org/springframework/data/release/ArtifactUnitTests.java b/release-tools/src/test/java/org/springframework/data/release/ArtifactUnitTests.java
index 13dda41..260dcb5 100644
--- a/release-tools/src/test/java/org/springframework/data/release/ArtifactUnitTests.java
+++ b/release-tools/src/test/java/org/springframework/data/release/ArtifactUnitTests.java
@@ -19,7 +19,7 @@ import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Test;
-import org.springframework.data.release.maven.Artifact;
+import org.springframework.data.release.build.MavenArtifact;
import org.springframework.data.release.model.ArtifactVersion;
import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.ReleaseTrains;
@@ -32,7 +32,7 @@ public class ArtifactUnitTests {
@Test
public void testname() {
- Artifact artifact = new Artifact(ReleaseTrains.DIJKSTRA.getModuleIteration(Iteration.M1, "JPA"));
+ MavenArtifact artifact = new MavenArtifact(ReleaseTrains.DIJKSTRA.getModuleIteration(Iteration.M1, "JPA"));
assertThat(artifact.getArtifactId(), is("spring-data-jpa"));
assertThat(artifact.getVersion(), is(ArtifactVersion.of("1.6.0.M1")));
diff --git a/release-tools/src/test/java/org/springframework/data/release/maven/MavenIntegrationTests.java b/release-tools/src/test/java/org/springframework/data/release/build/MavenIntegrationTests.java
similarity index 64%
rename from release-tools/src/test/java/org/springframework/data/release/maven/MavenIntegrationTests.java
rename to release-tools/src/test/java/org/springframework/data/release/build/MavenIntegrationTests.java
index d85930d..aaa8d8e 100644
--- a/release-tools/src/test/java/org/springframework/data/release/maven/MavenIntegrationTests.java
+++ b/release-tools/src/test/java/org/springframework/data/release/build/MavenIntegrationTests.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.data.release.maven;
+package org.springframework.data.release.build;
import java.io.IOException;
@@ -21,8 +21,16 @@ import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.release.AbstractIntegrationTests;
+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.Iteration;
+import org.springframework.data.release.model.ModuleIteration;
+import org.springframework.data.release.model.Phase;
+import org.springframework.data.release.model.Projects;
+import org.springframework.data.release.model.ReleaseTrains;
+import org.springframework.data.release.model.TrainIteration;
+import org.springframework.data.release.model.UpdateInformation;
import org.xmlbeam.ProjectionFactory;
import org.xmlbeam.io.XBFileIO;
@@ -33,6 +41,8 @@ public class MavenIntegrationTests extends AbstractIntegrationTests {
@Autowired Workspace workspace;
@Autowired ProjectionFactory projection;
+ @Autowired MavenBuildSystem maven;
+ @Autowired GitOperations git;
@Test
public void modifiesParentPomCorrectly() throws IOException {
@@ -42,7 +52,7 @@ public class MavenIntegrationTests extends AbstractIntegrationTests {
ParentPom pom = io.read(ParentPom.class);
pom.setSharedResourcesVersion(ArtifactVersion.of("1.2.0.RELEASE"));
- // System.out.println(projection.asString(pom));
+ System.out.println(projection.asString(pom));
}
@Test
@@ -57,4 +67,17 @@ public class MavenIntegrationTests extends AbstractIntegrationTests {
// System.out.println(projection.asString(pom));
}
+
+ @Test
+ public void testname() throws Exception {
+
+ git.update(ReleaseTrains.HOPPER);
+
+ TrainIteration iteration = new TrainIteration(ReleaseTrains.HOPPER, Iteration.M1);
+ ModuleIteration build = iteration.getModule(Projects.BUILD);
+ UpdateInformation information = new UpdateInformation(iteration, Phase.PREPARE);
+
+ maven.updateProjectDescriptors(build, information);
+ maven.prepareVersion(build, Phase.PREPARE);
+ }
}
diff --git a/release-tools/src/test/java/org/springframework/data/release/deployment/DeploymentInformationIntegrationTests.java b/release-tools/src/test/java/org/springframework/data/release/deployment/DeploymentInformationIntegrationTests.java
new file mode 100644
index 0000000..18e3d3a
--- /dev/null
+++ b/release-tools/src/test/java/org/springframework/data/release/deployment/DeploymentInformationIntegrationTests.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2015-2016 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
+ *
+ * http://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.deployment;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+import org.junit.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.ModuleIteration;
+import org.springframework.data.release.model.Projects;
+import org.springframework.data.release.model.ReleaseTrains;
+import org.springframework.data.release.model.TrainIteration;
+
+/**
+ * Integration test for {@link DeploymentInformation}.
+ *
+ * @author Oliver Gierke
+ */
+public class DeploymentInformationIntegrationTests extends AbstractIntegrationTests {
+
+ @Autowired DeploymentProperties properties;
+
+ @Test
+ public void createsDeploymentInformation() {
+
+ TrainIteration iteration = new TrainIteration(ReleaseTrains.HOPPER, Iteration.M1);
+ ModuleIteration buildModule = iteration.getModule(Projects.BUILD);
+
+ DeploymentInformation information = new DeploymentInformation(buildModule, properties);
+
+ assertThat(information.getDeploymentTargetUrl(), containsString(properties.getServer().getUri().toString()));
+ assertThat(information.getBuildName(), is("Spring Data Build - Release"));
+ assertThat(information.getTargetRepository(), is("test-libs-milestone-local"));
+ }
+}
diff --git a/release-tools/src/test/java/org/springframework/data/release/deployment/DeploymentOperationsIntegrationTests.java b/release-tools/src/test/java/org/springframework/data/release/deployment/DeploymentOperationsIntegrationTests.java
new file mode 100644
index 0000000..4f747a9
--- /dev/null
+++ b/release-tools/src/test/java/org/springframework/data/release/deployment/DeploymentOperationsIntegrationTests.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015 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
+ *
+ * http://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.deployment;
+
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.release.AbstractIntegrationTests;
+import org.springframework.data.release.build.BuildOperations;
+import org.springframework.data.release.git.GitOperations;
+import org.springframework.data.release.model.Iteration;
+import org.springframework.data.release.model.ModuleIteration;
+import org.springframework.data.release.model.Phase;
+import org.springframework.data.release.model.ReleaseTrains;
+import org.springframework.data.release.model.Train;
+
+/**
+ * @author Oliver Gierke
+ */
+public class DeploymentOperationsIntegrationTests extends AbstractIntegrationTests {
+
+ @Autowired GitOperations git;
+ @Autowired BuildOperations build;
+ @Autowired DeploymentOperations deployment;
+ @Autowired ArtifactoryClient client;
+
+ @Test
+ public void testname() {
+
+ Train train = ReleaseTrains.HOPPER;
+ ModuleIteration buildModule = train.getModuleIteration(Iteration.M1, "build");
+
+ git.update(train);
+ build.prepareVersion(buildModule, Phase.PREPARE);
+
+ DeploymentInformation information = build.buildAndDeployRelease(buildModule);
+
+ try {
+ deployment.promote(information);
+ } finally {
+ client.deleteArtifacts(information);
+ }
+ }
+}
diff --git a/release-tools/src/test/java/org/springframework/data/release/model/ModuleIterationUnitTests.java b/release-tools/src/test/java/org/springframework/data/release/model/ModuleIterationUnitTests.java
index a6f1b7b..986f2a7 100644
--- a/release-tools/src/test/java/org/springframework/data/release/model/ModuleIterationUnitTests.java
+++ b/release-tools/src/test/java/org/springframework/data/release/model/ModuleIterationUnitTests.java
@@ -31,7 +31,9 @@ public class ModuleIterationUnitTests {
TrainIteration iteration = new TrainIteration(ReleaseTrains.DIJKSTRA, Iteration.M1);
ModuleIteration module = iteration.getModule(Projects.JPA);
- assertThat(module.getVersionString(), is("1.6 M1"));
+ assertThat(module.getShortVersionString(), is("1.6 M1"));
+ assertThat(module.getMediumVersionString(), is("1.6 M1 (Dijkstra)"));
+ assertThat(module.getFullVersionString(), is("1.6.0.M1 (Dijkstra M1)"));
}
@Test
@@ -40,6 +42,8 @@ public class ModuleIterationUnitTests {
TrainIteration iteration = new TrainIteration(ReleaseTrains.DIJKSTRA, Iteration.SR1);
ModuleIteration module = iteration.getModule(Projects.JPA);
- assertThat(module.getVersionString(), is("1.6.1"));
+ assertThat(module.getShortVersionString(), is("1.6.1"));
+ assertThat(module.getMediumVersionString(), is("1.6.1 (Dijkstra SR1)"));
+ assertThat(module.getFullVersionString(), is("1.6.1.RELEASE (Dijkstra SR1)"));
}
}
diff --git a/release-tools/src/test/java/org/springframework/data/release/model/ProjectUnitTests.java b/release-tools/src/test/java/org/springframework/data/release/model/ProjectUnitTests.java
new file mode 100644
index 0000000..2e53c91
--- /dev/null
+++ b/release-tools/src/test/java/org/springframework/data/release/model/ProjectUnitTests.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2015 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
+ *
+ * http://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 static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+/**
+ * @author Oliver Gierke
+ */
+public class ProjectUnitTests {
+
+ @Test
+ public void testname() {
+
+ List projects = new ArrayList<>(Projects.PROJECTS);
+ // Collections.reverse(projects);
+ // Collections.sort(projects);
+
+ projects.stream().map(Project::getName).forEach(System.out::println);
+
+ System.out.println();
+
+ assertThat(projects.get(0), is(Projects.BUILD));
+ assertThat(projects.get(1), is(Projects.COMMONS));
+ }
+}
diff --git a/release-tools/src/test/java/org/springframework/data/release/model/SimpleIterationVersion.java b/release-tools/src/test/java/org/springframework/data/release/model/SimpleIterationVersion.java
index 203c090..ad6292b 100644
--- a/release-tools/src/test/java/org/springframework/data/release/model/SimpleIterationVersion.java
+++ b/release-tools/src/test/java/org/springframework/data/release/model/SimpleIterationVersion.java
@@ -22,4 +22,13 @@ public class SimpleIterationVersion implements IterationVersion {
private final Version version;
private final Iteration iteration;
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.release.model.IterationVersion#isServiceIteration()
+ */
+ @Override
+ public boolean isServiceIteration() {
+ return iteration.isServiceIteration();
+ }
}
diff --git a/release-tools/src/test/java/org/springframework/data/release/model/TrainsUnitTest.java b/release-tools/src/test/java/org/springframework/data/release/model/TrainsUnitTest.java
index f52650e..6ae3e7a 100644
--- a/release-tools/src/test/java/org/springframework/data/release/model/TrainsUnitTest.java
+++ b/release-tools/src/test/java/org/springframework/data/release/model/TrainsUnitTest.java
@@ -39,4 +39,18 @@ public class TrainsUnitTest {
public void addsNewlyAddedModule() {
assertThat(ReleaseTrains.HOPPER.getModule(Projects.ENVERS), is(notNullValue()));
}
+
+ @Test
+ public void testname() {
+
+ Iterable iterations = ReleaseTrains.HOPPER.getModuleIterations(Iteration.M1);
+
+ for (ModuleIteration iteration : iterations) {
+ System.out.println(iteration);
+ }
+
+ System.out.println();
+
+ iterations.forEach(System.out::println);
+ }
}
diff --git a/release-tools/src/test/java/org/springframework/data/release/model/UpdateInformationUnitTests.java b/release-tools/src/test/java/org/springframework/data/release/model/UpdateInformationUnitTests.java
new file mode 100644
index 0000000..5284f7d
--- /dev/null
+++ b/release-tools/src/test/java/org/springframework/data/release/model/UpdateInformationUnitTests.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 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
+ *
+ * http://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 static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link UpdateInformation}.
+ *
+ * @author Oliver Gierke
+ */
+public class UpdateInformationUnitTests {
+
+ TrainIteration hopperM1 = new TrainIteration(ReleaseTrains.HOPPER, Iteration.M1);
+
+ @Test(expected = IllegalArgumentException.class)
+ public void rejectsNullTrainIteration() {
+ new UpdateInformation(null, Phase.CLEANUP);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void rejectsNullPhase() {
+ new UpdateInformation(hopperM1, null);
+ }
+
+ @Test
+ public void exposesMilestoneRepositoryForMilestone() {
+ assertThat(new UpdateInformation(hopperM1, Phase.PREPARE).getRepository().getId(), is("spring-libs-milestone"));
+ }
+
+ @Test
+ public void exposesReleaseRepositoryForGA() {
+
+ Arrays.asList(Iteration.GA, Iteration.SR1).forEach(iteration -> {
+ TrainIteration trainIteration = new TrainIteration(ReleaseTrains.HOPPER, iteration);
+ assertThat(new UpdateInformation(trainIteration, Phase.PREPARE).getRepository().getId(),
+ is("spring-libs-release"));
+ });
+ }
+
+ @Test
+ public void calculatesProjectVersionToSetCorrectly() {
+
+ UpdateInformation updateInformation = new UpdateInformation(hopperM1, Phase.PREPARE);
+ assertThat(updateInformation.getProjectVersionToSet(Projects.JPA).toString(), is("1.10.0.M1"));
+
+ updateInformation = new UpdateInformation(hopperM1, Phase.CLEANUP);
+ assertThat(updateInformation.getProjectVersionToSet(Projects.JPA).toString(), is("1.10.0.BUILD-SNAPSHOT"));
+ }
+}
diff --git a/release-tools/src/test/resources/application-test.properties b/release-tools/src/test/resources/application-test.properties
index 4982dd4..6dd9cd1 100644
--- a/release-tools/src/test/resources/application-test.properties
+++ b/release-tools/src/test/resources/application-test.properties
@@ -1,3 +1,14 @@
-io.work-dir=~/temp/shell-test
+# Logging
logging.level.org.springframework=WARN
logging.level.org.springframework.data.release=INFO
+logging.level.org.springframework.web.client=TRACE
+
+# Workspace
+io.work-dir=~/temp/shell-test
+
+# Maven
+maven.localRepository=~/temp/.m2/repository
+
+# Deployment
+deployment.server.uri=https://repo.spring.io
+deployment.repository-prefix=test-