Skip to content

Commit

Permalink
(chocolatey#3381) Add new rule command
Browse files Browse the repository at this point in the history
This adds a new command called ´rule` with an alias of `rules` to be
able to view any Validation Rules that have been implemented by
Chocolatey CLI, or the details of a specific view.

This allows a user to see what is implemented when they are packaging
their Chocolatey CLI package. This is intended to be used in the future
to enhance other functionality.
  • Loading branch information
AdmiringWorm committed Jan 15, 2024
1 parent a7f72e0 commit 3570985
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/chocolatey/chocolatey.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Microsoft.CodeAnalysis.BannedApiAnalyzers.3.3.3\build\Microsoft.CodeAnalysis.BannedApiAnalyzers.props" Condition="Exists('..\packages\Microsoft.CodeAnalysis.BannedApiAnalyzers.3.3.3\build\Microsoft.CodeAnalysis.BannedApiAnalyzers.props')" />
<PropertyGroup>
Expand Down Expand Up @@ -204,6 +204,7 @@
<Compile Include="infrastructure.app\attributes\MultiServiceAttribute.cs" />
<Compile Include="infrastructure.app\commands\ChocolateyCacheCommand.cs" />
<Compile Include="infrastructure.app\commands\ChocolateyListCommand.cs" />
<Compile Include="infrastructure.app\commands\ChocolateyRuleCommand.cs" />
<Compile Include="infrastructure.app\commands\ChocolateyTemplateCommand.cs" />
<Compile Include="infrastructure.app\commands\ChocolateyCommandBase.cs" />
<Compile Include="infrastructure.app\domain\ApiKeyCommandType.cs" />
Expand Down
150 changes: 150 additions & 0 deletions src/chocolatey/infrastructure.app/commands/ChocolateyRuleCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
namespace chocolatey.infrastructure.app.commands
{
using System;
using System.Collections.Generic;
using System.Linq;
using chocolatey.infrastructure.app.attributes;
using chocolatey.infrastructure.app.configuration;
using chocolatey.infrastructure.commandline;
using chocolatey.infrastructure.commands;
using chocolatey.infrastructure.logging;
using chocolatey.infrastructure.rules;
using chocolatey.infrastructure.services;

[CommandFor("rule", "view or list implemented package rules.", Version = "2.3.0")]
[CommandFor("rules", "view or list implemented package rules.", Version = "2.3.0")]
public class ChocolateyRuleCommand : ChocolateyCommandBase, ICommand
{
private readonly IRuleService _ruleService;

public ChocolateyRuleCommand(IRuleService ruleService)
{
_ruleService = ruleService ?? throw new ArgumentNullException(nameof(ruleService));
}

public void ConfigureArgumentParser(OptionSet optionSet, ChocolateyConfiguration configuration)
{
optionSet
.Add("id=",
"The identifier of the rule to show more details about.",
option => configuration.Input = option);
}

public void ParseAdditionalArguments(IList<string> unparsedArguments, ChocolateyConfiguration configuration)
{
}

public void Validate(ChocolateyConfiguration configuration)
{
// Nothing to validate
}

public void DryRun(ChocolateyConfiguration configuration)
{
Run(configuration);
}

public void Run(ChocolateyConfiguration config)
{
var implementedRules = _ruleService.GetAllAvailableRules()
.OrderBy(r => r.Id);

if (!string.IsNullOrEmpty(config.Input))
{
var foundRule = implementedRules.FirstOrDefault(i => i.Id.IsEqualTo(config.Input));

// Since the return value is a structure, it will never be null.
// As such we check that the identifier is not empty.
if (string.IsNullOrEmpty(foundRule.Id))
{
throw new ApplicationException("No rule with the identifier {0} could be found.".FormatWith(config.Input));
}

this.Log().Info(@"ID: {0} | Severity: {1}
Summary: {2}
Help URL: {3}",
foundRule.Id,
foundRule.Severity,
foundRule.Summary,
foundRule.HelpUrl);

return;
}

if (config.RegularOutput)
{
this.Log().Info(ChocolateyLoggers.Important, "Implemented Package Rules");
}

OutputRules("Error/Required", config, implementedRules.Where(r => r.Severity == RuleType.Error).ToList());
OutputRules("Warning/Guideline", config, implementedRules.Where(r => r.Severity == RuleType.Warning).ToList());
OutputRules("Information/Suggestion", config, implementedRules.Where(r => r.Severity == RuleType.Information).ToList());
OutputRules("Notes", config, implementedRules.Where(r => r.Severity == RuleType.Note).ToList());
OutputRules("Disabled", config, implementedRules.Where(r => r.Severity == RuleType.None).ToList());
}

protected virtual void OutputRules(string type, ChocolateyConfiguration config, IReadOnlyList<ImmutableRule> rules)
{
if (config.RegularOutput)
{
this.Log().Info("");
this.Log().Info(ChocolateyLoggers.Important, type + " Rules");
this.Log().Info("");

if (rules.Count == 0)
{
this.Log().Info("No implemented " + type + " rules available.");

return;
}
}

foreach (var rule in rules)
{
if (config.RegularOutput)
{
this.Log().Info("{0}: {1}", rule.Id, rule.Summary);
}
else
{
this.Log().Info("{0}|{1}|{2}|{3}", rule.Severity, rule.Id, rule.Summary, rule.HelpUrl);
}
}
}

public bool MayRequireAdminAccess()
{
return false;
}

#pragma warning disable IDE1006
[Obsolete("This overload is deprecated and will be removed in v3.")]
public virtual void configure_argument_parser(OptionSet optionSet, ChocolateyConfiguration configuration)
=> ConfigureArgumentParser(optionSet, configuration);

[Obsolete("This overload is deprecated and will be removed in v3.")]
public virtual void handle_additional_argument_parsing(IList<string> unparsedArguments, ChocolateyConfiguration configuration)
=> ParseAdditionalArguments(unparsedArguments, configuration);

[Obsolete("This overload is deprecated and will be removed in v3.")]
public virtual void handle_validation(ChocolateyConfiguration configuration)
=> Validate(configuration);

[Obsolete("This overload is deprecated and will be removed in v3.")]
public virtual void help_message(ChocolateyConfiguration configuration)
=> HelpMessage(configuration);

[Obsolete("This overload is deprecated and will be removed in v3.")]
public virtual void noop(ChocolateyConfiguration configuration)
=> DryRun(configuration);

[Obsolete("This overload is deprecated and will be removed in v3.")]
public virtual void run(ChocolateyConfiguration configuration)
=> Run(configuration);

[Obsolete("This overload is deprecated and will be removed in v3.")]
public virtual bool may_require_admin_access()
=> MayRequireAdminAccess();
#pragma warning restore IDE1006
}
}

0 comments on commit 3570985

Please sign in to comment.