In our organization, we are running multiple GitHub repositories with different web services. All these projects require common rules for code styling. We moved the right way and created a service template project which is a basis for all the .NET solutions and defines a common architecture. It contains a set of projects with correct naming and references. However, we moved the wrong way and copied the .editorconfig
file to every new repository. There was a temptation to modify the .editorconfig
file whenever it does not fit the developer’s needs. And we did this fault.
There is not much information on the Internet on how to create a common .editorconfig
file and distribute it across multiple repositories. The god feeling told that it must be a NuGet package. After a long time of googling the problem, we found this solution. Thanks to Adam Craven who solved the same issue for his project.
EditorConfig helps maintain consistent coding styles for multiple developers working on the same project across various editors and IDEs. The EditorConfig project consists of a file format for defining coding styles and a collection of text editor plugins that enable editors to read the file format and adhere to defined styles. EditorConfig files are easily readable and they work nicely with version control systems.
In the .NET world, code analysis rules have various configuration options. You specify these options as key-value pairs in one of the following analyzer configuration files:
EditorConfig file: File-based or folder-based configuration options.
Global AnalyzerConfig file: Project-level configuration options. Useful when some project files reside outside the project folder.
You can set the severity for compiler warnings or analyzer rules in an EditorConfig file with the following syntax:
dotnet_diagnostic.<rule ID>.severity = <severity>
Setting a rule's severity in an EditorConfig file takes precedence over any severity that's set in a rule set or in Solution Explorer.
In some projects, there is a mix of local and global config files. Moreover, EditorConfg has some limitations in the .NET world also specified in this article in the limitations section. We tried both ways and moved back and forth with these two approaches. And finally decided to move a simple way to use just EditoConfig for our projects.
First things first, you need to create a new C# library project for the NuGet package. Let’s call it MyProject.EditorConfig
. This project will contain the following files:
.props
file.csproj
file.editorconfig
fileYou have to add PropertyGroup with the following properties set to the true value:
<PropertyGroup>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
</PropertyGroup>
EnforceCodeStyleInBuild
- allows code style rules specified in the EditorConfig file to be checked as part of the build;EnableNETAnalyzers
is true by default for .NET 5.0, but rather set it to true to support earlier versions of .NET;
As one of the limitations of EditorConfig is that some rules have Location.None
and cannot be specified in an EditorConfig file. If you do not use the Global AnalyzerConfig file as we do, you would have an option to disable those rules in the .props
file:
<PropertyGroup>
<NoWarn>$(NoWarn);CA1014</NoWarn>
</PropertyGroup>
Specify the location of the .editorconfig
file to copy from within the NuGet package folder structure:
<ItemGroup>
<EditorConfigFilesToCopy Include="$(MSBuildThisFileDirectory)../content/Rules/.editorconfig" />
</ItemGroup>
Be careful with
\
and/
symbols in the file path string on different platforms. It really took us much time to figure out why.editorconfig
file is not copied.
Use the MSBuild Copy
Task to copy the file to the folder of the .NET Project that is being built. This Target is defined to execute before the MSBuild BeforeBuild
Target.
<Target Name="CopyEditorConfig" BeforeTargets="BeforeBuild">
<Message Text="Copying the .editorconfig file from '@(EditorConfigFilesToCopy)' to '$(SolutionFolder)'"></Message>
<Copy
SourceFiles="@(EditorConfigFilesToCopy)"
DestinationFolder="$(SolutionFolder)"
SkipUnchangedFiles="true"
UseHardlinksIfPossible="false" />
</Target>
By default, when packing NuGet files that start with a period are ignored. To avoid that you have to add the following code to the .csproj
file:
<PropertyGroup>
<NoDefaultExcludes>true</NoDefaultExcludes>
</PropertyGroup>
After that you have to include .props
and .editorconfig
files:
<ItemGroup>
<None Include="MyProject.EditorConfig.props" Pack="true" PackagePath="\build" />
<None Include=".editorconfig" Pack="true" PackagePath="\content\Rules" />
</ItemGroup>
When the all job is done you can publish NuGet package to the local storage and verify that it works.
Execute the following command in the MyProject.EditorConfig
project folder to pack a NuGet package:
dotnet pack MyProject.EditorConfig.csproj -c Release -o out --no-restore
Publish it into local storage (folder). NuGet CLI hast to be installed beforehand:
nuget add out/MyProject.EditorConfig.1.0.0.nupkg -Source /Users/igorlopushko/test_nuget_expand/ -Expand
Specify a target folder with -Source
parameter.
Register local NuGet package path:
dotnet nuget add source /Users/igorlopushko/test_nuget_expand/
To add a local NuGet package to the target project execute this command in the target project’s folder:
dotnet add package MyProject.EditorConfig -s /Users/igorlopushko/test_nuget_expand/
When you build your target project you will get the .editorconfig
file in the root directory of this project. It will be overwritten every time you build a project. Even if it was modified somehow by mistake the .editorconfig
file will be overwritten on the build.
The solution is quite simple, but it made our team's life easier. We have added this NuGet package to all our projects and avoid desynchronization in code styles across all the repositories.