Skip to content

CI - Test and Build #166

CI - Test and Build

CI - Test and Build #166

Workflow file for this run

name: CI - Test and Build
on:
schedule:
- cron: '0 4 * * *'
- cron: '0 16 * * *'
push:
branches: ["main"]
pull_request:
branches: ["main"]
jobs:
# ==========================================================================
# Set environment variables for Docker image tagging
# ==========================================================================
set-env:
runs-on: ubuntu-24.04
outputs:
DOCKER_IMAGE_NAME: ${{ steps.env_vars.outputs.DOCKER_IMAGE_NAME }}
SHA_VAR: ${{ steps.env_vars.outputs.SHA_VAR }}
DATE_VAR: ${{ steps.dates.outputs.DATE_VAR }}
DATE_TIME_VAR: ${{ steps.dates.outputs.DATE_TIME_VAR }}
SOURCE_DATE_EPOCH_VAR: ${{ steps.dates.outputs.SOURCE_DATE_EPOCH_VAR }}
steps:
- name: Set repository name and SHA
id: env_vars
run: |
echo "DOCKER_IMAGE_NAME=ghcr.io/${GITHUB_REPOSITORY,,}" >> $GITHUB_OUTPUT
echo "SHA_VAR=${GITHUB_SHA}" >> $GITHUB_OUTPUT
- name: Generate date and time strings
id: dates
run: |
now=$(date '+%s')
echo "DATE_VAR=$(date -u -d "@$now" '+%Y-%m-%d')" >> $GITHUB_OUTPUT
echo "DATE_TIME_VAR=$(date -u -d "@$now" '+%Y-%m-%d.%H-%M-%S')" >> $GITHUB_OUTPUT
year_month=$(date -u -d "@$now" '+%Y-%m')
echo "SOURCE_DATE_EPOCH_VAR=$(date -u -d "${year_month}-01 00:00:00" '+%s')" >> $GITHUB_OUTPUT
# ==========================================================================
# Frontend Tests (Cloudflare Pages handles build & deployment)
# ==========================================================================
frontend-test:
runs-on: ubuntu-24.04
defaults:
run:
working-directory: frontend
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '24'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json
- name: Install dependencies
run: npm ci --no-audit --no-fund
- name: Run tests
run: npm test -- --run
# ==========================================================================
# Trigger Cloudflare Pages Deployment
# ==========================================================================
deploy-frontend:
needs: [frontend-test]
if: github.event_name != 'pull_request'
runs-on: ubuntu-24.04
steps:
- name: Trigger Cloudflare Pages deploy
run: |
curl -X POST "${{ secrets.CF_PAGES_DEPLOY_HOOK }}"
# ==========================================================================
# Backend Tests
# ==========================================================================
backend-test:
runs-on: ubuntu-24.04
defaults:
run:
working-directory: backend
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '24'
cache: 'npm'
cache-dependency-path: backend/package-lock.json
- name: Install dependencies
run: npm ci --no-audit --no-fund
- name: Generate Prisma client
run: npx prisma generate
- name: Run database migrations
run: npx prisma migrate deploy
env:
DATABASE_URL: "file:./test.db"
- name: Run tests
run: npm test
env:
DATABASE_URL: "file:./test.db"
JWT_SECRET: "test-secret-key-for-ci"
# ==========================================================================
# Backend Docker Build Matrix (amd64 + arm64)
# ==========================================================================
backend-build:
needs: [set-env, frontend-test, backend-test]
if: github.event_name != 'pull_request'
permissions:
contents: read
packages: write
runs-on: ${{ matrix.runner }}
strategy:
matrix:
include:
- platform: linux/amd64
variant: amd64
runner: ubuntu-24.04
- platform: linux/arm64
variant: arm64
runner: ubuntu-24.04-arm
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: ./backend
file: ./backend/Dockerfile
platforms: ${{ matrix.platform }}
push: true
tags: |
${{ needs.set-env.outputs.DOCKER_IMAGE_NAME }}:latest.${{ matrix.variant }}
${{ needs.set-env.outputs.DOCKER_IMAGE_NAME }}:${{ needs.set-env.outputs.DATE_VAR }}.${{ matrix.variant }}
${{ needs.set-env.outputs.DOCKER_IMAGE_NAME }}:${{ needs.set-env.outputs.DATE_TIME_VAR }}.${{ matrix.variant }}
${{ needs.set-env.outputs.DOCKER_IMAGE_NAME }}:${{ needs.set-env.outputs.SHA_VAR }}.${{ matrix.variant }}
${{ needs.set-env.outputs.DOCKER_IMAGE_NAME }}:${{ needs.set-env.outputs.SHA_VAR }}.${{ needs.set-env.outputs.DATE_VAR }}.${{ matrix.variant }}
${{ needs.set-env.outputs.DOCKER_IMAGE_NAME }}:${{ needs.set-env.outputs.SHA_VAR }}.${{ needs.set-env.outputs.DATE_TIME_VAR }}.${{ matrix.variant }}
outputs: "type=registry,compression=zstd,force-compression=true,compression-level=3,rewrite-timestamp=true,oci-mediatypes=true"
cache-from: type=gha,scope=${{ matrix.variant }}
cache-to: type=gha,mode=max,scope=${{ matrix.variant }}
env:
SOURCE_DATE_EPOCH: ${{ needs.set-env.outputs.SOURCE_DATE_EPOCH_VAR }}
# ==========================================================================
# Create Multi-arch Manifest
# ==========================================================================
create-manifest:
needs: [set-env, backend-build]
if: github.event_name != 'pull_request'
permissions:
packages: write
runs-on: ubuntu-24.04
steps:
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create and push manifest list
run: |
# The most specific tags for the platform-specific images
AMD64_TAG="${DOCKER_IMAGE_NAME}:${SHA_VAR}.${DATE_TIME_VAR}.amd64"
ARM64_TAG="${DOCKER_IMAGE_NAME}:${SHA_VAR}.${DATE_TIME_VAR}.arm64"
# All the tags we want to create
TAG_OPTIONS=()
TAGS=(
"latest"
"${DATE_VAR}"
"${DATE_TIME_VAR}"
"${SHA_VAR}"
"${SHA_VAR}.${DATE_VAR}"
"${SHA_VAR}.${DATE_TIME_VAR}"
)
# Build the tag options for docker buildx imagetools
for tag in "${TAGS[@]}"; do
TAG_OPTIONS+=(--tag "${DOCKER_IMAGE_NAME}:${tag}")
done
# Create a single manifest with multiple tags
echo "Creating manifest with tags: ${TAGS[*]}"
docker buildx imagetools create "${TAG_OPTIONS[@]}" "${AMD64_TAG}" "${ARM64_TAG}"
env:
DOCKER_IMAGE_NAME: ${{ needs.set-env.outputs.DOCKER_IMAGE_NAME }}
DATE_VAR: ${{ needs.set-env.outputs.DATE_VAR }}
DATE_TIME_VAR: ${{ needs.set-env.outputs.DATE_TIME_VAR }}
SHA_VAR: ${{ needs.set-env.outputs.SHA_VAR }}