Skip to content

Commit bee4998

Browse files
authored
Merge pull request #1 from plsgard/develop
First release
2 parents b03ea70 + ceb41f0 commit bee4998

26 files changed

Lines changed: 996 additions & 0 deletions

Directory.Build.props

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project>
2+
<PropertyGroup>
3+
<LocalVersion>0.1.1-alpha</LocalVersion>
4+
<LangVersion>latest</LangVersion>
5+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
6+
<NoWarn>$(NoWarn);1591</NoWarn>
7+
<Authors>Pier-Lionel Sgard</Authors>
8+
<Company>Plsgd</Company>
9+
<PackageLicenseExpression>MIT</PackageLicenseExpression>
10+
<RepositoryUrl>https://github.com/plsgard/dotnet-command</RepositoryUrl>
11+
<PackageProjectUrl>https://github.com/plsgard/dotnet-command</PackageProjectUrl>
12+
<Copyright>© Plsgd (Pier-Lionel Sgard)</Copyright>
13+
</PropertyGroup>
14+
</Project>

Dotnet.Command.sln

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 15
4+
VisualStudioVersion = 15.0.26124.0
5+
MinimumVisualStudioVersion = 15.0.26124.0
6+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F035738F-60EC-4382-B1C8-69AC33D1CB70}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Command.Abstractions", "src\System.Command.Abstractions\System.Command.Abstractions.csproj", "{0E454D58-D7E4-4B54-9458-2299197A66B8}"
9+
EndProject
10+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dotnet.Command", "src\Dotnet.Command\Dotnet.Command.csproj", "{4A2EE007-5726-4D4B-989E-614AFF00142B}"
11+
EndProject
12+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{EA97DEA1-A971-4CC2-B354-A090818CEA0D}"
13+
EndProject
14+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Command.Abstractions.Tests", "tests\System.Command.Abstractions.Tests\System.Command.Abstractions.Tests.csproj", "{EA5DBE2B-016E-46FC-9FEB-8ECE832B6198}"
15+
EndProject
16+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Command.Fake.Commands", "tests\System.Command.Fake.Commands\System.Command.Fake.Commands.csproj", "{9888869A-D217-4563-9D6C-16A0FCD548E2}"
17+
EndProject
18+
Global
19+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
20+
Debug|Any CPU = Debug|Any CPU
21+
Debug|x64 = Debug|x64
22+
Debug|x86 = Debug|x86
23+
Release|Any CPU = Release|Any CPU
24+
Release|x64 = Release|x64
25+
Release|x86 = Release|x86
26+
EndGlobalSection
27+
GlobalSection(SolutionProperties) = preSolution
28+
HideSolutionNode = FALSE
29+
EndGlobalSection
30+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
31+
{0E454D58-D7E4-4B54-9458-2299197A66B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32+
{0E454D58-D7E4-4B54-9458-2299197A66B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
33+
{0E454D58-D7E4-4B54-9458-2299197A66B8}.Debug|x64.ActiveCfg = Debug|Any CPU
34+
{0E454D58-D7E4-4B54-9458-2299197A66B8}.Debug|x64.Build.0 = Debug|Any CPU
35+
{0E454D58-D7E4-4B54-9458-2299197A66B8}.Debug|x86.ActiveCfg = Debug|Any CPU
36+
{0E454D58-D7E4-4B54-9458-2299197A66B8}.Debug|x86.Build.0 = Debug|Any CPU
37+
{0E454D58-D7E4-4B54-9458-2299197A66B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
38+
{0E454D58-D7E4-4B54-9458-2299197A66B8}.Release|Any CPU.Build.0 = Release|Any CPU
39+
{0E454D58-D7E4-4B54-9458-2299197A66B8}.Release|x64.ActiveCfg = Release|Any CPU
40+
{0E454D58-D7E4-4B54-9458-2299197A66B8}.Release|x64.Build.0 = Release|Any CPU
41+
{0E454D58-D7E4-4B54-9458-2299197A66B8}.Release|x86.ActiveCfg = Release|Any CPU
42+
{0E454D58-D7E4-4B54-9458-2299197A66B8}.Release|x86.Build.0 = Release|Any CPU
43+
{4A2EE007-5726-4D4B-989E-614AFF00142B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
44+
{4A2EE007-5726-4D4B-989E-614AFF00142B}.Debug|Any CPU.Build.0 = Debug|Any CPU
45+
{4A2EE007-5726-4D4B-989E-614AFF00142B}.Debug|x64.ActiveCfg = Debug|Any CPU
46+
{4A2EE007-5726-4D4B-989E-614AFF00142B}.Debug|x64.Build.0 = Debug|Any CPU
47+
{4A2EE007-5726-4D4B-989E-614AFF00142B}.Debug|x86.ActiveCfg = Debug|Any CPU
48+
{4A2EE007-5726-4D4B-989E-614AFF00142B}.Debug|x86.Build.0 = Debug|Any CPU
49+
{4A2EE007-5726-4D4B-989E-614AFF00142B}.Release|Any CPU.ActiveCfg = Release|Any CPU
50+
{4A2EE007-5726-4D4B-989E-614AFF00142B}.Release|Any CPU.Build.0 = Release|Any CPU
51+
{4A2EE007-5726-4D4B-989E-614AFF00142B}.Release|x64.ActiveCfg = Release|Any CPU
52+
{4A2EE007-5726-4D4B-989E-614AFF00142B}.Release|x64.Build.0 = Release|Any CPU
53+
{4A2EE007-5726-4D4B-989E-614AFF00142B}.Release|x86.ActiveCfg = Release|Any CPU
54+
{4A2EE007-5726-4D4B-989E-614AFF00142B}.Release|x86.Build.0 = Release|Any CPU
55+
{EA5DBE2B-016E-46FC-9FEB-8ECE832B6198}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
56+
{EA5DBE2B-016E-46FC-9FEB-8ECE832B6198}.Debug|Any CPU.Build.0 = Debug|Any CPU
57+
{EA5DBE2B-016E-46FC-9FEB-8ECE832B6198}.Debug|x64.ActiveCfg = Debug|Any CPU
58+
{EA5DBE2B-016E-46FC-9FEB-8ECE832B6198}.Debug|x64.Build.0 = Debug|Any CPU
59+
{EA5DBE2B-016E-46FC-9FEB-8ECE832B6198}.Debug|x86.ActiveCfg = Debug|Any CPU
60+
{EA5DBE2B-016E-46FC-9FEB-8ECE832B6198}.Debug|x86.Build.0 = Debug|Any CPU
61+
{EA5DBE2B-016E-46FC-9FEB-8ECE832B6198}.Release|Any CPU.ActiveCfg = Release|Any CPU
62+
{EA5DBE2B-016E-46FC-9FEB-8ECE832B6198}.Release|Any CPU.Build.0 = Release|Any CPU
63+
{EA5DBE2B-016E-46FC-9FEB-8ECE832B6198}.Release|x64.ActiveCfg = Release|Any CPU
64+
{EA5DBE2B-016E-46FC-9FEB-8ECE832B6198}.Release|x64.Build.0 = Release|Any CPU
65+
{EA5DBE2B-016E-46FC-9FEB-8ECE832B6198}.Release|x86.ActiveCfg = Release|Any CPU
66+
{EA5DBE2B-016E-46FC-9FEB-8ECE832B6198}.Release|x86.Build.0 = Release|Any CPU
67+
{9888869A-D217-4563-9D6C-16A0FCD548E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
68+
{9888869A-D217-4563-9D6C-16A0FCD548E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
69+
{9888869A-D217-4563-9D6C-16A0FCD548E2}.Debug|x64.ActiveCfg = Debug|Any CPU
70+
{9888869A-D217-4563-9D6C-16A0FCD548E2}.Debug|x64.Build.0 = Debug|Any CPU
71+
{9888869A-D217-4563-9D6C-16A0FCD548E2}.Debug|x86.ActiveCfg = Debug|Any CPU
72+
{9888869A-D217-4563-9D6C-16A0FCD548E2}.Debug|x86.Build.0 = Debug|Any CPU
73+
{9888869A-D217-4563-9D6C-16A0FCD548E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
74+
{9888869A-D217-4563-9D6C-16A0FCD548E2}.Release|Any CPU.Build.0 = Release|Any CPU
75+
{9888869A-D217-4563-9D6C-16A0FCD548E2}.Release|x64.ActiveCfg = Release|Any CPU
76+
{9888869A-D217-4563-9D6C-16A0FCD548E2}.Release|x64.Build.0 = Release|Any CPU
77+
{9888869A-D217-4563-9D6C-16A0FCD548E2}.Release|x86.ActiveCfg = Release|Any CPU
78+
{9888869A-D217-4563-9D6C-16A0FCD548E2}.Release|x86.Build.0 = Release|Any CPU
79+
EndGlobalSection
80+
GlobalSection(NestedProjects) = preSolution
81+
{0E454D58-D7E4-4B54-9458-2299197A66B8} = {F035738F-60EC-4382-B1C8-69AC33D1CB70}
82+
{4A2EE007-5726-4D4B-989E-614AFF00142B} = {F035738F-60EC-4382-B1C8-69AC33D1CB70}
83+
{EA5DBE2B-016E-46FC-9FEB-8ECE832B6198} = {EA97DEA1-A971-4CC2-B354-A090818CEA0D}
84+
{9888869A-D217-4563-9D6C-16A0FCD548E2} = {EA97DEA1-A971-4CC2-B354-A090818CEA0D}
85+
EndGlobalSection
86+
EndGlobal

LICENSE.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2020 Plsgd (Pier-Lionel Sgard)
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
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` | [![Nuget](https://img.shields.io/nuget/v/Plsgd.System.Command.Abstractions.svg)](https://nuget.org/packages/Plsgd.System.Command.Abstractions) | user-defined C# command, command parser, migration command, ... |
8+
| `dotnet-command` | [![Nuget](https://img.shields.io/nuget/v/plsgd-dotnet-command.svg)](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).
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<ItemGroup>
3+
<ProjectReference Include="..\System.Command.Abstractions\System.Command.Abstractions.csproj" />
4+
</ItemGroup>
5+
<ItemGroup>
6+
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20427.1" />
7+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.7" />
8+
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.7" />
9+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.7" />
10+
<PackageReference Include="System.CommandLine.Hosting" Version="0.3.0-alpha.20427.1" />
11+
</ItemGroup>
12+
<PropertyGroup>
13+
<OutputType>Exe</OutputType>
14+
<TargetFramework>netcoreapp3.1</TargetFramework>
15+
<PackAsTool>true</PackAsTool>
16+
<ToolCommandName>dotnet-cmd</ToolCommandName>
17+
<PackageId>plsgd-dotnet-command</PackageId>
18+
<Version>0.1.1-alpha</Version>
19+
<Title>Dotnet Command</Title>
20+
<Description>A .NET Core global tool to call user-defined C# command to execute some operations through .NET CLI.</Description>
21+
<PackageTags>dotnet-core,tool,command,c#,migration,.net core</PackageTags>
22+
</PropertyGroup>
23+
</Project>

0 commit comments

Comments
 (0)