Repository navigation
ci(release): find the Windows DLL where CMake actually puts it #2
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Release tag (e.g., v1.0.0)' | |
| required: true | |
| type: string | |
| permissions: | |
| contents: write | |
| jobs: | |
| # =========================================================================== | |
| # Build pre-compiled C libraries for all supported platforms | |
| # =========================================================================== | |
| build-libs: | |
| name: Build (${{ matrix.name }}) | |
| runs-on: ${{ matrix.runner }} | |
| # The Linux leg runs inside the same manylinux_2_28 image upstream zvec uses | |
| # for its own prebuilt SDK (zvec/.github/workflows/_build_prebuilt.yml), so | |
| # the libzvec_c_api.so attached to the release still loads on glibc 2.28 | |
| # distros - CentOS 8, RHEL 8, Ubuntu 20.04. On the bare ubuntu-24.04 runner | |
| # it links glibc 2.39 and ends up demanding GLIBC_2.38. | |
| container: ${{ matrix.container || null }} | |
| # Longest observed leg is windows-x64 at ~1h11m. | |
| timeout-minutes: 150 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - name: darwin-arm64 | |
| runner: macos-15 | |
| platform: darwin_arm64 | |
| lib_name: libzvec_c_api.dylib | |
| artifact_name: zvec-libs-darwin-arm64 | |
| container: '' | |
| cache_abi: host | |
| - name: linux-x64 | |
| runner: ubuntu-24.04 | |
| platform: linux_amd64 | |
| lib_name: libzvec_c_api.so | |
| artifact_name: zvec-libs-linux-x64 | |
| # Pinned dated tag, the same batch upstream uses. | |
| container: 'quay.io/pypa/manylinux_2_28_x86_64:2026.03.01-1' | |
| cache_abi: manylinux_2_28 | |
| - name: linux-arm64 | |
| runner: ubuntu-24.04-arm | |
| platform: linux_arm64 | |
| lib_name: libzvec_c_api.so | |
| artifact_name: zvec-libs-linux-arm64 | |
| # Same image family upstream builds its aarch64 SDK in. | |
| container: 'quay.io/pypa/manylinux_2_28_aarch64:2026.03.01-1' | |
| cache_abi: manylinux_2_28 | |
| - name: windows-x64 | |
| runner: windows-2025 | |
| platform: windows_amd64 | |
| lib_name: zvec_c_api.dll | |
| artifact_name: zvec-libs-windows-x64 | |
| container: '' | |
| cache_abi: host | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| with: | |
| # A tag push already checks out the tag; a workflow_dispatch run | |
| # would otherwise check out the default branch and build libraries | |
| # that do not correspond to the tag they get attached to. | |
| ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }} | |
| submodules: recursive | |
| - name: Set up JDK 11 | |
| uses: actions/setup-java@v6 | |
| with: | |
| distribution: temurin | |
| java-version: '11' | |
| cache: maven | |
| # The manylinux image ships no Maven, and the runner's preinstalled | |
| # /usr/share/maven is not visible inside a container job. The linux leg | |
| # needs it for the "Verify Maven compile with vendor libs" step below. | |
| - name: Install Maven (Linux container) | |
| if: runner.os == 'Linux' | |
| shell: bash | |
| run: | | |
| MVN_VERSION=3.9.16 | |
| curl -fsSL "https://archive.apache.org/dist/maven/maven-3/${MVN_VERSION}/binaries/apache-maven-${MVN_VERSION}-bin.tar.gz" \ | |
| | tar -xz -C /opt | |
| echo "/opt/apache-maven-${MVN_VERSION}/bin" >> "$GITHUB_PATH" | |
| # --- Version-anchored cache (same key family as publish-jar.yml, so | |
| # both workflows share one cache): keyed by the zvec submodule commit | |
| # and the release tag, which is compiled into the library --- | |
| - name: Resolve zvec submodule commit and version | |
| id: zvec | |
| shell: bash | |
| run: | | |
| echo "sha=$(git -C zvec rev-parse HEAD)" >> "$GITHUB_OUTPUT" | |
| # zvec/cmake/version.cmake derives the version from `git describe | |
| # --tags` and otherwise falls back to a deliberately obvious dummy | |
| # v0.0.0. In CI that fallback always wins, because the submodule is | |
| # checked out detached and without tags - so the released library | |
| # used to report v0.0.0-g<sha> through Zvec.getVersion(), and 0.0.0 | |
| # through getVersionMajor/Minor/Patch. Feed the release tag in | |
| # explicitly, the way upstream zvec does in _build_prebuilt.yml. | |
| # Anything that is not a vX.Y.Z string is dropped rather than passed | |
| # on: version.cmake raises FATAL_ERROR on a malformed override. | |
| TAG="${{ inputs.tag || github.ref_name }}" | |
| case "$TAG" in v*) ;; *) TAG="v$TAG" ;; esac | |
| if printf '%s' "$TAG" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+'; then | |
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "::warning::'$TAG' is not a vX.Y.Z version; the native build will report zvec's fallback version" | |
| echo "tag=" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Restore zvec build cache | |
| id: cache-zvec | |
| uses: actions/cache/restore@v6 | |
| with: | |
| path: zvec/build | |
| # cache_abi keeps the host-glibc and manylinux build trees apart, and | |
| # the tag keeps builds with different OVERRIDE_GIT_DESCRIBE values | |
| # apart, since that string is compiled into the library. | |
| key: zvec-build-${{ matrix.name }}-${{ matrix.cache_abi }}-${{ steps.zvec.outputs.sha }}-${{ steps.zvec.outputs.tag }} | |
| # --- Unix build tools --- | |
| - name: Set up Python (for CMake / Ninja) | |
| if: runner.os == 'macOS' && steps.cache-zvec.outputs.cache-hit != 'true' | |
| uses: actions/setup-python@v7 | |
| with: | |
| python-version: '3.10' | |
| - name: Install build tools (Unix) | |
| if: runner.os != 'Windows' && steps.cache-zvec.outputs.cache-hit != 'true' | |
| run: | | |
| if [ "$(uname -s)" = "Linux" ]; then | |
| # setup-python is skipped inside the container: the CPython it | |
| # downloads is built for the host glibc and will not run in a | |
| # glibc 2.28 image. Use the bundled CPython instead, the same way | |
| # upstream zvec's _build_prebuilt.yml does. | |
| PYBIN=$(ls -d /opt/python/cp3*/bin | head -1) | |
| echo "$PYBIN" >> "$GITHUB_PATH" | |
| export PATH="$PYBIN:$PATH" | |
| fi | |
| python3 -m pip install --upgrade pip cmake==3.30.0 ninja==1.11.1 | |
| echo "$(python3 -c 'import site; print(site.USER_BASE)')/bin" >> "$GITHUB_PATH" | |
| shell: bash | |
| # --- Windows build tools --- | |
| - name: Set up MSVC (Windows) | |
| if: runner.os == 'Windows' | |
| uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1 (pinned by SHA; dependabot keeps it current) | |
| - name: Install CMake and Ninja (Windows) | |
| if: runner.os == 'Windows' && steps.cache-zvec.outputs.cache-hit != 'true' | |
| run: pip install cmake==3.30.0 ninja==1.11.1 | |
| shell: pwsh | |
| # --- Build C-API library (skipped on cache hit) --- | |
| - name: Build C-API library (Unix) | |
| if: runner.os != 'Windows' && steps.cache-zvec.outputs.cache-hit != 'true' | |
| env: | |
| ZVEC_TAG: ${{ steps.zvec.outputs.tag }} | |
| run: | | |
| NPROC=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 2) | |
| cd zvec | |
| mkdir -p build && cd build | |
| cmake .. \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DBUILD_C_BINDINGS=ON \ | |
| -DOVERRIDE_GIT_DESCRIBE="$ZVEC_TAG" \ | |
| -G Ninja | |
| cmake --build . -j$NPROC --target zvec_c_api | |
| touch .zvec-build-ok | |
| shell: bash | |
| - name: Build C-API library (Windows) | |
| if: runner.os == 'Windows' && steps.cache-zvec.outputs.cache-hit != 'true' | |
| env: | |
| ZVEC_TAG: ${{ steps.zvec.outputs.tag }} | |
| run: | | |
| cd zvec | |
| New-Item -ItemType Directory -Force -Path build | Out-Null | |
| cd build | |
| cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_C_BINDINGS=ON ` | |
| "-DOVERRIDE_GIT_DESCRIBE=$env:ZVEC_TAG" -G Ninja | |
| cmake --build . --target zvec_c_api -j $env:NUMBER_OF_PROCESSORS | |
| New-Item -ItemType File -Force -Path .zvec-build-ok | Out-Null | |
| shell: pwsh | |
| # Save as soon as the build is known good; the marker file is written | |
| # only by a successful build, so a later failure still leaves a reusable | |
| # cache. continue-on-error absorbs the 409 raised when a concurrent run | |
| # (e.g. a manual Publish JAR run sharing the same key) already stored it. | |
| - name: Save zvec build cache | |
| if: always() && steps.cache-zvec.outputs.cache-hit != 'true' && hashFiles('zvec/build/.zvec-build-ok') != '' | |
| uses: actions/cache/save@v6 | |
| continue-on-error: true | |
| with: | |
| path: zvec/build | |
| key: zvec-build-${{ matrix.name }}-${{ matrix.cache_abi }}-${{ steps.zvec.outputs.sha }}-${{ steps.zvec.outputs.tag }} | |
| # --- Package libraries --- | |
| - name: Package libraries (Unix) | |
| if: runner.os != 'Windows' | |
| run: | | |
| PLATFORM="${{ matrix.platform }}" | |
| mkdir -p staging/$PLATFORM staging/include/zvec | |
| # Copy shared library | |
| cp zvec/build/lib/${{ matrix.lib_name }} staging/$PLATFORM/ | |
| echo "✓ Copied ${{ matrix.lib_name }}" | |
| # Copy public header | |
| cp zvec/src/include/zvec/c_api.h staging/include/zvec/ | |
| echo "✓ Copied c_api.h" | |
| # Jieba dict: the jieba FTS tokenizer needs these files at runtime; | |
| # ship them under data/jieba_dict, mirroring the zvec SDK layout. | |
| mkdir -p staging/data/jieba_dict | |
| cp zvec/thirdparty/cppjieba/cppjieba-5.6.7/dict/jieba.dict.utf8 staging/data/jieba_dict/ | |
| cp zvec/thirdparty/cppjieba/cppjieba-5.6.7/dict/hmm_model.utf8 staging/data/jieba_dict/ | |
| echo "✓ Copied jieba dict" | |
| # Apache-2.0 4(d): this archive redistributes the zvec library and the | |
| # cppjieba dictionary, so it carries zvec's own license and attribution | |
| # notices along with them. | |
| cp zvec/LICENSE staging/LICENSE | |
| cp zvec/NOTICE staging/NOTICE | |
| echo "✓ Copied LICENSE + NOTICE" | |
| ls -la staging/$PLATFORM/ | |
| du -h staging/$PLATFORM/${{ matrix.lib_name }} | |
| shell: bash | |
| - name: Verify the linux library stays glibc 2.27 compatible | |
| if: runner.os == 'Linux' | |
| shell: bash | |
| run: | | |
| # The README advertises a glibc 2.27 floor (Ubuntu 18.04+, Debian 10+, | |
| # RHEL/CentOS 8+, Fedora 28+) and the manylinux_2_28 toolchain only | |
| # references symbols up to GLIBC_2.27 today, so pin exactly that. | |
| LIMIT=2.27 | |
| SO="staging/${{ matrix.platform }}/${{ matrix.lib_name }}" | |
| MAX=$(readelf -V "$SO" | grep -oE 'GLIBC_[0-9]+\.[0-9]+' | sed 's/GLIBC_//' | sort -uV | tail -1) | |
| echo "$SO: highest versioned GLIBC symbol = ${MAX:-none}" | |
| if [ -n "$MAX" ] && [ "$(printf '%s\n%s\n' "$MAX" "$LIMIT" | sort -V | tail -1)" != "$LIMIT" ]; then | |
| echo "::error::$SO requires GLIBC_$MAX but the documented floor is GLIBC_$LIMIT - either it was not built inside the manylinux_2_28 container, or zvec started using a newer symbol (raise LIMIT and the README floor together)" | |
| exit 1 | |
| fi | |
| - name: Package libraries (Windows) | |
| if: runner.os == 'Windows' | |
| # bash rather than pwsh: the same library is resolved in bash by the | |
| # Publish JAR workflow's "Resolve zvec lib directory" step, and Git Bash | |
| # is present on every Windows runner (the license guard below already | |
| # relies on it). One idiom for both workflows, and a failure here prints | |
| # what is actually on disk - under pwsh the runner's | |
| # ErrorActionPreference=stop made Write-Error end the step before the | |
| # diagnostic listing could run, so the first failure said only | |
| # "DLL not found". | |
| shell: bash | |
| run: | | |
| PLATFORM="${{ matrix.platform }}" | |
| mkdir -p "staging/$PLATFORM" staging/include/zvec | |
| # zvec's CMake sends RUNTIME output (.dll plus executables) to | |
| # build/bin and ARCHIVE/LIBRARY output (.lib, .so, .dylib) to | |
| # build/lib - see zvec/cmake/bazel.cmake - while a Release/ | |
| # subdirectory only exists with a multi-config generator. This | |
| # workflow builds with Ninja, so the DLL is in build/bin; search every | |
| # layout anyway and match on a wildcard so a suffixed name resolves. | |
| find_c_api() { | |
| for d in zvec/build/bin zvec/build/bin/Release zvec/build/lib zvec/build/lib/Release; do | |
| [ -d "$d" ] || continue | |
| find "$d" -maxdepth 1 -type f -name "*zvec_c_api*$1" 2>/dev/null | head -n1 | |
| done | |
| } | |
| DLL=$(find_c_api .dll | head -n1) | |
| if [ -z "$DLL" ]; then | |
| echo "::error::zvec_c_api DLL not found under zvec/build" | |
| find zvec/build \( -name '*.dll' -o -name '*.lib' \) -print 2>/dev/null | head -40 | |
| exit 1 | |
| fi | |
| cp "$DLL" "staging/$PLATFORM/" | |
| echo "✓ Copied DLL from $DLL" | |
| # Import library (.lib) - optional but useful for downstream C/C++ consumers | |
| LIB=$(find_c_api .lib | head -n1) | |
| if [ -n "$LIB" ]; then | |
| cp "$LIB" "staging/$PLATFORM/" | |
| echo "✓ Copied import lib from $LIB" | |
| fi | |
| # Public header | |
| cp zvec/src/include/zvec/c_api.h staging/include/zvec/ | |
| echo "✓ Copied c_api.h" | |
| # Jieba dict (mirrors the zvec SDK layout data/jieba_dict) | |
| mkdir -p staging/data/jieba_dict | |
| cp zvec/thirdparty/cppjieba/cppjieba-5.6.7/dict/jieba.dict.utf8 staging/data/jieba_dict/ | |
| cp zvec/thirdparty/cppjieba/cppjieba-5.6.7/dict/hmm_model.utf8 staging/data/jieba_dict/ | |
| echo "✓ Copied jieba dict" | |
| # Apache-2.0 4(d): carry zvec's license and attribution notices. | |
| cp zvec/LICENSE staging/LICENSE | |
| cp zvec/NOTICE staging/NOTICE | |
| echo "✓ Copied LICENSE + NOTICE" | |
| ls -la "staging/$PLATFORM/" | |
| # --- License guard --- | |
| # The archives attached to the GitHub Release carry the same zvec_c_api | |
| # binary as the Maven Central JARs, so they get the same check. | |
| - name: Verify no GPL-only RocksDB code is linked into the library | |
| shell: bash | |
| run: | | |
| # RocksDB is dual-licensed Apache-2.0 / GPLv2 and is shipped here under | |
| # Apache-2.0. Its PerconaFT-derived range_tree lock manager | |
| # (utilities/transactions/lock/range/) is the only GPL-exclusive part, | |
| # and zvec never uses pessimistic transactions, so the linker drops | |
| # those objects. grep -a rather than strings/readelf/objdump: grep is | |
| # available on every runner (Git Bash on Windows) and works on ELF, | |
| # Mach-O and PE alike. | |
| SO="staging/${{ matrix.platform }}/${{ matrix.lib_name }}" | |
| GPL_PATTERN='range_tree|locktree|RangeTree|PessimisticTransaction|percona' | |
| if [ ! -f "$SO" ]; then | |
| echo "::error::$SO is missing - nothing to license-check" | |
| exit 1 | |
| fi | |
| HITS=$(grep -a -i -c -E "$GPL_PATTERN" "$SO" || true) | |
| echo "$SO: GPL-only RocksDB symbol hits = $HITS" | |
| if [ "$HITS" != "0" ]; then | |
| echo "::error::$SO links the GPL-only RocksDB range_tree code ($HITS hits) and cannot ship under Apache-2.0" | |
| exit 1 | |
| fi | |
| # Positive control: prove the scan really looked at the RocksDB-bearing | |
| # runtime library, so a renamed or empty file cannot pass as clean. | |
| ROCKS=$(grep -a -c -E 'rocksdb' "$SO" || true) | |
| echo "$SO: rocksdb hits = $ROCKS (expected > 0)" | |
| if [ "$ROCKS" -eq 0 ]; then | |
| echo "::error::$SO carries no RocksDB symbols - the scan is not looking at the real library" | |
| exit 1 | |
| fi | |
| # --- Verify Maven build compiles against staged vendor libs --- | |
| - name: Verify Maven compile with vendor libs (Unix) | |
| if: runner.os != 'Windows' | |
| run: | | |
| PLATFORM="${{ matrix.platform }}" | |
| mkdir -p lib/$PLATFORM lib/include/zvec | |
| cp staging/$PLATFORM/* lib/$PLATFORM/ | |
| cp staging/include/zvec/c_api.h lib/include/zvec/ | |
| LIB_PATH="${{ github.workspace }}/lib/$PLATFORM" | |
| mvn compile -Dzvec.lib.path="$LIB_PATH" -B | |
| echo "✓ Maven compile succeeded with vendor libraries" | |
| shell: bash | |
| - name: Verify Maven compile with vendor libs (Windows) | |
| if: runner.os == 'Windows' | |
| run: | | |
| $platform = "${{ matrix.platform }}" | |
| New-Item -ItemType Directory -Force -Path "lib/$platform" | Out-Null | |
| New-Item -ItemType Directory -Force -Path "lib/include/zvec" | Out-Null | |
| Copy-Item "staging/$platform/*" "lib/$platform/" | |
| Copy-Item "staging/include/zvec/c_api.h" "lib/include/zvec/" | |
| $libPath = "${{ github.workspace }}\lib\$platform" | |
| $env:PATH = "$libPath;$env:PATH" | |
| mvn compile "-Dzvec.lib.path=$libPath" -B | |
| Write-Host "✓ Maven compile succeeded with vendor libraries" | |
| shell: pwsh | |
| # --- Create release archive --- | |
| - name: Create archive (Unix) | |
| if: runner.os != 'Windows' | |
| run: | | |
| cd staging | |
| tar -czf ../${{ matrix.artifact_name }}.tar.gz . | |
| cd .. | |
| sha256sum ${{ matrix.artifact_name }}.tar.gz > ${{ matrix.artifact_name }}.tar.gz.sha256 | |
| echo "=== Archive ===" | |
| ls -la ${{ matrix.artifact_name }}.tar.gz | |
| cat ${{ matrix.artifact_name }}.tar.gz.sha256 | |
| shell: bash | |
| - name: Create archive (Windows) | |
| if: runner.os == 'Windows' | |
| run: | | |
| cd staging | |
| Compress-Archive -Path * -DestinationPath ..\${{ matrix.artifact_name }}.zip | |
| cd .. | |
| $hash = (Get-FileHash "${{ matrix.artifact_name }}.zip" -Algorithm SHA256).Hash.ToLower() | |
| "$hash ${{ matrix.artifact_name }}.zip" | Out-File -Encoding ascii "${{ matrix.artifact_name }}.zip.sha256" | |
| Write-Host "=== Archive ===" | |
| Get-ChildItem "${{ matrix.artifact_name }}.zip" | |
| Get-Content "${{ matrix.artifact_name }}.zip.sha256" | |
| shell: pwsh | |
| # --- Upload artifact for the release job --- | |
| - name: Upload artifact (Unix) | |
| if: runner.os != 'Windows' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ${{ matrix.artifact_name }} | |
| path: | | |
| ${{ matrix.artifact_name }}.tar.gz | |
| ${{ matrix.artifact_name }}.tar.gz.sha256 | |
| - name: Upload artifact (Windows) | |
| if: runner.os == 'Windows' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ${{ matrix.artifact_name }} | |
| path: | | |
| ${{ matrix.artifact_name }}.zip | |
| ${{ matrix.artifact_name }}.zip.sha256 | |
| # =========================================================================== | |
| # NOTE: the Maven JAR build & Central deployment intentionally live in the | |
| # standalone "Publish JAR" workflow (.github/workflows/publish-jar.yml), | |
| # which is manual-only. Once this release looks good, run it by hand with | |
| # the same tag to build the JAR family and (opt-in) deploy to Maven Central. | |
| # =========================================================================== | |
| # =========================================================================== | |
| # Create GitHub Release with all platform libraries | |
| # =========================================================================== | |
| release: | |
| name: Create Release | |
| needs: [ build-libs ] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| with: | |
| # Same ref as build-libs, so the release notes and the checksums are | |
| # generated from the commit that was actually built. | |
| ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }} | |
| - name: Determine tag | |
| id: tag | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| echo "tag=${{ inputs.tag }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT | |
| fi | |
| shell: bash | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: ./artifacts | |
| - name: List artifacts | |
| run: | | |
| echo "=== Downloaded artifacts ===" | |
| find ./artifacts -type f | sort | |
| shell: bash | |
| - name: Generate release notes | |
| id: notes | |
| run: | | |
| TAG="${{ steps.tag.outputs.tag }}" | |
| VERSION="${TAG#v}" | |
| cat > release-notes.md << EOF | |
| ## zvec-java ${TAG} | |
| Industrial-grade Java bindings for the [Zvec](https://github.com/alibaba/zvec) vector database C API. | |
| ### Pre-built C Libraries | |
| Download the archive for your platform and extract it to the \`lib/\` directory of your project: | |
| | Platform | Archive | Architecture | | |
| |----------|---------|--------------| | |
| | **macOS** | \`zvec-libs-darwin-arm64.tar.gz\` | Apple Silicon (arm64) | | |
| | **Linux** | \`zvec-libs-linux-x64.tar.gz\` | x86-64 | | |
| | **Windows** | \`zvec-libs-windows-x64.zip\` | x86-64 | | |
| ### Maven JAR | |
| The JAR family (multi-platform fat JAR, per-platform classifier JARs, nolib JAR) is | |
| published separately from this release: run the **Publish JAR** workflow manually with | |
| the tag \`${TAG}\` once this release has been verified. Afterwards the artifacts are | |
| available from Maven Central. | |
| ### Maven Dependency | |
| \`\`\`xml | |
| <dependency> | |
| <groupId>org.zvec</groupId> | |
| <artifactId>zvec-java</artifactId> | |
| <version>${VERSION}</version> | |
| </dependency> | |
| \`\`\` | |
| ### Quick Start | |
| \`\`\`bash | |
| # Extract pre-built library to lib/<platform>/ | |
| tar -xzf zvec-libs-linux-x64.tar.gz -C lib/ | |
| # Run with vendor library | |
| mvn test -Dzvec.lib.path=lib/linux_amd64 | |
| \`\`\` | |
| ### SHA-256 Checksums | |
| See the \`.sha256\` files attached to this release for verification. | |
| EOF | |
| echo "notes_file=release-notes.md" >> $GITHUB_OUTPUT | |
| shell: bash | |
| - name: Collect release assets | |
| run: | | |
| mkdir -p release-assets | |
| # Platform libraries | |
| find ./artifacts -name "*.tar.gz" -o -name "*.tar.gz.sha256" \ | |
| -o -name "*.zip" -o -name "*.zip.sha256" | while read f; do | |
| cp "$f" release-assets/ | |
| done | |
| echo "=== Release assets ===" | |
| ls -lh release-assets/ | |
| shell: bash | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3 (pinned by SHA; it publishes with contents:write) | |
| with: | |
| tag_name: ${{ steps.tag.outputs.tag }} | |
| name: "zvec-java ${{ steps.tag.outputs.tag }}" | |
| body_path: release-notes.md | |
| draft: false | |
| prerelease: ${{ contains(steps.tag.outputs.tag, '-') }} | |
| files: release-assets/* | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |