Skip to content

Commit 3a17feb

Browse files
Added dependencyScope detection for maven components (#87)
* Added "DependencyScope" for scanned component. Currently detection is only active for maven components. * Added telemetry to keep track of each recorded component.
1 parent 63dcae6 commit 3a17feb

19 files changed

Lines changed: 352 additions & 27 deletions

File tree

Directory.Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,6 @@
4141
<PackageVersion Include="System.Runtime.Loader" Version="4.3.0"/>
4242
<PackageVersion Include="System.Threading.Tasks.Dataflow" Version="4.9.0"/>
4343
<PackageVersion Include="yamldotnet" Version="11.2.1"/>
44+
<PackageVersion Include="Faker.net" Version="2.0.154"/>
4445
</ItemGroup>
4546
</Project>

src/Microsoft.ComponentDetection.Common/DependencyGraph/ComponentRecorder.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Linq;
66
using System.Runtime.CompilerServices;
77
using Microsoft.ComponentDetection.Contracts;
8+
using Microsoft.ComponentDetection.Contracts.BcdeModels;
89
using Microsoft.ComponentDetection.Contracts.TypedComponent;
910

1011
[assembly: InternalsVisibleTo("Microsoft.ComponentDetection.Common.Tests")]
@@ -133,7 +134,8 @@ public void RegisterUsage(
133134
DetectedComponent detectedComponent,
134135
bool isExplicitReferencedDependency = false,
135136
string parentComponentId = null,
136-
bool? isDevelopmentDependency = null)
137+
bool? isDevelopmentDependency = null,
138+
DependencyScope? dependencyScope = null)
137139
{
138140
if (detectedComponent == null)
139141
{
@@ -167,7 +169,7 @@ public void RegisterUsage(
167169
lock (registerUsageLock)
168170
{
169171
storedComponent = detectedComponentsInternal.GetOrAdd(componentId, detectedComponent);
170-
AddComponentToGraph(ManifestFileLocation, detectedComponent, isExplicitReferencedDependency, parentComponentId, isDevelopmentDependency);
172+
AddComponentToGraph(ManifestFileLocation, detectedComponent, isExplicitReferencedDependency, parentComponentId, isDevelopmentDependency, dependencyScope);
171173
}
172174
}
173175

@@ -186,13 +188,20 @@ public IComponentRecorder GetParentComponentRecorder()
186188
return recorder;
187189
}
188190

189-
private void AddComponentToGraph(string location, DetectedComponent detectedComponent, bool isExplicitReferencedDependency, string parentComponentId, bool? isDevelopmentDependency)
191+
private void AddComponentToGraph(
192+
string location,
193+
DetectedComponent detectedComponent,
194+
bool isExplicitReferencedDependency,
195+
string parentComponentId,
196+
bool? isDevelopmentDependency,
197+
DependencyScope? dependencyScope)
190198
{
191199
var componentNode = new DependencyGraph.ComponentRefNode
192200
{
193201
Id = detectedComponent.Component.Id,
194202
IsExplicitReferencedDependency = isExplicitReferencedDependency,
195203
IsDevelopmentDependency = isDevelopmentDependency,
204+
DependencyScope = dependencyScope,
196205
};
197206

198207
DependencyGraph.AddComponent(componentNode, parentComponentId);

src/Microsoft.ComponentDetection.Common/DependencyGraph/DependencyGraph.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Linq;
66
using System.Runtime.CompilerServices;
77
using Microsoft.ComponentDetection.Contracts;
8+
using Microsoft.ComponentDetection.Contracts.BcdeModels;
89

910
[assembly: InternalsVisibleTo("Microsoft.ComponentDetection.Common.Tests")]
1011

@@ -46,6 +47,11 @@ public void AddComponent(ComponentRefNode componentNode, string parentComponentI
4647
currentNode.IsDevelopmentDependency = currentNode.IsDevelopmentDependency.GetValueOrDefault(true) && componentNode.IsDevelopmentDependency.Value;
4748
}
4849

50+
if (componentNode.DependencyScope.HasValue)
51+
{
52+
currentNode.DependencyScope = DependencyScopeComparer.GetMergedDependencyScope(currentNode.DependencyScope, componentNode.DependencyScope);
53+
}
54+
4955
return currentNode;
5056
});
5157

