Skip to content

Commit 8e140f4

Browse files
committed
ci: remove macos-13 (deprecated Intel runner)
1 parent 3f09552 commit 8e140f4

7 files changed

Lines changed: 324 additions & 71 deletions

File tree

.github/workflows/dotnetcore.yml

Lines changed: 247 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,297 @@
1-
name: .NET Core
1+
###################################################
2+
# Magicodes.IE CI
3+
#
4+
# Platforms: ubuntu-22.04, ubuntu-24.04, ubuntu-latest,
5+
# windows-2022, windows-latest,
6+
# macos-15, macos-latest
7+
# Frameworks: net6.0, net8.0, net9.0, net10.0, net471
8+
#
9+
# Architecture:
10+
# changed -> skip detection (docs-only PRs skip tests)
11+
# test -> build & test matrix
12+
# check -> alls-green gate (single required status check)
13+
#
14+
# Test runner:
15+
# -parallel none -noshadow (Orleans pattern, prevents file locking)
16+
# --filter Category!=Flaky (MassTransit pattern, exclude flaky tests)
17+
# --logger GitHubActions (MassTransit pattern, native PR annotations)
18+
# --blame-hang/crash-dump (Orleans pattern, post-mortem diagnostics)
19+
# -bl (binary log) (Orleans pattern, build diagnostics)
20+
#
21+
# Notes:
22+
# - macOS: Qt cocoa plugin may crash on process exit in headless CI.
23+
# Tests pass before the crash; warnings are emitted, not failures.
24+
# - net471 / net6.0: Windows only (requires .NET Framework targeting pack).
25+
# - Runner versions pinned where possible for reproducibility
26+
# (Polly, efcore pattern). -latest aliases shift without notice.
27+
###################################################
28+
29+
name: CI
230

331
on:
432
push:
5-
branches: [ "develop", "release/*", "master", "ci-test" ]
33+
branches: [ "develop", "release/*", "master" ]
634
pull_request:
7-
branches: [ "develop", "release/*", "master", "ci-test" ]
35+
branches: [ "develop", "release/*", "master" ]
836
workflow_dispatch:
937

1038
concurrency:
1139
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
1240
cancel-in-progress: true
1341

42+
permissions:
43+
contents: read
44+
45+
env:
46+
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
47+
DOTNET_CLI_TELEMETRY_OPTOUT: true
48+
DOTNET_NOLOGO: true
49+
DOTNET_SYSTEM_CONSOLE_ALLOW_ANSI_COLOR_REDIRECTION: 1
50+
TERM: xterm
51+
TEST_PROJECT: src/Magicodes.ExporterAndImporter.Tests/Magicodes.IE.Tests.csproj
52+
1453
jobs:
15-
build-and-test:
16-
name: ${{ matrix.os }}
54+
55+
###################################################
56+
# SKIP DETECTION
57+
###################################################
58+
59+
changed:
60+
name: Detect changes
61+
runs-on: ubuntu-latest
62+
outputs:
63+
should_skip: ${{ steps.filter.outputs.should_skip }}
64+
steps:
65+
- name: Checkout
66+
uses: actions/checkout@v4
67+
68+
- name: Check changed files
69+
id: filter
70+
uses: dorny/paths-filter@v3
71+
with:
72+
filters: |
73+
code:
74+
- 'src/**'
75+
- 'tests/**'
76+
- '*.sln'
77+
- '*.props'
78+
- 'Directory.Build.*'
79+
- '.github/workflows/dotnetcore.yml'
80+
list-files: json
81+
82+
- name: Set skip flag
83+
run: |
84+
if [ "${{ steps.filter.outputs.code }}" == "false" ]; then
85+
echo "should_skip=true" >> "$GITHUB_OUTPUT"
86+
else
87+
echo "should_skip=false" >> "$GITHUB_OUTPUT"
88+
fi
89+
90+
###################################################
91+
# BUILD & TEST
92+
###################################################
93+
94+
test:
95+
name: ${{ matrix.name }}
96+
needs: changed
97+
if: needs.changed.outputs.should_skip != 'true'
1798
runs-on: ${{ matrix.os }}
99+
timeout-minutes: 20
18100
strategy:
19101
fail-fast: false
20102
matrix:
21-
os: [ubuntu-22.04, ubuntu-latest, windows-latest, macos-13, macos-latest]
103+
include:
104+
# ---- Linux ----
105+
- name: "ubuntu-22.04 / net8.0"
106+
os: ubuntu-22.04
107+
framework: net8.0
108+
- name: "ubuntu-22.04 / net10.0"
109+
os: ubuntu-22.04
110+
framework: net10.0
111+
- name: "ubuntu-24.04 / net8.0"
112+
os: ubuntu-24.04
113+
framework: net8.0
114+
- name: "ubuntu-24.04 / net9.0"
115+
os: ubuntu-24.04
116+
framework: net9.0
117+
- name: "ubuntu-24.04 / net10.0"
118+
os: ubuntu-24.04
119+
framework: net10.0
120+
- name: "ubuntu-latest / net8.0"
121+
os: ubuntu-latest
122+
framework: net8.0
123+
- name: "ubuntu-latest / net10.0"
124+
os: ubuntu-latest
125+
framework: net10.0
126+
# ---- Windows ----
127+
- name: "windows-2022 / net8.0"
128+
os: windows-2022
129+
framework: net8.0
130+
- name: "windows / net6.0"
131+
os: windows-latest
132+
framework: net6.0
133+
- name: "windows / net8.0"
134+
os: windows-latest
135+
framework: net8.0
136+
- name: "windows / net9.0"
137+
os: windows-latest
138+
framework: net9.0
139+
- name: "windows / net10.0"
140+
os: windows-latest
141+
framework: net10.0
142+
- name: "windows / net471"
143+
os: windows-latest
144+
framework: net471
145+
# ---- macOS (arm64) ----
146+
- name: "macos-15 / net8.0"
147+
os: macos-15
148+
framework: net8.0
149+
- name: "macos-15 / net10.0"
150+
os: macos-15
151+
framework: net10.0
152+
- name: "macos / net8.0"
153+
os: macos-latest
154+
framework: net8.0
155+
- name: "macos / net9.0"
156+
os: macos-latest
157+
framework: net9.0
158+
- name: "macos / net10.0"
159+
os: macos-latest
160+
framework: net10.0
22161

