Files
zeekay c467eb2ad8 the release lane refuses rather than publishing nothing
Publishing to Maven Central rode inside hanzo.yml's `binaries:` block behind
`if [ -n "$GPG_SIGNING_KEY" ]`. hanzoai/ci fetches deploy credentials and has no
occurrence of GPG_SIGNING, MAVEN_CENTRAL, SONATYPE or ORG_GRADLE_PROJECT
anywhere in it, so that condition has been false on every run this repo has ever
made: a tag assembled the jar, uploaded nothing, and reported success. Four
alpha tags exist with an empty registry behind them.

So the upload moves out of `binaries:` into .hanzo/workflows/publish-maven.yml —
the shape python-sdk already publishes under — where it reads its credential
from KMS and FAILS when the credential is absent. One lane per destination:
`binaries:` attaches the jar to the release, this uploads to Central.

The credential is registry-scoped, not repo-scoped: one `ai.hanzo` namespace and
one signing key serve every JVM client, so it is sealed once at org hanzo, env
prod, path `maven`, and hanzoai/java-sdk reads the same five keys.

The POM is what a reader sees on Central before any code, so it names this
artifact: a Kotlin client, at the public mirror a stranger can open, under a
license that carries its URL. `Hanzo API` / `API documentation for Hanzo` named
neither the language nor the thing, and the scm pointed at a redirect.
2026-08-14 17:51:16 -07:00

60 lines
3.0 KiB
YAML

# Hanzo CI — the ONE way this repo is gated, read by hanzoai/ci.
#
# No `images:` and no `deploy:`: this is a client library. What CI owes is a
# gate plus the jar. Nothing is on Maven Central yet, so until a tag publishes
# one, a consumer builds the jar and resolves it from `mavenLocal()`.
test:
- name: sdk-build
# Every module: the generated client (192 API classes, 2461 models) and the
# six example flows. It can be the whole build again because every module is
# now part of the one client — the second, hand-shaped client that could not
# compile is deleted, and the hand-listed subset it forced went with it.
run: ./scripts/build
- name: sdk-lint
# ktfmt over what is written by hand: `Hanzo.kt` and the examples. It is
# switched off for the generated sources, which must stay byte-identical to
# the generator's output or the client lane's `--check` fails.
run: ./scripts/lint
- name: flows-test
# Pins the six canonical flows to the routes hanzoai/openapi `flows.yaml`
# names, and asserts the client actually sends the bearer token and the org
# header. Those two facts are the whole contract of a generated SDK.
run: ./gradlew :hanzo-kotlin-cloud:test
binaries:
- name: hanzo-kotlin-cloud
# The jar: built on every push, attached to the release on a tag.
#
# Maven Central is NOT published from here. It is
# `.hanzo/workflows/publish-maven.yml` — one lane, which reads its
# credential from KMS and fails when the credential is absent. This block
# used to carry a second upload behind `if [ -n "$GPG_SIGNING_KEY" ]`, and
# hanzoai/ci sets no such variable (it fetches deploy credentials, not
# publishing ones), so the condition was false on every run ever made: a tag
# assembled the jar, published nothing, and went green.
run: ./gradlew :hanzo-kotlin-cloud:assemble
out: hanzo-kotlin-cloud/build/libs/*.jar
# THE CLIENT LANE — this repo is a PROJECTION of one API document at one version.
#
# hanzoai/cloud's release sends `repository_dispatch: spec-update` carrying
# (version, sha, spec_sha256); hanzoai/ci fetches openapi.yaml AT THAT SHA,
# REFUSES if the bytes hash to anything else, runs `generate:`, writes
# `.spec-lock` beside the code, and — only after the `test:` block below has
# passed over exactly those bytes — commits and cuts a patch.
#
# The document moved from hanzoai/openapi `hanzo.yaml` (a curated projection,
# 1794 paths / 2456 operations, and NOTHING HAS EVER SENT the spec-update this
# repo listens for) to hanzoai/cloud `openapi.yaml` — 1814 paths / 2479
# operations, emitted from the code by each app's own router and gated on every
# cloud release. The source, rather than a copy of it.
client:
generate: ./scripts/generate.sh
# NO version: — this client's version is a gradle -alpha.N build, not
# x.y.z, so there is no patch for the lane to derive. Its projection
# still lands and is still gated; the cut waits for a human, instead of
# a tag naming bytes under a number nobody chose.