diff --git a/projects/reactor/pom.xml b/projects/reactor/pom.xml
index f181053f..7b827a0c 100644
--- a/projects/reactor/pom.xml
+++ b/projects/reactor/pom.xml
@@ -17,6 +17,7 @@
UTF-8
1.8
+ 4.3.0.RELEASE
@@ -25,6 +26,16 @@
releaser-spring
${project.version}
+
+ org.cloudfoundry
+ cloudfoundry-client-reactor
+ ${cloudfoundry-client.version}
+
+
+ org.cloudfoundry
+ cloudfoundry-operations
+ ${cloudfoundry-client.version}
+
org.springframework.boot
diff --git a/projects/reactor/src/main/java/releaser/reactor/ReactorConfiguration.java b/projects/reactor/src/main/java/releaser/reactor/ReactorConfiguration.java
new file mode 100644
index 00000000..434360a1
--- /dev/null
+++ b/projects/reactor/src/main/java/releaser/reactor/ReactorConfiguration.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2013-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package releaser.reactor;
+
+import org.cloudfoundry.client.CloudFoundryClient;
+import org.cloudfoundry.doppler.DopplerClient;
+import org.cloudfoundry.operations.CloudFoundryOperations;
+import org.cloudfoundry.operations.DefaultCloudFoundryOperations;
+import org.cloudfoundry.reactor.ConnectionContext;
+import org.cloudfoundry.reactor.DefaultConnectionContext;
+import org.cloudfoundry.reactor.TokenProvider;
+import org.cloudfoundry.reactor.client.ReactorCloudFoundryClient;
+import org.cloudfoundry.reactor.doppler.ReactorDopplerClient;
+import org.cloudfoundry.reactor.tokenprovider.PasswordGrantTokenProvider;
+import org.cloudfoundry.reactor.uaa.ReactorUaaClient;
+import org.cloudfoundry.uaa.UaaClient;
+import releaser.internal.Releaser;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+class ReactorConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ CfClient cfClient(CloudFoundryOperations cloudFoundryOperations) {
+ return new CfClient(cloudFoundryOperations);
+ }
+
+ @Bean
+ RestartSiteProjectPostReleaseTask restartSiteProjectPostReleaseTask(Releaser releaser,
+ CfClient cfClient, @Value("${cf.reactorAppName}") String reactorAppName) {
+ return new RestartSiteProjectPostReleaseTask(releaser, cfClient, reactorAppName);
+ }
+
+}
+
+@Configuration
+class CfConfiguration {
+
+ @Bean
+ DefaultConnectionContext connectionContext(@Value("${cf.apiHost}") String apiHost) {
+ return DefaultConnectionContext.builder().apiHost(apiHost).build();
+ }
+
+ @Bean
+ PasswordGrantTokenProvider tokenProvider(@Value("${cf.username}") String username,
+ @Value("${cf.password}") String password) {
+ return PasswordGrantTokenProvider.builder().password(password).username(username)
+ .build();
+ }
+
+ @Bean
+ ReactorCloudFoundryClient cloudFoundryClient(ConnectionContext connectionContext,
+ TokenProvider tokenProvider) {
+ return ReactorCloudFoundryClient.builder().connectionContext(connectionContext)
+ .tokenProvider(tokenProvider).build();
+ }
+
+ @Bean
+ ReactorDopplerClient dopplerClient(ConnectionContext connectionContext,
+ TokenProvider tokenProvider) {
+ return ReactorDopplerClient.builder().connectionContext(connectionContext)
+ .tokenProvider(tokenProvider).build();
+ }
+
+ @Bean
+ ReactorUaaClient uaaClient(ConnectionContext connectionContext,
+ TokenProvider tokenProvider) {
+ return ReactorUaaClient.builder().connectionContext(connectionContext)
+ .tokenProvider(tokenProvider).build();
+ }
+
+ @Bean
+ DefaultCloudFoundryOperations defaultCloudFoundryOperations(
+ CloudFoundryClient cloudFoundryClient, DopplerClient dopplerClient,
+ UaaClient uaaClient, @Value("${cf.organization}") String organizationId,
+ @Value("${cf.space}") String spaceId) {
+ return DefaultCloudFoundryOperations.builder()
+ .cloudFoundryClient(cloudFoundryClient).dopplerClient(dopplerClient)
+ .uaaClient(uaaClient).organization(organizationId).space(spaceId).build();
+ }
+
+}
diff --git a/projects/reactor/src/main/java/releaser/reactor/RestartSiteProjectPostReleaseTask.java b/projects/reactor/src/main/java/releaser/reactor/RestartSiteProjectPostReleaseTask.java
new file mode 100644
index 00000000..cc75607c
--- /dev/null
+++ b/projects/reactor/src/main/java/releaser/reactor/RestartSiteProjectPostReleaseTask.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2013-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package releaser.reactor;
+
+import org.cloudfoundry.operations.CloudFoundryOperations;
+import org.cloudfoundry.operations.applications.RestartApplicationRequest;
+import releaser.internal.Releaser;
+import releaser.internal.spring.Arguments;
+import releaser.internal.spring.ExecutionResult;
+import releaser.internal.tasks.DryRunReleaseReleaserTask;
+import releaser.internal.tasks.release.PublishDocsReleaseTask;
+
+public class RestartSiteProjectPostReleaseTask extends PublishDocsReleaseTask
+ implements DryRunReleaseReleaserTask {
+
+ private static final String REACTOR_CORE_PROJECT_NAME = "reactor-core";
+
+ private final CfClient cfClient;
+
+ private final String reactorAppName;
+
+ public RestartSiteProjectPostReleaseTask(Releaser releaser, CfClient cfClient,
+ String reactorAppName) {
+ super(releaser);
+ this.cfClient = cfClient;
+ this.reactorAppName = reactorAppName;
+ }
+
+ @Override
+ public ExecutionResult runTask(Arguments args) {
+ if (!REACTOR_CORE_PROJECT_NAME.equals(args.projectToRun.name())) {
+ return ExecutionResult.success();
+ }
+ this.cfClient.restartApp(this.reactorAppName);
+ return ExecutionResult.success();
+ }
+
+}
+
+class CfClient {
+
+ private final CloudFoundryOperations cloudFoundryOperations;
+
+ CfClient(CloudFoundryOperations cloudFoundryOperations) {
+ this.cloudFoundryOperations = cloudFoundryOperations;
+ }
+
+ void restartApp(String name) {
+ this.cloudFoundryOperations.applications()
+ .restart(RestartApplicationRequest.builder().name(name).build());
+ }
+
+}
diff --git a/projects/reactor/src/main/resources/application.yml b/projects/reactor/src/main/resources/application.yml
index 2eea9d59..56cb4819 100644
--- a/projects/reactor/src/main/resources/application.yml
+++ b/projects/reactor/src/main/resources/application.yml
@@ -14,4 +14,9 @@ releaser:
release-train-project-name: reactor
release-train-dependency-names:
- reactor
- git-org-url: https://github.com/reactor
\ No newline at end of file
+ git-org-url: https://github.com/reactor
+cf:
+ organization: FrameworksAndRuntimes
+ space: Reactor
+ reactorAppName: projectreactor
+ apiHost: api.run.pivotal.io
\ No newline at end of file
diff --git a/projects/reactor/src/test/java/releaser/ReleaserApplicationTests.java b/projects/reactor/src/test/java/releaser/ReleaserApplicationTests.java
index 6d0c2bf8..df77e517 100644
--- a/projects/reactor/src/test/java/releaser/ReleaserApplicationTests.java
+++ b/projects/reactor/src/test/java/releaser/ReleaserApplicationTests.java
@@ -16,26 +16,49 @@
package releaser;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import releaser.internal.options.Parser;
import releaser.internal.spring.ExecutionResultHandler;
import releaser.internal.spring.SpringReleaser;
+import releaser.internal.tasks.DryRunReleaseReleaserTask;
+import releaser.internal.tasks.ReleaserTask;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.AnnotationAwareOrderComparator;
+import org.springframework.test.context.ActiveProfiles;
@SpringBootTest(
classes = { ReleaserApplicationTests.Config.class, ReleaserApplication.class },
properties = { "releaser.sagan.update-sagan=false" })
+@ActiveProfiles("test")
class ReleaserApplicationTests {
+ @Autowired
+ ApplicationContext context;
+
@Test
void contextLoads() {
}
+ @Test
+ void should_load_reactor_version_of_publish_docs() {
+ Map beans = context
+ .getBeansOfType(DryRunReleaseReleaserTask.class);
+ List inOrder = new LinkedList<>(beans.values());
+ inOrder.sort(AnnotationAwareOrderComparator.INSTANCE);
+ System.out.println(inOrder);
+ }
+
@Configuration
static class Config {
diff --git a/projects/reactor/src/test/java/releaser/reactor/RestartSiteProjectPostReleaseTaskTests.java b/projects/reactor/src/test/java/releaser/reactor/RestartSiteProjectPostReleaseTaskTests.java
new file mode 100644
index 00000000..0b17573f
--- /dev/null
+++ b/projects/reactor/src/test/java/releaser/reactor/RestartSiteProjectPostReleaseTaskTests.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2013-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package releaser.reactor;
+
+import org.assertj.core.api.BDDAssertions;
+import org.cloudfoundry.operations.CloudFoundryOperations;
+import org.junit.jupiter.api.Test;
+import org.mockito.BDDMockito;
+import releaser.internal.Releaser;
+import releaser.internal.ReleaserProperties;
+import releaser.internal.options.Options;
+import releaser.internal.project.ProjectVersion;
+import releaser.internal.project.Projects;
+import releaser.internal.spring.Arguments;
+import releaser.internal.spring.ExecutionResult;
+import releaser.internal.spring.ProjectToRun;
+import releaser.internal.spring.ProjectsFromBom;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.ActiveProfiles;
+
+@SpringBootTest(classes = RestartSiteProjectPostReleaseTaskTests.Config.class)
+@ActiveProfiles("test")
+class RestartSiteProjectPostReleaseTaskTests {
+
+ @Autowired
+ RestartSiteProjectPostReleaseTask task;
+
+ @Autowired
+ CfClient cfClient;
+
+ @Test
+ void should_update_the_website() {
+ Arguments arguments = Arguments.forProject(reactorCoreProject());
+
+ ExecutionResult result = task.runTask(arguments);
+
+ BDDAssertions.then(result.isSuccess()).isTrue();
+ BDDMockito.then(this.cfClient).should()
+ .restartApp(BDDMockito.eq("projectreactor"));
+ }
+
+ @Test
+ void should_not_update_the_website_if_project_not_reactor_core() {
+ Arguments arguments = Arguments.forProject(nonReactorCoreProject());
+
+ ExecutionResult result = task.runTask(arguments);
+
+ BDDAssertions.then(result.isSuccess()).isTrue();
+ BDDMockito.then(this.cfClient).shouldHaveNoInteractions();
+ }
+
+ private ProjectToRun reactorCoreProject() {
+ return new ProjectToRun(null,
+ new ProjectsFromBom(new Projects(), new ProjectVersion("foo", "1.0.0")),
+ new ProjectVersion("foo", "1.0.0"), new ReleaserProperties(),
+ BDDMockito.mock(Options.class)) {
+ @Override
+ public String name() {
+ return "reactor-core";
+ }
+ };
+ }
+
+ private ProjectToRun nonReactorCoreProject() {
+ return new ProjectToRun(null,
+ new ProjectsFromBom(new Projects(), new ProjectVersion("foo", "1.0.0")),
+ new ProjectVersion("foo", "1.0.0"), new ReleaserProperties(),
+ BDDMockito.mock(Options.class)) {
+ @Override
+ public String name() {
+ return "whatever";
+ }
+ };
+ }
+
+ @Configuration
+ @EnableAutoConfiguration
+ static class Config extends ReactorConfiguration {
+
+ @Bean
+ Releaser mockReleaser() {
+ return BDDMockito.mock(Releaser.class);
+ }
+
+ @Bean
+ CloudFoundryOperations mockCloudFoundryOperations() {
+ return BDDMockito.mock(CloudFoundryOperations.class);
+ }
+
+ @Override
+ CfClient cfClient(CloudFoundryOperations cloudFoundryOperations) {
+ return BDDMockito.mock(CfClient.class);
+ }
+
+ }
+
+}
diff --git a/projects/reactor/src/test/resources/application-test.yml b/projects/reactor/src/test/resources/application-test.yml
new file mode 100644
index 00000000..79678c85
--- /dev/null
+++ b/projects/reactor/src/test/resources/application-test.yml
@@ -0,0 +1,3 @@
+cf:
+ username: foo
+ password: bar
\ No newline at end of file