Skip to content

Switch to System.CommandLine for .NET Framework compatibility#402

Merged
sensslen merged 7 commits into
mainfrom
copilot/switch-to-system-commandline
Jan 21, 2026
Merged

Switch to System.CommandLine for .NET Framework compatibility#402
sensslen merged 7 commits into
mainfrom
copilot/switch-to-system-commandline

Conversation

Copy link
Copy Markdown

Copilot AI commented Jan 21, 2026

McMaster.CommandLine dropped .NET Standard 2.0 support, breaking .NET Framework 4.7.2 compatibility.

Changes

  • Package: Replaced McMaster.Extensions.CommandLineUtils with System.CommandLine (2.0.2)
  • API Migration: Refactored from attribute-decorated properties to explicit option definitions
    // Before: McMaster.CommandLine
    [Option(ShortName = "i", LongName = "input", Description = "...")]
    public string? InputFile { get; }
    
    // After: System.CommandLine
    var inputFileOption = new Option<string?>("-i", "--input")
    {
        Description = "The project (or solution) file for which to analyze dependency licenses"
    };
  • Architecture: Converted from instance-based execution model to static methods with explicit parameter passing
  • Entry Points: Updated NuGetLicenseCore and NuGetLicenseFramework to invoke RootCommand instead of CommandLineApplication.ExecuteAsync<T>()
  • Shell Completion: Added completion command to generate shell completion scripts for bash, PowerShell, and zsh

Shell Completion Support

Users can now enable tab completion for the tool:

# Bash
source <(nuget-license completion --shell bash)

# PowerShell
nuget-license completion --shell powershell | Out-String | Invoke-Expression

# Zsh
source <(nuget-license completion --shell zsh)

The completion scripts leverage System.CommandLine's built-in [suggest] directive to provide context-aware completions for all command options.

Compatibility

All 16 command line options preserved with identical behavior. Version option now handled automatically by System.CommandLine from assembly attributes. All target frameworks supported: net8.0, net9.0, net10.0, net472.

Original prompt

This section details on the original issue you should resolve

