From 9fc76ffcba77cadbd574e7b89c93a33d2d6de48f Mon Sep 17 00:00:00 2001 From: Shawn Chen Date: Thu, 24 Sep 2026 08:29:15 +1200 Subject: [PATCH 1/3] Publish RCs from public Maven repository --- .github/workflows/rc-release.yml | 80 ++++++++++++++++++-------- README.md | 46 ++++----------- deploy/vercel-maven/.gitignore | 2 + deploy/vercel-maven/README.md | 37 ++++++++++++ deploy/vercel-maven/index.html | 16 ++++++ deploy/vercel-maven/vercel.json | 28 ++++++++++ scripts/publish-rc-repository.sh | 96 ++++++++++++++++++++++++++++++++ 7 files changed, 246 insertions(+), 59 deletions(-) create mode 100644 deploy/vercel-maven/.gitignore create mode 100644 deploy/vercel-maven/README.md create mode 100644 deploy/vercel-maven/index.html create mode 100644 deploy/vercel-maven/vercel.json create mode 100755 scripts/publish-rc-repository.sh diff --git a/.github/workflows/rc-release.yml b/.github/workflows/rc-release.yml index b991e3a..47312b2 100644 --- a/.github/workflows/rc-release.yml +++ b/.github/workflows/rc-release.yml @@ -1,8 +1,7 @@ name: Maven RC release -# RCs are published to GitHub Packages while Maven Central Publisher Pro is being arranged. -# The permanent Maven coordinates are used from the first RC, so the later Central migration -# changes only the repository URL, not users' dependencies. +# RCs are staged as a standard Maven repository for upload to the public Vercel Blob store +# behind maven.chdb.io. Stable releases will move to Maven Central without changing coordinates. on: push: tags: @@ -88,12 +87,18 @@ jobs: # shellcheck disable=SC2086 mvn $MAVEN_ARGS -pl chdb-jdbc,chdb-native-${{ matrix.platform }} package -DskipTests mkdir -p "maven/${{ matrix.platform }}" - cp "chdb-jdbc/target/chdb-jdbc-${RC_VERSION}.jar" "maven/${{ matrix.platform }}/" cp "chdb-native-${{ matrix.platform }}/target/chdb-native-${{ matrix.platform }}-${RC_VERSION}.jar" "maven/${{ matrix.platform }}/" - cp pom.xml "maven/${{ matrix.platform }}/chdb-java-parent.pom" - cp chdb-jdbc/pom.xml "maven/${{ matrix.platform }}/chdb-jdbc.pom" cp "chdb-native-${{ matrix.platform }}/pom.xml" "maven/${{ matrix.platform }}/chdb-native-${{ matrix.platform }}.pom" - cp chdb-bom/pom.xml "maven/${{ matrix.platform }}/chdb-bom.pom" + + # Build the pure-Java artifacts once. JAR ZIP timestamps differ across matrix jobs, + # so accepting four interchangeable copies would make the published bytes depend on + # artifact download order. + if [ '${{ matrix.platform }}' = linux-x86_64-gnu ]; then + cp "chdb-jdbc/target/chdb-jdbc-${RC_VERSION}.jar" "maven/${{ matrix.platform }}/" + cp pom.xml "maven/${{ matrix.platform }}/chdb-java-parent.pom" + cp chdb-jdbc/pom.xml "maven/${{ matrix.platform }}/chdb-jdbc.pom" + cp chdb-bom/pom.xml "maven/${{ matrix.platform }}/chdb-bom.pom" + fi - uses: actions/upload-artifact@v4 with: @@ -102,13 +107,10 @@ jobs: if-no-files-found: error retention-days: 14 - publish: - name: publish RC to GitHub Packages + stage: + name: stage public Maven repository needs: build runs-on: ubuntu-latest - permissions: - contents: read - packages: write steps: - uses: actions/checkout@v4 with: @@ -118,9 +120,6 @@ jobs: with: distribution: temurin java-version: '11' - server-id: github - server-username: GITHUB_ACTOR - server-password: GITHUB_TOKEN - name: Resolve RC version run: | @@ -136,37 +135,70 @@ jobs: pattern: maven-* path: maven - - name: Publish Maven artifacts - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITHUB_ACTOR: ${{ github.actor }} + - name: Build the Maven repository directory run: | set -eu - REPOSITORY_URL="https://maven.pkg.github.com/${GITHUB_REPOSITORY_OWNER,,}/chdb-java" + REPOSITORY_URL="file://${GITHUB_WORKSPACE}/repository" PARENT_POM=$(find maven -name chdb-java-parent.pom -print -quit) JDBC_POM=$(find maven -name chdb-jdbc.pom -print -quit) BOM_POM=$(find maven -name chdb-bom.pom -print -quit) + # shellcheck disable=SC2086 mvn $MAVEN_ARGS org.apache.maven.plugins:maven-deploy-plugin:3.1.3:deploy-file \ -Dfile="$PARENT_POM" -DgroupId=com.clickhouse.chdb -DartifactId=chdb-java-parent \ -Dversion="$RC_VERSION" -Dpackaging=pom -DgeneratePom=false \ - -DrepositoryId=github -Durl="$REPOSITORY_URL" + -DrepositoryId=chdb-rc -Durl="$REPOSITORY_URL" + # shellcheck disable=SC2086 mvn $MAVEN_ARGS org.apache.maven.plugins:maven-deploy-plugin:3.1.3:deploy-file \ -Dfile="$(find maven -name "chdb-jdbc-${RC_VERSION}.jar" -print -quit)" \ -DpomFile="$JDBC_POM" -DgeneratePom=false \ - -DrepositoryId=github -Durl="$REPOSITORY_URL" + -DrepositoryId=chdb-rc -Durl="$REPOSITORY_URL" for platform in macos-aarch64 macos-x86_64 linux-x86_64-gnu linux-aarch64-gnu; do NATIVE_POM=$(find maven -name "chdb-native-${platform}.pom" -print -quit) NATIVE_JAR=$(find maven -name "chdb-native-${platform}-${RC_VERSION}.jar" -print -quit) + # shellcheck disable=SC2086 mvn $MAVEN_ARGS org.apache.maven.plugins:maven-deploy-plugin:3.1.3:deploy-file \ -Dfile="$NATIVE_JAR" -DpomFile="$NATIVE_POM" -DgeneratePom=false \ - -DrepositoryId=github -Durl="$REPOSITORY_URL" + -DrepositoryId=chdb-rc -Durl="$REPOSITORY_URL" done + # shellcheck disable=SC2086 mvn $MAVEN_ARGS org.apache.maven.plugins:maven-deploy-plugin:3.1.3:deploy-file \ -Dfile="$BOM_POM" -DpomFile="$BOM_POM" -Dpackaging=pom \ -DgroupId=com.clickhouse.chdb -DartifactId=chdb-bom -Dversion="$RC_VERSION" \ -DgeneratePom=false \ - -DrepositoryId=github -Durl="$REPOSITORY_URL" + -DrepositoryId=chdb-rc -Durl="$REPOSITORY_URL" + + # Version discovery is intentionally not supported by this temporary RC repository. + # Mutable artifact-level metadata would collide with the next immutable RC upload. + find repository -type f -name 'maven-metadata*' -delete + + find repository -type f \( -name '*.jar' -o -name '*.pom' \) -print0 | + while IFS= read -r -d '' file; do + md5sum "$file" | awk '{print $1}' > "$file.md5" + sha1sum "$file" | awk '{print $1}' > "$file.sha1" + sha256sum "$file" | awk '{print $1}' > "$file.sha256" + sha512sum "$file" | awk '{print $1}' > "$file.sha512" + done + + - uses: actions/upload-artifact@v4 + with: + name: maven-repository + path: repository + if-no-files-found: error + retention-days: 14 + + - name: Record the publication handoff + run: | + { + echo '### RC repository staged' + echo + # shellcheck disable=SC2016 + echo 'Download the `maven-repository` artifact and publish it with:' + echo + echo '```console' + echo 'scripts/publish-rc-repository.sh /path/to/maven-repository' + echo '```' + } >> "$GITHUB_STEP_SUMMARY" diff --git a/README.md b/README.md index 9f30bc3..000f786 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ ClickHouse. It runs the engine in your JVM's process — no server, no network streaming, forward-only result sets over ClickHouse SQL. > **Status: release candidate.** The first Maven release candidate is `v1.0.0-rc.1`, built with -> chDB Core `26.7.3`. RC artifacts are published to GitHub Packages until Maven Central is ready; -> the public API is not frozen. See +> chDB Core `26.7.3`. RC artifacts are available from the public chDB Maven repository; the +> public API is not frozen. See > [What works today](#what-works-today). ```java @@ -42,13 +42,7 @@ and is loaded from a real packaged JAR, in CI: floor rather than infer it from symbol versions. - **Engine:** chDB Core **26.7.3**, pinned. The C ABI is version-locked, so the driver refuses to run against a different engine build rather than risking a struct-layout mismatch. - That release is a stable chdb-core release, which is what [work plan - §4.3](CHDB_JAVA_V1_WORK_PLAN.md) requires of a V1 GA engine: the previous baseline, - `26.7.2-rc.2`, was a pre-release and made every binding built on it a preview. -- **Not supported:** Windows, musl (Alpine), 32-bit, GraalVM Native Image, Android. See - [work plan §2.3](CHDB_JAVA_V1_WORK_PLAN.md). - -[docs/v1-progress.md](docs/v1-progress.md) has the phase-by-phase status and what is left. +- **Not supported:** Windows, musl (Alpine), 32-bit, GraalVM Native Image, Android. ## Installing @@ -63,26 +57,12 @@ on. The native package pulls in the driver, so declaring it alone is enough. ``` -GitHub Packages requires a GitHub classic PAT with `read:packages` in `~/.m2/settings.xml`: - -```xml - - - - github - YOUR_GITHUB_USERNAME - YOUR_GITHUB_PAT - - - -``` - -Add the repository to the consuming project: +Add the public RC repository to the consuming project. It does not require a username or token: ```xml - github - https://maven.pkg.github.com/chdb-io/chdb-java + chdb-rc + https://maven.chdb.io ``` @@ -95,7 +75,7 @@ architecture — declare the driver plus each native package you need: com.clickhouse.chdb chdb-bom - 1.0.0 + 1.0.0-rc.1 pom import @@ -130,11 +110,10 @@ SemVer, on the binding alone: `1.0.0` is the first release and a major bump mean change to the Java API. The engine version is not part of it — it is in each package's `manifest.properties`, pinned in [`scripts/engine.properties`](scripts/engine.properties) and named in the release notes (`26.7.3` today), and the driver refuses to load any other build. -See [work plan §4.3](CHDB_JAVA_V1_WORK_PLAN.md). The first test version is the RC `1.0.0-rc.1`; later candidates increment the final number, and the first stable Maven release is `1.0.0`. RCs use the permanent `com.clickhouse.chdb` groupId, -so moving stable releases to Maven Central will not change dependency coordinates. +so publishing stable releases to Maven Central will not change dependency coordinates. ## Connecting @@ -192,7 +171,7 @@ Use a second `Connection` — they can share the storage path — or close the f The engine runs in your process. There is no crash isolation: if it segfaults, your JVM dies with it, and no Java `catch` can intervene. That is the price of an in-process binding, and it is the reason not to embed chDB in a service where that is unacceptable. Subprocess isolation -is a post-V1 idea, not something V1 offers. +is not supported. The related trade is that the driver switches off chDB's own crash handlers, because they overwrite the ones HotSpot needs to function. You keep a working JVM and lose ClickHouse-format @@ -227,9 +206,8 @@ engine. In Tomcat, Spark or Flink this decides where the driver goes. See | ✅ | Bounded memory on results far larger than the heap | | ✅ | Host JVM signal handlers preserved — see [signal handlers](docs/signal-handlers.md) | | ✅ | Native loading from the platform JAR, or a directory you point at | -| 🚧 | Framework smoke tests — HikariCP, MyBatis and jOOQ pass, and nothing on the full `DatabaseMetaData` surface throws; Spring `JdbcTemplate` is next, and ShardingSphere cannot parse a `jdbc:chdb:` URL at all — see [under a framework](docs/unsupported.md#under-a-framework) | +| 🚧 | Framework smoke tests — HikariCP, MyBatis and jOOQ pass, and nothing on the full `DatabaseMetaData` surface throws; Spring `JdbcTemplate` is not yet verified, and ShardingSphere cannot parse a `jdbc:chdb:` URL at all — see [under a framework](docs/unsupported.md#under-a-framework) | | 🚧 | Soak tests; full-process ASan, which needs an upstream sanitizer build of chdb-core | -| 🚧 | Maven Central publishing — nothing is released yet | | ❌ | Transactions, batch updates, scrollable/updatable result sets, `CallableStatement` | | ❌ | Stored procedures, generated keys, `Blob`/`Clob`/`Array`/`SQLXML` | | ❌ | `Array`, `Map`, `Tuple`, `Nested`, `Variant`, `JSON`, `Dynamic` columns | @@ -265,7 +243,7 @@ detection. | Storage path | many connections on one path; a second path refused with a usable diagnosis; rebinding after the last close; a failed connect leaving nothing pinned | | Loader | five failure paths: no platform package, a bad override, a missing shim, a corrupted cache and a tampered checksum | | Packaging | each platform JAR is built, then the engine is loaded back out of it and a query run, on every platform | -| Version floors | the full suite again on AlmaLinux 8 — glibc 2.28, RHEL 8's base — against the artefacts the release job would publish; and the build fails if a platform's measured floor rises above its ceiling | +| Version floors | the full suite again on AlmaLinux 8 — glibc 2.28, RHEL 8's base — against the packaged artifacts; and the build fails if a platform's measured floor rises above its ceiling | **Sanitizers**, on both a Linux and a macOS toolchain: UBSan over the whole integration suite in a real JVM against the real engine, and ASan plus UBSan over a 107-check harness for the shim's @@ -287,7 +265,6 @@ but not exercised on an old macOS, because no such runner exists. | [Memory](docs/memory.md) | Why `-Xmx` does not bound chDB, and what does | | [ClassLoaders](docs/classloaders.md) | Tomcat, Spark, Flink: where to put the driver | | [Upstream findings](docs/upstream-findings.md) | Engine behaviours this binding works around, with reproductions | -| [V1 progress](docs/v1-progress.md) | Phase-by-phase status against the work plan, and what to do next | ## Building from source @@ -339,7 +316,6 @@ scripts/engine.properties the pinned engine version and its checksums scripts/fetch-libchdb.sh downloads and verifies the pinned engine scripts/build-native.sh builds the shim and stages a platform package scripts/verify-consumer.sh resolves the driver from a repository, outside this checkout -scripts/check-release-tag.sh refuses a release whose tag does not name the commit ``` ## Reporting a problem diff --git a/deploy/vercel-maven/.gitignore b/deploy/vercel-maven/.gitignore new file mode 100644 index 0000000..245259b --- /dev/null +++ b/deploy/vercel-maven/.gitignore @@ -0,0 +1,2 @@ +.vercel +.env* diff --git a/deploy/vercel-maven/README.md b/deploy/vercel-maven/README.md new file mode 100644 index 0000000..6e90bbe --- /dev/null +++ b/deploy/vercel-maven/README.md @@ -0,0 +1,37 @@ +# chDB public Maven repository gateway + +This Vercel project gives RC consumers the stable, anonymous repository URL +`https://maven.chdb.io`. Maven files live in the public `chdb-maven-blob` store; the gateway +rewrites `/com/...` to that store. + +The gateway deliberately disables Vercel's external-rewrite cache. Vercel Blob already caches +the immutable artifacts, while a second cache at the rewrite layer can incorrectly reuse one +HTTP Range response for a different range of the same large JAR. + +## Deploy the gateway + +The local directory is linked to the ClickHouse team project `chdb-maven`: + +```console +cd deploy/vercel-maven +npx --yes vercel@latest build --prod --scope clickhouse +npx --yes vercel@latest deploy --prebuilt --prod --scope clickhouse +``` + +## Publish an RC + +The `Maven RC release` workflow builds a `maven-repository` artifact. Download and publish it +from an account with Developer access to the ClickHouse Vercel team: + +```console +gh run download RUN_ID --name maven-repository --dir /tmp/chdb-maven-repository +cd deploy/vercel-maven +npx --yes vercel@latest link --project chdb-maven --scope clickhouse +npx --yes vercel@latest env pull .env.local --environment=development +cd ../.. +scripts/publish-rc-repository.sh /tmp/chdb-maven-repository +``` + +The environment file is ignored by Git. It supplies a short-lived Vercel OIDC credential; no +personal or long-lived Blob token is stored in GitHub. RC paths are immutable, and the upload +script refuses to overwrite an existing file. diff --git a/deploy/vercel-maven/index.html b/deploy/vercel-maven/index.html new file mode 100644 index 0000000..5ad212a --- /dev/null +++ b/deploy/vercel-maven/index.html @@ -0,0 +1,16 @@ + + + + + + chDB Maven repository + + +
+

chDB Maven repository

+

Public release-candidate artifacts for chDB Java.

+

Use https://maven.chdb.io as the repository URL. Authentication is not required.

+

Documentation and source

+
+ + diff --git a/deploy/vercel-maven/vercel.json b/deploy/vercel-maven/vercel.json new file mode 100644 index 0000000..3b2688e --- /dev/null +++ b/deploy/vercel-maven/vercel.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://openapi.vercel.sh/vercel.json", + "rewrites": [ + { + "source": "/com/:path*", + "destination": "https://ygrvrz9pslxmp8da.public.blob.vercel-storage.com/com/:path*" + } + ], + "headers": [ + { + "source": "/com/:path*", + "headers": [ + { + "key": "x-vercel-enable-rewrite-caching", + "value": "0" + }, + { + "key": "Vercel-CDN-Cache-Control", + "value": "no-store" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + } + ] + } + ] +} diff --git a/scripts/publish-rc-repository.sh b/scripts/publish-rc-repository.sh new file mode 100755 index 0000000..4154d7c --- /dev/null +++ b/scripts/publish-rc-repository.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +# Upload an already-staged Maven repository to the public chDB Vercel Blob store. +# Run `vercel env pull .env.local --environment=development` from +# deploy/vercel-maven immediately before this command so the short-lived OIDC +# credential is fresh. Published RC paths are immutable: this script never +# overwrites an existing blob. + +set -euo pipefail + +usage() { + printf 'Usage: %s [--dry-run] \n' "$(basename "$0")" >&2 + exit 2 +} + +DRY_RUN=false +if [[ ${1:-} == --dry-run ]]; then + DRY_RUN=true + shift +fi +[[ $# -eq 1 ]] || usage + +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +PROJECT_DIR=$(cd "$SCRIPT_DIR/.." && pwd) +GATEWAY_DIR="$PROJECT_DIR/deploy/vercel-maven" +REPOSITORY_DIR=$(cd "$1" && pwd) +ENV_FILE=${CHDB_VERCEL_ENV_FILE:-"$GATEWAY_DIR/.env.local"} + +[[ -d "$REPOSITORY_DIR/com/clickhouse/chdb" ]] || { + printf 'Expected com/clickhouse/chdb below %s\n' "$REPOSITORY_DIR" >&2 + exit 1 +} + +if find "$REPOSITORY_DIR" -type l -print -quit | grep -q .; then + printf 'Refusing to publish a repository containing symbolic links\n' >&2 + exit 1 +fi + +file_count=0 +while IFS= read -r -d '' file; do + relative=${file#"$REPOSITORY_DIR/"} + if [[ ! "$relative" =~ ^com/clickhouse/chdb/[^/]+/[^/]+/[^/]+\.(jar|pom)(\.(md5|sha1|sha256|sha512))?$ ]]; then + printf 'Refusing to publish a non-versioned Maven artifact path: %s\n' "$relative" >&2 + exit 1 + fi + file_count=$((file_count + 1)) +done < <(find "$REPOSITORY_DIR" -type f -print0) + +(( file_count > 0 )) || { + printf 'No files found below %s\n' "$REPOSITORY_DIR" >&2 + exit 1 +} + +if [[ "$DRY_RUN" == true ]]; then + printf 'Validated %d immutable Maven files below %s\n' "$file_count" "$REPOSITORY_DIR" + exit 0 +fi + +[[ -f "$ENV_FILE" ]] || { + printf 'Missing %s. Run these commands first:\n' "$ENV_FILE" >&2 + printf ' cd %q\n' "$GATEWAY_DIR" >&2 + printf ' npx --yes vercel@latest link --project chdb-maven --scope clickhouse\n' >&2 + printf ' npx --yes vercel@latest env pull .env.local --environment=development\n' >&2 + exit 1 +} + +set -a +# shellcheck disable=SC1090 +. "$ENV_FILE" +set +a + +: "${BLOB_STORE_ID:?BLOB_STORE_ID is missing from $ENV_FILE}" +: "${VERCEL_OIDC_TOKEN:?VERCEL_OIDC_TOKEN is missing from $ENV_FILE}" + +if command -v vercel >/dev/null 2>&1; then + VERCEL=(vercel) +else + VERCEL=(npx --yes vercel@latest) +fi + +printf 'Uploading %d immutable files to store %s\n' "$file_count" "$BLOB_STORE_ID" + +while IFS= read -r -d '' file; do + relative=${file#"$REPOSITORY_DIR/"} + "${VERCEL[@]}" blob put "$file" \ + --pathname "$relative" \ + --access public \ + --add-random-suffix false \ + --allow-overwrite false \ + --cache-control-max-age 31536000 \ + --multipart true \ + --store-id "$BLOB_STORE_ID" \ + --oidc-token "$VERCEL_OIDC_TOKEN" +done < <(find "$REPOSITORY_DIR" -type f -print0) + +printf 'Published %d files. Verify the RC from https://maven.chdb.io with a fresh Maven cache.\n' "$file_count" From 19cbad6b187bfe88244ad2996eee907b277ef3f2 Mon Sep 17 00:00:00 2001 From: Shawn Chen Date: Thu, 24 Sep 2026 09:29:19 +1200 Subject: [PATCH 2/3] Make RC uploads rollback-safe --- deploy/vercel-maven/README.md | 5 +- scripts/publish-rc-repository.sh | 102 ++++++++++++++++++++++++++++--- 2 files changed, 99 insertions(+), 8 deletions(-) diff --git a/deploy/vercel-maven/README.md b/deploy/vercel-maven/README.md index 6e90bbe..1e6efda 100644 --- a/deploy/vercel-maven/README.md +++ b/deploy/vercel-maven/README.md @@ -34,4 +34,7 @@ scripts/publish-rc-repository.sh /tmp/chdb-maven-repository The environment file is ignored by Git. It supplies a short-lived Vercel OIDC credential; no personal or long-lived Blob token is stored in GitHub. RC paths are immutable, and the upload -script refuses to overwrite an existing file. +script refuses to overwrite an existing file. Before writing anything, it checks every destination +path. If an upload fails or is interrupted, it removes the blobs written by that run so the complete +RC can be retried safely. If rollback itself fails, remove the paths reported by the script before +retrying; the next preflight will refuse to overwrite them. diff --git a/scripts/publish-rc-repository.sh b/scripts/publish-rc-repository.sh index 4154d7c..5173f7c 100755 --- a/scripts/publish-rc-repository.sh +++ b/scripts/publish-rc-repository.sh @@ -36,16 +36,19 @@ if find "$REPOSITORY_DIR" -type l -print -quit | grep -q .; then exit 1 fi -file_count=0 +FILES=() +RELATIVE_PATHS=() while IFS= read -r -d '' file; do relative=${file#"$REPOSITORY_DIR/"} if [[ ! "$relative" =~ ^com/clickhouse/chdb/[^/]+/[^/]+/[^/]+\.(jar|pom)(\.(md5|sha1|sha256|sha512))?$ ]]; then printf 'Refusing to publish a non-versioned Maven artifact path: %s\n' "$relative" >&2 exit 1 fi - file_count=$((file_count + 1)) + FILES+=("$file") + RELATIVE_PATHS+=("$relative") done < <(find "$REPOSITORY_DIR" -type f -print0) +file_count=${#FILES[@]} (( file_count > 0 )) || { printf 'No files found below %s\n' "$REPOSITORY_DIR" >&2 exit 1 @@ -78,10 +81,92 @@ else VERCEL=(npx --yes vercel@latest) fi +BLOB_AUTH_ARGS=( + --store-id "$BLOB_STORE_ID" + --oidc-token "$VERCEL_OIDC_TOKEN" +) + +blob_exists() { + local target=$1 + local output + + if ! output=$("${VERCEL[@]}" blob list \ + --prefix "$target" \ + --limit 1000 \ + --mode expanded \ + --no-color \ + "${BLOB_AUTH_ARGS[@]}"); then + printf 'Failed to check whether %s already exists\n' "$target" >&2 + return 2 + fi + + awk -v target="$target" ' + { + for (field = 1; field <= NF; field++) { + if ($field == target) { + found = 1 + } + } + } + END { exit found ? 0 : 1 } + ' <<<"$output" +} + +printf 'Checking %d destination paths before upload\n' "$file_count" +conflict_count=0 +for relative in "${RELATIVE_PATHS[@]}"; do + if blob_exists "$relative"; then + printf 'Refusing to overwrite existing blob: %s\n' "$relative" >&2 + conflict_count=$((conflict_count + 1)) + else + result=$? + (( result == 1 )) || exit "$result" + fi +done + +(( conflict_count == 0 )) || { + printf 'Preflight found %d existing destination path(s); nothing was uploaded\n' \ + "$conflict_count" >&2 + exit 1 +} + +UPLOADED_PATHS=() +uploaded_count=0 +rollback() { + local status=$1 + local rollback_failed=false + + trap - ERR INT TERM + set +e + + if (( uploaded_count > 0 )); then + printf 'Upload did not complete; removing %d blob(s) written by this run\n' \ + "$uploaded_count" >&2 + + for relative in "${UPLOADED_PATHS[@]}"; do + if ! "${VERCEL[@]}" blob del "$relative" "${BLOB_AUTH_ARGS[@]}"; then + printf 'Rollback failed for %s; remove it before retrying\n' "$relative" >&2 + rollback_failed=true + fi + done + fi + + if [[ "$rollback_failed" == true ]]; then + printf 'Rollback was incomplete; the next preflight will refuse to publish over remaining blobs\n' >&2 + fi + + exit "$status" +} + +trap 'rollback $?' ERR +trap 'rollback 130' INT +trap 'rollback 143' TERM + printf 'Uploading %d immutable files to store %s\n' "$file_count" "$BLOB_STORE_ID" -while IFS= read -r -d '' file; do - relative=${file#"$REPOSITORY_DIR/"} +for index in "${!FILES[@]}"; do + file=${FILES[$index]} + relative=${RELATIVE_PATHS[$index]} "${VERCEL[@]}" blob put "$file" \ --pathname "$relative" \ --access public \ @@ -89,8 +174,11 @@ while IFS= read -r -d '' file; do --allow-overwrite false \ --cache-control-max-age 31536000 \ --multipart true \ - --store-id "$BLOB_STORE_ID" \ - --oidc-token "$VERCEL_OIDC_TOKEN" -done < <(find "$REPOSITORY_DIR" -type f -print0) + "${BLOB_AUTH_ARGS[@]}" + UPLOADED_PATHS+=("$relative") + uploaded_count=$((uploaded_count + 1)) +done + +trap - ERR INT TERM printf 'Published %d files. Verify the RC from https://maven.chdb.io with a fresh Maven cache.\n' "$file_count" From 13042921d9f0d9f6a7369af6816b7f5c30d8a3fb Mon Sep 17 00:00:00 2001 From: Shawn Chen Date: Thu, 24 Sep 2026 09:54:33 +1200 Subject: [PATCH 3/3] Rollback RC uploads on SIGHUP --- scripts/publish-rc-repository.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/publish-rc-repository.sh b/scripts/publish-rc-repository.sh index 5173f7c..c6319bf 100755 --- a/scripts/publish-rc-repository.sh +++ b/scripts/publish-rc-repository.sh @@ -136,7 +136,7 @@ rollback() { local status=$1 local rollback_failed=false - trap - ERR INT TERM + trap - ERR HUP INT TERM set +e if (( uploaded_count > 0 )); then @@ -159,6 +159,7 @@ rollback() { } trap 'rollback $?' ERR +trap 'rollback 129' HUP trap 'rollback 130' INT trap 'rollback 143' TERM @@ -179,6 +180,6 @@ for index in "${!FILES[@]}"; do uploaded_count=$((uploaded_count + 1)) done -trap - ERR INT TERM +trap - ERR HUP INT TERM printf 'Published %d files. Verify the RC from https://maven.chdb.io with a fresh Maven cache.\n' "$file_count"