diff --git a/.github/workflows/migration-test.yml b/.github/workflows/migration-test.yml
new file mode 100644
index 0000000000..4e359e6618
--- /dev/null
+++ b/.github/workflows/migration-test.yml
@@ -0,0 +1,30 @@
+name: Database Migration Test
+
+on:
+ workflow_dispatch:
+ pull_request:
+ branches:
+ - main
+
+jobs:
+ qa:
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ db: [mysql, mariadb, postgres, oracle, sqlserver]
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Set up Docker
+ uses: docker/setup-buildx-action@v3
+
+ - name: Run QA script
+ run: |
+ ./mvnw clean install -DskipTests -PskipFrontendBuild
+ cd qa
+ chmod +x ./db-migration-test.sh
+ ./db-migration-test.sh ${{ matrix.db }}
diff --git a/database/pom.xml b/database/pom.xml
index b016d49b4a..319a99581f 100644
--- a/database/pom.xml
+++ b/database/pom.xml
@@ -310,6 +310,212 @@
+
+ mt-mysql
+
+ mysql
+ com.mysql.cj.jdbc.Driver
+ com.mysql.cj.jdbc.MysqlDataSource
+ mysql-ds.xml
+ ${env.MT_MYSQL_HOST_PORT}
+ ${env.MT_MYSQL_DATABASE}
+ ${env.MT_MYSQL_USERNAME}
+ ${env.MT_MYSQL_PASSWORD}
+ ${database.name}?allowPublicKeyRetrieval=true
+ jdbc:mysql://${database.username}:${database.password}@localhost:${database.port}/${database.params}
+
+
+
+
+ com.mysql
+ mysql-connector-j
+ test
+
+
+
+
+
+
+ org.codehaus.mojo
+ sql-maven-plugin
+
+
+ com.mysql
+ mysql-connector-j
+ ${version.mysql}
+
+
+
+
+
+
+
+
+
+ mt-mariadb
+
+ mariadb
+ org.mariadb.jdbc.Driver
+ org.hibernate.dialect.MariaDBDialect
+ org.mariadb.jdbc.MariaDbDataSource
+ ${env.MT_MARIADB_HOST_PORT}
+ ${env.MT_MARIADB_DATABASE}
+ ${env.MT_MARIADB_USERNAME}
+ ${env.MT_MARIADB_PASSWORD}
+ ${database.name}?user=${database.username}&password=${database.password}
+ jdbc:mariadb://localhost:${database.port}/${database.params}
+
+
+
+
+ org.mariadb.jdbc
+ mariadb-java-client
+ test
+
+
+
+
+
+
+ org.codehaus.mojo
+ sql-maven-plugin
+
+
+ org.mariadb.jdbc
+ mariadb-java-client
+ ${version.mariadb}
+
+
+
+
+
+
+
+
+
+ mt-postgres
+
+ postgres
+ org.postgresql.Driver
+ org.hibernate.dialect.PostgreSQLDialect
+ org.postgresql.ds.PGSimpleDataSource
+ postgresql-ds.xml
+ ${env.MT_POSTGRES_HOST_PORT}
+ ${env.MT_POSTGRES_DATABASE}
+ ${env.MT_POSTGRES_USERNAME}
+ ${env.MT_POSTGRES_PASSWORD}
+ ${database.name}?user=${database.username}&password=${database.password}
+ jdbc:postgresql://localhost:${database.port}/${database.params}
+
+
+
+
+ org.postgresql
+ postgresql
+ test
+
+
+
+
+
+
+ org.codehaus.mojo
+ sql-maven-plugin
+
+
+ org.postgresql
+ postgresql
+ ${version.postgresql}
+
+
+
+
+
+
+
+
+
+ mt-sqlserver
+
+ sqlserver
+ com.microsoft.sqlserver.jdbc.SQLServerDriver
+ com.microsoft.sqlserver.jdbc.SQLServerDataSource
+ sqlserver-ds.xml
+ ${env.MT_MSSQL_HOST_PORT}
+ ${env.MT_MSSQL_DATABASE}
+ ${env.MT_MSSQL_USERNAME}
+ ${env.MT_MSSQL_PASSWORD}
+ ;databaseName=${database.name};user=${database.username};password=${database.password};encrypt=false;
+ jdbc:sqlserver://localhost:${database.port}${database.params}
+
+
+
+
+ com.microsoft.sqlserver
+ mssql-jdbc
+ test
+
+
+
+
+
+
+ org.codehaus.mojo
+ sql-maven-plugin
+
+
+ com.microsoft.sqlserver
+ mssql-jdbc
+ ${version.sqlserver}
+
+
+
+
+
+
+
+
+
+ mt-oracle
+
+ oracle
+ oracle.jdbc.OracleDriver
+ oracle.jdbc.pool.OracleDataSource
+ oracle-ds.xml
+ ${env.MT_ORACLE_HOST_PORT}
+ ${env.MT_ORACLE_DATABASE}
+ ${env.MT_ORACLE_USERNAME}
+ ${env.MT_ORACLE_PASSWORD}
+ ${database.name}
+ jdbc:oracle:thin:${database.username}/${database.password}@//localhost:${database.port}/${database.params}
+
+
+
+ com.oracle.database.jdbc
+ ojdbc11
+ test
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ sql-maven-plugin
+
+
+ com.oracle.database.jdbc
+ ojdbc11
+ ${version.oracle}
+
+
+
+
+
+
+
+
oracle
diff --git a/qa/db-migration-test.sh b/qa/db-migration-test.sh
new file mode 100755
index 0000000000..d1f2266e42
--- /dev/null
+++ b/qa/db-migration-test.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+set -e
+
+DB_TYPE="$1"
+TEST_DB_CONTAINER_PATH=./test-database-container
+
+case "$DB_TYPE" in
+ mysql)
+ source "$TEST_DB_CONTAINER_PATH"/mysql/qa-mysql.sh
+ test_mysql
+ ;;
+ mariadb)
+ source "$TEST_DB_CONTAINER_PATH"/mariadb/qa-mariadb.sh
+ test_mariadb
+ ;;
+ postgres)
+ source "$TEST_DB_CONTAINER_PATH"/postgres/qa-postgres.sh
+ test_postgres
+ ;;
+ sqlserver)
+ source "$TEST_DB_CONTAINER_PATH"/sqlserver/qa-sqlserver.sh
+ test_sqlserver
+ ;;
+ oracle)
+ source "$TEST_DB_CONTAINER_PATH"/oracle/qa-oracle.sh
+ test_oracle
+ ;;
+ *)
+ echo "Usage: $0 {mysql|mariadb|postgres|oracle|sqlserver}"
+ exit 1
+ ;;
+esac
diff --git a/qa/test-database-container/mariadb/docker-compose.yaml b/qa/test-database-container/mariadb/docker-compose.yaml
new file mode 100644
index 0000000000..91d9658ee6
--- /dev/null
+++ b/qa/test-database-container/mariadb/docker-compose.yaml
@@ -0,0 +1,11 @@
+services:
+ mariadb:
+ image: mariadb:11.8
+ container_name: ${MT_MARIADB_CONTAINER_NAME}
+ ports:
+ - "${MT_MARIADB_HOST_PORT}:3306"
+ environment:
+ - MARIADB_ROOT_PASSWORD=${MT_MARIADB_PASSWORD}
+ - MARIADB_DATABASE=${MT_MARIADB_DATABASE}
+ volumes:
+ - ./my.cnf:/etc/mysql/conf.d/my.cnf
diff --git a/qa/test-database-container/mariadb/my.cnf b/qa/test-database-container/mariadb/my.cnf
new file mode 100644
index 0000000000..be0ee41361
--- /dev/null
+++ b/qa/test-database-container/mariadb/my.cnf
@@ -0,0 +1,2 @@
+[mysqld]
+transaction-isolation=READ-COMMITTED
\ No newline at end of file
diff --git a/qa/test-database-container/mariadb/qa-mariadb.sh b/qa/test-database-container/mariadb/qa-mariadb.sh
new file mode 100755
index 0000000000..614eb9ba15
--- /dev/null
+++ b/qa/test-database-container/mariadb/qa-mariadb.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+test_mariadb() {
+ set -e # Exit on error (except where we trap it)
+
+ # Configuration
+ export MT_MARIADB_CONTAINER_NAME="mariadb_11_8"
+ export MT_MARIADB_USERNAME="root"
+ export MT_MARIADB_PASSWORD="123456"
+
+ export MT_MARIADB_HOST_PORT="33070"
+ export MT_MARIADB_DATABASE="operaton"
+
+ MAX_RETRIES=30
+ SLEEP_SEC=2
+ COMPOSE_FILE="./test-database-container/mariadb/docker-compose.yaml"
+ MAVEN_WRAPPER="../mvnw"
+
+ # Bring down possible running containers from a broken execution
+ cleanup_containers
+
+ # Start containers
+ docker compose -f "${COMPOSE_FILE}" up -d
+ echo "⏳ Waiting for MariaDB to be ready inside container $MT_MARIADB_CONTAINER_NAME..."
+
+ # Wait for container to be available
+ retries=0
+ until docker exec -i "$MT_MARIADB_CONTAINER_NAME" \
+ mariadb -u"$MT_MARIADB_USERNAME" -p"$MT_MARIADB_PASSWORD" -e "SELECT 'i_am_up';" 2>/dev/null | grep -q "i_am_up"; do
+ retries=$((retries+1))
+ if [ "$retries" -ge "$MAX_RETRIES" ]; then
+ echo "❌ MariaDB did not become ready in time!"
+ cleanup_containers
+ exit 1
+ fi
+ echo "⏳ MariaDB not ready yet... waiting $SLEEP_SEC seconds"
+ sleep "$SLEEP_SEC"
+ done
+
+ echo "🚀 MariaDB is ready!"
+
+ # Run Maven build, capture exit code
+ set +e # allow Maven to fail without stopping the script
+ "$MAVEN_WRAPPER" clean install -Prolling-update,mt-mariadb
+ BUILD_EXIT_CODE=$?
+ set -e
+
+ # Always bring down containers at the end
+ cleanup_containers
+
+ # Exit with Maven's exit code
+ exit $BUILD_EXIT_CODE
+}
+
+cleanup_containers() {
+ docker compose -f "${COMPOSE_FILE}" down
+}
diff --git a/qa/test-database-container/mysql/docker-compose.yaml b/qa/test-database-container/mysql/docker-compose.yaml
new file mode 100644
index 0000000000..35aaf7255c
--- /dev/null
+++ b/qa/test-database-container/mysql/docker-compose.yaml
@@ -0,0 +1,11 @@
+services:
+ mysql:
+ image: mysql:9.2.0
+ container_name: ${MT_MYSQL_CONTAINER_NAME}
+ ports:
+ - "${MT_MYSQL_HOST_PORT}:3306"
+ environment:
+ - MYSQL_ROOT_PASSWORD=${MT_MYSQL_PASSWORD}
+ - MYSQL_DATABASE=${MT_MYSQL_DATABASE}
+ volumes:
+ - ./my.cnf:/etc/mysql/conf.d/my.cnf
diff --git a/qa/test-database-container/mysql/my.cnf b/qa/test-database-container/mysql/my.cnf
new file mode 100644
index 0000000000..be0ee41361
--- /dev/null
+++ b/qa/test-database-container/mysql/my.cnf
@@ -0,0 +1,2 @@
+[mysqld]
+transaction-isolation=READ-COMMITTED
\ No newline at end of file
diff --git a/qa/test-database-container/mysql/qa-mysql.sh b/qa/test-database-container/mysql/qa-mysql.sh
new file mode 100755
index 0000000000..a4a93479fa
--- /dev/null
+++ b/qa/test-database-container/mysql/qa-mysql.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+test_mysql() {
+ set -e # Exit on error (except where we trap it)
+
+ # Configuration
+ export MT_MYSQL_CONTAINER_NAME="mysql_9_2_0"
+ export MT_MYSQL_USERNAME="root"
+ export MT_MYSQL_PASSWORD="123456"
+
+ export MT_MYSQL_HOST_PORT="33060"
+ export MT_MYSQL_DATABASE="operaton"
+
+ MAX_RETRIES=30
+ SLEEP_SEC=2
+ COMPOSE_FILE="./test-database-container/mysql/docker-compose.yaml"
+ MAVEN_WRAPPER="../mvnw"
+
+ # Bring down possible running containers from a broken execution
+ cleanup_containers
+
+ # Start containers
+ docker compose -f "${COMPOSE_FILE}" up -d
+ echo "⏳ Waiting for MySQL to be ready inside container $MT_MYSQL_CONTAINER_NAME..."
+
+ # Wait for container to be available
+ retries=0
+ until docker exec -i "$MT_MYSQL_CONTAINER_NAME" \
+ mysql -u"$MT_MYSQL_USERNAME" -p"$MT_MYSQL_PASSWORD" -e "SELECT 'i_am_up';" 2>/dev/null | grep -q "i_am_up"; do
+ retries=$((retries+1))
+ if [ "$retries" -ge "$MAX_RETRIES" ]; then
+ echo "❌ MySQL did not become ready in time!"
+ cleanup_containers
+ exit 1
+ fi
+ echo "⏳ MySQL not ready yet... waiting $SLEEP_SEC seconds"
+ sleep "$SLEEP_SEC"
+ done
+
+ echo "🚀 MySQL is ready!"
+
+ # Run Maven build, capture exit code
+ set +e # allow Maven to fail without stopping the script
+ "$MAVEN_WRAPPER" clean install -Prolling-update,mt-mysql
+ BUILD_EXIT_CODE=$?
+ set -e
+
+ # Always bring down containers at the end
+ cleanup_containers
+
+ # Exit with Maven's exit code
+ exit $BUILD_EXIT_CODE
+}
+
+cleanup_containers() {
+ docker compose -f "${COMPOSE_FILE}" down
+}
\ No newline at end of file
diff --git a/qa/test-database-container/oracle/docker-compose.yaml b/qa/test-database-container/oracle/docker-compose.yaml
new file mode 100644
index 0000000000..f7dca6b0f8
--- /dev/null
+++ b/qa/test-database-container/oracle/docker-compose.yaml
@@ -0,0 +1,9 @@
+services:
+ oracledb:
+ image: gvenzl/oracle-xe:21-faststart
+ container_name: ${MT_ORACLE_CONTAINER_NAME}
+ ports:
+ - "${MT_ORACLE_HOST_PORT}:1521"
+ environment:
+ - ORACLE_PASSWORD=${MT_ORACLE_PASSWORD}
+ - ORACLE_DATABASE=${MT_ORACLE_DATABASE}
\ No newline at end of file
diff --git a/qa/test-database-container/oracle/qa-oracle.sh b/qa/test-database-container/oracle/qa-oracle.sh
new file mode 100755
index 0000000000..52b4cec29f
--- /dev/null
+++ b/qa/test-database-container/oracle/qa-oracle.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+test_oracle() {
+ set -e # Exit on error (except where we trap it)
+
+ # Configuration
+ export MT_ORACLE_CONTAINER_NAME="oracle_21"
+ export MT_ORACLE_USERNAME="SYSTEM"
+ export MT_ORACLE_PASSWORD="123456"
+
+ export MT_ORACLE_HOST_PORT="15210"
+ export MT_ORACLE_DATABASE="operaton"
+
+ MAX_RETRIES=30
+ SLEEP_SEC=2
+ COMPOSE_FILE="./test-database-container/oracle/docker-compose.yaml"
+ MAVEN_WRAPPER="../mvnw"
+
+ # Bring down possible running containers from a broken execution
+ cleanup_containers
+
+ # Start containers
+ docker compose -f "${COMPOSE_FILE}" up -d
+ echo "⏳ Waiting for OracleDB to be ready inside container $MT_ORACLE_CONTAINER_NAME..."
+
+ # Wait for container to be available
+ retries=0
+ until docker exec -i "$MT_ORACLE_CONTAINER_NAME" \
+ bash -c "echo \"SELECT 'i_am_up' FROM dual;\" | sqlplus -S ${MT_ORACLE_USERNAME}/${MT_ORACLE_PASSWORD}@//localhost:1521/${MT_ORACLE_DATABASE}" 2>/dev/null | grep -q "i_am_up"; do
+ retries=$((retries+1))
+ if [ "$retries" -ge "$MAX_RETRIES" ]; then
+ echo "❌ OracleDB did not become ready in time!"
+ cleanup_containers
+ exit 1
+ fi
+ echo "⏳ OracleDB not ready yet... waiting $SLEEP_SEC seconds"
+ sleep "$SLEEP_SEC"
+ done
+
+ echo "🚀 OracleDB is ready!"
+
+ # Run Maven build, capture exit code
+ set +e # allow Maven to fail without stopping the script
+ "$MAVEN_WRAPPER" clean install -Prolling-update,mt-oracle
+ BUILD_EXIT_CODE=$?
+ set -e
+
+ # Always bring down containers at the end
+ cleanup_containers
+
+ # Exit with Maven's exit code
+ exit $BUILD_EXIT_CODE
+}
+
+cleanup_containers() {
+ docker compose -f "${COMPOSE_FILE}" down
+}
diff --git a/qa/test-database-container/postgres/docker-compose.yaml b/qa/test-database-container/postgres/docker-compose.yaml
new file mode 100644
index 0000000000..a603f5fdbf
--- /dev/null
+++ b/qa/test-database-container/postgres/docker-compose.yaml
@@ -0,0 +1,10 @@
+services:
+ postgres:
+ image: postgres:17
+ container_name: ${MT_POSTGRES_CONTAINER_NAME}
+ ports:
+ - "${MT_POSTGRES_HOST_PORT}:5432"
+ environment:
+ - POSTGRES_PASSWORD=${MT_POSTGRES_PASSWORD}
+ - POSTGRES_DB=${MT_POSTGRES_DATABASE}
+ - POSTGRES_USER=${MT_POSTGRES_USERNAME}
\ No newline at end of file
diff --git a/qa/test-database-container/postgres/qa-postgres.sh b/qa/test-database-container/postgres/qa-postgres.sh
new file mode 100755
index 0000000000..cbdee37457
--- /dev/null
+++ b/qa/test-database-container/postgres/qa-postgres.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+test_postgres() {
+ set -e # Exit on error (except where we trap it)
+
+ # Configuration
+ export MT_POSTGRES_CONTAINER_NAME="postgres_17"
+ export MT_POSTGRES_USERNAME="root"
+ export MT_POSTGRES_PASSWORD="123456"
+
+ export MT_POSTGRES_HOST_PORT="54320"
+ export MT_POSTGRES_DATABASE="operaton"
+
+ MAX_RETRIES=30
+ SLEEP_SEC=2
+ COMPOSE_FILE="./test-database-container/postgres/docker-compose.yaml"
+ MAVEN_WRAPPER="../mvnw"
+
+ # Bring down possible running containers from a broken execution
+ cleanup_containers
+
+ # Start containers
+ docker compose -f "${COMPOSE_FILE}" up -d
+ echo "⏳ Waiting for PostgreSQL to be ready inside container $MT_POSTGRES_CONTAINER_NAME..."
+
+ # Wait for container to be available
+ retries=0
+ until docker exec -i "$MT_POSTGRES_CONTAINER_NAME" \
+ psql -U "$MT_POSTGRES_USERNAME" -d "$MT_POSTGRES_DATABASE" -c "SELECT 'i_am_up';" 2>/dev/null | grep -q "i_am_up"; do
+ retries=$((retries+1))
+ if [ "$retries" -ge "$MAX_RETRIES" ]; then
+ echo "❌ PostgreSQL did not become ready in time!"
+ cleanup_containers
+ exit 1
+ fi
+ echo "⏳ PostgreSQL not ready yet... waiting $SLEEP_SEC seconds"
+ sleep "$SLEEP_SEC"
+ done
+
+ echo "🚀 PostgreSQL is ready!"
+
+ # Run Maven build, capture exit code
+ set +e # allow Maven to fail without stopping the script
+ "$MAVEN_WRAPPER" clean install -Prolling-update,mt-postgres
+ BUILD_EXIT_CODE=$?
+ set -e
+
+ # Always bring down containers at the end
+ cleanup_containers
+
+ # Exit with Maven's exit code
+ exit $BUILD_EXIT_CODE
+}
+
+cleanup_containers() {
+ docker compose -f "${COMPOSE_FILE}" down
+}
\ No newline at end of file
diff --git a/qa/test-database-container/sqlserver/docker-compose.yaml b/qa/test-database-container/sqlserver/docker-compose.yaml
new file mode 100644
index 0000000000..041c703ce4
--- /dev/null
+++ b/qa/test-database-container/sqlserver/docker-compose.yaml
@@ -0,0 +1,10 @@
+services:
+ sqlserver:
+ image: mcr.microsoft.com/mssql/server:2022-latest
+ container_name: ${MT_MSSQL_CONTAINER_NAME}
+ ports:
+ - "${MT_MSSQL_HOST_PORT}:1433"
+ environment:
+ - ACCEPT_EULA=Y
+ - SA_PASSWORD=${MT_MSSQL_PASSWORD}
+ - MSSQL_PID=Developer
\ No newline at end of file
diff --git a/qa/test-database-container/sqlserver/qa-sqlserver.sh b/qa/test-database-container/sqlserver/qa-sqlserver.sh
new file mode 100755
index 0000000000..5c355cca73
--- /dev/null
+++ b/qa/test-database-container/sqlserver/qa-sqlserver.sh
@@ -0,0 +1,69 @@
+#!/bin/bash
+test_sqlserver() {
+ set -e # Exit on error (except where we trap it)
+
+ # Configuration
+ export MT_MSSQL_CONTAINER_NAME="sqlserver_2022"
+ export MT_MSSQL_USERNAME="sa"
+ export MT_MSSQL_PASSWORD="P@ssw0rd123ABC"
+
+ export MT_MSSQL_HOST_PORT="14330"
+ export MT_MSSQL_DATABASE="operaton"
+
+ MAX_RETRIES=30
+ SLEEP_SEC=2
+ COMPOSE_FILE="./test-database-container/sqlserver/docker-compose.yaml"
+ MAVEN_WRAPPER="../mvnw"
+
+ # Bring down possible running containers from a broken execution
+ cleanup_containers
+
+ # Start containers
+ docker compose -f "${COMPOSE_FILE}" up -d
+ echo "⏳ Waiting for MsSQL to be ready inside container $MT_MSSQL_CONTAINER_NAME..."
+
+ # Wait for container to be available
+ retries=0
+ until docker exec -i "$MT_MSSQL_CONTAINER_NAME" \
+ /opt/mssql-tools18/bin/sqlcmd -S localhost -C -N -U "$MT_MSSQL_USERNAME" -P "$MT_MSSQL_PASSWORD" -Q "SELECT 'i_am_up';" 2>/dev/null | grep -q "i_am_up"; do
+ retries=$((retries+1))
+ if [ "$retries" -ge "$MAX_RETRIES" ]; then
+ echo "❌ MsSQL did not become ready in time!"
+ cleanup_containers
+ exit 1
+ fi
+ echo "⏳ MsSQL not ready yet... waiting $SLEEP_SEC seconds"
+ sleep "$SLEEP_SEC"
+ done
+
+ echo "🚗 MsSQL is ready! - creating test database $MT_MSSQL_DATABASE ..."
+ docker exec -i "$MT_MSSQL_CONTAINER_NAME" \
+ /opt/mssql-tools18/bin/sqlcmd -S localhost -C -N -U "$MT_MSSQL_USERNAME" -P "$MT_MSSQL_PASSWORD" -Q "CREATE DATABASE [$MT_MSSQL_DATABASE];"
+
+ DB_LIST=$(docker exec -i "$MT_MSSQL_CONTAINER_NAME" \
+ /opt/mssql-tools18/bin/sqlcmd -S localhost -C -N -U "$MT_MSSQL_USERNAME" -P "$MT_MSSQL_PASSWORD" -Q "SELECT name FROM sys.databases;")
+
+ if echo "$DB_LIST" | grep -qw "$MT_MSSQL_DATABASE"; then
+ echo "✅ Test database $MT_MSSQL_DATABASE created successfully!"
+ else
+ echo "❌ Test database $MT_MSSQL_DATABASE could not be created!"
+ cleanup_containers
+ exit 1
+ fi
+
+ # Run Maven build, capture exit code
+ set +e # allow Maven to fail without stopping the script
+ "$MAVEN_WRAPPER" clean install -Prolling-update,mt-sqlserver
+ BUILD_EXIT_CODE=$?
+ set -e
+
+ # Always bring down containers at the end
+ cleanup_containers
+
+ # Exit with Maven's exit code
+ exit $BUILD_EXIT_CODE
+}
+
+cleanup_containers() {
+ docker compose -f "${COMPOSE_FILE}" down
+}