<issue_title>Switch to System.Commandline</issue_title>
<issue_description>McMaster.Commandline no longer supports .net standard 2.0 and therefore is not compatible with .net framework. Therefore we should switch to another library to parse command line arguments. System.CommandLine seems the obvious choice (https://www.nuget.org/packages/System.CommandLine)</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 4 commits January 21, 2026 08:21
Co-authored-by: sensslen <3428860+sensslen@users.noreply.github.com>
Co-authored-by: sensslen <3428860+sensslen@users.noreply.github.com>
Co-authored-by: sensslen <3428860+sensslen@users.noreply.github.com>
Co-authored-by: sensslen <3428860+sensslen@users.noreply.github.com>
Copilot AI changed the title [WIP] Switch to System.CommandLine for argument parsing Switch to System.CommandLine for .NET Framework compatibility Jan 21, 2026
Copilot AI requested a review from sensslen January 21, 2026 08:35
@sensslen
Copy link
Copy Markdown
Owner

@copilot System.Commandline is available in version 2.0.2. we should avoid beta versions

Copy link
Copy Markdown
Author

Copilot AI commented Jan 21, 2026

@copilot System.Commandline is available in version 2.0.2. we should avoid beta versions

I've investigated the System.CommandLine versioning, and there's a complication:

Two different API versions exist:

  • Stable 2.0.2: Uses older API (no AddOption/SetHandler methods)
  • Pre-release 2.0.0-beta4+: Uses modern API (which our current code uses)

The stable 2.0.2 release actually has an older, incompatible API. To avoid beta versions while keeping the modern API, we have these options:

  1. Use latest RC (2.0.0-rc.2.25502.107) - Still pre-release but closer to stable than beta4
  2. Rewrite for stable 2.0.2 - Requires significant code changes to use the old API

Which approach would you prefer? If you want to stick with non-beta/non-RC versions, I'll need to rewrite the command line parsing to use the older 2.0.2 API.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 21, 2026

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Comment @coderabbitai help to get the list of available commands and usage tips.

@sensslen sensslen marked this pull request as ready for review January 21, 2026 12:18
@sensslen
Copy link
Copy Markdown
Owner

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 21, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@sensslen
Copy link
Copy Markdown
Owner

@copilot Now add command line autocomplete

Copy link
Copy Markdown
Author

Copilot AI commented Jan 21, 2026

@copilot Now add command line autocomplete

I've added command line autocomplete support in commit e2ec47a.

The tool now includes a completion command that generates shell completion scripts for bash, PowerShell, and zsh:

Usage examples:

# Bash
nuget-license completion --shell bash > ~/.nuget-license-completion.sh
source ~/.nuget-license-completion.sh

# Or add to ~/.bashrc:
source <(nuget-license completion --shell bash)

# PowerShell
nuget-license completion --shell powershell | Out-String | Invoke-Expression

# Zsh
nuget-license completion --shell zsh > ~/.nuget-license-completion.zsh
source ~/.nuget-license-completion.zsh

The completion scripts leverage System.CommandLine's built-in [suggest] directive to provide option and command completions. Users can now tab-complete all command options and values.

@sensslen
Copy link
Copy Markdown
Owner

@copilot the output I get is Description:
A .net tool to print and validate the licenses of .net code. This tool supports .NET (Core), .NET Standard and .NET
Framework projects.

Usage:
NuGetLicenseCore [options]

Options:
-i, --input The project (or solution) file for which to analyze dependency
licenses
-ji, --json-input File in json format that contains an array of all files to be
evaluated. The Files can either point to a project or a
solution.
-t, --include-transitive If set, the whole license tree is followed in order to
determine all nuget's used by the projects
-a, --allowed-license-types File in json format that contains an array of all allowed
license types
-ignore, --ignored-packages File in json format that contains an array of nuget package
names to ignore (e.g. useful for nuget packages built
in-house). Note that even though the packages are ignored,
their transitive dependencies are not. Wildcard characters ()
are supported to specify ranges of ignored packages.
-mapping, --licenseurl-to-license-mappings File in json format that contains a dictionary to map license
urls to licenses.
-override, --override-package-information File in json format that contains a list of package and license
information which should be used in favor of the online
version. This option can be used to override the license type
of packages that e.g. specify the license as file.
-d, --license-information-download-location When set, the application downloads all licenses given using a
license URL to the specified folder.
-o, --output <Json|JsonPretty|Markdown|Table> This parameter allows to choose between tabular and json
output. [default: Table]
-err, --error-only If this option is set and there are license validation errors,
only the errors are returned as result. Otherwise all
validation results are always returned.
-include-ignored, --include-ignored-packages If this option is set, the packages that are ignored from
validation are still included in the output.
-exclude-projects, --exclude-projects-matching This option allows to specify project name(s) to exclude from
the analysis. This can be useful to exclude test projects from
the analysis when supplying a solution file as input. Wildcard
characters (
) are supported to specify ranges of ignored
projects. The input can either be a file name containing a list
of project names in json format or a plain string that is then
used as a single entry.
-isp, --include-shared-projects If set, shared projects (.shproj) will be included in the
analysis. By default, shared projects are excluded.
-f, --target-framework This option allows to select a Target framework moniker
(https://learn.microsoft.com/en-us/dotnet/standard/frameworks)
for which to analyze dependencies.
-fo, --file-output The destination file to put the validation output to. If
omitted, the output is printed to the console.
-file-mapping, --licensefile-to-license-mappings File in json format that contains a dictionary to map license
files to licenses.
-?, -h, --help Show help and usage information
--version Show version information. Unfortunately the Usage section can be very misleading, as renaming the executable does not rename the usage. Get rid of it

Copilot stopped work on behalf of sensslen due to an error January 21, 2026 12:51
@sensslen sensslen force-pushed the copilot/switch-to-system-commandline branch from e2ec47a to 5b906ce Compare January 21, 2026 12:51
@sensslen sensslen merged commit 7c61c55 into main Jan 21, 2026
82 checks passed
@sensslen sensslen deleted the copilot/switch-to-system-commandline branch January 21, 2026 12:52
@sonarqubecloud
Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Switch to System.Commandline

2 participants