Skip to content

Commit

Permalink
Fixes CycloneDX#284, Switch to aether and filter artifacts based on i…
Browse files Browse the repository at this point in the history
…ndividual scopes

Signed-off-by: Kevin Conner <[email protected]>
  • Loading branch information
knrc committed Mar 1, 2023
1 parent 7498d2e commit 2bddc70
Show file tree
Hide file tree
Showing 24 changed files with 1,106 additions and 273 deletions.
284 changes: 103 additions & 181 deletions src/main/java/org/cyclonedx/maven/BaseCycloneDxMojo.java

Large diffs are not rendered by default.

132 changes: 132 additions & 0 deletions src/main/java/org/cyclonedx/maven/CycloneDxRepositorySystem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package org.cyclonedx.maven;

import java.util.Collection;
import java.util.List;

import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.SyncContext;
import org.eclipse.aether.collection.CollectRequest;
import org.eclipse.aether.collection.CollectResult;
import org.eclipse.aether.collection.DependencyCollectionException;
import org.eclipse.aether.deployment.DeployRequest;
import org.eclipse.aether.deployment.DeployResult;
import org.eclipse.aether.deployment.DeploymentException;
import org.eclipse.aether.installation.InstallRequest;
import org.eclipse.aether.installation.InstallResult;
import org.eclipse.aether.installation.InstallationException;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.LocalRepositoryManager;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.resolution.ArtifactDescriptorException;
import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
import org.eclipse.aether.resolution.ArtifactDescriptorResult;
import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.ArtifactResolutionException;
import org.eclipse.aether.resolution.ArtifactResult;
import org.eclipse.aether.resolution.DependencyRequest;
import org.eclipse.aether.resolution.DependencyResolutionException;
import org.eclipse.aether.resolution.DependencyResult;
import org.eclipse.aether.resolution.MetadataRequest;
import org.eclipse.aether.resolution.MetadataResult;
import org.eclipse.aether.resolution.VersionRangeRequest;
import org.eclipse.aether.resolution.VersionRangeResolutionException;
import org.eclipse.aether.resolution.VersionRangeResult;
import org.eclipse.aether.resolution.VersionRequest;
import org.eclipse.aether.resolution.VersionResolutionException;
import org.eclipse.aether.resolution.VersionResult;

class CycloneDxRepositorySystem implements RepositorySystem {
private final RepositorySystem repositorySystem;
private CollectResult collectResult;
public CycloneDxRepositorySystem(final RepositorySystem repositorySystem) {
this.repositorySystem = repositorySystem;
}

public CollectResult getCollectResult() {
return collectResult;
}

@Override
public CollectResult collectDependencies(final RepositorySystemSession session, final CollectRequest request)
throws DependencyCollectionException {
collectResult = repositorySystem.collectDependencies(session, request);
return collectResult;
}

@Override
public DeployResult deploy(final RepositorySystemSession session, final DeployRequest request)
throws DeploymentException {
return repositorySystem.deploy(session, request);
}

@Override
public InstallResult install(final RepositorySystemSession session, final InstallRequest request)
throws InstallationException {
return repositorySystem.install(session, request);
}

@Override
public RemoteRepository newDeploymentRepository(final RepositorySystemSession session, final RemoteRepository repository) {
return repositorySystem.newDeploymentRepository(session, repository);
}

@Override
public LocalRepositoryManager newLocalRepositoryManager(final RepositorySystemSession session,
final LocalRepository localRepository) {
return repositorySystem.newLocalRepositoryManager(session, localRepository);
}

@Override
public List<RemoteRepository> newResolutionRepositories(final RepositorySystemSession session,
final List<RemoteRepository> repositories) {
return repositorySystem.newResolutionRepositories(session, repositories);
}

@Override
public SyncContext newSyncContext(final RepositorySystemSession session, final boolean shared) {
return repositorySystem.newSyncContext(session, shared);
}

@Override
public ArtifactDescriptorResult readArtifactDescriptor(final RepositorySystemSession session,
final ArtifactDescriptorRequest request) throws ArtifactDescriptorException {
return repositorySystem.readArtifactDescriptor(null, request);
}

@Override
public ArtifactResult resolveArtifact(final RepositorySystemSession session, final ArtifactRequest request)
throws ArtifactResolutionException {
return repositorySystem.resolveArtifact(session, request);
}

@Override
public List<ArtifactResult> resolveArtifacts(final RepositorySystemSession session,
final Collection<? extends ArtifactRequest> requests) throws ArtifactResolutionException {
return repositorySystem.resolveArtifacts(session, requests);
}

@Override
public DependencyResult resolveDependencies(final RepositorySystemSession session, final DependencyRequest request)
throws DependencyResolutionException {
return repositorySystem.resolveDependencies(session, request);
}

@Override
public List<MetadataResult> resolveMetadata(final RepositorySystemSession session,
final Collection<? extends MetadataRequest> requests) {
return repositorySystem.resolveMetadata(session, requests);
}

@Override
public VersionResult resolveVersion(final RepositorySystemSession session, final VersionRequest request)
throws VersionResolutionException {
return repositorySystem.resolveVersion(session, request);
}

@Override
public VersionRangeResult resolveVersionRange(final RepositorySystemSession session, final VersionRangeRequest request)
throws VersionRangeResolutionException {
return repositorySystem.resolveVersionRange(session, request);
}
}
29 changes: 29 additions & 0 deletions src/main/java/org/cyclonedx/maven/DefaultModelConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import org.cyclonedx.model.Tool;
import org.cyclonedx.util.BomUtils;
import org.cyclonedx.util.LicenseResolver;
import org.eclipse.aether.artifact.ArtifactProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -103,6 +104,34 @@ private String generatePackageUrl(final Artifact artifact, final boolean include
return generatePackageUrl(artifact.getGroupId(), artifact.getArtifactId(), version, qualifiers, null);
}

