Compare commits

..

2 Commits

Author SHA1 Message Date
fcf938ee6f chore: version 0.9.4 release 2026-03-25 12:22:50 +01:00
6e4f19a965 Release 0.9.3 2026-03-24 11:15:18 +01:00
11 changed files with 149 additions and 21 deletions

View File

@@ -4,6 +4,7 @@ WORKDIR /build/frontend
ARG VITE_API_URL=/api ARG VITE_API_URL=/api
ENV VITE_API_URL=${VITE_API_URL} ENV VITE_API_URL=${VITE_API_URL}
COPY backend/pom.xml /build/backend/pom.xml
COPY frontend/package*.json ./ COPY frontend/package*.json ./
RUN npm ci RUN npm ci
@@ -19,7 +20,8 @@ RUN mvn -B -q -DskipTests dependency:go-offline
COPY backend/ ./ COPY backend/ ./
COPY --from=frontend-build /build/frontend/dist ./src/main/resources/static COPY --from=frontend-build /build/frontend/dist ./src/main/resources/static
RUN mvn -B -q -DskipTests package RUN mvn -B -q -DskipTests package \
&& cp "$(find target -maxdepth 1 -type f -name '*.jar' ! -name '*.original' | head -n 1)" /build/backend/app.jar
FROM eclipse-temurin:21-jre-alpine AS runtime FROM eclipse-temurin:21-jre-alpine AS runtime
@@ -27,7 +29,7 @@ WORKDIR /app
RUN addgroup -S spring && adduser -S spring -G spring RUN addgroup -S spring && adduser -S spring -G spring
COPY --from=backend-build /build/backend/target/muh-backend-0.0.1-SNAPSHOT.jar /app/app.jar COPY --from=backend-build /build/backend/app.jar /app/app.jar
USER spring:spring USER spring:spring

View File

@@ -12,7 +12,7 @@
<groupId>de.svencarstensen</groupId> <groupId>de.svencarstensen</groupId>
<artifactId>muh-backend</artifactId> <artifactId>muh-backend</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.9.4</version>
<name>muh-backend</name> <name>muh-backend</name>
<description>MUH application backend</description> <description>MUH application backend</description>

View File

