Skip to content

Commit 7bd2fc3

Browse files
authored
Merge pull request #2068 from shimat/add-package-smoke-test
Add a package smoke test gate before publishing to nuget.org
2 parents 88c0ec5 + 0d0c1e9 commit 7bd2fc3

3 files changed

Lines changed: 140 additions & 1 deletion

File tree

.github/workflows/publish_nuget.yml

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,66 @@ jobs:
222222
*.snupkg
223223
retention-days: 7
224224

225-
Publish:
225+
# ---------------------------------------------------------------------------
226+
# Consume the actual, about-to-be-published .nupkg files as a real PackageReference
227+
# (against a local feed, not a ProjectReference against source) before anything gets
228+
# pushed to nuget.org. Catches packaging mistakes - wrong RID asset placement, a missing
229+
# native library, a broken dependency graph - that the source-level "test" jobs in
230+
# windows.yml/manylinux.yml/macos.yml never exercise, since those only ever run against
231+
# loose build output with the native binary copied in by hand.
232+
# ---------------------------------------------------------------------------
233+
PackageSmokeTest:
234+
name: Package smoke test (${{ matrix.os }})
226235
needs: Prepare
236+
strategy:
237+
fail-fast: false
238+
matrix:
239+
include:
240+
- os: windows-latest
241+
runtime_package: OpenCvSharp5.Windows
242+
- os: ubuntu-latest
243+
runtime_package: OpenCvSharp5.official.runtime.linux-x64
244+
runs-on: ${{ matrix.os }}
245+
246+
steps:
247+
- uses: actions/checkout@v7
248+
249+
- name: Download release packages
250+
uses: actions/download-artifact@v8
251+
with:
252+
name: release-packages
253+
path: release-packages
254+
255+
- name: Install .NET
256+
uses: actions/setup-dotnet@v5
257+
with:
258+
dotnet-version: '10.0.x'
259+
260+
- name: Determine package version
261+
id: version
262+
shell: bash
263+
run: |
264+
file=$(ls release-packages/OpenCvSharp5.[0-9]*.nupkg | head -1)
265+
name=$(basename "$file")
266+
version=${name#OpenCvSharp5.}
267+
version=${version%.nupkg}
268+
echo "Package version under test: $version"
269+
echo "version=$version" >> "$GITHUB_OUTPUT"
270+
271+
- name: Run package smoke test
272+
shell: bash
273+
env:
274+
SMOKE_TEST_VERSION: ${{ steps.version.outputs.version }}
275+
SMOKE_TEST_RUNTIME_PACKAGE: ${{ matrix.runtime_package }}
276+
run: |
277+
cd test/OpenCvSharp.PackageSmokeTest
278+
dotnet run -c Release \
279+
-p:RestoreAdditionalProjectSources="$GITHUB_WORKSPACE/release-packages" \
280+
-p:SmokeTestPackageVersion="$SMOKE_TEST_VERSION" \
281+
-p:SmokeTestRuntimePackage="$SMOKE_TEST_RUNTIME_PACKAGE"
282+
283+
Publish:
284+
needs: [Prepare, PackageSmokeTest]
227285
runs-on: ubuntu-24.04
228286
environment: nuget-production
229287

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net10.0</TargetFramework>
6+
<Nullable>enable</Nullable>
7+
<ImplicitUsings>enable</ImplicitUsings>
8+
<IsPackable>false</IsPackable>
9+
</PropertyGroup>
10+
11+
<!--
12+
This project intentionally has no ProjectReference to src/OpenCvSharp: it exists to catch
13+
packaging mistakes (wrong RID asset placement, missing files, a broken dependency graph) in the
14+
actual .nupkg files about to be pushed to nuget.org, which a ProjectReference-based test can
15+
never exercise. .github/workflows/publish_nuget.yml adds the freshly built, not-yet-published
16+
packages as a local NuGet feed and passes -p:SmokeTestPackageVersion=<version> plus
17+
-p:SmokeTestRuntimePackage=<runtime package id> before restoring, so this project always targets
18+
whichever version and platform runtime package is actually about to be published, never a
19+
hardcoded one.
20+
-->
21+
<PropertyGroup>
22+
<SmokeTestPackageVersion Condition="'$(SmokeTestPackageVersion)' == ''">0.0.0-dev</SmokeTestPackageVersion>
23+
<SmokeTestRuntimePackage Condition="'$(SmokeTestRuntimePackage)' == ''">OpenCvSharp5.official.runtime.linux-x64</SmokeTestRuntimePackage>
24+
</PropertyGroup>
25+
26+
<ItemGroup>
27+
<PackageReference Include="OpenCvSharp5" Version="$(SmokeTestPackageVersion)" />
28+
<PackageReference Include="$(SmokeTestRuntimePackage)" Version="$(SmokeTestPackageVersion)" />
29+
</ItemGroup>
30+
31+
</Project>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Pre-publish smoke test: exercises the actual .nupkg files about to be pushed to nuget.org,
2+
// referenced the same way a real consumer would (PackageReference against a NuGet feed, not
3+
// ProjectReference against source), to catch packaging mistakes (wrong RID asset placement,
4+
// missing native library, broken dependency graph) that a source-level test can never see.
5+
// Asserts and sets the process exit code instead of using a test framework, since the point is
6+
// just "does a freshly `dotnet add package`-d app work at all", not exhaustive API coverage.
7+
using System.Globalization;
8+
using OpenCvSharp;
9+
10+
try
11+
{
12+
var version = Cv2.GetVersionString();
13+
14+
using var mat = new Mat(256, 256, MatType.CV_8UC1, Scalar.All(0));
15+
Cv2.Rectangle(mat, new Rect(40, 40, 120, 120), Scalar.All(255), thickness: -1);
16+
Cv2.Circle(mat, new Point(180, 180), 30, Scalar.All(200), thickness: -1);
17+
18+
using var orb = ORB.Create(500);
19+
using var descriptors = new Mat();
20+
orb.DetectAndCompute(mat, default, out var keypoints, descriptors);
21+
22+
foreach (var ext in new[] { ".jpg", ".png", ".tiff" })
23+
{
24+
var encoded = Cv2.ImEncode(ext, mat, out var buf);
25+
if (!encoded || buf.Length == 0)
26+
throw new InvalidOperationException($"ImEncode({ext}) failed or produced an empty buffer");
27+
28+
using var decoded = Cv2.ImDecode(buf, ImreadModes.Unchanged);
29+
if (decoded.Empty() || decoded.Size() != mat.Size())
30+
throw new InvalidOperationException(
31+
$"ImDecode({ext}) round trip failed: empty={decoded.Empty()}, size={decoded.Size()}");
32+
}
33+
34+
using var blob = Cv2.Dnn.BlobFromImage(mat, size: new Size(64, 64));
35+
if (blob.Empty())
36+
throw new InvalidOperationException("Cv2.Dnn.BlobFromImage produced an empty blob");
37+
38+
var blobShape = string.Join('x', Enumerable.Range(0, blob.Dims).Select(blob.Size));
39+
40+
Console.WriteLine(string.Format(
41+
CultureInfo.InvariantCulture,
42+
"ok: OpenCV {0}, ORB keypoints: {1}, dnn blob shape: {2}",
43+
version, keypoints.Length, blobShape));
44+
return 0;
45+
}
46+
catch (Exception ex)
47+
{
48+
Console.Error.WriteLine("error: " + ex);
49+
return 1;
50+
}

0 commit comments

Comments
 (0)