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: Build and publish release packages | |
| permissions: | |
| contents: write | |
| packages: write | |
| on: | |
| release: | |
| # 'published' is triggered when publishing draft release, 'created' is not | |
| types: [published] | |
| env: | |
| # phase34 / #320 — CI starts cold, so incremental compilation | |
| # only adds artifacts and slows the build (Rust perf-team: | |
| # https://kobzol.github.io/rust/rustc/2025/05/20/disable-debuginfo-to-improve-rust-compile-times.html). | |
| CARGO_INCREMENTAL: "0" | |
| jobs: | |
| # Build dashboard first - shared by all jobs | |
| build-dashboard: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Install pnpm | |
| run: npm install -g pnpm | |
| - name: Set version from release tag | |
| run: echo "VITE_APP_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV | |
| - name: Build dashboard | |
| run: | | |
| cd dashboard | |
| pnpm install --frozen-lockfile | |
| pnpm build | |
| - name: Upload dashboard artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: dashboard-dist | |
| path: dashboard/dist | |
| retention-days: 1 | |
| # Separated Linux builds - each runs independently | |
| # If one fails, others continue | |
| build-linux-x86_64-gnu: | |
| needs: build-dashboard | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Download dashboard artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dashboard-dist | |
| path: dashboard/dist | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y gcc-multilib clang cmake protobuf-compiler libssl-dev pkg-config | |
| rustup default stable | |
| rustup update | |
| - name: Override leaked Windows OPENSSL_DIR (point at system libssl) | |
| # The ubuntu-latest GH-hosted runner image leaks | |
| # OPENSSL_DIR=C:/Program Files/OpenSSL-Win64 (and | |
| # OPENSSL_NO_VENDOR=1) into Linux jobs, which together make | |
| # openssl-sys's build script panic with "OpenSSL include | |
| # directory does not exist" before the vendored-openssl | |
| # feature can take over. Point at the system libssl-dev | |
| # install instead -- same fix applied to rust.yml in 7fad253d. | |
| run: | | |
| echo "OPENSSL_DIR=/usr" >> $GITHUB_ENV | |
| echo "OPENSSL_INCLUDE_DIR=/usr/include" >> $GITHUB_ENV | |
| echo "OPENSSL_LIB_DIR=/usr/lib/x86_64-linux-gnu" >> $GITHUB_ENV | |
| echo "PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig" >> $GITHUB_ENV | |
| shell: bash | |
| - name: Build and publish vectorizer | |
| uses: taiki-e/upload-rust-binary-action@v1 | |
| with: | |
| bin: vectorizer | |
| target: x86_64-unknown-linux-gnu | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and publish vectorizer-cli | |
| uses: taiki-e/upload-rust-binary-action@v1 | |
| with: | |
| bin: vectorizer-cli | |
| target: x86_64-unknown-linux-gnu | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| # Linux glibc binaries for Docker: amd64 em ubuntu-latest, arm64 em ubuntu-22.04-arm (glibc 2.35 = compatível com distroless Debian 12 / glibc 2.36) | |
| build-linux-gnu-for-docker: | |
| needs: build-dashboard | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - arch: amd64 | |
| runner: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| lib_dir: x86_64-linux-gnu | |
| - arch: arm64 | |
| # ubuntu-22.04-arm ships glibc 2.35; the prebuilt | |
| # ONNX Runtime that `ort-sys` pulls in references | |
| # `__isoc23_strtol` (glibc 2.38+) and `__cxa_call_terminate` | |
| # (newer libstdc++), so the link step fails with | |
| # `undefined reference`. ubuntu-24.04-arm has glibc 2.39 | |
| # plus a libstdc++ that resolves both symbols. | |
| runner: ubuntu-24.04-arm | |
| target: aarch64-unknown-linux-gnu | |
| lib_dir: aarch64-linux-gnu | |
| runs-on: ${{ matrix.runner }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Download dashboard artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dashboard-dist | |
| path: dashboard/dist | |
| - name: Install dependencies | |
| env: | |
| MATRIX_TARGET: ${{ matrix.target }} | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y gcc clang cmake protobuf-compiler libssl-dev pkg-config | |
| rustup default stable | |
| rustup update | |
| rustup target add "$MATRIX_TARGET" | |
| - name: Override leaked Windows OPENSSL_DIR (point at system libssl) | |
| # See comment on the same step in build-linux-x86_64-gnu above. | |
| # `lib_dir` is matrix-driven so the arm64 runner finds | |
| # /usr/lib/aarch64-linux-gnu instead of the amd64 path. | |
| env: | |
| MATRIX_LIB_DIR: ${{ matrix.lib_dir }} | |
| run: | | |
| echo "OPENSSL_DIR=/usr" >> $GITHUB_ENV | |
| echo "OPENSSL_INCLUDE_DIR=/usr/include" >> $GITHUB_ENV | |
| echo "OPENSSL_LIB_DIR=/usr/lib/$MATRIX_LIB_DIR" >> $GITHUB_ENV | |
| echo "PKG_CONFIG_PATH=/usr/lib/$MATRIX_LIB_DIR/pkgconfig" >> $GITHUB_ENV | |
| shell: bash | |
| - name: Build (gnu) | |
| # Drop the bogus `--features vendored-openssl` -- vectorizer-server | |
| # has no such feature, and now that the leaked OPENSSL_DIR is | |
| # overridden we link against the system libssl-dev installed | |
| # above. Drop `--no-default-features` since vectorizer-server | |
| # has no relevant defaults (only the opt-in `s2s-tests`). | |
| env: | |
| MATRIX_TARGET: ${{ matrix.target }} | |
| run: cargo build --release --target "$MATRIX_TARGET" --bin vectorizer | |
| - name: Prepare binary for artifact | |
| run: | | |
| mkdir -p binaries/linux-${{ matrix.arch }} | |
| cp target/${{ matrix.target }}/release/vectorizer binaries/linux-${{ matrix.arch }}/ | |
| chmod +x binaries/linux-${{ matrix.arch }}/vectorizer | |
| - name: Upload linux binary for Docker | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: linux-binaries-${{ matrix.arch }} | |
| path: binaries/linux-${{ matrix.arch }} | |
| retention-days: 1 | |
| # build-linux-aarch64-musl: removed in v3.0.8. | |
| # | |
| # The aarch64 musl artifact has been a perennial release blocker: | |
| # `cross` auto-forwards the GH-runner's leaked Win64 | |
| # OPENSSL_DIR=C:/Program Files/OpenSSL-Win64 into its container even | |
| # after the workflow `unset`s it and Cross.toml passthrough is empty, | |
| # so openssl-sys panics before vendored-openssl can run. Fixing it | |
| # properly means either patching the cross image (Dockerfile.aarch64- | |
| # unknown-linux-musl above) to ENV-clear OPENSSL_DIR, or replacing | |
| # cross with a native ubuntu-24.04-arm + musl-tools build. Both are | |
| # tracked separately; the rest of the matrix (amd64 GNU + Docker | |
| # multi-arch + Apple Silicon plain + Apple Silicon Metal + Windows) | |
| # ships every other release target. | |
| build-mac-binaries: | |
| needs: build-dashboard | |
| strategy: | |
| matrix: | |
| # x86_64-apple-darwin used to live here; dropped because | |
| # `ort-sys` (transitive via the `fastembed` default feature) | |
| # ships no prebuilt for Intel Mac and the workflow has no | |
| # `ORT_STRATEGY=compile` plumbing. Apple Silicon is the only | |
| # supported macOS target now -- the sibling | |
| # `build-mac-metal-binaries` job covers the same target with | |
| # Metal GPU support. | |
| include: | |
| - target: aarch64-apple-darwin | |
| os: macos-latest | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Download dashboard artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dashboard-dist | |
| path: dashboard/dist | |
| - name: Install dependencies | |
| run: | | |
| brew update-reset | |
| brew install gcc cmake protobuf | |
| rustup default stable | |
| rustup update | |
| rustup show | |
| cargo -Vv | |
| - name: Build and publish vectorizer | |
| uses: taiki-e/upload-rust-binary-action@v1 | |
| with: | |
| bin: vectorizer | |
| target: ${{ matrix.target }} | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and publish vectorizer-cli | |
| uses: taiki-e/upload-rust-binary-action@v1 | |
| with: | |
| bin: vectorizer-cli | |
| target: ${{ matrix.target }} | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| build-mac-metal-binaries: | |
| needs: build-dashboard | |
| name: Build macOS ARM with Metal GPU support | |
| strategy: | |
| matrix: | |
| include: | |
| - target: aarch64-apple-darwin | |
| os: macos-latest | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Download dashboard artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dashboard-dist | |
| path: dashboard/dist | |
| - name: Install dependencies | |
| run: | | |
| brew update-reset | |
| brew install gcc cmake protobuf | |
| rustup default stable | |
| rustup update | |
| rustup target add ${{ matrix.target }} | |
| rustup show | |
| cargo -Vv | |
| # Tag separado para Mac com Metal: asset nomeado vectorizer-*-metal (resto = manifesto automático) | |
| - name: Build vectorizer with Metal support | |
| uses: taiki-e/upload-rust-binary-action@v1 | |
| with: | |
| bin: vectorizer | |
| target: ${{ matrix.target }} | |
| features: hive-gpu | |
| archive: vectorizer-${{ matrix.target }}-metal | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build vectorizer-cli with Metal support | |
| uses: taiki-e/upload-rust-binary-action@v1 | |
| with: | |
| bin: vectorizer-cli | |
| target: ${{ matrix.target }} | |
| features: hive-gpu | |
| archive: vectorizer-cli-${{ matrix.target }}-metal | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| build-windows-binaries: | |
| needs: build-dashboard | |
| strategy: | |
| matrix: | |
| include: | |
| - os: windows-latest | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - name: Install minimal stable | |
| uses: dtolnay/rust-toolchain@stable | |
| - uses: actions/checkout@v7 | |
| - name: Download dashboard artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dashboard-dist | |
| path: dashboard/dist | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Install protoc | |
| shell: pwsh | |
| run: | | |
| # Chocolatey mirror returns flaky 503s — retry up to 3 times. | |
| $ok = $false | |
| for ($i = 1; $i -le 3; $i++) { | |
| choco install protoc -y --no-progress | |
| if ($LASTEXITCODE -eq 0) { $ok = $true; break } | |
| Write-Host "choco install protoc attempt $i failed; sleeping 15s" | |
| Start-Sleep -Seconds 15 | |
| } | |
| if (-not $ok) { Write-Error "protoc install failed after 3 attempts"; exit 1 } | |
| - name: Build | |
| run: cargo build --release | |
| - name: Build and publish vectorizer | |
| uses: taiki-e/upload-rust-binary-action@v1 | |
| with: | |
| bin: vectorizer | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and publish vectorizer-cli | |
| uses: taiki-e/upload-rust-binary-action@v1 | |
| with: | |
| bin: vectorizer-cli | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| # Docker: per-arch single-platform image build on a NATIVE runner (no | |
| # QEMU emulation), pushed by digest. The sibling | |
| # `publish-docker-manifest` job downstream stitches both digests into a | |
| # single multi-arch manifest list and pushes the human-readable tags | |
| # to both ghcr.io (always) and `hivehub/vectorizer` on Docker Hub | |
| # (gated on `DOCKERHUB_USERNAME` + `DOCKERHUB_TOKEN` repo secrets). | |
| # | |
| # See `docs/development/docker-builds.md` for the full pipeline | |
| # diagram and the rationale (phase10_optimize-docker-build-time). | |
| publish-docker: | |
| needs: | |
| - build-dashboard | |
| - build-linux-gnu-for-docker | |
| - build-linux-x86_64-gnu | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - arch: amd64 | |
| runner: ubuntu-latest | |
| platform: linux/amd64 | |
| - arch: arm64 | |
| runner: ubuntu-24.04-arm | |
| platform: linux/arm64 | |
| runs-on: ${{ matrix.runner }} | |
| env: | |
| DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} | |
| permissions: | |
| contents: read | |
| packages: write | |
| id-token: write # required for SLSA provenance attestation | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Download dashboard artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dashboard-dist | |
| path: dashboard/dist | |
| - name: Download Linux binary (${{ matrix.arch }}) | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: linux-binaries-${{ matrix.arch }} | |
| path: binaries/linux-${{ matrix.arch }} | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Set version from tag | |
| id: version | |
| run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT" | |
| - name: Login to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.repository_owner }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Login to Docker Hub | |
| if: env.DOCKERHUB_USERNAME != '' | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Build and push by digest (${{ matrix.platform }}) | |
| id: build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: ./docker/Dockerfile.artifacts | |
| push: true | |
| platforms: ${{ matrix.platform }} | |
| # Push by digest (no tag) — the manifest job below assembles | |
| # the human-readable tags from these digests. | |
| outputs: type=image,name=ghcr.io/${{ github.repository }},push-by-digest=true,name-canonical=true,push=true | |
| provenance: mode=max | |
| sbom: true | |
| build-args: | | |
| GIT_COMMIT_ID=${{ steps.version.outputs.VERSION }} | |
| BUILD_DATE=${{ github.event.release.published_at }} | |
| # GHA cache scoped per-arch so amd64 and arm64 don't fight | |
| # for the same cache key. | |
| cache-from: type=gha,scope=docker-${{ matrix.arch }} | |
| cache-to: type=gha,mode=max,scope=docker-${{ matrix.arch }} | |
| - name: Export digest | |
| run: | | |
| mkdir -p /tmp/digests | |
| digest="${{ steps.build.outputs.digest }}" | |
| touch "/tmp/digests/${digest#sha256:}" | |
| - name: Upload digest | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: docker-digest-${{ matrix.arch }} | |
| path: /tmp/digests/* | |
| if-no-files-found: error | |
| retention-days: 1 | |
| # Manifest list assembly: stitches the per-arch digests pushed by the | |
| # matrix job above into a single multi-arch manifest list, tags it | |
| # on both ghcr.io and (when secrets are configured) Docker Hub. Final | |
| # step runs `docker scout policy` against the published manifest as a | |
| # supply-chain gate — fails the workflow on policy regression. | |
| publish-docker-manifest: | |
| needs: publish-docker | |
| runs-on: ubuntu-latest | |
| env: | |
| DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Download digests | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: /tmp/digests | |
| pattern: docker-digest-* | |
| merge-multiple: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Login to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.repository_owner }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Login to Docker Hub | |
| if: env.DOCKERHUB_USERNAME != '' | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Docker metadata (ghcr.io) | |
| id: meta-ghcr | |
| uses: docker/metadata-action@v6 | |
| with: | |
| images: ghcr.io/${{ github.repository }} | |
| tags: | | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| - name: Docker metadata (Docker Hub) | |
| id: meta-hub | |
| if: env.DOCKERHUB_USERNAME != '' | |
| uses: docker/metadata-action@v6 | |
| with: | |
| images: hivehub/vectorizer | |
| tags: | | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| - name: Create manifest list (ghcr.io) | |
| working-directory: /tmp/digests | |
| run: | | |
| docker buildx imagetools create \ | |
| $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
| $(printf 'ghcr.io/${{ github.repository }}@sha256:%s ' *) | |
| env: | |
| DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta-ghcr.outputs.json }} | |
| - name: Create manifest list (Docker Hub) | |
| if: env.DOCKERHUB_USERNAME != '' | |
| working-directory: /tmp/digests | |
| # Same per-arch digests as the ghcr.io step — buildx | |
| # imagetools transparently re-tags / cross-pushes the manifest | |
| # list to the Docker Hub repo without re-uploading layers. | |
| run: | | |
| docker buildx imagetools create \ | |
| $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
| $(printf 'ghcr.io/${{ github.repository }}@sha256:%s ' *) | |
| env: | |
| DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta-hub.outputs.json }} | |
| - name: Inspect manifest list | |
| run: | | |
| PRIMARY=$(jq -cr '.tags[0]' <<< "${{ steps.meta-ghcr.outputs.json }}") | |
| docker buildx imagetools inspect "$PRIMARY" | |
| - name: Resolve published version tag | |
| id: version | |
| # The release tag arrives as `refs/tags/v3.x.y`; strip the `v` | |
| # to match the metadata-action's `{{version}}` output, which is | |
| # what both ghcr.io and Docker Hub were tagged with above. | |
| run: | | |
| ref="${GITHUB_REF#refs/tags/}" | |
| echo "VERSION=${ref#v}" >> "$GITHUB_OUTPUT" | |
| - name: Docker Scout policy gate | |
| if: env.DOCKERHUB_USERNAME != '' | |
| uses: docker/scout-action@v1 | |
| with: | |
| command: policy | |
| image: hivehub/vectorizer:${{ steps.version.outputs.VERSION }} | |
| organization: hivehub | |
| platform: linux/amd64 | |
| exit-code: true | |
| dockerhub-user: ${{ secrets.DOCKERHUB_USERNAME }} | |
| dockerhub-password: ${{ secrets.DOCKERHUB_TOKEN }} |