From e02d58d91322793e0da757542b7f2112736d6b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Honza=20Br=C3=A1zdil?= Date: Thu, 5 Jun 2025 11:18:54 +0200 Subject: [PATCH 1/3] [AB]: Add option to specify maven settings.xml --- .../config/DependencyResolutionConfig.java | 6 ++++ .../impl/dependencies/DependencyResolver.java | 31 +++++++++++++------ pom.xml | 2 +- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/experimental/src/main/java/org/jboss/bacon/experimental/impl/config/DependencyResolutionConfig.java b/experimental/src/main/java/org/jboss/bacon/experimental/impl/config/DependencyResolutionConfig.java index 217605d5c..e926f48f1 100644 --- a/experimental/src/main/java/org/jboss/bacon/experimental/impl/config/DependencyResolutionConfig.java +++ b/experimental/src/main/java/org/jboss/bacon/experimental/impl/config/DependencyResolutionConfig.java @@ -1,5 +1,6 @@ package org.jboss.bacon.experimental.impl.config; +import java.nio.file.Path; import java.util.List; import java.util.Set; @@ -67,4 +68,9 @@ public class DependencyResolutionConfig { * suffix). This is useful to make sure whole dependency tree is build correctly. */ private boolean rebuildNonAutoBuilds = false; + + /** + * Path to the maven settings.xml file to use instead of the system one. + */ + private Path mavenSettings; } diff --git a/experimental/src/main/java/org/jboss/bacon/experimental/impl/dependencies/DependencyResolver.java b/experimental/src/main/java/org/jboss/bacon/experimental/impl/dependencies/DependencyResolver.java index 3f9744cfc..735026808 100644 --- a/experimental/src/main/java/org/jboss/bacon/experimental/impl/dependencies/DependencyResolver.java +++ b/experimental/src/main/java/org/jboss/bacon/experimental/impl/dependencies/DependencyResolver.java @@ -31,6 +31,8 @@ import io.quarkus.bom.decomposer.ReleaseId; import io.quarkus.bom.decomposer.ReleaseOrigin; import io.quarkus.bom.decomposer.ReleaseVersion; +import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext; +import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContextConfig; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import io.quarkus.devtools.messagewriter.MessageWriter; @@ -91,6 +93,16 @@ private void setupConfig(ProjectDependencyConfig.Mutable dominoConfig) { } public DependencyResult resolve(Path projectDir, Path dominoConfigFile) { + ProjectDependencyResolver resolver = configureResolver(projectDir, dominoConfigFile); + + PrintStream origOut = System.out; + System.setOut(new PrintStream(new LogOutputStream())); + ReleaseCollection releaseCollection = resolver.getReleaseCollection(); + System.setOut(origOut); + return parseReleaseCollection(releaseCollection); + } + + private ProjectDependencyResolver configureResolver(Path projectDir, Path dominoConfigFile) { ProjectDependencyConfig.Mutable dominoConfig; if (dominoConfigFile == null) { dominoConfig = ProjectDependencyConfig.builder(); @@ -102,6 +114,9 @@ public DependencyResult resolve(Path projectDir, Path dominoConfigFile) { } } ProjectDependencyResolver.Builder resolverBuilder = ProjectDependencyResolver.builder(); + if (config.getMavenSettings() != null) { + resolverBuilder.setUserMavenSettings(config.getMavenSettings()); + } if (projectDir != null) { dominoConfig.setProjectDir(projectDir); resolverBuilder.setArtifactResolver(getArtifactResolver(projectDir)); @@ -109,14 +124,9 @@ public DependencyResult resolve(Path projectDir, Path dominoConfigFile) { setupConfig(dominoConfig); ProjectDependencyConfig conf = dominoConfig.build(); logDominoConfig(conf); - ProjectDependencyResolver resolver = resolverBuilder.setMessageWriter(new Slf4jMessageWriter()) + return resolverBuilder.setMessageWriter(new Slf4jMessageWriter()) .setDependencyConfig(conf) .build(); - PrintStream origOut = System.out; - System.setOut(new PrintStream(new LogOutputStream())); - ReleaseCollection releaseCollection = resolver.getReleaseCollection(); - System.setOut(origOut); - return parseReleaseCollection(releaseCollection); } private void logDominoConfig(ProjectDependencyConfig conf) { @@ -132,11 +142,14 @@ private void logDominoConfig(ProjectDependencyConfig conf) { protected MavenArtifactResolver getArtifactResolver(Path projectDir) { try { - return MavenArtifactResolver.builder() + MavenArtifactResolver.Builder builder = MavenArtifactResolver.builder() .setCurrentProject(projectDir.toAbsolutePath().toString()) .setEffectiveModelBuilder(true) - .setPreferPomsFromWorkspace(true) - .build(); + .setPreferPomsFromWorkspace(true); + if (config.getMavenSettings() != null) { + builder.setUserSettings(config.getMavenSettings().toFile()); + } + return builder.build(); } catch (BootstrapMavenException e) { throw new RuntimeException("Failed to initialize Maven artifact resolver", e); } diff --git a/pom.xml b/pom.xml index b02242dca..f337a7464 100644 --- a/pom.xml +++ b/pom.xml @@ -80,7 +80,7 @@ 2.12.0 2.19.0 3.12.1 - 0.0.120 + 0.0.121 3.5.0 2.3.1 1.1.4 From 54809a2048c9cdc5de763493ade0971923226812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Honza=20Br=C3=A1zdil?= Date: Thu, 5 Jun 2025 11:27:43 +0200 Subject: [PATCH 2/3] [AB]: migrate from deprecated domino API --- .../impl/dependencies/DependencyResolver.java | 48 ++++++++----------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/experimental/src/main/java/org/jboss/bacon/experimental/impl/dependencies/DependencyResolver.java b/experimental/src/main/java/org/jboss/bacon/experimental/impl/dependencies/DependencyResolver.java index 735026808..be66376b3 100644 --- a/experimental/src/main/java/org/jboss/bacon/experimental/impl/dependencies/DependencyResolver.java +++ b/experimental/src/main/java/org/jboss/bacon/experimental/impl/dependencies/DependencyResolver.java @@ -28,11 +28,6 @@ import org.jboss.pnc.common.version.SuffixedVersion; import org.jboss.pnc.common.version.VersionParser; -import io.quarkus.bom.decomposer.ReleaseId; -import io.quarkus.bom.decomposer.ReleaseOrigin; -import io.quarkus.bom.decomposer.ReleaseVersion; -import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext; -import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContextConfig; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import io.quarkus.devtools.messagewriter.MessageWriter; @@ -42,6 +37,8 @@ import io.quarkus.domino.ProjectDependencyResolver; import io.quarkus.domino.ReleaseCollection; import io.quarkus.domino.ReleaseRepo; +import io.quarkus.domino.scm.ScmRepository; +import io.quarkus.domino.scm.ScmRevision; import io.quarkus.maven.dependency.ArtifactCoords; import lombok.extern.slf4j.Slf4j; @@ -88,7 +85,6 @@ private void setupConfig(ProjectDependencyConfig.Mutable dominoConfig) { .setWarnOnMissingScm(true) .setRecipeRepos(config.getRecipeRepos()) .setProjectArtifacts(artifacts) - .setValidateCodeRepoTags(false) // TODO .setIncludeAlreadyBuilt(true); // TODO } @@ -175,15 +171,15 @@ private DependencyResult parseReleaseCollection(ReleaseCollection releaseCollect return result; } - private void setupDependencies(Map mapping, Map> depsToCut) { + private void setupDependencies(Map mapping, Map> depsToCut) { for (var entry : mapping.entrySet()) { ReleaseRepo repo = entry.getKey(); Project project = entry.getValue(); - Set toCut = depsToCut.getOrDefault(repo.id(), Collections.emptySet()); + Set toCut = depsToCut.getOrDefault(repo.getRevision(), Collections.emptySet()); project.setDependencies( repo.getDependencies() .stream() - .filter(d -> !toCut.contains(d.id())) + .filter(d -> !toCut.contains(d.getRevision())) .map(mapping::get) .filter(this::filterProductized) .collect(Collectors.toSet())); @@ -248,9 +244,9 @@ private boolean filterProductized(Project releaseRepo) { return true; } - private Map> processCircularDependencies( + private Map> processCircularDependencies( Collection circularDependencies) { - Map> depsToCut = new HashMap<>(); + Map> depsToCut = new HashMap<>(); if (!circularDependencies.isEmpty()) { log.error( "Detected circular dependencies. This may be caused by incorrect SCM information, " @@ -258,17 +254,17 @@ private Map> processCircularDependencies( + "but this will lead to broken build config."); for (CircularReleaseDependency circularDependency : circularDependencies) { log.error("Detected loop: " + circularDependency); - List releaseDependencyChain = circularDependency.getReleaseDependencyChain(); - ReleaseId child = releaseDependencyChain.get(releaseDependencyChain.size() - 1); - ReleaseId parent = releaseDependencyChain.get(releaseDependencyChain.size() - 2); - Set releaseIds = depsToCut.computeIfAbsent(parent, k -> new HashSet<>()); + List releaseDependencyChain = circularDependency.getDependencyChain(); + ScmRevision child = releaseDependencyChain.get(releaseDependencyChain.size() - 1); + ScmRevision parent = releaseDependencyChain.get(releaseDependencyChain.size() - 2); + Set releaseIds = depsToCut.computeIfAbsent(parent, k -> new HashSet<>()); releaseIds.add(child); } } return depsToCut; } - private Project mapToProject(ReleaseRepo repo, Map> depsToCut) { + private Project mapToProject(ReleaseRepo repo, Map> depsToCut) { Project project = new Project(); Set gavs = repo.getArtifacts() .keySet() @@ -276,9 +272,9 @@ private Project mapToProject(ReleaseRepo repo, Map> de .map(a -> new GAV(a.getGroupId(), a.getArtifactId(), a.getVersion())) .collect(Collectors.toSet()); project.setGavs(gavs); - project.setSourceCodeURL(getSourceCodeURL(repo.id())); - project.setSourceCodeRevision(getSourceCodeRevision(repo.id())); - if (depsToCut.containsKey(repo.id())) { + project.setSourceCodeURL(getSourceCodeURL(repo.getRevision())); + project.setSourceCodeRevision(getSourceCodeRevision(repo.getRevision())); + if (depsToCut.containsKey(repo.getRevision())) { GAV firstGAV = project.getFirstGAV(); log.warn("Project " + firstGAV + " has cut some dependency(ies)."); project.setCutDependency(true); @@ -301,20 +297,16 @@ private void setDepth(Project project, int depth) { } } - private String getSourceCodeURL(ReleaseId releaseId) { - ReleaseOrigin origin = releaseId.origin(); // TODO: this API will probably change + private String getSourceCodeURL(ScmRevision releaseId) { + ScmRepository origin = releaseId.getRepository(); if (origin.isUrl()) { - return origin.toString(); + return origin.getUrl(); } return null; } - private String getSourceCodeRevision(ReleaseId releaseId) { - ReleaseVersion version = releaseId.version(); // TODO: this API will probably change - if (version.isTag()) { - return version.asString(); - } - return null; + private String getSourceCodeRevision(ScmRevision releaseId) { + return releaseId.getValue(); } private static class Slf4jMessageWriter implements MessageWriter { From 9c975e60c9431437e1e56a2f34bdfc2a5810d8a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Honza=20Br=C3=A1zdil?= Date: Thu, 12 Jun 2025 18:35:57 +0200 Subject: [PATCH 3/3] [AB]: Refactoring and javadocs --- .../experimental/DependencyGenerator.java | 2 +- .../impl/dependencies/DependencyResolver.java | 21 +++++++++++++---- .../impl/generator/BuildConfigGenerator.java | 12 ++++++++-- .../impl/generator/ProjectNameGenerator.java | 3 +++ .../impl/projectfinder/ProjectFinder.java | 23 +++++-------------- .../impl/projectfinder/ProjectFinderTest.java | 4 +--- 6 files changed, 37 insertions(+), 28 deletions(-) diff --git a/experimental/src/main/java/org/jboss/bacon/experimental/DependencyGenerator.java b/experimental/src/main/java/org/jboss/bacon/experimental/DependencyGenerator.java index 2d58fd95c..6bf9ea5f4 100644 --- a/experimental/src/main/java/org/jboss/bacon/experimental/DependencyGenerator.java +++ b/experimental/src/main/java/org/jboss/bacon/experimental/DependencyGenerator.java @@ -104,7 +104,7 @@ private PigConfiguration generatePigConfig() { // Initialize working classes DependencyResolver dependencyResolver = new DependencyResolver(config.getDependencyResolutionConfig()); ProjectNameGenerator projectNameGenerator = new ProjectNameGenerator(); - ProjectFinder projectFinder = new ProjectFinder(config.getBuildConfigGeneratorConfig()); + ProjectFinder projectFinder = new ProjectFinder(); BuildConfigGenerator buildConfigGenerator = new BuildConfigGenerator( config.getBuildConfigGeneratorConfig()); // Analyze dependencies diff --git a/experimental/src/main/java/org/jboss/bacon/experimental/impl/dependencies/DependencyResolver.java b/experimental/src/main/java/org/jboss/bacon/experimental/impl/dependencies/DependencyResolver.java index be66376b3..93a37cf23 100644 --- a/experimental/src/main/java/org/jboss/bacon/experimental/impl/dependencies/DependencyResolver.java +++ b/experimental/src/main/java/org/jboss/bacon/experimental/impl/dependencies/DependencyResolver.java @@ -57,6 +57,19 @@ public DependencyResolver(DependencyResolutionConfig dependencyResolutionConfig) lookupApi = DaHelper.createLookupApi(); } + /** + * Resolve the dependencies for project specified in the autobuilder config or by the projectDir property. + * + * @param projectDir Optional path to the directory with the project to analyze. + * @param dominoConfigFile Optional path to domino config file. + * @return The dependency tree(s) of the analyzed project. + */ + public DependencyResult resolve(Path projectDir, Path dominoConfigFile) { + ProjectDependencyResolver resolver = configureResolver(projectDir, dominoConfigFile); + ReleaseCollection releaseCollection = resolveDependencies(resolver); + return parseReleaseCollection(releaseCollection); + } + private void setupConfig(ProjectDependencyConfig.Mutable dominoConfig) { config.getExcludeArtifacts().stream().map(GACTVParser::parse).forEach(dominoConfig::addExcludePattern); AutobuildConfig autobuildConfig = Objects.requireNonNull( @@ -88,14 +101,12 @@ private void setupConfig(ProjectDependencyConfig.Mutable dominoConfig) { .setIncludeAlreadyBuilt(true); // TODO } - public DependencyResult resolve(Path projectDir, Path dominoConfigFile) { - ProjectDependencyResolver resolver = configureResolver(projectDir, dominoConfigFile); - - PrintStream origOut = System.out; + private static ReleaseCollection resolveDependencies(ProjectDependencyResolver resolver) { + PrintStream origOut = System.out; // workaround System.out usage by libraries and redirect it to logger System.setOut(new PrintStream(new LogOutputStream())); ReleaseCollection releaseCollection = resolver.getReleaseCollection(); System.setOut(origOut); - return parseReleaseCollection(releaseCollection); + return releaseCollection; } private ProjectDependencyResolver configureResolver(Path projectDir, Path dominoConfigFile) { diff --git a/experimental/src/main/java/org/jboss/bacon/experimental/impl/generator/BuildConfigGenerator.java b/experimental/src/main/java/org/jboss/bacon/experimental/impl/generator/BuildConfigGenerator.java index c857bf269..8886ee16f 100644 --- a/experimental/src/main/java/org/jboss/bacon/experimental/impl/generator/BuildConfigGenerator.java +++ b/experimental/src/main/java/org/jboss/bacon/experimental/impl/generator/BuildConfigGenerator.java @@ -39,6 +39,14 @@ public BuildConfigGenerator(BuildConfigGeneratorConfig buildConfigGeneratorConfi environments = new EnvironmentResolver(buildConfigGeneratorConfig); } + /** + * Generates build configs for each of the projects in the dependency tree. + *

+ * If the config for a project already exists and has name with -AUTOBUILD suffix, it's reused.
+ * If the config for a project already exists without the suffix or for a different project version, it's copied and + * updated.
+ * If the config does not exist yet, a dummy config is generated. + */ public List generateConfigs(DependencyResult dependencies, FoundProjects foundProjects) { Map buildConfigMap = new TreeMap<>(new ProjectDepthComparator()); for (Project project : dependencies.getTopLevelProjects()) { @@ -48,7 +56,7 @@ public List generateConfigs(DependencyResult dependencies, FoundPro log.info( "Some Build Configs might have been generated or modified. Autobuilder appended command `false` to " + "build scripts of such Build Configs and a human should review the Build Configs before " - + "removig the command `false`. The generated build-config.yaml can still be run in PNC " + + "removing the command `false`. The generated build-config.yaml can still be run in PNC " + "even with the command `false` present, as it will provide you with information about " + "alignment and the build run."); } else { @@ -77,7 +85,7 @@ private BuildConfig generateConfig( return buildConfig; } - public BuildConfig processProject(Project project, FoundProject found) { + private BuildConfig processProject(Project project, FoundProject found) { String name = project.getName(); // Strategy if (found.isManaged()) { diff --git a/experimental/src/main/java/org/jboss/bacon/experimental/impl/generator/ProjectNameGenerator.java b/experimental/src/main/java/org/jboss/bacon/experimental/impl/generator/ProjectNameGenerator.java index b4324f7ee..400b06f77 100644 --- a/experimental/src/main/java/org/jboss/bacon/experimental/impl/generator/ProjectNameGenerator.java +++ b/experimental/src/main/java/org/jboss/bacon/experimental/impl/generator/ProjectNameGenerator.java @@ -37,6 +37,9 @@ public class ProjectNameGenerator { private Set allProjects; private Map> projectsByGA; + /** + * Generates names from the project artifacts to be used as the Build Configs' names. + */ public void nameProjects(Set projects) { allProjects = new HashSet<>(); projectsByGA = new HashMap<>(); diff --git a/experimental/src/main/java/org/jboss/bacon/experimental/impl/projectfinder/ProjectFinder.java b/experimental/src/main/java/org/jboss/bacon/experimental/impl/projectfinder/ProjectFinder.java index d914508f9..54c61f7c1 100644 --- a/experimental/src/main/java/org/jboss/bacon/experimental/impl/projectfinder/ProjectFinder.java +++ b/experimental/src/main/java/org/jboss/bacon/experimental/impl/projectfinder/ProjectFinder.java @@ -48,29 +48,18 @@ public class ProjectFinder { private final BuildClient buildClient; private final BuildConfigurationClient buildConfigClient; private final VersionParser versionParser = new VersionParser("redhat", "temporary-redhat"); - private final BuildConfigGeneratorConfig config; - public ProjectFinder(BuildConfigGeneratorConfig config) { - this.config = config; + public ProjectFinder() { lookupApi = DaHelper.createLookupApi(); artifactClient = new ClientCreator<>(ArtifactClient::new).newClient(); buildClient = new ClientCreator<>(BuildClient::new).newClient(); buildConfigClient = new ClientCreator<>(BuildConfigurationClient::new).newClient(); } - ProjectFinder( - BuildConfigGeneratorConfig config, - LookupApi lookupApi, - ArtifactClient artifactClient, - BuildClient buildClient, - BuildConfigurationClient buildConfigClient) { - this.config = config; - this.lookupApi = lookupApi; - this.artifactClient = artifactClient; - this.buildClient = buildClient; - this.buildConfigClient = buildConfigClient; - } - + /** + * Tries to find existing Build Configs for each of the projects. It tries to find Build Config that built the + * closest version of the project to version we are interested in. + */ public FoundProjects findProjects(DependencyResult dependencies) { Set projects = new HashSet<>(); traverseTree(projects, dependencies.getTopLevelProjects()); @@ -281,7 +270,7 @@ private static class BuildVersion { * Compares Build Config Revisions by modification time. If the modification times are the same or some is null, it * compares the Revisions by revision (rev) number. */ - private class BuildConfigRevisionAgeComparator implements Comparator { + private static class BuildConfigRevisionAgeComparator implements Comparator { @Override public int compare(BuildConfigurationRevision one, BuildConfigurationRevision two) { diff --git a/experimental/src/test/java/org/jboss/bacon/experimental/impl/projectfinder/ProjectFinderTest.java b/experimental/src/test/java/org/jboss/bacon/experimental/impl/projectfinder/ProjectFinderTest.java index 22b91bd97..87c209bf5 100644 --- a/experimental/src/test/java/org/jboss/bacon/experimental/impl/projectfinder/ProjectFinderTest.java +++ b/experimental/src/test/java/org/jboss/bacon/experimental/impl/projectfinder/ProjectFinderTest.java @@ -41,7 +41,6 @@ public class ProjectFinderTest { private static WireMockServer mockServer; - private BuildConfigGeneratorConfig config; private ProjectFinder finder; public static final Path CONFIG_LOCATION = Paths.get("target", "test-config"); @@ -52,8 +51,7 @@ public static void initBaconConfig() { @BeforeEach public void initProjectFinder() { - config = new BuildConfigGeneratorConfig(); - finder = new ProjectFinder(config); + finder = new ProjectFinder(); } @Test