Skip to content

Commit

Permalink
Merge branch '2.3.x'
Browse files Browse the repository at this point in the history
Closes gh-24316
  • Loading branch information
mbhave committed Dec 2, 2020
2 parents 3dc03ac + f569d76 commit 6c6e339
Show file tree
Hide file tree
Showing 9 changed files with 463 additions and 0 deletions.
@@ -0,0 +1,66 @@
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.spring.concourse.releasescripts.command;

import java.util.List;

import io.spring.concourse.releasescripts.ReleaseType;
import io.spring.concourse.releasescripts.sdkman.SdkmanService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.boot.ApplicationArguments;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

/**
* Command used to publish to SDKMAN.
*
* @author Madhura Bhave
*/
@Component
public class PublishToSdkmanCommand implements Command {

private static final Logger logger = LoggerFactory.getLogger(PublishToSdkmanCommand.class);

private final SdkmanService service;

public PublishToSdkmanCommand(SdkmanService service) {
this.service = service;
}

@Override
public void run(ApplicationArguments args) throws Exception {
logger.debug("Running 'push to SDKMAN' command");
List<String> nonOptionArgs = args.getNonOptionArgs();
Assert.state(!nonOptionArgs.isEmpty(), "No command argument specified");
Assert.state(nonOptionArgs.size() >= 3, "Release type or version not specified");
String releaseType = nonOptionArgs.get(1);
ReleaseType type = ReleaseType.from(releaseType);
if (!ReleaseType.RELEASE.equals(type)) {
return;
}
String version = nonOptionArgs.get(2);
boolean makeDefault = false;
if (nonOptionArgs.size() == 4) {
String releaseBranch = nonOptionArgs.get(3);
makeDefault = ("master".equals(releaseBranch));
}
this.service.publish(version, makeDefault);
}

}
@@ -0,0 +1,49 @@
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.spring.concourse.releasescripts.sdkman;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
* {@link ConfigurationProperties @ConfigurationProperties} for SDKMAN.
*
* @author Madhura Bhave
*/
@ConfigurationProperties(prefix = "sdkman")
public class SdkmanProperties {

private String consumerKey;

private String consumerToken;

public String getConsumerKey() {
return this.consumerKey;
}

public void setConsumerKey(String consumerKey) {
this.consumerKey = consumerKey;
}

public String getConsumerToken() {
return this.consumerToken;
}

public void setConsumerToken(String consumerToken) {
this.consumerToken = consumerToken;
}

}
@@ -0,0 +1,141 @@
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.spring.concourse.releasescripts.sdkman;

import java.net.URI;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

/**
* Central class for interacting with SDKMAN's API.
*
* @author Madhura Bhave
*/
@Component
public class SdkmanService {

private static final Logger logger = LoggerFactory.getLogger(SdkmanService.class);

private static final String SDKMAN_URL = "https://vendors.sdkman.io/";

private static final String DOWNLOAD_URL = "https://repo.spring.io/simple/libs-release-local/org/springframework/boot/spring-boot-cli/"
+ "%s/spring-boot-cli-%s-bin.zip";

private static final String SPRING_BOOT = "springboot";

private final RestTemplate restTemplate;

public SdkmanService(RestTemplateBuilder builder, SdkmanProperties properties) {
String consumerKey = properties.getConsumerKey();
String consumerToken = properties.getConsumerToken();
if (StringUtils.hasLength(consumerKey)) {
builder = builder.basicAuthentication(consumerKey, consumerToken);
}
this.restTemplate = builder.build();
}

public void publish(String version, boolean makeDefault) {
release(version);
if (makeDefault) {
makeDefault(version);
}
broadcast(version);
}

private void broadcast(String version) {
BroadcastRequest broadcastRequest = new BroadcastRequest(version);
RequestEntity<BroadcastRequest> broadcastEntity = RequestEntity.post(URI.create(SDKMAN_URL + "announce/struct"))
.contentType(MediaType.APPLICATION_JSON).body(broadcastRequest);
this.restTemplate.exchange(broadcastEntity, String.class);
logger.debug("Broadcast complete");
}

private void makeDefault(String version) {
logger.debug("Making this version the default");
Request request = new Request(version);
RequestEntity<Request> requestEntity = RequestEntity.post(URI.create(SDKMAN_URL + "default"))
.contentType(MediaType.APPLICATION_JSON).body(request);
this.restTemplate.exchange(requestEntity, String.class);
logger.debug("Make default complete");
}

private void release(String version) {
ReleaseRequest releaseRequest = new ReleaseRequest(version, String.format(DOWNLOAD_URL, version, version));
RequestEntity<ReleaseRequest> releaseEntity = RequestEntity.post(URI.create(SDKMAN_URL + "release"))
.contentType(MediaType.APPLICATION_JSON).body(releaseRequest);
this.restTemplate.exchange(releaseEntity, String.class);
logger.debug("Release complete");
}

static class Request {

private final String candidate = SPRING_BOOT;

private final String version;

Request(String version) {
this.version = version;
}

public String getCandidate() {
return this.candidate;
}

public String getVersion() {
return this.version;
}

}

static class ReleaseRequest extends Request {

private final String url;

ReleaseRequest(String version, String url) {
super(version);
this.url = url;
}

public String getUrl() {
return this.url;
}

}

static class BroadcastRequest extends Request {

private final String hashtag = SPRING_BOOT;

BroadcastRequest(String version) {
super(version);
}

public String getHashtag() {
return this.hashtag;
}

}

}
@@ -0,0 +1,104 @@
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.spring.concourse.releasescripts.command;

