refactor(cli): rename audit-log to audit-config with deprecation alias (#23 M8)
This commit is contained in:
@@ -4,11 +4,50 @@ using ScadaLink.Commons.Messages.Management;
|
||||
|
||||
namespace ScadaLink.CLI.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// The <c>scadalink audit-config</c> command group: views the configuration-change
|
||||
/// audit log (the <c>IAuditService</c> trail of admin edits — distinct from the
|
||||
/// centralized append-only Audit Log served by <see cref="AuditCommands"/>).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Renamed from <c>audit-log</c> in #23 M8-T7 to avoid confusion with the new
|
||||
/// <c>scadalink audit</c> group. The old <c>audit-log</c> name is retained as a
|
||||
/// deprecated alias; <see cref="DeprecatedAlias"/> still resolves the full subcommand
|
||||
/// tree, and <c>Program.cs</c> prints a deprecation warning when it is used.
|
||||
/// </remarks>
|
||||
public static class AuditLogCommands
|
||||
{
|
||||
/// <summary>The deprecated alias kept for backward compatibility with the old command name.</summary>
|
||||
public const string DeprecatedAlias = "audit-log";
|
||||
|
||||
/// <summary>The deprecation warning emitted when the old <c>audit-log</c> name is used.</summary>
|
||||
public const string DeprecationWarning =
|
||||
"Warning: 'audit-log' is deprecated and will be removed in a future release. "
|
||||
+ "Use 'audit-config' instead.";
|
||||
|
||||
/// <summary>
|
||||
/// Writes the <see cref="DeprecationWarning"/> to <paramref name="stderr"/> when the
|
||||
/// CLI was invoked via the deprecated <c>audit-log</c> command name (i.e. the first
|
||||
/// argument is <see cref="DeprecatedAlias"/>). The command itself still works — it is
|
||||
/// an alias of <c>audit-config</c> — so this only adds the migration warning.
|
||||
/// Factored out of <c>Program.cs</c> so it is unit-testable without spawning a process.
|
||||
/// </summary>
|
||||
public static void WriteDeprecationWarningIfNeeded(string[] args, TextWriter stderr)
|
||||
{
|
||||
if (args.Length > 0
|
||||
&& string.Equals(args[0], DeprecatedAlias, StringComparison.Ordinal))
|
||||
{
|
||||
stderr.WriteLine(DeprecationWarning);
|
||||
}
|
||||
}
|
||||
|
||||
public static Command Build(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var command = new Command("audit-log") { Description = "Query audit logs" };
|
||||
var command = new Command("audit-config") { Description = "Query the configuration-change audit log" };
|
||||
// Backward-compatible alias for the pre-M8 `audit-log` name. The alias keeps
|
||||
// full subcommand parity automatically; the deprecation warning is emitted by
|
||||
// the args[0] check in Program.cs.
|
||||
command.Aliases.Add(DeprecatedAlias);
|
||||
|
||||
command.Add(BuildQuery(urlOption, formatOption, usernameOption, passwordOption));
|
||||
|
||||
|
||||
@@ -39,5 +39,10 @@ rootCommand.SetAction(_ =>
|
||||
Console.WriteLine("Use --help to see available commands.");
|
||||
});
|
||||
|
||||
// Deprecation notice for the pre-M8 `audit-log` command name. The command itself
|
||||
// still works (it is an alias of `audit-config`), but using the old name emits a
|
||||
// warning to stderr so scripts can be migrated.
|
||||
AuditLogCommands.WriteDeprecationWarningIfNeeded(args, Console.Error);
|
||||
|
||||
var parseResult = CommandLineParser.Parse(rootCommand, args);
|
||||
return await parseResult.InvokeAsync();
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
using System.CommandLine;
|
||||
using ScadaLink.CLI.Commands;
|
||||
|
||||
namespace ScadaLink.CLI.Tests.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for the <c>audit-log</c> → <c>audit-config</c> rename (Audit Log #23 M8-T7):
|
||||
/// the new name parses, the deprecated <c>audit-log</c> alias still resolves the full
|
||||
/// subcommand tree and emits a stderr deprecation warning, and the renamed group does
|
||||
/// not collide with the distinct <c>audit</c> group from Bundle A.
|
||||
/// </summary>
|
||||
public class AuditConfigDeprecationTests
|
||||
{
|
||||
private static readonly Option<string> Url = new("--url") { Recursive = true };
|
||||
private static readonly Option<string> Username = new("--username") { Recursive = true };
|
||||
private static readonly Option<string> Password = new("--password") { Recursive = true };
|
||||
private static readonly Option<string> Format = CliOptions.CreateFormatOption();
|
||||
|
||||
private static RootCommand BuildRoot()
|
||||
{
|
||||
var root = new RootCommand();
|
||||
root.Add(Url);
|
||||
root.Add(Username);
|
||||
root.Add(Password);
|
||||
root.Add(Format);
|
||||
root.Add(AuditCommands.Build(Url, Format, Username, Password));
|
||||
root.Add(AuditLogCommands.Build(Url, Format, Username, Password));
|
||||
return root;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AuditConfig_Query_Works()
|
||||
{
|
||||
// The new `audit-config query` name parses cleanly with no errors.
|
||||
var root = BuildRoot();
|
||||
var parse = root.Parse(new[] { "audit-config", "query", "--user", "alice" });
|
||||
Assert.Empty(parse.Errors);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AuditLog_Query_StillWorks_ButEmitsDeprecationWarning_ToStderr()
|
||||
{
|
||||
// The deprecated `audit-log` alias still resolves the full subcommand tree...
|
||||
var root = BuildRoot();
|
||||
var parse = root.Parse(new[] { "audit-log", "query", "--user", "alice" });
|
||||
Assert.Empty(parse.Errors);
|
||||
|
||||
// ...and invoking via the old name emits the deprecation warning to stderr.
|
||||
var stderr = new StringWriter();
|
||||
AuditLogCommands.WriteDeprecationWarningIfNeeded(
|
||||
new[] { "audit-log", "query" }, stderr);
|
||||
var warning = stderr.ToString();
|
||||
Assert.Contains("deprecated", warning);
|
||||
Assert.Contains("audit-config", warning);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeprecationWarning_NotEmitted_ForNewName()
|
||||
{
|
||||
// The new `audit-config` name must not trigger the deprecation warning.
|
||||
var stderr = new StringWriter();
|
||||
AuditLogCommands.WriteDeprecationWarningIfNeeded(
|
||||
new[] { "audit-config", "query" }, stderr);
|
||||
Assert.Equal("", stderr.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeprecationWarning_NotEmitted_ForUnrelatedCommand()
|
||||
{
|
||||
var stderr = new StringWriter();
|
||||
AuditLogCommands.WriteDeprecationWarningIfNeeded(
|
||||
new[] { "audit", "query" }, stderr);
|
||||
Assert.Equal("", stderr.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Audit_And_AuditConfig_AreDistinctCommands_NoConflict()
|
||||
{
|
||||
var root = BuildRoot();
|
||||
|
||||
var auditNames = new[] { "audit", "audit-config" };
|
||||
foreach (var name in auditNames)
|
||||
{
|
||||
var match = root.Subcommands.SingleOrDefault(c => c.Name == name);
|
||||
Assert.NotNull(match);
|
||||
}
|
||||
|
||||
// The two groups are distinct objects with distinct subcommand sets:
|
||||
// `audit` has query/export/verify-chain; `audit-config` has only query.
|
||||
var audit = root.Subcommands.Single(c => c.Name == "audit");
|
||||
var auditConfig = root.Subcommands.Single(c => c.Name == "audit-config");
|
||||
Assert.NotSame(audit, auditConfig);
|
||||
Assert.Contains(audit.Subcommands, c => c.Name == "verify-chain");
|
||||
Assert.DoesNotContain(auditConfig.Subcommands, c => c.Name == "verify-chain");
|
||||
|
||||
// `audit-config` carries the deprecated `audit-log` alias; `audit` does not.
|
||||
Assert.Contains(AuditLogCommands.DeprecatedAlias, auditConfig.Aliases);
|
||||
Assert.DoesNotContain(AuditLogCommands.DeprecatedAlias, audit.Aliases);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user