Skip to content

Commit 52fc1c3

Browse files
Merge pull request #59 from SixLabors/js/net10-net11-targets
Add net10/net11 preview CI and simplify guards
2 parents 6949b10 + 75572af commit 52fc1c3

10 files changed

Lines changed: 110 additions & 109 deletions

File tree

‎.github/workflows/build-and-test.yml‎

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,31 @@ jobs:
1313
matrix:
1414
options:
1515
- os: ubuntu-latest
16-
framework: net8.0
16+
framework: net11.0
17+
sdk-preview: true
1718
runtime: -x64
1819
codecov: false
1920
- os: macos-latest
20-
framework: net8.0
21+
framework: net11.0
22+
sdk-preview: true
2123
runtime: -x64
2224
codecov: false
2325
- os: windows-latest
24-
framework: net8.0
26+
framework: net11.0
27+
sdk-preview: true
28+
runtime: -x64
29+
codecov: false
30+
31+
- os: ubuntu-latest
32+
framework: net10.0
33+
runtime: -x64
34+
codecov: false
35+
- os: macos-latest
36+
framework: net10.0
37+
runtime: -x64
38+
codecov: false
39+
- os: windows-latest
40+
framework: net10.0
2541
runtime: -x64
2642
codecov: true
2743

@@ -52,19 +68,45 @@ jobs:
5268
restore-keys: ${{ runner.os }}-nuget-
5369

5470
- name: DotNet Setup
71+
if: ${{ matrix.options.sdk-preview != true }}
5572
uses: actions/setup-dotnet@v4
5673
with:
5774
dotnet-version: |
58-
8.0.x
75+
10.0.x
76+
77+
- name: DotNet Setup Preview
78+
if: ${{ matrix.options.sdk-preview == true }}
79+
uses: actions/setup-dotnet@v4
80+
with:
81+
dotnet-quality: preview
82+
dotnet-version: |
83+
11.0.x
5984
6085
- name: DotNet Build
86+
if: ${{ matrix.options.sdk-preview != true }}
87+
shell: pwsh
88+
run: ./ci-build.ps1 "${{matrix.options.framework}}"
89+
90+
- name: DotNet Build Preview
91+
if: ${{ matrix.options.sdk-preview == true }}
6192
shell: pwsh
6293
run: ./ci-build.ps1 "${{matrix.options.framework}}"
94+
env:
95+
SIXLABORS_TESTING_PREVIEW: True
6396

6497
- name: DotNet Test
98+
if: ${{ matrix.options.sdk-preview != true }}
99+
shell: pwsh
100+
run: ./ci-test.ps1 "${{matrix.options.os}}" "${{matrix.options.framework}}" "${{matrix.options.runtime}}" "${{matrix.options.codecov}}"
101+
env:
102+
XUNIT_PATH: .\tests\SharedInfrastructure.Tests # Required for xunit
103+
104+
- name: DotNet Test Preview
105+
if: ${{ matrix.options.sdk-preview == true }}
65106
shell: pwsh
66107
run: ./ci-test.ps1 "${{matrix.options.os}}" "${{matrix.options.framework}}" "${{matrix.options.runtime}}" "${{matrix.options.codecov}}"
67108
env:
109+
SIXLABORS_TESTING_PREVIEW: True
68110
XUNIT_PATH: .\tests\SharedInfrastructure.Tests # Required for xunit
69111

70112
- name: Update Codecov

‎global.json‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Pins the .NET SDK to major version 10 or later for all SixLabors repositories.
2+
// The build copies this file to consuming repositories together with .editorconfig and
3+
// the other shared config files (see msbuild/targets/SixLabors.Src.targets).
4+
{
5+
"sdk": {
6+
// The floor, not an exact build: resolution never selects an SDK below major 10.
7+
"version": "10.0.0",
8+
9+
// Select the newest installed SDK at or above the floor. This spans feature bands,
10+
// minor versions, and major versions, so a machine with only stable 10.0.x SDKs
11+
// resolves the newest of those, and a machine with a newer SDK resolves that instead.
12+
"rollForward": "latestMajor",
13+
14+
// Let the CLI and Visual Studio select preview SDKs when one is installed.
15+
// Machines and CI lanes without a preview SDK are unaffected.
16+
"allowPrerelease": true
17+
}
18+
}

