Merge pull request #286 from ryanjbaxter/release-bundle-distribution-for-commercial

Use artifactory client
This commit is contained in:
Ryan Baxter
2024-06-03 16:06:16 -04:00
committed by GitHub
10 changed files with 288 additions and 11 deletions

14
pom.xml
View File

@@ -12,7 +12,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-build</artifactId>
<version>4.0.3</version>
<version>4.0.6</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
@@ -47,6 +47,8 @@
<fliptables.version>1.1.0</fliptables.version>
<zt.exec.version>1.12</zt.exec.version>
<okhttp.version>4.11.0</okhttp.version>
<artifactory-client.version>2.17.0</artifactory-client.version>
<groovy.version>4.0.6</groovy.version>
</properties>
<dependencyManagement>
@@ -145,6 +147,16 @@
<artifactId>awaitility</artifactId>
<version>${awaitility.version}</version>
</dependency>
<dependency>
<groupId>org.jfrog.artifactory.client</groupId>
<artifactId>artifactory-java-client-services</artifactId>
<version>${artifactory-client.version}</version>
</dependency>
<dependency>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy</artifactId>
<version>${groovy.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

View File

@@ -113,3 +113,57 @@ releaser:
projects-to-skip:
- spring-boot
- spring-cloud-stream
bundles:
repos:
spring-cloud-build:
- "org/springframework/cloud/spring-cloud-build*"
- "org/springframework/cloud/spring-cloud-starter-build*"
- "org/springframework/cloud/spring-cloud-dependencies-parent*"
spring-cloud-config:
- "org/springframework/cloud/spring-cloud-config*"
- "org/springframework/cloud/spring-cloud-starter-config*"
spring-cloud-function:
- "org/springframework/cloud/spring-cloud-function*"
- "org/springframework/cloud/spring-cloud-starter-function*"
spring-cloud-stream:
- "org/springframework/cloud/spring-cloud-stream*"
- "org/springframework/cloud/spring-cloud-starter-stream*"
spring-cloud-task:
- "org/springframework/cloud/spring-cloud-task*"
- "org/springframework/cloud/spring-cloud-starter-task*"
spring-cloud-bus:
- "org/springframework/cloud/spring-cloud-bus*"
- "org/springframework/cloud/spring-cloud-starter-bus*"
spring-cloud-commons:
- "org/springframework/cloud/spring-cloud-commons*"
- "org/springframework/cloud/spring-cloud-starter-commons*"
spring-cloud-netflix:
- "org/springframework/cloud/spring-cloud-netflix*"
- "org/springframework/cloud/spring-cloud-starter-netflix*"
spring-cloud-openfeign:
- "org/springframework/cloud/spring-cloud-openfeign*"
- "org/springframework/cloud/spring-cloud-starter-openfeign*"
spring-cloud-consul:
- "org/springframework/cloud/spring-cloud-consul*"
- "org/springframework/cloud/spring-cloud-starter-consul*"
spring-cloud-circuitbreaker:
- "org/springframework/cloud/spring-cloud-circuitbreaker*"
- "org/springframework/cloud/spring-cloud-starter-circuitbreaker*"
spring-cloud-gateway:
- "org/springframework/cloud/spring-cloud-gateway*"
- "org/springframework/cloud/spring-cloud-starter-gateway*"
spring-cloud-zookeeper:
- "org/springframework/cloud/spring-cloud-zookeeper*"
- "org/springframework/cloud/spring-cloud-starter-zookeeper*"
spring-cloud-contract:
- "org/springframework/cloud/spring-cloud-contract*"
- "org/springframework/cloud/spring-cloud-starter-contract*"
spring-cloud-kubernetes:
- "org/springframework/cloud/spring-cloud-kubernetes*"
- "org/springframework/cloud/spring-cloud-starter-kubernetes*"
spring-cloud-vault:
- "org/springframework/cloud/spring-cloud-vault*"
- "org/springframework/cloud/spring-cloud-starter-vault*"
spring-cloud-release:
- "org/springframework/cloud/spring-cloud-starter*"
- "org/springframework/cloud/spring-cloud-dependencies*"

View File

@@ -91,6 +91,14 @@
<groupId>io.spring.initializr</groupId>
<artifactId>initializr-metadata</artifactId>
</dependency>
<dependency>
<groupId>org.jfrog.artifactory.client</groupId>
<artifactId>artifactory-java-client-services</artifactId>
</dependency>
<dependency>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

View File

@@ -18,11 +18,13 @@ package releaser.internal;
import java.io.File;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import releaser.internal.buildsystem.GradleUpdater;
import releaser.internal.buildsystem.ProjectPomUpdater;
import releaser.internal.commercial.ReleaseBundleCreator;
import releaser.internal.docs.DocumentationUpdater;
import releaser.internal.git.ProjectGitHandler;
import releaser.internal.github.ProjectGitHubHandler;
@@ -69,11 +71,13 @@ public class Releaser {
private ReleaserProperties releaserProperties;
private ReleaseBundleCreator releaseBundleCreator;
public Releaser(ReleaserProperties releaserProperties, ProjectPomUpdater projectPomUpdater,
ProjectCommandExecutor projectCommandExecutor, ProjectGitHandler projectGitHandler,
ProjectGitHubHandler projectGitHubHandler, TemplateGenerator templateGenerator, GradleUpdater gradleUpdater,
SaganUpdater saganUpdater, DocumentationUpdater documentationUpdater,
PostReleaseActions postReleaseActions) {
SaganUpdater saganUpdater, DocumentationUpdater documentationUpdater, PostReleaseActions postReleaseActions,
ReleaseBundleCreator releaseBundleCreator) {
this.releaserProperties = releaserProperties;
this.projectPomUpdater = projectPomUpdater;
this.projectCommandExecutor = projectCommandExecutor;
@@ -84,6 +88,7 @@ public class Releaser {
this.saganUpdater = saganUpdater;
this.documentationUpdater = documentationUpdater;
this.postReleaseActions = postReleaseActions;
this.releaseBundleCreator = releaseBundleCreator;
}
public File clonedProjectFromOrg(String projectName) {
@@ -377,7 +382,8 @@ public class Releaser {
return ExecutionResult.skipped();
}
public ExecutionResult createReleaseBundle(boolean commercial, ProjectVersion versionFromBom, Boolean dryRun) {
public ExecutionResult createReleaseBundle(boolean commercial, ProjectVersion versionFromBom, Boolean dryRun,
Map<String, List<String>> commercialRepos, String projectName) {
if (dryRun) {
log.info("\nWon't create a release bundle for a dry run");
return ExecutionResult.skipped();
@@ -391,7 +397,25 @@ public class Releaser {
return ExecutionResult.skipped();
}
log.info("\nCreating a release bundle");
return ExecutionResult.success();
if (!commercialRepos.containsKey(projectName)) {
log.warn("No commercial repos configured for project [{}], double check releaser.bundles.repos",
projectName);
}
List<String> repos = commercialRepos.get(projectName);
log.info("Creating release bundles for project [{}] in repos [{}]", projectName, repos);
try {
boolean result = this.releaseBundleCreator.createReleaseBundle(repos, versionFromBom.version);
if (!result) {
log.warn("Failed to create release bundle");
return ExecutionResult.unstable(new BuildUnstableException("Failed to create a release bundle"));
}
log.info("\nSuccessfully created a release bundle");
return ExecutionResult.success();
}
catch (Exception ex) {
log.error("Failed to create a release bundle", ex);
return ExecutionResult.unstable(new BuildUnstableException("Failed to create a release bundle", ex));
}
}
}

View File

@@ -80,6 +80,8 @@ public class ReleaserProperties implements Serializable {
private boolean commercial = false;
private Bundles bundles = new Bundles();
/**
* Project name to its version - overrides all versions retrieved from a release train
* repository like Spring Cloud Release.
@@ -208,6 +210,14 @@ public class ReleaserProperties implements Serializable {
this.commercial = commercial;
}
public Bundles getBundles() {
return bundles;
}
public void setBundles(Bundles bundles) {
this.bundles = bundles;
}
@Override
public String toString() {
return "ReleaserProperties{" + "workingDir='" + this.workingDir + '\'' + ", git=" + this.git + ", pom="
@@ -1563,4 +1573,68 @@ public class ReleaserProperties implements Serializable {
}
public static class Bundles implements Serializable {
private boolean createProjectReleaseBundle = false;
private boolean createReleaseTrainReleaseBundle = false;
private String repoUrl = "https://usw1.packages.broadcom.com";
private String repoUsername;
private String repoPassword;
private Map<String, List<String>> repos;
public boolean isCreateProjectReleaseBundle() {
return createProjectReleaseBundle;
}
public void setCreateProjectReleaseBundle(boolean createProjectReleaseBundle) {
this.createProjectReleaseBundle = createProjectReleaseBundle;
}
public boolean isCreateReleaseTrainReleaseBundle() {
return createReleaseTrainReleaseBundle;
}
public void setCreateReleaseTrainReleaseBundle(boolean createReleaseTrainReleaseBundle) {
this.createReleaseTrainReleaseBundle = createReleaseTrainReleaseBundle;
}
public Map<String, List<String>> getRepos() {
return repos;
}
public void setRepos(Map<String, List<String>> repos) {
this.repos = repos;
}
public String getRepoUrl() {
return repoUrl;
}
public void setRepoUrl(String repoUrl) {
this.repoUrl = repoUrl;
}
public String getRepoUsername() {
return repoUsername;
}
public void setRepoUsername(String repoUsername) {
this.repoUsername = repoUsername;
}
public String getRepoPassword() {
return repoPassword;
}
public void setRepoPassword(String repoPassword) {
this.repoPassword = repoPassword;
}
}
}

View File

@@ -0,0 +1,80 @@
/*
* 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.commercial;
import java.io.IOException;
import java.util.List;
import org.jfrog.artifactory.client.Artifactory;
import org.jfrog.artifactory.client.ArtifactoryClientBuilder;
import org.jfrog.artifactory.client.ArtifactoryRequest;
import org.jfrog.artifactory.client.ArtifactoryResponse;
import org.jfrog.artifactory.client.aql.AqlItem;
import org.jfrog.artifactory.client.aql.AqlQueryBuilder;
import org.jfrog.artifactory.client.impl.ArtifactoryRequestImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import releaser.internal.ReleaserProperties;
/**
* @author Ryan Baxter
*/
public class ReleaseBundleCreator {
private static final Logger log = LoggerFactory.getLogger(ReleaseBundleCreator.class);
private ReleaserProperties properties;
private Artifactory artifactory;
public ReleaseBundleCreator(ReleaserProperties properties) {
this.properties = properties;
this.artifactory = ArtifactoryClientBuilder.create().setUrl(properties.getBundles().getRepoUrl())
.setUsername(properties.getBundles().getRepoUsername())
.setPassword(properties.getBundles().getRepoPassword()).build();
}
public boolean createReleaseBundle(List<String> repos, String version) throws IOException {
AqlQueryBuilder builder = new AqlQueryBuilder()
.item(AqlItem.aqlItem("repo", AqlItem.aqlItem("$eq", "spring-enterprise-maven-prod-local")));
AqlItem[] items = new AqlItem[repos.size()];
for (String repo : repos) {
items[repos.indexOf(repo)] = AqlItem.match("path", repo + "/" + version);
}
String aql = builder.or(items).asc("path", "name").build();
return createReleaseBundle(aql);
}
public boolean createReleaseBundle(String aql) throws IOException {
log.info("Creating release bundle with AQL [{}]", aql);
ArtifactoryRequest aqlRequest = new ArtifactoryRequestImpl().method(ArtifactoryRequest.Method.POST)
.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(aql);
ArtifactoryResponse response = artifactory.restCall(aqlRequest);
if (!response.isSuccessResponse()) {
log.warn("Failed to create release bundle {}", response.getRawBody());
return false;
}
log.info("Created release bundle {}", response.getRawBody());
return true;
}
}

View File

@@ -17,6 +17,7 @@
package releaser.internal;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.function.Supplier;
@@ -31,6 +32,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
import releaser.SpringCloudReleaserProperties;
import releaser.internal.buildsystem.GradleUpdater;
import releaser.internal.buildsystem.ProjectPomUpdater;
import releaser.internal.commercial.ReleaseBundleCreator;
import releaser.internal.docs.DocumentationUpdater;
import releaser.internal.git.ProjectGitHandler;
import releaser.internal.github.ProjectGitHubHandler;
@@ -92,7 +94,13 @@ public class ReleaserTests {
Releaser releaser(Supplier<ProjectVersion> originalVersionSupplier) {
return new Releaser(SpringCloudReleaserProperties.get(), this.projectPomUpdater, this.projectCommandExecutor,
this.projectGitHandler, this.projectGitHubHandler, this.templateGenerator, this.gradleUpdater,
this.saganUpdater, this.documentationUpdater, this.postReleaseActions) {
this.saganUpdater, this.documentationUpdater, this.postReleaseActions,
new ReleaseBundleCreator(SpringCloudReleaserProperties.get()) {
@Override
public boolean createReleaseBundle(String aql) throws IOException {
return true;
}
}) {
@Override
ProjectVersion originalVersion(File project) {
return originalVersionSupplier.get();
@@ -103,7 +111,13 @@ public class ReleaserTests {
Releaser releaser() {
return new Releaser(new ReleaserProperties(), this.projectPomUpdater, this.projectCommandExecutor,
this.projectGitHandler, this.projectGitHubHandler, this.templateGenerator, this.gradleUpdater,
this.saganUpdater, this.documentationUpdater, this.postReleaseActions);
this.saganUpdater, this.documentationUpdater, this.postReleaseActions,
new ReleaseBundleCreator(SpringCloudReleaserProperties.get()) {
@Override
public boolean createReleaseBundle(String aql) throws IOException {
return true;
}
});
}
@Test

View File

@@ -24,6 +24,7 @@ import releaser.internal.ReleaserProperties;
import releaser.internal.ReleaserPropertiesUpdater;
import releaser.internal.buildsystem.GradleUpdater;
import releaser.internal.buildsystem.ProjectPomUpdater;
import releaser.internal.commercial.ReleaseBundleCreator;
import releaser.internal.docs.CustomProjectDocumentationUpdater;
import releaser.internal.docs.DocumentationUpdater;
import releaser.internal.git.ProjectGitHandler;
@@ -154,10 +155,10 @@ class ReleaserConfiguration {
ProjectGitHandler projectGitHandler, ProjectGitHubHandler projectGitHubHandler,
TemplateGenerator templateGenerator, GradleUpdater gradleUpdater, SaganUpdater saganUpdater,
DocumentationUpdater documentationUpdater, PostReleaseActions postReleaseActions,
ReleaserProperties releaserProperties) {
ReleaserProperties releaserProperties, ReleaseBundleCreator releaseBundleCreator) {
return new Releaser(releaserProperties, projectPomUpdater, projectCommandExecutor, projectGitHandler,
projectGitHubHandler, templateGenerator, gradleUpdater, saganUpdater, documentationUpdater,
postReleaseActions);
postReleaseActions, releaseBundleCreator);
}
@Bean
@@ -173,4 +174,10 @@ class ReleaserConfiguration {
return new OptionsParser(allTasks, singleProjectReleaserTasks, context);
}
@Bean
@ConditionalOnMissingBean
ReleaseBundleCreator releaseBundleCreator(ReleaserProperties properties) {
return new ReleaseBundleCreator(properties);
}
}

View File

@@ -17,6 +17,7 @@
package releaser.internal.tasks.postrelease;
import releaser.internal.Releaser;
import releaser.internal.project.ProjectVersion;
import releaser.internal.spring.Arguments;
import releaser.internal.tasks.ProjectPostReleaseReleaserTask;
import releaser.internal.tech.BuildUnstableException;
@@ -61,7 +62,8 @@ public class CreateProjectReleaseBundlePostReleaseTask implements ProjectPostRel
@Override
public ExecutionResult runTask(Arguments args) throws BuildUnstableException, RuntimeException {
return this.releaser.createReleaseBundle(args.properties.isCommercial(), args.versionFromBom,
args.options.dryRun);
args.options.dryRun, args.properties.getBundles().getRepos(),
new ProjectVersion(args.project).projectName);
}
@Override

View File

@@ -17,6 +17,7 @@
package releaser.internal.tasks.postrelease;
import releaser.internal.Releaser;
import releaser.internal.project.ProjectVersion;
import releaser.internal.spring.Arguments;
import releaser.internal.tasks.TrainPostReleaseReleaserTask;
import releaser.internal.tech.BuildUnstableException;
@@ -60,7 +61,8 @@ 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);
return releaser.createReleaseBundle(args.properties.isCommercial(), args.versionFromBom, args.options.dryRun,
args.properties.getBundles().getRepos(), new ProjectVersion(args.project).projectName);
}
@Override