diff --git a/CycloneDX.Tests/FunctionalTests/FunctionalTestHelper.cs b/CycloneDX.Tests/FunctionalTests/FunctionalTestHelper.cs index 0396d305..ff690683 100644 --- a/CycloneDX.Tests/FunctionalTests/FunctionalTestHelper.cs +++ b/CycloneDX.Tests/FunctionalTests/FunctionalTestHelper.cs @@ -68,6 +68,19 @@ public static async Task Test(string assetsJson, RunOptions options, INuget return await Test(options, nugetService, mockFileSystem, expectedExitCode).ConfigureAwait(false); } + public static async Task TestWithProjectFile(string assetsJson, string projectFileContents, RunOptions options, INugetServiceFactory nugetService = null, ExitCode expectedExitCode = ExitCode.OK) + { + nugetService ??= CreateMockNugetServiceFactory(); + + var mockFileSystem = new MockFileSystem(new Dictionary + { + { MockUnixSupport.Path("c:/ProjectPath/Project.csproj"), new MockFileData(projectFileContents) }, + { MockUnixSupport.Path("c:/ProjectPath/obj/project.assets.json"), new MockFileData(assetsJson) } + }); + + return await Test(options, nugetService, mockFileSystem, expectedExitCode).ConfigureAwait(false); + } + public static async Task Test(RunOptions options, MockFileSystem mockFileSystem, ExitCode expectedExitCode = ExitCode.OK) => await Test(options, CreateMockNugetServiceFactory(), diff --git a/CycloneDX.Tests/FunctionalTests/ProjectFileVersionMetadata.cs b/CycloneDX.Tests/FunctionalTests/ProjectFileVersionMetadata.cs new file mode 100644 index 00000000..50c770d4 --- /dev/null +++ b/CycloneDX.Tests/FunctionalTests/ProjectFileVersionMetadata.cs @@ -0,0 +1,24 @@ +using System.IO; +using System.Threading.Tasks; +using CycloneDX.Models; +using Xunit; + +namespace CycloneDX.Tests.FunctionalTests +{ + public class ProjectFileVersionMetadata + { + [Fact(Timeout = 15000)] + public async Task MetadataVersionFromProjectFile() + { + var assetsJson = File.ReadAllText(Path.Combine("FunctionalTests", "TestcaseFiles", "SimpleNETStandardLibrary.json")); + var options = new RunOptions + { + }; + + var csproj = "\n \n Exe\n SampleProject\n 1.2.3\n \n \n \n\n"; + + var bom = await FunctionalTestHelper.TestWithProjectFile(assetsJson, csproj, options); + Assert.Equal("1.2.3", bom.Metadata.Component.Version); + } + } +} diff --git a/CycloneDX/Interfaces/IProjectFileService.cs b/CycloneDX/Interfaces/IProjectFileService.cs index 7a6728c2..2d9ccf9d 100755 --- a/CycloneDX/Interfaces/IProjectFileService.cs +++ b/CycloneDX/Interfaces/IProjectFileService.cs @@ -29,6 +29,7 @@ public interface IProjectFileService Task> RecursivelyGetProjectDotnetDependencysAsync(string projectFilePath, string baseIntermediateOutputPath, bool excludeTestProjects, string framework, string runtime); Task> RecursivelyGetProjectReferencesAsync(string projectFilePath); Component GetComponent(DotnetDependency dotnetDependency); + (string name, string version) GetAssemblyNameAndVersion(string projectFilePath); bool IsTestProject(string projectFilePath); } } diff --git a/CycloneDX/Runner.cs b/CycloneDX/Runner.cs index 443737e3..dfd46d76 100644 --- a/CycloneDX/Runner.cs +++ b/CycloneDX/Runner.cs @@ -184,6 +184,14 @@ public async Task HandleCommandAsync(RunOptions options) } packages = await projectFileService.RecursivelyGetProjectDotnetDependencysAsync(fullSolutionOrProjectFilePath, baseIntermediateOutputPath, excludetestprojects, framework, runtime).ConfigureAwait(false); topLevelComponent.Name = fileSystem.Path.GetFileNameWithoutExtension(SolutionOrProjectFile); + if (string.IsNullOrEmpty(setVersion)) + { + var (_, projectVersion) = projectFileService.GetAssemblyNameAndVersion(fullSolutionOrProjectFilePath); + if (!string.IsNullOrEmpty(projectVersion)) + { + topLevelComponent.Version = projectVersion; + } + } } else if (Utils.IsSupportedProjectType(SolutionOrProjectFile)) { @@ -194,6 +202,14 @@ public async Task HandleCommandAsync(RunOptions options) } packages = await projectFileService.GetProjectDotnetDependencysAsync(fullSolutionOrProjectFilePath, baseIntermediateOutputPath, excludetestprojects, framework, runtime).ConfigureAwait(false); topLevelComponent.Name = fileSystem.Path.GetFileNameWithoutExtension(SolutionOrProjectFile); + if (string.IsNullOrEmpty(setVersion)) + { + var (_, projectVersion) = projectFileService.GetAssemblyNameAndVersion(fullSolutionOrProjectFilePath); + if (!string.IsNullOrEmpty(projectVersion)) + { + topLevelComponent.Version = projectVersion; + } + } } else if (fileSystem.Path.GetFileName(SolutionOrProjectFile).ToLowerInvariant().Equals("packages.config", StringComparison.OrdinalIgnoreCase)) { diff --git a/CycloneDX/Services/ProjectFileService.cs b/CycloneDX/Services/ProjectFileService.cs index 6ce7a0c3..272fdf63 100755 --- a/CycloneDX/Services/ProjectFileService.cs +++ b/CycloneDX/Services/ProjectFileService.cs @@ -81,7 +81,7 @@ public bool IsTestProject(string projectFilePath) return testProjectPropertyGroup != null; } - private (string name, string version) GetAssemblyNameAndVersion(string projectFilePath) + public (string name, string version) GetAssemblyNameAndVersion(string projectFilePath) { if (!_fileSystem.File.Exists(projectFilePath)) { @@ -111,7 +111,7 @@ public bool IsTestProject(string projectFilePath) // Extract Version XmlElement versionElement = xmldoc.SelectSingleNode("/Project/PropertyGroup/Version") as XmlElement; - string version = versionElement?.Value; + string version = versionElement?.InnerText; if (version == null) {