feat: Add CSV output format support#484
Conversation
This commit adds support for CSV output format, which is useful for: - Importing license data into Excel - Compliance and audit reporting - Feeding data into internal tools and CI/CD pipelines Changes: - Added Csv to OutputType enum - Created CsvOutputFormatter class with proper escaping - Updated CommandLineOptionsParser to handle CSV format - Updated help text to include CSV option Closes sensslen#423
WalkthroughThis pull request adds CSV output format support to the NuGet license tool. A new Possibly related PRs
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Tip Migrating from UI to YAML configuration.Use the |
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/NuGetLicense/Output/Csv/CsvOutputFormatter.cs (1)
17-23: Add XML docs to the new public constructor andWritemethod.These are public APIs and should be documented with XML comments for consistency and consumer clarity. As per coding guidelines, "Public APIs in C# should have XML documentation comments using
<summary>,<param>,<returns>,<exception>tags as appropriate".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/NuGetLicense/Output/Csv/CsvOutputFormatter.cs` around lines 17 - 23, Add XML documentation comments for the public CsvOutputFormatter constructor and the public Write method: for the constructor CsvOutputFormatter(bool printErrorsOnly, bool skipIgnoredPackages) add a <summary> describing the purpose of the constructor and <param> tags for printErrorsOnly and skipIgnoredPackages; for the method Task Write(Stream stream, IList<LicenseValidationResult> results) add a <summary> explaining what the method writes, <param> tags for stream and results, a <returns> documenting the returned Task, and an <exception> tag if the method can throw (e.g., ArgumentNullException for null arguments or IOException for stream errors) — place the comments immediately above the constructor and method declarations using standard C# XML doc syntax.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/NuGetLicense/Output/Csv/CsvOutputFormatter.cs`:
- Around line 42-60: The ValidationErrors are being escaped twice: each item is
passed through EscapeCsvField in the Select and then the joined string (errors /
errorContexts) is passed through EscapeCsvField again when building the CSV
line; change this by removing the per-item escaping in the Selects that build
errors and errorContexts so they produce plain strings (e.g. string.Join("; ",
result.ValidationErrors.Select(e => e.Error))) and keep the single
EscapeCsvField call when adding errors and errorContexts to the CSV line; update
references in CsvOutputFormatter.cs to only call EscapeCsvField on the final
errors and errorContexts variables.
---
Nitpick comments:
In `@src/NuGetLicense/Output/Csv/CsvOutputFormatter.cs`:
- Around line 17-23: Add XML documentation comments for the public
CsvOutputFormatter constructor and the public Write method: for the constructor
CsvOutputFormatter(bool printErrorsOnly, bool skipIgnoredPackages) add a
<summary> describing the purpose of the constructor and <param> tags for
printErrorsOnly and skipIgnoredPackages; for the method Task Write(Stream
stream, IList<LicenseValidationResult> results) add a <summary> explaining what
the method writes, <param> tags for stream and results, a <returns> documenting
the returned Task, and an <exception> tag if the method can throw (e.g.,
ArgumentNullException for null arguments or IOException for stream errors) —
place the comments immediately above the constructor and method declarations
using standard C# XML doc syntax.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 14b1e840-eb6d-4dba-ac53-a03894d12f1d
📒 Files selected for processing (4)
src/NuGetLicense/CommandLineOptionsParser.cssrc/NuGetLicense/Output/Csv/CsvOutputFormatter.cssrc/NuGetLicense/Program.cssrc/NuGetUtility/OutputType.cs
| string errors = result.ValidationErrors.Any() | ||
| ? string.Join("; ", result.ValidationErrors.Select(e => EscapeCsvField(e.Error))) | ||
| : ""; | ||
| string errorContexts = result.ValidationErrors.Any() | ||
| ? string.Join("; ", result.ValidationErrors.Select(e => EscapeCsvField(e.Context))) | ||
| : ""; | ||
|
|
||
| var line = string.Join(",", | ||
| EscapeCsvField(result.PackageId), | ||
| EscapeCsvField(result.PackageVersion.ToString()), | ||
| EscapeCsvField(result.LicenseInformationOrigin.ToString()), | ||
| EscapeCsvField(result.License), | ||
| EscapeCsvField(result.LicenseUrl), | ||
| EscapeCsvField(result.Copyright), | ||
| EscapeCsvField(result.Authors), | ||
| EscapeCsvField(result.Description), | ||
| EscapeCsvField(result.Summary), | ||
| EscapeCsvField(errors), | ||
| EscapeCsvField(errorContexts) |
There was a problem hiding this comment.
Avoid double-escaping Error and Error Context values.
Line 42–47 escapes each error item, and Line 59–60 escapes the joined field again. This can produce incorrect CSV cell content (extra quotes).
Proposed fix
- string errors = result.ValidationErrors.Any()
- ? string.Join("; ", result.ValidationErrors.Select(e => EscapeCsvField(e.Error)))
- : "";
- string errorContexts = result.ValidationErrors.Any()
- ? string.Join("; ", result.ValidationErrors.Select(e => EscapeCsvField(e.Context)))
- : "";
+ string errors = result.ValidationErrors.Any()
+ ? string.Join("; ", result.ValidationErrors.Select(e => e.Error))
+ : string.Empty;
+ string errorContexts = result.ValidationErrors.Any()
+ ? string.Join("; ", result.ValidationErrors.Select(e => e.Context))
+ : string.Empty;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| string errors = result.ValidationErrors.Any() | |
| ? string.Join("; ", result.ValidationErrors.Select(e => EscapeCsvField(e.Error))) | |
| : ""; | |
| string errorContexts = result.ValidationErrors.Any() | |
| ? string.Join("; ", result.ValidationErrors.Select(e => EscapeCsvField(e.Context))) | |
| : ""; | |
| var line = string.Join(",", | |
| EscapeCsvField(result.PackageId), | |
| EscapeCsvField(result.PackageVersion.ToString()), | |
| EscapeCsvField(result.LicenseInformationOrigin.ToString()), | |
| EscapeCsvField(result.License), | |
| EscapeCsvField(result.LicenseUrl), | |
| EscapeCsvField(result.Copyright), | |
| EscapeCsvField(result.Authors), | |
| EscapeCsvField(result.Description), | |
| EscapeCsvField(result.Summary), | |
| EscapeCsvField(errors), | |
| EscapeCsvField(errorContexts) | |
| string errors = result.ValidationErrors.Any() | |
| ? string.Join("; ", result.ValidationErrors.Select(e => e.Error)) | |
| : string.Empty; | |
| string errorContexts = result.ValidationErrors.Any() | |
| ? string.Join("; ", result.ValidationErrors.Select(e => e.Context)) | |
| : string.Empty; | |
| var line = string.Join(",", | |
| EscapeCsvField(result.PackageId), | |
| EscapeCsvField(result.PackageVersion.ToString()), | |
| EscapeCsvField(result.LicenseInformationOrigin.ToString()), | |
| EscapeCsvField(result.License), | |
| EscapeCsvField(result.LicenseUrl), | |
| EscapeCsvField(result.Copyright), | |
| EscapeCsvField(result.Authors), | |
| EscapeCsvField(result.Description), | |
| EscapeCsvField(result.Summary), | |
| EscapeCsvField(errors), | |
| EscapeCsvField(errorContexts) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/NuGetLicense/Output/Csv/CsvOutputFormatter.cs` around lines 42 - 60, The
ValidationErrors are being escaped twice: each item is passed through
EscapeCsvField in the Select and then the joined string (errors / errorContexts)
is passed through EscapeCsvField again when building the CSV line; change this
by removing the per-item escaping in the Selects that build errors and
errorContexts so they produce plain strings (e.g. string.Join("; ",
result.ValidationErrors.Select(e => e.Error))) and keep the single
EscapeCsvField call when adding errors and errorContexts to the CSV line; update
references in CsvOutputFormatter.cs to only call EscapeCsvField on the final
errors and errorContexts variables.
|
@vincent067 thank you for your contribution. There is already an open pull-request to add csv support: #468. can you help bring this across the finish line? |
|
Csv support has been merged |



Hi maintainers! 👋
First off, thank you for creating and maintaining this excellent tool! nuget-license has been incredibly helpful for license compliance analysis in our .NET projects.
Feature Description
This PR adds CSV output format support to nuget-license, allowing users to export license analysis results in a structured CSV format that can be easily consumed by other tools and systems.
Use Cases
Implementation Details
Related Issue
This implementation addresses the feature request in #423.
I hope this contribution helps make the tool even more useful for the community. Please let me know if you'd like any adjustments to the implementation or documentation!
Thanks again for the great work on this project! 🙏
Summary by CodeRabbit