Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build and Push Docker Image Workflow #192

Draft
wants to merge 25 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions .github/workflows/build-and-push-docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: Build and Push Docker Images

on:
pull_request:
paths-ignore:
- 'README.md'
- 'CODE_OF_CONDUCT.md'
- 'CONTRIBUTING.md'
- 'LICENSE'
- 'SECURITY.md'
- 'docs/**'
- 'keycloakify/**'
- '.github/**'
- '!.github/workflows/build-and-push-docker-image.yml'
- '!.github/workflows/dev.yml'
push:
branches:
- develop

jobs:
build:
name: ${{ matrix.path }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- dockerfile: ./webapp/Dockerfile
image: ls1intum/Hephaestus/webapp
context: ./webapp
path: webapp
- dockerfile: ./server/intelligence-service/Dockerfile
image: ls1intum/Hephaestus/intelligence-service
context: ./server/intelligence-service
path: intelligence-service
- dockerfile: ./server/webhook-ingest/Dockerfile
image: ls1intum/Hephaestus/webhook-ingest
context: ./server/webhook-ingest
path: webhook-ingest
- dockerfile: ./server/application-server/Dockerfile
image: ls1intum/Hephaestus/application-server
context: ./server/application-server
path: application-server

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: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ matrix.image }}
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: Build and push Docker Image
uses: docker/build-push-action@v6
with:
context: ${{ matrix.context }}
file: ${{ matrix.dockerfile }}
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
push: true
cache-from: type=gha,scope=${{ matrix.image }}
cache-to: type=gha,scope=${{ matrix.image }},mode=max
1 change: 0 additions & 1 deletion build_images.sh

This file was deleted.

8 changes: 6 additions & 2 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
services:
application-server:
image: hephaestus-application-server
build:
context: ./server/application-server
ports:
- '8080'
environment:
Expand Down Expand Up @@ -43,4 +44,7 @@ services:

