diff --git a/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/artifactory/ArtifactoryService.java b/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/artifactory/ArtifactoryService.java index 423f6899b37..3a927d6b2a5 100644 --- a/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/artifactory/ArtifactoryService.java +++ b/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/artifactory/ArtifactoryService.java @@ -124,26 +124,27 @@ public class ArtifactoryService { */ public void distribute(String sourceRepo, ReleaseInfo releaseInfo, Set artifactDigests) { logger.debug("Attempting distribute via Artifactory"); - if (this.bintrayService.isDistributionComplete(releaseInfo, artifactDigests, Duration.ofMinutes(2))) { - logger.info("Distribution already complete"); - return; + if (!this.bintrayService.isDistributionStarted(releaseInfo)) { + startDistribute(sourceRepo, releaseInfo); } + if (!this.bintrayService.isDistributionComplete(releaseInfo, artifactDigests, Duration.ofMinutes(60))) { + throw new DistributionTimeoutException("Distribution timed out."); + } + } + + private void startDistribute(String sourceRepo, ReleaseInfo releaseInfo) { DistributionRequest request = new DistributionRequest(new String[] { sourceRepo }); RequestEntity requestEntity = RequestEntity .post(URI.create(DISTRIBUTION_URL + releaseInfo.getBuildName() + "/" + releaseInfo.getBuildNumber())) .contentType(MediaType.APPLICATION_JSON).body(request); try { this.restTemplate.exchange(requestEntity, Object.class); - logger.debug("Distribution call completed"); + logger.debug("Distribute call completed"); } catch (HttpClientErrorException ex) { logger.info("Failed to distribute."); throw ex; } - if (!this.bintrayService.isDistributionComplete(releaseInfo, artifactDigests, Duration.ofMinutes(60))) { - throw new DistributionTimeoutException("Distribution timed out."); - } - } private PromotionRequest getPromotionRequest(String targetRepo) { diff --git a/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/bintray/BintrayService.java b/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/bintray/BintrayService.java index ce8996bb066..80ca5fa41fc 100644 --- a/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/bintray/BintrayService.java +++ b/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/bintray/BintrayService.java @@ -29,6 +29,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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; @@ -73,6 +74,22 @@ public class BintrayService { this.restTemplate = builder.build(); } + public boolean isDistributionStarted(ReleaseInfo releaseInfo) { + logger.debug("Checking if distribution is started"); + RequestEntity request = getPackageFilesRequest(releaseInfo, 1); + try { + logger.debug("Checking bintray"); + this.restTemplate.exchange(request, PackageFile[].class).getBody(); + return true; + } + catch (HttpClientErrorException ex) { + if (ex.getStatusCode() != HttpStatus.NOT_FOUND) { + throw ex; + } + return false; + } + } + public boolean isDistributionComplete(ReleaseInfo releaseInfo, Set requiredDigests, Duration timeout) { return isDistributionComplete(releaseInfo, requiredDigests, timeout, Duration.ofSeconds(20)); } @@ -80,7 +97,7 @@ public class BintrayService { public boolean isDistributionComplete(ReleaseInfo releaseInfo, Set requiredDigests, Duration timeout, Duration pollInterval) { logger.debug("Checking if distribution is complete"); - RequestEntity request = getRequest(releaseInfo, 0); + RequestEntity request = getPackageFilesRequest(releaseInfo, 0); try { waitAtMost(timeout).with().pollDelay(Duration.ZERO).pollInterval(pollInterval).until(() -> { logger.debug("Checking bintray"); @@ -115,7 +132,7 @@ public class BintrayService { return false; } - private RequestEntity getRequest(ReleaseInfo releaseInfo, int includeUnpublished) { + private RequestEntity getPackageFilesRequest(ReleaseInfo releaseInfo, int includeUnpublished) { return RequestEntity.get(URI.create(BINTRAY_URL + "packages/" + this.bintrayProperties.getSubject() + "/" + this.bintrayProperties.getRepo() + "/" + releaseInfo.getGroupId() + "/versions/" + releaseInfo.getVersion() + "/files?include_unpublished=" + includeUnpublished)).build(); diff --git a/ci/images/releasescripts/src/test/java/io/spring/concourse/releasescripts/artifactory/ArtifactoryServiceTests.java b/ci/images/releasescripts/src/test/java/io/spring/concourse/releasescripts/artifactory/ArtifactoryServiceTests.java index 20601d1f5b7..7cf1e7f067e 100644 --- a/ci/images/releasescripts/src/test/java/io/spring/concourse/releasescripts/artifactory/ArtifactoryServiceTests.java +++ b/ci/images/releasescripts/src/test/java/io/spring/concourse/releasescripts/artifactory/ArtifactoryServiceTests.java @@ -63,9 +63,7 @@ import static org.springframework.test.web.client.response.MockRestResponseCreat @EnableConfigurationProperties(ArtifactoryProperties.class) class ArtifactoryServiceTests { - private static final Duration SHORT_TIMEOUT = Duration.ofMinutes(2); - - private static final Duration LONG_TIMEOUT = Duration.ofMinutes(60); + private static final Duration TIMEOUT = Duration.ofMinutes(60); @Autowired private ArtifactoryService service; @@ -133,8 +131,8 @@ class ArtifactoryServiceTests { @SuppressWarnings("unchecked") void distributeWhenSuccessful() throws Exception { ReleaseInfo releaseInfo = getReleaseInfo(); - given(this.bintrayService.isDistributionComplete(eq(releaseInfo), (Set) any(), any())).willReturn(false, - true); + given(this.bintrayService.isDistributionStarted(eq(releaseInfo))).willReturn(false); + given(this.bintrayService.isDistributionComplete(eq(releaseInfo), (Set) any(), any())).willReturn(true); this.server.expect(requestTo("https://repo.spring.io/api/build/distribute/example-build/example-build-1")) .andExpect(method(HttpMethod.POST)) .andExpect(content().json( @@ -146,8 +144,7 @@ class ArtifactoryServiceTests { this.service.distribute("libs-release-local", releaseInfo, artifactDigests); this.server.verify(); InOrder ordered = inOrder(this.bintrayService); - ordered.verify(this.bintrayService).isDistributionComplete(releaseInfo, artifactDigests, SHORT_TIMEOUT); - ordered.verify(this.bintrayService).isDistributionComplete(releaseInfo, artifactDigests, LONG_TIMEOUT); + ordered.verify(this.bintrayService).isDistributionComplete(releaseInfo, artifactDigests, TIMEOUT); } @Test @@ -165,7 +162,7 @@ class ArtifactoryServiceTests { assertThatExceptionOfType(HttpClientErrorException.class) .isThrownBy(() -> this.service.distribute("libs-release-local", releaseInfo, artifactDigests)); this.server.verify(); - verify(this.bintrayService, times(1)).isDistributionComplete(releaseInfo, artifactDigests, SHORT_TIMEOUT); + verify(this.bintrayService, times(1)).isDistributionStarted(releaseInfo); verifyNoMoreInteractions(this.bintrayService); } @@ -189,8 +186,7 @@ class ArtifactoryServiceTests { .isThrownBy(() -> this.service.distribute("libs-release-local", releaseInfo, artifactDigests)); this.server.verify(); InOrder ordered = inOrder(this.bintrayService); - ordered.verify(this.bintrayService).isDistributionComplete(releaseInfo, artifactDigests, SHORT_TIMEOUT); - ordered.verify(this.bintrayService).isDistributionComplete(releaseInfo, artifactDigests, LONG_TIMEOUT); + ordered.verify(this.bintrayService).isDistributionComplete(releaseInfo, artifactDigests, TIMEOUT); } private ReleaseInfo getReleaseInfo() {