forked from zottce/samp-rs
-
Notifications
You must be signed in to change notification settings - Fork 0
357 lines (319 loc) · 14.2 KB
/
Copy pathrust.yml
File metadata and controls
357 lines (319 loc) · 14.2 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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
name: Rust
on:
push:
branches: [ "master" ]
paths-ignore: &doc-paths
- '**.md'
- 'docs/**'
- 'mkdocs.yml'
- 'LICENSE'
pull_request:
branches: [ "master" ]
paths-ignore: *doc-paths
env:
CARGO_TERM_COLOR: always
# Minimal default token; jobs escalate explicitly where needed.
permissions:
contents: read
jobs:
# ---------------------------------------------------------------------------
# Detect whether benchmark-relevant code changed. The bench job is gated on
# this so it does not run for docs-, changelog- or CI-only changes.
# ---------------------------------------------------------------------------
changes:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
outputs:
code: ${{ steps.filter.outputs.code }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: dorny/paths-filter@7b450fff21473bca461d4b92ce414b9d0420d706 # v4.0.2
id: filter
with:
filters: |
code:
- 'samp/**'
- 'samp-sdk/**'
- 'samp-codegen/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'scripts/**'
- '.github/workflows/rust.yml'
# ---------------------------------------------------------------------------
# Cross-platform build, test and lint (i686)
# ---------------------------------------------------------------------------
build:
strategy:
matrix:
include:
- os: ubuntu-latest
target: i686-unknown-linux-gnu
artifact: target/i686-unknown-linux-gnu/debug/libplugin.so
- os: windows-latest
target: i686-pc-windows-msvc
artifact: target/i686-pc-windows-msvc/debug/plugin.dll
# 64-bit target where `c_char == u8` (unlike the 32-bit targets above,
# where it is `i8`). Cross-compiled and only `cargo check`ed — it can't
# run natively on the x64 runner — to catch ABI/type mismatches in the
# FFI signatures that a 32-bit-only matrix would miss.
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
check_only: true
runs-on: ${{ matrix.os }}
permissions:
contents: read # checkout
actions: write # upload-artifact + rust-cache (cache write)
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Install Rust
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
targets: ${{ matrix.target }}
- name: Install system dependencies (Linux)
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y gcc-multilib g++-multilib
- name: Cache cargo build
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
cache-all-crates: true
prefix-key: "v1"
# Cross-only target (aarch64): just type-check the pure-Rust library crates —
# it can't run on the x64 runner. Catches ABI/type regressions like `c_char`
# (`i8` vs `u8`). Scoped to the SDK/codegen/samp crates so it doesn't drag in
# example-only deps with C build scripts (aws-lc-sys) that would need a cross
# C toolchain not installed here.
- name: Check (cross-only target)
if: matrix.check_only
run: cargo check -p rust-samp-sdk -p rust-samp-codegen -p rust-samp --target ${{ matrix.target }}
- name: Build
if: '!matrix.check_only'
run: cargo build --verbose --target ${{ matrix.target }}
- name: Run tests
if: '!matrix.check_only'
run: cargo test --verbose --target ${{ matrix.target }}
- name: Run clippy
if: '!matrix.check_only'
run: cargo clippy --all-targets --target ${{ matrix.target }} -- -D warnings
- name: Security audit
if: runner.os == 'Linux' && !matrix.check_only
run: cargo install cargo-audit --locked && cargo audit
- name: Upload artifact
if: '!matrix.check_only && github.event_name == ''push'' && github.ref == ''refs/heads/master'''
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: plugin-${{ matrix.target }}
path: ${{ matrix.artifact }}
retention-days: 14
# ---------------------------------------------------------------------------
# Benchmarks — Linux i686
#
# Runs on: push to master AND pull_request.
# Baseline flow:
# 1. Restore the baseline saved in the previous master run (via cache)
# 2. Run benchmarks saving as "new"
# 3. If a "main" baseline exists, compare with critcmp and print regressions
# 4. Push to master only: promote "new" → "main" and save to cache for the next run
# 5. Always: write the report to the run's Step Summary (visible in the PR
# checks tab without needing to download the artifact)
# ---------------------------------------------------------------------------
bench:
needs: changes
runs-on: ubuntu-latest
# Run only when benchmark-relevant code changed (see the `changes` job) and
# never for Dependabot (dependency bumps don't need a bench run, and
# Dependabot PRs get a read-only token that can't post the comment).
if: |
needs.changes.outputs.code == 'true' &&
github.actor != 'dependabot[bot]' &&
(
(github.event_name == 'push' && github.ref == 'refs/heads/master') ||
github.event_name == 'pull_request'
)
permissions:
contents: read # checkout
actions: write # cache write (promotion of "new" → "main" baseline on master)
pull-requests: write # post / update the sticky PR comment with the bench report
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Install Rust
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
targets: i686-unknown-linux-gnu
- name: Install system dependencies
run: sudo apt-get update && sudo apt-get install -y gcc-multilib g++-multilib
- name: Cache cargo build
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
cache-all-crates: true
prefix-key: "v1-bench"
- name: Restore benchmark baseline
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: target/criterion
key: bench-baseline-main
# Accept any previously saved baseline if there is no exact match
restore-keys: bench-baseline-
- name: Run benchmarks
shell: bash
run: |
# `set -o pipefail` is required — without it, a failing `cargo bench`
# exits non-zero but the pipeline status is taken from `tee` (which
# always succeeds), silently swallowing the failure and producing an
# empty `target/criterion/` that breaks extract-bench downstream.
set -euo pipefail
# Two criterion 0.8.2 workarounds, both needed:
#
# 1. We do NOT pass `--save-baseline new` even though we want results
# in `new/`. Criterion's *default* already saves to `new/`
# (and rotates the previous `new/` to `base/`). With criterion
# 0.8.2, passing `--save-baseline new` explicitly creates the
# `new/*.json` files as 0 bytes, which then breaks both critcmp
# and `scripts/extract-bench.py` downstream. Skipping the flag
# keeps the same `new/` directory layout that "Promote new
# baseline to main" expects, with valid JSON contents.
#
# 2. `--noplot` skips the HTML report generation. The `plotters`
# backend in criterion 0.8.2 panics in
# `plot/plotters_backend/summary.rs:199` with
# `Option::unwrap on a None value` after benchmarks finish on
# CI. CI does not need HTML — critcmp and extract-bench read
# the raw JSON which criterion still writes correctly.
cargo bench -p rust-samp-sdk --target i686-unknown-linux-gnu -- \
--noplot \
2>&1 | tee bench_results.txt
- name: Compare against baseline and generate report
run: |
if [ -d target/criterion ]; then
HAS_MAIN=$(find target/criterion -name "estimates.json" -path "*/main/*" | head -1)
if [ -n "$HAS_MAIN" ]; then
echo "Comparing against previous baseline..."
cargo install critcmp --locked --quiet
critcmp main new --threshold 5 | tee bench_comparison.txt || true
# Generate bench_report.md with a Markdown table
echo "# Benchmark Report" > bench_report.md
echo "" >> bench_report.md
echo "Comparison between the previous baseline (\`main\`) and the current build (\`new\`)." >> bench_report.md
echo "Threshold: changes >= 5% are reported." >> bench_report.md
echo "" >> bench_report.md
echo "| Benchmark | Before (main) | After (new) | Δ% |" >> bench_report.md
echo "|-----------|---------------|-------------|-----|" >> bench_report.md
# Parse critcmp output (lines: " bench_name before after pct%")
grep -E "^\s+\S" bench_comparison.txt | while IFS= read -r line; do
name=$(echo "$line" | awk '{print $1}')
before=$(echo "$line" | awk '{print $2, $3}')
after=$(echo "$line" | awk '{print $4, $5}')
pct=$(echo "$line" | awk '{print $NF}')
echo "| \`$name\` | $before | $after | $pct |" >> bench_report.md
done
# Summary
improved=$(grep -c "^-\|IMPROVED" bench_comparison.txt 2>/dev/null || echo 0)
regressed=$(grep -c "^+\|REGRESSED" bench_comparison.txt 2>/dev/null || echo 0)
echo "" >> bench_report.md
echo "**Summary:** improvements: $improved | regressions: $regressed" >> bench_report.md
echo "" >> bench_report.md
echo "_Generated automatically by CI at \`$(date -u '+%Y-%m-%d %H:%M UTC')\`_" >> bench_report.md
else
echo "No previous baseline found — this run will be the first." | tee bench_comparison.txt
echo "# Benchmark Report" > bench_report.md
echo "" >> bench_report.md
echo "No previous baseline found — this is the first run." >> bench_report.md
fi
fi
- name: Extract per-bench data (mean + CI)
env:
VERSION: ${{ github.ref_name }}
GIT_SHA: ${{ github.sha }}
run: python3 scripts/extract-bench.py
- name: Publish report to Step Summary
if: always()
run: |
{
if [ -f bench_report.md ]; then
cat bench_report.md
echo ""
fi
if [ -f bench-entry.json ]; then
python3 scripts/render-bench-entry.py
fi
} >> "$GITHUB_STEP_SUMMARY"
- name: Fetch previous bench comment (if any)
if: github.event_name == 'pull_request'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
shell: bash
run: |
# The sticky-pull-request-comment action tags its comment with the
# marker below. We use the same marker to locate the prior comment
# and extract the previous run's bench data from it.
STICKY_TAG="<!-- Sticky Pull Request Commentbench-report -->"
gh api "repos/${REPO}/issues/${PR_NUMBER}/comments" \
--paginate \
--jq ".[] | select(.body | contains(\"$STICKY_TAG\")) | .body" \
> previous_comment.md || true
if [ -s previous_comment.md ]; then
echo "Previous bench comment found ($(wc -c < previous_comment.md) bytes)."
else
echo "No previous bench comment on this PR yet — first run."
fi
- name: Build PR comment body
if: github.event_name == 'pull_request'
shell: bash
env:
PR_NUM: ${{ github.event.pull_request.number }}
PR_REF: ${{ github.event.pull_request.head.ref }}
SHA: ${{ github.event.pull_request.head.sha }}
SERVER_URL: ${{ github.server_url }}
REPO: ${{ github.repository }}
RUN_ID: ${{ github.run_id }}
run: |
# For PR builds, github.ref_name is "<num>/merge" — turn it into
# something more legible like "#5 (head_ref)". Untrusted values come
# through env (not interpolated into the shell) to avoid injection.
VERSION="#${PR_NUM} (${PR_REF})"
RUN_URL="${SERVER_URL}/${REPO}/actions/runs/${RUN_ID}"
python3 scripts/build-bench-comment.py \
--current bench-entry.json \
--previous previous_comment.md \
--version "$VERSION" \
--sha "$SHA" \
--run-url "$RUN_URL" \
--output pr_comment.md
echo "::group::Comment preview (first 40 lines)"
head -40 pr_comment.md
echo "::endgroup::"
- name: Post / update bench comment on the PR
if: github.event_name == 'pull_request'
uses: marocchino/sticky-pull-request-comment@5770ad5eb8f42dd2c4f34da00c94c5381e49af88 # v3.0.5
with:
header: bench-report # identifies which sticky comment to update
path: pr_comment.md
- name: Promote new baseline to main
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
run: |
# Copy "new" baseline results to "main" (overwrites)
find target/criterion -type d -name "new" | while read dir; do
main_dir="${dir%/new}/main"
rm -rf "$main_dir"
cp -r "$dir" "$main_dir"
done
- name: Save benchmark baseline
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: target/criterion
key: bench-baseline-${{ github.sha }}
- name: Upload benchmark results
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: bench-results
path: |
bench_results.txt
bench_comparison.txt
bench_report.md
bench-entry.json
if-no-files-found: warn
retention-days: 14