‎msbuild/props/SixLabors.Global.props‎

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

6363
<!-- Compilation settings that explicitly differ from the Sdk.props/targets defaults -->
6464
<PropertyGroup>
65-
<LangVersion>12.0</LangVersion>
65+
<LangVersion>14.0</LangVersion>
6666
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
6767
<Features>strict;IOperation</Features>
6868
<HighEntropyVA>true</HighEntropyVA>

‎msbuild/targets/SixLabors.Src.targets‎

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,26 @@
77

88
<ItemGroup>
99
<!-- Shared config files that have to exist at root level. -->
10-
<SixLaborsConfigFilesToCopy Include="$(MSBuildThisFileDirectory)..\..\.editorconfig;$(MSBuildThisFileDirectory)..\..\.gitattributes;$(MSBuildThisFileDirectory)..\..\AGENTS.md;$(MSBuildThisFileDirectory)..\..\CLAUDE.md;$(MSBuildThisFileDirectory)..\..\GEMINI.md;$(MSBuildThisFileDirectory)..\..\codecov.yml;" />
10+
<SixLaborsConfigFilesToCopy Include="$(MSBuildThisFileDirectory)..\..\.editorconfig" />
11+
<SixLaborsConfigFilesToCopy Include="$(MSBuildThisFileDirectory)..\..\.gitattributes" />
12+
<SixLaborsConfigFilesToCopy Include="$(MSBuildThisFileDirectory)..\..\AGENTS.md" />
13+
<SixLaborsConfigFilesToCopy Include="$(MSBuildThisFileDirectory)..\..\CLAUDE.md" />
14+
<SixLaborsConfigFilesToCopy Include="$(MSBuildThisFileDirectory)..\..\GEMINI.md" />
15+
<SixLaborsConfigFilesToCopy Include="$(MSBuildThisFileDirectory)..\..\codecov.yml" />
16+
<SixLaborsConfigFilesToCopy Include="$(MSBuildThisFileDirectory)..\..\global.json" />
1117
</ItemGroup>
1218

1319
<!-- Copy the config files on src build. -->
14-
<Target Name="SixLaborsCopyConfigFiles" BeforeTargets="Build" Condition="'$(SixLaborsDisableConfigCopy)' == ''">
20+
<Target Name="SixLaborsCopyConfigFiles" BeforeTargets="Build" Condition="'$(SIXLABORS_DISABLE_CONFIG_COPY)' == ''">
1521
<Copy SourceFiles="@(SixLaborsConfigFilesToCopy)"
1622
SkipUnchangedFiles = "true"
1723
DestinationFolder="$(SixLaborsSolutionDirectory)" />
24+
25+
<!--
26+
Copied separately because the file lives in the .github subdirectory. DestinationFolder
27+
above flattens everything into the repo root, so this copy uses DestinationFiles with
28+
the full target path to keep the subpath intact.
29+
-->
1830
<Copy SourceFiles="$(MSBuildThisFileDirectory)..\..\.github\copilot-instructions.md"
1931
SkipUnchangedFiles="true"
2032
DestinationFiles="$(SixLaborsSolutionDirectory).github\copilot-instructions.md" />
@@ -67,8 +79,7 @@
6779
and '$(TargetFramework)'!=''
6880
and $([System.String]::Copy('$(PackageId)').StartsWith('SixLabors.'))
6981
and '$(PackageId)'!='SixLabors.Licensing'
70-
and ( '$(PkgSixLabors_Licensing)'==''
71-
or !Exists('$(PkgSixLabors_Licensing)\build\net8.0\SixLabors.Licensing.dll') )">
82+
and ( '$(PkgSixLabors_Licensing)'=='' or !Exists('$(PkgSixLabors_Licensing)\build\net8.0\SixLabors.Licensing.dll') )">
7283
<Error Text="Licensing task not found under $(PkgSixLabors_Licensing)\build\net8.0. Ensure the dev-only PackageReference (GeneratePathProperty='true') is present and restore ran." />
7384
</Target>
7485

‎src/SharedInfrastructure/DebugGuard.cs‎