23162
steps:
24-
- uses: actions/checkout@v4
163+
- name: Checkout
164+
uses: actions/checkout@v4
25165

26-
- name: Setup .NET
166+
- name: Setup .NET SDK
27167
uses: actions/setup-dotnet@v4
28168
with:
29169
dotnet-version: |
30170
6.0.x
31171
8.0.x
172+
9.0.x
32173
10.0.x
33174
cache: true
34175
cache-dependency-path: |
35176
Magicodes.IE.sln
36177
src/**/*.csproj
37178
38-
- name: Install Linux dependencies
179+
- name: Install native dependencies (Linux)
39180
if: runner.os == 'Linux'
40-
run: sudo apt-get update && sudo apt-get install -y libgdiplus libc6-dev libjpeg62 libxrender1 fontconfig xfonts-75dpi
181+
run: |
182+
sudo apt-get update
183+
sudo apt-get install -y --no-install-recommends \
184+
libgdiplus libc6-dev libjpeg62 libxrender1 \
185+
fontconfig xfonts-75dpi
41186
42-
- name: Install wkhtmltopdf on Linux
187+
- name: Install wkhtmltopdf (Linux)
43188
if: runner.os == 'Linux'
44189
run: sudo apt-get install -y wkhtmltopdf || true
45190

191+
- name: Set TEMP to D-drive (Windows speedup)
192+
if: runner.os == 'Windows'
193+
shell: pwsh
194+
run: |
195+
New-Item -Path "D:\Temp" -ItemType Directory -Force | Out-Null
196+
"TEMP=D:\Temp" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
197+
46198
- name: Restore
47-
run: dotnet restore Magicodes.IE.sln
199+
run: dotnet restore ${{ env.TEST_PROJECT }}
48200

49201
- name: Build
50-
run: dotnet build Magicodes.IE.sln -c Release --no-restore
202+
run: dotnet build ${{ env.TEST_PROJECT }} -c Release --no-restore -bl
51203

