Skip to content

Release - Docker Images #213

Release - Docker Images

Release - Docker Images #213

name: Release - Docker Images
on:
workflow_dispatch:
push:
tags:
- '*.*.*'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
AWS_REGION: us-east-1
jobs:
image-tag:
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.resolve.outputs.tag }}
steps:
- name: Resolve Docker image tag
id: resolve
shell: bash
run: |
if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" && "${GITHUB_REF_TYPE}" == "branch" ]]; then
tag="$(printf '%s' "${GITHUB_REF_NAME}" | sed -E 's#[^A-Za-z0-9_.-]+#-#g')"
tag="${tag:0:128}"
if [[ ! "$tag" =~ ^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$ ]]; then
tag="branch-${tag}"
fi
tag="${tag:0:128}"
if [[ ! "$tag" =~ ^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$ ]]; then
echo "::error::Branch name '${GITHUB_REF_NAME}' did not produce a valid Docker tag"
exit 1
fi
else
tag="latest"
fi
echo "tag=$tag" >> "$GITHUB_OUTPUT"
echo "Resolved Docker image tag: $tag"
# Use the reusable parallel test workflow
frontend-tests:
uses: ./.github/workflows/test-frontend-parallel.yml
agents-tests:
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
task: [test, check, build]
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.10"
- name: Cache Bun install
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: agents-bun-${{ runner.os }}-${{ hashFiles('agents/bun.lock') }}
restore-keys: |
agents-bun-${{ runner.os }}-
- name: Install dependencies
working-directory: agents
run: bun install --frozen-lockfile
- name: Run ${{ matrix.task }}
working-directory: agents
run: |
if [ "${{ matrix.task }}" = "test" ]; then
bun test
elif [ "${{ matrix.task }}" = "check" ]; then
bun run check
else
bun run test:build
fi
backend-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Cache GGUF model
uses: actions/cache@v4
with:
path: backend/llm/backends/llamacpp/models/*.gguf
key: gguf-model-granite-v2
enableCrossOsArchive: true
- name: Download GGUF model
run: |
if [ ! -f backend/llm/backends/llamacpp/models/granite-embedding-107m-multilingual-Q8_0.gguf ]; then
mkdir -p backend/llm/backends/llamacpp/models
curl -fSL -o backend/llm/backends/llamacpp/models/granite-embedding-107m-multilingual-Q8_0.gguf \
"https://huggingface.co/keisuke-miyako/granite-embedding-107m-multilingual-gguf-q8_0/resolve/main/granite-embedding-107m-multilingual-Q8_0.gguf?download=true"
fi
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.26.2'
- name: Install build dependencies
run: |
sudo apt-get update
sudo apt-get install -y cmake g++ libvulkan-dev glslc
- name: Compute llama-go submodule sha
id: llama-sha
run: echo "sha=$(git -C backend/util/llama-go rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: Cache llama.cpp build (Vulkan)
id: llama-cache
uses: actions/cache@v4
with:
path: |
backend/util/llama-go/libbinding.a
backend/util/llama-go/libllama.a
backend/util/llama-go/libggml*.a
backend/util/llama-go/libcommon.a
backend/util/llama-go/build
# `portable` suffix: GGML_NATIVE=OFF so cached artifacts are
# safe to reuse across heterogeneous GitHub-hosted runners
# (mixed AVX-512 / non-AVX-512 CPUs). Without it, an artifact
# built on an AVX-512 host crashes with SIGILL on runners that
# lack AVX-512.
key: llama-vulkan-linux-portable-${{ steps.llama-sha.outputs.sha }}
- name: Build llama.cpp (with Vulkan GPU support)
if: steps.llama-cache.outputs.cache-hit != 'true'
run: |
cd backend/util/llama-go
BUILD_TYPE=vulkan CMAKE_ARGS="-DBUILD_SHARED_LIBS=OFF -DGGML_NATIVE=OFF" make libbinding.a
- name: Run tests
run: go test --count 1 ./backend/...
env:
CGO_ENABLED: 1
LIBRARY_PATH: ${{ github.workspace }}/backend/util/llama-go
C_INCLUDE_PATH: ${{ github.workspace }}/backend/util/llama-go
LLAMA_LOG: error
# Run tests again with the race-detector.
# Using the same job to reuse the build cache.
- name: Run tests with race detector
run: go test --count 1 -race ./backend/...
env:
CGO_ENABLED: 1
LIBRARY_PATH: ${{ github.workspace }}/backend/util/llama-go
C_INCLUDE_PATH: ${{ github.workspace }}/backend/util/llama-go
LLAMA_LOG: error
# Build frontend apps and run performance tests.
# Uploads pre-built artifacts so Docker jobs skip rebuilding.
build-and-perf-test:
runs-on: ubuntu-latest
needs: [frontend-tests, backend-tests]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Install Node.js 22
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
- name: Install Dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Build Web App
run: pnpm web:prod
- name: Run Notify Tests
run: pnpm --filter @shm/notify test
- name: Build Notify App
run: pnpm notify:build
- name: Start Web Server
run: |
pnpm web:start &
sleep 5 # Wait for server to start
- name: Run Performance Tests
run: |
cd frontend/apps/perf-web
pnpm start --url http://localhost:3000 --app web
- name: Upload web build artifacts
uses: actions/upload-artifact@v4
with:
name: web-build
path: frontend/apps/web/build/
retention-days: 1
- name: Upload notify build artifacts
uses: actions/upload-artifact@v4
with:
name: notify-build
path: frontend/apps/notify/build/
retention-days: 1
docker-web:
runs-on: ubuntu-latest
needs: [image-tag, build-and-perf-test]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Get commit date
run: |
COMMIT_DATE=$(git show -s --format="%cd" ${{ github.sha }})
echo "COMMIT_DATE=$COMMIT_DATE" >> $GITHUB_ENV
- name: Download web build artifacts
uses: actions/download-artifact@v4
with:
name: web-build
path: frontend/apps/web/build/
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: DockerHub Release seedhypermedia/web:${{ needs.image-tag.outputs.tag }}
uses: docker/build-push-action@v4
with:
context: .
push: true
file: frontend/apps/web/Dockerfile
tags: seedhypermedia/web:${{ needs.image-tag.outputs.tag }}
build-args: |
PREBUILT=true
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
SITE_SENTRY_DSN=${{ secrets.SITE_SENTRY_DSN }}
COMMIT_HASH=${{ github.sha }}
BRANCH=${{ github.ref }}
DATE=${{ env.COMMIT_DATE }}
cache-from: type=gha,scope=docker-web-release
cache-to: type=gha,mode=max,scope=docker-web-release
docker-notify:
runs-on: ubuntu-latest
needs: [image-tag, build-and-perf-test]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Get commit date
run: |
COMMIT_DATE=$(git show -s --format="%cd" ${{ github.sha }})
echo "COMMIT_DATE=$COMMIT_DATE" >> $GITHUB_ENV
- name: Download notify build artifacts
uses: actions/download-artifact@v4
with:
name: notify-build
path: frontend/apps/notify/build/
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: DockerHub Release seedhypermedia/notify:${{ needs.image-tag.outputs.tag }}
uses: docker/build-push-action@v4
with:
context: .
push: true
file: frontend/apps/notify/Dockerfile
tags: seedhypermedia/notify:${{ needs.image-tag.outputs.tag }}
build-args: |
PREBUILT=true
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
NOTIFY_SENTRY_DSN=${{ secrets.NOTIFY_SENTRY_DSN }}
COMMIT_HASH=${{ github.sha }}
BRANCH=${{ github.ref }}
DATE=${{ env.COMMIT_DATE }}
cache-from: type=gha,scope=docker-notify-release
cache-to: type=gha,mode=max,scope=docker-notify-release
docker-site:
runs-on: ubuntu-latest
needs: [image-tag, frontend-tests, backend-tests]
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Get commit date
run: |
COMMIT_DATE=$(git show -s --format="%cd" ${{ github.sha }})
echo "COMMIT_DATE=$COMMIT_DATE" >> $GITHUB_ENV
- name: Cache GGUF model
uses: actions/cache@v4
with:
path: backend/llm/backends/llamacpp/models/*.gguf
key: gguf-model-granite-v2
enableCrossOsArchive: true
- name: Download GGUF model
run: |
if [ ! -f backend/llm/backends/llamacpp/models/granite-embedding-107m-multilingual-Q8_0.gguf ]; then
mkdir -p backend/llm/backends/llamacpp/models
curl -fSL -o backend/llm/backends/llamacpp/models/granite-embedding-107m-multilingual-Q8_0.gguf \
"https://huggingface.co/keisuke-miyako/granite-embedding-107m-multilingual-gguf-q8_0/resolve/main/granite-embedding-107m-multilingual-Q8_0.gguf?download=true"
fi
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: DockerHub Release seedhypermedia/site:${{ needs.image-tag.outputs.tag }}
uses: docker/build-push-action@v4
with:
context: .
push: true
file: backend/cmd/seed-daemon/Dockerfile
tags: seedhypermedia/site:${{ needs.image-tag.outputs.tag }}
build-args: |
COMMIT_HASH=${{ github.sha }}
BRANCH=${{ github.ref }}
DATE=${{ env.COMMIT_DATE }}
cache-from: type=gha,scope=docker-site-release
cache-to: type=gha,mode=max,scope=docker-site-release
docker-monitord:
runs-on: ubuntu-latest
needs: [image-tag, frontend-tests, backend-tests]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: DockerHub Release seedhypermedia/monitord:${{ needs.image-tag.outputs.tag }}
uses: docker/build-push-action@v4
with:
push: true
file: backend/cmd/monitord/Dockerfile
tags: seedhypermedia/monitord:${{ needs.image-tag.outputs.tag }}
cache-from: type=gha,scope=docker-monitord-release
cache-to: type=gha,mode=max,scope=docker-monitord-release
docker-relayd:
runs-on: ubuntu-latest
needs: [image-tag, frontend-tests, backend-tests]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: DockerHub Release seedhypermedia/relayd:${{ needs.image-tag.outputs.tag }}
uses: docker/build-push-action@v4
with:
push: true
file: backend/cmd/relayd/Dockerfile
tags: seedhypermedia/relayd:${{ needs.image-tag.outputs.tag }}
cache-from: type=gha,scope=docker-relayd-release
cache-to: type=gha,mode=max,scope=docker-relayd-release
docker-agents:
runs-on: ubuntu-latest
needs: [image-tag, agents-tests]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: DockerHub Release seedhypermedia/agents:${{ needs.image-tag.outputs.tag }}
uses: docker/build-push-action@v4
with:
context: .
push: true
file: agents/Dockerfile
tags: seedhypermedia/agents:${{ needs.image-tag.outputs.tag }}
cache-from: type=gha,scope=docker-agents-release
cache-to: type=gha,mode=max,scope=docker-agents-release
docker-vault:
runs-on: ubuntu-latest
needs: [image-tag, frontend-tests, backend-tests]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: DockerHub Release seedhypermedia/vault:${{ needs.image-tag.outputs.tag }}
uses: docker/build-push-action@v4
with:
context: .
push: true
file: vault/Dockerfile
tags: seedhypermedia/vault:${{ needs.image-tag.outputs.tag }}
cache-from: type=gha,scope=docker-vault-release
cache-to: type=gha,mode=max,scope=docker-vault-release