Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
PrivateAssets="all"
Condition="$(MSBuildProjectExtension) == '.csproj'" />
<PackageReference Include="SonarAnalyzer.CSharp"
Version="10.12.0.118525"
Version="10.14.0.120626"
PrivateAssets="all"
Condition="$(MSBuildProjectExtension) == '.csproj'" />
<PackageReference Include="Roslynator.Analyzers"
Expand Down
2 changes: 1 addition & 1 deletion src/KubeOps.Abstractions/KubeOps.Abstractions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<ItemGroup>
<PackageReference Include="JsonPatch.Net" Version="3.3.0" />
<PackageReference Include="KubernetesClient" Version="16.0.7" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.6"/>
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.7"/>
<PackageReference Include="ZiggyCreatures.FusionCache" Version="2.3.0" />
</ItemGroup>

Expand Down
30 changes: 18 additions & 12 deletions src/KubeOps.Cli/Arguments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ namespace KubeOps.Cli;

internal static class Arguments
{
public static readonly Argument<FileInfo?> SolutionOrProjectFile = new(
"sln/csproj file",
() =>
public static readonly Argument<FileInfo> SolutionOrProjectFile = new("sln/csproj file")
{
DefaultValueFactory = result =>
{
var projectFile
= Directory.EnumerateFiles(
Expand All @@ -24,20 +24,26 @@ var slnFile
"*.sln")
.Select(f => new FileInfo(f))
.FirstOrDefault();

return (projectFile, slnFile) switch
var file = (projectFile, slnFile) switch
{
({ } prj, _) => prj,
(_, { } sln) => sln,
_ => null,
};

if (file is not null)
{
return file;
}

result.AddError("No solution or project file found in the current directory, and none was provided.");
return new FileInfo("not-found");
},
"A solution or project file where entities are located. " +
"If omitted, the current directory is searched for a *.csproj or *.sln file. " +
"If an *.sln file is used, all projects in the solution (with the newest framework) will be searched for entities. " +
"This behaviour can be filtered by using the --project and --target-framework option.");
Description = "A solution or project file where entities are located. " +
"If omitted, the current directory is searched for a *.csproj or *.sln file. " +
"If an *.sln file is used, all projects in the solution (with the newest framework) will be searched for entities. " +
"This behaviour can be filtered by using the --project and --target-framework option.",
};

public static readonly Argument<string> OperatorName = new(
"name",
"Name of the operator.");
public static readonly Argument<string> OperatorName = new("name") { Description = "Name of the operator.", };
}
5 changes: 2 additions & 3 deletions src/KubeOps.Cli/Commands/Generator/Generate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ public static Command Command
{
OperatorGenerator.Command,
};
cmd.AddAlias("gen");
cmd.AddAlias("g");
cmd.SetHandler(ctx => ctx.HelpBuilder.Write(cmd, Console.Out));
cmd.Aliases.Add("gen");
cmd.Aliases.Add("g");

return cmd;
}
Expand Down
28 changes: 15 additions & 13 deletions src/KubeOps.Cli/Commands/Generator/OperatorGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,21 @@ public static Command Command
Arguments.OperatorName,
Arguments.SolutionOrProjectFile,
};
cmd.AddAlias("op");
cmd.SetHandler(ctx => Handler(AnsiConsole.Console, ctx));
cmd.Aliases.Add("op");
cmd.SetAction(result => Handler(AnsiConsole.Console, result));

return cmd;
}
}