@@ -31,6 +31,8 @@ spring:
enable: ${MUH_MAIL_STARTTLS:false} enable: ${MUH_MAIL_STARTTLS:false}
muh: muh:
app:
version: '@project.version@'
cors: cors:
allowed-origins: ${MUH_ALLOWED_ORIGINS:http://localhost:5173,http://localhost:3000} allowed-origins: ${MUH_ALLOWED_ORIGINS:http://localhost:5173,http://localhost:3000}
security: security:

73
docker_push.sh Executable file
View File

@@ -0,0 +1,73 @@
#!/usr/bin/env bash
set -euo pipefail
readonly SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
readonly REGISTRY_IMAGE="registry.assecutor.org/muh"
readonly POM_FILE="${SCRIPT_DIR}/backend/pom.xml"
usage() {
cat <<'EOF'
Verwendung:
./docker_push.sh [x.y.z]
Beispiel:
./docker_push.sh 0.9.13
./docker_push.sh
Voraussetzungen:
- Docker Buildx ist installiert
- Login zur Registry wurde bereits ausgeführt:
docker login registry.assecutor.org
Ohne Versionsargument wird automatisch die Version aus backend/pom.xml verwendet.
Optional kann VITE_API_URL als Umgebungsvariable gesetzt werden.
EOF
}
fail() {
echo "Fehler: $*" >&2
exit 1
}
require_command() {
command -v "$1" >/dev/null 2>&1 || fail "'$1' wurde nicht gefunden."
}
resolve_app_version() {
[[ -f "${POM_FILE}" ]] || fail "'${POM_FILE}' wurde nicht gefunden."
local version
version="$(sed -n '/<parent>/,/<\/parent>/!{ s/.*<version>\(.*\)<\/version>.*/\1/p; }' "${POM_FILE}" | head -1)"
[[ -n "${version}" ]] || fail "Version konnte nicht aus ${POM_FILE} ermittelt werden."
[[ "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || fail "Version in ${POM_FILE} muss das Format x.y.z haben."
echo "${version}"
}
VERSION="${1:-$(resolve_app_version)}"
if [[ "${VERSION}" == "-h" || "${VERSION}" == "--help" ]]; then
usage
exit 0
fi
if [[ ! "${VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
fail "Versionsnummer muss das Format x.y.z haben."
fi
require_command docker
docker buildx version >/dev/null 2>&1 || fail "Docker Buildx ist nicht verfügbar."
cd "${SCRIPT_DIR}"
echo "Verwende Release-Version ${VERSION}."
echo "Pushe Image ${REGISTRY_IMAGE}:${VERSION} ..."
docker buildx build \
--platform linux/amd64 \
--build-arg "VITE_API_URL=${VITE_API_URL:-/api}" \
-t "${REGISTRY_IMAGE}:${VERSION}" \
--push \
.
echo "Fertig: ${REGISTRY_IMAGE}:${VERSION}"

View File

@@ -1 +1,3 @@
declare const __APP_VERSION__: string;
interface Worker {} interface Worker {}

View File

@@ -1,6 +1,5 @@
import { NavLink, Outlet, useLocation, useNavigate } from "react-router-dom"; import { NavLink, Outlet, useLocation, useNavigate } from "react-router-dom";
import { useSession } from "../lib/session"; import { useSession } from "../lib/session";
import { APP_VERSION } from "../lib/version";
const PAGE_TITLES: Record<string, string> = { const PAGE_TITLES: Record<string, string> = {
"/home": "Startseite", "/home": "Startseite",
@@ -43,7 +42,7 @@ export default function AppShell() {
<aside className="sidebar"> <aside className="sidebar">
<div className="sidebar__brand"> <div className="sidebar__brand">
<div className="sidebar__logo"> <div className="sidebar__logo">
MUH <span className="sidebar__version">({APP_VERSION})</span> MUH <span className="sidebar__version">({__APP_VERSION__})</span>
</div> </div>
</div> </div>

View File

@@ -1,14 +0,0 @@
/**
* Application Version
*
* Semantic Versioning: MAJOR.MINOR.PATCH
* - MAJOR: Incompatible API changes
* - MINOR: New functionality (backward compatible)
* - PATCH: Bug fixes (backward compatible)
*/
export const APP_VERSION = "0.9.2";
/**
* Build date - set at build time
*/
export const BUILD_DATE = new Date().toISOString().split('T')[0];

View File

@@ -126,7 +126,7 @@ export default function UserManagementPage() {
if (!userToUpdate) return; if (!userToUpdate) return;
await apiPost("/portal/users", { await apiPost("/portal/users", {
id: userId, ...userToUpdate,
active: newStatus, active: newStatus,
}); });

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,26 @@
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { defineConfig } from "vite"; import { defineConfig } from "vite";
import react from "@vitejs/plugin-react"; import react from "@vitejs/plugin-react";
const CONFIG_DIR = path.dirname(fileURLToPath(import.meta.url));
const POM_PATH = path.resolve(CONFIG_DIR, "../backend/pom.xml");
function resolveAppVersion() {
const content = fs.readFileSync(POM_PATH, "utf8");
const parentRange = content.indexOf("<parent>");
const parentEnd = content.indexOf("</parent>");
const withoutParent = content.slice(0, parentRange) + content.slice(parentEnd + "</parent>".length);
const match = withoutParent.match(/<version>(\d+\.\d+\.\d+)<\/version>/);
if (match) {
return match[1];
}
throw new Error(`Version konnte nicht aus ${POM_PATH} ermittelt werden.`);
}
export default defineConfig({ export default defineConfig({
plugins: [react()], plugins: [react()],
define: {
__APP_VERSION__: JSON.stringify(resolveAppVersion()),
},
server: { server: {
port: 5173, port: 5173,
host: "0.0.0.0", host: "0.0.0.0",

View File

@@ -1,8 +1,53 @@
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { defineConfig } from "vite"; import { defineConfig } from "vite";
import react from "@vitejs/plugin-react"; import react from "@vitejs/plugin-react";
const CONFIG_DIR = path.dirname(fileURLToPath(import.meta.url));
const APPLICATION_CONFIG_PATH = path.resolve(CONFIG_DIR, "../backend/src/main/resources/application.yml");
function resolveAppVersion(): string {
const lines = fs.readFileSync(APPLICATION_CONFIG_PATH, "utf8").split(/\r?\n/);
let inMuhSection = false;
let inAppSection = false;
for (const line of lines) {
const trimmedLine = line.trim();
if (!trimmedLine || trimmedLine.startsWith("#")) {
continue;
}
const indentation = line.length - line.trimStart().length;
if (indentation === 0) {
inMuhSection = trimmedLine === "muh:";
inAppSection = false;
continue;
}
if (inMuhSection && indentation === 2) {
inAppSection = trimmedLine === "app:";
continue;
}
if (inMuhSection && inAppSection && indentation === 4 && trimmedLine.startsWith("version:")) {
const version = trimmedLine.slice("version:".length).trim().replace(/^['"]|['"]$/g, "");
if (/^\d+\.\d+\.\d+$/.test(version)) {
return version;
}
throw new Error(`Ungueltige Versionsnummer in ${APPLICATION_CONFIG_PATH}: ${version}`);
}
}
throw new Error(`muh.app.version konnte nicht aus ${APPLICATION_CONFIG_PATH} ermittelt werden.`);
}
export default defineConfig({ export default defineConfig({
plugins: [react()], plugins: [react()],
define: {
__APP_VERSION__: JSON.stringify(resolveAppVersion()),
},
server: { server: {
port: 5173, port: 5173,
host: "0.0.0.0", host: "0.0.0.0",