|
| 1 | +# CoseSignTool Coding Standards for GitHub Copilot |
| 2 | + |
| 3 | +This file ensures GitHub Copilot follows the repository's coding standards as defined in .editorconfig and established patterns. |
| 4 | + |
| 5 | +## Code Generation Preferences |
| 6 | + |
| 7 | +### File Headers |
| 8 | +- Always include the Microsoft copyright header at the top of all C# files: |
| 9 | +```csharp |
| 10 | +// Copyright (c) Microsoft Corporation. |
| 11 | +// Licensed under the MIT License. |
| 12 | +``` |
| 13 | + |
| 14 | +### Namespace and Using Directives |
| 15 | +- Use file-scoped namespaces (C# 10+ feature): `namespace MyNamespace;` |
| 16 | +- Place using directives inside the namespace |
| 17 | +- Sort System directives first, then others alphabetically |
| 18 | +- Do not separate import directive groups with blank lines |
| 19 | +- Follow namespace-to-folder structure matching |
| 20 | + |
| 21 | +### Naming Conventions |
| 22 | +- **Constants**: PascalCase (e.g., `DefaultStoreName`) |
| 23 | +- **Static private fields**: PascalCase (e.g. `StaticStoreName`) |
| 24 | +- **Private/internal instance fields**: camelCase (e.g., `commands`) |
| 25 | +- **Public properties/methods**: PascalCase |
| 26 | +- **Local variables**: camelCase |
| 27 | +- **Parameters**: camelCase |
| 28 | + |
| 29 | +### Code Style Preferences |
| 30 | +- **Braces**: Always use braces for control statements (enforced as error) |
| 31 | +- **var usage**: Avoid `var` - use explicit types for clarity |
| 32 | +- **this qualifier**: useh `this.` so that it's clear when member parameters or state is being modified |
| 33 | +- **Predefined types**: Use predefined types (`int`, `string`) over .NET types (`Int32`, `String`) |
| 34 | +- **Null checking**: Prefer `is null` over `== null` |
| 35 | +- **Object initialization**: Prefer object and collection initializers |
| 36 | +- **String interpolation**: Use simplified interpolation when possible |
| 37 | + |
| 38 | +### Expression Preferences |
| 39 | +- **Expression-bodied members**: |
| 40 | + - Use for properties, indexers, and accessors when appropriate |
| 41 | + - Avoid for methods, constructors, and operators (prefer block bodies) |
| 42 | +- **Pattern matching**: Prefer pattern matching over `is` with cast checks |
| 43 | +- **Target-typed new**: Use when type is apparent (e.g., `List<string> items = new();`) |
| 44 | +- **Using statements**: Prefer simple using statements over using blocks |
| 45 | + |
| 46 | +### Formatting Rules |
| 47 | +- **Indentation**: 4 spaces (no tabs) |
| 48 | +- **End of line**: CRLF (Windows line endings) |
| 49 | +- **Final newline**: Do not insert final newline |
| 50 | +- **Trim whitespace**: Always trim trailing whitespace |
| 51 | +- **New lines**: |
| 52 | + - Opening braces on new line for all constructs |
| 53 | + - `else`, `catch`, `finally` on new lines |
| 54 | + - Members in object initializers on new lines |
| 55 | + |
| 56 | +### Space Preferences |
| 57 | +- No space after casts: `(int)value` |
| 58 | +- Space after keywords: `if (condition)` |
| 59 | +- Space around binary operators: `a + b` |
| 60 | +- Space after commas: `Method(a, b, c)` |
| 61 | +- Space around colons in inheritance: `class Derived : Base` |
| 62 | +- No space before dots: `object.Property` |
| 63 | +- No space in empty parentheses: `Method()` |
| 64 | + |
| 65 | +### Modifier Order |
| 66 | +Follow this order: `public`, `private`, `protected`, `internal`, `static`, `extern`, `new`, `virtual`, `abstract`, `sealed`, `override`, `readonly`, `unsafe`, `volatile`, `async` |
| 67 | + |
| 68 | +### Error Handling and Diagnostics |
| 69 | +- Null reference warnings are suggestions, not errors |
| 70 | +- Unused parameters should be flagged |
| 71 | +- Platform compatibility should be validated |
| 72 | +- File headers are required (enforced as error) |
| 73 | +- Missing braces are errors |
| 74 | +- Unused private members are errors |
| 75 | + |
| 76 | +### Plugin Project-Specific Patterns |
| 77 | +- **Plugin naming**: Use `.Plugin.csproj` suffix for auto-packaging |
| 78 | +- **Plugin Assembly naming**: Use `.Plugin.dll` suffix for runtime discovery |
| 79 | +- **Plugin Exit codes**: Use the `PluginExitCode` enum for plugin commands |
| 80 | +- **Async patterns**: Always use `CancellationToken` parameters in async methods |
| 81 | +- **Plugin Interface implementation**: Implement plugin interfaces (`ICoseSignToolPlugin`, `IPluginCommand`) |
| 82 | +- **Plugin Error handling**: Use appropriate exit codes and console error output |
| 83 | + |
| 84 | +### Documentation |
| 85 | +- Use XML documentation comments for public APIs |
| 86 | +- Include parameter descriptions and return value documentation |
| 87 | +- Use `<summary>`, `<param>`, `<returns>` tags appropriately |
| 88 | +- Where possible provide appropriate `<example>` tags for different behaviors |
| 89 | +- Document exceptions with `<exception>` tags |
| 90 | + |
| 91 | +### Testing Patterns |
| 92 | +- Use descriptive test method names |
| 93 | +- Follow Arrange-Act-Assert pattern |
| 94 | +- Use meaningful assertions with clear error messages |
| 95 | +- Include both positive and negative test cases |
| 96 | +- Cover as close to 100% of blocks as posible without overgenerating test cases |
| 97 | +- Prefer NUnit tests with the new `Assert.That` syntax when writing new tests |
| 98 | +- Prefer data-driven test cases when possible |
| 99 | +- Prefer test local state over shared state to enable parallel execution |
| 100 | +- Leverage maintainability patterns in test code by creating shared functions for common code |
| 101 | + |
| 102 | +### Plugin Development Guidelines |
| 103 | +- Implement `PluginCommandBase` for command implementations |
| 104 | +- Use proper dependency injection patterns |
| 105 | +- Handle configuration through `IConfiguration` |
| 106 | +- Implement proper cancellation token support |
| 107 | +- Follow security best practices for plugin loading |
| 108 | + |
| 109 | +## Example Code Structure |
| 110 | + |
| 111 | +```csharp |
| 112 | +// Copyright (c) Microsoft Corporation. |
| 113 | +// Licensed under the MIT License. |
| 114 | +
|
| 115 | +using Microsoft.Extensions.Configuration; |
| 116 | +using CoseSignTool.Abstractions; |
| 117 | + |
| 118 | +namespace CoseSignTool.MyPlugin; |
| 119 | + |
| 120 | +/// <summary> |
| 121 | +/// Example plugin implementation following repository standards. |
| 122 | +/// </summary> |
| 123 | +public class ExamplePlugin : ICoseSignToolPlugin |
| 124 | +{ |
| 125 | + private readonly List<IPluginCommand> commands; |
| 126 | + private static readonly object LockObject = new(); |
| 127 | + |
| 128 | + public ExamplePlugin() |
| 129 | + { |
| 130 | + this.commands = new List<IPluginCommand> |
| 131 | + { |
| 132 | + new ExampleCommand() |
| 133 | + }; |
| 134 | + } |
| 135 | + |
| 136 | + public string Name => "Example Plugin"; |
| 137 | + public string Version => "1.0.0"; |
| 138 | + public string Description => "An example plugin demonstrating coding standards."; |
| 139 | + public IEnumerable<IPluginCommand> Commands => _commands; |
| 140 | + |
| 141 | + public void Initialize(IConfiguration? configuration = null) |
| 142 | + { |
| 143 | + // Initialization logic here |
| 144 | + } |
| 145 | +} |
| 146 | + |
| 147 | +/// <summary> |
| 148 | +/// Example command implementation. |
| 149 | +/// </summary> |
| 150 | +public class ExampleCommand : PluginCommandBase |
| 151 | +{ |
| 152 | + public override string Name => "example"; |
| 153 | + public override string Description => "Example command for demonstration."; |
| 154 | + public override string Usage => "example --input <file> [--output <file>]"; |
| 155 | + |
| 156 | + public override IDictionary<string, string> Options => new Dictionary<string, string> |
| 157 | + { |
| 158 | + ["--input"] = "input", |
| 159 | + ["--output"] = "output" |
| 160 | + }; |
| 161 | + |
| 162 | + public override async Task<PluginExitCode> ExecuteAsync( |
| 163 | + IConfiguration configuration, |
| 164 | + CancellationToken cancellationToken = default) |
| 165 | + { |
| 166 | + try |
| 167 | + { |
| 168 | + string inputFile = base.GetRequiredValue(configuration, "input"); |
| 169 | + string? outputFile = base.GetOptionalValue(configuration, "output"); |
| 170 | + |
| 171 | + if (!File.Exists(inputFile)) |
| 172 | + { |
| 173 | + Console.Error.WriteLine($"Input file not found: {inputFile}"); |
| 174 | + return PluginExitCode.UserSpecifiedFileNotFound; |
| 175 | + } |
| 176 | + |
| 177 | + // Process the file |
| 178 | + await this.ProcessFileAsync(inputFile, outputFile, cancellationToken); |
| 179 | + |
| 180 | + return PluginExitCode.Success; |
| 181 | + } |
| 182 | + catch (OperationCanceledException) |
| 183 | + { |
| 184 | + Console.Error.WriteLine("Operation was cancelled"); |
| 185 | + return PluginExitCode.UnknownError; |
| 186 | + } |
| 187 | + catch (ArgumentNullException ex) |
| 188 | + { |
| 189 | + Console.Error.WriteLine($"Missing required option: {ex.ParamName}"); |
| 190 | + return PluginExitCode.MissingRequiredOption; |
| 191 | + } |
| 192 | + catch (Exception ex) |
| 193 | + { |
| 194 | + Console.Error.WriteLine($"Unexpected error: {ex.Message}"); |
| 195 | + return PluginExitCode.UnknownError; |
| 196 | + } |
| 197 | + } |
| 198 | + |
| 199 | + private static async Task ProcessFileAsync( |
| 200 | + string inputFile, |
| 201 | + string? outputFile, |
| 202 | + CancellationToken cancellationToken) |
| 203 | + { |
| 204 | + // Implementation here |
| 205 | + await Task.CompletedTask; |
| 206 | + } |
| 207 | +} |
| 208 | +``` |
| 209 | + |
| 210 | +## Summary |
| 211 | +When generating code for this repository, always: |
| 212 | +1. Include the Microsoft copyright header |
| 213 | +2. Use file-scoped namespaces |
| 214 | +3. Follow the specified naming conventions |
| 215 | +4. Use explicit types instead of var |
| 216 | +5. Include proper error handling with appropriate exit codes |
| 217 | +6. Implement cancellation token support in async methods |
| 218 | +7. If creating a plug-in, use the established plugin patterns for extensibility |
| 219 | +8. Follow the formatting and spacing rules exactly as specified |
| 220 | +9. Include comprehensive XML documentation for public APIs |
| 221 | +10. Ensure all generated code follows the .editorconfig rules |
0 commit comments