diff --git a/.github/RELEASE_TEMPLATE.md b/.github/RELEASE_TEMPLATE.md
new file mode 100644
index 00000000..008f37c2
--- /dev/null
+++ b/.github/RELEASE_TEMPLATE.md
@@ -0,0 +1,32 @@
+
+
+## Kalicz.StrongTypes
+
+-
+
+## Kalicz.StrongTypes.EfCore
+
+-
+
+## Kalicz.StrongTypes.FsCheck
+
+-
+
+## Breaking changes
+
+-
+
+## Upgrade notes
+
+-
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f3be3c3b..ec8939ad 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -7,6 +7,8 @@ on:
pull_request:
branches:
- main
+ release:
+ types: [published]
permissions:
contents: read
@@ -48,36 +50,54 @@ jobs:
**/TestResults/**/*.trx
retention-days: 5
- - name: Pack
- if: github.ref == 'refs/heads/main' && github.event_name == 'push'
- run: |
- dotnet pack ./src/StrongTypes/StrongTypes.csproj -c $config -o out
- dotnet pack ./src/StrongTypes.EfCore/StrongTypes.EfCore.csproj -c $config -o out
-
- - name: Upload NuGet package
- if: github.ref == 'refs/heads/main' && github.event_name == 'push'
- uses: actions/upload-artifact@v7
- with:
- name: nuget-package
- path: out/*.nupkg
- retention-days: 1
-
publish:
needs: build
- if: github.ref == 'refs/heads/main' && github.event_name == 'push'
+ # Gate on main: a Release drafted through the UI carries the selected
+ # branch in target_commitish. Only releases targeted at main publish.
+ if: github.event_name == 'release' && github.event.release.target_commitish == 'main'
runs-on: ubuntu-latest
environment: Nuget.org
+ env:
+ config: 'Release'
+ DOTNET_NOLOGO: true
+ DOTNET_CLI_TELEMETRY_OPTOUT: true
+
steps:
- - name: Download NuGet package
- uses: actions/download-artifact@v8
- with:
- name: nuget-package
+ - name: Checkout
+ uses: actions/checkout@v6
- name: Setup .NET 10
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0.x
+ - name: Parse version from tag
+ id: version
+ run: |
+ TAG="${GITHUB_REF_NAME}"
+ echo "version=${TAG#v}" >> "$GITHUB_OUTPUT"
+
+ # GeneratePackageOnBuild=true in the csproj files means `dotnet build`
+ # produces the nupkg as a side-effect; no separate `dotnet pack` step
+ # needed. -p:Version cascades into referenced projects (EfCore's
+ # ProjectReference to core), so EfCore's nuspec pins its core
+ # dependency to the same version.
+ # Build the whole solution; non-publishable projects (tests, internal
+ # source generators, analyzers) set IsPackable=false so they produce no
+ # nupkg. GeneratePackageOnBuild=true on publishable csprojs means the
+ # build itself emits .nupkg files into PackageOutputPath. New publishable
+ # packages are picked up automatically by setting the same two properties.
+ - name: Build and pack
+ env:
+ NOTES: ${{ github.event.release.body }}
+ VERSION: ${{ steps.version.outputs.version }}
+ run: |
+ dotnet build StrongTypes.slnx \
+ -c $config \
+ -p:Version="$VERSION" \
+ -p:PackageReleaseNotes="$NOTES" \
+ -p:PackageOutputPath="$PWD/out"
+
- name: Publish packages
- run: dotnet nuget push ./*.nupkg --skip-duplicate --source nuget.org --api-key ${{secrets.NUGET_TOKEN}}
+ run: dotnet nuget push ./out/*.nupkg --source nuget.org --api-key ${{ secrets.NUGET_TOKEN }}
diff --git a/StrongTypes.slnx b/StrongTypes.slnx
index c2558381..53dc544e 100644
--- a/StrongTypes.slnx
+++ b/StrongTypes.slnx
@@ -6,6 +6,9 @@
+
+
+
diff --git a/src/StrongTypes.EfCore/StrongTypes.EfCore.csproj b/src/StrongTypes.EfCore/StrongTypes.EfCore.csproj
index dbd5ba08..cf8c05ea 100644
--- a/src/StrongTypes.EfCore/StrongTypes.EfCore.csproj
+++ b/src/StrongTypes.EfCore/StrongTypes.EfCore.csproj
@@ -7,9 +7,7 @@
true
CS1591
- 0.3.0
- 0.3.0
- 0.3.0
+ 0.0.0-dev
Kalicz.StrongTypes.EfCore
KaliCZ
Copyright © 2026 KaliCZ
@@ -21,7 +19,6 @@
git
https://github.com/KaliCZ/StrongTypes.git
readme.md
- 0.3.0: Initial release. Ships NonEmptyString and numeric-wrapper value converters. Single-call configuration via optionsBuilder.UseStrongTypes().
true
true
diff --git a/src/StrongTypes.Tests/Generators.cs b/src/StrongTypes.FsCheck/Generators.cs
similarity index 93%
rename from src/StrongTypes.Tests/Generators.cs
rename to src/StrongTypes.FsCheck/Generators.cs
index f28f2a47..d4a2381e 100644
--- a/src/StrongTypes.Tests/Generators.cs
+++ b/src/StrongTypes.FsCheck/Generators.cs
@@ -1,16 +1,12 @@
-#nullable enable
-
-using System.Collections.Generic;
using FsCheck;
using FsCheck.Fluent;
-namespace StrongTypes.Tests;
+namespace StrongTypes.FsCheck;
///
-/// Shared FsCheck arbitraries for the test project. Reference via
+/// Shared FsCheck arbitraries for Kalicz.StrongTypes. Reference via
/// [Properties(Arbitrary = new[] { typeof(Generators) })]
-/// on a test class. Add new arbitraries here rather than creating
-/// per-feature generator classes.
+/// on a test class.
///
public static class Generators
{
@@ -80,7 +76,7 @@ public static class Generators
///
/// with ~20% chance of .
/// FsCheck's default string generator never produces null, so
- /// the None branch has to be injected explicitly via .
+ /// the None branch has to be injected explicitly via Gen.Frequency.
/// Empty and whitespace strings are kept as valid Some values — use
/// when you want the non-empty invariant.
///
diff --git a/src/StrongTypes.FsCheck/StrongTypes.FsCheck.csproj b/src/StrongTypes.FsCheck/StrongTypes.FsCheck.csproj
new file mode 100644
index 00000000..a2a4ad84
--- /dev/null
+++ b/src/StrongTypes.FsCheck/StrongTypes.FsCheck.csproj
@@ -0,0 +1,34 @@
+
+
+ net10.0
+ 14.0
+ enable
+ enable
+ true
+ CS1591
+
+ 0.0.0-dev
+ Kalicz.StrongTypes.FsCheck
+ KaliCZ
+ Copyright © 2026 KaliCZ
+ FsCheck arbitraries for Kalicz.StrongTypes. Drop-in property-test support for NonEmptyString, Positive<T>, NonNegative<T>, Negative<T>, NonPositive<T>, Maybe<T>, and NonEmptyEnumerable<T> via a single [Properties(Arbitrary = new[] { typeof(Generators) })] attribute.
+ StrongTypes, FsCheck, PropertyTesting, Arbitrary, Generators
+ MIT
+ false
+ https://github.com/KaliCZ/StrongTypes
+ git
+ https://github.com/KaliCZ/StrongTypes.git
+ readme.md
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/StrongTypes.FsCheck/readme.md b/src/StrongTypes.FsCheck/readme.md
new file mode 100644
index 00000000..6cbed8e7
--- /dev/null
+++ b/src/StrongTypes.FsCheck/readme.md
@@ -0,0 +1,49 @@
+# Kalicz.StrongTypes.FsCheck
+
+FsCheck arbitraries for [Kalicz.StrongTypes](https://www.nuget.org/packages/Kalicz.StrongTypes).
+Lets you write property tests against code that takes or returns `NonEmptyString`,
+`Positive`, `NonNegative`, `Negative`, `NonPositive`, `Maybe`, and
+`NonEmptyEnumerable` without hand-rolling generators that re-derive each type's
+invariants.
+
+## Install
+
+```powershell
+dotnet add package Kalicz.StrongTypes.FsCheck
+```
+
+## Register
+
+Register everything with one attribute on your test class:
+
+```csharp
+using FsCheck.Xunit;
+using StrongTypes.FsCheck;
+
+[Properties(Arbitrary = new[] { typeof(Generators) })]
+public class MyTests
+{
+ [Property]
+ public void NonEmptyString_round_trips_through_json(NonEmptyString value)
+ {
+ // value is guaranteed non-null, non-empty, non-whitespace
+ }
+
+ [Property]
+ public void Positive_stays_positive(Positive value)
+ {
+ Assert.True(value.Value > 0);
+ }
+}
+```
+
+## What ships
+
+- `NonEmptyString` — filtered to non-null, non-whitespace values
+- `NullableNonEmptyString` — ~10% null injection
+- `Positive`, `Negative`, `NonNegative`, `NonPositive`
+- `Maybe`, `Maybe`, `Maybe`, `Maybe>` —
+ ~20% `None` injection
+- `NonEmptyEnumerable`
+
+Version matches the core `Kalicz.StrongTypes` package you install alongside it.
diff --git a/src/StrongTypes.Tests/GlobalUsings.cs b/src/StrongTypes.Tests/GlobalUsings.cs
new file mode 100644
index 00000000..1456e4d5
--- /dev/null
+++ b/src/StrongTypes.Tests/GlobalUsings.cs
@@ -0,0 +1 @@
+global using StrongTypes.FsCheck;
diff --git a/src/StrongTypes.Tests/StrongTypes.Tests.csproj b/src/StrongTypes.Tests/StrongTypes.Tests.csproj
index b917b0c6..2eeaedb5 100644
--- a/src/StrongTypes.Tests/StrongTypes.Tests.csproj
+++ b/src/StrongTypes.Tests/StrongTypes.Tests.csproj
@@ -15,5 +15,6 @@
+
diff --git a/src/StrongTypes/StrongTypes.csproj b/src/StrongTypes/StrongTypes.csproj
index ac699ddc..382ff526 100644
--- a/src/StrongTypes/StrongTypes.csproj
+++ b/src/StrongTypes/StrongTypes.csproj
@@ -2,9 +2,7 @@
true
CS1591
- 0.3.0
- 0.3.0
- 0.3.0
+ 0.0.0-dev
Kalicz.StrongTypes
A C# library that reduces boilerplate and prevents bugs through stronger typing. Continuation of FuncSharp.
KaliCZ
@@ -13,7 +11,6 @@
https://github.com/KaliCZ/StrongTypes
MIT
false
- 0.3.0: Generic numeric types: Positive<T>, NonNegative<T>, Negative<T>, NonPositive<T>. Added a full E2E capability for these types and NonEmptyString - API JSON serialization and EF Core converters in a separate Kalicz.StrongTypes.EfCore.
git
https://github.com/KaliCZ/StrongTypes
true