-
-
Notifications
You must be signed in to change notification settings - Fork 31
test: verify expected license type from mapping in UrlToLicenseMapping tests #494
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| // Licensed to the projects contributors. | ||
| // The license conditions are provided in the LICENSE file located in the project root | ||
|
|
||
| using System.Globalization; | ||
| using NuGetLicense.LicenseValidator; | ||
|
|
||
| namespace NuGetLicense.Output.Csv | ||
| { | ||
| /// <summary> | ||
| /// Outputs license validation results in CSV format. | ||
| /// </summary> | ||
| public class CsvOutputFormatter : IOutputFormatter | ||
| { | ||
| private readonly bool _printErrorsOnly; | ||
| private readonly bool _skipIgnoredPackages; | ||
| private readonly string[] _includedColumns; | ||
|
|
||
| public CsvOutputFormatter(bool printErrorsOnly, bool skipIgnoredPackages, string[]? includedColumns = null) | ||
| { | ||
| _printErrorsOnly = printErrorsOnly; | ||
| _skipIgnoredPackages = skipIgnoredPackages; | ||
| _includedColumns = includedColumns ?? Array.Empty<string>(); | ||
| } | ||
|
|
||
| public async Task Write(Stream stream, IList<LicenseValidationResult> results) | ||
| { | ||
| if (_printErrorsOnly) | ||
| { | ||
| results = results.Where(r => r.ValidationErrors.Any()).ToList(); | ||
| } | ||
| else if (_skipIgnoredPackages) | ||
| { | ||
| results = results.Where(r => r.LicenseInformationOrigin != LicenseInformationOrigin.Ignored).ToList(); | ||
| } | ||
|
|
||
| using var writer = new StreamWriter(stream, leaveOpen: true); | ||
|
|
||
| // Define all available columns | ||
| var allColumns = new Dictionary<string, Func<LicenseValidationResult, string?>>(StringComparer.OrdinalIgnoreCase) | ||
| { | ||
| ["Package"] = r => r.PackageId, | ||
| ["Version"] = r => r.PackageVersion.ToString(), | ||
| ["LicenseInformationOrigin"] = r => r.LicenseInformationOrigin.ToString(), | ||
| ["LicenseExpression"] = r => r.License, | ||
| ["LicenseUrl"] = r => r.LicenseUrl, | ||
| ["Copyright"] = r => r.Copyright, | ||
| ["Authors"] = r => r.Authors, | ||
| ["Description"] = r => r.Description, | ||
| ["Summary"] = r => r.Summary, | ||
| ["Error"] = r => r.ValidationErrors.Any() ? string.Join("; ", r.ValidationErrors.Select(e => e.Error)) : null, | ||
| ["ErrorContext"] = r => r.ValidationErrors.Any() ? string.Join("; ", r.ValidationErrors.Select(e => e.Context)) : null | ||
| }; | ||
|
|
||
| // Determine which columns to include | ||
| var columnsToInclude = _includedColumns.Length > 0 | ||
| ? allColumns.Where(c => _includedColumns.Contains(c.Key, StringComparer.OrdinalIgnoreCase)).ToList() | ||
| : allColumns.ToList(); | ||
|
|
||
| // If no valid columns specified, use all columns | ||
| if (columnsToInclude.Count == 0) | ||
| { | ||
| columnsToInclude = allColumns.ToList(); | ||
| } | ||
|
|
||
| // Write header | ||
| var header = string.Join(",", columnsToInclude.Select(c => EscapeCsvField(c.Key))); | ||
| await writer.WriteLineAsync(header); | ||
|
|
||
| // Write rows | ||
| foreach (var result in results) | ||
| { | ||
| var values = columnsToInclude.Select(c => EscapeCsvField(c.Value(result))); | ||
| var line = string.Join(",", values); | ||
| await writer.WriteLineAsync(line); | ||
| } | ||
|
|
||
| await writer.FlushAsync(); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Escapes a field for CSV output. | ||
| /// Handles fields containing commas, quotes, or newlines. | ||
| /// </summary> | ||
| private static string EscapeCsvField(string? field) | ||
| { | ||
| if (string.IsNullOrEmpty(field)) | ||
| { | ||
| return ""; | ||
| } | ||
|
|
||
| // If the field contains comma, quote, or newline, wrap it in quotes | ||
| if (field.Contains(',') || field.Contains('"') || field.Contains('\n') || field.Contains('\r')) | ||
| { | ||
| // Replace double quotes with two double quotes | ||
| return "\"" + field.Replace("\"", "\"\"") + "\""; | ||
| } | ||
|
|
||
| return field; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -41,7 +41,7 @@ public class Program : ICommandLineOptions | |||||||||
| [Option("-d|--license-information-download-location", Description = "Specifies a folder where the application will download all licenses provided via license URLs.")] | ||||||||||
| public string? DownloadLicenseInformation { get; set; } | ||||||||||
|
|
||||||||||
| [Option("-o|--output", Description = "Specifies the output format. Valid values are Table, Markdown, Json, or JsonPretty (default: Table).")] | ||||||||||
| [Option("-o|--output", Description = "Specifies the output format. Valid values are Table, Markdown, Json, JsonPretty, or Csv (default: Table).")] | ||||||||||
| public OutputType OutputType { get; set; } = OutputType.Table; | ||||||||||
|
|
||||||||||
| [Option("-err|--error-only", Description = "When set, only validation errors are returned as result. Otherwise, all validation results are always returned.")] | ||||||||||
|
|
@@ -68,6 +68,9 @@ public class Program : ICommandLineOptions | |||||||||
| [Option("--exclude-publish-false", Description = "If set, packages with <Publish>false</Publish> metadata are excluded from analysis.")] | ||||||||||
| public bool ExcludePublishFalse { get; set; } | ||||||||||
|
|
||||||||||
| [Option("-c|--include-columns", Description = "Specifies which columns to include in the output. Provide a semicolon-separated list of column names (e.g., \"Package;Version;License\"). Available columns: Package, Version, LicenseInformationOrigin, LicenseExpression, LicenseUrl, Copyright, Authors, PackageProjectUrl, Error, ErrorContext. If omitted, all relevant columns are shown.")] | ||||||||||
| public string? IncludedColumns { get; set; } | ||||||||||
|
Comment on lines
+71
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CLI help example uses a non-existent column token. The example shows Proposed wording fix- [Option("-c|--include-columns", Description = "Specifies which columns to include in the output. Provide a semicolon-separated list of column names (e.g., \"Package;Version;License\"). Available columns: Package, Version, LicenseInformationOrigin, LicenseExpression, LicenseUrl, Copyright, Authors, PackageProjectUrl, Error, ErrorContext. If omitted, all relevant columns are shown.")]
+ [Option("-c|--include-columns", Description = "Specifies which columns to include in the output. Provide a semicolon-separated list of column names (e.g., \"Package;Version;LicenseExpression\"). Available columns: Package, Version, LicenseInformationOrigin, LicenseExpression, LicenseUrl, Copyright, Authors, PackageProjectUrl, Error, ErrorContext. If omitted, all relevant columns are shown.")]📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
|
|
||||||||||
| public async Task<int> OnExecuteAsync(CommandLineApplication app, CancellationToken cancellationToken) | ||||||||||
| { | ||||||||||
| // Check if mandatory parameters are provided | ||||||||||
|
|
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PackageProjectUrlis missing from CSV column definitions, breaking a documented include-column value.--include-columns PackageProjectUrlcurrently yields no match here and can fall back to all columns, which is surprising.Programadvertises this column, and table output supports it.Proposed fix
var allColumns = new Dictionary<string, Func<LicenseValidationResult, string?>>(StringComparer.OrdinalIgnoreCase) { ["Package"] = r => r.PackageId, ["Version"] = r => r.PackageVersion.ToString(), ["LicenseInformationOrigin"] = r => r.LicenseInformationOrigin.ToString(), ["LicenseExpression"] = r => r.License, ["LicenseUrl"] = r => r.LicenseUrl, + ["PackageProjectUrl"] = r => r.PackageProjectUrl, ["Copyright"] = r => r.Copyright, ["Authors"] = r => r.Authors, ["Description"] = r => r.Description, ["Summary"] = r => r.Summary, ["Error"] = r => r.ValidationErrors.Any() ? string.Join("; ", r.ValidationErrors.Select(e => e.Error)) : null, ["ErrorContext"] = r => r.ValidationErrors.Any() ? string.Join("; ", r.ValidationErrors.Select(e => e.Context)) : null };📝 Committable suggestion
🤖 Prompt for AI Agents