Merge branch 'fix/cli-39-version-train'
# Conflicts: # archreview/2026-07-12/remediation/00-tracking.md
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -20,7 +20,7 @@ Operating constraints carried from prior work:
|
|||||||
| CLI-36 | Medium | P0 | S | — | Done | Go CLI `stream-events` silently destroys the ReplayGap signal |
|
| CLI-36 | Medium | P0 | S | — | Done | Go CLI `stream-events` silently destroys the ReplayGap signal |
|
||||||
| CLI-37 | Medium | P1 | M | CLI-38 | Done | Status-array validation must branch on `category` per the proto contract (4-vs-1 divergence) |
|
| CLI-37 | Medium | P1 | M | CLI-38 | Done | Status-array validation must branch on `category` per the proto contract (4-vs-1 divergence) |
|
||||||
| CLI-38 | Medium | P1 | S | — | Done | Align .NET/Go/Java on `hresult < 0` — lands prior CLI-08 and cures the design-doc drift |
|
| CLI-38 | Medium | P1 | S | — | Done | Align .NET/Go/Java on `hresult < 0` — lands prior CLI-08 and cures the design-doc drift |
|
||||||
| CLI-39 | Medium | P1 | S | CLI-35..38, CLI-45 | Not started | Bump client versions off the already-published 0.1.2 before the next publish; add registry-collision guard |
|
| CLI-39 | Medium | P1 | S | CLI-35..38, CLI-45 | Done | Bump client versions off the already-published 0.1.2 before the next publish; add registry-collision guard |
|
||||||
| CLI-40 | Low | — | M | — | Done | Port the exact-secret credential scrub to Rust/Java/.NET |
|
| CLI-40 | Low | — | M | — | Done | Port the exact-secret credential scrub to Rust/Java/.NET |
|
||||||
| CLI-41 | Low | — | M | — | Done | Uniform malformed-reply contract for AuthenticateUser/ArchestrAUserToId/AddBufferedItem |
|
| CLI-41 | Low | — | M | — | Done | Uniform malformed-reply contract for AuthenticateUser/ArchestrAUserToId/AddBufferedItem |
|
||||||
| CLI-42 | Low | P1 | S | — | Done | Document the vendored Rust proto layout (CLI-02's missing doc half) |
|
| CLI-42 | Low | P1 | S | — | Done | Document the vendored Rust proto layout (CLI-02's missing doc half) |
|
||||||
|
|||||||
@@ -487,7 +487,7 @@ dotnet nuget add source https://gitea.dohertylan.com/api/packages/dohertj2/nuget
|
|||||||
Then add the package to your project:
|
Then add the package to your project:
|
||||||
|
|
||||||
````bash
|
````bash
|
||||||
dotnet add package ZB.MOM.WW.MxGateway.Client --version 0.1.1
|
dotnet add package ZB.MOM.WW.MxGateway.Client --version 0.2.0
|
||||||
````
|
````
|
||||||
|
|
||||||
The `ZB.MOM.WW.MxGateway.Contracts` package is pulled in transitively.
|
The `ZB.MOM.WW.MxGateway.Contracts` package is pulled in transitively.
|
||||||
|
|||||||
@@ -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.1.2</Version>
|
<Version>0.2.0</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
|
||||||
|
|||||||
@@ -471,7 +471,7 @@ go run ./cmd/mxgw-go smoke -endpoint $env:MXGATEWAY_ENDPOINT -plaintext -api-key
|
|||||||
The module is resolved directly from the git repo — no package registry:
|
The module is resolved directly from the git repo — no package registry:
|
||||||
|
|
||||||
````bash
|
````bash
|
||||||
go get gitea.dohertylan.com/dohertj2/mxaccessgw/clients/go@v0.1.1
|
go get gitea.dohertylan.com/dohertj2/mxaccessgw/clients/go@v0.2.0
|
||||||
````
|
````
|
||||||
|
|
||||||
Then import:
|
Then import:
|
||||||
@@ -494,11 +494,13 @@ Go modules in monorepo subdirectories use prefixed tags. To tag a release
|
|||||||
from this repo:
|
from this repo:
|
||||||
|
|
||||||
````bash
|
````bash
|
||||||
pwsh scripts/tag-go-module.ps1 -Version v0.1.1 -Push
|
pwsh scripts/tag-go-module.ps1 -Version v0.2.0 -Push
|
||||||
````
|
````
|
||||||
|
|
||||||
The script validates semver, refuses to tag with uncommitted tracked
|
The script validates semver, refuses to tag with uncommitted tracked
|
||||||
changes, creates an annotated tag `clients/go/v0.1.1`, and (with `-Push`)
|
changes, verifies `clients/go/mxgateway/version.go`'s `ClientVersion`
|
||||||
|
matches the requested tag version (failing the tag otherwise — CLI-21/CLI-39),
|
||||||
|
creates an annotated tag `clients/go/v0.2.0`, and (with `-Push`)
|
||||||
pushes it to origin.
|
pushes it to origin.
|
||||||
|
|
||||||
## Related Documentation
|
## Related Documentation
|
||||||
|
|||||||
@@ -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.1.2"
|
ClientVersion = "0.2.0"
|
||||||
|
|
||||||
// GatewayProtocolVersion matches GatewayContractInfo.GatewayProtocolVersion
|
// GatewayProtocolVersion matches GatewayContractInfo.GatewayProtocolVersion
|
||||||
// in the shared .NET contracts.
|
// in the shared .NET contracts.
|
||||||
|
|||||||
@@ -465,7 +465,7 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.zb.mom.ww.mxgateway:zb-mom-ww-mxgateway-client:0.1.2'
|
implementation 'com.zb.mom.ww.mxgateway:zb-mom-ww-mxgateway-client:0.2.1'
|
||||||
}
|
}
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,14 @@ ext {
|
|||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
group = 'com.zb.mom.ww.mxgateway'
|
group = 'com.zb.mom.ww.mxgateway'
|
||||||
version = '0.2.0'
|
// 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
|
||||||
|
// observable behavior (status.category-based validation, hresult < 0,
|
||||||
|
// exact-secret redaction, typed malformed-reply errors). Bump to 0.2.1
|
||||||
|
// so the published coordinate matches the conformant behavior the other
|
||||||
|
// four clients ship at 0.2.0 for the first time. See CLI-39 and the
|
||||||
|
// "Versioning" section of docs/ClientPackaging.md.
|
||||||
|
version = '0.2.1'
|
||||||
|
|
||||||
pluginManager.withPlugin('java') {
|
pluginManager.withPlugin('java') {
|
||||||
java {
|
java {
|
||||||
|
|||||||
+2
-2
@@ -59,7 +59,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.0"));
|
assertTrue(run.output().contains("mxgateway-java 0.2.1"));
|
||||||
assertTrue(run.output().contains("gatewayProtocolVersion=3"));
|
assertTrue(run.output().contains("gatewayProtocolVersion=3"));
|
||||||
assertTrue(run.output().contains("workerProtocolVersion=1"));
|
assertTrue(run.output().contains("workerProtocolVersion=1"));
|
||||||
}
|
}
|
||||||
@@ -89,7 +89,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.0\""));
|
assertTrue(run.output().contains("\"clientVersion\":\"0.2.1\""));
|
||||||
assertTrue(run.output().contains("\"gatewayProtocolVersion\":3"));
|
assertTrue(run.output().contains("\"gatewayProtocolVersion\":3"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -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.0";
|
private static final String CLIENT_VERSION = "0.2.1";
|
||||||
|
|
||||||
private MxGatewayClientVersion() {
|
private MxGatewayClientVersion() {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.1.2"
|
version = "0.2.0"
|
||||||
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.1.2"
|
__version__ = "0.2.0"
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
"""Tests for the Python CLI."""
|
"""Tests for the Python CLI."""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import tomllib
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from click.testing import CliRunner
|
from click.testing import CliRunner
|
||||||
@@ -12,6 +14,21 @@ from zb_mom_ww_mxgateway_cli.commands import main
|
|||||||
_BATCH_EOR = "__MXGW_BATCH_EOR__"
|
_BATCH_EOR = "__MXGW_BATCH_EOR__"
|
||||||
|
|
||||||
|
|
||||||
|
def test_version_matches_pyproject_toml() -> None:
|
||||||
|
"""`__version__` must track `pyproject.toml`'s `[project].version`.
|
||||||
|
|
||||||
|
The existing `version` command tests only assert self-consistency against
|
||||||
|
`__version__` (the two hardcoded literals could still drift from each
|
||||||
|
other without either test catching it — the CLI-26 residual drift mode).
|
||||||
|
This test pins `__version__` to the single source of truth instead.
|
||||||
|
"""
|
||||||
|
pyproject_path = Path(__file__).resolve().parent.parent / "pyproject.toml"
|
||||||
|
with pyproject_path.open("rb") as handle:
|
||||||
|
pyproject = tomllib.load(handle)
|
||||||
|
|
||||||
|
assert __version__ == pyproject["project"]["version"]
|
||||||
|
|
||||||
|
|
||||||
def test_require_certificate_validation_flag_flows_through_connect(
|
def test_require_certificate_validation_flag_flows_through_connect(
|
||||||
monkeypatch: pytest.MonkeyPatch,
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|||||||
Generated
+2
-2
@@ -590,7 +590,7 @@ checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mxgw-cli"
|
name = "mxgw-cli"
|
||||||
version = "0.1.2"
|
version = "0.2.0"
|
||||||
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.1.2"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "zb-mom-ww-mxgateway-client"
|
name = "zb-mom-ww-mxgateway-client"
|
||||||
version = "0.1.2"
|
version = "0.2.0"
|
||||||
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.1.2"
|
version = "0.2.0"
|
||||||
authors = ["Joseph Doherty"]
|
authors = ["Joseph Doherty"]
|
||||||
license = "Proprietary"
|
license = "Proprietary"
|
||||||
repository = "https://gitea.dohertylan.com/dohertj2/mxaccessgw"
|
repository = "https://gitea.dohertylan.com/dohertj2/mxaccessgw"
|
||||||
|
|||||||
@@ -436,5 +436,5 @@ Then add the dependency:
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
zb-mom-ww-mxgateway-client = { version = "0.1.1", registry = "dohertj2-gitea" }
|
zb-mom-ww-mxgateway-client = { version = "0.2.0", registry = "dohertj2-gitea" }
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -32,6 +32,73 @@ $env:MXGATEWAY_TEST_ITEM = 'TestObject.TestInt'
|
|||||||
Use plaintext only for a local gateway. Use TLS when the gateway crosses a
|
Use plaintext only for a local gateway. Use TLS when the gateway crosses a
|
||||||
machine boundary or uses a production certificate.
|
machine boundary or uses a production certificate.
|
||||||
|
|
||||||
|
## Versioning
|
||||||
|
|
||||||
|
Every client's version lives in its own manifest: `clients/rust/Cargo.toml`
|
||||||
|
(`[package]` and `[workspace.package]`, both must match — `crates/mxgw-cli`
|
||||||
|
inherits via `version.workspace = true`), `clients/python/pyproject.toml`
|
||||||
|
(`[project].version`) and `clients/python/src/zb_mom_ww_mxgateway/version.py`
|
||||||
|
(`__version__`, must match `pyproject.toml`), `clients/go/mxgateway/version.go`
|
||||||
|
(`ClientVersion`), `clients/dotnet/ZB.MOM.WW.MxGateway.Client/ZB.MOM.WW.MxGateway.Client.csproj`
|
||||||
|
(`<Version>`), and `clients/java/build.gradle` (`subprojects { version = ... }`,
|
||||||
|
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`
|
||||||
|
(`<Version>`) 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' `<Version>` 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 `<Version>` 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`
|
||||||
|
step queries the Gitea package API
|
||||||
|
(`GET /api/v1/packages/dohertj2/{type}/{name}/{version}`) for the version
|
||||||
|
about to be published and aborts with a clear error if it already exists —
|
||||||
|
the script never force-overwrites a published artifact. `scripts/tag-go-module.ps1`
|
||||||
|
carries the equivalent guard for the Go module: it refuses to create a
|
||||||
|
`clients/go/vX.Y.Z` tag unless `clients/go/mxgateway/version.go`'s
|
||||||
|
`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 — 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
|
||||||
|
0.2.0 on 2026-06-26** — before the CLI-37/38/40/41 conformance fixes changed
|
||||||
|
the client's observable behavior (`category`-based status validation,
|
||||||
|
`hresult < 0`, exact-secret redaction, typed malformed-reply errors). Reusing
|
||||||
|
0.2.0 for the conformant Java build would have labeled two different APIs
|
||||||
|
with the same coordinate, so **Java is the one exception: it shipped as
|
||||||
|
0.2.1**, not 0.2.0. Operators publishing a future release must re-check the
|
||||||
|
target version against the live registry before assuming any of these
|
||||||
|
numbers are still unclaimed — the guards above do this automatically at
|
||||||
|
publish time, but a version bump in the source is still a manual step per
|
||||||
|
client.
|
||||||
|
|
||||||
## .NET
|
## .NET
|
||||||
|
|
||||||
The .NET client uses .NET 10 and references
|
The .NET client uses .NET 10 and references
|
||||||
|
|||||||
@@ -87,6 +87,12 @@ $GiteaNugetFeed = 'https://gitea.dohertylan.com/api/packages/dohertj2/nuget/inde
|
|||||||
$GiteaPypiFeed = 'https://gitea.dohertylan.com/api/packages/dohertj2/pypi'
|
$GiteaPypiFeed = 'https://gitea.dohertylan.com/api/packages/dohertj2/pypi'
|
||||||
$JavaHome = '/Users/dohertj2/.local/jdks/jdk-21.0.11+10/Contents/Home'
|
$JavaHome = '/Users/dohertj2/.local/jdks/jdk-21.0.11+10/Contents/Home'
|
||||||
|
|
||||||
|
# Generic Gitea package registry API (https://gitea.dohertylan.com/api/v1/packages/{owner}/{type}/{name}/{version}):
|
||||||
|
# returns 200 when that exact name+version already exists in the given feed
|
||||||
|
# type, 404 when it does not. Used as a pre-publish collision guard (CLI-39)
|
||||||
|
# so a re-run of this script can never silently overwrite a published artifact.
|
||||||
|
$GiteaPackageApiBase = 'https://gitea.dohertylan.com/api/v1/packages/dohertj2'
|
||||||
|
|
||||||
function Write-Header {
|
function Write-Header {
|
||||||
param([string]$Text)
|
param([string]$Text)
|
||||||
Write-Host ''
|
Write-Host ''
|
||||||
@@ -94,6 +100,64 @@ function Write-Header {
|
|||||||
Write-Host $Text -ForegroundColor Cyan
|
Write-Host $Text -ForegroundColor Cyan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Test-GiteaPackageExists {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Queries the Gitea package API for an existing name+version in a feed.
|
||||||
|
.OUTPUTS
|
||||||
|
$true if the package/version already exists, $false if it does not.
|
||||||
|
Throws if the registry cannot be reached or returns anything other
|
||||||
|
than 200/404 — callers must treat "cannot verify" as "do not publish".
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)][string]$Type,
|
||||||
|
[Parameter(Mandatory)][string]$Name,
|
||||||
|
[Parameter(Mandatory)][string]$Version
|
||||||
|
)
|
||||||
|
|
||||||
|
$uri = "$GiteaPackageApiBase/$Type/$Name/$Version"
|
||||||
|
$headers = @{}
|
||||||
|
if (-not [string]::IsNullOrEmpty($env:GITEA_TOKEN)) {
|
||||||
|
$user = if ([string]::IsNullOrEmpty($env:GITEA_USERNAME)) { 'dohertj2' } else { $env:GITEA_USERNAME }
|
||||||
|
$pair = "$($user):$($env:GITEA_TOKEN)"
|
||||||
|
$basic = [Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
|
||||||
|
$headers['Authorization'] = "Basic $basic"
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = Invoke-WebRequest -Uri $uri -Headers $headers -Method Get -UseBasicParsing -ErrorAction Stop
|
||||||
|
return ($response.StatusCode -eq 200)
|
||||||
|
} catch {
|
||||||
|
$statusCode = $null
|
||||||
|
if ($_.Exception.PSObject.Properties['Response'] -and $_.Exception.Response) {
|
||||||
|
$statusCode = [int]$_.Exception.Response.StatusCode
|
||||||
|
}
|
||||||
|
if ($statusCode -eq 404) {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
throw "Unable to query the Gitea package API for '$Type/$Name/$Version' ($uri): $($_.Exception.Message). Refusing to publish without a collision check — verify manually (or check GITEA_USERNAME/GITEA_TOKEN/network) and retry."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Assert-GiteaPackageNotPublished {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Aborts the script if $Name/$Version already exists in the $Type feed.
|
||||||
|
Never force-overwrites a published artifact (CLI-39).
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)][string]$Type,
|
||||||
|
[Parameter(Mandatory)][string]$Name,
|
||||||
|
[Parameter(Mandatory)][string]$Version
|
||||||
|
)
|
||||||
|
|
||||||
|
Write-Host "Checking Gitea '$Type' feed for existing '$Name' $Version..."
|
||||||
|
if (Test-GiteaPackageExists -Type $Type -Name $Name -Version $Version) {
|
||||||
|
throw "Gitea package '$Name' version '$Version' already exists in the '$Type' feed. Bump the client version before publishing — this script never force-overwrites a published artifact."
|
||||||
|
}
|
||||||
|
Write-Host " Not found in the '$Type' feed — safe to publish '$Name' $Version." -ForegroundColor Green
|
||||||
|
}
|
||||||
|
|
||||||
# -------- .NET --------
|
# -------- .NET --------
|
||||||
|
|
||||||
function Invoke-PackDotnet {
|
function Invoke-PackDotnet {
|
||||||
@@ -121,6 +185,15 @@ function Invoke-PackDotnet {
|
|||||||
if ($Publish) {
|
if ($Publish) {
|
||||||
Write-Host 'Publishing .NET packages to Gitea...' -ForegroundColor Yellow
|
Write-Host 'Publishing .NET packages to Gitea...' -ForegroundColor Yellow
|
||||||
Get-ChildItem $OutputDir -Filter 'ZB.MOM.WW.MxGateway.*.nupkg' | ForEach-Object {
|
Get-ChildItem $OutputDir -Filter 'ZB.MOM.WW.MxGateway.*.nupkg' | ForEach-Object {
|
||||||
|
# nupkg filenames are '<PackageId>.<Version>.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 '^(?<id>.+?)\.(?<version>\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)$') {
|
||||||
|
throw "Could not parse a NuGet package id/version out of '$($_.Name)'."
|
||||||
|
}
|
||||||
|
Assert-GiteaPackageNotPublished -Type 'nuget' -Name $Matches.id -Version $Matches.version
|
||||||
|
|
||||||
& dotnet nuget push $_.FullName --source $GiteaNugetFeed --api-key $env:GITEA_TOKEN
|
& dotnet nuget push $_.FullName --source $GiteaNugetFeed --api-key $env:GITEA_TOKEN
|
||||||
if ($LASTEXITCODE -ne 0) { throw "dotnet nuget push failed for '$($_.Name)'." }
|
if ($LASTEXITCODE -ne 0) { throw "dotnet nuget push failed for '$($_.Name)'." }
|
||||||
}
|
}
|
||||||
@@ -159,6 +232,20 @@ function Invoke-PackPython {
|
|||||||
Write-Host "Packed Python artifacts -> $OutputDir" -ForegroundColor Green
|
Write-Host "Packed Python artifacts -> $OutputDir" -ForegroundColor Green
|
||||||
|
|
||||||
if ($Publish) {
|
if ($Publish) {
|
||||||
|
$pyprojectPath = Join-Path $RepoRoot 'clients/python/pyproject.toml'
|
||||||
|
$pyprojectContent = Get-Content $pyprojectPath -Raw
|
||||||
|
# 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\](?<section>.*?)(?=^\[|\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]
|
||||||
|
|
||||||
Write-Host 'Publishing Python distribution to Gitea...' -ForegroundColor Yellow
|
Write-Host 'Publishing Python distribution to Gitea...' -ForegroundColor Yellow
|
||||||
$wheels = @(Get-ChildItem $OutputDir -Filter 'zb_mom_ww_mxaccess_gateway_client-*.whl')
|
$wheels = @(Get-ChildItem $OutputDir -Filter 'zb_mom_ww_mxaccess_gateway_client-*.whl')
|
||||||
$sdists = @(Get-ChildItem $OutputDir -Filter 'zb_mom_ww_mxaccess_gateway_client-*.tar.gz')
|
$sdists = @(Get-ChildItem $OutputDir -Filter 'zb_mom_ww_mxaccess_gateway_client-*.tar.gz')
|
||||||
@@ -206,6 +293,20 @@ function Invoke-PackRust {
|
|||||||
Write-Host "Packed Rust artifacts -> $OutputDir" -ForegroundColor Green
|
Write-Host "Packed Rust artifacts -> $OutputDir" -ForegroundColor Green
|
||||||
|
|
||||||
if ($Publish) {
|
if ($Publish) {
|
||||||
|
$cargoTomlPath = Join-Path $rustDir 'Cargo.toml'
|
||||||
|
$cargoTomlContent = Get-Content $cargoTomlPath -Raw
|
||||||
|
# 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\](?<section>.*?)(?=^\[|\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]
|
||||||
|
|
||||||
Write-Host 'Publishing Rust crate to Gitea...' -ForegroundColor Yellow
|
Write-Host 'Publishing Rust crate to Gitea...' -ForegroundColor Yellow
|
||||||
Push-Location (Join-Path $RepoRoot 'clients/rust')
|
Push-Location (Join-Path $RepoRoot 'clients/rust')
|
||||||
try {
|
try {
|
||||||
@@ -269,6 +370,21 @@ function Invoke-PackJava {
|
|||||||
Write-Host "Packed Java artifacts -> $OutputDir" -ForegroundColor Green
|
Write-Host "Packed Java artifacts -> $OutputDir" -ForegroundColor Green
|
||||||
|
|
||||||
if ($Publish) {
|
if ($Publish) {
|
||||||
|
$buildGradlePath = Join-Path $javaDir 'build.gradle'
|
||||||
|
$buildGradleContent = Get-Content $buildGradlePath -Raw
|
||||||
|
if ($buildGradleContent -notmatch "(?m)^\s*group\s*=\s*'([^']+)'") {
|
||||||
|
throw "Could not find subprojects { group = '...' } in '$buildGradlePath'."
|
||||||
|
}
|
||||||
|
$javaGroup = $Matches[1]
|
||||||
|
if ($buildGradleContent -notmatch "(?m)^\s*version\s*=\s*'([^']+)'") {
|
||||||
|
throw "Could not find subprojects { version = '...' } in '$buildGradlePath'."
|
||||||
|
}
|
||||||
|
$javaVersion = $Matches[1]
|
||||||
|
# Gitea's Maven package API identifies the package as "groupId:artifactId",
|
||||||
|
# not the bare artifact id — passing just the artifact id here would query
|
||||||
|
# a name that never exists and silently defeat the guard.
|
||||||
|
Assert-GiteaPackageNotPublished -Type 'maven' -Name "$javaGroup`:zb-mom-ww-mxgateway-client" -Version $javaVersion
|
||||||
|
|
||||||
Write-Host 'Publishing Java artifacts to Gitea Maven feed...' -ForegroundColor Yellow
|
Write-Host 'Publishing Java artifacts to Gitea Maven feed...' -ForegroundColor Yellow
|
||||||
Push-Location $javaDir
|
Push-Location $javaDir
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -36,6 +36,23 @@ if ($Version -notmatch '^v\d+\.\d+\.\d+(-[A-Za-z0-9.-]+)?$') {
|
|||||||
throw "Version '$Version' must match semver vX.Y.Z (optionally with -prerelease suffix)."
|
throw "Version '$Version' must match semver vX.Y.Z (optionally with -prerelease suffix)."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# CLI-21 guard: the tag must match what the module itself reports via
|
||||||
|
# ClientVersion, or `go get <module>@vX.Y.Z` resolves a tag whose module
|
||||||
|
# code disagrees with its own version constant.
|
||||||
|
$versionGoPath = Join-Path $PSScriptRoot '..' 'clients/go/mxgateway/version.go'
|
||||||
|
if (-not (Test-Path $versionGoPath)) {
|
||||||
|
throw "Could not find '$versionGoPath' to verify ClientVersion before tagging."
|
||||||
|
}
|
||||||
|
$versionGoContent = Get-Content $versionGoPath -Raw
|
||||||
|
if ($versionGoContent -notmatch 'ClientVersion\s*=\s*"([^"]+)"') {
|
||||||
|
throw "Could not find a ClientVersion = `"...`" constant in '$versionGoPath'."
|
||||||
|
}
|
||||||
|
$clientVersion = $Matches[1]
|
||||||
|
$tagVersion = $Version.TrimStart('v')
|
||||||
|
if ($clientVersion -ne $tagVersion) {
|
||||||
|
throw "clients/go/mxgateway/version.go ClientVersion is '$clientVersion' but the requested tag is '$tagVersion'. Update ClientVersion to match before tagging."
|
||||||
|
}
|
||||||
|
|
||||||
$tag = "clients/go/$Version"
|
$tag = "clients/go/$Version"
|
||||||
Write-Host "Creating Go-module tag: $tag" -ForegroundColor Cyan
|
Write-Host "Creating Go-module tag: $tag" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,14 @@
|
|||||||
|
|
||||||
<!-- TST-11: single-source the .NET-side version for Server, Worker, Contracts, and tests
|
<!-- TST-11: single-source the .NET-side version for Server, Worker, Contracts, and tests
|
||||||
(they otherwise stamp the SDK default 1.0.0, so a deployed gateway cannot be correlated
|
(they otherwise stamp the SDK default 1.0.0, so a deployed gateway cannot be correlated
|
||||||
to a release). Kept at 0.1.2 to match the Contracts package and the aligned Python/Rust/
|
to a release). Server/Worker/Tests stay at this default. CLI-39 (2026-08-07) moved the
|
||||||
Go clients; the Java client leads at 0.2.0 after its JDK-17 retarget. The git short SHA is
|
published `ZB.MOM.WW.MxGateway.Contracts` and `.Client` nuget packages to 0.2.0 via an
|
||||||
appended to InformationalVersion (0.1.2+<sha>) so support can map a running binary to a
|
explicit <Version> override in Contracts.csproj (MSBuild property-last-write-wins over
|
||||||
commit; the query is guarded so a build outside a git checkout still succeeds. -->
|
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+<sha>) so support can map a running binary to a commit; the
|
||||||
|
query is guarded so a build outside a git checkout still succeeds. -->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>0.1.2</Version>
|
<Version>0.1.2</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -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.1.2</Version>
|
<Version>0.2.0</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>
|
||||||
|
|||||||
Reference in New Issue
Block a user