|
| 1 | +This repository contains the code for the `Plsgd.System.Command.Abstractions` libraries and the `dotnet-command` global tool. |
| 2 | + |
| 3 | +## Packages |
| 4 | + |
| 5 | +| Package | Version | Description | |
| 6 | +| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | |
| 7 | +| `Plsgd.System.Command.Abstractions` | [](https://nuget.org/packages/Plsgd.System.Command.Abstractions) | user-defined C# command, command parser, migration command, ... | |
| 8 | +| `dotnet-command` | [](https://nuget.org/packages/plsgd-dotnet-command) | A command-line tool to call user-defined C# command based on `Plsgd.System.Command.Abstractions`. | |
| 9 | + |
| 10 | +## Documentation |
| 11 | + |
| 12 | +The need behind this package was to be able to execute some operations like update external datas of a provider, migrate some project datas who are not stored in database, etc... without depending on a project and in C# in order to be easily testable by the project containing the commands. |
| 13 | + |
| 14 | +### `Plsgd.System.Command.Abstractions` |
| 15 | + |
| 16 | +This package contains all abstractions who can be used to create your command to call. You will have to import it in the project containing your command. The root namespace is `System.Command`. |
| 17 | + |
| 18 | +### `dotnet-command` |
| 19 | + |
| 20 | +This is the tool to use in order to call the commands that you've created. |
| 21 | + |
| 22 | +#### Install the `dotnet-command` tool |
| 23 | + |
| 24 | +``` |
| 25 | +dotnet tool install -g plsgd-dotnet-command |
| 26 | +
|
| 27 | +# don't forget to add --version <version> if you want to use specific version, especially for the preview versions who are not downloaded by default |
| 28 | +``` |
| 29 | + |
| 30 | +#### Get help |
| 31 | + |
| 32 | +``` |
| 33 | +dotnet cmd --help |
| 34 | +``` |
| 35 | + |
| 36 | +### How does it work? |
| 37 | + |
| 38 | +1. You create a .NET Core project, with some C# custom command by using `Plsgd.System.Command.Abstractions` and the corresponding base classes. |
| 39 | +2. You use the `dotnet-command` tool with CLI to call the command that you want to execute, providing the correct path to the project containing your command |
| 40 | +3. The `dotnet-command` tool will parse your arguments, try to find the provided command in the provided project, and execute it |
| 41 | + |
| 42 | +### Command |
| 43 | + |
| 44 | +A command is a class who contains some operations to execute. Currently, there are 2 kinds of commands : "execution command" and "migration command". |
| 45 | +An "execution command" has only one operation. A "migration command" is a command who can be applied or reverted. |
| 46 | + |
| 47 | +The `Plsgd.System.Command.Abstractions` package provides 2 base abstract classes: `ExecutionCommand` and `MigrationCommand`. |
| 48 | +All commands inherit from `Command` abstract class, who itself implements `ICommand` interface. And each abstract command class implements respectively of `IExecutionCommand` and `IMigrationCommand`. |
| 49 | + |
| 50 | +#### ExecutionCommand |
| 51 | + |
| 52 | +Contains one operation `Execute()` and can only be executed. |
| 53 | + |
| 54 | +#### MigrationCommand |
| 55 | + |
| 56 | +Contains two operations: `Up()` and `Down()`. It can be applied (with `Up`), or reverted (with `Down`). |
| 57 | + |
| 58 | +### Parser |
| 59 | + |
| 60 | +A parser is a way to retrieve the command(s) to call. Currently, there is only one parser : `AssemblyCommandParser`. |
| 61 | + |
| 62 | +#### AssemblyCommandParser |
| 63 | + |
| 64 | +This parser searches for command inside a provided assembly. |
| 65 | + |
| 66 | +### Options |
| 67 | + |
| 68 | +The options represent all the parameters used to find and call the commands. Currently, there is only one options class, corresponding to the parser above : `AssemblyCommandOptions`. |
| 69 | + |
| 70 | +#### AssemblyCommandOptions |
| 71 | + |
| 72 | +The options class simply contains the name of the command to execute, and the assembly where to find it (the command). |
| 73 | + |
| 74 | +## Getting started |
| 75 | + |
| 76 | +### 1. Create a custom command |
| 77 | + |
| 78 | +First of all, you have to import the `Plsgd.System.Command.Abstractions` package in the project where you want to create your custom commands: |
| 79 | + |
| 80 | +``` |
| 81 | +dotnet add package Plsgd.System.Command.Abstractions |
| 82 | +
|
| 83 | +# don't forget to add -v <version> if you want to use specific version, especially for the preview versions who are not downloaded by default |
| 84 | +``` |
| 85 | + |
| 86 | +Create a new class derived from `ExecutionCommand`, if you only want to execute this command, or from `MigrationCommand` if you want create a migration who can be applied or reverted: |
| 87 | + |
| 88 | +```csharp |
| 89 | +using System.Command.Commands |
| 90 | + |
| 91 | +public class MyExecutionCommand : ExecutionCommand |
| 92 | +{ |
| 93 | + public MyExecutionCommand() : base("my-exec-command-name") // the unique name of your command |
| 94 | + { } |
| 95 | + |
| 96 | + public override void Execute() |
| 97 | + { |
| 98 | + // you custom code to execute |
| 99 | + } |
| 100 | +} |
| 101 | +``` |
| 102 | + |
| 103 | +If you want to create a migration command, inherit from `MigrationCommand`: |
| 104 | + |
| 105 | +```csharp |
| 106 | +using System.Command.Commands |
| 107 | + |
| 108 | +public class MyMigrationCommand : MigrationCommand |
| 109 | +{ |
| 110 | + public MyMigrationCommand() : base("my-migration-command-name") // the unique name of your command |
| 111 | + { } |
| 112 | + |
| 113 | + public override void Up() |
| 114 | + { |
| 115 | + // you custom code to apply |
| 116 | + } |
| 117 | + |
| 118 | + public override void Down() |
| 119 | + { |
| 120 | + // you custom code to revert |
| 121 | + } |
| 122 | +} |
| 123 | +``` |
| 124 | + |
| 125 | +> Don't forget to build this project in order to get the assembly generated |
| 126 | + |
| 127 | +### 2. Execute your command or Apply a migration |
| 128 | + |
| 129 | +#### Execute an `ExecutionCommand` > `dotnet cmd exec` |
| 130 | + |
| 131 | +``` |
| 132 | +dotnet cmd exec <name_of_the_command> --assembly <path_to_dll_containing_your_command> |
| 133 | + |
| 134 | +# e.g. |
| 135 | +dotnet cmd exec my-exec-command-name --assembly ../src/MyProject.Commands/bin/Debug/netcoreapp31/MyProject.Commands.dll |
| 136 | +``` |
| 137 | + |
| 138 | +#### Apply a `MigrationCommand` > `dotnet cmd migration apply` |
| 139 | + |
| 140 | +``` |
| 141 | +dotnet cmd migration apply <name_of_the_command> --assembly <path_to_dll_containing_your_command> |
| 142 | + |
| 143 | +# e.g. |
| 144 | +dotnet cmd migration apply my-migration-command-name --assembly ../src/MyProject.Commands/bin/Debug/netcoreapp31/MyProject.Commands.dll |
| 145 | +``` |
| 146 | + |
| 147 | +#### Revert a `MigrationCommand` > `dotnet cmd migration revert` |
| 148 | + |
| 149 | +``` |
| 150 | +dotnet cmd migration revert <name_of_the_command> --assembly <path_to_dll_containing_your_command> |
| 151 | + |
| 152 | +# e.g. |
| 153 | +dotnet cmd migration apply my-migration-command-name --assembly ../src/MyProject.Commands/bin/Debug/netcoreapp31/MyProject.Commands.dll |
| 154 | +``` |
| 155 | + |
| 156 | +### Configuration |
| 157 | + |
| 158 | +You may need to execute some commands using some parameters through a `IConfiguration` instance like a `appsettings.json` configuration. |
| 159 | + |
| 160 | +Each command who inherits from `Command` will have a `Configuration` property of type `IConfiguration`. By default, this property is populated trying to load an `appsettings.json` file **placed next to the provided assembly**. |
| 161 | + |
| 162 | +So if you want to use a configuration file, follow these steps: |
| 163 | + |
| 164 | +- create an `appsettings.json` file in the project containing your commands |
| 165 | +- edit your `cproj` file to add an operation to copy the `appsettings.json` file during the build (in order to get it next to your assembly): |
| 166 | + |
| 167 | +```xml |
| 168 | +<Project Sdk="Microsoft.NET.Sdk"> |
| 169 | + <!-- create a ConfigFiles property including all files following the pattern --> |
| 170 | + <ItemGroup> |
| 171 | + <ConfigFiles Include="appsettings.json"/> |
| 172 | + </ItemGroup> |
| 173 | + <!-- add a target who, after build, will copy all ConfigFiles in the output directory --> |
| 174 | + <Target Name="CopyConfigFiles" AfterTargets="AfterBuild"> |
| 175 | + <Copy SourceFiles="@(ConfigFiles)" DestinationFolder="$(OutDir)" SkipUnchangedFiles="true"/> |
| 176 | + </Target> |
| 177 | +</Project> |
| 178 | +``` |
| 179 | + |
| 180 | +- use the `Configuration` property in your command to retrieve what you want: |
| 181 | + |
| 182 | +```csharp |
| 183 | +using System.Command.Commands |
| 184 | + |
| 185 | +public class MyExecutionCommand : ExecutionCommand |
| 186 | +{ |
| 187 | + public MyExecutionCommand() : base("my-exec-command-name") // the unique name of your command |
| 188 | + { } |
| 189 | + |
| 190 | + public override void Execute() |
| 191 | + { |
| 192 | + var apiSecret = Configuration.GetSection("Api:Secret").Value; |
| 193 | + // use your config value... |
| 194 | + } |
| 195 | +} |
| 196 | +``` |
| 197 | + |
| 198 | +> Note that your classes who inherits from `ExecutionCommand` or `MigrationCommand` may have a constructor with a `IConfiguration configuration` parameter, in order to mock the configuration in your tests. |
| 199 | +
|
| 200 | +### Logging |
| 201 | + |
| 202 | +By default, the `dotnet-command` tool will inject its own `ILogger` when he calls the command. So you can add a `ILogger` in the constructor of your command, and use it where you want: |
| 203 | + |
| 204 | +```csharp |
| 205 | +using System.Command.Commands |
| 206 | + |
| 207 | +public class MyExecutionCommand : ExecutionCommand |
| 208 | +{ |
| 209 | + private readonly ILogger<MyExecutionCommand> _logger; |
| 210 | + |
| 211 | + public MyExecutionCommand(ILogger<MyExecutionCommand> logger) : base("my-exec-command-name") // the unique name of your command |
| 212 | + { |
| 213 | + _logger = logger; |
| 214 | + } |
| 215 | + |
| 216 | + public override void Execute() |
| 217 | + { |
| 218 | + _logger.LogInformation("Executing my operation..."); |
| 219 | + // ... |
| 220 | + } |
| 221 | +} |
| 222 | +``` |
| 223 | + |
| 224 | +## License |
| 225 | + |
| 226 | +Both projects are licensed under the terms of the [MIT license](LICENSE.md). |
0 commit comments