Skip to content

Clean-room v4 regen: 3-project split, Fallout codegen/CI, trusted publishing#7

Merged
ChrisonSimtian merged 7 commits into
mainfrom
feat/clean-room-regen-v5
Jul 23, 2026
Merged

Clean-room v4 regen: 3-project split, Fallout codegen/CI, trusted publishing#7
ChrisonSimtian merged 7 commits into
mainfrom
feat/clean-room-regen-v5

Conversation

@ChrisonSimtian

Copy link
Copy Markdown
Collaborator

Revives the library and modernises it end to end. Ships as 4.7.11 (via tag).

What changed

  • In-stack codegen — a Fallout Generate target using NSwag's C# API (no CLI/.nswag/scripts). Overlay coerces the 32 number resource-ids → long and hoists inline param enums (fixes Type/Action × System.*). Run: ./build.ps1 Generate.
  • 3-project architecture (enforced by a NetArchTest spec):
    • TvdbClient.Models — generated DTOs, API-versioned (Tvdb.Models)
    • TvdbClient.Abstractions — generic contracts/config/envelope
    • TvdbClient — core: generated clients + auth/DI
  • Health — fixed the .FromCallingAssembly() DI bug (clients didn't register for consumers), dropped vestigial Newtonsoft + the prerelease Scrutor dep (→ stable 5.0.1), repo URLs → Chrison-dev, README + badges.
  • Tests — replaced TUnit with the Fallout stack (xUnit + FluentAssertions + Verify + NetArchTest + Mockly); architecture specs pass.
  • CI/publishing — Fallout-driven build.yml (Test + Pack) + publish.yml using NuGet Trusted Publishing (OIDC) — no stored API key. Old hand-written workflows removed.

Deferred to a fast-follow (agreed)

  • The ergonomic facade unwrap → T/Page<T> (clients currently return the {data,status} wrapper). Everything works; this is a public-API nicety for 4.7.12.

To publish (owner steps)

See the PR discussion / release notes — requires the one-time nuget.org Trusted Publisher policy + a NUGET_USER repo variable, then tag v4.7.11.

🤖 Generated with Claude Code

ChrisonSimtian and others added 7 commits July 23, 2026 16:05
Turns the ad-hoc NSwag generation into a one-command, reproducible pipeline:

- tools/openapi/patch_spec.py — checked-in overlay (PyYAML). Coerces the 32
  integer resource-id PATH params that TheTVDB types as `number` (→ C# double)
  to integer/int64 (→ long). Narrow by design: the only other `number` fields
  are the genuinely-float `score` properties, left untouched.
- tools/openapi/generate.sh — download live v4 spec → apply overlay → run NSwag.
  Raw + patched specs are committed so a regen diff is reviewable.
- Pin NSwag as a local tool (NSwag.ConsoleCore 14.2.0, rollForward=true so it
  runs on the net10 runtime when net9 isn't installed).
- Repoint TvdbClient.nswag at the local patched spec.

Smoke-verified: NSwag against the patched spec emits 32 `long id` params, 0
`double id`. The in-place regen + model cleanup + facade come next.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…peline)

Per review feedback (stay within the .NET stack — no Python/Bash), replace the
previous patch_spec.py + generate.sh with a Fallout build.

- build/ Fallout build project (Fallout.Common/Components 11.0.18 from nuget.org,
  isolated from the repo-root packaging props). `Build.cs` adds a `Generate`
  target that uses NSwag's C# API directly (NSwag.CodeGeneration.CSharp) — no CLI,
  no .nswag config, no intermediate patched-yaml. It downloads the live v4 spec,
  applies the overlay in-memory (coerce the 32 integer id PATH params from
  `number` → int64, i.e. C# `long`; the only other `number` fields are the float
  `score`s, left alone), then emits clients + DTOs.
- build.ps1 / build.cmd bootstrappers (run the build project directly; no global
  tool needed): `./build.ps1 Generate`.
- .fallout/ root marker; drop the NSwag CLI tool pin from dotnet-tools.json.
- Remove tools/openapi/*.{py,sh}, the committed spec yamls, and TvdbClient.nswag.

Verified: `./build.ps1 Generate` succeeds and emits 32 `long id`, 0 `double id`,
135 model classes. The generated OUTPUT is intentionally not in this commit — the
in-place regen + hand-split-model cleanup + facade land in the next step.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…els project

Establishes the intended architecture: the API-versioned generated models live
in their own project/namespace, separate from the generic client core.

- New `TvdbClient.Models` project (PackageId TvdbClient.Models) holds the
  generated DTOs (ns `Tvdb.Models`); version tracks the TheTVDB API version.
- The `Generate` target now emits DTOs-only → Tvdb.Models and clients-only →
  Tvdb.Clients (core project), the clients importing Tvdb.Models. No more single
  namespace.
- Overlay gains inline-parameter-enum hoisting: TheTVDB's inline `/updates`
  type/action enums generated as `Type`/`Action`, colliding with System.* —
  they're now hoisted to named component schemas ({OperationId}{Param}).
- Delete the ~64 hand-split model files + stale generated artifacts
  (Clients/Interfaces.cs, ILoginClient.cs, Models/ResponseClasses.cs, the old
  single-project TvdbModels.cs); keep the hand-written generics (ApiResponseWrapper,
  Token, LoginRequestBody, AbstractBaseRecord). Fix the invalid body-less
  ITvdbClient marker interface.

Both src projects build clean (32 `long id`, 0 `double id`, 133 DTOs). Still to
come: extract the generic TvdbClient.Abstractions (3rd project), the facade
unwrap → T/Page<T>, and the NetArchTest architecture spec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…plit)

Completes the 3-project architecture: one API-versioned project + two generic.

- New TvdbClient.Abstractions (ns Tvdb.Abstractions): the generic contracts —
  ITvdbClient, ITokenProvider, TvdbConfiguration, ApiResponseWrapper<T>, Token,
  LoginRequestBody, AbstractBaseRecord. Depends only on the Models leaf.
- Vacates the Tvdb.Models namespace of hand-written types (they were wrongly
  sharing the generated DTOs' namespace).
- Generated clients now import Tvdb.Abstractions (for ITvdbClient).
- Delete dead code: Tvdb.Types param enums (superseded by hoisted generated
  enums in Tvdb.Models) and all Converters (generated DTOs use DateTimeOffset/
  TimeSpan); inline the trivial IsInThePast extension into Token.
- Re-point the facade (Bootstrapper/TokenProvider/Handler) at Tvdb.Abstractions.

All three src projects build clean. Architecture test enforcing the separation
lands next.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the stale TUnit test project with the first Fallout-style spec project
(xUnit + FluentAssertions + Verify + NetArchTest + Mockly; versioned packages
injected via tests/Directory.Build.props for *.Specs — no Central Package
Management).

ArchitectureSpecs locks the architecture Chris asked to protect:
- TvdbClient.Models depends on no other Tvdb project (regeneratable leaf).
- TvdbClient.Abstractions does not depend on the client core.
- The generated-model namespace Tvdb.Models lives only in the Models assembly.

All 3 specs pass. (RollForward=Major so the net9 test host runs on dev machines
that only have the net8/net10 runtimes.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Fix package URLs: ChrisonSimtian → Chrison-dev (repo moved orgs).
- Drop vestigial Newtonsoft.Json dep (generated code uses System.Text.Json;
  Newtonsoft only appeared in NSwag's generated comments).
- Move off the prerelease Scrutor.Extensions.HttpClient 5.1.2-alpha.2 → stable 5.0.1.
- Fix the DI registration bug: scan the core assembly (FromAssemblyOf<...>) instead
  of FromCallingAssembly(), which resolved to the consumer's assembly as a package
  and left the clients unregistered.
- GitVersion: Major.Minor tracks the API version, patch is our counter; next-version
  4.7.11. Static fallback bumped to 4.7.11.
- Rewrite README with accurate usage (the old example referenced a non-existent
  API) + NuGet/build/license badges + the 3-package layout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- build/Build.cs gains Test + Pack targets (DotNet tasks) and a [GitHubActions]
  attribute describing the build lane. CI bootstraps via `dotnet run --project
  build/_build.csproj` (not the `fallout` global tool, which isn't on nuget.org).
- .github/workflows/build.yml: PR/push-to-main → Test + Pack (uploads packages +
  test results). Replaces the old hand-written release.yml + code-coverage.yml.
- .github/workflows/publish.yml: tag `v*` → Pack → NuGet Trusted Publishing (OIDC
  via NuGet/login@v1, no stored key) → push all three packages.
- global.json (SDK pin) + .fallout/parameters.json (Solution) for the build.
- GitVersion: releases cut by tagging v<Major.Minor.patch>; Major.Minor track the
  API version, patch is our counter. GitVersion.MsBuild moved to src props so all
  three packages share one computed version.

Verified locally: `./build.ps1 Pack` → 3 specs pass, 3 consistently-versioned
packages in artifacts/packages.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ChrisonSimtian
ChrisonSimtian merged commit c678487 into main Jul 23, 2026
1 check passed
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