diff --git a/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/command/PublishToCentralCommand.java b/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/command/PublishToCentralCommand.java index 23ec5a319d3..2dccc1876e4 100644 --- a/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/command/PublishToCentralCommand.java +++ b/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/command/PublishToCentralCommand.java @@ -72,8 +72,9 @@ public class PublishToCentralCommand implements Command { byte[] content = Files.readAllBytes(new File(buildInfoLocation).toPath()); BuildInfoResponse buildInfoResponse = this.objectMapper.readValue(content, BuildInfoResponse.class); BuildInfo buildInfo = buildInfoResponse.getBuildInfo(); + ReleaseInfo releaseInfo = ReleaseInfo.from(buildInfo); String artifactsLocation = nonOptionArgs.get(3); - this.sonatype.publish(ReleaseInfo.from(buildInfo), new File(artifactsLocation).toPath()); + this.sonatype.publish(releaseInfo, new File(artifactsLocation).toPath()); } } diff --git a/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/sonatype/SonatypeService.java b/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/sonatype/SonatypeService.java index 1f17dd12609..da92b0c207b 100644 --- a/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/sonatype/SonatypeService.java +++ b/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/sonatype/SonatypeService.java @@ -89,11 +89,30 @@ public class SonatypeService { } /** - * Checks if artifacts are already published to Maven Central. - * @return true if artifacts are published + * Publishes the release by creating a staging repository and deploying to it the + * artifacts at the given {@code artifactsRoot}. The repository is then closed and, + * upon successfully closure, it is released. * @param releaseInfo the release information + * @param artifactsRoot the root directory of the artifacts to stage */ - public boolean artifactsPublished(ReleaseInfo releaseInfo) { + public void publish(ReleaseInfo releaseInfo, Path artifactsRoot) { + if (artifactsPublished(releaseInfo)) { + return; + } + logger.info("Creating staging repository"); + String buildId = releaseInfo.getBuildNumber(); + String repositoryId = createStagingRepository(buildId); + Collection artifacts = this.artifactCollector.collectArtifacts(artifactsRoot); + logger.info("Staging repository {} created. Deploying {} artifacts", repositoryId, artifacts.size()); + deploy(artifacts, repositoryId); + logger.info("Deploy complete. Closing staging repository"); + close(repositoryId); + logger.info("Staging repository closed"); + release(repositoryId, buildId); + logger.info("Staging repository released"); + } + + private boolean artifactsPublished(ReleaseInfo releaseInfo) { try { ResponseEntity entity = this.restTemplate .getForEntity(String.format(NEXUS_REPOSITORY_PATH + "%s/spring-boot-%s.jar.sha1", @@ -109,27 +128,6 @@ public class SonatypeService { return false; } - /** - * Publishes the release by creating a staging repository and deploying to it the - * artifacts at the given {@code artifactsRoot}. The repository is then closed and, - * upon successfully closure, it is released. - * @param releaseInfo the release information - * @param artifactsRoot the root directory of the artifacts to stage - */ - public void publish(ReleaseInfo releaseInfo, Path artifactsRoot) { - logger.info("Creating staging repository"); - String buildId = releaseInfo.getBuildNumber(); - String repositoryId = createStagingRepository(buildId); - Collection artifacts = this.artifactCollector.collectArtifacts(artifactsRoot); - logger.info("Staging repository {} created. Deploying {} artifacts", repositoryId, artifacts.size()); - deploy(artifacts, repositoryId); - logger.info("Deploy complete. Closing staging repository"); - close(repositoryId); - logger.info("Staging repository closed"); - release(repositoryId, buildId); - logger.info("Staging repository released"); - } - private String createStagingRepository(String buildId) { Map body = new HashMap<>(); body.put("data", Collections.singletonMap("description", buildId)); diff --git a/ci/images/releasescripts/src/test/java/io/spring/concourse/releasescripts/sonatype/SonatypeServiceTests.java b/ci/images/releasescripts/src/test/java/io/spring/concourse/releasescripts/sonatype/SonatypeServiceTests.java index c8bd5e8e7dc..6c9133c7c67 100644 --- a/ci/images/releasescripts/src/test/java/io/spring/concourse/releasescripts/sonatype/SonatypeServiceTests.java +++ b/ci/images/releasescripts/src/test/java/io/spring/concourse/releasescripts/sonatype/SonatypeServiceTests.java @@ -74,29 +74,23 @@ class SonatypeServiceTests { } @Test - void artifactsPublishedWhenPublishedShouldReturnTrue() { + void publishWhenAlreadyPublishedShouldNotPublish() { this.server.expect(requestTo(String.format( "/service/local/repositories/releases/content/org/springframework/boot/spring-boot/%s/spring-boot-%s.jar.sha1", "1.1.0.RELEASE", "1.1.0.RELEASE"))).andExpect(method(HttpMethod.GET)) .andRespond(withSuccess().body("ce8d8b6838ecceb68962b9150b18682f4237ccf71".getBytes())); - boolean published = this.service.artifactsPublished(getReleaseInfo()); - assertThat(published).isTrue(); - this.server.verify(); - } - - @Test - void artifactsPublishedWhenNotPublishedShouldReturnFalse() { - this.server.expect(requestTo(String.format( - "/service/local/repositories/releases/content/org/springframework/boot/spring-boot/%s/spring-boot-%s.jar.sha1", - "1.1.0.RELEASE", "1.1.0.RELEASE"))).andExpect(method(HttpMethod.GET)) - .andRespond(withStatus(HttpStatus.NOT_FOUND)); - boolean published = this.service.artifactsPublished(getReleaseInfo()); - assertThat(published).isFalse(); + Path artifactsRoot = new File("src/test/resources/io/spring/concourse/releasescripts/sonatype/artifactory-repo") + .toPath(); + this.service.publish(getReleaseInfo(), artifactsRoot); this.server.verify(); } @Test void publishWithSuccessfulClose() throws IOException { + this.server.expect(requestTo(String.format( + "/service/local/repositories/releases/content/org/springframework/boot/spring-boot/%s/spring-boot-%s.jar.sha1", + "1.1.0.RELEASE", "1.1.0.RELEASE"))).andExpect(method(HttpMethod.GET)) + .andRespond(withStatus(HttpStatus.NOT_FOUND)); this.server.expect(requestTo("/service/local/staging/profiles/1a2b3c4d/start")) .andExpect(method(HttpMethod.POST)).andExpect(header("Content-Type", "application/json")) .andExpect(header("Accept", "application/json, application/*+json")) @@ -145,6 +139,10 @@ class SonatypeServiceTests { @Test void publishWithCloseFailureDueToRuleViolations() throws IOException { + this.server.expect(requestTo(String.format( + "/service/local/repositories/releases/content/org/springframework/boot/spring-boot/%s/spring-boot-%s.jar.sha1", + "1.1.0.RELEASE", "1.1.0.RELEASE"))).andExpect(method(HttpMethod.GET)) + .andRespond(withStatus(HttpStatus.NOT_FOUND)); this.server.expect(requestTo("/service/local/staging/profiles/1a2b3c4d/start")) .andExpect(method(HttpMethod.POST)).andExpect(header("Content-Type", "application/json")) .andExpect(header("Accept", "application/json, application/*+json"))