-
-
Save benc-uk/1da5e443e3bc0b34bc0346b716c36c19 to your computer and use it in GitHub Desktop.
- Recommended linter: Built-in code analyzers as part of the .NET platform and SDK
- Website: https://docs.microsoft.com/dotnet/fundamentals/code-analysis/overview
As of .NET 5, this is included in the base SDK
Install the C# extension for VS Code
By default the extensions will not fix or format on save and the linter is not enabled, switch it on with enableRoslynAnalyzers
and formatOnSave
{
"[csharp]": {
"editor.defaultFormatter": "ms-dotnettools.csharp",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": true
}
},
"omnisharp.enableRoslynAnalyzers": true,
"omnisharp.useModernNet": true,
"omnisharp.enableEditorConfigSupport": true,
"omnisharp.analyzeOpenDocumentsOnly": true
}
name: Example CI for GitHub Actions
on:
push:
jobs:
linting:
name: Run code checks
runs-on: ubuntu-latest
steps:
- uses: actions/setup-dotnet@v2
with:
dotnet-version: '6.0.x' # SDK Version to use
- uses: actions/checkout@v3
# Check formatting and style first
- run: dotnet format --verbosity detailed --verify-no-changes
working-directory: ./src
# There's no way to separately run code analysis/linting, the best choice is do a build
- run: dotnet clean && dotnet build -warnaserror
working-directory: ./src
The linter should be enabled by default when running a build, however it's probably worth configuring it, to be explicit:
Add to .csproj
file
<PropertyGroup>
<!-- Enable the code analyzers, should be on by default -->
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<!-- Not essential if running dotnet format before build -->
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<!-- This setting does nothing currently, due to a bug, hope they fix it -->
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
</PropertyGroup>
The bulk of configuration should be done in a .editorconfig
file.
The provided file, is
Example .editorconfig file
root = true
end_of_line = lf
# All files
[*]
indent_style = space
# XML project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
# Indentation and spacing
# Code files
[*.{cs,csx}]
indent_size = 4
tab_width = 4
insert_final_newline = true
charset = utf-8-bom
###############################
# .NET Coding Conventions #
###############################
# Organize usings
dotnet_sort_system_directives_first = true
# this. preferences
dotnet_style_qualification_for_field = false:silent
dotnet_style_qualification_for_property = false:silent
dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_event = false:silent
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
dotnet_style_predefined_type_for_member_access = true:silent
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
dotnet_style_readonly_field = true:suggestion
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
###############################
# C# Coding Conventions #
###############################
# var preferences
csharp_style_var_for_built_in_types = true:silent
csharp_style_var_when_type_is_apparent = true:silent
csharp_style_var_elsewhere = true:silent
# Expression-bodied members
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
# Pattern matching preferences
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
# Null-checking preferences
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Modifier preferences
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
# Expression-level preferences
csharp_prefer_braces = true:silent
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_prefer_local_over_anonymous_function = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
###############################
# C# Formatting Rules #
###############################
# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
# Space preferences
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
# Wrapping preferences
csharp_preserve_single_line_statements = true
csharp_preserve_single_line_blocks = true
########################################
# Enable analyzer rules sets #
# - Switch on everything by default #
########################################
dotnet_analyzer_diagnostic.category-Design.severity = error
dotnet_analyzer_diagnostic.category-Documentation.severity = error
dotnet_analyzer_diagnostic.category-Globalization.severity = none
dotnet_analyzer_diagnostic.category-Interoperability.severity = error
dotnet_analyzer_diagnostic.category-Maintainability.severity = error
dotnet_analyzer_diagnostic.category-Naming.severity = error
dotnet_analyzer_diagnostic.category-Performance.severity = error
dotnet_analyzer_diagnostic.category-SingleFile.severity = error
dotnet_analyzer_diagnostic.category-Reliability.severity = error
dotnet_analyzer_diagnostic.category-Security.severity = error
dotnet_analyzer_diagnostic.category-Style.severity = error
dotnet_analyzer_diagnostic.category-Usage.severity = error
dotnet_analyzer_diagnostic.category-CodeQuality.severity = error
# This rule often clashes with CA1707 (no underscores)
dotnet_diagnostic.IDE0130.severity = none
- Recommended linter:
dotnet format
as of .NET 6 this is included in the SDK. The there is technically no separate formatter it's just a subset of the code analysis rules, those beginning withIDExxxx
that the format tool will run. - Website: https://github.com/dotnet/format
dotnet format --verify-no-changes
- Recommended linter:
golangci-lint
this is a Go linter aggregator and runner, designed with CI in mind - Website: https://golangci-lint.run/
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $HOME/.local/bin
golangci-lint --version
{
"go.lintTool": "golangci-lint",
"go.lintOnSave": "file",
}
This linter has a dedicated GitHub Action available https://github.com/golangci/golangci-lint-action. It is suggested you use this action, rather than trying to manually install the binary as part of the workflow and running with bash.
Sample minimal workflow to run this action
name: Example for golangci-lint
on:
push:
jobs:
linting:
name: Run linting
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v3
- uses: actions/checkout@v3
- uses: golangci/golangci-lint-action@v3
As a linter aggregator, golangci-lint
has a lot of options and possible linters it can call. See https://golangci-lint.run/usage/linters. It's best to enable linters one at a time observe the effects, some suggestions are provided below.
Example .golangci.yaml
file
# =================================================================
# An opinionated config for linting Go code with golangci-lint
# See https://golangci-lint.run/usage/linters
# =================================================================
linters:
enable:
- revive # Replacement for golint
- gofmt # Runs gofmt as part of the linter
- gosec # Find security issues
- wsl # Whitespace style enforcer, a matter of taste
- stylecheck # A few Go style rules
- nosnakecase # We are not writing Python here
- misspell # Find misspelled words
- cyclop # Find cyclomatic complexity
- gocyclo # Also find cyclomatic complexity
- bodyclose # Check for HTTP body close errors
- nilerr # Find bad nil/err handling
- nilnil # Also find bad nil/err handling
- tagliatelle # Find badly named struct tags
#- gomnd # Find magic numbers, enable at your peril
linters-settings:
misspell:
locale: UK # Enable UK spelling
# Check struck tag naming
tagliatelle:
case:
use-field-name: true
rules:
json: goCamel
yaml: goCamel
revive:
severity: error
enable-all-rules: false
confidence: 0.5
rules:
# There are MANY rules you could enable...
# See https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md
# And https://golangci-lint.run/usage/linters/#revive
- name: line-length-limit
severity: error
arguments: [120]
- Recommended formatter: The built-in
go fmt
which is part of the standard Go language toolchain
NA, it's part of the base Go language tooling
The Go language extension for VS Code will automatically run go fmt
on save, but if you wish to explicitly enable it, use the following settings
{
"go.formatTool": "gofmt",
"[go]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
}
},
}
Run this formatter as part of golangci-lint
as one of the configurable linters it can run (even though strictly speaking it is not a linter!), by adding gofmt
to the enabled linters list in the configuration.
If you wish to run the tool directly in a pipeline, be aware it does not set an non-zero exit code when it finds code that needs formatting, a workaround is to use bash as follows
if [[ "$(gofmt -l ./srcdir | wc -l)" -gt 0 ]]; then
# Output to the logs the code that needs formatting
gofmt -d ./srcdir
exit 1
fi
NA, this tool requires no configuration
- Recommended linter:
eslint
- ESlint has become the de-facto linter for both JavaScript and TypeScript - Website: https://eslint.org/
Install in your project, to be run via npm
npm install eslint --save-dev
Add a script to run the linter in the package.json
to run eslint
"scripts": {
"lint": "eslint ./src",
"lint-fix": "eslint ./src --fix"
},
Install the ESLint extension
This requires little to no config, and by default will find linting errors as you type.
Should you wish to try to auto fix linting problems when saving files, you can enable it as follows:
"[typescript][javascript]": {
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}
name: Example CI for GitHub Actions
on:
push:
jobs:
linting:
name: Run linting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: "16.x"
cache: "npm"
- run: npm ci
- run: npm run lint
ESLint is a sophisticated linter supporting several languages and many runtime environments, as such it's difficult to provide a single suggested config and rule setup. It is recommended you run the interactive configuration creator to get started.
npm init @eslint/config
- Pick "To check syntax and find problems" when prompted, this will add the
eslint:recommended
ruleset. - If you save the config in JSON format, e.g.
.eslintrc.json
the VS Code extension can provide intellisense and auto completion.
Suggested rules to switch on are:
"rules": {
// Use const instead of var or let where possible
"prefer-const": "error",
// Disallow use of var for declaring variables
"no-var": "error",
// Use arrow functions for callbacks
"prefer-arrow-callback": "error",
// Always use `function()` style declarations
"func-style": ["error", "declaration"],
// Find pointless return statements
"no-useless-return": "error",
// Best practice is not to throw strings for errors
"no-throw-literal": "error",
}
It's strongly advised to not switch on any rules related purely to formatting (e.g. semi
, indent
, quotes
rules) and leave these concerns to the code formatter Prettier (see below)
There are many publicly available rule sets for ESLint, which can provide an very opinionated set of rules should you wish. Most are collected here - Awesome ESLint Collection. If you use such a ruleset, it is suggested to also use eslint-config-prettier which will prevent any overlap with Prettier by switching off any conflicting rules.
- Recommended formatter:
prettier
- Prettier is an opinionated code formatter which supports multiple language. - Website: https://prettier.io/
Prettier has only a few options & rules, which is a big part of it's strength. It can also format HTML, CSS, Markdown and YAML
If you are curious as to why separating formatting from linting is good idea toy can read this comparison
Install in your project, to be run via npm
npm install prettier --save-dev
Extend the linting script in package.json
to also run prettier
"scripts": {
"lint": "eslint ./src && prettier --check ./src",
"lint-fix": "eslint ./src --fix && prettier --write ./src"
}
Install the Prettier extension
To have prettier run & format code automatically set it as the default formatter
"[typescript][javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
}
Run via npm, see linter above
Example .prettierrc
, obviously many of these settings come down to personal preference
{
"semi": false,
"singleQuote": true,
"useTabs": false,
"printWidth": 120,
"endOfLine": "lf",
"trailingComma": "none",
"arrowParens": "always",
"bracketSameLine": true
}
- Recommended linter:
- Website:
some commands
{
"blah": "blah"
}
name: Example CI for GitHub Actions
on:
push:
jobs:
linting:
name: Run linting
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v3
- uses: actions/checkout@v3
# Rest of the workflow here
some config
- Recommended formatter:
- Website:
Blah
{
// If required
}
Blah
example config