Repository navigation
146 lines (128 loc) · 5.58 KB
/
Copy pathci.yml
File metadata and controls
146 lines (128 loc) · 5.58 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
# 日常 push / PR 的构建与测试门禁;发布流水线见 release.yml。
name: ci
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
build-test:
strategy:
fail-fast: false
matrix:
include:
# 现代 .NET 在 linux 跑(附带覆盖率收集);net48(验证 netstandard2.0 资产)需要 Windows 运行时
- os: ubuntu-latest
frameworks: "net8.0 net10.0"
- os: windows-latest
frameworks: "net48"
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v7
- name: Set up .NET
uses: actions/setup-dotnet@v6
with:
dotnet-version: |
8.0.x
10.0.x
- name: Build
run: dotnet build StreamFrame.slnx -c Release
- name: Test (${{ matrix.frameworks }})
shell: bash
env:
FRAMEWORKS: ${{ matrix.frameworks }}
# 覆盖率只在 Ubuntu 收集(矩阵值不进 job 名,避免必需检查名随之变化)
COLLECT_COVERAGE: ${{ matrix.os == 'ubuntu-latest' }}
run: |
for fw in $FRAMEWORKS; do
if [ "$COLLECT_COVERAGE" = "true" ]; then
dotnet test StreamFrame.slnx -c Release --no-build -f $fw \
--collect:"XPlat Code Coverage" --results-directory "coverage/$fw"
else
dotnet test StreamFrame.slnx -c Release --no-build -f $fw
fi
done
# 覆盖率摘要写入 job Summary(自包含,不依赖外部服务);原始 cobertura XML 附为 artifact
- name: Coverage summary
if: matrix.os == 'ubuntu-latest'
shell: bash
run: |
python3 - <<'PYEOF'
import glob, os, xml.etree.ElementTree as ET
def fmt(rate):
return f"{rate * 100:.1f}%"
lines = ["", "## 测试覆盖率(XPlat Code Coverage)", "",
"| 目标 | Line | Branch | 覆盖行/总行 |", "|---|---|---|---|"]
for tfm_dir in sorted(glob.glob("coverage/*")):
tfm = os.path.basename(tfm_dir)
reports = glob.glob(os.path.join(tfm_dir, "**", "coverage.cobertura.xml"), recursive=True)
if not reports:
continue
# 同一 TFM 只应有一份(单一测试项目);防御性取第一份
root = ET.parse(reports[0]).getroot()
line_rate = float(root.get("line-rate", "0"))
branch_rate = float(root.get("branch-rate", "0"))
all_lines = list(root.iter("line"))
covered_lines = sum(1 for l in all_lines if int(l.get("hits", "0")) > 0)
lines.append(f"| {tfm} | {fmt(line_rate)} | {fmt(branch_rate)} | {covered_lines}/{len(all_lines)} |")
if tfm.endswith("net8.0"):
detail = ["", f"<details><summary>按程序集({tfm})</summary>", "",
"| 程序集 | Line | Branch |", "|---|---|---|"]
for pkg in root.iter("package"):
detail.append(f"| {pkg.get('name', '?')} | "
f"{fmt(float(pkg.get('line-rate', '0')))} | "
f"{fmt(float(pkg.get('branch-rate', '0')))} |")
detail += ["", "</details>", ""]
lines += detail
summary = "\n".join(lines) + "\n"
print(summary)
with open(os.environ.get("GITHUB_STEP_SUMMARY", "/dev/stdout"), "a", encoding="utf-8") as f:
f.write(summary)
PYEOF
- name: Upload coverage artifacts
if: matrix.os == 'ubuntu-latest'
uses: actions/upload-artifact@v7
with:
name: coverage-${{ github.run_number }}
path: coverage/
retention-days: 14
# NativeAOT/裁剪兼容性门禁(非必需检查):发布引用库的冒烟工程(PublishAot 在工程内开启,
# 涵盖裁剪分析)。IL2026/IL3050 等警告经 TreatWarningsAsErrors 变为错误,防止库悄悄
# 引入反射/动态代码。ubuntu runner 自带 AOT 原生工具链。
aot:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v7
- name: Set up .NET
uses: actions/setup-dotnet@v6
with:
dotnet-version: |
8.0.x
10.0.x
- name: PublishAot(NativeAOT + 裁剪警告门禁)
run: dotnet publish samples/StreamFrame.AotSmoke -c Release -r linux-x64 -o artifacts/aot
- name: Run NativeAOT smoke(连接、会话发送、普通发送与内容校验)
run: timeout 40s ./artifacts/aot/StreamFrame.AotSmoke
- name: Verify NativeAOT failure exit codes
shell: bash
run: |
set -euo pipefail
for fault in connect missing consumer content; do
category="$fault"
case "$fault" in
connect) category=connection ;;
missing) category=messages ;;
esac
status=0
timeout 40s ./artifacts/aot/StreamFrame.AotSmoke "--fault=$fault" > "$fault.log" 2>&1 || status=$?
cat "$fault.log"
# 只接受程序自身报告的指定故障:0、崩溃、启动失败或 timeout 的 124 均失败。
if [ "$status" -ne 1 ] || ! grep -Fq "AOT smoke FAILED [$category]:" "$fault.log"; then
echo "::error::Fault $fault was not detected correctly (exit=$status)"
exit 1
fi
echo "Verified expected failure: $fault (exit=$status)" | tee -a "$GITHUB_STEP_SUMMARY"
done