From 440e7cf03d2e12a236057fb7c438b0c5adc706e5 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Fri, 7 Aug 2026 08:07:40 -0400 Subject: [PATCH] fix(CLI-39): bump Contracts nupkg to 0.2.0; scope pack-clients.ps1 regexes Code review of the CLI-39 branch caught an Important gap: Contracts.csproj was left at the already-published 0.1.2 while the .NET Client moved to 0.2.0. Invoke-PackDotnet in scripts/pack-clients.ps1 packs and publishes both ZB.MOM.WW.MxGateway.Contracts and .Client through the same -Publish loop, and the new collision guard runs every nupkg it finds through Assert-GiteaPackageNotPublished. Left as-is, the next real .NET publish would pack Contracts at 0.1.2, the guard would correctly refuse to republish it, and the loop would abort mid-way with Client (alphabetically first) possibly already pushed -- the two packages permanently out of lockstep. - src/ZB.MOM.WW.MxGateway.Contracts/ZB.MOM.WW.MxGateway.Contracts.csproj: 0.1.2 -> 0.2.0, matching the .NET Client (they have always released together). - src/Directory.Build.props: corrected a comment that was now stale -- it claimed the repo-wide 0.1.2 default was kept to match the Contracts package, which is no longer true now that Contracts.csproj overrides it. The value itself is unchanged; Server/Worker/Tests staying at 0.1.2 is a separate, not-yet-made decision, out of scope for CLI-39. - docs/ClientPackaging.md: Contracts.csproj added as a fifth manifest in the Versioning section, with the near-miss recorded. Also hardened scripts/pack-clients.ps1 per the same review: the Python (pyproject.toml) and Rust (Cargo.toml) version-extraction regexes now scope to the [project]/[package] section header instead of matching the first "version = ..." line anywhere in the file (Cargo.toml has an identical second one under [workspace.package] -- matching whichever came first was luck of ordering, not correctness). One-line comment added on the nuget filename-parse regex. Verified live against the real Gitea registry: Contracts and Client both still refuse at 0.1.2 and both now pass at 0.2.0, including running the actual Invoke-PackDotnet filename-parse-then-guard logic against two freshly packed real .nupkg files. dotnet build of Contracts.csproj and the client slnx both clean. No publish performed. --- .../2026-07-12/remediation/00-tracking.md | 1 + docs/ClientPackaging.md | 34 +++++++++++++++---- scripts/pack-clients.ps1 | 21 ++++++++++-- src/Directory.Build.props | 12 ++++--- .../ZB.MOM.WW.MxGateway.Contracts.csproj | 2 +- 5 files changed, 57 insertions(+), 13 deletions(-) diff --git a/archreview/2026-07-12/remediation/00-tracking.md b/archreview/2026-07-12/remediation/00-tracking.md index 9b1cba4..2ff447c 100644 --- a/archreview/2026-07-12/remediation/00-tracking.md +++ b/archreview/2026-07-12/remediation/00-tracking.md @@ -177,3 +177,4 @@ Sequence these together rather than piecemeal — several are one change set spa | 2026-08-07 | **P1 doc-drift batch → `Done`: TST-27, WRK-26 (discharges IPC-29), CLI-42, CLI-43, IPC-28** (branch `fix/doc-drift-batch`). Doc-only; no source, proto, or test changes — cross-checked against HEAD in this worktree. **TST-27**: `docs/GatewayConfiguration.md`'s `ShowTagValues` row no longer says "Reserved" — it now states what `false` (default) does (`DashboardEventBroadcaster` blanks tag values from a deep-cloned `MxEvent` before the SignalR events-hub mirror, metadata still renders), the security relevance (the per-session hub ACL, SEC-25 roadmap item 12, still does not exist, so this redaction is the only thing between a low-trust Viewer and other sessions' tag values), and the honest scope limit (the flag does **not** cover `/browse`). **WRK-26** (discharges **IPC-29**): `docs/MxAccessWorkerInstanceDesign.md`'s "Outbound Queues" section rewritten from the stale five-level priority list to the two-class `Control`/`Event` scheduler actually shipped (`WorkerFrameWriter`/`WorkerFrameWritePriority.cs`), with the collapsed-decision rationale recorded, and the overflow paragraph rewritten to the implemented fail-fast (`WorkerFault` category `QueueOverflow` → fault frame written → `RunAsync` unwinds → generic `WorkerExitCode.UnexpectedFailure`, dedicated code still open). `docs/WorkerFrameProtocol.md` gained a new "Write Scheduling And Sequencing" section: the two priority classes, enqueue-then-contend/single-lock-holder-drains-all, write-time peek-stamp-commit sequencing, per-frame-rejection vs. stream-failure semantics, and flush coalescing — stated truthfully as landed (WRK-23's peek-stamp-commit is live at HEAD) or not (the drain loop still awaits each event `WriteAsync` individually, so WRK-25's N-events-one-flush batching has **not** landed and the section says so explicitly). Cancellation is deliberately **not** documented as a firm contract — a one-paragraph placeholder notes it is pending WRK-22, which has not landed (confirmed by reading `WorkerFrameWriter.cs`: no `Claimed`/tombstone machinery exists yet). `gateway.md:328-330` was cross-checked and left unchanged — its sequence prose (both sides stamp at write, per GWC-28) already reads true. **CLI-42**: `clients/rust/README.md` and `docs/ClientPackaging.md`'s Rust section now document the vendored proto layout matching `clients/rust/build.rs` exactly — repo-path-first resolution (`../../src/ZB.MOM.WW.MxGateway.Contracts/Protos`) falling back to `clients/rust/protos/` when the canonical path is absent (published-tarball case), the same-commit refresh rule enforced by `scripts/check-codegen.ps1` Check 3, and why `cargo package`/`cargo publish` run without `--no-verify` (matches `scripts/pack-clients.ps1:190-192`). **CLI-43**: `docs/style-guides/JavaStyleGuide.md` line 8 now says "Target Java 17 (the Ignition 8.3 baseline...)" mirroring the CLI-12 wording, matching the shipped `clients/java/build.gradle` toolchain-17 build. **IPC-28**: `docs/Grpc.md`'s exception-mapping prose gained `CommandTooLarge` → `ResourceExhausted` (verified against the live `switch` in `Grpc/MxAccessGatewayService.cs:950-960`), and the `Invoke` section gained one sentence on the oversized-payload path (`WorkerClient.InvokeAsync` rejects at the enqueue boundary per-correlation, session not faulted — verified against `WorkerClient.cs:220-234`), cross-referencing the headroom rule already documented in `docs/GatewayConfiguration.md:120-129`. Did not touch the DrainEvents-truncation row or the proto/`Generated/` trees — those belong to a parallel codegen task per the handoff note. **Source files cross-read for accuracy** (no edits): `src/ZB.MOM.WW.MxGateway.Worker/Ipc/WorkerFrameWriter.cs`, `.../WorkerFrameWritePriority.cs`, `.../WorkerPipeSession.cs` (confirmed two-class scheduler, WRK-21/23/28/30 landed, WRK-25/WRK-22 not landed), `src/ZB.MOM.WW.MxGateway.Worker/WorkerApplication.cs` (exit-code mapping), `src/ZB.MOM.WW.MxGateway.Worker/MxAccess/MxAccessEventQueue.cs` (overflow fault path), `src/ZB.MOM.WW.MxGateway.Server/Dashboard/Hubs/DashboardEventBroadcaster.cs` + `Configuration/DashboardOptions.cs` + `docs/GatewayDashboardDesign.md:170` (ShowTagValues), `src/ZB.MOM.WW.MxGateway.Server/Grpc/MxAccessGatewayService.cs:940-963` + `Workers/WorkerClient.cs:205-244` + `Workers/WorkerClientErrorCode.cs` (CommandTooLarge mapping), `clients/rust/build.rs`, `clients/rust/Cargo.toml`, `scripts/check-codegen.ps1`, `scripts/pack-clients.ps1` (Rust vendoring), `gateway.md:326-360` (sequence-prose cross-check). Verification (greps, doc-only — no build required): `grep -n 'Reserved' docs/GatewayConfiguration.md` no longer matches the `ShowTagValues` row; `grep -n 'faults' docs/MxAccessWorkerInstanceDesign.md` shows no remaining five-level list; `grep -n 'scheduling' docs/WorkerFrameProtocol.md` finds the new section; `grep -rn 'Java 21' docs/style-guides/` empty; `grep -i vendored docs/ClientPackaging.md clients/rust/README.md` non-empty in both; `grep -n 'CommandTooLarge' docs/Grpc.md` shows the mapping. | | 2026-08-07 | **IPC-23 + IPC-24 + IPC-25 + IPC-32 → `Done`; GWC-25 deferred proto-comment resolved** (branch `fix/ipc-24-25-codegen`). The proto-comment/doc + regen wave for the P0 codegen-freshness cluster. **Proto comments (comment-only):** `mxaccess_worker.proto` `GatewayHello.max_frame_bytes` gained the every-frame-must-fit / reply-builders-truncate sentence (IPC-23); `mxaccess_gateway.proto` `DrainEventsReply` gained the count-cap+byte-cap / drain-until-empty comment (IPC-23); `mxaccess_gateway.proto` `ReplayGap.oldest_available_sequence` gained the empty-ring value definition (`highest observed + 1`, `oldest − 1` formula stays valid) resolving GWC-25's deferred amendment. **Regen wave:** `Contracts/Generated/{MxaccessGateway,MxaccessWorker}.cs` (XML-doc only, no descriptor delta), `clients/rust/protos/{mxaccess_gateway,mxaccess_worker}.proto` byte-copied, Go `internal/generated/{mxaccess_gateway,mxaccess_worker}.pb.go` (worker binding was genuinely stale — it lacked the whole `MaxFrameBytes` field/accessor/rawDesc, now refreshed; gateway.pb.go got the new doc comments), Python `generated/mxaccess_worker_pb2.py` (real descriptor delta — `max_frame_bytes` field + cascaded offsets), Java aggregates `MxaccessGateway.java`/`MxaccessWorker.java` (javadoc from the new proto comments — **zero** protobuf-version churn under the pinned toolchain), and the client descriptor set `mxaccessgw-client-v1.protoset`. **IPC-24:** regenerating Java on the pinned toolchain (grpc 1.76.0 / protobuf 4.33.1, Homebrew JDK 17) produced only the legitimate javadoc delta with no `validateProtobufGencodeVersion`/`major=/minor=/patch=` churn — so the preferred path was taken: the unconditional churn-revert step and its comment were **deleted** from `.gitea/workflows/ci.yml` (the `git diff --exit-code` gate is now a true message-level drift gate for the single-file Java aggregates). **IPC-25:** pinned the Go generators in `clients/go/generate-proto.ps1` (`protoc-gen-go` v1.36.11 assert, `protoc-gen-go-grpc` 1.6.2 assert, protoc warn-only; also fixed a latent `(if …)`→`$(if …)` parse bug that broke the script under pwsh 7); added **Check 4** to `scripts/check-codegen.ps1` (regenerate Go+Python bindings, fail on any diff, tool-missing FAILS not skips) and relabeled the banners `1/4`…`4/4` + header comment (**IPC-32** folded in); added the pinned-generator installs to the `portable` CI job before the codegen step. **Docs same commit:** `ClientProtoGeneration.md` (pinned-versions table + Go/Python Check-4 guard + Java-revert-deleted note), `Contracts.md` (four-check enumeration), `GatewayTesting.md` (java job + four-check prose), `clients/java/zb-mom-ww-mxgateway-client/build.gradle` checkGeneratedClean caveat. **IPC-23 DrainEvents-truncation doc deviation:** `docs/Grpc.md` has no DrainEvents row (it documents only the seven public RPCs; DrainEvents is a worker diagnostic), and `docs/WorkerFrameProtocol.md` (owned by the parallel doc batch) already carries the byte-cap/drain-until-empty prose via WRK-21 — so no Grpc.md edit was made. **Evidence (macOS):** `pwsh scripts/check-codegen.ps1` all four checks green (banners `1/4`…`4/4`); `dotnet build …NonWindows.slnx` 0 warnings/0 errors; `dotnet test …Tests --filter ~ClientProtoInputTests` green; `grep -c max_frame_bytes` → Go worker 2, Python worker 1 (both non-zero, were 0); `clients/go` gofmt clean + `go build` + `go test` ok; `clients/python` `pytest` 163 passed/1 skipped; Java `gradle generateProto` clean under JDK 17. **Negative-path proof:** added a scratch field to `mxaccess_worker.proto`, regenerated only `Contracts/Generated/`, reran `check-codegen.ps1` and confirmed **Check 4 fails naming both `clients/go/internal/generated` and `clients/python/…/generated`**, then reverted. **Not published** (CLI-39 gates Go/Python republish). | | 2026-08-07 | **CLI-39 → `Done`** (branch `fix/cli-39-version-train`). The last client task in the P1 release train — lands after CLI-35/36/37/38/40/41/44/45 so the next publish carries the conformant behavior, not the pre-remediation API. Bumped all five client version constants off the already-published 0.1.2: Rust `Cargo.toml` `[package]` + `[workspace.package]` → 0.2.0 (`crates/mxgw-cli` inherits via `version.workspace = true`; `CLIENT_VERSION` already derived via `env!("CARGO_PKG_VERSION")` from CLI-29, no separate edit needed); Python `pyproject.toml` + `version.py` → 0.2.0, plus a new `test_version_matches_pyproject_toml` (`clients/python/tests/test_cli.py`) that parses `pyproject.toml` with `tomllib` and asserts `__version__` matches it — closes the CLI-26 residual (the old test only checked self-consistency against `__version__`, so the two literals could still drift from each other undetected); Go `mxgateway/version.go` `ClientVersion` → 0.2.0; .NET `ZB.MOM.WW.MxGateway.Client.csproj` `` → 0.2.0. **Java is the one exception, landed at 0.2.1, not 0.2.0**: queried the live Gitea package API (`GET /api/v1/packages/dohertj2/maven/com.zb.mom.ww.mxgateway:zb-mom-ww-mxgateway-client/0.2.0` — reachable and credentialed in this environment) and confirmed Java 0.2.0 was already published on 2026-06-26, before the CLI-37/38/40/41 conformance fixes changed the client's observable behavior; reusing 0.2.0 for the now-conformant build would have labeled two different APIs identically, so `build.gradle`'s `subprojects { version = '0.2.1' }`, the hand-maintained `MxGatewayClientVersion.CLIENT_VERSION` constant, and the two `MxGatewayCliTests` version assertions all moved to 0.2.1 together (`clients/java/README.md`'s Maven dependency example updated to match — it had drifted to a stale `0.1.2` example). Confirmed via the same live API that Python (`pypi`) and Rust (`cargo`) had only ever reached 0.1.1 in the registry (0.1.2 was set in source but never actually published), while `nuget` (`ZB.MOM.WW.MxGateway.Client`/`.Contracts`) reached 0.1.2 — recorded as historical context in the new "Versioning" section of `docs/ClientPackaging.md` rather than left implicit. **Publish-pipeline guards:** `scripts/tag-go-module.ps1` gained the CLI-21 guard that was designed but never implemented — after semver validation it now reads `clients/go/mxgateway/version.go`'s `ClientVersion` and throws if it does not equal the requested tag version (stripped of `v`), before touching git. `scripts/pack-clients.ps1` gained a Gitea package-registry collision guard (`Test-GiteaPackageExists`/`Assert-GiteaPackageNotPublished`, hitting the documented `GET /api/v1/packages/{owner}/{type}/{name}/{version}` package API) wired into all four artifact-producing `-Publish` blocks (.NET nupkg identity parsed from the packed filename so both `Client` and `Contracts` are covered; Python from `pyproject.toml`; Rust from `Cargo.toml`; Java from `build.gradle`'s `group`+`version`, **required for a real check** since Gitea's Maven package identity is `groupId:artifactId`, not the bare artifact id — an early version of this guard used the bare id and would have silently never matched anything, caught by testing it live against the known-published 0.2.0 before landing); Go is unaffected (no artifact producer in this script; the version-match guard above is its collision protection). Every non-404 registry response (including a plain 401 from an unauthenticated call) is treated as "cannot verify" and aborts — the guard fails closed, never proceeds on ambiguity. **No `.proto` changes; no publish performed.** Docs same commit: `docs/ClientPackaging.md` gained a "Versioning" section (single-source-of-truth list per client, the bump-before-publish rule, the Java exception with evidence); `clients/dotnet/README.md`, `clients/rust/README.md`, `clients/go/README.md` (install example + `tag-go-module.ps1` example + guard behavior sentence), `clients/java/README.md` had their stale `0.1.1`/`0.1.2` example version strings updated to the new released numbers. **Verification** (macOS, all four non-Java languages against the live tree): `cargo check --workspace` clean (`zb-mom-ww-mxgateway-client v0.2.0`, `mxgw-cli v0.2.0`), `cargo test --workspace` version tests pass (`version_json_output_has_protocol_versions`); `python -m pytest` 164 passed / 1 skipped (was 163; the one new test); Go `gofmt -l .` clean, `go build ./...` clean, `go test ./...` ok; `dotnet build clients/dotnet/ZB.MOM.WW.MxGateway.Client.slnx` 0 warnings/0 errors, client tests 128 passed / 1 skipped (unchanged). `JAVA_HOME=/opt/homebrew/opt/openjdk@17 gradle test` BUILD SUCCESSFUL, CLI suite 51/51 passed including both version-string assertions now at `0.2.1`, **no generated-tree churn** to revert (no `.proto` changed). Script guards: `pwsh -NoProfile` dry-run of `tag-go-module.ps1` — mismatched version (`v1.2.3`) failed with the new guard message before touching git; matched version (`v0.2.0`) passed the guard and reached the pre-existing dirty-working-tree check (expected, uncommitted changes present) — proves the new check runs first and does not block a correct version. `pack-clients.ps1`'s guard functions were exercised directly (dot-sourced in isolation, no pack/publish side effects) against the **live** Gitea registry with real credentials already present in this environment (`GITEA_USERNAME`/`GITEA_TOKEN` from `~/.zshenv`): correctly refused on every known-published artifact (nuget Client 0.1.2, maven 0.2.0, pypi 0.1.1, cargo 0.1.1) and correctly passed on every unpublished target version (0.2.0/0.2.1 across all four). **No actual publish was attempted or performed** — the task explicitly forbids it, and the sandbox additionally refuses any Bash command that inlines `$GITEA_TOKEN`/`$GITEA_USERNAME` into the command text (a credential-use guard, not a git-safety one), so the live checks above ran only by having the script's own functions read the already-exported env vars internally rather than the invoking command line referencing them. | +| 2026-08-07 | Code-review follow-up on the same branch (`fix/cli-39-version-train`). **Important gap fixed:** `src/ZB.MOM.WW.MxGateway.Contracts/ZB.MOM.WW.MxGateway.Contracts.csproj` was left at `0.1.2` — the original CLI-39 pass bumped the .NET Client but missed that `Invoke-PackDotnet` in `scripts/pack-clients.ps1` packs and publishes **both** `ZB.MOM.WW.MxGateway.Contracts` and `.Client` through the same `-Publish` loop, and the new collision guard runs every `ZB.MOM.WW.MxGateway.*.nupkg` it finds through `Assert-GiteaPackageNotPublished`. Left as-is, the next real `.NET` publish would have packed Contracts at the already-published 0.1.2, the guard would have correctly refused it, and the bare `ForEach-Object` would have aborted mid-loop — with `Client` (0.2.0, alphabetically first) potentially already pushed and `Contracts` stuck at 0.1.2, the two published nupkgs out of lockstep. Fixed: bumped `Contracts.csproj` to `0.2.0` alongside the Client (they have always released together). Also updated the now-stale comment in `src/Directory.Build.props` (it previously said the repo-wide `0.1.2` default was "kept ... to match the Contracts package"; that's no longer true now that Contracts overrides it — the comment now explains the override and that Server/Worker/Tests staying at `0.1.2` is a separate, not-yet-made decision; the `Directory.Build.props` `` value itself was **not** changed, since Server/Worker are not published packages and were out of scope for CLI-39). `docs/ClientPackaging.md`'s "Versioning" section gained `Contracts.csproj` as a fifth manifest (explaining why it must move with the .NET Client) and a note on the near-miss. **Cheap hardening also applied:** the Python (`pyproject.toml`) and Rust (`Cargo.toml`) version-extraction regexes in `pack-clients.ps1` now scope to the `[project]`/`[package]` section header respectively (matching the first `version = "..."` line anywhere in the file was luck of ordering — Cargo.toml has an identical second one under `[workspace.package]`), plus a one-line comment on the nuget filename-parse regex explaining the lazy-id/anchored-version split. **Verification:** `dotnet build src/ZB.MOM.WW.MxGateway.Contracts/ZB.MOM.WW.MxGateway.Contracts.csproj` 0 warnings/0 errors; `dotnet pack` of that project confirmed the artifact is literally named `ZB.MOM.WW.MxGateway.Contracts.0.2.0.nupkg`; `dotnet build clients/dotnet/ZB.MOM.WW.MxGateway.Client.slnx` still 0 warnings/0 errors. Re-ran the pack-clients.ps1 guard function-harness live against the real Gitea registry: `ZB.MOM.WW.MxGateway.Contracts`/`.Client` **0.1.2 both still refused**, **0.2.0 both now pass** — then went one step further and packed both projects for real (`dotnet pack`, no `-Publish`) and ran the exact `Invoke-PackDotnet` filename-parse-then-guard logic against the two real `.nupkg` files, confirming both parse to `id`/`version` correctly and both clear the live collision check. The scoped Python/Rust regexes were also exercised live against the real `pyproject.toml`/`Cargo.toml` and still resolve to `0.2.0`. No publish performed. | diff --git a/docs/ClientPackaging.md b/docs/ClientPackaging.md index 66c029b..f4f6af6 100644 --- a/docs/ClientPackaging.md +++ b/docs/ClientPackaging.md @@ -45,6 +45,21 @@ mirrored by the hand-maintained `MxGatewayClientVersion.CLIENT_VERSION` constant — the two have drifted before and there is no build-time link between them, so bump both together). +`src/ZB.MOM.WW.MxGateway.Contracts/ZB.MOM.WW.MxGateway.Contracts.csproj` +(``) is a fifth, easy-to-miss manifest: it is not itself a +language client, but `Invoke-PackDotnet` in `scripts/pack-clients.ps1` +packs and publishes it in lockstep with the .NET Client (both +`ZB.MOM.WW.MxGateway.*` nupkgs go through the same `-Publish` loop), and +Contracts and the .NET Client have always released at the same version. +Bump Contracts' `` alongside the .NET Client's — leaving it behind +means the next `-Publish` packs a stale Contracts version, the collision +guard below correctly refuses to re-publish it, and the loop aborts +mid-way with the Client possibly already pushed (nupkgs are enumerated +alphabetically, and `Client` sorts before `Contracts`). This is distinct +from `src/Directory.Build.props`'s repo-wide `` default, which +stamps the Server/Worker/test assemblies and is not part of the published +client package set — see the comment there. + **Bump the version before every publish, never after.** A Gitea package feed rejects re-uploading an existing name+version, and `scripts/pack-clients.ps1` enforces this before it ever attempts a push: each per-language `-Publish` @@ -57,12 +72,19 @@ carries the equivalent guard for the Go module: it refuses to create a `ClientVersion` already equals `X.Y.Z` (CLI-21/CLI-39), so a forgotten version bump fails the tag instead of shipping a mismatched module. -As of 2026-08-07 (CLI-39) all five clients moved to **0.2.0**, converging on -one number after four of the five had drifted onto the *already-published* -0.1.2/0.1.1 while their public APIs kept changing underneath it (see -`archreview/2026-07-12/remediation/50-clients.md` CLI-39). Verified against -the live Gitea package API at that time: `nuget` had `ZB.MOM.WW.MxGateway.Client` -and `.Contracts` published through 0.1.2; `pypi` (`zb-mom-ww-mxaccess-gateway-client`) +As of 2026-08-07 (CLI-39) all five clients — plus `ZB.MOM.WW.MxGateway.Contracts`, +which releases in lockstep with the .NET Client — moved to **0.2.0**, +converging on one number after four of the five had drifted onto the +*already-published* 0.1.2/0.1.1 while their public APIs kept changing +underneath it (see `archreview/2026-07-12/remediation/50-clients.md` CLI-39). +A code-review follow-up on the same branch caught that the initial CLI-39 +pass bumped the .NET Client but left `Contracts.csproj` at 0.1.2 — since +both publish through the same `Invoke-PackDotnet` `-Publish` loop, that +would have made the very next `.NET` publish abort on the new collision +guard partway through (Client already pushed, Contracts refused as a +re-publish of the already-published 0.1.2). Fixed in the same branch. +Verified against the live Gitea package API at that time: `nuget` had +`ZB.MOM.WW.MxGateway.Client` and `.Contracts` published through 0.1.2; `pypi` (`zb-mom-ww-mxaccess-gateway-client`) and `cargo` (`zb-mom-ww-mxgateway-client`) had only reached 0.1.1 despite their source pinning 0.1.2; **`maven` (`com.zb.mom.ww.mxgateway:zb-mom-ww-mxgateway-client`) had already published diff --git a/scripts/pack-clients.ps1 b/scripts/pack-clients.ps1 index 63794df..87990a2 100644 --- a/scripts/pack-clients.ps1 +++ b/scripts/pack-clients.ps1 @@ -185,6 +185,9 @@ function Invoke-PackDotnet { if ($Publish) { Write-Host 'Publishing .NET packages to Gitea...' -ForegroundColor Yellow Get-ChildItem $OutputDir -Filter 'ZB.MOM.WW.MxGateway.*.nupkg' | ForEach-Object { + # nupkg filenames are '..nupkg'; the id itself contains + # dots (e.g. 'ZB.MOM.WW.MxGateway.Client'), so the id capture is lazy and the + # version capture anchors on the leading digit to split at the right dot. $fileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($_.Name) if ($fileBaseName -notmatch '^(?.+?)\.(?\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)$') { throw "Could not parse a NuGet package id/version out of '$($_.Name)'." @@ -231,7 +234,14 @@ function Invoke-PackPython { if ($Publish) { $pyprojectPath = Join-Path $RepoRoot 'clients/python/pyproject.toml' $pyprojectContent = Get-Content $pyprojectPath -Raw - if ($pyprojectContent -notmatch '(?m)^\s*version\s*=\s*"([^"]+)"') { + # Scope to the [project] section (not just the first "version = ..." line + # in the file) — [build-system]/[tool.*] sections can carry their own + # version-shaped keys, and matching the file's first hit would be luck + # of ordering, not correctness. + if ($pyprojectContent -notmatch '(?ms)^\[project\](?
.*?)(?=^\[|\z)') { + throw "Could not find a [project] section in '$pyprojectPath'." + } + if ($Matches.section -notmatch '(?m)^\s*version\s*=\s*"([^"]+)"') { throw "Could not find [project].version in '$pyprojectPath'." } Assert-GiteaPackageNotPublished -Type 'pypi' -Name 'zb-mom-ww-mxaccess-gateway-client' -Version $Matches[1] @@ -285,7 +295,14 @@ function Invoke-PackRust { if ($Publish) { $cargoTomlPath = Join-Path $rustDir 'Cargo.toml' $cargoTomlContent = Get-Content $cargoTomlPath -Raw - if ($cargoTomlContent -notmatch '(?m)^\s*version\s*=\s*"([^"]+)"') { + # Scope to the [package] section specifically — Cargo.toml also carries a + # [workspace.package] section with its own "version = ..." line (today + # identical, by convention, not by anything this regex can rely on), and + # matching whichever comes first in the file is luck of ordering. + if ($cargoTomlContent -notmatch '(?ms)^\[package\](?
.*?)(?=^\[|\z)') { + throw "Could not find a [package] section in '$cargoTomlPath'." + } + if ($Matches.section -notmatch '(?m)^\s*version\s*=\s*"([^"]+)"') { throw "Could not find [package] version in '$cargoTomlPath'." } Assert-GiteaPackageNotPublished -Type 'cargo' -Name 'zb-mom-ww-mxgateway-client' -Version $Matches[1] diff --git a/src/Directory.Build.props b/src/Directory.Build.props index dedc388..d390d73 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -11,10 +11,14 @@ + to a release). Server/Worker/Tests stay at this default. CLI-39 (2026-08-07) moved the + published `ZB.MOM.WW.MxGateway.Contracts` and `.Client` nuget packages to 0.2.0 via an + explicit override in Contracts.csproj (MSBuild property-last-write-wins over + this Directory.Build.props default) — Server/Worker assembly stamping and the published + client packages are deliberately decoupled; a broader 0.2.0 alignment for Server/Worker + is a separate, not-yet-made decision. The git short SHA is appended to + InformationalVersion (0.1.2+) so support can map a running binary to a commit; the + query is guarded so a build outside a git checkout still succeeds. --> 0.1.2 diff --git a/src/ZB.MOM.WW.MxGateway.Contracts/ZB.MOM.WW.MxGateway.Contracts.csproj b/src/ZB.MOM.WW.MxGateway.Contracts/ZB.MOM.WW.MxGateway.Contracts.csproj index 8cfb3fe..c51323b 100644 --- a/src/ZB.MOM.WW.MxGateway.Contracts/ZB.MOM.WW.MxGateway.Contracts.csproj +++ b/src/ZB.MOM.WW.MxGateway.Contracts/ZB.MOM.WW.MxGateway.Contracts.csproj @@ -7,7 +7,7 @@ true ZB.MOM.WW.MxGateway.Contracts - 0.1.2 + 0.2.0 Joseph Doherty ZB MOM WW Copyright (c) ZB MOM WW. All rights reserved.