-
Notifications
You must be signed in to change notification settings - Fork 7
172 lines (153 loc) · 7.62 KB
/
Copy pathcode-quality.yml
File metadata and controls
172 lines (153 loc) · 7.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
name: Code Quality
# Single consolidated job for the push/PR path: one SDK setup, one restore, one build —
# reused across formatting, header, warning-clean, and test checks. Runs on direct pushes to
# main/master (this repo commits to main directly) and on PRs. Formatting, license headers,
# a warning-clean build, and tests are BLOCKING. File size is advisory until the oversized
# files are split — see docs/CODE_QUALITY_ENFORCEMENT.md.
#
# The release path (build/pack/publish) lives in build-and-publish.yml and runs on tags only.
on:
push:
branches: [ main, master ]
paths:
- 'SharpConsoleUI/**'
- 'SharpConsoleUI.Tests/**'
- 'SharpConsoleUI.Tests/aot.test/**'
- '.editorconfig'
- '.github/workflows/code-quality.yml'
pull_request:
branches: [ main, master ]
paths:
- 'SharpConsoleUI/**'
- 'SharpConsoleUI.Tests/**'
- 'SharpConsoleUI.Tests/aot.test/**'
- '.editorconfig'
- '.github/workflows/code-quality.yml'
workflow_dispatch:
# Cancel an in-progress run when a newer commit is pushed to the same ref.
concurrency:
group: code-quality-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Single SDK setup for the whole job. The library multi-targets net8/9/10, so all three
# SDKs are required to build (and stay warning-clean) across every target. NuGet packages
# are cached across runs.
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
9.0.x
10.0.x
cache: true
cache-dependency-path: |
SharpConsoleUI/SharpConsoleUI.csproj
SharpConsoleUI.Tests/SharpConsoleUI.Tests.csproj
# --- Fast checks first: no build needed, fail early. ---
- name: Formatting (blocking)
run: |
echo "## Formatting" >> "$GITHUB_STEP_SUMMARY"
if dotnet format SharpConsoleUI/SharpConsoleUI.csproj --verify-no-changes --verbosity diagnostic; then
echo "✅ Code matches .editorconfig." >> "$GITHUB_STEP_SUMMARY"
else
echo "❌ \`dotnet format SharpConsoleUI/SharpConsoleUI.csproj\` would make changes. Run it and commit the result." >> "$GITHUB_STEP_SUMMARY"
exit 1
fi
- name: License headers (blocking)
run: |
echo "## License headers" >> "$GITHUB_STEP_SUMMARY"
missing=0
while IFS= read -r f; do
if ! head -8 "$f" | grep -q "License: MIT"; then
echo "::error file=$f::Missing file-header banner (Author / Email / License: MIT)"
missing=$((missing+1))
fi
done < <(find SharpConsoleUI -name '*.cs' -not -path '*/bin/*' -not -path '*/obj/*')
if [ "$missing" -eq 0 ]; then
echo "✅ All source files carry the header banner." >> "$GITHUB_STEP_SUMMARY"
else
echo "❌ $missing file(s) missing the header banner." >> "$GITHUB_STEP_SUMMARY"
exit 1
fi
- name: File size (advisory)
continue-on-error: true
run: |
echo "## File size (advisory)" >> "$GITHUB_STEP_SUMMARY"
# Count CODE lines only — exclude blank lines, comment lines, and the license banner —
# so well-documented files (XML doc comments) aren't penalized. Threshold is the
# documented limit + 100 slack (complex controls 800 -> 900 code lines).
echo "Files over 900 code lines — split into collaborators when practical (see docs/CODE_QUALITY.md):" >> "$GITHUB_STEP_SUMMARY"
over=0
while IFS= read -r f; do
code=$(grep -cvE '^\s*$|^\s*//|^\s*/\*|^\s*\*' "$f")
if [ "$code" -gt 900 ]; then
echo "::warning file=$f::$code code lines (>900 — consider extracting collaborators)"
echo "- \`$f\` — $code code lines" >> "$GITHUB_STEP_SUMMARY"
over=$((over+1))
fi
done < <(find SharpConsoleUI -name '*.cs' -not -path '*/bin/*' -not -path '*/obj/*')
[ "$over" -eq 0 ] && echo "✅ None." >> "$GITHUB_STEP_SUMMARY"
echo "_Advisory only — does not fail the build (yet). See docs/CODE_QUALITY_ENFORCEMENT.md Phase 4._" >> "$GITHUB_STEP_SUMMARY"
# --- Build once, then reuse it for the warning check and the tests. ---
- name: Restore
run: dotnet restore SharpConsoleUI.Tests/SharpConsoleUI.Tests.csproj
- name: Build warning-clean (blocking)
run: |
echo "## Analyzer warnings" >> "$GITHUB_STEP_SUMMARY"
# Build the test project (pulls in the library across all TFMs) so this single build is
# reused by the test step via --no-build. Capture library warnings from the output.
build_log=$(dotnet build SharpConsoleUI.Tests/SharpConsoleUI.Tests.csproj -c Release --no-restore --no-incremental 2>&1)
echo "$build_log"
# IL = trim/AOT analyzer warnings (elevated to warning in .editorconfig) so an
# AOT-compat regression in the library's own code fails this fast job too.
count=$(echo "$build_log" | grep -E "SharpConsoleUI/.*warning (CS|CA|IDE|IL)" | grep -c "warning" || true)
echo "Library code warnings (CS/CA/IDE/IL, all TFMs): **$count**" >> "$GITHUB_STEP_SUMMARY"
if [ "$count" -ne 0 ]; then
echo "❌ Build produced $count library code warning(s). The library must build warning-clean." >> "$GITHUB_STEP_SUMMARY"
exit 1
fi
echo "✅ Warning-clean." >> "$GITHUB_STEP_SUMMARY"
- name: Test (blocking)
run: |
echo "## Tests" >> "$GITHUB_STEP_SUMMARY"
dotnet test SharpConsoleUI.Tests/SharpConsoleUI.Tests.csproj -c Release --no-build --verbosity normal --blame-hang --blame-hang-timeout 120s --blame-hang-dump-type none
echo "✅ Tests passed." >> "$GITHUB_STEP_SUMMARY"
# Proves the library is NativeAOT-compatible: publishes the AotSmoke sample with
# PublishAot=true (the csproj treats trim/AOT IL warnings as errors), then runs the
# native binary headlessly. A regression that reintroduces reflection/dynamic code or
# roots an AOT-incompatible dependency fails the publish or the run.
aot:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
cache: true
cache-dependency-path: SharpConsoleUI.Tests/aot.test/AotSmoke.csproj
# NativeAOT links native code on the host, which needs clang + zlib headers.
- name: Install AOT toolchain
run: sudo apt-get update && sudo apt-get install -y clang zlib1g-dev
- name: Publish NativeAOT (blocking — IL warnings are errors)
run: |
echo "## NativeAOT publish" >> "$GITHUB_STEP_SUMMARY"
dotnet publish SharpConsoleUI.Tests/aot.test/AotSmoke.csproj -c Release -r linux-x64
echo "✅ Published native binary with no trim/AOT warnings." >> "$GITHUB_STEP_SUMMARY"
- name: Run native binary (blocking)
run: |
echo "## NativeAOT smoke run" >> "$GITHUB_STEP_SUMMARY"
bin="SharpConsoleUI.Tests/aot.test/bin/Release/net10.0/linux-x64/native/AotSmoke"
out=$("$bin" 2>&1); code=$?
echo "$out"
if [ "$code" -ne 0 ] || ! echo "$out" | grep -q "AOT SMOKE OK"; then
echo "❌ Native smoke binary failed (exit $code)." >> "$GITHUB_STEP_SUMMARY"
exit 1
fi
echo "✅ Native binary ran and exited cleanly." >> "$GITHUB_STEP_SUMMARY"