import io.spring.concourse.releasescripts.sdkman.SdkmanService;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import org.springframework.boot.DefaultApplicationArguments;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;

/**
* Tests for {@link PublishToSdkmanCommand}.
*
* @author Madhura Bhave
*/
class PublishToSdkmanCommandTests {

@Mock
private SdkmanService service;

private PublishToSdkmanCommand command;

@BeforeEach
void setup() {
MockitoAnnotations.initMocks(this);
this.command = new PublishToSdkmanCommand(this.service);
}

@Test
void runWhenReleaseTypeNotSpecifiedShouldThrowException() throws Exception {
Assertions.assertThatIllegalStateException()
.isThrownBy(() -> this.command.run(new DefaultApplicationArguments("publishGradlePlugin")));
}

@Test
void runWhenVersionNotSpecifiedShouldThrowException() throws Exception {
Assertions.assertThatIllegalStateException()
.isThrownBy(() -> this.command.run(new DefaultApplicationArguments("publishGradlePlugin", "RELEASE")));
}

@Test
void runWhenReleaseTypeMilestoneShouldDoNothing() throws Exception {
this.command.run(new DefaultApplicationArguments("publishGradlePlugin", "M", "1.2.3"));
verifyNoInteractions(this.service);
}

@Test
void runWhenReleaseTypeRCShouldDoNothing() throws Exception {
this.command.run(new DefaultApplicationArguments("publishGradlePlugin", "RC", "1.2.3"));
verifyNoInteractions(this.service);
}

@Test
void runWhenBranchNotSpecifiedShouldCallServiceWithMakeDefaultFalse() throws Exception {
DefaultApplicationArguments args = new DefaultApplicationArguments("promote", "RELEASE", "1.2.3");
testRun(args, false);
}

@Test
void runWhenBranchNotMasterShouldCallServiceWithMakeDefaultFalse() throws Exception {
DefaultApplicationArguments args = new DefaultApplicationArguments("promote", "RELEASE", "1.2.3", "other");
testRun(args, false);
}

@Test
void runWhenReleaseTypeReleaseShouldCallService() throws Exception {
DefaultApplicationArguments args = new DefaultApplicationArguments("promote", "RELEASE", "1.2.3", "master");
testRun(args, true);
}

private void testRun(DefaultApplicationArguments args, boolean makeDefault) throws Exception {
ArgumentCaptor<String> versionCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<Boolean> makeDefaultCaptor = ArgumentCaptor.forClass(Boolean.class);
this.command.run(args);
verify(this.service).publish(versionCaptor.capture(), makeDefaultCaptor.capture());
String version = versionCaptor.getValue();
Boolean makeDefaultValue = makeDefaultCaptor.getValue();
assertThat(version).isEqualTo("1.2.3");
assertThat(makeDefaultValue).isEqualTo(makeDefault);
}

}

0 comments on commit 6c6e339

Please sign in to comment.