diff --git a/DemaConsulting.SpdxTool.sln.DotSettings b/DemaConsulting.SpdxTool.sln.DotSettings
index af14ace..d0efa3a 100644
--- a/DemaConsulting.SpdxTool.sln.DotSettings
+++ b/DemaConsulting.SpdxTool.sln.DotSettings
@@ -1,4 +1,6 @@
True
True
+ True
+ True
True
\ No newline at end of file
diff --git a/README.md b/README.md
index e2cbb92..60044fa 100644
--- a/README.md
+++ b/README.md
@@ -42,12 +42,13 @@ Commands:
copy-package Copy package between SPDX documents (workflow only).
find-package [criteria] Find package ID in SPDX document
print Print text to the console
- query [arguments] Query program output for value
+ query [arguments] Query program output for value
rename-id Rename an element ID in an SPDX document.
run-workflow Runs the workflow file
sha256 Generate or verify sha256 hashes of files
to-markdown Create Markdown summary for SPDX document
update-package Update package in SPDX document (workflow only).
+ validate [ntia] Validate SPDX document for issues
```
@@ -232,4 +233,10 @@ steps:
summary: # Optional new package summary
description: # Optional new package description
license: # Optional new package license
+
+ # Validate an SPDX document
+- command: validate
+ inputs:
+ spdx: # SPDX file name
+ ntia: true # Optional NTIA checking
```
diff --git a/spdx-workflow.yaml b/spdx-workflow.yaml
index a620b69..71b7abc 100644
--- a/spdx-workflow.yaml
+++ b/spdx-workflow.yaml
@@ -46,7 +46,13 @@ steps:
operation: generate
file: ${{ spdx }}
+ # Validate the SPDX document
+- command: validate
+ inputs:
+ spdx: ${{ spdx }}
+
+ # Generate the summary
- command: to-markdown
inputs:
spdx: ${{ spdx }}
- markdown: ${{ summary-markdown }}
\ No newline at end of file
+ markdown: ${{ summary-markdown }}
diff --git a/src/DemaConsulting.SpdxTool/Commands/CommandRegistry.cs b/src/DemaConsulting.SpdxTool/Commands/CommandRegistry.cs
index 0e0d780..516ed7a 100644
--- a/src/DemaConsulting.SpdxTool/Commands/CommandRegistry.cs
+++ b/src/DemaConsulting.SpdxTool/Commands/CommandRegistry.cs
@@ -20,7 +20,8 @@ public static class CommandsRegistry
{ RunWorkflow.Entry.Name, RunWorkflow.Entry },
{ Sha256Command.Entry.Name, Sha256Command.Entry },
{ ToMarkdown.Entry.Name, ToMarkdown.Entry },
- { UpdatePackage.Entry.Name, UpdatePackage.Entry }
+ { UpdatePackage.Entry.Name, UpdatePackage.Entry },
+ { Validate.Entry.Name, Validate.Entry }
};
///
diff --git a/src/DemaConsulting.SpdxTool/Commands/Validate.cs b/src/DemaConsulting.SpdxTool/Commands/Validate.cs
new file mode 100644
index 0000000..c881e47
--- /dev/null
+++ b/src/DemaConsulting.SpdxTool/Commands/Validate.cs
@@ -0,0 +1,108 @@
+using DemaConsulting.SpdxTool.Spdx;
+using YamlDotNet.Core;
+using YamlDotNet.RepresentationModel;
+
+namespace DemaConsulting.SpdxTool.Commands;
+
+///
+/// Command to validate SPDX documents
+///
+public class Validate : Command
+{
+ ///
+ /// Singleton instance of this command
+ ///
+ public static readonly Validate Instance = new();
+
+ ///
+ /// Entry information for this command
+ ///
+ public static readonly CommandEntry Entry = new(
+ "validate",
+ "validate [ntia]",
+ "Validate SPDX document for issues",
+ new[]
+ {
+ "This command validates an SPDX document for issues.",
+ "",
+ "From the command-line this can be used as:",
+ " spdx-tool validate [ntia]",
+ "",
+ "From a YAML file this can be used as:",
+ " - command: validate",
+ " inputs:",
+ " spdx: # SPDX file name",
+ " ntia: true # Optional NTIA checking"
+ },
+ Instance);
+
+ ///
+ /// Private constructor - this is a singleton
+ ///
+ private Validate()
+ {
+ }
+
+ ///
+ public override void Run(string[] args)
+ {
+ // Report an error if for missing arguments
+ if (args.Length == 0)
+ throw new CommandUsageException("'validate' command missing arguments");
+
+ // Process the arguments
+ var spdxFile = args[0];
+ var ntia = args.Skip(1).Any(a => a == "ntia");
+
+ // Perform validation
+ DoValidate(spdxFile, ntia);
+ }
+
+ ///
+ public override void Run(YamlMappingNode step, Dictionary variables)
+ {
+ // Get the step inputs
+ var inputs = GetMapMap(step, "inputs");
+
+ // Get the 'spdx' input
+ var spdxFile = GetMapString(inputs, "spdx", variables) ??
+ throw new YamlException(step.Start, step.End, "'to-markdown' command missing 'spdx' input");
+
+ // Get the 'ntia' input
+ var ntiaValue = GetMapString(inputs, "ntia", variables);
+ var ntia = ntiaValue?.ToLowerInvariant() == "true";
+
+ // Perform validation
+ DoValidate(spdxFile, ntia);
+ }
+
+ ///
+ /// Validate SPDX document for issues
+ ///
+ /// SPDX document file name
+ /// NTIA flag
+ /// on issues
+ public static void DoValidate(string spdxFile, bool ntia)
+ {
+ // Load the SPDX document
+ var doc = SpdxHelpers.LoadJsonDocument(spdxFile);
+
+ // Get the issues
+ var issues = new List();
+ doc.Validate(issues, ntia);
+
+ // Skip if no issues detected
+ if (issues.Count == 0)
+ return;
+
+ // Report issues to console
+ Console.ForegroundColor = ConsoleColor.DarkYellow;
+ foreach (var issue in issues)
+ Console.WriteLine(issue);
+ Console.ResetColor();
+ Console.WriteLine();
+
+ // Throw error
+ throw new CommandErrorException($"Found {issues.Count} Issues in {spdxFile}");
+ }
+}
\ No newline at end of file
diff --git a/src/DemaConsulting.SpdxTool/DemaConsulting.SpdxTool.csproj b/src/DemaConsulting.SpdxTool/DemaConsulting.SpdxTool.csproj
index ff31f9e..e289ca2 100644
--- a/src/DemaConsulting.SpdxTool/DemaConsulting.SpdxTool.csproj
+++ b/src/DemaConsulting.SpdxTool/DemaConsulting.SpdxTool.csproj
@@ -40,7 +40,7 @@
-
+
diff --git a/test/DemaConsulting.SpdxTool.Tests/DemaConsulting.SpdxTool.Tests.csproj b/test/DemaConsulting.SpdxTool.Tests/DemaConsulting.SpdxTool.Tests.csproj
index ac6a278..da6a374 100644
--- a/test/DemaConsulting.SpdxTool.Tests/DemaConsulting.SpdxTool.Tests.csproj
+++ b/test/DemaConsulting.SpdxTool.Tests/DemaConsulting.SpdxTool.Tests.csproj
@@ -18,9 +18,9 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
+
+
+