Skip to content
Draft

Docs #1401

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.jboss.bacon.experimental.impl.config;

import java.nio.file.Path;
import java.util.List;
import java.util.Set;

Expand Down Expand Up @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +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.BootstrapMavenException;
import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver;
import io.quarkus.devtools.messagewriter.MessageWriter;
Expand All @@ -40,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;

Expand All @@ -58,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(
Expand Down Expand Up @@ -86,11 +98,18 @@ private void setupConfig(ProjectDependencyConfig.Mutable dominoConfig) {
.setWarnOnMissingScm(true)
.setRecipeRepos(config.getRecipeRepos())
.setProjectArtifacts(artifacts)
.setValidateCodeRepoTags(false) // TODO
.setIncludeAlreadyBuilt(true); // TODO
}

public DependencyResult resolve(Path projectDir, Path dominoConfigFile) {
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 releaseCollection;
}

private ProjectDependencyResolver configureResolver(Path projectDir, Path dominoConfigFile) {
ProjectDependencyConfig.Mutable dominoConfig;
if (dominoConfigFile == null) {
dominoConfig = ProjectDependencyConfig.builder();
Expand All @@ -102,21 +121,19 @@ 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));
}
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) {
Expand All @@ -132,11 +149,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);
}
Expand All @@ -162,15 +182,15 @@ private DependencyResult parseReleaseCollection(ReleaseCollection releaseCollect
return result;
}

private void setupDependencies(Map<ReleaseRepo, Project> mapping, Map<ReleaseId, Set<ReleaseId>> depsToCut) {
private void setupDependencies(Map<ReleaseRepo, Project> mapping, Map<ScmRevision, Set<ScmRevision>> depsToCut) {
for (var entry : mapping.entrySet()) {
ReleaseRepo repo = entry.getKey();
Project project = entry.getValue();
Set<ReleaseId> toCut = depsToCut.getOrDefault(repo.id(), Collections.emptySet());
Set<ScmRevision> 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()));
Expand Down Expand Up @@ -235,37 +255,37 @@ private boolean filterProductized(Project releaseRepo) {
return true;
}

private Map<ReleaseId, Set<ReleaseId>> processCircularDependencies(
private Map<ScmRevision, Set<ScmRevision>> processCircularDependencies(
Collection<CircularReleaseDependency> circularDependencies) {
Map<ReleaseId, Set<ReleaseId>> depsToCut = new HashMap<>();
Map<ScmRevision, Set<ScmRevision>> depsToCut = new HashMap<>();
if (!circularDependencies.isEmpty()) {
log.error(
"Detected circular dependencies. This may be caused by incorrect SCM information, "
+ "consider updating the recipe repository. We are cutting the dependency loop now, "
+ "but this will lead to broken build config.");
for (CircularReleaseDependency circularDependency : circularDependencies) {
log.error("Detected loop: " + circularDependency);
List<ReleaseId> releaseDependencyChain = circularDependency.getReleaseDependencyChain();
ReleaseId child = releaseDependencyChain.get(releaseDependencyChain.size() - 1);
ReleaseId parent = releaseDependencyChain.get(releaseDependencyChain.size() - 2);
Set<ReleaseId> releaseIds = depsToCut.computeIfAbsent(parent, k -> new HashSet<>());
List<ScmRevision> releaseDependencyChain = circularDependency.getDependencyChain();
ScmRevision child = releaseDependencyChain.get(releaseDependencyChain.size() - 1);
ScmRevision parent = releaseDependencyChain.get(releaseDependencyChain.size() - 2);
Set<ScmRevision> releaseIds = depsToCut.computeIfAbsent(parent, k -> new HashSet<>());
releaseIds.add(child);
}
}
return depsToCut;
}

private Project mapToProject(ReleaseRepo repo, Map<ReleaseId, Set<ReleaseId>> depsToCut) {
private Project mapToProject(ReleaseRepo repo, Map<ScmRevision, Set<ScmRevision>> depsToCut) {
Project project = new Project();
Set<GAV> gavs = repo.getArtifacts()
.keySet()
.stream()
.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);
Expand All @@ -288,20 +308,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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ public BuildConfigGenerator(BuildConfigGeneratorConfig buildConfigGeneratorConfi
environments = new EnvironmentResolver(buildConfigGeneratorConfig);
}

/**
* Generates build configs for each of the projects in the dependency tree.
* <p>
* If the config for a project already exists and has name with -AUTOBUILD suffix, it's reused.<br>
* If the config for a project already exists without the suffix or for a different project version, it's copied and
* updated.<br>
* If the config does not exist yet, a dummy config is generated.
*/
public List<BuildConfig> generateConfigs(DependencyResult dependencies, FoundProjects foundProjects) {
Map<Project, BuildConfig> buildConfigMap = new TreeMap<>(new ProjectDepthComparator());
for (Project project : dependencies.getTopLevelProjects()) {
Expand All @@ -48,7 +56,7 @@ public List<BuildConfig> 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 {
Expand Down Expand Up @@ -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()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ public class ProjectNameGenerator {
private Set<Project> allProjects;
private Map<GA, Set<Project>> projectsByGA;

/**
* Generates names from the project artifacts to be used as the Build Configs' names.
*/
public void nameProjects(Set<Project> projects) {
allProjects = new HashSet<>();
projectsByGA = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Project> projects = new HashSet<>();
traverseTree(projects, dependencies.getTopLevelProjects());
Expand Down Expand Up @@ -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<BuildConfigurationRevision> {
private static class BuildConfigRevisionAgeComparator implements Comparator<BuildConfigurationRevision> {

@Override
public int compare(BuildConfigurationRevision one, BuildConfigurationRevision two) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand All @@ -52,8 +51,7 @@ public static void initBaconConfig() {

@BeforeEach
public void initProjectFinder() {
config = new BuildConfigGeneratorConfig();
finder = new ProjectFinder(config);
finder = new ProjectFinder();
}

@Test
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
<commons-configuration2.version>2.12.0</commons-configuration2.version>
<commons-io.version>2.19.0</commons-io.version>
<compiler.plugin.version>3.12.1</compiler.plugin.version>
<domino.version>0.0.120</domino.version>
<domino.version>0.0.121</domino.version>
<enforcer.plugin.version>3.5.0</enforcer.plugin.version>
<glassfish-jaxb.version>2.3.1</glassfish-jaxb.version>
<glassfish-json.version>1.1.4</glassfish-json.version>
Expand Down