Skip to content
Merged
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
2 changes: 1 addition & 1 deletion docs/detectors/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@

| Detector | Status |
| ------------------------------ | ------------ |
| SwiftResolvedComponentDetector | Experimental |
| SwiftResolvedComponentDetector | Stable |

- [Uv](uv.md)

Expand Down
13 changes: 2 additions & 11 deletions docs/detectors/swift.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Swift Package Manager Detection

Swift detection is enabled by default, and detected components are included in scan results without additional detector arguments.

## Requirements

Swift Package Manager detection requires the following file to be present in the scan directory:
Expand All @@ -14,17 +16,6 @@ The version, the url and commit hash of the dependencies are stored in this file

[This is the only reference in the Apple documentation to the `Package.resolved` file.][1]

## Experiment results

Swift detection is experimental. The registered `SwiftDetectorExperiment` uses an empty control group
and `SwiftResolvedComponentDetector` as its experiment group, so all Swift discoveries are reported as additions.
It does not depend on CocoaPods detection or compare Swift packages against CocoaPods packages.

Enable experiment processing with `CD_DETECTOR_EXPERIMENTS` or `DetectorExperiments.Enable`.
Scans with no Swift components do not produce experiment results. Disabling the Swift detector also disables this experiment.
The CLI writes results to `Experiment_SwiftDetectorExperiment_{timestamp}_{processId}.json`;
hosts that emit `ExperimentResults` custom events must register their own `IExperimentProcessor`.

## Known limitations

Right now the detector does not support parsing `Package.swift` file to get the dependencies.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Microsoft.ComponentDetection.Detectors.Swift;
/// <summary>
/// Detects Swift Package Manager components.
/// </summary>
public class SwiftResolvedComponentDetector : FileComponentDetector, IExperimentalDetector
public class SwiftResolvedComponentDetector : FileComponentDetector
Comment thread
ryanbrandenburg marked this conversation as resolved.
{
// We are only interested in packages coming from remote sources such as git
// The Package Kind is not an enum because the Swift Package Manager contract does not specify the possible values.
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ public static IServiceCollection AddComponentDetection(this IServiceCollection s
services.AddSingleton<IExperimentConfiguration, SimplePipExperiment>();
services.AddSingleton<IExperimentConfiguration, CondaLockDetectorExperiment>();
services.AddSingleton<IExperimentConfiguration, LinuxApplicationLayerExperiment>();
services.AddSingleton<IExperimentConfiguration, SwiftDetectorExperiment>();

// Detectors
// CocoaPods
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,12 @@ public void CondaLockComponentDetector_ImplementsIExperimentalDetector()
}

[TestMethod]
public void SwiftResolvedComponentDetector_ImplementsIExperimentalDetector()
public void SwiftResolvedComponentDetector_IsDefaultOn()
{
var swiftDetector = this.detectors.SingleOrDefault(d => d.Id == "Swift");

swiftDetector.Should().NotBeNull("because SwiftResolvedComponentDetector should be registered");
swiftDetector.Should().BeAssignableTo<IExperimentalDetector>("because SwiftResolvedComponentDetector should implement IExperimentalDetector");
swiftDetector.Should().NotBeAssignableTo<IExperimentalDetector>("because SwiftResolvedComponentDetector should be default-on");
swiftDetector.Should().NotBeAssignableTo<IDefaultOffComponentDetector>("because SwiftResolvedComponentDetector should be enabled by default");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Microsoft.ComponentDetection.Orchestrator.Tests.Experiments;
using System.Threading.Tasks;
using AwesomeAssertions;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Detectors.Swift;
using Microsoft.ComponentDetection.Orchestrator.Experiments.Configs;
using Microsoft.ComponentDetection.Orchestrator.Extensions;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -36,9 +37,11 @@ public void ExperimentConfig_HaveDistinctNames()
}

[TestMethod]
public void ExperimentConfig_RegistersSwiftDetectorExperiment()
public void ExperimentConfig_SwiftDetectorIsNotInExperimentGroup()
{
this.configs.OfType<SwiftDetectorExperiment>().Should().ContainSingle();
var swiftDetector = new SwiftResolvedComponentDetector(null, null, null);

this.configs.Should().OnlyContain(config => !config.IsInExperimentGroup(swiftDetector));
}

[TestMethod]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,12 @@ namespace Microsoft.ComponentDetection.Orchestrator.Tests.Experiments;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using AwesomeAssertions;
using Microsoft.ComponentDetection.Common.DependencyGraph;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.BcdeModels;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.CocoaPods;
using Microsoft.ComponentDetection.Detectors.NuGet;
using Microsoft.ComponentDetection.Detectors.Swift;
using Microsoft.ComponentDetection.Orchestrator.Commands;
using Microsoft.ComponentDetection.Orchestrator.Experiments;
using Microsoft.ComponentDetection.Orchestrator.Experiments.Configs;
Expand Down Expand Up @@ -169,69 +165,6 @@ public async Task FinishAsync_ProcessesExperimentsAsync()
Times.Once());
}

