Build and Release #16
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
| # Copyright 2025 The Drasi Authors. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| name: Build and Release | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Version Tag (optional, defaults to version from Cargo.toml)' | |
| required: false | |
| image_prefix: | |
| description: 'Image Prefix (defaults to ghcr.io/<repo-owner>)' | |
| required: false | |
| default: '' | |
| dry_run: | |
| description: 'Dry run — build everything but skip publish/release steps' | |
| required: false | |
| type: boolean | |
| default: false | |
| schedule: | |
| - cron: '0 8 * * 1' # Weekly Monday 08:00 UTC dry-run | |
| permissions: | |
| id-token: write | |
| contents: read | |
| packages: write | |
| env: | |
| IMAGE_NAME: drasi-server | |
| # Resolved image prefix: use the user-provided value if set, otherwise default | |
| # to ghcr.io/<repo-owner> so forks publish to their own namespace by default. | |
| IMAGE_PREFIX: ${{ inputs.image_prefix != '' && inputs.image_prefix || format('ghcr.io/{0}', github.repository_owner) }} | |
| jobs: | |
| # Determine the version tag to use | |
| determine-version: | |
| name: Determine Version Tag | |
| runs-on: ubuntu-latest | |
| outputs: | |
| tag: ${{ steps.version.outputs.tag }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Determine version | |
| id: version | |
| run: | | |
| if [ -n "${{ inputs.tag }}" ]; then | |
| echo "Using provided tag: ${{ inputs.tag }}" | |
| echo "tag=${{ inputs.tag }}" >> $GITHUB_OUTPUT | |
| else | |
| # Extract version from Cargo.toml | |
| VERSION=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/') | |
| TAG="v${VERSION}" | |
| echo "Using version from Cargo.toml: ${TAG}" | |
| echo "tag=${TAG}" >> $GITHUB_OUTPUT | |
| fi | |
| # Build all Linux binaries on a single runner using cross (the whole point of cross) | |
| build-linux: | |
| name: Build Linux binaries | |
| runs-on: ubuntu-latest | |
| needs: determine-version | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: stable | |
| # Install cross from a pinned git commit: the last tagged release (0.2.5, | |
| # March 2022) ships container images based on glibc 2.27, which is too old | |
| # for current rustc's build-script binaries (require GLIBC_2.34). Main has | |
| # newer base images, but we pin to a specific commit for reproducibility. | |
| - name: Install cross | |
| run: cargo install cross --git https://github.com/cross-rs/cross --rev 65fe72b0cdb1e7e0cc0652517498d4389cc8f5cf --locked | |
| - name: Build all Linux targets | |
| run: | | |
| TARGETS=( | |
| "x86_64-unknown-linux-gnu:x86_64-linux-gnu" | |
| "aarch64-unknown-linux-gnu:aarch64-linux-gnu" | |
| "x86_64-unknown-linux-musl:x86_64-linux-musl" | |
| "aarch64-unknown-linux-musl:aarch64-linux-musl" | |
| ) | |
| for entry in "${TARGETS[@]}"; do | |
| TARGET="${entry%%:*}" | |
| SUFFIX="${entry##*:}" | |
| ARTIFACT_NAME="drasi-server-${SUFFIX}" | |
| echo "=========================================" | |
| echo "Building ${TARGET} -> ${ARTIFACT_NAME}" | |
| echo "=========================================" | |
| rustup target add "${TARGET}" | |
| cross build --release --target "${TARGET}" --bin drasi-server | |
| SRC="target/${TARGET}/release/drasi-server" | |
| if [[ -f "$SRC" ]]; then | |
| cp "$SRC" "$ARTIFACT_NAME" | |
| chmod +x "$ARTIFACT_NAME" | |
| echo "✓ ${ARTIFACT_NAME}" | |
| else | |
| echo "Error: Built binary not found at $SRC" | |
| ls -la "target/${TARGET}/release/" || true | |
| exit 1 | |
| fi | |
| done | |
| echo "All Linux binaries built:" | |
| ls -lh drasi-server-* | |
| - name: Upload x86_64-linux-gnu | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: drasi-server-x86_64-linux-gnu | |
| path: drasi-server-x86_64-linux-gnu | |
| if-no-files-found: error | |
| - name: Upload aarch64-linux-gnu | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: drasi-server-aarch64-linux-gnu | |
| path: drasi-server-aarch64-linux-gnu | |
| if-no-files-found: error | |
| - name: Upload x86_64-linux-musl | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: drasi-server-x86_64-linux-musl | |
| path: drasi-server-x86_64-linux-musl | |
| if-no-files-found: error | |
| - name: Upload aarch64-linux-musl | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: drasi-server-aarch64-linux-musl | |
| path: drasi-server-aarch64-linux-musl | |
| if-no-files-found: error | |
| # macOS requires native builds (can't cross-compile to macOS) | |
| build-macos: | |
| name: Build macOS (${{ matrix.arch }}) | |
| runs-on: ${{ matrix.runner }} | |
| needs: determine-version | |
| strategy: | |
| matrix: | |
| include: | |
| - target: aarch64-apple-darwin | |
| artifact_suffix: aarch64-apple-darwin | |
| arch: ARM64 | |
| runner: macos-latest | |
| - target: x86_64-apple-darwin | |
| artifact_suffix: x86_64-apple-darwin | |
| arch: x86_64 | |
| runner: macos-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: stable | |
| - name: Add Rust target | |
| run: rustup target add ${{ matrix.target }} | |
| - name: Install build dependencies | |
| run: brew install protobuf pkg-config jq oniguruma autoconf automake libtool | |
| - name: Build x86_64 static libs (for cross-compile) | |
| if: matrix.target == 'x86_64-apple-darwin' | |
| run: | | |
| set -euo pipefail | |
| X86_PREFIX="${{ github.workspace }}/x86_64-deps" | |
| mkdir -p "$X86_PREFIX" | |
| # Build oniguruma for x86_64 | |
| git clone --depth 1 https://github.com/kkos/oniguruma.git /tmp/oniguruma | |
| cd /tmp/oniguruma | |
| autoreconf -vfi | |
| ./configure --host=x86_64-apple-darwin --prefix="$X86_PREFIX" \ | |
| CC="clang -arch x86_64" CFLAGS="-arch x86_64" \ | |
| --enable-static --disable-shared | |
| make -j$(sysctl -n hw.ncpu) && make install | |
| # Build jq for x86_64 (with oniguruma) | |
| git clone --depth 1 https://github.com/jqlang/jq.git /tmp/jq | |
| cd /tmp/jq | |
| git submodule update --init | |
| autoreconf -fi | |
| ./configure --host=x86_64-apple-darwin --prefix="$X86_PREFIX" \ | |
| CC="clang -arch x86_64" CFLAGS="-arch x86_64" \ | |
| --with-oniguruma="$X86_PREFIX" \ | |
| --enable-static --disable-shared --disable-maintainer-mode | |
| make -j$(sysctl -n hw.ncpu) && make install | |
| echo "x86_64 static libs installed to $X86_PREFIX:" | |
| ls -la "$X86_PREFIX/lib/" | |
| - name: Build binary | |
| run: | | |
| export LIBJQ_STATIC=1 | |
| export LIBONIG_STATIC=1 | |
| if [[ "${{ matrix.target }}" == "x86_64-apple-darwin" ]]; then | |
| X86_PREFIX="${{ github.workspace }}/x86_64-deps" | |
| export JQ_LIB_DIR="$X86_PREFIX/lib" | |
| export ONIG_LIB_DIR="$X86_PREFIX/lib" | |
| export PKG_CONFIG_PATH="$X86_PREFIX/lib/pkgconfig" | |
| export CFLAGS_x86_64_apple_darwin="-arch x86_64" | |
| else | |
| export JQ_LIB_DIR="$(brew --prefix jq)/lib" | |
| export ONIG_LIB_DIR="$(brew --prefix oniguruma)/lib" | |
| fi | |
| cargo build --release --target ${{ matrix.target }} --bin drasi-server | |
| SRC_BINARY="target/${{ matrix.target }}/release/drasi-server" | |
| ARTIFACT_NAME="drasi-server-${{ matrix.artifact_suffix }}" | |
| if [[ -f "$SRC_BINARY" ]]; then | |
| cp "$SRC_BINARY" "$ARTIFACT_NAME" | |
| chmod +x "$ARTIFACT_NAME" | |
| else | |
| echo "Error: Built binary not found at $SRC_BINARY" | |
| exit 1 | |
| fi | |
| - name: Upload binary artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: drasi-server-${{ matrix.artifact_suffix }} | |
| path: drasi-server-${{ matrix.artifact_suffix }} | |
| if-no-files-found: error | |
| # Windows MSVC native build (uses vendored static libs for jq and OpenSSL) | |
| build-windows-msvc: | |
| name: Build Windows MSVC (x86_64) | |
| runs-on: windows-latest | |
| needs: determine-version | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: stable | |
| - name: Pull vendored native libraries | |
| shell: bash | |
| run: cargo xtask vendor pull x86_64-pc-windows-msvc --tag v1 | |
| - name: Build binary | |
| shell: bash | |
| run: | | |
| cargo build --release --target x86_64-pc-windows-msvc --bin drasi-server | |
| SRC_BINARY="target/x86_64-pc-windows-msvc/release/drasi-server.exe" | |
| ARTIFACT_NAME="drasi-server-x86_64-windows-msvc.exe" | |
| echo "=== Build output ===" | |
| ls -lh "$SRC_BINARY" || true | |
| file "$SRC_BINARY" || true | |
| if [[ -f "$SRC_BINARY" ]]; then | |
| cp "$SRC_BINARY" "$ARTIFACT_NAME" | |
| echo "✓ Built $ARTIFACT_NAME ($(du -h "$ARTIFACT_NAME" | cut -f1))" | |
| else | |
| echo "Error: Built binary not found at $SRC_BINARY" | |
| echo "=== release directory listing ===" | |
| ls -la "target/x86_64-pc-windows-msvc/release/" || true | |
| exit 1 | |
| fi | |
| - name: Upload binary artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: drasi-server-x86_64-windows-msvc | |
| path: drasi-server-x86_64-windows-msvc.exe | |
| if-no-files-found: error | |
| # ─── SSE CLI builds (pure Rust, no C dependencies) ─── | |
| # Build all Linux SSE CLI binaries using cross | |
| build-sse-cli-linux: | |
| name: Build SSE CLI Linux binaries | |
| runs-on: ubuntu-latest | |
| needs: determine-version | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: stable | |
| # See note in build-linux about why we install cross from a pinned commit. | |
| - name: Install cross | |
| run: cargo install cross --git https://github.com/cross-rs/cross --rev 65fe72b0cdb1e7e0cc0652517498d4389cc8f5cf --locked | |
| - name: Build all Linux targets | |
| run: | | |
| TARGETS=( | |
| "x86_64-unknown-linux-gnu:x86_64-linux-gnu" | |
| "aarch64-unknown-linux-gnu:aarch64-linux-gnu" | |
| "x86_64-unknown-linux-musl:x86_64-linux-musl" | |
| "aarch64-unknown-linux-musl:aarch64-linux-musl" | |
| ) | |
| for entry in "${TARGETS[@]}"; do | |
| TARGET="${entry%%:*}" | |
| SUFFIX="${entry##*:}" | |
| ARTIFACT_NAME="drasi-sse-cli-${SUFFIX}" | |
| echo "=========================================" | |
| echo "Building SSE CLI ${TARGET} -> ${ARTIFACT_NAME}" | |
| echo "=========================================" | |
| rustup target add "${TARGET}" | |
| cross build --release --target "${TARGET}" --manifest-path examples/sse-cli/Cargo.toml | |
| SRC="examples/sse-cli/target/${TARGET}/release/drasi-sse-cli" | |
| if [[ -f "$SRC" ]]; then | |
| cp "$SRC" "$ARTIFACT_NAME" | |
| chmod +x "$ARTIFACT_NAME" | |
| echo "✓ ${ARTIFACT_NAME}" | |
| else | |
| echo "Error: Built binary not found at $SRC" | |
| ls -la "target/${TARGET}/release/" || true | |
| exit 1 | |
| fi | |
| done | |
| echo "All SSE CLI Linux binaries built:" | |
| ls -lh drasi-sse-cli-* | |
| - name: Upload x86_64-linux-gnu | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: drasi-sse-cli-x86_64-linux-gnu | |
| path: drasi-sse-cli-x86_64-linux-gnu | |
| if-no-files-found: error | |
| - name: Upload aarch64-linux-gnu | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: drasi-sse-cli-aarch64-linux-gnu | |
| path: drasi-sse-cli-aarch64-linux-gnu | |
| if-no-files-found: error | |
| - name: Upload x86_64-linux-musl | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: drasi-sse-cli-x86_64-linux-musl | |
| path: drasi-sse-cli-x86_64-linux-musl | |
| if-no-files-found: error | |
| - name: Upload aarch64-linux-musl | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: drasi-sse-cli-aarch64-linux-musl | |
| path: drasi-sse-cli-aarch64-linux-musl | |
| if-no-files-found: error | |
| # macOS SSE CLI builds (native) | |
| build-sse-cli-macos: | |
| name: Build SSE CLI macOS (${{ matrix.arch }}) | |
| runs-on: ${{ matrix.runner }} | |
| needs: determine-version | |
| strategy: | |
| matrix: | |
| include: | |
| - target: aarch64-apple-darwin | |
| artifact_suffix: aarch64-apple-darwin | |
| arch: ARM64 | |
| runner: macos-latest | |
| - target: x86_64-apple-darwin | |
| artifact_suffix: x86_64-apple-darwin | |
| arch: x86_64 | |
| runner: macos-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: stable | |
| - name: Add Rust target | |
| run: rustup target add ${{ matrix.target }} | |
| - name: Build binary | |
| run: | | |
| cargo build --release --target ${{ matrix.target }} --manifest-path examples/sse-cli/Cargo.toml | |
| SRC_BINARY="examples/sse-cli/target/${{ matrix.target }}/release/drasi-sse-cli" | |
| ARTIFACT_NAME="drasi-sse-cli-${{ matrix.artifact_suffix }}" | |
| if [[ -f "$SRC_BINARY" ]]; then | |
| cp "$SRC_BINARY" "$ARTIFACT_NAME" | |
| chmod +x "$ARTIFACT_NAME" | |
| else | |
| echo "Error: Built binary not found at $SRC_BINARY" | |
| ls -la "examples/sse-cli/target/${{ matrix.target }}/release/" || true | |
| exit 1 | |
| fi | |
| - name: Upload binary artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: drasi-sse-cli-${{ matrix.artifact_suffix }} | |
| path: drasi-sse-cli-${{ matrix.artifact_suffix }} | |
| if-no-files-found: error | |
| # Windows SSE CLI build (cross-compiled from Linux) | |
| build-sse-cli-windows: | |
| name: Build SSE CLI Windows (x86_64) | |
| runs-on: ubuntu-latest | |
| needs: determine-version | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: stable | |
| # See note in build-linux about why we install cross from a pinned commit. | |
| - name: Install cross | |
| run: cargo install cross --git https://github.com/cross-rs/cross --rev 65fe72b0cdb1e7e0cc0652517498d4389cc8f5cf --locked | |
| - name: Build binary | |
| run: | | |
| rustup target add x86_64-pc-windows-gnu | |
| cross build --release --target x86_64-pc-windows-gnu --manifest-path examples/sse-cli/Cargo.toml | |
| SRC_BINARY="examples/sse-cli/target/x86_64-pc-windows-gnu/release/drasi-sse-cli.exe" | |
| ARTIFACT_NAME="drasi-sse-cli-x86_64-windows.exe" | |
| if [[ -f "$SRC_BINARY" ]]; then | |
| cp "$SRC_BINARY" "$ARTIFACT_NAME" | |
| echo "✓ Built $ARTIFACT_NAME ($(du -h "$ARTIFACT_NAME" | cut -f1))" | |
| else | |
| echo "Error: Built binary not found at $SRC_BINARY" | |
| ls -la "examples/sse-cli/target/x86_64-pc-windows-gnu/release/" || true | |
| exit 1 | |
| fi | |
| - name: Upload binary artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: drasi-sse-cli-x86_64-windows | |
| path: drasi-sse-cli-x86_64-windows.exe | |
| if-no-files-found: error | |
| # Build Docker images for Linux platforms | |
| build-docker: | |
| name: Build Docker ${{ matrix.platform }} | |
| runs-on: ${{ matrix.runner }} | |
| needs: determine-version | |
| strategy: | |
| matrix: | |
| include: | |
| - platform: linux/amd64 | |
| runner: ubuntu-latest | |
| suffix: amd64 | |
| - platform: linux/arm64 | |
| runner: ubuntu-24.04-arm | |
| suffix: arm64 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| - name: Log in to GitHub Container Registry | |
| if: ${{ github.event_name != 'schedule' && !inputs.dry_run }} | |
| uses: docker/login-action@v4 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.repository_owner }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push platform-specific image | |
| if: ${{ github.event_name != 'schedule' && !inputs.dry_run }} | |
| env: | |
| IMAGE_PREFIX: ${{ env.IMAGE_PREFIX }} | |
| DOCKER_TAG_VERSION: ${{ needs.determine-version.outputs.tag }}-${{ matrix.suffix }} | |
| DOCKERX_OPTS: --platform ${{ matrix.platform }} --push --cache-from type=gha --cache-to type=gha,mode=max | |
| run: | | |
| make docker-build | |
| - name: Build platform-specific image (dry run) | |
| if: ${{ github.event_name == 'schedule' || inputs.dry_run }} | |
| env: | |
| IMAGE_PREFIX: local | |
| DOCKER_TAG_VERSION: dry-run-${{ matrix.suffix }} | |
| DOCKERX_OPTS: --platform ${{ matrix.platform }} --cache-from type=gha --cache-to type=gha,mode=max --load | |
| run: | | |
| make docker-build | |
| # Create multi-arch manifest | |
| create-manifest: | |
| name: Create Multi-Arch Manifest | |
| if: ${{ github.event_name != 'schedule' && !inputs.dry_run }} | |
| needs: [determine-version, build-docker] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v4 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.repository_owner }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create and push manifest list | |
| run: | | |
| docker buildx imagetools create -t ${{ env.IMAGE_PREFIX }}/${{ env.IMAGE_NAME }}:${{ needs.determine-version.outputs.tag }} \ | |
| ${{ env.IMAGE_PREFIX }}/${{ env.IMAGE_NAME }}:${{ needs.determine-version.outputs.tag }}-amd64 \ | |
| ${{ env.IMAGE_PREFIX }}/${{ env.IMAGE_NAME }}:${{ needs.determine-version.outputs.tag }}-arm64 | |
| - name: Create and push 'latest' tag | |
| run: | | |
| docker buildx imagetools create -t ${{ env.IMAGE_PREFIX }}/${{ env.IMAGE_NAME }}:latest \ | |
| ${{ env.IMAGE_PREFIX }}/${{ env.IMAGE_NAME }}:${{ needs.determine-version.outputs.tag }}-amd64 \ | |
| ${{ env.IMAGE_PREFIX }}/${{ env.IMAGE_NAME }}:${{ needs.determine-version.outputs.tag }}-arm64 | |
| - name: Generate summary | |
| run: | | |
| echo "## Docker Image Published :rocket:" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Image:** \`${{ env.IMAGE_PREFIX }}/${{ env.IMAGE_NAME }}:${{ needs.determine-version.outputs.tag }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "**Platforms:** \`linux/amd64, linux/arm64\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Tags Created" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`${{ env.IMAGE_PREFIX }}/${{ env.IMAGE_NAME }}:${{ needs.determine-version.outputs.tag }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`${{ env.IMAGE_PREFIX }}/${{ env.IMAGE_NAME }}:latest\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Platform-Specific Tags" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`${{ env.IMAGE_PREFIX }}/${{ env.IMAGE_NAME }}:${{ needs.determine-version.outputs.tag }}-amd64\`" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`${{ env.IMAGE_PREFIX }}/${{ env.IMAGE_NAME }}:${{ needs.determine-version.outputs.tag }}-arm64\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Pull Commands" >> $GITHUB_STEP_SUMMARY | |
| echo '```bash' >> $GITHUB_STEP_SUMMARY | |
| echo "docker pull ${{ env.IMAGE_PREFIX }}/${{ env.IMAGE_NAME }}:${{ needs.determine-version.outputs.tag }}" >> $GITHUB_STEP_SUMMARY | |
| echo "docker pull ${{ env.IMAGE_PREFIX }}/${{ env.IMAGE_NAME }}:latest" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "## Binary Artifacts Published :package:" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "Binary artifacts are available as workflow artifacts for the following targets:" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`drasi-server-aarch64-apple-darwin\` (macOS ARM64 / Apple Silicon)" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`drasi-server-x86_64-apple-darwin\` (macOS x86_64 / Intel)" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`drasi-server-x86_64-windows-msvc.exe\` (Windows x86_64 MSVC)" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`drasi-server-aarch64-linux-gnu\` (Linux ARM64 glibc)" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`drasi-server-x86_64-linux-gnu\` (Linux x86_64 glibc)" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`drasi-server-aarch64-linux-musl\` (Linux ARM64 musl)" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`drasi-server-x86_64-linux-musl\` (Linux x86_64 musl)" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### SSE CLI Binaries" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`drasi-sse-cli-aarch64-apple-darwin\` (macOS ARM64)" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`drasi-sse-cli-x86_64-apple-darwin\` (macOS x86_64)" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`drasi-sse-cli-x86_64-windows.exe\` (Windows x86_64)" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`drasi-sse-cli-aarch64-linux-gnu\` (Linux ARM64 glibc)" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`drasi-sse-cli-x86_64-linux-gnu\` (Linux x86_64 glibc)" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`drasi-sse-cli-aarch64-linux-musl\` (Linux ARM64 musl)" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Examples" >> $GITHUB_STEP_SUMMARY | |
| echo "- \`drasi-server-examples.zip\`" >> $GITHUB_STEP_SUMMARY echo "- \`drasi-sse-cli-x86_64-linux-musl\` (Linux x86_64 musl)" >> $GITHUB_STEP_SUMMARY | |
| # Smoke-test each binary with the hello-world (mock source) config | |
| test-binaries: | |
| name: Test ${{ matrix.artifact_suffix }} | |
| needs: [build-linux, build-macos, build-windows-msvc] | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # macOS ARM64 (Apple Silicon) | |
| - artifact_suffix: aarch64-apple-darwin | |
| runner: macos-latest | |
| binary_name: "drasi-server-aarch64-apple-darwin" | |
| # macOS x86_64 (Intel) - cross-compiled, tested via Rosetta 2 | |
| - artifact_suffix: x86_64-apple-darwin | |
| runner: macos-latest | |
| binary_name: "drasi-server-x86_64-apple-darwin" | |
| # Linux x86_64 | |
| - artifact_suffix: x86_64-linux-gnu | |
| runner: ubuntu-latest | |
| binary_name: "drasi-server-x86_64-linux-gnu" | |
| # Linux ARM64 | |
| - artifact_suffix: aarch64-linux-gnu | |
| runner: ubuntu-24.04-arm | |
| binary_name: "drasi-server-aarch64-linux-gnu" | |
| # Windows x86_64 (MSVC) | |
| - artifact_suffix: x86_64-windows-msvc | |
| runner: windows-latest | |
| binary_name: "drasi-server-x86_64-windows-msvc.exe" | |
| # Linux x86_64 (musl) — tested inside Alpine container | |
| - artifact_suffix: x86_64-linux-musl | |
| runner: ubuntu-latest | |
| binary_name: "drasi-server-x86_64-linux-musl" | |
| use_alpine: true | |
| # Linux ARM64 (musl) — tested inside Alpine container | |
| - artifact_suffix: aarch64-linux-musl | |
| runner: ubuntu-24.04-arm | |
| binary_name: "drasi-server-aarch64-linux-musl" | |
| use_alpine: true | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Download binary artifact | |
| uses: actions/download-artifact@v5 | |
| with: | |
| name: drasi-server-${{ matrix.artifact_suffix }} | |
| path: bin | |
| - name: Run hello-world smoke test (Unix) | |
| if: runner.os != 'Windows' && !matrix.use_alpine | |
| run: | | |
| chmod +x "bin/${{ matrix.binary_name }}" | |
| BINARY="$(pwd)/bin/${{ matrix.binary_name }}" | |
| # Plugins are auto-installed at server startup (autoInstallPlugins: true | |
| # in the test config) from the default OCI registry. | |
| SERVER_BINARY="$BINARY" \ | |
| tests/integration/hello-world/run-integration-test.sh | |
| - name: Run hello-world smoke test (Alpine/musl) | |
| if: matrix.use_alpine | |
| run: | | |
| chmod +x "bin/${{ matrix.binary_name }}" | |
| docker run --rm \ | |
| -v "$(pwd)/bin:/bin-artifacts" \ | |
| -v "$(pwd)/tests:/tests" \ | |
| alpine:latest \ | |
| sh -c " | |
| apk add --no-cache bash curl libstdc++ libgcc && | |
| SERVER_BINARY=/bin-artifacts/${{ matrix.binary_name }} \ | |
| bash /tests/integration/hello-world/run-integration-test.sh | |
| " | |
| - name: Run hello-world smoke test (Windows) | |
| if: runner.os == 'Windows' | |
| shell: bash | |
| run: | | |
| BINARY_PATH="$(pwd)/bin/${{ matrix.binary_name }}" | |
| echo "=== Downloaded artifact contents ===" | |
| find bin/ -type f | head -30 | |
| echo "" | |
| echo "=== Binary info ===" | |
| file "$BINARY_PATH" || true | |
| echo "Size: $(du -h "$BINARY_PATH" | cut -f1)" | |
| echo "" | |
| # Quick sanity: try running with --help first | |
| echo "=== Sanity check: --help ===" | |
| "$BINARY_PATH" --help 2>&1 || echo "(exit code: $?)" | |
| echo "" | |
| # Plugins are auto-installed at server startup (autoInstallPlugins: true | |
| # in the test config) from the default OCI registry. | |
| SERVER_BINARY="$BINARY_PATH" \ | |
| tests/integration/hello-world/run-integration-test.sh | |
| - name: Show server logs on failure | |
| if: failure() | |
| shell: bash | |
| run: | | |
| echo "=== Server logs ===" | |
| if [ -f tests/integration/hello-world/server.log ]; then | |
| cat tests/integration/hello-world/server.log | |
| else | |
| echo "No server log file found" | |
| fi | |
| echo "" | |
| echo "=== bin/ directory ===" | |
| ls -la bin/ 2>/dev/null || true | |
| echo "" | |
| echo "=== Windows Event Logs (Application) ===" | |
| powershell -Command "Get-WinEvent -LogName Application -MaxEvents 10 | Format-List" 2>/dev/null || true | |
| # Create GitHub Release with binary artifacts | |
| create-release: | |
| name: Create GitHub Release | |
| if: ${{ github.event_name != 'schedule' && !inputs.dry_run }} | |
| needs: [determine-version, create-manifest, test-binaries, build-sse-cli-linux, build-sse-cli-macos, build-sse-cli-windows] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Download drasi-server artifacts | |
| uses: actions/download-artifact@v5 | |
| with: | |
| path: artifacts | |
| pattern: drasi-server-* | |
| merge-multiple: false | |
| - name: Download drasi-sse-cli artifacts | |
| uses: actions/download-artifact@v5 | |
| with: | |
| path: artifacts | |
| pattern: drasi-sse-cli-* | |
| merge-multiple: false | |
| - name: Zip examples folder | |
| run: | | |
| zip -r "drasi-server-examples.zip" examples/ \ | |
| -x 'examples/sse-cli/target/*' \ | |
| -x 'examples/trading/target/*' | |
| echo "✓ Created drasi-server-examples.zip" | |
| ls -lh "drasi-server-examples.zip" | |
| - name: Prepare release assets | |
| id: prepare | |
| run: | | |
| mkdir -p release-assets | |
| find artifacts -type f -exec cp {} release-assets/ \; | |
| cp drasi-server-examples.zip release-assets/ | |
| ls -lh release-assets/ | |
| ASSET_COUNT=$(ls -1 release-assets/ | wc -l) | |
| echo "asset_count=${ASSET_COUNT}" >> $GITHUB_OUTPUT | |
| - name: Create release notes | |
| run: | | |
| cat > release-notes.md << 'NOTES_EOF' | |
| ## Binary Artifacts | |
| This release includes pre-built binaries for the following platforms: | |
| ### macOS | |
| - ARM64 (Apple Silicon) - `drasi-server-aarch64-apple-darwin` | |
| - x86_64 (Intel) - `drasi-server-x86_64-apple-darwin` | |
| ### Windows | |
| - x86_64 (MSVC) - `drasi-server-x86_64-windows-msvc.exe` | |
| ### Linux (glibc) | |
| - ARM64 - `drasi-server-aarch64-linux-gnu` | |
| - x86_64 - `drasi-server-x86_64-linux-gnu` | |
| ### Linux (musl) | |
| - ARM64 - `drasi-server-aarch64-linux-musl` | |
| - x86_64 - `drasi-server-x86_64-linux-musl` | |
| ## Examples | |
| - `drasi-server-examples.zip` — Example configurations, scripts, and projects | |
| ## SSE CLI Binaries | |
| Pre-built binaries for the `drasi-sse-cli` tool (streams query change events via SSE): | |
| ### macOS | |
| - ARM64 (Apple Silicon) - `drasi-sse-cli-aarch64-apple-darwin` | |
| - x86_64 (Intel) - `drasi-sse-cli-x86_64-apple-darwin` | |
| ### Windows | |
| - x86_64 - `drasi-sse-cli-x86_64-windows.exe` | |
| ### Linux (glibc) | |
| - ARM64 - `drasi-sse-cli-aarch64-linux-gnu` | |
| - x86_64 - `drasi-sse-cli-x86_64-linux-gnu` | |
| ### Linux (musl) | |
| - ARM64 - `drasi-sse-cli-aarch64-linux-musl` | |
| - x86_64 - `drasi-sse-cli-x86_64-linux-musl` | |
| ## Docker Images | |
| Multi-arch Docker images are available at: | |
| - `${{ env.IMAGE_PREFIX }}/${{ env.IMAGE_NAME }}:${{ needs.determine-version.outputs.tag }}` | |
| - `${{ env.IMAGE_PREFIX }}/${{ env.IMAGE_NAME }}:latest` | |
| Supported architectures: `linux/amd64`, `linux/arm64` | |
| NOTES_EOF | |
| - name: Create or update versioned GitHub Release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| TAG="${{ needs.determine-version.outputs.tag }}" | |
| if gh release view "${TAG}" --repo ${{ github.repository }} 2>/dev/null; then | |
| echo "Release ${TAG} already exists. Updating with new artifacts..." | |
| gh release upload "${TAG}" release-assets/* --repo ${{ github.repository }} --clobber | |
| else | |
| echo "Creating new release ${TAG}..." | |
| gh release create "${TAG}" \ | |
| release-assets/* \ | |
| --repo ${{ github.repository }} \ | |
| --title "Release ${TAG}" \ | |
| --notes-file release-notes.md | |
| fi | |
| - name: Create or update 'latest' GitHub Release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| TAG="${{ needs.determine-version.outputs.tag }}" | |
| # Delete existing 'latest' release and tag if they exist | |
| if gh release view "latest" --repo ${{ github.repository }} 2>/dev/null; then | |
| echo "Deleting existing 'latest' release..." | |
| gh release delete "latest" --repo ${{ github.repository }} --yes --cleanup-tag | |
| fi | |
| echo "Creating 'latest' release (pointing to ${TAG})..." | |
| gh release create "latest" \ | |
| release-assets/* \ | |
| --repo ${{ github.repository }} \ | |
| --title "Latest Release (${TAG})" \ | |
| --notes-file release-notes.md \ | |
| --prerelease | |
| - name: Update summary | |
| run: | | |
| TAG="${{ needs.determine-version.outputs.tag }}" | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "## GitHub Releases Published :tada:" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "- Versioned: [\`${TAG}\`](https://github.com/${{ github.repository }}/releases/tag/${TAG})" >> $GITHUB_STEP_SUMMARY | |
| echo "- Latest: [\`latest\`](https://github.com/${{ github.repository }}/releases/tag/latest) (points to ${TAG})" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "Total assets: ${{ steps.prepare.outputs.asset_count }}" >> $GITHUB_STEP_SUMMARY |