Merge fix/c3-client-versions: CLI-46 client versions bumped past the published train (0.2.1 / Java 0.2.2), pypi 0.2.0 broken-connect() note, check-client-versions.ps1 drift guard in CI

This commit is contained in:
Joseph Doherty
2026-08-20 09:22:48 -04:00
16 changed files with 291 additions and 19 deletions
+14
View File
@@ -23,7 +23,12 @@ jobs:
# tests, the codegen/descriptor freshness guards, and the clients that build on Linux. # tests, the codegen/descriptor freshness guards, and the clients that build on Linux.
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
# fetch-depth: 0 (full history + tags): the CLI-46 client-version-freshness check below
# diffs each client's source against its last publish tag (e.g. clients/go/vX.Y.Z), which
# a shallow, tagless checkout cannot resolve.
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-dotnet@v4 - uses: actions/setup-dotnet@v4
with: with:
@@ -77,6 +82,15 @@ jobs:
shell: pwsh shell: pwsh
run: ./scripts/check-codegen.ps1 run: ./scripts/check-codegen.ps1
# CLI-46: catches a client whose source changed since its last publish
# tag while the version constant still reads that tag's already-shipped
# number — the drift the pack-clients.ps1/tag-go-module.ps1 collision
# guards only catch at actual publish time. Needs tag history, hence
# `fetch-depth: 0` on this job's checkout above.
- name: Client version freshness
shell: pwsh
run: ./scripts/check-client-versions.ps1
- name: Gateway fake-worker tests - name: Gateway fake-worker tests
run: dotnet test src/ZB.MOM.WW.MxGateway.Tests/ZB.MOM.WW.MxGateway.Tests.csproj -c Release --no-build run: dotnet test src/ZB.MOM.WW.MxGateway.Tests/ZB.MOM.WW.MxGateway.Tests.csproj -c Release --no-build
@@ -13,7 +13,7 @@ This plan is executed as **seven parallel batches**, each by one subagent workin
| Batch | Branch | Findings | Model | Why this model | Status | | Batch | Branch | Findings | Model | Why this model | Status |
|---|---|---|---|---|---| |---|---|---|---|---|---|
| A | `fix/c3-client-versions` | CLI-46 | sonnet | Mechanical five-client bump + README note + one script guard; recipe is fully specified | Not started | | A | `fix/c3-client-versions` | CLI-46 | sonnet | Mechanical five-client bump + README note + one script guard; recipe is fully specified | Done |
| B | `fix/c3-glauth-doc` | TST-31 | sonnet | Reconcile a table against one TOML source of truth, re-derive one default, change an assert to a log | Done | | B | `fix/c3-glauth-doc` | TST-31 | sonnet | Reconcile a table against one TOML source of truth, re-derive one default, change an assert to a log | Done |
| C | `fix/c3-tracker-hygiene` | GWC-31 + housekeeping (close GWC-16/IPC-08/IPC-31, refresh TST-06/TST-17, register WRK-31) | sonnet | Cross-file comment/ID sweep needs care about what each ID *means*, but no logic changes | Not started | | C | `fix/c3-tracker-hygiene` | GWC-31 + housekeeping (close GWC-16/IPC-08/IPC-31, refresh TST-06/TST-17, register WRK-31) | sonnet | Cross-file comment/ID sweep needs care about what each ID *means*, but no logic changes | Not started |
| D | `fix/c3-dashboard-acl` | SEC-40, SEC-41, GWC-38 | opus | Authorization semantics, fail-closed decisions, claims re-resolution; each needs a regression test | Not started | | D | `fix/c3-dashboard-acl` | SEC-40, SEC-41, GWC-38 | opus | Authorization semantics, fail-closed decisions, claims re-resolution; each needs a regression test | Not started |
@@ -66,7 +66,6 @@ This plan is executed as **seven parallel batches**, each by one subagent workin
- WRK-32: one `pumpStep()` before capturing the `CurrentVersion` baseline in `MxAccessCommandExecutor.cs`; rewrite the executor doc comment (`:996-1003`) to state the recency-based contract; add the same to `docs/MxAccessWorkerInstanceDesign.md` write-completion section and the reply-field comment in `mxaccess_gateway.proto` (**comment-only proto edit → regenerate all generated artifacts in the same commit**, per the repo rule; if regen tooling is unavailable on macOS, skip the proto comment and say so). - WRK-32: one `pumpStep()` before capturing the `CurrentVersion` baseline in `MxAccessCommandExecutor.cs`; rewrite the executor doc comment (`:996-1003`) to state the recency-based contract; add the same to `docs/MxAccessWorkerInstanceDesign.md` write-completion section and the reply-field comment in `mxaccess_gateway.proto` (**comment-only proto edit → regenerate all generated artifacts in the same commit**, per the repo rule; if regen tooling is unavailable on macOS, skip the proto comment and say so).
- WRK-34 if trivial: `CreateFault(StaHung, "Watchdog", …)` with the correlation id moved into the message. - WRK-34 if trivial: `CreateFault(StaHung, "Watchdog", …)` with the correlation id moved into the message.
- Cannot build on macOS: keep diff minimal, net48-safe (no init-only/positional records). Verified on windev afterwards. - Cannot build on macOS: keep diff minimal, net48-safe (no init-only/positional records). Verified on windev afterwards.
- **Done-pending-windev** (`93edb1b` WRK-33, `20a3eef` WRK-32, `3679e59` WRK-34) on `fix/c3-worker-residuals`. WRK-32 applied `CaptureCompletionBaseline` (pump-then-snapshot) uniformly to all four write call sites (Write/Write2/WriteSecured/WriteSecured2), not just the two the finding cited as evidence, since the correlation gap is identical at all four. **Deferred**: the `mxaccess_gateway.proto` reply-field comment was not edited — a comment-only proto change still requires regenerating every generated artifact (C#, Go, Python, Java, Rust, protoset) per the repo rule, and this macOS box cannot verify all five client generator pins for a Low-severity doc-only change; the contract is documented in `docs/MxAccessWorkerInstanceDesign.md` instead. `NonWindows.slnx` builds clean (0 warnings/errors); worker/Worker.Tests unverified until windev runs `MxAccessCommandExecutorTests`/`WorkerPipeSessionTests`.
### G — GWC-32, GWC-34, GWC-37 (opus) ### G — GWC-32, GWC-34, GWC-37 (opus)
- GWC-32: `DisposeAsync` transitions `_state` to `Closed` under `_syncRoot` before completing channels (or `if (_disposed || IsTerminalState()) return;` in `StageWorkerEvent`); update the XML doc to name all three completion paths. Test: dispose a Ready client mid-dispatch → no `ProtocolViolation` fault/metric. - GWC-32: `DisposeAsync` transitions `_state` to `Closed` under `_syncRoot` before completing channels (or `if (_disposed || IsTerminalState()) return;` in `StageWorkerEvent`); update the XML doc to name all three completion paths. Test: dispose a Ready client mid-dispatch → no `ProtocolViolation` fault/metric.
@@ -19,7 +19,7 @@
<PropertyGroup> <PropertyGroup>
<IsPackable>true</IsPackable> <IsPackable>true</IsPackable>
<PackageId>ZB.MOM.WW.MxGateway.Client</PackageId> <PackageId>ZB.MOM.WW.MxGateway.Client</PackageId>
<Version>0.2.0</Version> <Version>0.2.1</Version>
<Description>.NET 10 gRPC client for the MxAccessGateway service. Provides typed wrappers, retry, and a lazy-browse walker over the Galaxy Repository hierarchy.</Description> <Description>.NET 10 gRPC client for the MxAccessGateway service. Provides typed wrappers, retry, and a lazy-browse walker over the Galaxy Repository hierarchy.</Description>
<PackageReadmeFile>README.md</PackageReadmeFile> <PackageReadmeFile>README.md</PackageReadmeFile>
<!-- Only the shipped library generates XML docs (matching src/Contracts). The Cli and <!-- Only the shipped library generates XML docs (matching src/Contracts). The Cli and
+1 -1
View File
@@ -3,7 +3,7 @@ package mxgateway
const ( const (
// ClientVersion is the released semantic version of this Go client module. // ClientVersion is the released semantic version of this Go client module.
// Keep it in sync with the module tag applied by scripts/tag-go-module.ps1. // Keep it in sync with the module tag applied by scripts/tag-go-module.ps1.
ClientVersion = "0.2.0" ClientVersion = "0.2.1"
// GatewayProtocolVersion matches GatewayContractInfo.GatewayProtocolVersion // GatewayProtocolVersion matches GatewayContractInfo.GatewayProtocolVersion
// in the shared .NET contracts. // in the shared .NET contracts.
+1 -1
View File
@@ -483,7 +483,7 @@ repositories {
} }
dependencies { dependencies {
implementation 'com.zb.mom.ww.mxgateway:zb-mom-ww-mxgateway-client:0.2.1' implementation 'com.zb.mom.ww.mxgateway:zb-mom-ww-mxgateway-client:0.2.2'
} }
```` ````
+7 -4
View File
@@ -16,11 +16,14 @@ subprojects {
// 0.2.0 was already published to the Gitea Maven feed on 2026-06-26, // 0.2.0 was already published to the Gitea Maven feed on 2026-06-26,
// before the CLI-37/38/40/41 conformance fixes changed the client's // before the CLI-37/38/40/41 conformance fixes changed the client's
// observable behavior (status.category-based validation, hresult < 0, // observable behavior (status.category-based validation, hresult < 0,
// exact-secret redaction, typed malformed-reply errors). Bump to 0.2.1 // exact-secret redaction, typed malformed-reply errors). Bumped to 0.2.1
// so the published coordinate matches the conformant behavior the other // so the published coordinate matched the conformant behavior the other
// four clients ship at 0.2.0 for the first time. See CLI-39 and the // four clients shipped at 0.2.0 for the first time. See CLI-39 and the
// "Versioning" section of docs/ClientPackaging.md. // "Versioning" section of docs/ClientPackaging.md.
version = '0.2.1' // 0.2.1 was itself published (Maven, 2026-08-07); this is the next
// release-train bump (CLI-46), one ahead of the other four clients'
// 0.2.1 because the Java coordinate has always trailed by one number.
version = '0.2.2'
pluginManager.withPlugin('java') { pluginManager.withPlugin('java') {
java { java {
@@ -60,7 +60,7 @@ final class MxGatewayCliTests {
assertEquals(0, run.exitCode()); assertEquals(0, run.exitCode());
assertEquals("", run.errors()); assertEquals("", run.errors());
assertTrue(run.output().contains("mxgateway-java 0.2.1")); assertTrue(run.output().contains("mxgateway-java 0.2.2"));
assertTrue(run.output().contains("gatewayProtocolVersion=3")); assertTrue(run.output().contains("gatewayProtocolVersion=3"));
assertTrue(run.output().contains("workerProtocolVersion=1")); assertTrue(run.output().contains("workerProtocolVersion=1"));
} }
@@ -90,7 +90,7 @@ final class MxGatewayCliTests {
CliRun run = execute(new FakeClientFactory(), "version", "--json"); CliRun run = execute(new FakeClientFactory(), "version", "--json");
assertEquals(0, run.exitCode()); assertEquals(0, run.exitCode());
assertTrue(run.output().contains("\"clientVersion\":\"0.2.1\"")); assertTrue(run.output().contains("\"clientVersion\":\"0.2.2\""));
assertTrue(run.output().contains("\"gatewayProtocolVersion\":3")); assertTrue(run.output().contains("\"gatewayProtocolVersion\":3"));
} }
@@ -9,7 +9,7 @@ package com.zb.mom.ww.mxgateway.client;
public final class MxGatewayClientVersion { public final class MxGatewayClientVersion {
private static final int GATEWAY_PROTOCOL_VERSION = 3; private static final int GATEWAY_PROTOCOL_VERSION = 3;
private static final int WORKER_PROTOCOL_VERSION = 1; private static final int WORKER_PROTOCOL_VERSION = 1;
private static final String CLIENT_VERSION = "0.2.1"; private static final String CLIENT_VERSION = "0.2.2";
private MxGatewayClientVersion() { private MxGatewayClientVersion() {
} }
+9
View File
@@ -484,6 +484,15 @@ mxgw-py smoke --endpoint $env:MXGATEWAY_ENDPOINT --plaintext --api-key-env MXGAT
## Installing from the Gitea PyPI Feed ## Installing from the Gitea PyPI Feed
**The published `0.2.0` artifact cannot connect.** Its `connect()` built the
`grpc.aio` channel inside `asyncio.to_thread`, and a `grpc.aio` channel binds
to the event loop current on the *constructing* thread — so every
non-stub connection raised `RuntimeError: There is no current event loop in
thread`. Fixed in-tree by commit `a8f86b5` (`resolve_channel_security` now
runs off-loop, `create_channel` runs on-loop). The fix is superseded by
`0.2.1`; do not install `0.2.0` from the feed below — use `0.2.1` or later,
or install from source at a commit at or after `a8f86b5`.
The client publishes to the internal Gitea PyPI feed: The client publishes to the internal Gitea PyPI feed:
````bash ````bash
+1 -1
View File
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "zb-mom-ww-mxaccess-gateway-client" name = "zb-mom-ww-mxaccess-gateway-client"
version = "0.2.0" version = "0.2.1"
description = "Async Python client for MXAccess Gateway." description = "Async Python client for MXAccess Gateway."
readme = "README.md" readme = "README.md"
requires-python = ">=3.12" requires-python = ">=3.12"
@@ -1,3 +1,3 @@
"""Package version information.""" """Package version information."""
__version__ = "0.2.0" __version__ = "0.2.1"
+2 -2
View File
@@ -590,7 +590,7 @@ checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084"
[[package]] [[package]]
name = "mxgw-cli" name = "mxgw-cli"
version = "0.2.0" version = "0.2.1"
dependencies = [ dependencies = [
"clap", "clap",
"futures-util", "futures-util",
@@ -1490,7 +1490,7 @@ dependencies = [
[[package]] [[package]]
name = "zb-mom-ww-mxgateway-client" name = "zb-mom-ww-mxgateway-client"
version = "0.2.0" version = "0.2.1"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-util", "futures-util",
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "zb-mom-ww-mxgateway-client" name = "zb-mom-ww-mxgateway-client"
version = "0.2.0" version = "0.2.1"
edition = "2021" edition = "2021"
authors = ["Joseph Doherty"] authors = ["Joseph Doherty"]
description = "Async Rust client for the MxAccessGateway gRPC service, including a lazy-browse walker over the Galaxy Repository hierarchy." description = "Async Rust client for the MxAccessGateway gRPC service, including a lazy-browse walker over the Galaxy Repository hierarchy."
@@ -25,7 +25,7 @@ resolver = "2"
[workspace.package] [workspace.package]
edition = "2021" edition = "2021"
version = "0.2.0" version = "0.2.1"
authors = ["Joseph Doherty"] authors = ["Joseph Doherty"]
license = "Proprietary" license = "Proprietary"
repository = "https://gitea.dohertylan.com/dohertj2/mxaccessgw" repository = "https://gitea.dohertylan.com/dohertj2/mxaccessgw"
+37
View File
@@ -72,6 +72,23 @@ 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 `ClientVersion` already equals `X.Y.Z` (CLI-21/CLI-39), so a forgotten
version bump fails the tag instead of shipping a mismatched module. version bump fails the tag instead of shipping a mismatched module.
Both of those guards only fire when someone actually runs a publish.
CLI-46 found the same hazard recurring silently *between* publishes: a
real bug fix (the pypi 0.2.0 `connect()` fix above, commit `a8f86b5`) plus
later wire-surface changes shipped into the tree while every version
constant still read the already-published number, and nothing recorded
that the registry artifact and the in-repo source had diverged.
`scripts/check-client-versions.ps1` is the PR-time half of that guard —
wired into CI (`.gitea/workflows/ci.yml`, the `portable` job, next to the
codegen freshness checks): for each client it finds the latest publish tag
(`clients/go/vX.Y.Z` for Go — the only client with a git tag at all; .NET,
Python, Rust, and Java publish straight to a package registry via
`pack-clients.ps1 -Publish` with no corresponding git tag, so the check
reports "no tags found" and passes for those four today) and fails if
`clients/<lang>` differs from that tag while the version constant still
equals the tag's version. A client with no publish tag is not a
violation — there is no "since the last publish" window to check yet.
As of 2026-08-07 (CLI-39) all five clients — plus `ZB.MOM.WW.MxGateway.Contracts`, 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**, 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 converging on one number after four of the five had drifted onto the
@@ -111,6 +128,26 @@ confirmed present through the Gitea package API after the push, and
`go list -m` resolves the Go tag. These are the numbers a future release `go list -m` resolves the Go tag. These are the numbers a future release
bumps off. bumps off.
**The published pypi `0.2.0` artifact has a broken `connect()` (CLI-46).**
Its `connect()` built the `grpc.aio` channel inside `asyncio.to_thread`, and
a `grpc.aio` channel binds to the event loop current on the *constructing*
thread, so every non-stub connection raised `RuntimeError: There is no
current event loop in thread` — TST-24's first real-wire run caught it.
Fixed in-tree by commit `a8f86b5` (2026-08-10): `resolve_channel_security`
now runs off-loop, `create_channel` runs on-loop. That fix, plus later
wire-surface additions (`d9ea8a8`, `c748361`), shipped after the 2026-08-07
publish while the version constants still read the already-published
0.2.0/0.2.1 numbers above — see `clients/python/README.md` for the
user-facing warning. **0.2.0 is superseded by 0.2.1; do not install it.**
As of this remediation (CLI-46), the in-source version constants for the
.NET, Go, Python, and Rust clients (plus Contracts) read **0.2.1**, and the
Java client reads **0.2.2**. These are not yet published — the numbers
above (0.2.0 four clients + Contracts, 0.2.1 Java) remain the live registry
state until the next `pack-clients.ps1` / `tag-go-module.ps1` run. Once that
publish lands, update this section with the new coordinates and commit(s),
the same way the 2026-08-07 record above was written after the fact.
## .NET ## .NET
The .NET client uses .NET 10 and references The .NET client uses .NET 10 and references
+210
View File
@@ -0,0 +1,210 @@
#!/usr/bin/env pwsh
<#
.SYNOPSIS
Fails a PR that changes a client's source without bumping its version
past the last thing actually published (CLI-46).
.DESCRIPTION
CLI-39 (2026-07-12 cycle) added publish-time guards that refuse to
re-publish an already-published name+version
(scripts/pack-clients.ps1's Assert-GiteaPackageNotPublished,
scripts/tag-go-module.ps1's ClientVersion-vs-tag check). Those guards
only fire when someone actually runs a publish. CLI-46 (2026-08-19
cycle) found the same hazard recurring silently in between publishes:
library source (including a real bug fix, commit a8f86b5) shipped
while the version constant still equalled the already-published
number, so nothing in the tree recorded that the published artifact
and the in-repo source had diverged. This script is the PR-time half
of that guard: catch the drift as soon as it happens, not at the next
publish.
For each client this repo ships, the script:
1. Finds the latest "publish tag" for that client, per the tag
naming convention its own publish tooling actually uses.
2. If no such tag exists, says so and passes (nothing to compare
against yet — this is expected for every client except Go; see
below).
3. If a tag exists, reads the version recorded in-source at that tag
and the version recorded in-source now. If `clients/<lang>` has
changed since the tag AND the version constant is unchanged, that
is exactly the CLI-46 pattern: source moved, the published
coordinate did not, and nothing says so. Fail.
Tag conventions, as implemented today (verified against
scripts/pack-clients.ps1, scripts/tag-go-module.ps1, and `git tag -l`):
- Go is the only client with a git tag at all: `tag-go-module.ps1`
creates `clients/go/vX.Y.Z` (CLI-21/CLI-39 already keep this tag's
version in lockstep with clients/go/mxgateway/version.go's
ClientVersion at *tag time*; this script is what keeps it in
lockstep *between* tags).
- .NET, Python, Rust, and Java publish straight to a package
registry via `pack-clients.ps1 -Publish` (NuGet/PyPI/cargo/Maven
API pushes) with no corresponding git tag of any kind — there is
nothing in this repo's history to diff against for those four.
The script looks for a same-shaped tag anyway
(`clients/<lang>/v*`) so it stays correct if that ever changes,
but today it will report "no tags found" and pass for all four.
A client with no tag is not a violation of anything — it means no
release train has ever tagged that client, so there is no "since the
last publish" window to check. The check exists to catch drift once a
baseline exists, not to demand one.
.EXAMPLE
pwsh scripts/check-client-versions.ps1
#>
[CmdletBinding()]
param()
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
Push-Location $repoRoot
try {
# One entry per official client. `TagGlob` is the tag naming pattern that
# client's own publish tooling uses (see doc comment above); `VersionFile`
# + `VersionPattern` locate the single version-of-record constant
# docs/ClientPackaging.md's "Versioning" section names as authoritative
# for that client; `SourceDir` is the diff scope (matches the literal
# `clients/<lang>` scope described in the CLI-46 remediation task).
$clients = @(
[ordered]@{
Name = 'dotnet'
SourceDir = 'clients/dotnet'
TagGlob = 'clients/dotnet/v*'
VersionFile = 'clients/dotnet/ZB.MOM.WW.MxGateway.Client/ZB.MOM.WW.MxGateway.Client.csproj'
VersionPattern = '<Version>([^<]+)</Version>'
},
[ordered]@{
Name = 'go'
SourceDir = 'clients/go'
TagGlob = 'clients/go/v*'
VersionFile = 'clients/go/mxgateway/version.go'
VersionPattern = 'ClientVersion\s*=\s*"([^"]+)"'
},
[ordered]@{
Name = 'python'
SourceDir = 'clients/python'
TagGlob = 'clients/python/v*'
VersionFile = 'clients/python/src/zb_mom_ww_mxgateway/version.py'
VersionPattern = '__version__\s*=\s*"([^"]+)"'
},
[ordered]@{
Name = 'rust'
SourceDir = 'clients/rust'
TagGlob = 'clients/rust/v*'
VersionFile = 'clients/rust/Cargo.toml'
VersionPattern = 'version\s*=\s*"([^"]+)"'
},
[ordered]@{
Name = 'java'
SourceDir = 'clients/java'
TagGlob = 'clients/java/v*'
VersionFile = 'clients/java/build.gradle'
VersionPattern = "version\s*=\s*'([^']+)'"
}
)
function Get-LatestTag {
param([string]$Glob)
# --sort=-v:refname orders by version-aware descending semver, so the
# first line is the newest tag matching the glob. Empty result means
# no tag of this shape has ever been created for this client.
$tags = git tag -l --sort='-v:refname' $Glob
if (-not $tags) {
return $null
}
return @($tags -split "`n")[0].Trim()
}
function Get-VersionFromFile {
param([string]$Path, [string]$Pattern)
if (-not (Test-Path $Path)) {
throw "Version file not found: $Path"
}
$content = Get-Content -Path $Path -Raw
$match = [regex]::Match($content, $Pattern)
if (-not $match.Success) {
throw "Could not find a version matching /$Pattern/ in $Path"
}
return $match.Groups[1].Value
}
function Get-VersionFromFileAtRevision {
param([string]$Revision, [string]$Path, [string]$Pattern)
$content = git show "${Revision}:${Path}" 2>$null
if ($LASTEXITCODE -ne 0 -or -not $content) {
# The version file did not exist (or was at a different path) at
# that tag. Treat as "unknown" rather than failing the whole
# check — the drift comparison below only needs "does the
# current version still equal the tag's version", and an
# unresolvable historical version can never equal the current
# one, so this degrades to "assume it changed" (safe: it will
# not mask a real drift).
return $null
}
$match = [regex]::Match(($content -join "`n"), $Pattern)
if (-not $match.Success) {
return $null
}
return $match.Groups[1].Value
}
$failures = New-Object System.Collections.Generic.List[string]
foreach ($client in $clients) {
Write-Host ''
Write-Host "== $($client.Name) ==" -ForegroundColor Cyan
$tag = Get-LatestTag -Glob $client.TagGlob
if (-not $tag) {
Write-Host " No publish tags matching '$($client.TagGlob)' — nothing to compare against yet. Pass." -ForegroundColor Yellow
continue
}
Write-Host " Latest publish tag: $tag"
$currentVersion = Get-VersionFromFile -Path $client.VersionFile -Pattern $client.VersionPattern
Write-Host " Current version constant ($($client.VersionFile)): $currentVersion"
# Any diff at all in the client's source tree since its last publish
# tag — matches the CLI-46 remediation task's literal check.
git diff --quiet $tag -- $client.SourceDir
$sourceChanged = ($LASTEXITCODE -ne 0)
if (-not $sourceChanged) {
Write-Host " No changes under $($client.SourceDir) since $tag. Pass." -ForegroundColor Green
continue
}
$tagVersion = Get-VersionFromFileAtRevision -Revision $tag -Path $client.VersionFile -Pattern $client.VersionPattern
Write-Host " Source under $($client.SourceDir) changed since $tag (tag's version constant: $(if ($tagVersion) { $tagVersion } else { '<unresolvable>' }))."
if ($currentVersion -eq $tagVersion) {
$failures.Add("$($client.Name): source changed since publish tag '$tag' but $($client.VersionFile) still reads '$currentVersion' (the version at '$tag'). Bump the version before another publish (CLI-46).")
Write-Host " FAIL: version constant unchanged since the publish tag." -ForegroundColor Red
}
else {
Write-Host " Version constant already bumped ('$tagVersion' -> '$currentVersion') since $tag. Pass." -ForegroundColor Green
}
}
Write-Host ''
if ($failures.Count -gt 0) {
Write-Host 'Client version freshness check FAILED:' -ForegroundColor Red
foreach ($failure in $failures) {
Write-Host " - $failure" -ForegroundColor Red
}
exit 1
}
Write-Host 'Client version freshness check passed.' -ForegroundColor Green
}
finally {
Pop-Location
}
@@ -7,7 +7,7 @@
<PropertyGroup> <PropertyGroup>
<IsPackable>true</IsPackable> <IsPackable>true</IsPackable>
<PackageId>ZB.MOM.WW.MxGateway.Contracts</PackageId> <PackageId>ZB.MOM.WW.MxGateway.Contracts</PackageId>
<Version>0.2.0</Version> <Version>0.2.1</Version>
<Authors>Joseph Doherty</Authors> <Authors>Joseph Doherty</Authors>
<Company>ZB MOM WW</Company> <Company>ZB MOM WW</Company>
<Copyright>Copyright (c) ZB MOM WW. All rights reserved.</Copyright> <Copyright>Copyright (c) ZB MOM WW. All rights reserved.</Copyright>