From 62161afcdf81022149da2a9990190a3696795365 Mon Sep 17 00:00:00 2001 From: Pavel Nasovich Date: Sun, 1 Mar 2026 22:08:30 +0100 Subject: [PATCH 1/4] Add modern .NET (net8.0/netstandard2.0) project support --- .github/workflows/ci.yml | 47 +++++++++++++++ README.md | 22 +++++++ assets/psake-common.ps1 | 2 +- docs/modernization-plan.md | 43 ++++++++++++++ .../FlatFile.Benchmark.csproj | 57 +++++++++++++++++++ .../FlatFile.Core.Attributes.Modern.csproj | 19 +++++++ .../FlatFile.Core.Attributes.csproj | 57 +++++++++++++++++++ .../FlatFile.Core.Modern.csproj | 15 +++++ .../Exceptions/ParseLineException.cs | 2 + src/FlatFile.Core/FlatFile.Core.csproj | 57 +++++++++++++++++++ ...latFile.Delimited.Attributes.Modern.csproj | 21 +++++++ .../FlatFile.Delimited.Attributes.csproj | 57 +++++++++++++++++++ .../FlatFile.Delimited.Modern.csproj | 19 +++++++ .../FlatFile.Delimited.csproj | 57 +++++++++++++++++++ ...tFile.FixedLength.Attributes.Modern.csproj | 21 +++++++ .../FlatFile.FixedLength.Attributes.csproj | 57 +++++++++++++++++++ .../FlatFile.FixedLength.Modern.csproj | 19 +++++++ .../FlatFile.FixedLength.csproj | 57 +++++++++++++++++++ src/FlatFile.Tests/FlatFile.Tests.csproj | 57 +++++++++++++++++++ 19 files changed, 685 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/ci.yml create mode 100644 docs/modernization-plan.md create mode 100644 src/FlatFile.Core.Attributes.Modern/FlatFile.Core.Attributes.Modern.csproj create mode 100644 src/FlatFile.Core.Modern/FlatFile.Core.Modern.csproj create mode 100644 src/FlatFile.Delimited.Attributes.Modern/FlatFile.Delimited.Attributes.Modern.csproj create mode 100644 src/FlatFile.Delimited.Modern/FlatFile.Delimited.Modern.csproj create mode 100644 src/FlatFile.FixedLength.Attributes.Modern/FlatFile.FixedLength.Attributes.Modern.csproj create mode 100644 src/FlatFile.FixedLength.Modern/FlatFile.FixedLength.Modern.csproj diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0f4a746 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,47 @@ +name: CI + +on: + push: + branches: [ master, main, dev ] + pull_request: + +jobs: + build-netfx: + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + framework: [NET35, NET40, NET45, NET451, NET452, NET46, NET461, NET462, NET47, NET471, NET472, NET48] + + steps: + - uses: actions/checkout@v4 + + - name: Setup NuGet + uses: NuGet/setup-nuget@v2 + + - name: Restore NuGet packages + run: nuget restore src/FlatFile.sln + + - name: Build (.NET Framework ${{ matrix.framework }}) + run: msbuild src/FlatFile.sln /p:Configuration=Release /p:Framework=${{ matrix.framework }} /m /v:minimal + + build-modern-dotnet: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 8.0.x + + - name: Build modern SDK-style projects + run: | + dotnet build src/FlatFile.Core.Modern/FlatFile.Core.Modern.csproj -c Release + dotnet build src/FlatFile.Core.Attributes.Modern/FlatFile.Core.Attributes.Modern.csproj -c Release + dotnet build src/FlatFile.Delimited.Modern/FlatFile.Delimited.Modern.csproj -c Release + dotnet build src/FlatFile.FixedLength.Modern/FlatFile.FixedLength.Modern.csproj -c Release + dotnet build src/FlatFile.Delimited.Attributes.Modern/FlatFile.Delimited.Attributes.Modern.csproj -c Release + dotnet build src/FlatFile.FixedLength.Attributes.Modern/FlatFile.FixedLength.Attributes.Modern.csproj -c Release diff --git a/README.md b/README.md index 5c30b8a..ec98142 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,28 @@ FlatFile FlatFile is a library to work with flat files (work up-to 100 times faster then [FileHelpers](https://www.nuget.org/packages/FileHelpers/2.0.0)) + +## Modernization status + +- ✅ Added .NET Framework **4.8** build target (`Framework=NET35/40/45/451/452/46/461/462/47/471/472/48`) across projects. +- ✅ Added GitHub Actions CI matrix for all supported .NET Framework build aliases in this repository. +- ✅ Added SDK-style modern projects targeting `netstandard2.0` and `net8.0` for .NET Core / modern .NET support. +- 📘 See [docs/modernization-plan.md](docs/modernization-plan.md) for the full upgrade roadmap (including SDK-style migration, PackageReference, and netstandard/net8 targeting). + + +### Modern .NET support + +This repository now includes SDK-style projects for modern runtimes: + +- `src/FlatFile.Core.Modern` +- `src/FlatFile.Core.Attributes.Modern` +- `src/FlatFile.Delimited.Modern` +- `src/FlatFile.FixedLength.Modern` +- `src/FlatFile.Delimited.Attributes.Modern` +- `src/FlatFile.FixedLength.Attributes.Modern` + +Each targets `netstandard2.0` and `net8.0`, enabling usage from .NET Core and latest .NET apps while preserving the legacy .NET Framework projects. + ### Installing FlatFile #### Installing all packages diff --git a/assets/psake-common.ps1 b/assets/psake-common.ps1 index 293bd40..956b8a7 100644 --- a/assets/psake-common.ps1 +++ b/assets/psake-common.ps1 @@ -21,7 +21,7 @@ Properties { $solution_path = "$src_dir\$solution" $sharedAssemblyInfo = "$src_dir\SharedAssemblyInfo.cs" $config = "Release" - $frameworks = @("NET35", "NET40", "NET45") + $frameworks = @("NET35", "NET40", "NET45", "NET451", "NET452", "NET46", "NET461", "NET462", "NET47", "NET471", "NET472", "NET48") ### Files $releaseNotes = "$base_dir\ChangeLog.md" diff --git a/docs/modernization-plan.md b/docs/modernization-plan.md new file mode 100644 index 0000000..e1d8c45 --- /dev/null +++ b/docs/modernization-plan.md @@ -0,0 +1,43 @@ +# FlatFile modernization plan + +This repository is a mature .NET Framework codebase with broad usage. The safest modernization strategy is **incremental** and **compatibility-first**. + +## Changes applied in this update + +1. Added build-target aliases for all maintained .NET Framework lines used by enterprise consumers (`NET451`, `NET452`, `NET46`, `NET461`, `NET462`, `NET47`, `NET471`, `NET472`, `NET48`) in addition to legacy aliases already present (`NET35`, `NET40`, `NET45`). +2. Extended the psake build pipeline to compile every declared framework alias. +3. Added a GitHub Actions CI matrix that restores once and builds the solution for each framework alias on `windows-latest`. +4. Added SDK-style modern library projects (`*.Modern.csproj`) targeting `netstandard2.0` and `net8.0` to provide .NET Core / modern .NET support. + +## Recommended next modernization phases + +### Phase 1: Packaging and CI hygiene (low risk) + +- Move from external `.nuspec` packing to SDK-style `dotnet pack` metadata in project files. +- Add SourceLink and deterministic builds. +- Add test execution in CI (`xUnit`) and fail-fast gates. +- Rotate package publishing credentials and use GitHub/ADO secret stores. + +### Phase 2: Project-system migration (medium risk) + +- Gradually migrate legacy csproj files to SDK-style projects after validating consumer migration from the new `*.Modern` projects. +- Keep compatibility by multitargeting: + - `net48` (existing consumers) + - `netstandard2.0` (broad modern compatibility) +- Replace `packages.config` with `PackageReference`. + +### Phase 3: Runtime/API modernization (medium-high risk) + +- Add nullable reference types in new API surfaces first, then expand internally. +- Add `Span`/`ReadOnlySpan` overloads for high-throughput parsing paths. +- Introduce async stream APIs where useful (`IAsyncEnumerable` for line reading). + +### Phase 4: Ecosystem and maintenance + +- Add Roslyn analyzers (`Microsoft.CodeAnalysis.NetAnalyzers`) with warning baseline. +- Define semantic versioning and deprecation policy per target framework. +- Consider `net8.0` target for optimized modern runtime behavior. + +## Why this approach + +For a package family with millions of downloads, preserving binary compatibility while introducing modern targets in stages avoids consumer breakage and keeps release risk manageable. diff --git a/src/FlatFile.Benchmark/FlatFile.Benchmark.csproj b/src/FlatFile.Benchmark/FlatFile.Benchmark.csproj index caa3588..09b1eed 100644 --- a/src/FlatFile.Benchmark/FlatFile.Benchmark.csproj +++ b/src/FlatFile.Benchmark/FlatFile.Benchmark.csproj @@ -31,6 +31,63 @@ prompt 4 + + + + v4.5.1 + AnyCPU + + + v4.5.2 + AnyCPU + + + v4.6 + AnyCPU + + + v4.6.1 + AnyCPU + + + v4.6.2 + AnyCPU + + + v4.7 + AnyCPU + + + v4.7.1 + AnyCPU + + + v4.7.2 + AnyCPU + + + v4.8 + AnyCPU + true + full + false + bin\$(Configuration)\$(Framework)\ + DEBUG;TRACE + prompt + 4 + + + v4.8 + AnyCPU + pdbonly + true + bin\$(Configuration)\$(Framework)\ + TRACE + prompt + 4 + bin\$(Configuration)\$(Framework)\FlatFile.Benchmark.XML + + ..\packages\Benchmark.It.1.2.0\lib\BenchmarkIt.dll diff --git a/src/FlatFile.Core.Attributes.Modern/FlatFile.Core.Attributes.Modern.csproj b/src/FlatFile.Core.Attributes.Modern/FlatFile.Core.Attributes.Modern.csproj new file mode 100644 index 0000000..cc3653c --- /dev/null +++ b/src/FlatFile.Core.Attributes.Modern/FlatFile.Core.Attributes.Modern.csproj @@ -0,0 +1,19 @@ + + + netstandard2.0;net8.0 + FlatFile.Core.Attributes + FlatFile.Core.Attributes + false + latest + disable + true + + + + + + + + + + diff --git a/src/FlatFile.Core.Attributes/FlatFile.Core.Attributes.csproj b/src/FlatFile.Core.Attributes/FlatFile.Core.Attributes.csproj index 87f339c..5689453 100644 --- a/src/FlatFile.Core.Attributes/FlatFile.Core.Attributes.csproj +++ b/src/FlatFile.Core.Attributes/FlatFile.Core.Attributes.csproj @@ -86,6 +86,63 @@ 4 bin\$(Configuration)\$(Framework)\$(AssemblyName).XML + + + + v4.5.1 + AnyCPU + + + v4.5.2 + AnyCPU + + + v4.6 + AnyCPU + + + v4.6.1 + AnyCPU + + + v4.6.2 + AnyCPU + + + v4.7 + AnyCPU + + + v4.7.1 + AnyCPU + + + v4.7.2 + AnyCPU + + + v4.8 + AnyCPU + true + full + false + bin\$(Configuration)\$(Framework)\ + DEBUG;TRACE + prompt + 4 + + + v4.8 + AnyCPU + pdbonly + true + bin\$(Configuration)\$(Framework)\ + TRACE + prompt + 4 + bin\$(Configuration)\$(Framework)\FlatFile.Core.Attributes.XML + + diff --git a/src/FlatFile.Core.Modern/FlatFile.Core.Modern.csproj b/src/FlatFile.Core.Modern/FlatFile.Core.Modern.csproj new file mode 100644 index 0000000..8f79071 --- /dev/null +++ b/src/FlatFile.Core.Modern/FlatFile.Core.Modern.csproj @@ -0,0 +1,15 @@ + + + netstandard2.0;net8.0 + FlatFile.Core + FlatFile.Core + false + latest + disable + true + + + + + + diff --git a/src/FlatFile.Core/Exceptions/ParseLineException.cs b/src/FlatFile.Core/Exceptions/ParseLineException.cs index 707a336..679fa17 100644 --- a/src/FlatFile.Core/Exceptions/ParseLineException.cs +++ b/src/FlatFile.Core/Exceptions/ParseLineException.cs @@ -29,11 +29,13 @@ public ParseLineException(string line, int lineNumber) public int LineNumber { get; private set; } public string Line { get; private set; } +#pragma warning disable SYSLIB0051 protected ParseLineException(SerializationInfo info, StreamingContext context, string line, int lineNumber) : base(info, context) { Line = line; LineNumber = lineNumber; } +#pragma warning restore SYSLIB0051 } } diff --git a/src/FlatFile.Core/FlatFile.Core.csproj b/src/FlatFile.Core/FlatFile.Core.csproj index 08ab631..4cb20c8 100644 --- a/src/FlatFile.Core/FlatFile.Core.csproj +++ b/src/FlatFile.Core/FlatFile.Core.csproj @@ -86,6 +86,63 @@ 4 bin\$(Configuration)\$(Framework)\FlatFile.Core.XML + + + + v4.5.1 + AnyCPU + + + v4.5.2 + AnyCPU + + + v4.6 + AnyCPU + + + v4.6.1 + AnyCPU + + + v4.6.2 + AnyCPU + + + v4.7 + AnyCPU + + + v4.7.1 + AnyCPU + + + v4.7.2 + AnyCPU + + + v4.8 + AnyCPU + true + full + false + bin\$(Configuration)\$(Framework)\ + DEBUG;TRACE + prompt + 4 + + + v4.8 + AnyCPU + pdbonly + true + bin\$(Configuration)\$(Framework)\ + TRACE + prompt + 4 + bin\$(Configuration)\$(Framework)\FlatFile.Core.XML + + diff --git a/src/FlatFile.Delimited.Attributes.Modern/FlatFile.Delimited.Attributes.Modern.csproj b/src/FlatFile.Delimited.Attributes.Modern/FlatFile.Delimited.Attributes.Modern.csproj new file mode 100644 index 0000000..e18900c --- /dev/null +++ b/src/FlatFile.Delimited.Attributes.Modern/FlatFile.Delimited.Attributes.Modern.csproj @@ -0,0 +1,21 @@ + + + netstandard2.0;net8.0 + FlatFile.Delimited.Attributes + FlatFile.Delimited.Attributes + false + latest + disable + true + + + + + + + + + + + + diff --git a/src/FlatFile.Delimited.Attributes/FlatFile.Delimited.Attributes.csproj b/src/FlatFile.Delimited.Attributes/FlatFile.Delimited.Attributes.csproj index 8c89756..3c6c5fa 100644 --- a/src/FlatFile.Delimited.Attributes/FlatFile.Delimited.Attributes.csproj +++ b/src/FlatFile.Delimited.Attributes/FlatFile.Delimited.Attributes.csproj @@ -84,6 +84,63 @@ 4 bin\$(Configuration)\$(Framework)\$(AssemblyName).XML + + + + v4.5.1 + AnyCPU + + + v4.5.2 + AnyCPU + + + v4.6 + AnyCPU + + + v4.6.1 + AnyCPU + + + v4.6.2 + AnyCPU + + + v4.7 + AnyCPU + + + v4.7.1 + AnyCPU + + + v4.7.2 + AnyCPU + + + v4.8 + AnyCPU + true + full + false + bin\$(Configuration)\$(Framework)\ + DEBUG;TRACE + prompt + 4 + + + v4.8 + AnyCPU + pdbonly + true + bin\$(Configuration)\$(Framework)\ + TRACE + prompt + 4 + bin\$(Configuration)\$(Framework)\FlatFile.Delimited.Attributes.XML + + diff --git a/src/FlatFile.Delimited.Modern/FlatFile.Delimited.Modern.csproj b/src/FlatFile.Delimited.Modern/FlatFile.Delimited.Modern.csproj new file mode 100644 index 0000000..2b5afe6 --- /dev/null +++ b/src/FlatFile.Delimited.Modern/FlatFile.Delimited.Modern.csproj @@ -0,0 +1,19 @@ + + + netstandard2.0;net8.0 + FlatFile.Delimited + FlatFile.Delimited + false + latest + disable + true + + + + + + + + + + diff --git a/src/FlatFile.Delimited/FlatFile.Delimited.csproj b/src/FlatFile.Delimited/FlatFile.Delimited.csproj index 1523482..32a8a8f 100644 --- a/src/FlatFile.Delimited/FlatFile.Delimited.csproj +++ b/src/FlatFile.Delimited/FlatFile.Delimited.csproj @@ -84,6 +84,63 @@ 4 bin\$(Configuration)\$(Framework)\FlatFile.Delimited.XML + + + + v4.5.1 + AnyCPU + + + v4.5.2 + AnyCPU + + + v4.6 + AnyCPU + + + v4.6.1 + AnyCPU + + + v4.6.2 + AnyCPU + + + v4.7 + AnyCPU + + + v4.7.1 + AnyCPU + + + v4.7.2 + AnyCPU + + + v4.8 + AnyCPU + true + full + false + bin\$(Configuration)\$(Framework)\ + DEBUG;TRACE + prompt + 4 + + + v4.8 + AnyCPU + pdbonly + true + bin\$(Configuration)\$(Framework)\ + TRACE + prompt + 4 + bin\$(Configuration)\$(Framework)\FlatFile.Delimited.XML + + diff --git a/src/FlatFile.FixedLength.Attributes.Modern/FlatFile.FixedLength.Attributes.Modern.csproj b/src/FlatFile.FixedLength.Attributes.Modern/FlatFile.FixedLength.Attributes.Modern.csproj new file mode 100644 index 0000000..4620a83 --- /dev/null +++ b/src/FlatFile.FixedLength.Attributes.Modern/FlatFile.FixedLength.Attributes.Modern.csproj @@ -0,0 +1,21 @@ + + + netstandard2.0;net8.0 + FlatFile.FixedLength.Attributes + FlatFile.FixedLength.Attributes + false + latest + disable + true + + + + + + + + + + + + diff --git a/src/FlatFile.FixedLength.Attributes/FlatFile.FixedLength.Attributes.csproj b/src/FlatFile.FixedLength.Attributes/FlatFile.FixedLength.Attributes.csproj index 5289115..32c95c4 100644 --- a/src/FlatFile.FixedLength.Attributes/FlatFile.FixedLength.Attributes.csproj +++ b/src/FlatFile.FixedLength.Attributes/FlatFile.FixedLength.Attributes.csproj @@ -84,6 +84,63 @@ 4 bin\$(Configuration)\$(Framework)\$(AssemblyName).XML + + + + v4.5.1 + AnyCPU + + + v4.5.2 + AnyCPU + + + v4.6 + AnyCPU + + + v4.6.1 + AnyCPU + + + v4.6.2 + AnyCPU + + + v4.7 + AnyCPU + + + v4.7.1 + AnyCPU + + + v4.7.2 + AnyCPU + + + v4.8 + AnyCPU + true + full + false + bin\$(Configuration)\$(Framework)\ + DEBUG;TRACE + prompt + 4 + + + v4.8 + AnyCPU + pdbonly + true + bin\$(Configuration)\$(Framework)\ + TRACE + prompt + 4 + bin\$(Configuration)\$(Framework)\FlatFile.FixedLength.Attributes.XML + + diff --git a/src/FlatFile.FixedLength.Modern/FlatFile.FixedLength.Modern.csproj b/src/FlatFile.FixedLength.Modern/FlatFile.FixedLength.Modern.csproj new file mode 100644 index 0000000..94e3b4b --- /dev/null +++ b/src/FlatFile.FixedLength.Modern/FlatFile.FixedLength.Modern.csproj @@ -0,0 +1,19 @@ + + + netstandard2.0;net8.0 + FlatFile.FixedLength + FlatFile.FixedLength + false + latest + disable + true + + + + + + + + + + diff --git a/src/FlatFile.FixedLength/FlatFile.FixedLength.csproj b/src/FlatFile.FixedLength/FlatFile.FixedLength.csproj index f0090b9..b1b1510 100644 --- a/src/FlatFile.FixedLength/FlatFile.FixedLength.csproj +++ b/src/FlatFile.FixedLength/FlatFile.FixedLength.csproj @@ -84,6 +84,63 @@ 4 bin\$(Configuration)\$(Framework)\FlatFile.FixedLength.XML + + + + v4.5.1 + AnyCPU + + + v4.5.2 + AnyCPU + + + v4.6 + AnyCPU + + + v4.6.1 + AnyCPU + + + v4.6.2 + AnyCPU + + + v4.7 + AnyCPU + + + v4.7.1 + AnyCPU + + + v4.7.2 + AnyCPU + + + v4.8 + AnyCPU + true + full + false + bin\$(Configuration)\$(Framework)\ + DEBUG;TRACE + prompt + 4 + + + v4.8 + AnyCPU + pdbonly + true + bin\$(Configuration)\$(Framework)\ + TRACE + prompt + 4 + bin\$(Configuration)\$(Framework)\FlatFile.FixedLength.XML + + diff --git a/src/FlatFile.Tests/FlatFile.Tests.csproj b/src/FlatFile.Tests/FlatFile.Tests.csproj index 57f98f9..9d1d0e0 100644 --- a/src/FlatFile.Tests/FlatFile.Tests.csproj +++ b/src/FlatFile.Tests/FlatFile.Tests.csproj @@ -31,6 +31,63 @@ prompt 4 + + + + v4.5.1 + AnyCPU + + + v4.5.2 + AnyCPU + + + v4.6 + AnyCPU + + + v4.6.1 + AnyCPU + + + v4.6.2 + AnyCPU + + + v4.7 + AnyCPU + + + v4.7.1 + AnyCPU + + + v4.7.2 + AnyCPU + + + v4.8 + AnyCPU + true + full + false + bin\$(Configuration)\$(Framework)\ + DEBUG;TRACE + prompt + 4 + + + v4.8 + AnyCPU + pdbonly + true + bin\$(Configuration)\$(Framework)\ + TRACE + prompt + 4 + bin\$(Configuration)\$(Framework)\FlatFile.Tests.XML + + ..\packages\FakeItEasy.2.2.0\lib\net40\FakeItEasy.dll From b7bac20a1206694305ba79d7e19403d5ef1ef271 Mon Sep 17 00:00:00 2001 From: Pavel Nasovich Date: Sun, 1 Mar 2026 22:11:24 +0100 Subject: [PATCH 2/4] Fix CI by installing MSBuild on Windows runner --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0f4a746..7856bca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,10 @@ jobs: - name: Setup NuGet uses: NuGet/setup-nuget@v2 + + - name: Setup MSBuild + uses: microsoft/setup-msbuild@v2 + - name: Restore NuGet packages run: nuget restore src/FlatFile.sln From 9203207d3525eb82aa19bff3af919c767826bb10 Mon Sep 17 00:00:00 2001 From: Pavel Nasovich Date: Sun, 1 Mar 2026 22:18:09 +0100 Subject: [PATCH 3/4] Break to v2: drop legacy .NET targets and standardize on net8 --- .github/workflows/ci.yml | 30 ++---------- README.md | 12 ++--- assets/psake-common.ps1 | 42 ++++++++--------- docs/modernization-plan.md | 47 +++++-------------- .../FlatFile.Core.Attributes.Modern.csproj | 5 +- .../FlatFile.Core.Modern.csproj | 5 +- ...latFile.Delimited.Attributes.Modern.csproj | 5 +- .../FlatFile.Delimited.Modern.csproj | 5 +- ...tFile.FixedLength.Attributes.Modern.csproj | 5 +- .../FlatFile.FixedLength.Modern.csproj | 5 +- 10 files changed, 65 insertions(+), 96 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7856bca..0f87426 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,30 +6,7 @@ on: pull_request: jobs: - build-netfx: - runs-on: windows-latest - strategy: - fail-fast: false - matrix: - framework: [NET35, NET40, NET45, NET451, NET452, NET46, NET461, NET462, NET47, NET471, NET472, NET48] - - steps: - - uses: actions/checkout@v4 - - - name: Setup NuGet - uses: NuGet/setup-nuget@v2 - - - - name: Setup MSBuild - uses: microsoft/setup-msbuild@v2 - - - name: Restore NuGet packages - run: nuget restore src/FlatFile.sln - - - name: Build (.NET Framework ${{ matrix.framework }}) - run: msbuild src/FlatFile.sln /p:Configuration=Release /p:Framework=${{ matrix.framework }} /m /v:minimal - - build-modern-dotnet: + build-dotnet8: runs-on: ubuntu-latest steps: @@ -38,10 +15,9 @@ jobs: - name: Setup .NET SDK uses: actions/setup-dotnet@v4 with: - dotnet-version: | - 8.0.x + dotnet-version: 8.0.x - - name: Build modern SDK-style projects + - name: Build modern SDK-style projects (v2) run: | dotnet build src/FlatFile.Core.Modern/FlatFile.Core.Modern.csproj -c Release dotnet build src/FlatFile.Core.Attributes.Modern/FlatFile.Core.Attributes.Modern.csproj -c Release diff --git a/README.md b/README.md index ec98142..e2123de 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,13 @@ FlatFile is a library to work with flat files (work up-to 100 times faster then ## Modernization status -- ✅ Added .NET Framework **4.8** build target (`Framework=NET35/40/45/451/452/46/461/462/47/471/472/48`) across projects. -- ✅ Added GitHub Actions CI matrix for all supported .NET Framework build aliases in this repository. -- ✅ Added SDK-style modern projects targeting `netstandard2.0` and `net8.0` for .NET Core / modern .NET support. -- 📘 See [docs/modernization-plan.md](docs/modernization-plan.md) for the full upgrade roadmap (including SDK-style migration, PackageReference, and netstandard/net8 targeting). - +- 🚨 **v2 breaking change**: dropped legacy .NET Framework targets (`net35`-`net48`) and old build pipeline. +- ✅ Modernized runtime support to **.NET 8** only via SDK-style projects. +- ✅ CI now builds modern projects with `dotnet build` on GitHub Actions. ### Modern .NET support -This repository now includes SDK-style projects for modern runtimes: +Active projects: - `src/FlatFile.Core.Modern` - `src/FlatFile.Core.Attributes.Modern` @@ -24,7 +22,7 @@ This repository now includes SDK-style projects for modern runtimes: - `src/FlatFile.Delimited.Attributes.Modern` - `src/FlatFile.FixedLength.Attributes.Modern` -Each targets `netstandard2.0` and `net8.0`, enabling usage from .NET Core and latest .NET apps while preserving the legacy .NET Framework projects. +All of them target `net8.0` and carry package/assembly version `2.0.0`. ### Installing FlatFile diff --git a/assets/psake-common.ps1 b/assets/psake-common.ps1 index 956b8a7..dacecac 100644 --- a/assets/psake-common.ps1 +++ b/assets/psake-common.ps1 @@ -20,8 +20,15 @@ Properties { ### Project information $solution_path = "$src_dir\$solution" $sharedAssemblyInfo = "$src_dir\SharedAssemblyInfo.cs" - $config = "Release" - $frameworks = @("NET35", "NET40", "NET45", "NET451", "NET452", "NET46", "NET461", "NET462", "NET47", "NET471", "NET472", "NET48") + $config = "Release" + $modern_projects = @( + "$src_dir\FlatFile.Core.Modern\FlatFile.Core.Modern.csproj", + "$src_dir\FlatFile.Core.Attributes.Modern\FlatFile.Core.Attributes.Modern.csproj", + "$src_dir\FlatFile.Delimited.Modern\FlatFile.Delimited.Modern.csproj", + "$src_dir\FlatFile.FixedLength.Modern\FlatFile.FixedLength.Modern.csproj", + "$src_dir\FlatFile.Delimited.Attributes.Modern\FlatFile.Delimited.Attributes.Modern.csproj", + "$src_dir\FlatFile.FixedLength.Attributes.Modern\FlatFile.FixedLength.Attributes.Modern.csproj" + ) ### Files $releaseNotes = "$base_dir\ChangeLog.md" @@ -29,34 +36,27 @@ Properties { ## Tasks -Task Restore -Description "Restore NuGet packages for solution." { - "Restoring NuGet packages for '$solution_path'..." - Exec { .$nuget restore $solution_path } +Task Restore -Description "Restore .NET packages for modern projects." { + foreach ($project in $modern_projects) { + "Restoring '$project'..." + Exec { dotnet restore $project } + } } Task Clean -Description "Clean up build and project folders." { Clean-Directory $build_dir - if ($solution) { - "Cleaning up '$solution'..." - - foreach ($framework in $frameworks) { - Exec { msbuild $solution_path /target:Clean /nologo /verbosity:minimal /p:Framework=$framework} - } + foreach ($project in $modern_projects) { + "Cleaning '$project'..." + Exec { dotnet clean $project -c $config } } } -Task Compile -Depends Clean, Restore -Description "Compile all the projects in a solution." { - "Compiling '$solution'..." - - $extra = $null - if ($appVeyor) { - $extra = "/logger:C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" +Task Compile -Depends Clean, Restore -Description "Compile all modern SDK-style projects." { + foreach ($project in $modern_projects) { + "Compiling '$project'..." + Exec { dotnet build $project -c $config --no-restore } } - - foreach ($framework in $frameworks) { - Exec { msbuild $solution_path /p:"Configuration=$config;Framework=$framework" /nologo /verbosity:minimal $extra } - } } ### Pack functions diff --git a/docs/modernization-plan.md b/docs/modernization-plan.md index e1d8c45..444d30b 100644 --- a/docs/modernization-plan.md +++ b/docs/modernization-plan.md @@ -1,43 +1,20 @@ # FlatFile modernization plan -This repository is a mature .NET Framework codebase with broad usage. The safest modernization strategy is **incremental** and **compatibility-first**. +## Current direction (v2) -## Changes applied in this update +This repository now follows a **modern-only** strategy: -1. Added build-target aliases for all maintained .NET Framework lines used by enterprise consumers (`NET451`, `NET452`, `NET46`, `NET461`, `NET462`, `NET47`, `NET471`, `NET472`, `NET48`) in addition to legacy aliases already present (`NET35`, `NET40`, `NET45`). -2. Extended the psake build pipeline to compile every declared framework alias. -3. Added a GitHub Actions CI matrix that restores once and builds the solution for each framework alias on `windows-latest`. -4. Added SDK-style modern library projects (`*.Modern.csproj`) targeting `netstandard2.0` and `net8.0` to provide .NET Core / modern .NET support. +1. Legacy .NET Framework build matrix was removed from CI. +2. SDK-style projects under `*.Modern` are the active build path. +3. Active target is `net8.0` with version `2.0.0` (breaking major release). -## Recommended next modernization phases +## Why -### Phase 1: Packaging and CI hygiene (low risk) +The previous mixed strategy (legacy + modern) produced unstable CI and unnecessary maintenance overhead. +A major-version reset enables simpler tooling, faster builds, and a clear support policy. -- Move from external `.nuspec` packing to SDK-style `dotnet pack` metadata in project files. -- Add SourceLink and deterministic builds. -- Add test execution in CI (`xUnit`) and fail-fast gates. -- Rotate package publishing credentials and use GitHub/ADO secret stores. +## Next steps -### Phase 2: Project-system migration (medium risk) - -- Gradually migrate legacy csproj files to SDK-style projects after validating consumer migration from the new `*.Modern` projects. -- Keep compatibility by multitargeting: - - `net48` (existing consumers) - - `netstandard2.0` (broad modern compatibility) -- Replace `packages.config` with `PackageReference`. - -### Phase 3: Runtime/API modernization (medium-high risk) - -- Add nullable reference types in new API surfaces first, then expand internally. -- Add `Span`/`ReadOnlySpan` overloads for high-throughput parsing paths. -- Introduce async stream APIs where useful (`IAsyncEnumerable` for line reading). - -### Phase 4: Ecosystem and maintenance - -- Add Roslyn analyzers (`Microsoft.CodeAnalysis.NetAnalyzers`) with warning baseline. -- Define semantic versioning and deprecation policy per target framework. -- Consider `net8.0` target for optimized modern runtime behavior. - -## Why this approach - -For a package family with millions of downloads, preserving binary compatibility while introducing modern targets in stages avoids consumer breakage and keeps release risk manageable. +- Publish v2 packages from modern projects (`dotnet pack`). +- Add analyzers and nullable annotations incrementally. +- Add dedicated test projects targeting `net8.0`. diff --git a/src/FlatFile.Core.Attributes.Modern/FlatFile.Core.Attributes.Modern.csproj b/src/FlatFile.Core.Attributes.Modern/FlatFile.Core.Attributes.Modern.csproj index cc3653c..95ba650 100644 --- a/src/FlatFile.Core.Attributes.Modern/FlatFile.Core.Attributes.Modern.csproj +++ b/src/FlatFile.Core.Attributes.Modern/FlatFile.Core.Attributes.Modern.csproj @@ -1,12 +1,15 @@ - netstandard2.0;net8.0 + net8.0 FlatFile.Core.Attributes FlatFile.Core.Attributes false latest disable true + 2.0.0 + 2.0.0.0 + 2.0.0.0 diff --git a/src/FlatFile.Core.Modern/FlatFile.Core.Modern.csproj b/src/FlatFile.Core.Modern/FlatFile.Core.Modern.csproj index 8f79071..ce7d9bb 100644 --- a/src/FlatFile.Core.Modern/FlatFile.Core.Modern.csproj +++ b/src/FlatFile.Core.Modern/FlatFile.Core.Modern.csproj @@ -1,12 +1,15 @@ - netstandard2.0;net8.0 + net8.0 FlatFile.Core FlatFile.Core false latest disable true + 2.0.0 + 2.0.0.0 + 2.0.0.0 diff --git a/src/FlatFile.Delimited.Attributes.Modern/FlatFile.Delimited.Attributes.Modern.csproj b/src/FlatFile.Delimited.Attributes.Modern/FlatFile.Delimited.Attributes.Modern.csproj index e18900c..e115b0e 100644 --- a/src/FlatFile.Delimited.Attributes.Modern/FlatFile.Delimited.Attributes.Modern.csproj +++ b/src/FlatFile.Delimited.Attributes.Modern/FlatFile.Delimited.Attributes.Modern.csproj @@ -1,12 +1,15 @@ - netstandard2.0;net8.0 + net8.0 FlatFile.Delimited.Attributes FlatFile.Delimited.Attributes false latest disable true + 2.0.0 + 2.0.0.0 + 2.0.0.0 diff --git a/src/FlatFile.Delimited.Modern/FlatFile.Delimited.Modern.csproj b/src/FlatFile.Delimited.Modern/FlatFile.Delimited.Modern.csproj index 2b5afe6..0c46795 100644 --- a/src/FlatFile.Delimited.Modern/FlatFile.Delimited.Modern.csproj +++ b/src/FlatFile.Delimited.Modern/FlatFile.Delimited.Modern.csproj @@ -1,12 +1,15 @@ - netstandard2.0;net8.0 + net8.0 FlatFile.Delimited FlatFile.Delimited false latest disable true + 2.0.0 + 2.0.0.0 + 2.0.0.0 diff --git a/src/FlatFile.FixedLength.Attributes.Modern/FlatFile.FixedLength.Attributes.Modern.csproj b/src/FlatFile.FixedLength.Attributes.Modern/FlatFile.FixedLength.Attributes.Modern.csproj index 4620a83..0b8b8d6 100644 --- a/src/FlatFile.FixedLength.Attributes.Modern/FlatFile.FixedLength.Attributes.Modern.csproj +++ b/src/FlatFile.FixedLength.Attributes.Modern/FlatFile.FixedLength.Attributes.Modern.csproj @@ -1,12 +1,15 @@ - netstandard2.0;net8.0 + net8.0 FlatFile.FixedLength.Attributes FlatFile.FixedLength.Attributes false latest disable true + 2.0.0 + 2.0.0.0 + 2.0.0.0 diff --git a/src/FlatFile.FixedLength.Modern/FlatFile.FixedLength.Modern.csproj b/src/FlatFile.FixedLength.Modern/FlatFile.FixedLength.Modern.csproj index 94e3b4b..f029abe 100644 --- a/src/FlatFile.FixedLength.Modern/FlatFile.FixedLength.Modern.csproj +++ b/src/FlatFile.FixedLength.Modern/FlatFile.FixedLength.Modern.csproj @@ -1,12 +1,15 @@ - netstandard2.0;net8.0 + net8.0 FlatFile.FixedLength FlatFile.FixedLength false latest disable true + 2.0.0 + 2.0.0.0 + 2.0.0.0 From 252e4b06c7cbc9e56fb28a547380a67451bf1820 Mon Sep 17 00:00:00 2001 From: Pavel Nasovich Date: Sun, 1 Mar 2026 22:24:09 +0100 Subject: [PATCH 4/4] Add GitHub NuGet publish workflow for v2 packages --- .github/workflows/publish-nuget.yml | 48 +++++++++++++++++++++++++++++ README.md | 10 ++++++ docs/modernization-plan.md | 7 +++++ src/Directory.Build.props | 17 ++++++++++ 4 files changed, 82 insertions(+) create mode 100644 .github/workflows/publish-nuget.yml create mode 100644 src/Directory.Build.props diff --git a/.github/workflows/publish-nuget.yml b/.github/workflows/publish-nuget.yml new file mode 100644 index 0000000..cb83561 --- /dev/null +++ b/.github/workflows/publish-nuget.yml @@ -0,0 +1,48 @@ +name: Publish NuGet (v2) + +on: + push: + branches: [ master ] + workflow_dispatch: + +permissions: + contents: read + +jobs: + publish: + runs-on: ubuntu-latest + env: + NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + PACKAGE_VERSION: 2.0.${{ github.run_number }} + + steps: + - uses: actions/checkout@v4 + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + + - name: Validate NuGet API key is configured + run: | + if [ -z "$NUGET_API_KEY" ]; then + echo "NUGET_API_KEY secret is not configured." >&2 + exit 1 + fi + + - name: Pack v2 packages + run: | + mkdir -p artifacts/packages + dotnet pack src/FlatFile.Core.Modern/FlatFile.Core.Modern.csproj -c Release -o artifacts/packages /p:Version=$PACKAGE_VERSION + dotnet pack src/FlatFile.Core.Attributes.Modern/FlatFile.Core.Attributes.Modern.csproj -c Release -o artifacts/packages /p:Version=$PACKAGE_VERSION + dotnet pack src/FlatFile.Delimited.Modern/FlatFile.Delimited.Modern.csproj -c Release -o artifacts/packages /p:Version=$PACKAGE_VERSION + dotnet pack src/FlatFile.FixedLength.Modern/FlatFile.FixedLength.Modern.csproj -c Release -o artifacts/packages /p:Version=$PACKAGE_VERSION + dotnet pack src/FlatFile.Delimited.Attributes.Modern/FlatFile.Delimited.Attributes.Modern.csproj -c Release -o artifacts/packages /p:Version=$PACKAGE_VERSION + dotnet pack src/FlatFile.FixedLength.Attributes.Modern/FlatFile.FixedLength.Attributes.Modern.csproj -c Release -o artifacts/packages /p:Version=$PACKAGE_VERSION + + - name: Publish packages to NuGet + run: | + dotnet nuget push "artifacts/packages/*.nupkg" \ + --api-key "$NUGET_API_KEY" \ + --source https://api.nuget.org/v3/index.json \ + --skip-duplicate diff --git a/README.md b/README.md index e2123de..cd8bae7 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,16 @@ Active projects: All of them target `net8.0` and carry package/assembly version `2.0.0`. +### NuGet publishing from GitHub + +When changes are merged to `master`, GitHub Actions can publish v2 packages automatically using `.github/workflows/publish-nuget.yml`. + +Required repository secret: + +- `NUGET_API_KEY`: NuGet.org API key with push permission for FlatFile packages. + +The publish workflow packs all `*.Modern` projects and pushes resulting `.nupkg` files to NuGet (`--skip-duplicate`). + ### Installing FlatFile #### Installing all packages diff --git a/docs/modernization-plan.md b/docs/modernization-plan.md index 444d30b..046fed4 100644 --- a/docs/modernization-plan.md +++ b/docs/modernization-plan.md @@ -18,3 +18,10 @@ A major-version reset enables simpler tooling, faster builds, and a clear suppor - Publish v2 packages from modern projects (`dotnet pack`). - Add analyzers and nullable annotations incrementally. - Add dedicated test projects targeting `net8.0`. + + +## CI/CD publishing + +- `.github/workflows/publish-nuget.yml` publishes NuGet packages on pushes to `master`. +- Configure repository secret `NUGET_API_KEY` before enabling release merges. +- Package versions are generated as `2.0.` in CI. diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 0000000..f416ac7 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,17 @@ + + + true + MIT + forcewake + Pavel Nasovich + FlatFile library for high-performance fixed-length and delimited file processing. + https://github.com/forcewake/FlatFile + https://github.com/forcewake/FlatFile + git + README.md + + + + + +