Conversation
mz-deploy was versioned independently at 0.7.0, hand-bumped and shipped from its own mz-deploy-v* git tags through a manually triggered pipeline. That made it impossible to tell from `mz-deploy --version` which server releases a CLI understands, and nothing checked that a release tag agreed with the version in Cargo.toml. Give mz-deploy the Materialize version and publish it from the release train. src/mz-deploy is added to bin/bump-version, so the crate tracks environmentd from here on. The three tarball steps move into ci/deploy/pipeline.template.yml behind `if: build.tag != ""`, since that pipeline also runs on every push to main with no tag to derive a version from. The Linux targets now extract the binary from the mz-deploy image the release build already produced rather than recompiling it, so the tarball ships exactly what CI tested; macOS still builds from source because it has no image. Release candidates publish a versioned tarball but no longer move the `mz-deploy-latest-*` redirect, which is the URL our install docs hand to users and so has to name a GA build. This adds an `update_latest` flag to TarballUploader.deploy_tarball, defaulting to the existing behavior for mz and mz-debug. Deploys now assert that the release tag matches src/mz-deploy/Cargo.toml, the guard ci/deploy_mz/linux.py already had. Note this also resolves an existing inconsistency: src/mz-deploy/ci/mzbuild.yml defaults to publish, so materialize/mz-deploy:v26.44.0 was already being published containing a binary that reported v0.7.0. The legacy mz-deploy-v0.* tags are left in place. They do not start with `v`, so git.get_version_tags ignores them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
mz-deploy and the server now share a version, but they still deploy separately, so a CLI can be driving a server it does not match. Nothing detected that, and the drift surfaced as a confusing failure partway through a deploy rather than as something the user could act on up front. Compare the two at connect and emit a notice on a mismatch. The server already announces its build as an `mz_version` ParameterStatus during the pgwire handshake, so this costs no round trip; the value is read off the `Connection` before the connection future is spawned. dbt-materialize reads the same parameter. Only the major and minor versions are compared. Patch releases do not change the surface the CLI drives, and ignoring the pre-release keeps a dev build quiet against the release it was cut from, which would otherwise mean a notice on every command during local development. The notice never changes the exit code, and is suppressed when the peer announces nothing parseable: the handshake has already succeeded by then, and a proxy that drops the parameter is not worth warning about on every command. It fires at most once per process, which matters because `test --no-docker` opens a connection per test. The `Once` is claimed only when a notice is warranted, so a matching first connection cannot mask a later mismatched one. Sandbox connections skip the check via a new `Client::connect_sandbox`. The sandbox runs an image tag this CLI picked, so skew there says nothing about the user's deployment target, and `wait_for_container` polls with a fresh connect up to 30 times. `BUILD_INFO` and `VERSION` move from the binary into the library so the client layer can reach them. Tests: unit tests in `client::version_skew` cover patch-only differences, dev and rc builds against their release, both mismatch directions, a major difference, the helm-chart suffix, and absent or unparseable values. A new `version_check` mzcompose workflow asserts that a server on the same version draws no notice, which is the false-positive case that would otherwise be noise for every user. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`test` and `explain` run against an ephemeral Materialize container, and with
no `mz_version` configured that container was always `latest`. So local runs
were checked against whatever had most recently been released rather than
against the server the project actually deploys to, and the two drifted apart
for the whole of a release cycle.
Default the sandbox image to this build's own version instead. Now that
mz-deploy carries the Materialize version, `v{version}` names the matching
published image.
A pre-release build has no such image, so it falls back to `latest`. Without
that, `test` would break for every developer working against a dev build.
`cloud` no longer shares an arm with the unset case. It means whatever
Materialize Cloud runs now, which `latest` tracks, so folding the two together
would have quietly redefined it. An explicit `mz_version` pin and the
`--docker-image` override are unaffected.
Tests: unit tests in `config` cover the pre-release fallback, an explicit pin,
`cloud`, and the unset default.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
a57beb1 to
71e3547
Compare
QA LLM Review1. MEDIUM — the new sandbox default never applies to projects created by
|
mz-deploy was versioned independently at
0.7.0, hand-bumped and shipped from its ownmz-deploy-v*git tags through a manually triggered pipeline. That made it impossible to tell frommz-deploy --versionwhich server releases a CLI understands, nothing detected when a CLI was driving a server it did not match, and nothing checked that a release tag agreed with the version in Cargo.toml.This gives mz-deploy the Materialize version, publishes it from the release train, and has it say something when it connects to a server it does not match.
Three commits, in an order that matters: the notice would fire on every connection and the sandbox would name a nonexistent image if the version change did not land first.
1. Version with the release train
src/mz-deployjoinsbin/bump-version, so the crate tracks environmentd. The three tarball steps move intoci/deploy/pipeline.template.ymlbehindif: build.tag != "", since that pipeline also runs on every push to main with no tag to parse.ci/deploy_mz-deploy/pipeline.template.ymlandMzDeployVersionare deleted.The Linux targets now extract the binary from the
mz-deployimage the release build already produced rather than recompiling it, so the tarball ships exactly what CI tested. macOS still builds from source, having no image.Release candidates publish a versioned tarball but no longer move the
mz-deploy-latest-*redirect, which is the URL our install docs hand to users and so has to name a GA build.TarballUploader.deploy_tarballgains anupdate_latestflag, defaulting to the existing behavior formzandmz-debug.Deploys now assert the release tag matches
src/mz-deploy/Cargo.toml, the guardci/deploy_mz/linux.pyalready had.This also resolves an existing inconsistency:
src/mz-deploy/ci/mzbuild.ymldefaults topublish, somaterialize/mz-deploy:v26.44.0was already being published containing a binary that reportedv0.7.0.2. Notice on version skew
The server already announces its build as an
mz_versionParameterStatus during the pgwire handshake, so the comparison costs no round trip. The value is read off theConnectionbefore the connection future is spawned. dbt-materialize reads the same parameter.Only major and minor are compared. Patch releases do not change the surface the CLI drives, and ignoring the pre-release keeps a dev build quiet against the release it was cut from, which would otherwise mean a notice on every command during local development.
The notice never changes the exit code, and is suppressed when the peer announces nothing parseable: the handshake has already succeeded by then, and a proxy that drops the parameter is not worth warning about on every command. It fires at most once per process, which matters because
test --no-dockeropens a connection per test. TheOnceis claimed only when a notice is warranted, so a matching first connection cannot mask a later mismatched one.Sandbox connections skip the check via a new
Client::connect_sandbox. The sandbox runs an image tag the CLI picked, so skew there says nothing about the user's deployment target, andwait_for_containerpolls with a fresh connect up to 30 times.3. Sandbox defaults to this build's version
testandexplainran againstlatest, so local runs were checked against whatever had most recently been released rather than against the server the project deploys to, and the two drifted for a whole release cycle. The sandbox image now defaults tov{version}, falling back tolateston a pre-release build since no such image is published.cloudwas split out of the unset arm so it keeps meaning "whatever Cloud runs now".Tests
Unit tests in
client::version_skewcover patch-only differences, dev and rc builds against their release, both mismatch directions, a major difference, the helm-chart suffix, and absent or unparseable values. Unit tests inconfigcover the pre-release image fallback, an explicit pin,cloud, and the unset default. A newversion_checkmzcompose workflow asserts that a server on the same version draws no notice, which is the false-positive case that would otherwise be noise for every user.Needs a decision before this ships
latestredirect, so it now needs refreshing on the release cadence, from GA tags only. Automating a tap PR would need a Buildkite secret with write access to the tap, which does not exist today. No owner yet.deploy-mz-deployBuildkite pipeline needs Buildkite admin; that config lives outside the repo. With the template deleted, a manual trigger would fail at upload.deployis forcedasync: falseon tags. Arguably correct, but worth sign-off from the release rotation.Release note
This release will make
mz-deployshare a version with Materialize, and warn when the CLI's version does not match the server it connects to.Follow-up
DockerRuntimereuses an existing container by name without comparing its image to the configured one, so a sandbox left over from before the default tag moved silently stays on the old version. Pre-existing, surfaced by commit 3.🤖 Generated with Claude Code