Repository navigation
155 lines (130 loc) · 5.74 KB
/
Copy pathci.yml
File metadata and controls
155 lines (130 loc) · 5.74 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
name: CI/CD Pipeline
on:
push:
branches: [ master, main, develop ]
pull_request:
branches: [ master, main ]
# Least privilege by default; jobs opt into more where needed.
permissions:
contents: read
env:
DOTNET_VERSION: '10.0.x'
NODE_VERSION: '20.x'
# Third-party and first-party actions are pinned to full commit SHAs (tag comment alongside) so a
# retagged or compromised release can't silently change what runs in CI.
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup .NET
uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Restore .NET dependencies
run: dotnet restore
- name: Install npm dependencies
run: npm ci
# Coverage is collected through coverlet's MSBuild integration rather than the
# `--collect:"XPlat Code Coverage"` data collector: only the MSBuild integration exposes
# /p:Threshold, and running both integrations in one invocation is unsupported. The cobertura
# report still lands in TestResults/, so the artifact upload below is unchanged.
#
# COVERAGE RATCHET - floors, not goals. Measured 2026-07-31 (263 tests):
# line 80.51% branch 77.80% method 92.27%
# Floors are set ~2-3 points under measured. ThresholdStat=total scores the whole run, not the
# worst module. RATCHET UPWARD ONLY: if a change pushes coverage under a floor, write the
# tests. Lowering a number here to turn a red build green removes the only thing this gate does.
# (%2c is an escaped comma - the dotnet CLI splits unescaped commas in -p: into new switches.)
#
# --blame-hang is the backstop for unbounded awaits: xunit has no default per-test timeout, so a
# test awaiting a TaskCompletionSource that is never completed hangs the runner until GitHub
# kills the job (6h) with no dump and no clue which test did it. 5m is per-test; the whole suite
# finishes in ~1s locally, so this fires only on a genuine hang, never on a slow runner.
- name: Run backend tests
run: >-
dotnet test csgoSkinStatistics.Tests --no-restore --verbosity normal
--logger trx --results-directory TestResults
--blame-hang --blame-hang-timeout 5m
-p:CollectCoverage=true
-p:CoverletOutputFormat=cobertura
-p:CoverletOutput=../TestResults/coverage.cobertura.xml
-p:Threshold=78%2c75%2c90
-p:ThresholdType=line%2cbranch%2cmethod
-p:ThresholdStat=total
# --coverage is what makes jest.config.js's coverageThreshold do anything at all; without it the
# declared threshold is inert. See jest.config.js for the measured values and the ratchet rule.
- name: Run frontend tests
run: npm test -- --coverage --watchAll=false
- name: Run linting
run: npm run lint
# No -warnaserror here on purpose: TreatWarningsAsErrors is set in both .csproj files instead,
# so the nullable analysis that <Nullable>enable</Nullable> was already running gates this
# build, the `dotnet test` build above, `dotnet publish` in build-and-package, and every local
# build - not just this one step. A CI-only switch would let warnings accumulate on developer
# machines and in the test job and only surface here, at the end of the pipeline.
- name: Build application
run: dotnet build --no-restore --configuration Release
- name: Upload test results
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: always()
with:
name: test-results
path: TestResults/
security-scan:
runs-on: ubuntu-latest
needs: test
permissions:
contents: read
security-events: write # upload-sarif writes to the code-scanning API
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
# Fail the build on actionable high/critical findings; the SARIF still uploads below.
severity: 'CRITICAL,HIGH'
exit-code: '1'
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@a8d1ac45b9a34d11fe398d5503176af0d06b303e # v3.30.7
if: always()
with:
sarif_file: 'trivy-results.sarif'
build-and-package:
runs-on: ubuntu-latest
needs: [test, security-scan]
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup .NET
uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: |
dotnet restore
npm ci
- name: Publish application
run: dotnet publish --configuration Release --output ./publish
- name: Upload build artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: published-app
path: ./publish/