diff --git a/.editorconfig b/.editorconfig index 422c04f5bc..fbc7f89474 100644 --- a/.editorconfig +++ b/.editorconfig @@ -215,6 +215,7 @@ dotnet_diagnostic.IL2026.severity = none dotnet_diagnostic.IL2070.severity = none dotnet_diagnostic.IL2075.severity = none dotnet_diagnostic.IL2090.severity = none +dotnet_diagnostic.CA2255.severity = none # This appears to be broken and results in false positives (causing dotnet format to delete valid test scenarios) dotnet_diagnostic.xUnit1025.severity = none diff --git a/.gitattributes b/.gitattributes index b5b1948c75..4f6b1f7048 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,6 +3,7 @@ *.sln text=auto eol=crlf *.slnx text=auto eol=lf *.sh eol=lf +.githooks/* eol=lf *.ps1 eol=lf CHANGELOG.md merge=union diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 0000000000..f92c94c85d --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,45 @@ +#!/bin/bash +set -e + +echo "🔍 Checking code formatting..." + +if ! git diff --quiet; then + echo "⚠️ Skipping format check: unstaged changes present." + echo " Stage or stash all changes before committing to enable the format check." + exit 0 +fi + +INCLUDE_ARGS=() +while IFS= read -r f; do + INCLUDE_ARGS+=(--include "$f") +done < <(git diff --cached --name-only --diff-filter=ACM | grep '\.cs$' || true) + +if [ ${#INCLUDE_ARGS[@]} -eq 0 ]; then + echo "✅ No C# files staged." + exit 0 +fi + +FORMAT_OUTPUT=$(dotnet format Sentry.slnx --no-restore \ + "${INCLUDE_ARGS[@]}" \ + --exclude ./modules ./**/*OptionsSetup.cs ./test/Sentry.Tests/AttributeReaderTests.cs 2>&1) || { + echo "" + echo "❌ dotnet format failed:" + echo "$FORMAT_OUTPUT" + echo "" + exit 1 +} + +if ! git diff --quiet; then + echo "" + echo "❌ Code formatting issues found!" + echo "" + echo "Please stage the formatting fixes and commit again:" + echo "" + echo " git add -u" + echo " git commit" + echo "" + exit 1 +fi + +echo "✅ Code formatting looks good!" +exit 0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e67f7916ae..69e350a0b2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,6 +22,31 @@ For a big feature it's advised to raise an issue to discuss it first. * To quickly get up and running, you can just run `dotnet build SentryNoMobile.slnf` (you're skipping the mobile targets) * To run a full build in Release mode and test, before pushing, run `./build.sh` or `./build.cmd` +## Git Hooks (Optional but Recommended) + +To automatically check and fix code formatting before committing, you can set up a pre-commit hook: + +```bash +./dev.cs setup-hooks +``` + +Before each commit, the hook runs `dotnet format` against your staged `.cs` files and auto-fixes any formatting issues. If fixes were applied, the commit is blocked — just stage the fixes and try again: + +```bash +git add -u +git commit +``` + +Note: the hook skips automatically if you have unstaged changes, to avoid touching work in progress. + +To opt out at any time: + +```bash +./dev.cs remove-hooks +``` + +**Note:** You can also bypass the hook for a specific commit using `git commit --no-verify` if needed. + ## Minimal Dependencies * The latest versions of the following .NET SDKs: diff --git a/dev.cs b/dev.cs index 7e441ab646..0eb57d78b4 100755 --- a/dev.cs +++ b/dev.cs @@ -103,6 +103,20 @@ public Task AiUpdateAsync(GlobalOptions options = default!) return RunStepAsync("npx @sentry/dotagents install", "npx", "@sentry/dotagents install", options.DryRun); } + [Command("setup-hooks", Description = "Configure git to use the repo's pre-commit hooks from .githooks/.")] + public Task SetupHooksAsync(GlobalOptions options = default!) + { + Console.WriteLine("[dev] Configuring git hooks path to .githooks/"); + return RunStepAsync("git config core.hooksPath", "git", "config core.hooksPath .githooks", options.DryRun); + } + + [Command("remove-hooks", Description = "Restore default git hooks behaviour (stops using .githooks/).")] + public Task RemoveHooksAsync(GlobalOptions options = default!) + { + Console.WriteLine("[dev] Restoring default git hooks path"); + return RunStepAsync("git config --unset core.hooksPath", "git", "config --unset core.hooksPath", options.DryRun); + } + [Command("nrest", Description = "Restore the default CI solution.")] public Task SolutionRestoreAsync( [Argument("solution", Description = "Solution file to restore. Defaults to platform-specific CI solution if omitted.")] string? solution = null,