diff --git a/releaser-core/src/main/java/releaser/internal/Releaser.java b/releaser-core/src/main/java/releaser/internal/Releaser.java index 4c1dae2c..c37e588a 100644 --- a/releaser-core/src/main/java/releaser/internal/Releaser.java +++ b/releaser-core/src/main/java/releaser/internal/Releaser.java @@ -384,16 +384,7 @@ public class Releaser { public ExecutionResult createReleaseBundle(boolean commercial, ProjectVersion versionFromBom, Boolean dryRun, Map> commercialRepos, String projectName) { - if (dryRun) { - log.info("\nWon't create a release bundle for a dry run"); - return ExecutionResult.skipped(); - } - if (versionFromBom.isSnapshot()) { - log.info("\nWon't create a release bundle for a SNAPSHOT version"); - return ExecutionResult.skipped(); - } - if (!commercial) { - log.info("\nWon't create a release bundle for a non commercial project"); + if (!shouldCreateReleaseBundle(dryRun, versionFromBom.isSnapshot(), commercial)) { return ExecutionResult.skipped(); } log.info("\nCreating a release bundle"); @@ -419,4 +410,65 @@ public class Releaser { } } + private boolean shouldCreateReleaseBundle(boolean dryRun, boolean isSnapshot, boolean commercial) { + if (!dryRun && !isSnapshot && commercial) { + return true; + } + if (dryRun) { + log.info("\nWon't create a release bundle for a dry run"); + } + if (isSnapshot) { + log.info("\nWon't create a release bundle for a SNAPSHOT version"); + } + if (!commercial) { + log.info("\nWon't create a release bundle for a non commercial project"); + } + return false; + } + + public ExecutionResult createReleaseTrainSourceBundle(List projectsWithNewRelease, + boolean isCommercial, boolean dryRun, ProjectVersion projectVersion) { + if (!shouldCreateReleaseBundle(dryRun, projectVersion.isSnapshot(), isCommercial)) { + return ExecutionResult.skipped(); + } + try { + boolean result = this.releaseBundleCreator.createReleaseTrainSourceBundle(projectsWithNewRelease, + projectVersion.version); + if (!result) { + log.warn("Failed to create release train source bundle"); + return ExecutionResult + .unstable(new BuildUnstableException("Failed to create a release train source bundle")); + } + log.info("\nSuccessfully created a release train source bundle"); + return ExecutionResult.success(); + } + catch (Exception ex) { + log.error("Failed to create a release train source bundle", ex); + return ExecutionResult + .unstable(new BuildUnstableException("Failed to create a release train source bundle", ex)); + } + } + + public ExecutionResult distributeReleaseTrainSourceBundle(boolean isCommercial, boolean dryRun, + ProjectVersion projectVersion) { + if (!shouldCreateReleaseBundle(dryRun, projectVersion.isSnapshot(), isCommercial)) { + return ExecutionResult.skipped(); + } + try { + boolean result = this.releaseBundleCreator.distributeReleaseTrainSourceBundle(projectVersion.version); + if (!result) { + log.warn("Failed to distribute release train source bundle"); + return ExecutionResult + .unstable(new BuildUnstableException("Failed to distribute a release train source bundle")); + } + log.info("\nSuccessfully distributed a release train source bundle"); + return ExecutionResult.success(); + } + catch (Exception ex) { + log.error("Failed to distribute a release train source bundle", ex); + return ExecutionResult + .unstable(new BuildUnstableException("Failed to distribute a release train source bundle", ex)); + } + } + } diff --git a/releaser-core/src/main/java/releaser/internal/ReleaserProperties.java b/releaser-core/src/main/java/releaser/internal/ReleaserProperties.java index d6484235..cd3181e9 100644 --- a/releaser-core/src/main/java/releaser/internal/ReleaserProperties.java +++ b/releaser-core/src/main/java/releaser/internal/ReleaserProperties.java @@ -1579,6 +1579,8 @@ public class ReleaserProperties implements Serializable { private boolean createReleaseTrainReleaseBundle = false; + private boolean distributeReleaseBundle = false; + private String repoUrl = "https://usw1.packages.broadcom.com"; private String repoUsername; @@ -1603,6 +1605,14 @@ public class ReleaserProperties implements Serializable { this.createReleaseTrainReleaseBundle = createReleaseTrainReleaseBundle; } + public boolean isDistributeReleaseBundle() { + return distributeReleaseBundle; + } + + public void setDistributeReleaseBundle(boolean distributeReleaseBundle) { + this.distributeReleaseBundle = distributeReleaseBundle; + } + public Map> getRepos() { return repos; } diff --git a/releaser-core/src/main/java/releaser/internal/commercial/ReleaseBundleCreator.java b/releaser-core/src/main/java/releaser/internal/commercial/ReleaseBundleCreator.java index 66bc96d6..f9cb43e8 100644 --- a/releaser-core/src/main/java/releaser/internal/commercial/ReleaseBundleCreator.java +++ b/releaser-core/src/main/java/releaser/internal/commercial/ReleaseBundleCreator.java @@ -17,6 +17,9 @@ package releaser.internal.commercial; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -32,6 +35,7 @@ import org.jfrog.artifactory.client.impl.ArtifactoryRequestImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import releaser.internal.ReleaserProperties; +import releaser.internal.project.ProjectVersion; /** * @author Ryan Baxter @@ -40,9 +44,11 @@ public class ReleaseBundleCreator { private static final Logger log = LoggerFactory.getLogger(ReleaseBundleCreator.class); - private Artifactory artifactory; + public static final String RELEASE_TRAIN_BUNDLE_NAME = "TNZ-spring-cloud-commercial-release"; - private ObjectMapper objectMapper; + private final Artifactory artifactory; + + private final ObjectMapper objectMapper; public ReleaseBundleCreator(ReleaserProperties properties) { log.info("Creating Artifactory client with URL [{}]", properties.getBundles().getRepoUrl()); @@ -54,11 +60,12 @@ public class ReleaseBundleCreator { this.objectMapper = new ObjectMapper(); } - public boolean createReleaseBundle(List repos, String version, String releaseBundleName) throws IOException { + public boolean createReleaseBundle(List repos, String version, String releaseBundleName) + throws IOException { Map json = new HashMap<>(); json.put("release_bundle_name", releaseBundleName); json.put("release_bundle_version", version); - json.put( "source_type", "aql"); + json.put("source_type", "aql"); json.put("source", createAqlMap(repos, version)); return createReleaseBundle(objectMapper.writeValueAsString(json)); } @@ -88,13 +95,77 @@ public class ReleaseBundleCreator { .apiUrl("lifecycle/api/v2/release_bundle").addQueryParam("project", "spring") .addHeader("X-JFrog-Signing-Key-Name", "packagesKey").requestType(ArtifactoryRequest.ContentType.JSON) .responseType(ArtifactoryRequest.ContentType.JSON).requestBody(json); - ArtifactoryResponse response = artifactory.restCall(aqlRequest); + return makeArtifactoryRequest(aqlRequest); + } + + public boolean createReleaseTrainSourceBundle(List projectsReleased, String version) + throws IOException { + log.info("Creating release train source bundle for projects {}", projectsReleased); + Map json = new HashMap<>(); + json.put("release_bundle_name", RELEASE_TRAIN_BUNDLE_NAME); + json.put("release_bundle_version", version); + json.put("skip_docker_manifest_resolution", false); + json.put("source_type", "release_bundles"); + json.put("source", createReleaseBundlesJson(projectsReleased)); + return createReleaseBundle(objectMapper.writeValueAsString(json)); + } + + private Map createReleaseBundlesJson(List projectsReleased) { + Map json = new HashMap<>(); + List> releaseBundles = new ArrayList<>(); + projectsReleased.forEach(project -> releaseBundles.add(createReleaseBundleJson(project))); + json.put("release_bundles", releaseBundles); + return json; + } + + private Map createReleaseBundleJson(ProjectVersion project) { + Map json = new HashMap<>(); + json.put("project_key", "spring"); + json.put("repository_key", "spring-release-bundles-v2"); + json.put("release_bundle_name", "TNZ-" + project.projectName + "-commercial"); + json.put("release_bundle_version", project.version); + return json; + } + + public boolean distributeReleaseTrainSourceBundle(String version) throws IOException { + return distributeReleaseBundle(RELEASE_TRAIN_BUNDLE_NAME, version, + objectMapper.writeValueAsString(createDistributionJson())); + } + + public boolean distributeReleaseBundle(String releaseBundleName, String version, String json) throws IOException { + log.info("Distributing release bundle with name [{}] and version[{}] and JSON data [{}]", releaseBundleName, + version, json); + ArtifactoryRequest request = new ArtifactoryRequestImpl().method(ArtifactoryRequest.Method.POST) + .apiUrl("lifecycle/api/v2/distribution/distribute/" + RELEASE_TRAIN_BUNDLE_NAME + "/" + version) + .addQueryParam("project", "spring").requestType(ArtifactoryRequest.ContentType.JSON) + .responseType(ArtifactoryRequest.ContentType.JSON).requestBody(json); + return makeArtifactoryRequest(request); + } + + private boolean makeArtifactoryRequest(ArtifactoryRequest request) throws IOException { + ArtifactoryResponse response = artifactory.restCall(request); if (!response.isSuccessResponse()) { - log.warn("Failed to create release bundle {}", response.getRawBody()); - return false; + log.warn("Artifactory request failed {}", response.getRawBody()); } - log.info("Created release bundle {}", response.getRawBody()); - return true; + else { + log.info("Artifactory request succeeded {}", response.getRawBody()); + } + return response.isSuccessResponse(); + } + + private Map createDistributionJson() { + Map json = new HashMap<>(); + json.put("auto_create_missing_repositories", "false"); + json.put("distribution_rules", List.of(Collections.singletonMap("site_name", "JP-SaaS"))); + json.put("modifications", createMappings()); + return json; + } + + private Map createMappings() { + Map input = Collections.singletonMap("input", "spring-enterprise-maven-prod-local/(.*)"); + Map output = Collections.singletonMap("output", "spring-enterprise/$1"); + List> mappingsArray = Arrays.asList(input, output); + return Collections.singletonMap("mappings", mappingsArray); } diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/CreateReleaseTrainReleaseBundlePostReleaseTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/CreateReleaseTrainReleaseBundlePostReleaseTask.java index 779c9c49..05748d5f 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/CreateReleaseTrainReleaseBundlePostReleaseTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/CreateReleaseTrainReleaseBundlePostReleaseTask.java @@ -16,6 +16,9 @@ package releaser.internal.tasks.postrelease; +import java.util.LinkedList; +import java.util.List; + import releaser.internal.Releaser; import releaser.internal.project.ProjectVersion; import releaser.internal.spring.Arguments; @@ -60,9 +63,16 @@ public class CreateReleaseTrainReleaseBundlePostReleaseTask implements TrainPost } @Override - public ExecutionResult runTask(Arguments args) throws BuildUnstableException, RuntimeException { - return releaser.createReleaseBundle(args.properties.isCommercial(), args.versionFromBom, args.options.dryRun, - args.properties.getBundles().getRepos(), new ProjectVersion(args.project).projectName); + public ExecutionResult runTask(Arguments args) throws BuildUnstableException { + List releasedProjects = new LinkedList<>(); + args.projects.forEach(projectVersion -> { + if (args.properties.getMetaRelease().getProjectsToSkip().stream() + .noneMatch(projectVersion.projectName::startsWith)) { + releasedProjects.add(projectVersion); + } + }); + return releaser.createReleaseTrainSourceBundle(releasedProjects, args.properties.isCommercial(), + args.options.dryRun, args.versionFromBom); } @Override diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/DistributeReleaseBundleTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/DistributeReleaseBundleTask.java new file mode 100644 index 00000000..ed002883 --- /dev/null +++ b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/DistributeReleaseBundleTask.java @@ -0,0 +1,72 @@ +/* + * Copyright 2013-2024 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.internal.tasks.postrelease; + +import releaser.internal.Releaser; +import releaser.internal.spring.Arguments; +import releaser.internal.tasks.TrainPostReleaseReleaserTask; +import releaser.internal.tech.BuildUnstableException; +import releaser.internal.tech.ExecutionResult; + +/** + * @author Ryan Baxter + */ +public class DistributeReleaseBundleTask implements TrainPostReleaseReleaserTask { + + /** + * Order of this task. The higher value, the lower order. + */ + public static final int ORDER = CreateReleaseTrainReleaseBundlePostReleaseTask.ORDER + 10; + + private final Releaser releaser; + + public DistributeReleaseBundleTask(Releaser releaser) { + this.releaser = releaser; + } + + @Override + public String name() { + return "distributeReleaseBundleTask"; + } + + @Override + public String shortName() { + return "drb"; + } + + @Override + public String header() { + return "DISTRIBUTING RELEASE BUNDLE"; + } + + @Override + public String description() { + return "Distributes the release bundle to the edge repository."; + } + + @Override + public ExecutionResult runTask(Arguments args) throws BuildUnstableException { + return releaser.distributeReleaseTrainSourceBundle(args.properties.isCommercial(), args.options.dryRun, + args.versionFromBom); + } + + @Override + public int getOrder() { + return ORDER; + } + +} diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/PostReleaseTasksConfiguration.java b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/PostReleaseTasksConfiguration.java index f7acf615..72359fb8 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/PostReleaseTasksConfiguration.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/PostReleaseTasksConfiguration.java @@ -106,4 +106,11 @@ class PostReleaseTasksConfiguration { return new CreateProjectReleaseBundlePostReleaseTask(releaser); } + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty("releaser.bundles.distribute-release-bundle") + DistributeReleaseBundleTask distributeReleaseBundleTask(Releaser releaser) { + return new DistributeReleaseBundleTask(releaser); + } + }