Lines changed: 3 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ internal static partial class DebugGuard
2323
/// <typeparam name="TValue">The type of the value.</typeparam>
2424
/// <exception cref="ArgumentNullException"><paramref name="value"/> is null.</exception>
2525
[Conditional("DEBUG")]
26-
public static void NotNull<TValue>([NotNull] TValue? value, [CallerArgumentExpression("value")] string? parameterName = null)
26+
public static void NotNull<TValue>([NotNull] TValue? value, [CallerArgumentExpression(nameof(value))] string? parameterName = null)
2727
where TValue : class =>
2828
ArgumentNullException.ThrowIfNull(value, parameterName);
2929

@@ -35,7 +35,7 @@ public static void NotNull<TValue>([NotNull] TValue? value, [CallerArgumentExpre
3535
/// <exception cref="ArgumentNullException"><paramref name="value"/> is null.</exception>
3636
/// <exception cref="ArgumentException"><paramref name="value"/> is empty or contains only blanks.</exception>
3737
[Conditional("DEBUG")]
38-
public static void NotNullOrWhiteSpace([NotNull] string? value, [CallerArgumentExpression("value")] string? paramName = null)
38+
public static void NotNullOrWhiteSpace([NotNull] string? value, [CallerArgumentExpression(nameof(value))] string? paramName = null)
3939
{
4040
ArgumentNullException.ThrowIfNull(value);
4141

@@ -204,25 +204,6 @@ public static void IsFalse(bool target, string parameterName, string message)
204204
/// </exception>
205205
[Conditional("DEBUG")]
206206
public static void MustBeSizedAtLeast<T>(ReadOnlySpan<T> source, int minLength, string parameterName)
207-
{
208-
if (source.Length < minLength)
209-
{
210-
ThrowArgumentException($"Span-s must be at least of length {minLength}!", parameterName);
211-
}
212-
}
213-
214-
/// <summary>
215-
/// Verifies, that the `source` span has the length of 'minLength', or longer.
216-
/// </summary>
217-
/// <typeparam name="T">The element type of the spans.</typeparam>
218-
/// <param name="source">The target span.</param>
219-
/// <param name="minLength">The minimum length.</param>
220-
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
221-
/// <exception cref="ArgumentException">
222-
/// <paramref name="source"/> has less than <paramref name="minLength"/> items.
223-
/// </exception>
224-
[Conditional("DEBUG")]
225-
public static void MustBeSizedAtLeast<T>(Span<T> source, int minLength, string parameterName)
226207
{
227208
if (source.Length < minLength)
228209
{
@@ -241,27 +222,7 @@ public static void MustBeSizedAtLeast<T>(Span<T> source, int minLength, string p
241222
[Conditional("DEBUG")]
242223
public static void DestinationShouldNotBeTooShort<TSource, TDest>(
243224
ReadOnlySpan<TSource> source,
244-
Span<TDest> destination,
245-
string destinationParamName)
246-
{
247-
if (destination.Length < source.Length)
248-
{
249-
ThrowArgumentException($"Destination span is too short!", destinationParamName);
250-
}
251-
}
252-
253-
/// <summary>
254-
/// Verifies that the 'destination' span is not shorter than 'source'.
255-
/// </summary>
256-
/// <typeparam name="TSource">The source element type.</typeparam>
257-
/// <typeparam name="TDest">The destination element type.</typeparam>
258-
/// <param name="source">The source span.</param>
259-
/// <param name="destination">The destination span.</param>
260-
/// <param name="destinationParamName">The name of the argument for 'destination'.</param>
261-
[Conditional("DEBUG")]
262-
public static void DestinationShouldNotBeTooShort<TSource, TDest>(
263-
Span<TSource> source,
264-
Span<TDest> destination,
225+
ReadOnlySpan<TDest> destination,
265226
string destinationParamName)
266227
{
267228
if (destination.Length < source.Length)

‎src/SharedInfrastructure/Guard.cs‎

Lines changed: 3 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ internal static partial class Guard
2121
/// <typeparam name="TValue">The type of the value.</typeparam>
2222
/// <exception cref="ArgumentNullException"><paramref name="value"/> is null.</exception>
2323
[MethodImpl(MethodImplOptions.AggressiveInlining)]
24-
public static void NotNull<TValue>([NotNull]TValue? value, [CallerArgumentExpression("value")] string? parameterName = null)
24+
public static void NotNull<TValue>([NotNull] TValue? value, [CallerArgumentExpression(nameof(value))] string? parameterName = null)
2525
where TValue : class =>
2626
ArgumentNullException.ThrowIfNull(value, parameterName);
2727

@@ -33,7 +33,7 @@ public static void NotNull<TValue>([NotNull]TValue? value, [CallerArgumentExpres
3333
/// <exception cref="ArgumentNullException"><paramref name="value"/> is null.</exception>
3434
/// <exception cref="ArgumentException"><paramref name="value"/> is empty or contains only blanks.</exception>
3535
[MethodImpl(MethodImplOptions.AggressiveInlining)]
36-
public static void NotNullOrWhiteSpace([NotNull]string? value, string parameterName)
36+
public static void NotNullOrWhiteSpace([NotNull] string? value, string parameterName)
3737
{
3838
if (!string.IsNullOrWhiteSpace(value))
3939
{
@@ -221,27 +221,6 @@ public static void MustBeSizedAtLeast<T>(ReadOnlySpan<T> source, int minLength,
221221
ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeSizedAtLeast(minLength, parameterName);
222222
}
223223

224-
/// <summary>
225-
/// Verifies, that the `source` span has the length of 'minLength', or longer.
226-
/// </summary>
227-
/// <typeparam name="T">The element type of the spans.</typeparam>
228-
/// <param name="source">The target span.</param>
229-
/// <param name="minLength">The minimum length.</param>
230-
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
231-
/// <exception cref="ArgumentException">
232-
/// <paramref name="source"/> has less than <paramref name="minLength"/> items.
233-
/// </exception>
234-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
235-
public static void MustBeSizedAtLeast<T>(Span<T> source, int minLength, string parameterName)
236-
{
237-
if (source.Length >= minLength)
238-
{
239-
return;
240-
}
241-
242-
ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeSizedAtLeast(minLength, parameterName);
243-
}
244-
245224
/// <summary>
246225
/// Verifies that the 'destination' span is not shorter than 'source'.
247226
/// </summary>
@@ -253,29 +232,7 @@ public static void MustBeSizedAtLeast<T>(Span<T> source, int minLength, string p
253232
[MethodImpl(MethodImplOptions.AggressiveInlining)]
254233
public static void DestinationShouldNotBeTooShort<TSource, TDest>(
255234
ReadOnlySpan<TSource> source,
256-
Span<TDest> destination,
257-
string destinationParamName)
258-
{
259-
if (destination.Length >= source.Length)
260-
{
261-
return;
262-
}
263-
264-
ThrowHelper.ThrowArgumentException("Destination span is too short!", destinationParamName);
265-
}
266-
267-
/// <summary>
268-
/// Verifies that the 'destination' span is not shorter than 'source'.
269-
/// </summary>
270-
/// <typeparam name="TSource">The source element type.</typeparam>
271-
/// <typeparam name="TDest">The destination element type.</typeparam>
272-
/// <param name="source">The source span.</param>
273-
/// <param name="destination">The destination span.</param>
274-
/// <param name="destinationParamName">The name of the argument for 'destination'.</param>
275-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
276-
public static void DestinationShouldNotBeTooShort<TSource, TDest>(
277-
Span<TSource> source,
278-
Span<TDest> destination,
235+
ReadOnlySpan<TDest> destination,
279236
string destinationParamName)
280237
{
281238
if (destination.Length >= source.Length)

‎tests/Directory.Build.props‎

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

44
<PropertyGroup>
55
<!--Disable config copy. This solution only.-->
6-
<SixLaborsDisableConfigCopy>true</SixLaborsDisableConfigCopy>
6+
<SIXLABORS_DISABLE_CONFIG_COPY>true</SIXLABORS_DISABLE_CONFIG_COPY>
77
</PropertyGroup>
88

99
<!-- Import the shared tests .props file -->

‎tests/SharedInfrastructure.Tests/DebugGuardTests.cs‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace SharedInfrastructure.Tests;
1111

1212
public class DebugGuardTests
1313
{
14-
private class Foo
14+
private sealed class Foo
1515
{
1616
}
1717

@@ -31,7 +31,7 @@ public void AllStaticMethodsOnOnDebugGuardHaveDEBUGConditional()
3131
[Fact]
3232
public void NotNull_WhenNull_Throws()
3333
{
34-
Foo foo = null;
34+
Foo? foo = null;
3535
Assert.Throws<ArgumentNullException>(() => Guard.NotNull(foo, nameof(foo)));
3636
}
3737

@@ -48,7 +48,7 @@ public void NotNull_WhenNotNull()
4848
[InlineData(" ", true)]
4949
[InlineData("$", false)]
5050
[InlineData("lol", false)]
51-
public void NotNullOrWhiteSpace(string str, bool shouldThrow)
51+
public void NotNullOrWhiteSpace(string? str, bool shouldThrow)
5252
{
5353
if (shouldThrow)
5454
{
@@ -205,13 +205,13 @@ public void MustBeGreaterThanOrEqualTo_IsLess_ThrowsNoException()
205205
[InlineData(new int[] { 1, 2 }, 1)]
206206
[InlineData(new int[] { 1, 2 }, 2)]
207207
public void MustBeSizedAtLeast_Array_LengthIsGreaterOrEqual_ThrowsNoException(int[] value, int minLength)
208-
=> DebugGuard.MustBeSizedAtLeast<int>(value, minLength, "myParamName");
208+
=> DebugGuard.MustBeSizedAtLeast(value, minLength, "myParamName");
209209

210210
[Fact]
211211
public void MustBeSizedAtLeast_Array_LengthIsLess_ThrowsException()
212212
{
213213
ArgumentException exception = Assert.Throws<ArgumentException>(
214-
() => DebugGuard.MustBeSizedAtLeast<int>(new int[] { 1, 2 }, 3, "myParamName"));
214+
static () => DebugGuard.MustBeSizedAtLeast([1, 2], 3, "myParamName"));
215215

216216
Assert.Equal("myParamName", exception.ParamName);
217217
Assert.Contains("The size must be at least 3.", exception.Message);

‎tests/SharedInfrastructure.Tests/GuardTests.cs‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ namespace SharedInfrastructure.Tests;
55

66
public class GuardTests
77
{
8-
private class Foo
8+
private sealed class Foo
99
{
1010
}
1111

1212
[Fact]
1313
public void NotNull_WhenNull_Throws()
1414
{
15-
Foo foo = null;
15+
Foo? foo = null;
1616
Assert.Throws<ArgumentNullException>(() => Guard.NotNull(foo, nameof(foo)));
1717
}
1818

@@ -29,7 +29,7 @@ public void NotNull_WhenNotNull()
2929
[InlineData(" ", true)]
3030
[InlineData("$", false)]
3131
[InlineData("lol", false)]
32-
public void NotNullOrWhiteSpace(string str, bool shouldThrow)
32+
public void NotNullOrWhiteSpace(string? str, bool shouldThrow)
3333
{
3434
if (shouldThrow)
3535
{
@@ -205,13 +205,13 @@ public void MustBeBetweenOrEqualTo_IsLessOrGreater_ThrowsNoException(int value,
205205
[InlineData(2, 1)]
206206
[InlineData(2, 2)]
207207
public void MustBeSizedAtLeast_Array_LengthIsGreaterOrEqual_ThrowsNoException(int valueLength, int minLength)
208-
=> Guard.MustBeSizedAtLeast<int>(new int[valueLength], minLength, "myParamName");
208+
=> Guard.MustBeSizedAtLeast(new int[valueLength], minLength, "myParamName");
209209

210210
[Fact]
211211
public void MustBeSizedAtLeast_Array_LengthIsLess_ThrowsException()
212212
{
213213
ArgumentException exception =
214-
Assert.Throws<ArgumentException>(() => Guard.MustBeSizedAtLeast<int>(new int[] { 1, 2 }, 3, "myParamName"));
214+
Assert.Throws<ArgumentException>(() => Guard.MustBeSizedAtLeast([1, 2], 3, "myParamName"));
215215

216216
Assert.Equal("myParamName", exception.ParamName);
217217
Assert.Contains("Spans must be at least of length 3", exception.Message);

0 commit comments

Comments
 (0)