Skip to content

Commit

Permalink
Add output version argument to merge command (#388)
Browse files Browse the repository at this point in the history
Copy of #366

---------

Signed-off-by: andreas hilti <[email protected]>
Co-authored-by: andreas hilti <[email protected]>
  • Loading branch information
mtsfoni and andreas-hilti authored Aug 11, 2024
1 parent 3bebe12 commit 01fb950
Show file tree
Hide file tree
Showing 17 changed files with 95 additions and 23 deletions.
5 changes: 5 additions & 0 deletions .markdownlint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"MD013": {
"code_blocks": false
}
}
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,14 +192,15 @@ Usage:
cyclonedx merge [options]
Options:
--input-files <input-files> Input BOM filenames (separate filenames with a space).
--output-file <output-file> Output BOM filename, will write to stdout if no value provided.
--input-format <autodetect|json|protobuf|xml> Specify input file format.
--output-format <autodetect|json|protobuf|xml> Specify output file format.
--hierarchical Perform a hierarchical merge.
--group <group> Provide the group of software the merged BOM describes.
--name <name> Provide the name of software the merged BOM describes (required for hierarchical merging).
--version <version> Provide the version of software the merged BOM describes (required for hierarchical merging).
--input-files <input-files> Input BOM filenames (separate filenames with a space).
--output-file <output-file> Output BOM filename, will write to stdout if no value provided.
--input-format <autodetect|json|protobuf|xml> Specify input file format.
--output-format <autodetect|json|protobuf|xml> Specify output file format.
--output-version <v1_0|v1_1|v1_2|v1_3|v1_4|v1_5> Specify output BOM specification version.
--hierarchical Perform a hierarchical merge.
--group <group> Provide the group of software the merged BOM describes.
--name <name> Provide the name of software the merged BOM describes (required for hierarchical merging).
--version <version> Provide the version of software the merged BOM describes (required for hierarchical merging).
```

Note: To perform a hierarchical merge all BOMs need the subject of the BOM
Expand Down
3 changes: 2 additions & 1 deletion src/cyclonedx/Commands/MergeCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public static void Configure(RootCommand rootCommand)
subCommand.Add(new Option<string>("--output-file", "Output BOM filename, will write to stdout if no value provided."));
subCommand.Add(new Option<CycloneDXBomFormat>("--input-format", "Specify input file format."));
subCommand.Add(new Option<CycloneDXBomFormat>("--output-format", "Specify output file format."));
subCommand.Add(new Option<SpecificationVersion>("--output-version", "Specify output BOM specification version."));
subCommand.Add(new Option<bool>("--hierarchical", "Perform a hierarchical merge."));
subCommand.Add(new Option<string>("--group", "Provide the group of software the merged BOM describes."));
subCommand.Add(new Option<string>("--name", "Provide the name of software the merged BOM describes (required for hierarchical merging)."));
Expand Down Expand Up @@ -110,7 +111,7 @@ public static async Task<int> Merge(MergeCommandOptions options)
Console.WriteLine($" Total {outputBom.Components?.Count ?? 0} components");
}

return await CliUtils.OutputBomHelper(outputBom, options.OutputFormat, options.OutputFile).ConfigureAwait(false);
return await CliUtils.OutputBomHelper(outputBom, (ConvertFormat)options.OutputFormat, options.OutputVersion, options.OutputFile).ConfigureAwait(false);
}

private static async Task<IEnumerable<Bom>> InputBoms(IEnumerable<string> inputFilenames, CycloneDXBomFormat inputFormat, bool outputToConsole)
Expand Down
5 changes: 3 additions & 2 deletions src/cyclonedx/Commands/MergeCommandOptions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// This file is part of CycloneDX CLI Tool
// This file is part of CycloneDX CLI Tool
//
// Licensed under the Apache License, Version 2.0 (the “License”);
// you may not use this file except in compliance with the License.
Expand All @@ -24,9 +24,10 @@ public class MergeCommandOptions
public string OutputFile { get; set; }
public CycloneDXBomFormat InputFormat { get; set; }
public CycloneDXBomFormat OutputFormat { get; set; }
public SpecificationVersion? OutputVersion { get; set; }
public bool Hierarchical { get; set; }
public string Group { get; set; }
public string Name { get; set; }
public string Version { get; set; }
}
}
}
28 changes: 16 additions & 12 deletions tests/cyclonedx.tests/MergeTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// This file is part of CycloneDX CLI Tool
// This file is part of CycloneDX CLI Tool
//
// Licensed under the Apache License, Version 2.0 (the “License”);
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -29,20 +29,23 @@ namespace CycloneDX.Cli.Tests
public class MergeTests
{
[Theory]
[InlineData(new string[] { "sbom1.json", "sbom2.json"}, CycloneDXBomFormat.autodetect, "sbom.json", CycloneDXBomFormat.autodetect, true, null, "Thing", "1")]
[InlineData(new string[] { "sbom1.json", "sbom2.json"}, CycloneDXBomFormat.autodetect, "sbom.json", CycloneDXBomFormat.autodetect, false, null, null, null)]
[InlineData(new string[] { "sbom1.json", "sbom2.json"}, CycloneDXBomFormat.autodetect, "sbom.xml", CycloneDXBomFormat.autodetect, false, null, null, null)]
[InlineData(new string[] { "sbom1.json", "sbom2.json"}, CycloneDXBomFormat.json, "sbom.json", CycloneDXBomFormat.autodetect, false, null, null, null)]
[InlineData(new string[] { "sbom1.xml", "sbom2.xml"}, CycloneDXBomFormat.autodetect, "sbom.xml", CycloneDXBomFormat.autodetect, false, null, null, null)]
[InlineData(new string[] { "sbom1.xml", "sbom2.xml"}, CycloneDXBomFormat.autodetect, "sbom.json", CycloneDXBomFormat.autodetect, false, null, null, null)]
[InlineData(new string[] { "sbom1.xml", "sbom2.xml"}, CycloneDXBomFormat.xml, "sbom.xml", CycloneDXBomFormat.autodetect, false, null, null, null)]
[InlineData(new string[] { "sbom1.json", "sbom2.xml"}, CycloneDXBomFormat.autodetect, "sbom.xml", CycloneDXBomFormat.autodetect, false, null, null, null)]
[InlineData(new string[] { "sbom1.json", "sbom2.json"}, CycloneDXBomFormat.autodetect, "sbom.json", CycloneDXBomFormat.json, false, null, null, null)]
[InlineData(new string[] { "sbom1.json", "sbom2.json"}, CycloneDXBomFormat.autodetect, "sbom.xml", CycloneDXBomFormat.xml, false, null, null, null)]
[InlineData(new[] { "sbom1.json", "sbom2.json"}, CycloneDXBomFormat.autodetect, "sbom.json", CycloneDXBomFormat.autodetect, null, true, null, "Thing", "1")]
[InlineData(new[] { "sbom1.json", "sbom2.json"}, CycloneDXBomFormat.autodetect, "sbom.json", CycloneDXBomFormat.autodetect, null, false, null, null, null)]
[InlineData(new[] { "sbom1.json", "sbom2.json"}, CycloneDXBomFormat.autodetect, "sbom.xml", CycloneDXBomFormat.autodetect, null, false, null, null, null)]
[InlineData(new[] { "sbom1.json", "sbom2.json"}, CycloneDXBomFormat.json, "sbom.json", CycloneDXBomFormat.autodetect, null, false, null, null, null)]
[InlineData(new[] { "sbom1.json", "sbom2.json" }, CycloneDXBomFormat.json, "sbom.json", CycloneDXBomFormat.autodetect, SpecificationVersion.v1_4, false, null, null, null)]
[InlineData(new[] { "sbom1.xml", "sbom2.xml"}, CycloneDXBomFormat.autodetect, "sbom.xml", CycloneDXBomFormat.autodetect, null, false, null, null, null)]
[InlineData(new[] { "sbom1.xml", "sbom2.xml" }, CycloneDXBomFormat.autodetect, "sbom.xml", CycloneDXBomFormat.autodetect, SpecificationVersion.v1_4, false, null, null, null)]
[InlineData(new[] { "sbom1.xml", "sbom2.xml"}, CycloneDXBomFormat.autodetect, "sbom.json", CycloneDXBomFormat.autodetect, null, false, null, null, null)]
[InlineData(new[] { "sbom1.xml", "sbom2.xml"}, CycloneDXBomFormat.xml, "sbom.xml", CycloneDXBomFormat.autodetect, null, false, null, null, null)]
[InlineData(new[] { "sbom1.json", "sbom2.xml"}, CycloneDXBomFormat.autodetect, "sbom.xml", CycloneDXBomFormat.autodetect, null, false, null, null, null)]
[InlineData(new[] { "sbom1.json", "sbom2.json"}, CycloneDXBomFormat.autodetect, "sbom.json", CycloneDXBomFormat.json, null, false, null, null, null)]
[InlineData(new[] { "sbom1.json", "sbom2.json"}, CycloneDXBomFormat.autodetect, "sbom.xml", CycloneDXBomFormat.xml, null, false, null, null, null)]
public async Task Merge(
string[] inputFilenames,
CycloneDXBomFormat inputFormat,
string outputFilename, CycloneDXBomFormat outputFormat,
SpecificationVersion? outputVersion,
bool hierarchical,
string group, string name, string version
)
Expand All @@ -57,6 +60,7 @@ public async Task Merge(
InputFormat = inputFormat,
OutputFile = fullOutputPath,
OutputFormat = outputFormat,
OutputVersion = outputVersion,
Hierarchical = hierarchical,
Group = group,
Name = name,
Expand All @@ -73,7 +77,7 @@ public async Task Merge(
var bom = File.ReadAllText(fullOutputPath);
bom = Regex.Replace(bom, @"\s*""serialNumber"": "".*?"",\r?\n", ""); // json
bom = Regex.Replace(bom, @"\s+serialNumber="".*?""", ""); // xml
Snapshot.Match(bom, SnapshotNameExtension.Create(hierarchical ? "Hierarchical" : "Flat", snapshotInputFilenames, inputFormat, outputFilename, outputFormat));
Snapshot.Match(bom, SnapshotNameExtension.Create(hierarchical ? "Hierarchical" : "Flat", snapshotInputFilenames, inputFormat, outputFilename, outputFormat, outputVersion));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.4", "version": 1,
"metadata": {
"component": {
"type": "application",
"name": "thing1",
"version": "1"
}
},
"components": [
{
"type": "library",
"name": "acme-library",
"version": "1.0.0"
},
{
"type": "application",
"name": "thing1",
"version": "1"
},
{
"type": "framework",
"name": "acme-framework",
"version": "1.0.0"
},
{
"type": "application",
"name": "thing2",
"version": "1"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<bom xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
<metadata>
<component type="application">
<name>thing1</name>
<version>1</version>
</component>
</metadata>
<components>
<component type="library">
<name>acme-library</name>
<version>1.0.0</version>
</component>
<component type="application">
<name>thing1</name>
<version>1</version>
</component>
<component type="framework">
<name>acme-framework</name>
<version>1.0.0</version>
</component>
<component type="application">
<name>thing2</name>
<version>1</version>
</component>
</components>
</bom>

0 comments on commit 01fb950

Please sign in to comment.