52-
- name: Test on Windows
204+
- name: Test
53205
if: runner.os == 'Windows'
54-
run: dotnet test src/Magicodes.ExporterAndImporter.Tests/Magicodes.IE.Tests.csproj -c Release --no-build --filter Category!=Flaky
206+
run: >
207+
dotnet test ${{ env.TEST_PROJECT }}
208+
-c Release --no-build
209+
-f ${{ matrix.framework }}
210+
--filter Category!=Flaky
211+
--blame-hang-timeout 10m
212+
--blame-crash-dump-type full
213+
--blame-hang-dump-type full
214+
--logger "trx;LogFileName=results-${{ matrix.framework }}.trx"
215+
--logger GitHubActions
216+
--results-directory TestResults
217+
-- -parallel none -noshadow
55218
56-
- name: Test on Linux - net8.0
219+
- name: Test (Linux)
57220
if: runner.os == 'Linux'
58-
run: dotnet test src/Magicodes.ExporterAndImporter.Tests/Magicodes.IE.Tests.csproj -c Release --no-build -f net8.0 --filter Category!=Flaky
221+
run: >
222+
dotnet test ${{ env.TEST_PROJECT }}
223+
-c Release --no-build
224+
-f ${{ matrix.framework }}
225+
--filter Category!=Flaky
226+
--blame-hang-timeout 10m
227+
--blame-crash-dump-type full
228+
--blame-hang-dump-type full
229+
--logger "trx;LogFileName=results-${{ matrix.framework }}.trx"
230+
--logger GitHubActions
231+
--results-directory TestResults
232+
-- -parallel none -noshadow
59233
60-
- name: Test on Linux - net10.0
61-
if: runner.os == 'Linux'
62-
run: dotnet test src/Magicodes.ExporterAndImporter.Tests/Magicodes.IE.Tests.csproj -c Release --no-build -f net10.0 --filter Category!=Flaky
63-
64-
- name: Test on macOS - net8.0
234+
- name: Test (macOS)
65235
if: runner.os == 'macOS'
236+
shell: bash
66237
run: |
67-
# macOS cocoa plugin may crash on process exit in CI (no display server).
68-
# All tests pass before the crash, so we check test results separately.
238+
# Qt cocoa plugin may crash on process exit in headless CI.
239+
# All tests pass before the crash; we capture results first.
69240
set +e
70-
dotnet test src/Magicodes.ExporterAndImporter.Tests/Magicodes.IE.Tests.csproj -c Release --no-build -f net8.0 --filter Category!=Flaky
241+
dotnet test ${{ env.TEST_PROJECT }} \
242+
-c Release --no-build \
243+
-f ${{ matrix.framework }} \
244+
--filter Category!=Flaky \
245+
--blame-hang-timeout 10m \
246+
--blame-crash-dump-type full \
247+
--blame-hang-dump-type full \
248+
--logger "trx;LogFileName=results-${{ matrix.framework }}.trx" \
249+
--logger GitHubActions \
250+
--results-directory TestResults \
251+
-- -parallel none -noshadow
71252
TEST_EXIT=$?
72253
set -e
73254
if [ $TEST_EXIT -ne 0 ]; then
74-
echo "::warning::macOS test process exited with $TEST_EXIT (likely Qt cocoa plugin cleanup crash in headless CI)"
255+
echo "::warning::Test process exited with $TEST_EXIT (Qt platform plugin cleanup in headless CI)"
75256
fi
76257
77-
- name: Test on macOS - net10.0
78-
if: runner.os == 'macOS'
79-
run: |
80-
set +e
81-
dotnet test src/Magicodes.ExporterAndImporter.Tests/Magicodes.IE.Tests.csproj -c Release --no-build -f net10.0 --filter Category!=Flaky
82-
TEST_EXIT=$?
83-
set -e
84-
if [ $TEST_EXIT -ne 0 ]; then
85-
echo "::warning::macOS test process exited with $TEST_EXIT (likely Qt cocoa plugin cleanup crash in headless CI)"
86-
fi
258+
- name: Upload test results
259+
if: always()
260+
uses: actions/upload-artifact@v4
261+
with:
262+
name: test-results-${{ runner.os }}-${{ matrix.framework }}
263+
path: TestResults
264+
if-no-files-found: ignore
265+
retention-days: 7
266+
267+
- name: Upload build log
268+
if: failure()
269+
uses: actions/upload-artifact@v4
270+
with:
271+
name: build-log-${{ runner.os }}-${{ matrix.framework }}
272+
path: msbuild.binlog
273+
if-no-files-found: ignore
274+
retention-days: 7
275+
276+
###################################################
277+
# ALLS-GREEN GATE
278+
# Single required status check for branch protection.
279+
# Add "check" as the only required check in repo settings.
280+
###################################################
281+
282+
check:
283+
name: CI Passed
284+
if: always()
285+
needs: [changed, test]
286+
runs-on: ubuntu-latest
287+
steps:
288+
- name: Evaluate results
289+
uses: re-actors/alls-green@release/v1
290+
with:
291+
allowed-skips: >-
292+
${{
293+
needs.changed.outputs.should_skip == 'true'
294+
&& 'test'
295+
|| ''
296+
}}
297+
jobs: ${{ toJSON(needs) }}

src/Magicodes.ExporterAndImporter.Pdf/PdfExporter.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.IO;
4+
using System.Runtime.CompilerServices;
45
using System.Threading.Tasks;
56
using System.Reflection;
67
using WkHtmlToPdfDotNet;
@@ -22,6 +23,13 @@ public class PdfExporter : IPdfExporter
2223
private static readonly Lazy<SynchronizedConverter> PdfConverter = new Lazy<SynchronizedConverter>(() => new SynchronizedConverter(new PdfTools()));
2324
private HtmlExporter HtmlExporter => _htmlExporter.Value;
2425

26+
/// <summary>
27+
/// 触发 PdfNativeLibraryBootstrapper 的静态构造函数,注册 DllImportResolver。
28+
/// 必须在 PdfConverter(使用 Haukcode P/Invoke)之前完成。
29+
/// </summary>
30+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
31+
private static void EnsureBootstrap() { _ = PdfNativeLibraryBootstrapper.CheckEnvironment(); }
32+
2533
public PdfExporter() : this(new PdfNativeLibraryService())
2634
{
2735
}
@@ -111,6 +119,7 @@ private Task<byte[]> ExportPdf(
111119
{
112120
try
113121
{
122+
EnsureBootstrap();
114123
var htmlToPdfDocument = PdfWkHtmlCompatibilityMapper.ToHtmlToPdfDocument(pdfExportOptions, htmlString);
115124
var result = PdfConverter.Value.Convert(htmlToPdfDocument);
116125
return Task.FromResult(result);

0 commit comments

Comments
 (0)