[TestMethod]
public async Task FinishAsync_ProcessesSwiftExperimentWithoutControlDetectorAsync()
{
var config = new SwiftDetectorExperiment();
var swiftDetector = new SwiftResolvedComponentDetector(null, null, null);
var podDetector = new PodComponentDetector(null, null, null);
var service = new ExperimentService(
[config],
[this.experimentProcessorMock.Object],
this.graphTranslationServiceMock.Object,
this.loggerMock.Object);
service.RemoveUnwantedExperimentsbyDetectors([podDetector]);

this.SetupGraphMock([]);
service.RecordDetectorRun(this.detectorMock.Object, this.componentRecorder, this.scanSettingsMock.Object);

var component = new SwiftComponent
{
Name = "alamofire",
Version = "5.9.1",
RepositoryUrl = new Uri("https://github.com/Alamofire/Alamofire"),
CommitHash = "f455c2975872ccd2d9c81594c658af65716e9b9a",
Kind = "remoteSourceControl",
};
this.SetupGraphMock([new ScannedComponent { Component = component }]);
service.RecordDetectorRun(swiftDetector, this.componentRecorder, this.scanSettingsMock.Object);

await service.FinishAsync();

this.experimentProcessorMock.Verify(
x => x.ProcessExperimentAsync(
config,
It.Is<ExperimentDiff>(diff =>
diff.AddedIds.Count == 1 && diff.AddedIds.Contains(component.Id)
&& diff.RemovedIds.Count == 0
&& diff.ControlDetectors.Count == 0
&& diff.ExperimentalDetectors.Count == 1
&& diff.ExperimentalDetectors.Single().DetectorId == swiftDetector.Id)),
Times.Once());
}

[TestMethod]
public async Task FinishAsync_SkipsSwiftExperimentWithoutSwiftComponentsAsync()
{
var config = new SwiftDetectorExperiment();
var service = new ExperimentService(
[config],
[this.experimentProcessorMock.Object],
this.graphTranslationServiceMock.Object,
this.loggerMock.Object);
this.SetupGraphMock(ExperimentTestUtils.CreateRandomComponents());
service.RecordDetectorRun(new PodComponentDetector(null, null, null), this.componentRecorder, this.scanSettingsMock.Object);

this.SetupGraphMock([]);
service.RecordDetectorRun(new SwiftResolvedComponentDetector(null, null, null), this.componentRecorder, this.scanSettingsMock.Object);

await service.FinishAsync();

this.experimentProcessorMock.Verify(
x => x.ProcessExperimentAsync(config, It.IsAny<ExperimentDiff>()),
Times.Never());
}

[TestMethod]
public async Task FinishAsync_SwallowsExceptionsAsync()
{
Expand Down

This file was deleted.

Loading