internal static async Task Handler(IAnsiConsole console, InvocationContext ctx)
internal static async Task<int> Handler(IAnsiConsole console, ParseResult parseResult)
{
var name = ctx.ParseResult.GetValueForArgument(Arguments.OperatorName);
var file = ctx.ParseResult.GetValueForArgument(Arguments.SolutionOrProjectFile);
var outPath = ctx.ParseResult.GetValueForOption(Options.OutputPath);
var format = ctx.ParseResult.GetValueForOption(Options.OutputFormat);
var dockerImage = ctx.ParseResult.GetValueForOption(Options.AccessibleDockerImage)!;
var dockerImageTag = ctx.ParseResult.GetValueForOption(Options.AccessibleDockerTag)!;
var name = parseResult.GetValue(Arguments.OperatorName) ?? "operator";
var file = parseResult.GetValue(Arguments.SolutionOrProjectFile);
var outPath = parseResult.GetValue(Options.OutputPath);
var format = parseResult.GetValue(Options.OutputFormat);
var dockerImage = parseResult.GetValue(Options.AccessibleDockerImage)!;
var dockerImageTag = parseResult.GetValue(Options.AccessibleDockerTag)!;

var result = new ResultOutput(console, format);
console.WriteLine("Generate operator resources.");
Expand All @@ -65,8 +65,8 @@ internal static async Task Handler(IAnsiConsole console, InvocationContext ctx)
{ Extension: ".sln", Exists: true } => await AssemblyLoader.ForSolution(
console,
file,
ctx.ParseResult.GetValueForOption(Options.SolutionProjectRegex),
ctx.ParseResult.GetValueForOption(Options.TargetFramework)),
parseResult.GetValue(Options.SolutionProjectRegex),
parseResult.GetValue(Options.TargetFramework)),
{ Exists: false } => throw new FileNotFoundException($"The file {file.Name} does not exist."),
_ => throw new NotSupportedException("Only *.csproj and *.sln files are supported."),
};
Expand Down Expand Up @@ -111,7 +111,7 @@ internal static async Task Handler(IAnsiConsole console, InvocationContext ctx)
new DeploymentGenerator(format).Generate(result);

console.MarkupLine("[green]Generate CRDs.[/]");
new CrdGenerator(parser, Array.Empty<byte>(), format).Generate(result);
new CrdGenerator(parser, [], format).Generate(result);
}

result.Add(
Expand Down Expand Up @@ -158,7 +158,7 @@ internal static async Task Handler(IAnsiConsole console, InvocationContext ctx)

if (outPath is not null)
{
if (ctx.ParseResult.GetValueForOption(Options.ClearOutputPath))
if (parseResult.GetValue(Options.ClearOutputPath))
{
console.MarkupLine("[yellow]Clear output path.[/]");
try
Expand All @@ -182,5 +182,7 @@ internal static async Task Handler(IAnsiConsole console, InvocationContext ctx)
{
result.Write();
}

return ExitCodes.Success;
}
}
24 changes: 12 additions & 12 deletions src/KubeOps.Cli/Commands/Management/Install.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,29 +30,29 @@ public static Command Command
Options.TargetFramework,
Arguments.SolutionOrProjectFile,
};
cmd.AddAlias("i");
cmd.SetHandler(ctx => Handler(
cmd.Aliases.Add("i");
cmd.SetAction(result => Handler(
AnsiConsole.Console,
new Kubernetes(KubernetesClientConfiguration.BuildDefaultConfig()),
ctx));
result));

return cmd;
}
}