networks:
app-network:
driver: bridge`
driver: bridge

volumes:
postgresql-data:
26 changes: 26 additions & 0 deletions server/application-server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
FROM maven:3.9.8-eclipse-temurin-21 AS build

WORKDIR /app

COPY pom.xml .

# This step is to cache dependencies, avoiding re-downloading them every time
RUN mvn dependency:go-offline

COPY src ./src

RUN mvn clean package -DskipTests

FROM eclipse-temurin:21

WORKDIR /app

COPY --from=build /app/target/*.jar /app/server.jar

RUN addgroup --system spring && adduser --system spring --ingroup spring

USER spring:spring

EXPOSE 8080

ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app/server.jar"]
8 changes: 0 additions & 8 deletions server/application-server/nixpacks.toml

This file was deleted.

70 changes: 28 additions & 42 deletions webapp/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,55 +1,41 @@
FROM node:latest as build
FROM node:22 as build

Check warning on line 1 in webapp/Dockerfile

View workflow job for this annotation

GitHub Actions / webapp

The 'as' keyword should match the case of the 'from' keyword

FromAsCasing: 'as' and 'FROM' keywords' casing do not match More info: https://docs.docker.com/go/dockerfile/rule/from-as-casing/

WORKDIR /app

COPY ./ /app/

# Ensure .env file exists
RUN mv .env* .env || true
RUN touch .env
RUN cat .env

# Fix buggy replacement of COOLIFY_URL in .env
RUN COOLIFY_URL_VALUE=$(grep '^COOLIFY_URL=' .env | cut -d '=' -f2) && \
sed -i "s|\$COOLIFY_URL|$COOLIFY_URL_VALUE|g" .env

# Export environment variables from .env
# This assumes that .env contains lines like VARIABLE=value
# and does not contain spaces around the '='
RUN set -a && \
. /app/.env && \
set +a && \
echo "Generating environment.prod.ts" && \
cat > src/environments/environment.prod.ts <<EOF
export const environment = {
clientUrl: '${APPLICATION_CLIENT_URL}',
serverUrl: '${APPLICATION_SERVER_URL}',
keycloak: {
url: '${KEYCLOAK_URL}',
realm: '${KEYCLOAK_REALM}',
clientId: '${KEYCLOAK_CLIENT_ID}',
skipLoginPage: ${KEYCLOAK_SKIP_LOGIN}
},
umami: {
enabled: '${UMAMI_ENABLED}',
scriptUrl: '${UMAMI_SCRIPT_URL}',
websiteId: '${UMAMI_WEBSITE_ID}',
domains: '${UMAMI_DOMAINS}'
},
legal: {
imprintHtml: '${LEGAL_IMPRINT_HTML}',
privacyHtml: '${LEGAL_PRIVACY_HTML}'
}
};
EOF
COPY package.json package-lock.json ./

RUN npm install

COPY . ./

RUN npm run build

FROM nginx:latest
FROM nginx:stable-alpine

ENV APPLICATION_CLIENT_URL=https://default-client.url
ENV APPLICATION_SERVER_URL=https://default-server.url

ENV KEYCLOAK_URL=https://default-keycloak.url
ENV KEYCLOAK_REALM=default-realm
ENV KEYCLOAK_CLIENT_ID=default-client-id
ENV KEYCLOAK_SKIP_LOGIN=false

ENV LEGAL_IMPRINT_HTML="<p>Default Imprint</p>"
ENV LEGAL_PRIVACY_HTML="<p>Default Privacy</p>"

ENV UMAMI_ENABLED=false
ENV UMAMI_SCRIPT_URL=""
ENV UMAMI_WEBSITE_ID=""
ENV UMAMI_DOMAINS=""

COPY --from=build /app/dist/webapp/browser /usr/share/nginx/html

COPY generate_config.sh /usr/local/bin/generate_config.sh
RUN chmod +x /usr/local/bin/generate_config.sh

COPY nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

ENTRYPOINT ["/usr/local/bin/generate_config.sh"]
CMD ["nginx", "-g", "daemon off;"]
6 changes: 0 additions & 6 deletions webapp/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,6 @@
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"budgets": [
{
"type": "initial",
Expand Down
27 changes: 27 additions & 0 deletions webapp/generate_config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/sh
# This script generates the environment.json file for the webapp based on the environment variables during the docker container startup.

cat <<EOF > /usr/share/nginx/html/environment.json
{
"clientUrl": "${APPLICATION_CLIENT_URL}",
"serverUrl": "${APPLICATION_SERVER_URL}",
"keycloak": {
"url": "${KEYCLOAK_URL}",
"realm": "${KEYCLOAK_REALM}",
"clientId": "${KEYCLOAK_CLIENT_ID}",
"skipLoginPage": ${KEYCLOAK_SKIP_LOGIN}
},
"umami": {
"enabled": ${UMAMI_ENABLED},
"scriptUrl": "${UMAMI_SCRIPT_URL}",
"websiteId": "${UMAMI_WEBSITE_ID}",
"domains": "${UMAMI_DOMAINS}"
},
"legal": {
"imprintHtml": "$(echo "${LEGAL_IMPRINT_HTML}" | sed 's/"/\\"/g')",
"privacyHtml": "$(echo "${LEGAL_PRIVACY_HTML}" | sed 's/"/\\"/g')"
}
}
EOF

exec "$@"
19 changes: 11 additions & 8 deletions webapp/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
"@storybook/test": "8.3.4",
"@tailwindcss/typography": "0.5.15",
"@types/jasmine": "5.1.4",
"@types/node": "22.10.1",
"@typescript-eslint/eslint-plugin": "8.2.0",
"@typescript-eslint/parser": "8.2.0",
"chromatic": "11.7.1",
Expand Down
20 changes: 20 additions & 0 deletions webapp/public/environment.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"clientUrl": "http://localhost:4200",
"serverUrl": "http://localhost:8080",
"keycloak": {
"url": "http://localhost:8081",
"realm": "hephaestus",
"clientId": "hephaestus",
"skipLoginPage": false
},
"umami": {
"enabled": false,
"scriptUrl": "",
"websiteId": "",
"domains": ""
},
"legal": {
"imprintHtml": "<p>This is the imprint.</p>",
"privacyHtml": "<p>This is the privacy policy.</p>"
}
}
14 changes: 8 additions & 6 deletions webapp/src/app/analytics.service.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { Injectable } from '@angular/core';
import { environment } from 'environments/environment';
import { inject, Injectable } from '@angular/core';
import { EnvironmentService } from './environment.service';

@Injectable({
providedIn: 'root'
})
export class AnalyticsService {
private environmentService = inject(EnvironmentService);

private scriptLoaded = false;

initialize(): void {
if (environment.umami.enabled) {
if (this.environmentService.env.umami.enabled) {
this.loadUmamiScript();
}
}
Expand All @@ -20,9 +22,9 @@ export class AnalyticsService {

const script = document.createElement('script');
script.defer = true;
script.src = environment.umami.scriptUrl;
script.setAttribute('data-website-id', environment.umami.websiteId);
script.setAttribute('data-domains', environment.umami.domains);
script.src = this.environmentService.env.umami.scriptUrl;
script.setAttribute('data-website-id', this.environmentService.env.umami.websiteId);
script.setAttribute('data-domains', this.environmentService.env.umami.domains);

script.onload = () => {
console.log('Umami analytics script loaded successfully.');
Expand Down
Loading
Loading