public String generatePackageUrl(final org.eclipse.aether.artifact.Artifact artifact) {
return generatePackageUrl(artifact, true);
}

public String generateVersionlessPackageUrl(final org.eclipse.aether.artifact.Artifact artifact) {
return generatePackageUrl(artifact, false);
}

private boolean isEmpty(final String value) {
return (value == null) || (value.length() == 0);
}
private String generatePackageUrl(final org.eclipse.aether.artifact.Artifact artifact, final boolean includeVersion) {
TreeMap<String, String> qualifiers = null;
final String type = artifact.getProperties().get(ArtifactProperties.TYPE);
final String classifier = artifact.getClassifier();
if (!isEmpty(type) || !isEmpty(classifier)) {
qualifiers = new TreeMap<>();
if (!isEmpty(type)) {
qualifiers.put("type", type);
}
if (!isEmpty(classifier)) {
qualifiers.put("classifier", classifier);
}
}
final String version = includeVersion ? artifact.getBaseVersion() : null;
return generatePackageUrl(artifact.getGroupId(), artifact.getArtifactId(), version, qualifiers, null);
}

private String generatePackageUrl(String groupId, String artifactId, String version, TreeMap<String, String> qualifiers, String subpath) {
try {
return new PackageURL(PackageURL.StandardTypes.MAVEN, groupId, artifactId, version, qualifiers, subpath).canonicalize();
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/cyclonedx/maven/ModelConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ public interface ModelConverter {

String generateVersionlessPackageUrl(final Artifact artifact);

String generatePackageUrl(final org.eclipse.aether.artifact.Artifact artifact);

String generateVersionlessPackageUrl(final org.eclipse.aether.artifact.Artifact artifact);

/**
* Converts a Maven artifact (dependency or transitive dependency) into a
* CycloneDX component.
Expand Down
20 changes: 20 additions & 0 deletions src/test/java/org/cyclonedx/maven/BaseMavenVerifier.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.cyclonedx.maven;

import io.takari.maven.testing.TestResources;
import io.takari.maven.testing.executor.MavenExecution;
import io.takari.maven.testing.executor.MavenRuntime;
import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder;

Expand Down Expand Up @@ -48,4 +49,23 @@ protected static String fileRead(File file, boolean normalizeEOL) throws IOExcep
}
return sb.toString();
}

protected File cleanAndBuild(final String project, final String[] excludeTypes) throws Exception {
File projDir = resources.getBasedir(project);

final MavenExecution initExecution = verifier
.forProject(projDir)
.withCliOption("-Dcurrent.version=" + getCurrentVersion()) // inject cyclonedx-maven-plugin version
.withCliOption("-X") // debug
.withCliOption("-B");
final MavenExecution execution;
if ((excludeTypes != null) && (excludeTypes.length > 0)) {
execution = initExecution.withCliOption("-DexcludeTypes=" + String.join(",", excludeTypes));
} else {
execution = initExecution;
}
execution.execute("clean", "package")
.assertErrorFreeLog();
return projDir;
}
}
100 changes: 8 additions & 92 deletions src/test/java/org/cyclonedx/maven/BomDependenciesTest.java
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
package org.cyclonedx.maven;

import static org.cyclonedx.maven.TestUtils.getComponentNode;
import static org.cyclonedx.maven.TestUtils.getComponentReferences;
import static org.cyclonedx.maven.TestUtils.getDependencyNode;
import static org.cyclonedx.maven.TestUtils.getDependencyReferences;
import static org.cyclonedx.maven.TestUtils.readXML;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import io.takari.maven.testing.executor.MavenExecution;
import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder;
import io.takari.maven.testing.executor.MavenVersions;
import io.takari.maven.testing.executor.junit.MavenJUnitTestRunner;
Expand Down Expand Up @@ -57,7 +55,7 @@ public BomDependenciesTest(MavenRuntimeBuilder runtimeBuilder) throws Exception

@Test
public void testBomDependencies() throws Exception {
final File projDir = cleanAndBuild(null);
final File projDir = cleanAndBuild("bom-dependencies", null);
checkHiddenTestArtifacts(projDir);
checkHiddenRuntimeArtifacts(projDir);
checkExtraneousComponents(projDir);
Expand Down Expand Up @@ -221,7 +219,7 @@ private void checkTopLevelTestComponentsAsCompile(final File projDir) throws Exc
*/
@Test
public void testTypeExcludes() throws Exception {
final File projDir = cleanAndBuild(new String[]{"test-jar"});
final File projDir = cleanAndBuild("bom-dependencies", new String[]{"test-jar"});

final Document bom = readXML(new File(projDir, "trustification/target/bom.xml"));

Expand Down Expand Up @@ -323,86 +321,4 @@ private void testHiddenVersionedTransitiveDependencies(final File projDir) throw
assertEquals("Invalid dependency count for versioned_dependency", 1, versionedDependencyDependencies.size());
assertTrue("Missing dependency1 dependency for versioned_dependency", versionedDependencyDependencies.contains(DEPENDENCY1));
}

private File cleanAndBuild(final String[] excludeTypes) throws Exception {
File projDir = resources.getBasedir("bom-dependencies");

final MavenExecution initExecution = verifier
.forProject(projDir)
.withCliOption("-Dcurrent.version=" + getCurrentVersion()) // inject cyclonedx-maven-plugin version
.withCliOption("-X") // debug
.withCliOption("-B");
final MavenExecution execution;
if ((excludeTypes != null) && (excludeTypes.length > 0)) {
execution = initExecution.withCliOption("-DexcludeTypes=" + String.join(",", excludeTypes));
} else {
execution = initExecution;
}
execution.execute("clean", "package")
.assertErrorFreeLog();
return projDir;
}

private static Node getDependencyNode(final Node dependencies, final String ref) {
return getChildElement(dependencies, ref, "dependency", "ref");
}

private static Node getComponentNode(final Node components, final String ref) {
return getChildElement(components, ref, "component", "bom-ref");
}

private static Node getChildElement(final Node parent, final String ref, final String elementName, final String attrName) {
final NodeList children = parent.getChildNodes();
final int numChildNodes = children.getLength();
for (int index = 0 ; index < numChildNodes ; index++) {
final Node child = children.item(index);
if ((child.getNodeType() == Node.ELEMENT_NODE) && elementName.equals(child.getNodeName())) {
final Node refNode = child.getAttributes().getNamedItem(attrName);
if (ref.equals(refNode.getNodeValue())) {
return child;
}
}
}
return null;
}

private static Set<String> getComponentReferences(final Node parent) {
return getReferences(null, parent, "component", "bom-ref");
}

private static Set<String> getDependencyReferences(final Node parent) {
return getReferences(null, parent, "dependency", "ref");
}

private static Set<String> getReferences(Set<String> references, final Node rootNode, final String elementName, final String attrName) {
if (references == null) {
references = new HashSet<>();
}
final NodeList children = rootNode.getChildNodes();
final int numChildNodes = children.getLength();
for (int index = 0 ; index < numChildNodes ; index++) {
final Node child = children.item(index);
if (child.getNodeType() == Node.ELEMENT_NODE) {
if (elementName.equals(child.getNodeName())) {
final Node refNode = child.getAttributes().getNamedItem(attrName);
if (refNode != null) {
references.add(refNode.getNodeValue());
}
}
getReferences(references, child, elementName, attrName);
}
}
return references;
}

private static Document readXML(File file) throws IOException, SAXException, ParserConfigurationException {
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

factory.setIgnoringComments(true);
factory.setIgnoringElementContentWhitespace(true);
factory.setValidating(false);

final DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(file);
}
}
Loading

0 comments on commit 2bddc70

Please sign in to comment.