internal static async Task Handler(IAnsiConsole console, IKubernetes client, InvocationContext ctx)
internal static async Task<int> Handler(IAnsiConsole console, IKubernetes client, ParseResult parseResult)
{
var file = ctx.ParseResult.GetValueForArgument(Arguments.SolutionOrProjectFile);
var force = ctx.ParseResult.GetValueForOption(Options.Force);
var file = parseResult.GetValue(Arguments.SolutionOrProjectFile);
var force = parseResult.GetValue(Options.Force);

var parser = file switch
{
{ Extension: ".csproj", Exists: true } => await AssemblyLoader.ForProject(console, file),
{ Extension: ".sln", Exists: true } => await AssemblyLoader.ForSolution(
console,
file,
ctx.ParseResult.GetValueForOption(Options.SolutionProjectRegex),
ctx.ParseResult.GetValueForOption(Options.TargetFramework)),
parseResult.GetValue(Options.SolutionProjectRegex),
parseResult.GetValue(Options.TargetFramework)),
{ Exists: false } => throw new FileNotFoundException($"The file {file.Name} does not exist."),
_ => throw new NotSupportedException("Only *.csproj and *.sln files are supported."),
};
Expand All @@ -62,8 +62,7 @@ internal static async Task Handler(IAnsiConsole console, IKubernetes client, Inv
if (crds.Count == 0)
{
console.WriteLine("No CRDs found. Exiting.");
ctx.ExitCode = ExitCodes.Success;
return;
return ExitCodes.Success;
}

console.WriteLine($"Found {crds.Count} CRDs.");
Expand All @@ -84,8 +83,7 @@ internal static async Task Handler(IAnsiConsole console, IKubernetes client, Inv
$"""[yellow]CRD "{crd.Spec.Group}/{crd.Spec.Names.Kind}" already exists.[/]""");
if (!force && !await console.ConfirmAsync("[yellow]Should the CRD be overwritten?[/]"))
{
ctx.ExitCode = ExitCodes.Aborted;
return;
return ExitCodes.Aborted;
}

crd.Metadata.ResourceVersion = existing.ResourceVersion();
Expand All @@ -112,5 +110,7 @@ internal static async Task Handler(IAnsiConsole console, IKubernetes client, Inv
throw;
}
}

return ExitCodes.Success;
}
}
24 changes: 12 additions & 12 deletions src/KubeOps.Cli/Commands/Management/Uninstall.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,29 +30,29 @@ public static Command Command
Options.TargetFramework,
Arguments.SolutionOrProjectFile,
};
cmd.AddAlias("u");
cmd.SetHandler(ctx => Handler(
cmd.Aliases.Add("u");
cmd.SetAction(result => Handler(
AnsiConsole.Console,
new Kubernetes(KubernetesClientConfiguration.BuildDefaultConfig()),
ctx));
result));

return cmd;
}
}

internal static async Task Handler(IAnsiConsole console, IKubernetes client, InvocationContext ctx)
internal static async Task<int> Handler(IAnsiConsole console, IKubernetes client, ParseResult parseResult)
{
var file = ctx.ParseResult.GetValueForArgument(Arguments.SolutionOrProjectFile);
var force = ctx.ParseResult.GetValueForOption(Options.Force);
var file = parseResult.GetValue(Arguments.SolutionOrProjectFile);
var force = parseResult.GetValue(Options.Force);

var parser = file switch
{
{ Extension: ".csproj", Exists: true } => await AssemblyLoader.ForProject(console, file),
{ Extension: ".sln", Exists: true } => await AssemblyLoader.ForSolution(
console,
file,
ctx.ParseResult.GetValueForOption(Options.SolutionProjectRegex),
ctx.ParseResult.GetValueForOption(Options.TargetFramework)),
parseResult.GetValue(Options.SolutionProjectRegex),
parseResult.GetValue(Options.TargetFramework)),
{ Exists: false } => throw new FileNotFoundException($"The file {file.Name} does not exist."),
_ => throw new NotSupportedException("Only *.csproj and *.sln files are supported."),
};
Expand All @@ -62,15 +62,13 @@ internal static async Task Handler(IAnsiConsole console, IKubernetes client, Inv
if (crds.Count == 0)
{
console.WriteLine("No CRDs found. Exiting.");
ctx.ExitCode = ExitCodes.Success;
return;
return ExitCodes.Success;
}

console.WriteLine($"Found {crds.Count} CRDs.");
if (!force && !await console.ConfirmAsync("[red]Should the CRDs be uninstalled?[/]", false))
{
ctx.ExitCode = ExitCodes.Aborted;
return;
return ExitCodes.Aborted;
}

console.WriteLine($"""Starting uninstall from cluster with url "{client.BaseUri}".""");
Expand Down Expand Up @@ -109,5 +107,7 @@ internal static async Task Handler(IAnsiConsole console, IKubernetes client, Inv
throw;
}
}