@@ -101,6 +107,11 @@ public bool HasComponents()
101107
return componentNodes[componentId].IsDevelopmentDependency;
102108
}
103109

110+
public DependencyScope? GetDependencyScope(string componentId)
111+
{
112+
return componentNodes[componentId].DependencyScope;
113+
}
114+
104115
public IEnumerable<string> GetAllExplicitlyReferencedComponents()
105116
{
106117
return componentNodes.Values
@@ -175,6 +186,8 @@ internal class ComponentRefNode
175186

176187
internal bool? IsDevelopmentDependency { get; set; }
177188

189+
internal DependencyScope? DependencyScope { get; set; }
190+
178191
internal ComponentRefNode()
179192
{
180193
DependencyIds = new HashSet<string>();
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using Microsoft.ComponentDetection.Contracts.BcdeModels;
5+
6+
namespace Microsoft.ComponentDetection.Common
7+
{
8+
/// <summary>
9+
/// Merges dependnecy Scope in their order of Priority.
10+
/// Higher priority scope, as indicated by its lower enum value is given precendence.
11+
/// </summary>
12+
public class DependencyScopeComparer
13+
{
14+
public static DependencyScope? GetMergedDependencyScope(DependencyScope? scope1, DependencyScope? scope2) {
15+
if (!scope1.HasValue)
16+
{
17+
return scope2;
18+
}
19+
else if (!scope2.HasValue)
20+
{
21+
return scope1;
22+
}
23+
24+
return (int)scope1 < (int)scope2 ? scope1 : scope2;
25+
}
26+
}
27+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.Runtime.CompilerServices;
2+
3+
namespace Microsoft.ComponentDetection.Common.Telemetry.Records
4+
{
5+
public class DetectedComponentScopeRecord : BaseDetectionTelemetryRecord
6+
{
7+
public override string RecordName => "ComponentScopeRecord";
8+
9+
public int? MavenProvidedScopeCount { get; set; } = 0;
10+
11+
[MethodImpl(MethodImplOptions.Synchronized)]
12+
public void IncrementProvidedScopeCount()
13+
{
14+
MavenProvidedScopeCount++;
15+
}
16+
}
17+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Microsoft.ComponentDetection.Contracts.BcdeModels
6+
{
7+
/// <summary>Used to communicate Dependency Scope of Component.
8+
/// Currently only populated for Maven component.
9+
/// The values are ordered in terms of priority, which is used to resolve the scope for duplicate component while merging them.
10+
/// </summary>
11+
public enum DependencyScope
12+
{
13+
/// <summary>default scope. dependencies are available in the project during all build tasks. propogated to dependent projects. </summary>
14+
MavenCompile = 0,
15+
16+
/// <summary> Required at Runtime, but not at compile time.</summary>
17+
MavenRuntime = 1,
18+
19+
/// <summary>Dependencies are available only at compile time and in the test classpath of the project. These dependencies are also not transitive.</summary>
20+
MavenProvided = 2,
21+
22+
/// <summary>Similar to provided scope. Requires explicit reference to Jar. </summary>
23+
MavenSystem = 3,
24+
25+
/// <summary>Used only at runtime.</summary>
26+
MavenTest = 4,
27+
}
28+
}

src/Microsoft.ComponentDetection.Contracts/BcdeModels/ScannedComponent.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Collections.Generic;
22
using Newtonsoft.Json;
3+
using Newtonsoft.Json.Converters;
34
using Newtonsoft.Json.Serialization;
45

56
namespace Microsoft.ComponentDetection.Contracts.BcdeModels
@@ -15,6 +16,9 @@ public class ScannedComponent
1516

1617
public bool? IsDevelopmentDependency { get; set; }
1718

19+
[JsonConverter(typeof(StringEnumConverter))]
20+
public DependencyScope? DependencyScope { get; set; }
21+
1822
public IEnumerable<TypedComponent.TypedComponent> TopLevelReferrers { get; set; }
1923

2024
public IEnumerable<int> ContainerDetailIds { get; set; }

src/Microsoft.ComponentDetection.Contracts/DetectedComponent.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Collections.Generic;
22
using System.Diagnostics;
3+
using Microsoft.ComponentDetection.Contracts.BcdeModels;
34

45
namespace Microsoft.ComponentDetection.Contracts
56
{
@@ -56,6 +57,9 @@ public DetectedComponent(TypedComponent.TypedComponent component, IComponentDete
5657

5758
/// <summary> Gets or sets the layer within a container where this component was found.</summary>
5859
public IDictionary<int, IEnumerable<int>> ContainerLayerIds { get; set; }
60+
61+
/// <summary> Gets or sets Dependency Scope of the component.</summary>
62+
public DependencyScope? DependencyScope { get; set; }
5963

6064
/// <summary>Adds a filepath to the FilePaths hashset for this detected component.</summary>
6165
/// <param name="filePath">The file path to add to the hashset.</param>

src/Microsoft.ComponentDetection.Contracts/IComponentRecorder.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Generic;
2+
using Microsoft.ComponentDetection.Contracts.BcdeModels;
23

34
namespace Microsoft.ComponentDetection.Contracts
45
{
@@ -25,12 +26,14 @@ public interface ISingleFileComponentRecorder
2526
/// <param name="isExplicitReferencedDependency">The value define if the component was referenced manually by the user in the location where the scanning is taking place.</param>
2627
/// <param name="parentComponentId">Id of the parent component.</param>
2728
/// <param name="isDevelopmentDependency">Boolean value indicating whether or not a component is a development-time dependency. Null implies that the value is unknown.</param>
29+
/// <param name="dependencyScope">Enum value indicating scope of the component. </param>
2830
/// <returns>DetectedComponent added or updated.</returns>
2931
void RegisterUsage(
3032
DetectedComponent detectedComponent,
3133
bool isExplicitReferencedDependency = false,
3234
string parentComponentId = null,
33-
bool? isDevelopmentDependency = null);
35+
bool? isDevelopmentDependency = null,
36+
DependencyScope? dependencyScope = null);
3437

3538
DetectedComponent GetComponent(string componentId);
3639

@@ -82,6 +85,13 @@ public interface IDependencyGraph
8285
/// <returns>True if a development dependency, false if not. Null when unknown.</returns>
8386
bool? IsDevelopmentDependency(string componentId);
8487

88+
/// <summary>
89+
/// Returns DepedencyScope for the given componentId.
90+
/// Null can be returned if a detector doesn't have the scope infromation.
91+
/// </summary>
92+
/// <param name="componentId">The componentId to check.</param>
93+
DependencyScope? GetDependencyScope(string componentId);
94+
8595
/// <summary>
8696
/// Gets the component IDs of all explicitly referenced components.
8797
/// </summary>

src/Microsoft.ComponentDetection.Detectors/ivy/IvyDetector.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Microsoft.ComponentDetection.Contracts;
1010
using Microsoft.ComponentDetection.Contracts.Internal;
1111
using Microsoft.ComponentDetection.Contracts.TypedComponent;
12+
using Microsoft.ComponentDetection.Contracts.BcdeModels;
1213
using Newtonsoft.Json.Linq;
1314

1415
namespace Microsoft.ComponentDetection.Detectors.Ivy
@@ -33,7 +34,7 @@ namespace Microsoft.ComponentDetection.Detectors.Ivy
3334
/// in the project's build.xml, or if they use any file inclusion mechanism, it will fail.
3435
///
3536
/// The file written out by the custom Ant task is a simple JSON file representing a series of calls to be made to
36-
/// the <see cref="ISingleFileComponentRecorder.RegisterUsage(DetectedComponent, bool, string, bool?)"/> method.
37+
/// the <see cref="ISingleFileComponentRecorder.RegisterUsage(DetectedComponent, bool, string, bool?, DependencyScope?)"/> method.
3738
/// </remarks>
3839
[Export(typeof(IComponentDetector))]
3940
public class IvyDetector : FileComponentDetector, IExperimentalDetector

0 commit comments

Comments
 (0)