ci(release): add static ONNX Runtime build for macOS x86_64 #45
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: | |
| - '[0-9]+.[0-9]+.[0-9]+*' # Matches semver tags like 0.1.0, 1.0.0, etc. | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Tag to release (semver format, e.g., 0.1.0)' | |
| required: true | |
| type: string | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_BACKTRACE: 1 | |
| jobs: | |
| create-release: | |
| name: Create Release | |
| runs-on: ubuntu-latest | |
| outputs: | |
| upload_url: ${{ steps.create_release.outputs.upload_url }} | |
| release_id: ${{ steps.create_release.outputs.id }} | |
| version: ${{ steps.get_version.outputs.VERSION }} | |
| changelog: ${{ steps.changelog.outputs.CHANGELOG }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # Fetch full history for changelog generation | |
| - name: Get version from tag | |
| id: get_version | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| VERSION="${{ github.event.inputs.tag }}" | |
| else | |
| VERSION="${GITHUB_REF#refs/tags/}" | |
| fi | |
| echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT | |
| echo "VERSION_NO_V=${VERSION#v}" >> $GITHUB_OUTPUT | |
| - name: Validate semver format | |
| run: | | |
| VERSION="${{ steps.get_version.outputs.VERSION }}" | |
| # POSIX-compatible regex check for semver | |
| case "$VERSION" in | |
| [0-9]*.[0-9]*.[0-9]*) | |
| # Basic semver format matched | |
| ;; | |
| *) | |
| echo "Error: Tag '$VERSION' is not a valid semver format" | |
| echo "Expected format: X.Y.Z, X.Y.Z-prerelease, or X.Y.Z+build" | |
| exit 1 | |
| ;; | |
| esac | |
| - name: Generate changelog | |
| id: changelog | |
| run: | | |
| # Get the previous tag | |
| PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") | |
| if [ -z "$PREV_TAG" ]; then | |
| CHANGELOG="Initial release" | |
| else | |
| # Generate changelog from commits since last tag | |
| CHANGELOG=$(git log ${PREV_TAG}..HEAD --pretty=format:"- %s" --no-merges | head -20) | |
| if [ -z "$CHANGELOG" ]; then | |
| CHANGELOG="- No changes since last release" | |
| fi | |
| fi | |
| # Escape for GitHub output (POSIX compatible) | |
| CHANGELOG=$(printf '%s\n' "$CHANGELOG" | sed 's/%/%25/g; s/\r/%0D/g' | awk '{printf "%s%0A", $0}' | sed 's/%0A$//') | |
| echo "CHANGELOG=$CHANGELOG" >> $GITHUB_OUTPUT | |
| - name: Check if release exists | |
| id: check_release | |
| run: | | |
| VERSION="${{ steps.get_version.outputs.VERSION }}" | |
| if gh release view "$VERSION" >/dev/null 2>&1; then | |
| echo "exists=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "exists=false" >> $GITHUB_OUTPUT | |
| fi | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create Release | |
| id: create_release | |
| if: steps.check_release.outputs.exists == 'false' | |
| run: | | |
| VERSION="${{ steps.get_version.outputs.version }}" | |
| IS_PRERELEASE="false" | |
| # Check if this is a prerelease (contains - or is 0.x.x) | |
| case "$VERSION" in | |
| *-*|0.*) | |
| IS_PRERELEASE="true" | |
| ;; | |
| esac | |
| # Create the release as draft | |
| if [ "$IS_PRERELEASE" = "true" ]; then | |
| gh release create "$VERSION" \ | |
| --title "Release $VERSION" \ | |
| --notes "${{ steps.changelog.outputs.CHANGELOG }}" \ | |
| --draft \ | |
| --prerelease | |
| else | |
| gh release create "$VERSION" \ | |
| --title "Release $VERSION" \ | |
| --notes "${{ steps.changelog.outputs.CHANGELOG }}" \ | |
| --draft | |
| fi | |
| # Get release info | |
| RELEASE_INFO=$(gh release view "$VERSION" --json id,uploadUrl) | |
| RELEASE_ID=$(echo "$RELEASE_INFO" | jq -r '.id') | |
| UPLOAD_URL=$(echo "$RELEASE_INFO" | jq -r '.uploadUrl') | |
| echo "id=${RELEASE_ID}" >> $GITHUB_OUTPUT | |
| echo "upload_url=${UPLOAD_URL}" >> $GITHUB_OUTPUT | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| build: | |
| name: Build ${{ matrix.target }} | |
| needs: create-release | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - target: x86_64-unknown-linux-musl | |
| os: ubuntu-latest | |
| archive: tar.gz | |
| - target: aarch64-unknown-linux-musl | |
| os: ubuntu-22.04-arm | |
| archive: tar.gz | |
| - target: x86_64-pc-windows-msvc | |
| os: windows-latest | |
| archive: zip | |
| - target: aarch64-pc-windows-msvc | |
| os: windows-11-arm | |
| archive: zip | |
| - target: x86_64-apple-darwin | |
| os: macos-15-intel | |
| archive: tar.gz | |
| - target: aarch64-apple-darwin | |
| os: macos-15 | |
| archive: tar.gz | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@1.95.0 | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Setup protoc | |
| uses: arduino/setup-protoc@v3 | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Cache dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ endsWith(matrix.target, '-unknown-linux-musl') && 'docker-alpine' || runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ endsWith(matrix.target, '-unknown-linux-musl') && 'docker-alpine' || runner.os }}-${{ matrix.target }}-cargo- | |
| ${{ endsWith(matrix.target, '-unknown-linux-musl') && 'docker-alpine' || runner.os }}-cargo- | |
| # Cache the static ONNX Runtime build for musl targets so we don't rebuild | |
| # (45–60 min) on every CI run. Cache full source+build tree because | |
| # ort-sys's full static-link branch needs build/_deps/ subtrees for | |
| # re2/abseil/protobuf/etc. | |
| # Cache the static ONNX Runtime build for targets where pyke ships no | |
| # prebuilts (musl, x86_64-apple-darwin). Cache full source+build tree | |
| # because ort-sys's full static-link branch needs build/_deps/ subtrees | |
| # for re2/abseil/protobuf/etc. | |
| - name: Cache ONNX Runtime static build | |
| if: endsWith(matrix.target, '-unknown-linux-musl') || matrix.target == 'x86_64-apple-darwin' | |
| uses: actions/cache@v4 | |
| with: | |
| path: onnxruntime-src | |
| key: onnxruntime-1.24.2-${{ matrix.target }}-v6 | |
| - name: Build binary | |
| shell: sh | |
| run: | | |
| if [ "${{ runner.os }}" = "Linux" ]; then | |
| # Linux musl: build ONNX Runtime statically from source inside Alpine, | |
| # then build octomind with fastembed enabled, linking ort-sys against | |
| # the local static build via ORT_LIB_LOCATION. Pyke ships no musl | |
| # prebuilts, so this is the only supported path. ORT 1.24.2 matches | |
| # ort-sys 2.0.0-rc.12 / fastembed's api-24 feature. | |
| # | |
| # Pre-create the cache dir on the host so Docker volume-mount | |
| # inherits writable permissions. | |
| mkdir -p onnxruntime-src | |
| docker run --rm \ | |
| -v "$(pwd):/workspace" \ | |
| -w /workspace \ | |
| rust:1.95.0-alpine3.22 \ | |
| sh -c ' | |
| set -eu | |
| # No protobuf-dev: it pulls in abseil-cpp-dev transitively, which | |
| # makes ORT'\''s CMake skip its bundled abseil and (because re2 | |
| # depends on bundled absl targets) drop re2 from the build entirely. | |
| # ort-sys 2.0.0-rc.12 hardcodes static links to ~25 absl_*, re2, | |
| # protobuf libs at fixed _deps/ paths, so all three must be built | |
| # by ORT, not the system. Without the system packages ORT | |
| # FetchContent'\''s and compiles all three from source. | |
| apk add --no-cache \ | |
| git perl bash musl-dev openssl-dev openssl-libs-static \ | |
| pkgconfig gcc g++ \ | |
| cmake make linux-headers python3 py3-pip patch | |
| # Provide stub execinfo.h — musl lacks it and Alpine 3.17+ removed | |
| # libexecinfo. ORT'\''s stacktrace.cc unconditionally includes it on | |
| # non-Android POSIX. The stub provides no-op backtrace functions. | |
| # Written to /tmp since /usr/include may not be writable. | |
| mkdir -p /tmp/include | |
| cat > /tmp/include/execinfo.h << "EOF" | |
| #ifndef _EXECINFO_H | |
| #define _EXECINFO_H | |
| #include <stddef.h> | |
| static inline int backtrace(void **buffer, int size) { (void)buffer; (void)size; return 0; } | |
| static inline char **backtrace_symbols(void *const *buffer, int size) { (void)buffer; (void)size; return NULL; } | |
| static inline void backtrace_symbols_fd(void *const *buffer, int size, int fd) { (void)buffer; (void)size; (void)fd; } | |
| #endif | |
| EOF | |
| export C_INCLUDE_PATH=/tmp/include | |
| export CPLUS_INCLUDE_PATH=/tmp/include | |
| rustup target add ${{ matrix.target }} | |
| ORT_SRC=/workspace/onnxruntime-src | |
| ORT_LIB_LOCATION="$ORT_SRC/build/Release" | |
| # libre2.a is the late marker — re2 is built last in the bundled | |
| # dep graph (after abseil + protobuf), so its presence proves the | |
| # full static tree is in place. A partial cache that only has | |
| # libonnxruntime_common.a but no libre2.a triggers a clean rebuild. | |
| if [ ! -f "$ORT_LIB_LOCATION/_deps/re2-build/libre2.a" ]; then | |
| echo "==> Building ONNX Runtime 1.24.2 from source (static, musl)" | |
| rm -rf "$ORT_SRC" | |
| git clone --single-branch --branch v1.24.2 --recursive \ | |
| https://github.com/microsoft/onnxruntime.git "$ORT_SRC" | |
| cd "$ORT_SRC" | |
| ./build.sh \ | |
| --config Release \ | |
| --build_dir build \ | |
| --parallel \ | |
| --skip_tests \ | |
| --skip_submodule_sync \ | |
| --allow_running_as_root \ | |
| --compile_no_warning_as_error \ | |
| --no_kleidiai \ | |
| --no_sve \ | |
| --cmake_extra_defines \ | |
| CMAKE_POSITION_INDEPENDENT_CODE=ON \ | |
| onnxruntime_BUILD_UNIT_TESTS=OFF \ | |
| onnxruntime_BUILD_SHARED_LIB=OFF | |
| # ORT'\''s static build (.a archives, --skip_tests) never link an | |
| # executable, so target_link_libraries deps like re2::re2 don'\''t | |
| # trigger compilation — re2 is FetchContent-populated but its | |
| # CMake target stays unbuilt. ort-sys 2.0.0-rc.12 hardcodes a | |
| # static link to it. Explicitly drive the re2 target inside ORT'\''s | |
| # configured build tree (uses bundled abseil from the same tree). | |
| cmake --build "$ORT_LIB_LOCATION" --target re2 -j | |
| cd /workspace | |
| else | |
| echo "==> Using cached ONNX Runtime static build" | |
| fi | |
| # ort-sys static_config #1 with empty profile detection. | |
| # ORT_LIB_LOCATION = build/Release (where libonnxruntime_common.a lives directly). | |
| # Profile detection iterates build/Release/{Release,RelWithDebInfo,...}, | |
| # none exist → profile="" → transform_dep adds no suffix. | |
| # lib_dir = base ✓, external_lib_dir = base/_deps = build/Release/_deps | |
| # which is where cmake actually places onnx-build/, re2-build/, abseil_cpp-build/, etc. | |
| # | |
| # DO NOT use ORT_LIB_LOCATION="$ORT_SRC/build": that triggers profile=Release | |
| # detection, which makes transform_dep append /Release to every _deps path, | |
| # so search paths land at build/_deps/onnx-build/Release (non-existent) and | |
| # linking fails with "could not find native static library 'onnx'". | |
| export ORT_LIB_LOCATION="$ORT_LIB_LOCATION" | |
| # GCC 15 (Alpine 3.23) introduced __cpu_features2 in libgcc. | |
| # ORT'\''s cpuid_info.cc.o references it; musl static link needs | |
| # libgcc.a explicitly or the symbol is undefined at link time. | |
| export RUSTFLAGS="-C link-arg=-lgcc" | |
| cargo build --release --target ${{ matrix.target }} | |
| ' | |
| elif [ "${{ runner.os }}" = "Windows" ]; then | |
| # Windows: Pyke ships prebuilts for MSVC targets. | |
| # Pyke's prebuilt ORT static lib is compiled with /MD (dynamic CRT). | |
| # Rust on MSVC defaults to /MT (static CRT) → __imp_* unresolved | |
| # symbol errors at link time. Switch to dynamic CRT to match. | |
| # vcruntime140.dll is present on all Windows hosts. | |
| export RUSTFLAGS="-C target-feature=-crt-static" | |
| cargo build --release --target ${{ matrix.target }} | |
| elif [ "${{ matrix.target }}" = "x86_64-apple-darwin" ]; then | |
| # macOS x86_64: pyke 2.0.0-rc.12 ships no x86_64-apple-darwin | |
| # prebuilt (xcframework linking unsupported on this target). Build | |
| # ONNX Runtime 1.24.2 from source statically and link via | |
| # ORT_LIB_LOCATION, same approach as Linux musl. | |
| ORT_SRC="$(pwd)/onnxruntime-src" | |
| ORT_LIB_LOCATION="$ORT_SRC/build/Release" | |
| if [ ! -f "$ORT_LIB_LOCATION/_deps/re2-build/libre2.a" ]; then | |
| echo "==> Building ONNX Runtime 1.24.2 from source (static, macOS x86_64)" | |
| rm -rf "$ORT_SRC" | |
| git clone --single-branch --branch v1.24.2 --recursive \ | |
| https://github.com/microsoft/onnxruntime.git "$ORT_SRC" | |
| (cd "$ORT_SRC" && ./build.sh \ | |
| --config Release \ | |
| --build_dir build \ | |
| --parallel \ | |
| --skip_tests \ | |
| --skip_submodule_sync \ | |
| --compile_no_warning_as_error \ | |
| --cmake_extra_defines \ | |
| CMAKE_POSITION_INDEPENDENT_CODE=ON \ | |
| CMAKE_OSX_ARCHITECTURES=x86_64 \ | |
| CMAKE_OSX_DEPLOYMENT_TARGET=11.0 \ | |
| onnxruntime_BUILD_UNIT_TESTS=OFF \ | |
| onnxruntime_BUILD_SHARED_LIB=OFF) | |
| # Static archive build never links an executable, so re2's | |
| # CMake target stays unbuilt while ort-sys hardcodes a static | |
| # link to libre2.a. Force-build it. | |
| cmake --build "$ORT_LIB_LOCATION" --target re2 -j | |
| else | |
| echo "==> Using cached ONNX Runtime static build" | |
| fi | |
| export ORT_LIB_LOCATION="$ORT_LIB_LOCATION" | |
| cargo build --release --target ${{ matrix.target }} | |
| else | |
| # Native build for other macOS targets (aarch64) — Pyke ships prebuilts. | |
| cargo build --release --target ${{ matrix.target }} | |
| fi | |
| - name: Create archive directory | |
| shell: sh | |
| run: mkdir -p dist | |
| - name: Create archive (Unix) | |
| if: matrix.archive == 'tar.gz' | |
| shell: sh | |
| run: | | |
| cd target/${{ matrix.target }}/release | |
| case "${{ matrix.target }}" in | |
| *windows*) | |
| tar czf ../../../dist/octomind-${{ needs.create-release.outputs.version }}-${{ matrix.target }}.tar.gz octomind.exe | |
| ;; | |
| *) | |
| tar czf ../../../dist/octomind-${{ needs.create-release.outputs.version }}-${{ matrix.target }}.tar.gz octomind | |
| ;; | |
| esac | |
| - name: Create archive (Windows) | |
| if: matrix.archive == 'zip' | |
| shell: sh | |
| run: | | |
| cd target/${{ matrix.target }}/release | |
| 7z a ../../../dist/octomind-${{ needs.create-release.outputs.version }}-${{ matrix.target }}.zip octomind.exe | |
| - name: Upload release asset | |
| shell: sh | |
| run: | | |
| gh release upload "${{ needs.create-release.outputs.version }}" \ | |
| "./dist/octomind-${{ needs.create-release.outputs.version }}-${{ matrix.target }}.${{ matrix.archive }}" \ | |
| --clobber | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| publish-crate: | |
| name: Publish to Crates.io | |
| needs: [create-release, build] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@1.95.0 | |
| - name: Setup protoc | |
| uses: arduino/setup-protoc@v3 | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Cache dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-publish-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo-publish- | |
| ${{ runner.os }}-cargo- | |
| - name: Validate version matches tag | |
| run: | | |
| VERSION="${{ needs.create-release.outputs.version }}" | |
| CARGO_VERSION=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/') | |
| if [ "$VERSION" != "$CARGO_VERSION" ]; then | |
| echo "❌ Version mismatch!" | |
| echo "Git tag: $VERSION" | |
| echo "Cargo.toml: $CARGO_VERSION" | |
| echo "Please update Cargo.toml version to match the git tag" | |
| exit 1 | |
| fi | |
| echo "✅ Version validation passed: $VERSION" | |
| - name: Check if version already published | |
| id: check_published | |
| run: | | |
| VERSION="${{ needs.create-release.outputs.version }}" | |
| # Check if this version already exists on crates.io | |
| if cargo search octomind --limit 1 | grep -q "octomind = \"$VERSION\""; then | |
| echo "already_published=true" >> $GITHUB_OUTPUT | |
| echo "⚠️ Version $VERSION already published to crates.io" | |
| else | |
| echo "already_published=false" >> $GITHUB_OUTPUT | |
| echo "✅ Version $VERSION not yet published" | |
| fi | |
| - name: Dry run publish | |
| if: steps.check_published.outputs.already_published == 'false' | |
| run: | | |
| echo "🔍 Running dry-run publish to validate package..." | |
| cargo publish --dry-run --no-default-features | |
| env: | |
| CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} | |
| - name: Publish to crates.io | |
| if: steps.check_published.outputs.already_published == 'false' | |
| run: | | |
| echo "🚀 Publishing to crates.io..." | |
| cargo publish --no-default-features | |
| echo "✅ Successfully published to crates.io!" | |
| env: | |
| CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} | |
| - name: Skip publishing | |
| if: steps.check_published.outputs.already_published == 'true' | |
| run: | | |
| echo "⏭️ Skipping crates.io publish - version already exists" | |
| finalize-release: | |
| name: Finalize Release | |
| needs: [create-release, build, publish-crate] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Publish release | |
| run: | | |
| VERSION="${{ needs.create-release.outputs.version }}" | |
| # Update release notes with download links | |
| cat > release_notes.md << EOF | |
| ## 🚀 What's Changed | |
| ${{ needs.create-release.outputs.changelog }} | |
| ## 📦 Installation | |
| ### Quick Install Script (Universal) | |
| \`\`\`bash | |
| curl -fsSL https://raw.githubusercontent.com/${{ github.repository }}/main/install.sh | sh | |
| \`\`\` | |
| **Works on:** Linux, macOS, Windows (Git Bash/WSL/MSYS2), and any Unix-like system | |
| ### Manual Download | |
| | Platform | Architecture | Download | | |
| |----------|--------------|----------| | |
| | Linux | x86_64 (static) | [octomind-${VERSION}-x86_64-unknown-linux-musl.tar.gz](https://github.com/${{ github.repository }}/releases/download/${VERSION}/octomind-${VERSION}-x86_64-unknown-linux-musl.tar.gz) | | |
| | Linux | ARM64 (static) | [octomind-${VERSION}-aarch64-unknown-linux-musl.tar.gz](https://github.com/${{ github.repository }}/releases/download/${VERSION}/octomind-${VERSION}-aarch64-unknown-linux-musl.tar.gz) | | |
| | Windows | x86_64 | [octomind-${VERSION}-x86_64-pc-windows-msvc.zip](https://github.com/${{ github.repository }}/releases/download/${VERSION}/octomind-${VERSION}-x86_64-pc-windows-msvc.zip) | | |
| | Windows | ARM64 | [octomind-${VERSION}-aarch64-pc-windows-msvc.zip](https://github.com/${{ github.repository }}/releases/download/${VERSION}/octomind-${VERSION}-aarch64-pc-windows-msvc.zip) | | |
| | macOS | x86_64 | [octomind-${VERSION}-x86_64-apple-darwin.tar.gz](https://github.com/${{ github.repository }}/releases/download/${VERSION}/octomind-${VERSION}-x86_64-apple-darwin.tar.gz) | | |
| | macOS | ARM64 | [octomind-${VERSION}-aarch64-apple-darwin.tar.gz](https://github.com/${{ github.repository }}/releases/download/${VERSION}/octomind-${VERSION}-aarch64-apple-darwin.tar.gz) | | |
| ### Using Cargo (from crates.io) | |
| \`\`\`bash | |
| cargo install octomind | |
| \`\`\` | |
| ### Using Cargo (from Git) | |
| \`\`\`bash | |
| cargo install --git https://github.com/${{ github.repository }} | |
| \`\`\` | |
| ### Verify Installation | |
| \`\`\`bash | |
| octomind --version | |
| \`\`\` | |
| EOF | |
| # Publish the release (remove draft status) | |
| gh release edit "$VERSION" --draft=false --notes-file release_notes.md | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| notify-homebrew: | |
| name: Notify Homebrew Tap | |
| needs: [create-release, finalize-release] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Dispatch update to homebrew-tap | |
| run: | | |
| curl -X POST \ | |
| -H "Accept: application/vnd.github+json" \ | |
| -H "Authorization: Bearer ${{ secrets.TAP_GITHUB_TOKEN }}" \ | |
| https://api.github.com/repos/muvon/homebrew-tap/dispatches \ | |
| -d "{\"event_type\":\"octomind-release\",\"client_payload\":{\"version\":\"${{ needs.create-release.outputs.version }}\"}}" | |
| docker: | |
| name: Build and Push Docker Images | |
| needs: [create-release, build, publish-crate] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - 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.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Set lowercase repository name | |
| id: repo | |
| run: echo "repository=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT | |
| - name: Build and push Docker image | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| platforms: linux/amd64,linux/arm64 | |
| push: true | |
| tags: | | |
| ghcr.io/${{ steps.repo.outputs.repository }}:latest | |
| ghcr.io/${{ steps.repo.outputs.repository }}:${{ needs.create-release.outputs.version }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max |