return ExitCodes.Success;
}
}
4 changes: 2 additions & 2 deletions src/KubeOps.Cli/Commands/Utilities/Version.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ public static Command Command
var cmd = new Command(
"api-version",
"Prints the actual server version of the connected kubernetes cluster.");
cmd.AddAlias("av");
cmd.SetHandler(() =>
cmd.Aliases.Add("av");
cmd.SetAction(_ =>
Handler(AnsiConsole.Console, new Kubernetes(KubernetesClientConfiguration.BuildDefaultConfig())));

return cmd;
Expand Down
2 changes: 1 addition & 1 deletion src/KubeOps.Cli/KubeOps.Cli.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta6.25358.103" />
</ItemGroup>

<ItemGroup>
Expand Down
86 changes: 47 additions & 39 deletions src/KubeOps.Cli/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,47 +11,55 @@ namespace KubeOps.Cli;

internal static class Options
{
public static readonly Option<OutputFormat> OutputFormat = new(
"--format",
() => Output.OutputFormat.Yaml,
"The format of the generated output.");

public static readonly Option<string?> OutputPath = new(
"--out",
"The path the command will write the files to. If omitted, prints output to console.");

public static readonly Option<string?> TargetFramework = new(
["--target-framework", "--tfm"],
description: "Target framework of projects in the solution to search for entities. " +
"If omitted, the newest framework is used.");

public static readonly Option<Regex?> SolutionProjectRegex = new(
"--project",
parseArgument: result =>
public static readonly Option<OutputFormat> OutputFormat = new("--format")
{
Description = "The format of the generated output.",
DefaultValueFactory = _ => Output.OutputFormat.Yaml,
};

public static readonly Option<string?> OutputPath = new("--out")
{
Description = "The path the command will write the files to. If omitted, prints output to console.",
};

public static readonly Option<string?> TargetFramework = new("--target-framework", "--tfm")
{
Description = "Target framework of projects in the solution to search for entities. " +
"If omitted, the newest framework is used.",
};

public static readonly Option<Regex?> SolutionProjectRegex = new("--project")
{
Description = "Regex pattern to filter projects in the solution to search for entities. " +
"If omitted, all projects are searched.",
CustomParser = result =>
{
var value = result.Tokens.Single().Value;
return new Regex(value);
},
description: "Regex pattern to filter projects in the solution to search for entities. " +
"If omitted, all projects are searched.");

public static readonly Option<bool> Force = new(
["--force", "-f"],
() => false,
description: "Do not bother the user with questions and just do it.");

public static readonly Option<bool> ClearOutputPath = new(
["--clear-out"],
() => false,
description: "Clear the output path before generating resources.");

public static readonly Option<string> AccessibleDockerImage = new(
"--docker-image",
() => "accessible-docker-image",
description: "An accessible docker image to deploy");

public static readonly Option<string> AccessibleDockerTag = new(
"--docker-image-tag",
() => "latest",
description: "Tag for an accessible docker image to deploy");
};

public static readonly Option<bool> Force = new("--force", "-f")
{
Description = "Do not bother the user with questions and just do it.",
DefaultValueFactory = _ => false,
};

public static readonly Option<bool> ClearOutputPath = new("--clear-out")
{
Description = "Clear the output path before generating resources.",
DefaultValueFactory = _ => false,
};

public static readonly Option<string> AccessibleDockerImage = new("--docker-image")
{
Description = "An accessible docker image to deploy.",
DefaultValueFactory = _ => "accessible-docker-image",
};

public static readonly Option<string> AccessibleDockerTag = new("--docker-image-tag")
{
Description = "Tag for an accessible docker image to deploy.",
DefaultValueFactory = _ => "latest",
};
}
Loading
Loading