Skip to content

Upgrade release workflow actions to Node 24 and add .NET Core 3.1#7

Closed
Chris-Wolfgang wants to merge 17 commits into
mainfrom
chore/upgrade-actions-and-add-netcore31
Closed

Upgrade release workflow actions to Node 24 and add .NET Core 3.1#7
Chris-Wolfgang wants to merge 17 commits into
mainfrom
chore/upgrade-actions-and-add-netcore31

Conversation

@Chris-Wolfgang
Copy link
Copy Markdown
Owner

Summary

  • actions/download-artifact: v4 → v8.0.1
  • softprops/action-gh-release: v2.5.0 (SHA a06a81a0) → v3.0.0 (SHA b4309332)
  • Adds 3.1.x to dotnet-version in all 3 setup-dotnet blocks.

Bundles two related release-workflow fixes:

  1. Node 24 actions upgrade (mirrors ETL-Test-Kit#54) — clears Node 20 deprecation warning.
  2. .NET Core 3.1 SDK in setup-dotnet (mirrors ETL-Json#54) — needed because test projects target netcoreapp3.1.

Breaking change review

  • download-artifact v5 changed the output path for single artifact downloads by ID. This workflow only downloads by name:, so unaffected.
  • action-gh-release v3.0.0 is purely a Node 24 runtime bump per release notes.

Test plan

  • Next release runs without Node 20 deprecation warning
  • .NET Core 3.1 SDK installs and netcoreapp3.1 tests succeed

Chris-Wolfgang and others added 17 commits April 15, 2026 21:24
…idation

Port legacy Benco.Framework.Etl.SqlBulkCopy to Wolfgang.Etl framework.
Inherits LoaderBase<TRecord, SqlBulkCopyReport> from Abstractions 0.12.0.

Key features:
- TypeMap reflection engine with [Table], [Column], [NotMapped] support
- TypeMapReader (DbDataReader) replaces DataTable for better performance
- Nested collection-to-table mapping (recursive)
- ISqlBulkCopyWrapper abstraction for unit testability
- Pre/post actions (DeleteAllRecords, TruncateTable, CustomAction)
- Opt-in DataAnnotation validation with OnValidationFailed callback
- 18 supported CLR types including DateTimeOffset, TimeSpan, Enum
- Structured logging via LoggerMessage.Define

101 tests passing across 11 TFMs (net462 through net10.0).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CI builds in Release mode with TreatWarningsAsErrors. Name unnamed
parameters and use string.Equals instead of == operator.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SqlBulkCopyWrapper and SqlBulkCopyWrapperFactory are thin pass-throughs
to Microsoft.Data.SqlClient.SqlBulkCopy requiring a real SQL Server.
Parameter records are compiler-generated. ColumnMap.CreateGetter has
an unreachable defensive branch. All excluded per coverage conventions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix SkipItemCount tracking: use separate counter independent of
  validation skips to preserve "skip first N" semantics
- Fix column mapping: use ColumnName for both source and destination
  so SqlBulkCopy matches against TypeMapReader.GetName() correctly
- Fix null connection guard: add EnsureConnectionAvailable() check
  for custom pre/post actions, not just SQL command execution
- Fix SQL identifier injection: escape ']' as ']]' in QualifiedTableName
- Fix nested table element type: resolve via IEnumerable<T> interface
  instead of GenericTypeArguments to handle Dictionary etc. correctly
- Fix TypeMapReader state guard: GetValue/IsDBNull validate Read() was
  called; GetName/GetOrdinal remain metadata-only (no row required)
- Fix whitespace overrides: treat empty/whitespace schema/table name
  overrides as "not provided" using IsNullOrWhiteSpace
- Fix validation position: remove double-counting of SkipItemCount

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove dead getMethod validation in ColumnMap.CreateGetter
- Change TypeMap cache key from pipe-delimited string to ValueTuple
  to eliminate collision risk
- Add Dictionary<string,int> ordinal lookup in TypeMapReader for O(1)
  GetOrdinal instead of O(n) linear scan

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix XML doc cref resolution for PreAction/PostAction enum references
- Replace IndexOutOfRangeException with ArgumentOutOfRangeException
  (S112/MA0012: reserved exception types)
- Suppress S3928/MA0015 for property-based ArgumentOutOfRangeException
- Remove redundant casts, using directives, and namespace qualifiers
- Remove redundant nullable warning suppression in TypeMap
- Split ValidateActionConfiguration to satisfy MA0051 method length

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add comprehensive tests for:
- NestedTableMap: constructor validation, null collection, array properties
- TypeMapReader: reader state validation, enum conversion, indexers,
  metadata properties, null ordinal
- SqlBulkCopyLoader: all constructor overloads, action validation,
  connection guards, skip+validation interaction, progress reporting
- TypeMap: unmapped types, no-column types, bracket escaping, whitespace
  overrides, caching

Exclude from coverage: ExecutePreActionAsync, ExecutePostActionAsync,
ExecuteSqlCommandAsync (require real SQL Server — integration test scope),
NestedTableMap.CreateValuesGetter (unreachable IEnumerable fallback).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove tests that create SqlConnection (fails on net6.0 due to
  missing System.Security.Permissions in Microsoft.Data.SqlClient 6.x)
- Use GetOrdinal instead of hardcoded ordinals in TypeMapReader tests
  to handle column ordering differences across TFMs
- 148 tests passing on all 11 TFMs with 96.5% line coverage

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add IFormatProvider to Convert.ChangeType and ToString calls
- Suppress S3267 for side-effecting foreach (AddColumnMapping is void)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… xUnit1030, AsyncFixer01)

- Split Status enum out of EnumRecord.cs into its own file (MA0048)
- Rename NoColumnsRecord.cs to NotMappedWithChildrenRecord.cs (MA0048)
- Change List<T> to IList<T> in test models (MA0016)
- Rename ToAsyncEnumerable to ToAsyncEnumerableAsync (VSTHRD200)
- Replace sync Read() with ReadAsync() in FakeSqlBulkCopyWrapper (VSTHRD103)
- Remove ConfigureAwait(false) from test methods (xUnit1030)
- Convert async tests that only await ThrowsAsync to return the Task directly (AsyncFixer01)

All 148 tests still pass across all 11 TFMs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This is a static helper, not a test method, so MA0004 applies.
The xUnit1030 rule about not using ConfigureAwait only applies to
methods marked with [Fact]/[Theory].

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add tests for invalid PreAction/PostAction enum values
- Add tests for PreAction.DeleteAllRecords/TruncateTable on NotMapped types
- Mark SqlConnection-based public constructors and CreateFactory as
  ExcludeFromCodeCoverage (require real SQL Server — integration scope)
- Mark CreateProgressTimer override as ExcludeFromCodeCoverage (the
  base.CreateProgressTimer fallback path requires real SQL Server use)

SqlBulkCopyLoader<T> coverage went from 86.7% to 99.5%.
Overall coverage: 99.8% line, 100% method, 94.9% branch.
152 tests pass on all 11 TFMs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous ExcludeFromCodeCoverage on CreateProgressTimer was wrong
— it threw away coverage of the wired-timer path that IS exercised by
every contract test. Only the base.CreateProgressTimer fallback line
was uncovered.

Fix: make timer parameter nullable in the internal test constructor
so a test can pass null and exercise the fallback path. Both branches
of CreateProgressTimer are now covered.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The two tests added in PR #5 used async/await for a single
ThrowsAsync call. Convert them to return Task directly to satisfy
AsyncFixer01.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- actions/download-artifact: v4 -> v8.0.1
- softprops/action-gh-release: v2.5.0 -> v3.0.0 (SHA b4309332)
- Add 3.1.x to dotnet-version in all 3 setup-dotnet blocks

Bundles two related release-workflow fixes (Node 24 mirrors ETL-Test-Kit#54;
3.1 mirrors ETL-Json#54). Test projects target netcoreapp3.1 and need
the 3.1 SDK to restore/test in release.yaml.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Chris-Wolfgang
Copy link
Copy Markdown
Owner Author

Closing — branch was inadvertently created from a divergent local state and bundled unrelated WIP commits with the one-line workflow fix. Replacing with a clean PR.

@Chris-Wolfgang Chris-Wolfgang deleted the chore/upgrade-actions-and-add-netcore31 branch April 27, 2026 22:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant