Skip to content

Commit

Permalink
Merge branch 'main' into feature/storage-migration
Browse files Browse the repository at this point in the history
  • Loading branch information
FelixTJDietrich authored Dec 6, 2024
2 parents 60b2e43 + 1235524 commit e478cdc
Show file tree
Hide file tree
Showing 10 changed files with 354 additions and 7 deletions.
94 changes: 94 additions & 0 deletions .github/workflows/build-and-push-shared.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Move to ls1intum/.github/.github/workflows/build-and-push-docker-image.yml@main in the future
name: Build and Push Docker Image

on:
workflow_call:
inputs:
image-name:
type: string
default: ${{ github.repository }}
description: "The name for the docker image (Default: Repository name)"
docker-file:
type: string
default: Dockerfile
description: "The path to the Dockerfile (Default: ./Dockerfile)"
docker-context:
type: string
default: .
description: "The context for the Docker build (Default: .)"
build-args:
type: string
description: "List of additional build contexts (e.g., name=path)"
required: false
platforms:
type: string
description: "List of platforms for which to build the image"
default: linux/amd64,linux/arm64
registry:
type: string
default: ghcr.io
description: "The registry to push the image to (Default: ghcr.io)"

secrets:
registry-user:
required: false
registry-password:
required: false

outputs:
image-tag:
description: "The tag of the pushed image"
value: ${{ jobs.build.outputs.image-tag }}
jobs:
build:
name: Build Docker Image for ${{ inputs.image-name }}
runs-on: ubuntu-latest
outputs:
image-tag: ${{ steps.set-tag.outputs.image-tag }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: all

- name: Install Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ inputs.registry }}
username: ${{ secrets.registry-user || github.actor }}
password: ${{ secrets.registry-password || secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ inputs.registry }}/${{ inputs.image-name }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=sha,prefix=,format=long
- name: Set image tag output
id: set-tag
run: echo "image-tag=${{ steps.meta.outputs.version }}" >> $GITHUB_OUTPUT

- name: Build and push Docker Image
uses: docker/build-push-action@v6
with:
context: ${{ inputs.docker-context }}
file: ${{ inputs.docker-file }}
platforms: ${{ inputs.platforms }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: ${{ inputs.build-args }}
push: true
16 changes: 16 additions & 0 deletions .github/workflows/build-and-push.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Build Docker Image

on:
pull_request:
push:
branches: [main]

jobs:
build-and-push-workflow:
name: Build and Push Docker Image
# TODO: uses: ls1intum/.github/.github/workflows/build-and-push-docker-image.yml@main
uses: ./.github/workflows/build-and-push-shared.yml
with:
image-name: ls1intum/apollon_standalone
docker-file: Dockerfile.redis
secrets: inherit
32 changes: 32 additions & 0 deletions .github/workflows/deploy-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Deploy to Dev

on:
workflow_dispatch:
inputs:
image-tag:
type: string
description: "Image tag to deploy (default: pr-<number> if PR exists, latest for default branch)"

jobs:
prepare-env:
runs-on: ubuntu-latest
environment: Dev
outputs:
env-vars: |
DEPLOYMENT_URL=${{ vars.DEPLOYMENT_URL }}
APOLLON_REDIS_DIAGRAM_TTL=${{ vars.APOLLON_REDIS_DIAGRAM_TTL }}
steps:
- name: Do nothing
run: echo "Nothing to do here"

deploy:
needs: prepare-env
# TODO: uses: ls1intum/.github/.github/workflows/deploy-docker-compose.yml@main
uses: ./.github/workflows/deploy-docker-compose-shared.yml
with:
environment: Dev
docker-compose-file: "./docker-compose.prod.yml"
main-image-name: ls1intum/apollon_standalone
image-tag: ${{ inputs.image-tag }}
env-vars: ${{ needs.prepare-env.outputs.env-vars }}
secrets: inherit
158 changes: 158 additions & 0 deletions .github/workflows/deploy-docker-compose-shared.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# ls1intum/.github/workflows/deploy-docker-compose.yml
name: Deploy Docker Compose

on:
workflow_call:
inputs:
environment:
type: string
description: "The deployment environment (e.g., production, staging)"
required: true
docker-compose-file:
type: string
default: "./docker-compose.yml"
description: "Path to the Docker Compose file (Default: ./docker-compose.yml)"
main-image-name:
type: string
description: "The name of the main image for checking if it exists with the given tag"
required: true
image-tag:
type: string
description: "Image tag to deploy (default: pr-<number> if PR exists, latest for default branch)"
env-vars:
type: string
description: "Additional environment variables in KEY=VALUE format, separated by newlines"
required: false

jobs:
prepare-deploy:
runs-on: ubuntu-latest
environment: Dev
outputs:
image-tag-to-deploy: ${{ steps.retrieve-image-tag.outputs.image-tag-to-deploy }}

steps:
- name: Retrieve image tag to deploy
id: retrieve-image-tag
run: |
if [ -n "${{ inputs.image-tag }}" ]; then
echo "image-tag-to-deploy=${{ inputs.image-tag }}" >> $GITHUB_OUTPUT
exit 0
fi
REF=$(echo "${{ github.event.ref }}" | sed -n 's#^refs/heads/##p')
if [ "$REF" = "${{ github.event.repository.default_branch }}" ]; then
echo "image-tag-to-deploy=latest" >> $GITHUB_OUTPUT
fi
PULLS=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "https://api.github.com/repos/${{ github.repository }}/pulls?head=${{ github.repository_owner }}:${REF}")
PR_NUMBER=$(echo "$PULLS" | jq -r '.[0].number')
if [ -z "$PR_NUMBER" ]; then
echo "No PR found for branch $REF."
exit 1
else
echo "PR #$PR_NUMBER found for branch $REF."
echo "image-tag-to-deploy=pr-$PR_NUMBER" >> $GITHUB_OUTPUT
fi
- name: Check if image exists
run: |
IMAGE_NAME="${{ inputs.main-image-name }}"
IMAGE_TAG="${{ steps.retrieve-image-tag.outputs.image-tag-to-deploy }}"
ENCODED_TOKEN=$(echo -n "${{ secrets.GITHUB_TOKEN }}" | base64)
TAG_EXISTS=$(curl -s -H "Authorization: Bearer ${ENCODED_TOKEN}" \
https://ghcr.io/v2/${IMAGE_NAME}/tags/list \
| jq -r --arg TAG "${IMAGE_TAG}" '.tags[] | select(. == $TAG)')
if [ -z "$TAG_EXISTS" ]; then
echo "Image ${IMAGE_NAME}:${IMAGE_TAG} does not exist."
exit 1
else
echo "Image ${IMAGE_NAME}:${IMAGE_TAG} exists."
fi
deploy:
needs: prepare-deploy
runs-on: ubuntu-latest
environment:
name: ${{ inputs.environment }}
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: SSH to VM and execute docker compose down (if exists)
uses: appleboy/[email protected]
with:
host: ${{ vars.VM_HOST }}
username: ${{ vars.VM_USERNAME }}
key: ${{ secrets.VM_SSH_PRIVATE_KEY }}
proxy_host: ${{ vars.DEPLOYMENT_GATEWAY_HOST }}
proxy_username: ${{ vars.DEPLOYMENT_GATEWAY_USER }}
proxy_key: ${{ secrets.DEPLOYMENT_GATEWAY_SSH_KEY }}
proxy_port: ${{ vars.DEPLOYMENT_GATEWAY_PORT }}
script: |
#!/bin/bash
set -e # Exit immediately if a command exits with a non-zero status
COMPOSE_FILE="${{ inputs.docker-compose-file }}"
# Check if docker-compose.prod.yml exists
if [ -f "$COMPOSE_FILE" ]; then
echo "$COMPOSE_FILE found."
# Check if .env exists
if [ -f ".env" ]; then
docker compose -f "$COMPOSE_FILE" --env-file=".env" down --remove-orphans --rmi all
else
docker compose -f "$COMPOSE_FILE" down --remove-orphans --rmi all
fi
else
echo "$COMPOSE_FILE does not exist. Skipping docker compose down."
fi
- name: Copy docker compose file to VM host
uses: appleboy/[email protected]
with:
host: ${{ vars.VM_HOST }}
username: ${{ vars.VM_USERNAME }}
key: ${{ secrets.VM_SSH_PRIVATE_KEY }}
proxy_host: ${{ vars.DEPLOYMENT_GATEWAY_HOST }}
proxy_username: ${{ vars.DEPLOYMENT_GATEWAY_USER }}
proxy_key: ${{ secrets.DEPLOYMENT_GATEWAY_SSH_KEY }}
proxy_port: ${{ vars.DEPLOYMENT_GATEWAY_PORT }}
source: ${{ inputs.docker-compose-file }}
target: /home/${{ vars.VM_USERNAME }}

- name: SSH to VM and create .env file
uses: appleboy/[email protected]
with:
host: ${{ vars.VM_HOST }}
username: ${{ vars.VM_USERNAME }}
key: ${{ secrets.VM_SSH_PRIVATE_KEY }}
proxy_host: ${{ vars.DEPLOYMENT_GATEWAY_HOST }}
proxy_username: ${{ vars.DEPLOYMENT_GATEWAY_USER }}
proxy_key: ${{ secrets.DEPLOYMENT_GATEWAY_SSH_KEY }}
proxy_port: ${{ vars.DEPLOYMENT_GATEWAY_PORT }}
script: |
touch .env
echo "ENVIRONMENT=${{ inputs.environment }}" > .env
echo "IMAGE_TAG=${{ needs.prepare-deploy.outputs.image-tag-to-deploy }}" >> .env
if [ "${{ inputs.env-vars }}" != "" ]; then
echo "${{ inputs.env-vars }}" >> .env
fi
- name: SSH to VM and execute docker compose up
uses: appleboy/[email protected]
with:
host: ${{ vars.VM_HOST }}
username: ${{ vars.VM_USERNAME }}
key: ${{ secrets.VM_SSH_PRIVATE_KEY }}
proxy_host: ${{ vars.DEPLOYMENT_GATEWAY_HOST }}
proxy_username: ${{ vars.DEPLOYMENT_GATEWAY_USER }}
proxy_key: ${{ secrets.DEPLOYMENT_GATEWAY_SSH_KEY }}
proxy_port: ${{ vars.DEPLOYMENT_GATEWAY_PORT }}
script: |
docker compose -f ${{ inputs.docker-compose-file }} --env-file=.env up --pull=always -d
8 changes: 3 additions & 5 deletions Dockerfile.redis
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@ RUN apk add --no-cache \
pango-dev \
giflib-dev


ARG DEPLOYMENT_URL="http://localhost:8080"

ENV APOLLON_REDIS_URL=""
ENV DEPLOYMENT_URL=${DEPLOYMENT_URL}
ENV DEPLOYMENT_URL="http://localhost:8080"
ENV APOLLON_REDIS_URL="redis://localhost:6379"
ENV APOLLON_REDIS_DIAGRAM_TTL="30d"

WORKDIR /app

Expand Down
36 changes: 36 additions & 0 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
services:
redis:
image: redis/redis-stack-server:7.4.0-v1
container_name: apollon-redis
volumes:
- ./redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- apollon-network

apollon-standalone:
image: "ghcr.io/ls1intum/apollon_standalone:${IMAGE_TAG}"
container_name: apollon-standalone
environment:
- APOLLON_REDIS_URL=redis://apollon-redis:6379
- APOLLON_REDIS_DIAGRAM_TTL=${APOLLON_REDIS_DIAGRAM_TTL}
- DEPLOYMENT_URL=${DEPLOYMENT_URL}
volumes:
- /opt/apollon/diagrams:/app/diagrams
restart: unless-stopped
ports:
- "8080:8080"
depends_on:
redis:
condition: service_healthy
networks:
- apollon-network

networks:
apollon-network:
driver: bridge
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ services:
- APOLLON_REDIS_URL=redis://apollon_redis:6379
- APOLLON_REDIS_DIAGRAM_TTL=${APOLLON_REDIS_DIAGRAM_TTL}
- DEPLOYMENT_URL=${DEPLOYMENT_URL}
volumes:
- ./diagrams:/app/diagrams
restart: always
networks:
- apollon_network
Expand Down
11 changes: 11 additions & 0 deletions packages/server/src/main/server.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import fs from 'fs';
import path from 'path';
import bodyParser from 'body-parser';
import express, { RequestHandler } from 'express';
import * as Sentry from '@sentry/node';
Expand All @@ -19,6 +21,15 @@ if (process.env.SENTRY_DSN) {
Sentry.setTag('package', 'server');
}

// Replace http://localhost:8080 with the actual process.env.DEPLOYMENT_URL
const jsFiles = fs.readdirSync(webappPath).filter((file) => file.endsWith('.js'));
jsFiles.forEach((file) => {
const filePath = path.join(webappPath, file);
const content = fs.readFileSync(filePath, 'utf8')
.replace(/http:\/\/localhost:8080/g, process.env.DEPLOYMENT_URL || 'http://localhost:8080');
fs.writeFileSync(filePath, content);
});

app.use('/', express.static(webappPath));
app.use(bodyParser.json() as RequestHandler);
app.use(
Expand Down
2 changes: 1 addition & 1 deletion packages/webapp/webpack/webpack.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ module.exports = {
}),
new webpack.DefinePlugin({
'process.env.APPLICATION_SERVER_VERSION': JSON.stringify(process.env.APPLICATION_SERVER_VERSION || true),
'process.env.DEPLOYMENT_URL': JSON.stringify(process.env.DEPLOYMENT_URL || 'http://localhost:8888'),
'process.env.DEPLOYMENT_URL': JSON.stringify(process.env.DEPLOYMENT_URL || 'http://localhost:8080'),
'process.env.SENTRY_DSN': JSON.stringify(process.env.SENTRY_DSN || null),
'process.env.POSTHOG_HOST': JSON.stringify(process.env.POSTHOG_HOST || null),
'process.env.POSTHOG_KEY': JSON.stringify(process.env.POSTHOG_KEY || null),
Expand Down
Loading

0 comments on commit e478cdc

Please sign in to comment.