fix(CLI-39): bump client versions off published 0.1.2; guard the publish pipeline
Converges all five clients on one version after four had drifted onto the already-published 0.1.2/0.1.1 while their APIs kept changing underneath it: - Rust Cargo.toml [package] + [workspace.package] -> 0.2.0 (CLIENT_VERSION already derives from CARGO_PKG_VERSION, no separate edit). - Python pyproject.toml + version.py -> 0.2.0; new test asserts __version__ matches pyproject.toml (closes the CLI-26 residual drift mode). - Go mxgateway/version.go ClientVersion -> 0.2.0. - .NET ZB.MOM.WW.MxGateway.Client.csproj <Version> -> 0.2.0. - Java -> 0.2.1, not 0.2.0: the live Gitea Maven feed already had 0.2.0 published (2026-06-26), before the CLI-37/38/40/41 conformance fixes changed the client's observable behavior, so reusing 0.2.0 would label two different APIs identically. Recorded as an exception in docs/ClientPackaging.md's new Versioning section. Publish-pipeline guards: - scripts/tag-go-module.ps1 implements the CLI-21 guard: after semver validation it refuses to tag unless clients/go/mxgateway/version.go's ClientVersion already matches the requested tag version. - scripts/pack-clients.ps1 gains a Gitea package-registry collision guard wired into every per-language -Publish step; it aborts if the target name+version already exists rather than force-overwriting. Verified live against the real Gitea registry (credentials already present in this environment) — correctly refuses on every known-published artifact and passes on every unpublished target. Docs updated in the same commit: docs/ClientPackaging.md (new Versioning section), and the five client READMEs' stale 0.1.1/0.1.2 example versions. No .proto changes. No publish performed.
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,51 @@ $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).
|
||||||
|
|
||||||
|
**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 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`)
|
||||||
|
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,12 @@ 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 {
|
||||||
|
$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 +229,13 @@ 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
|
||||||
|
if ($pyprojectContent -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 +283,13 @@ 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
|
||||||
|
if ($cargoTomlContent -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 +353,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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user