Commit 891c7120 authored by Andy Wilkinson's avatar Andy Wilkinson

Wait for distribution to reach Bintray before checking its completeness

Previously, as soon as the distribution of a release from Artifactory
to Bintray had been initiated we would start checking if it was
complete. This created a race condition between the distribution being
created and us checking if it was complete. If the check won the race
and happened before the creation, Bintray would respond with a 404.

This commit updates BintrayService to wait for up to 5 minutes for the
distribution to be created on Bintray. Once it has been created we
then wait for up to 40 minutes for it to be complete as we did before.

The use of Awaitility has been introduced in this commit to simplify
the logic required to wait for the distribution's creation and
completion.

Closes gh-18902
parent 8b1ff0a1
......@@ -44,6 +44,10 @@
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
......
......@@ -17,19 +17,25 @@
package io.spring.concourse.releasescripts.bintray;
import java.net.URI;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import io.spring.concourse.releasescripts.ReleaseInfo;
import io.spring.concourse.releasescripts.sonatype.SonatypeProperties;
import io.spring.concourse.releasescripts.sonatype.SonatypeService;
import io.spring.concourse.releasescripts.system.ConsoleLogger;
import org.awaitility.core.ConditionTimeoutException;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import static org.awaitility.Awaitility.waitAtMost;
/**
* Central class for interacting with Bintray's REST API.
*
......@@ -64,25 +70,29 @@ public class BintrayService {
}
public boolean isDistributionComplete(ReleaseInfo releaseInfo) {
RequestEntity<Void> publishedFilesRequest = getRequest(releaseInfo, 0);
RequestEntity<Void> allFilesRequest = getRequest(releaseInfo, 1);
Object[] allFiles = this.restTemplate.exchange(allFilesRequest, Object[].class).getBody();
int count = 0;
while (count < 120) {
Object[] publishedFiles = this.restTemplate.exchange(publishedFilesRequest, Object[].class).getBody();
int unpublished = allFiles.length - publishedFiles.length;
if (unpublished == 0) {
return true;
}
count++;
Object[] allFiles = waitAtMost(5, TimeUnit.MINUTES).with().pollDelay(20, TimeUnit.SECONDS).until(() -> {
try {
Thread.sleep(20000);
return this.restTemplate.exchange(allFilesRequest, Object[].class).getBody();
}
catch (InterruptedException e) {
catch (HttpClientErrorException ex) {
if (ex.getStatusCode() != HttpStatus.NOT_FOUND) {
throw ex;
}
return null;
}
}, Objects::nonNull);
RequestEntity<Void> publishedFilesRequest = getRequest(releaseInfo, 0);
try {
waitAtMost(40, TimeUnit.MINUTES).with().pollDelay(20, TimeUnit.SECONDS).until(() -> {
Object[] publishedFiles = this.restTemplate.exchange(publishedFilesRequest, Object[].class).getBody();
return allFiles.length == publishedFiles.length;
});
}
catch (ConditionTimeoutException ex) {
return false;
}
return false;
return true;
}
private RequestEntity<Void> getRequest(ReleaseInfo releaseInfo, int includeUnpublished) {
......
......@@ -28,6 +28,7 @@ import org.springframework.boot.test.autoconfigure.web.client.RestClientTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.test.web.client.ExpectedCount;
import org.springframework.test.web.client.MockRestServiceServer;
......@@ -40,6 +41,7 @@ import static org.springframework.test.web.client.match.MockRestRequestMatchers.
import static org.springframework.test.web.client.match.MockRestRequestMatchers.header;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
/**
......@@ -73,6 +75,11 @@ class BintrayServiceTests {
@Test
void isDistributionComplete() throws Exception {
this.server
.expect(requestTo(String.format(
"https://api.bintray.com/packages/%s/%s/%s/versions/%s/files?include_unpublished=%s",
this.properties.getSubject(), this.properties.getRepo(), "example", "1.1.0.RELEASE", 1)))
.andRespond(withStatus(HttpStatus.NOT_FOUND));
setupGetPackageFiles(1, "all-package-files.json");
setupGetPackageFiles(0, "published-files.json");
setupGetPackageFiles(0, "all-package-files.json");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment