Skip to content

Commit 183e6aa

Browse files
committed
Expand target frameworks to support .NET Standard 2.1 and .NET 6-9, add conditional dependencies by framework, introduce compatibility features for older targets, improve FreeBSD detection, refactor UIntPtr usage, and implement multi-platform CI test matrix.
1 parent 18202f1 commit 183e6aa

6 files changed

Lines changed: 177 additions & 8 deletions

File tree

.github/workflows/test-matrix.yml

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
name: Multi-Platform Test Matrix
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- develop
8+
pull_request:
9+
branches:
10+
- main
11+
- develop
12+
workflow_dispatch:
13+
inputs:
14+
dotnet_version:
15+
description: '.NET SDK version to use'
16+
required: false
17+
default: '9.0.x'
18+
type: string
19+
20+
jobs:
21+
test-matrix:
22+
name: Test on ${{ matrix.os }} (${{ matrix.arch }})
23+
runs-on: ${{ matrix.runner }}
24+
25+
strategy:
26+
fail-fast: false
27+
matrix:
28+
include:
29+
# Windows x64
30+
- os: windows
31+
arch: x64
32+
runner: windows-latest
33+
rid: win-x64
34+
35+
# Linux x64
36+
- os: linux
37+
arch: x64
38+
runner: ubuntu-latest
39+
rid: linux-x64
40+
41+
# Linux ARM64
42+
- os: linux
43+
arch: arm64
44+
runner: ubuntu-latest-arm64
45+
rid: linux-arm64
46+
47+
# macOS x64 (Intel)
48+
- os: macos
49+
arch: x64
50+
runner: macos-13
51+
rid: osx-x64
52+
53+
# macOS ARM64 (Apple Silicon)
54+
- os: macos
55+
arch: arm64
56+
runner: macos-latest
57+
rid: osx-arm64
58+
59+
steps:
60+
- name: Checkout code
61+
uses: actions/checkout@v4
62+
63+
- name: Setup .NET
64+
uses: actions/setup-dotnet@v4
65+
with:
66+
dotnet-version: ${{ inputs.dotnet_version || '9.0.x' }}
67+
68+
- name: Set up Docker Compose
69+
uses: docker/setup-compose-action@v1
70+
71+
- name: Start SSH test server (Docker)
72+
working-directory: ./src/NullOpsDevs.LibSsh.Test
73+
run: docker compose up --build -d
74+
75+
- name: Wait for SSH server to be ready
76+
run: |
77+
echo "Waiting for SSH server to start..."
78+
sleep 5
79+
80+
- name: Setup SSH Agent (Linux/macOS)
81+
if: matrix.os != 'windows'
82+
run: |
83+
eval $(ssh-agent -s)
84+
echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK" >> $GITHUB_ENV
85+
echo "SSH_AGENT_PID=$SSH_AGENT_PID" >> $GITHUB_ENV
86+
cp src/NullOpsDevs.LibSsh.Test/docker/test-keys/id_rsa /tmp/id_rsa
87+
chmod 600 /tmp/id_rsa
88+
ssh-add /tmp/id_rsa
89+
90+
- name: Setup SSH Agent (Windows)
91+
if: matrix.os == 'windows'
92+
shell: powershell
93+
run: |
94+
Start-Service ssh-agent
95+
Set-Service -Name ssh-agent -StartupType 'Automatic'
96+
Copy-Item "src\NullOpsDevs.LibSsh.Test\docker\test-keys\id_rsa" "$env:TEMP\id_rsa"
97+
ssh-add "$env:TEMP\id_rsa"
98+
99+
- name: Restore dependencies
100+
run: dotnet restore
101+
102+
- name: Build library (Release)
103+
run: dotnet build -c Release --no-restore
104+
105+
- name: Build test project (Release)
106+
run: dotnet build -c Release --self-contained -r ${{ matrix.rid }} ./src/NullOpsDevs.LibSsh.Test/NullOpsDevs.LibSsh.Test.csproj
107+
108+
- name: Run tests (Linux/macOS)
109+
if: matrix.os != 'windows'
110+
working-directory: ./src/NullOpsDevs.LibSsh.Test/bin/Release/net9.0/${{ matrix.rid }}/
111+
run: ./NullOpsDevs.LibSsh.Test
112+
113+
- name: Run tests (Windows)
114+
if: matrix.os == 'windows'
115+
working-directory: ./src/NullOpsDevs.LibSsh.Test/bin/Release/net9.0/${{ matrix.rid }}/
116+
shell: powershell
117+
run: .\NullOpsDevs.LibSsh.Test.exe
118+
119+
- name: Cleanup Docker
120+
if: always()
121+
working-directory: ./src/NullOpsDevs.LibSsh.Test
122+
run: docker compose down -v
123+
124+
# Summary job that depends on all matrix jobs
125+
test-summary:
126+
name: Test Summary
127+
needs: test-matrix
128+
runs-on: ubuntu-latest
129+
if: always()
130+
131+
steps:
132+
- name: Check test results
133+
run: |
134+
if [ "${{ needs.test-matrix.result }}" == "success" ]; then
135+
echo "✅ All platform tests passed!"
136+
exit 0
137+
else
138+
echo "❌ Some platform tests failed"
139+
exit 1
140+
fi

src/NullOpsDevs.LibSsh.Test/NullOpsDevs.LibSsh.Test.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>net9.0</TargetFramework>
5+
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<Nullable>enable</Nullable>
88
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#if NETSTANDARD2_0_OR_GREATER
2+
using JetBrains.Annotations;
3+
4+
// ReSharper disable once CheckNamespace
5+
namespace System.Runtime.CompilerServices;
6+
[PublicAPI]
7+
internal static class IsExternalInit;
8+
#endif

src/NullOpsDevs.LibSsh/NullOpsDevs.LibSsh.csproj

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<!-- Project settings -->
44
<PropertyGroup>
5-
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
5+
<TargetFrameworks>netstandard2.1;net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<Nullable>enable</Nullable>
88
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@@ -111,6 +111,21 @@
111111
<PackageReference Include="JetBrains.Annotations" Version="2025.2.2" PrivateAssets="All" />
112112
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/>
113113
</ItemGroup>
114+
115+
<!-- NETStandard 2.1 dependencies -->
116+
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.1'">
117+
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0" />
118+
</ItemGroup>
119+
120+
<!-- NET6 dependencies -->
121+
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
122+
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
123+
</ItemGroup>
124+
125+
<!-- NET7 dependencies -->
126+
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
127+
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
128+
</ItemGroup>
114129

115130
<!-- NET8 dependencies -->
116131
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">

src/NullOpsDevs.LibSsh/Platform/PlatformDependentStat.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,15 @@ public static unsafe PlatformInDependentStat From(void* structure)
3333

3434
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
3535
return CreateFromMacOsStruct(structure);
36-
37-
if (RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD))
36+
37+
#if NETSTANDARD2_1
38+
// Behavior verified on FreeBSD 14.3-RELEASE
39+
if (RuntimeInformation.OSDescription.Contains("freebsd", StringComparison.OrdinalIgnoreCase)) {
40+
#else
41+
if (RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD)) {
42+
#endif
3843
return CreateFromFreeBsdStruct(structure);
44+
}
3945
}
4046
catch (Exception ex)
4147
{

src/NullOpsDevs.LibSsh/SshSession.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,15 +172,15 @@ public unsafe SshHostKey GetHostKey()
172172
EnsureInitialized();
173173
EnsureInStatuses(SshConnectionStatus.Connected, SshConnectionStatus.LoggedIn);
174174

175-
UIntPtr length = 0;
175+
var length = UIntPtr.Zero;
176176
var type = 0;
177177

178178
var ptr = libssh2_session_hostkey(SessionPtr, &length, &type);
179179

180-
if (ptr == null || length == 0)
180+
if (ptr == null || length == UIntPtr.Zero)
181181
throw SshException.FromLastSessionError(SessionPtr);
182182

183-
var buffer = new byte[length];
183+
var buffer = new byte[length.ToUInt64()];
184184
Marshal.Copy(new IntPtr(ptr), buffer, 0, (int) length);
185185

186186
return new SshHostKey
@@ -205,7 +205,7 @@ public unsafe SshHostKey GetHostKey()
205205
EnsureInitialized();
206206
EnsureInStatuses(SshConnectionStatus.Connected, SshConnectionStatus.LoggedIn);
207207

208-
if(!Enum.IsDefined(method))
208+
if(!Enum.IsDefined(typeof(SshMethod), method))
209209
throw new ArgumentOutOfRangeException(nameof(method), method, null);
210210

211211
var result = libssh2_session_methods(SessionPtr, (int) method);

0 commit comments

Comments
 (0)