# Memex Docker CI
#
# Triggered on tag push (v*)
# Builds multi-arch Docker image (amd64 + arm64)
# Each arch builds on native runner, then combined
# Pushes to GitHub Container Registry
name: Docker
on:
push:
tags:
- 'v*'
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# Build web frontend first (required for rust-embed)
build-web:
name: Build Web
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
cache-dependency-path: web/pnpm-lock.yaml
- name: Install dependencies
working-directory: web
run: pnpm install --frozen-lockfile
- name: Build
working-directory: web
run: pnpm build
- name: Upload web dist
uses: actions/upload-artifact@v4
with:
name: web-dist
path: web/dist
retention-days: 1
# Build Rust binary for each architecture (needs web-dist for rust-embed)
build-binary:
name: Build Binary (${{ matrix.arch }})
runs-on: ${{ matrix.runner }}
needs: [build-web]
strategy:
matrix:
include:
- arch: amd64
runner: ubuntu-latest
target: x86_64-unknown-linux-gnu
- arch: arm64
runner: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download web dist
uses: actions/download-artifact@v4
with:
name: web-dist
path: web/dist
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo
uses: Swatinem/rust-cache@v2
with:
workspaces: memex-rs
shared-key: ${{ matrix.arch }}
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
pkg-config libssl-dev protobuf-compiler libprotobuf-dev
- name: Build release binary
working-directory: memex-rs
run: |
cargo build --release --features cli
strip target/release/memex
- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: memex-${{ matrix.arch }}
path: memex-rs/target/release/memex
retention-days: 1
# Package into multi-arch Docker image
package:
name: Package Docker Image
runs-on: ubuntu-latest
needs: [build-binary, build-web]
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Prepare build context
run: |
mkdir -p build/amd64 build/arm64 build/web
cp artifacts/memex-amd64/memex build/amd64/
cp artifacts/memex-arm64/memex build/arm64/
cp -r artifacts/web-dist/* build/web/
chmod +x build/amd64/memex build/arm64/memex
# Download vimo-agent for each architecture
curl -L -o build/amd64/vimo-agent https://github.com/vimo-ai/ai-cli-session-db/releases/latest/download/vimo-agent-linux-x64
curl -L -o build/arm64/vimo-agent https://github.com/vimo-ai/ai-cli-session-db/releases/latest/download/vimo-agent-linux-arm64
chmod +x build/amd64/vimo-agent build/arm64/vimo-agent
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push amd64
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/Dockerfile.ci
platforms: linux/amd64
build-args: |
TARGETARCH=amd64
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-amd64
cache-from: type=gha,scope=amd64
cache-to: type=gha,mode=max,scope=amd64
- name: Build and push arm64
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/Dockerfile.ci
platforms: linux/arm64
build-args: |
TARGETARCH=arm64
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-arm64
cache-from: type=gha,scope=arm64
cache-to: type=gha,mode=max,scope=arm64
- name: Create and push manifest
run: |
# Create multi-arch manifest for each tag
for tag in $(echo '${{ steps.meta.outputs.tags }}' | tr ',' '\n'); do
docker buildx imagetools create -t "$tag" \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-amd64 \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-arm64
done
- name: Summary
run: |
echo "### Docker Image Published" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Registry**: \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Tags**:" >> $GITHUB_STEP_SUMMARY
echo '${{ steps.meta.outputs.tags }}' | tr ',' '\n' | sed 's/^/- /' >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Platforms**: \`linux/amd64\`, \`linux/arm64\`" >> $GITHUB_STEP_SUMMARY