Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 13 additions & 0 deletions .config/dotnet-tools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"csharpier": {
"version": "1.3.0",
"commands": [
"csharpier"
],
"rollForward": false
}
}
}
9 changes: 9 additions & 0 deletions .csharpierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# CSharpier reindents MSBuild XML but leaves the interior of multi-line comments at its old
# indentation, so every commented csproj in this repo comes out with hanging comment bodies.
# The C# formatting is what is wanted here; the project files stay hand-maintained.
*.csproj
*.props
*.targets

# Build output. Nothing here is a source file.
artifacts/
53 changes: 53 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
root = true

# CSharpier is what enforces the layout below; this file exists so an IDE reaches the same answer
# while you type, rather than reformatting to its own defaults and losing the change at the next
# commit. CSharpier reads indent_style, indent_size, max_line_length and end_of_line from here, so
# those four are shared settings rather than a second opinion. Everything else describes what
# CSharpier already does and is not configurable in it.
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

[*.{json,yaml,yml,md}]
indent_size = 2

[*.md]
# Two trailing spaces is a line break in Markdown.
trim_trailing_whitespace = false

[*.{csproj,props,targets}]
# Not formatted by CSharpier — see .csharpierignore.
indent_size = 4

[*.cs]
max_line_length = 100

# Allman. This is the one CSharpier does not offer a choice about, and the reason the repo moved
# off K&R: matching the formatter is cheaper than arguing with it.
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

csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = one_less_than_current

csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_method_call_parameter_list_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_preserve_single_line_statements = false
csharp_preserve_single_line_blocks = true
6 changes: 6 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Revisions that only moved whitespace. GitHub honours this file automatically; for local blame:
#
# git config blame.ignoreRevsFile .git-blame-ignore-revs

# Reformat every C# file with CSharpier
79a2881a3fd722dd95f8aa589567003acb896678
45 changes: 45 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/bin/sh
#
# Rejects a commit whose C# is not CSharpier-formatted.
#
# Enable it once per clone:
#
# git config core.hooksPath .githooks
#
# A hook is local and skippable with --no-verify, so it is the fast answer rather than the
# guarantee; build-package.yaml runs the same check on every pull request.

set -eu

staged=$(git diff --cached --name-only --diff-filter=ACMR -- '*.cs')

if [ -z "$staged" ]; then
exit 0
fi

if ! command -v dotnet >/dev/null 2>&1; then
echo "pre-commit: dotnet is not on PATH, skipping the format check." >&2
exit 0
fi

# The manifest pins the version, so every clone and CI agree on what formatted means.
if ! dotnet tool run csharpier --version >/dev/null 2>&1; then
dotnet tool restore >/dev/null
fi

# Split on newlines only, so a path with spaces stays one argument, and with globbing off so one
# with a bracket in it is not expanded. Named paths skip CSharpier's cache and cost about 50ms
# each, which is worth paying to check the files being committed rather than the whole tree.
IFS='
'
set -f
set -- $staged
set +f

# The working tree is what gets checked, not the staged content. They differ only when a file is
# staged in part, which is rare enough not to pay for a temporary checkout on every commit.
if ! dotnet csharpier check "$@"; then
echo >&2
echo "pre-commit: run 'dotnet csharpier format .' and stage the result." >&2
exit 1
fi
8 changes: 8 additions & 0 deletions .github/workflows/build-package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ jobs:

- run: dotnet restore DependencyModules.sln

# The pre-commit hook in .githooks runs this too, but a hook is local and skippable. This is
# what actually holds the formatting. It runs before the build so a style-only failure costs
# seconds rather than a full compile and test cycle.
- name: Check formatting
run: |
dotnet tool restore
dotnet csharpier check .

- run: dotnet build DependencyModules.sln --no-restore --configuration Release

# Runs every test suite with coverage collection and merges the results.
Expand Down
46 changes: 46 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Contributing

## Setup

```sh
git config core.hooksPath .githooks
git config blame.ignoreRevsFile .git-blame-ignore-revs
dotnet tool restore
```

The first line turns on the pre-commit hook, which rejects a commit whose C# is not formatted. Git
does not carry hooks across a clone, so this is the one step that cannot be automated for you.

The second keeps the CSharpier reformat out of `git blame`, which otherwise reports it as the last
change to nearly every line in the repo. GitHub already reads that file without being asked.

## Formatting

C# layout is [CSharpier](https://csharpier.com)'s, and the version is pinned in
`.config/dotnet-tools.json` so every clone and CI agree on what formatted means. Braces are Allman.
Nothing about the style is up for discussion in review — run the formatter:

```sh
dotnet csharpier format .
```

`.editorconfig` describes the same layout for your IDE, so typing and formatting do not disagree.
Project files are excluded (see `.csharpierignore`); CSharpier reindents MSBuild XML but leaves the
interior of multi-line comments where it was, which this repo has a lot of.

`build-package.yaml` runs `dotnet csharpier check .` on every pull request. The hook is the fast
answer, that check is the guarantee.

## Build and test

```sh
dotnet build DependencyModules.sln
dotnet test DependencyModules.sln
```

Both target frameworks are built, so running the tests needs the .NET 8 runtime alongside the .NET
10 SDK that `global.json` selects.

`./scripts/coverage.sh 85` runs every suite with coverage and fails under the threshold, the same
way CI does. `./scripts/verify-packages.sh` packs the libraries and consumes them from a real
package reference, which is the only thing that catches a packaging fault.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,10 @@ time:

```csharp
[DependencyModule]
public partial class HandlerModule : IConventionModule {
void IConventionModule.Conventions(IConventionDefinitions conventions) {
public partial class HandlerModule : IConventionModule
{
void IConventionModule.Conventions(IConventionDefinitions conventions)
{
conventions.RegisterAll(typeof(IRequestHandler<,>)).AsScoped();

conventions.RegisterAll(typeof(IValidator<>))
Expand Down Expand Up @@ -172,12 +174,13 @@ Tests receive their dependencies as method parameters, against the real registra
[assembly: ApplicationModule]
[assembly: NSubstituteSupport]

public class OrderTests {
public class OrderTests
{
[ModuleTest]
public async Task PlaceOrder_PricesThroughTheChannel(
IRequestHandler<PlaceOrder, Order> handler,
[Mock] IBookRepository books) {

[Mock] IBookRepository books)
{
books.Find("isbn-1", Arg.Any<CancellationToken>())
.Returns(new Book("isbn-1", 20m));

Expand Down
Loading
Loading