Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add output version argument to merge command #366

Closed
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
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>
Loading