diff --git a/.csharpierrc.json b/.csharpierrc.json index 1073d01..0e17843 100644 --- a/.csharpierrc.json +++ b/.csharpierrc.json @@ -1,5 +1,4 @@ { - "$schema": "https://raw.githubusercontent.com/belav/csharpier/main/src/CSharpier.Cli/schema.json", "printWidth": 80, "useTabs": false, "tabWidth": 4, diff --git a/docker-compose.dev.yaml b/docker-compose.dev.yaml index eeca7f0..6fff877 100644 --- a/docker-compose.dev.yaml +++ b/docker-compose.dev.yaml @@ -6,11 +6,11 @@ services: environment: ACCEPT_EULA: "Y" SA_PASSWORD: "${SA_PASSWORD}" - MSSQL_PID: "Developer" + MSSQL_PID: "Express" ports: - "1433:1433" volumes: - - sqlserverdata:/var/opt/mssql + - sqlserverdata-dev:/var/opt/mssql healthcheck: test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P '${SA_PASSWORD}' -C -Q 'SELECT 1' || exit 1"] interval: 10s @@ -19,7 +19,25 @@ services: start_period: 30s networks: - devnet - + database.migrations: + image: database.migrations + container_name: dev-env-database-migrations + depends_on: + sqlserver: + condition: service_healthy + build: + context: ./src/Core/Database + dockerfile: Database.Migrations/Dockerfile + args: + BUILD_CONFIGURATION: Release + APP_UID: 1000 + environment: + DOTNET_RUNNING_IN_CONTAINER: "true" + DB_CONNECTION_STRING: "${DB_CONNECTION_STRING}" + MASTER_DB_CONNECTION_STRING: "${MASTER_DB_CONNECTION_STRING}" + restart: "no" + networks: + - devnet api.core: image: api.core container_name: dev-env-api-core @@ -44,14 +62,14 @@ services: networks: - devnet volumes: - - nuget-cache:/root/.nuget/packages + - nuget-cache-dev:/root/.nuget/packages volumes: - sqlserverdata: + sqlserverdata-dev: driver: local - nuget-cache: + nuget-cache-dev: driver: local networks: devnet: - driver: bridge \ No newline at end of file + driver: bridge diff --git a/docker-compose.prod.yaml b/docker-compose.prod.yaml index b6b9655..7efaaba 100644 --- a/docker-compose.prod.yaml +++ b/docker-compose.prod.yaml @@ -6,9 +6,9 @@ services: environment: ACCEPT_EULA: "Y" SA_PASSWORD: "${SA_PASSWORD}" - MSSQL_PID: "Developer" + MSSQL_PID: "Express" volumes: - - sqlserverdata:/var/opt/mssql + - sqlserverdata-prod:/var/opt/mssql healthcheck: test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P '${SA_PASSWORD}' -C -Q 'SELECT 1' || exit 1"] interval: 10s @@ -18,6 +18,26 @@ services: networks: - prodnet + database.migrations: + image: database.migrations + container_name: prod-env-database-migrations + depends_on: + sqlserver: + condition: service_healthy + build: + context: ./src/Core/Database + dockerfile: Database.Migrations/Dockerfile + args: + BUILD_CONFIGURATION: Release + APP_UID: 1000 + environment: + DOTNET_RUNNING_IN_CONTAINER: "true" + DB_CONNECTION_STRING: "${DB_CONNECTION_STRING}" + MASTER_DB_CONNECTION_STRING: "${MASTER_DB_CONNECTION_STRING}" + restart: "no" + networks: + - prodnet + api.core: image: api.core container_name: prod-env-api-core @@ -37,19 +57,20 @@ services: ASPNETCORE_ENVIRONMENT: "Production" ASPNETCORE_URLS: "http://0.0.0.0:8080" DOTNET_RUNNING_IN_CONTAINER: "true" + MASTER_DB_CONNECTION_STRING: "${MASTER_DB_CONNECTION_STRING}" DB_CONNECTION_STRING: "${DB_CONNECTION_STRING}" restart: unless-stopped networks: - prodnet volumes: - - nuget-cache:/root/.nuget/packages + - nuget-cache-prod:/root/.nuget/packages volumes: - sqlserverdata: + sqlserverdata-prod: driver: local - nuget-cache: + nuget-cache-prod: driver: local networks: prodnet: - driver: bridge \ No newline at end of file + driver: bridge diff --git a/src/Core/Core.slnx b/src/Core/Core.slnx index 7687959..b2f3ee2 100644 --- a/src/Core/Core.slnx +++ b/src/Core/Core.slnx @@ -4,7 +4,7 @@ - + diff --git a/src/Core/Database/Database.Core/Program.cs b/src/Core/Database/Database.Core/Program.cs deleted file mode 100644 index d3405e9..0000000 --- a/src/Core/Database/Database.Core/Program.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Get connection string from environment variable - -using System.Reflection; -using DbUp; - -var connectionString = Environment.GetEnvironmentVariable( - "DB_CONNECTION_STRING" -); - -var upgrader = DeployChanges - .To.SqlDatabase(connectionString) - .WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly()) - .LogToConsole() - .Build(); - -var result = upgrader.PerformUpgrade(); - -if (!result.Successful) -{ - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine(result.Error); - Console.ResetColor(); -#if DEBUG - Console.ReadLine(); -#endif - return -1; -} - -Console.ForegroundColor = ConsoleColor.Green; -Console.WriteLine("Success!"); -Console.ResetColor(); -return 0; diff --git a/src/Core/Database/Database.Core/Database.Core.csproj b/src/Core/Database/Database.Migrations/Database.Migrations.csproj similarity index 74% rename from src/Core/Database/Database.Core/Database.Core.csproj rename to src/Core/Database/Database.Migrations/Database.Migrations.csproj index 00a74a3..3488889 100644 --- a/src/Core/Database/Database.Core/Database.Core.csproj +++ b/src/Core/Database/Database.Migrations/Database.Migrations.csproj @@ -5,6 +5,7 @@ enable enable DataLayer + Linux @@ -14,4 +15,9 @@ + + + .dockerignore + + diff --git a/src/Core/Database/Database.Migrations/Dockerfile b/src/Core/Database/Database.Migrations/Dockerfile new file mode 100644 index 0000000..2fc184d --- /dev/null +++ b/src/Core/Database/Database.Migrations/Dockerfile @@ -0,0 +1,17 @@ + +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +# Copy everything from the context (src/Core/Database) +COPY . . +RUN dotnet restore "./Database.Migrations/Database.Migrations.csproj" +RUN dotnet build "./Database.Migrations/Database.Migrations.csproj" -c $BUILD_CONFIGURATION -o /app/build + +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./Database.Migrations/Database.Migrations.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +FROM mcr.microsoft.com/dotnet/runtime:10.0 AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Database.Migrations.dll"] diff --git a/src/Core/Database/Database.Migrations/Program.cs b/src/Core/Database/Database.Migrations/Program.cs new file mode 100644 index 0000000..1fa4b3a --- /dev/null +++ b/src/Core/Database/Database.Migrations/Program.cs @@ -0,0 +1,82 @@ +using System.Data; +using System.Reflection; +using DbUp; +using Microsoft.Data.SqlClient; + +namespace DataLayer; + +public static class Program +{ + private static readonly string? connectionString = Environment.GetEnvironmentVariable("DB_CONNECTION_STRING"); + private static readonly string? masterConnectionString = Environment.GetEnvironmentVariable("MASTER_DB_CONNECTION_STRING"); + + private static bool DeployMigrations() + { + var upgrader = DeployChanges + .To.SqlDatabase(connectionString) + .WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly()) + .LogToConsole() + .Build(); + + var result = upgrader.PerformUpgrade(); + return result.Successful; + } + + private static bool CreateDatabaseIfNotExists() + { + var myConn = new SqlConnection(masterConnectionString); + + const string str = """ + IF NOT EXISTS (SELECT 1 FROM sys.databases WHERE name = 'Biergarten') + CREATE DATABASE [Biergarten] + """; + + var myCommand = new SqlCommand(str, myConn); + try + { + myConn.Open(); + myCommand.ExecuteNonQuery(); + Console.WriteLine("Database creation command executed successfully."); + } + catch (System.Exception ex) + { + Console.WriteLine($"Error creating database: {ex}"); + } + finally + { + if (myConn.State == ConnectionState.Open) + { + myConn.Close(); + } + } + return true; + } + + public static int Main(string[] args) + { + Console.WriteLine("Starting database migrations..."); + + try + { + CreateDatabaseIfNotExists(); + var success = DeployMigrations(); + + if (success) + { + Console.WriteLine("Database migrations completed successfully."); + return 0; + } + else + { + Console.WriteLine("Database migrations failed."); + return 1; + } + } + catch (Exception ex) + { + Console.WriteLine("An error occurred during database migrations:"); + Console.WriteLine(ex.Message); + return 1; + } + } +} diff --git a/src/Core/Database/Database.Core/scripts/01-schema/schema.sql b/src/Core/Database/Database.Migrations/scripts/01-schema/schema.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/01-schema/schema.sql rename to src/Core/Database/Database.Migrations/scripts/01-schema/schema.sql diff --git a/src/Core/Database/Database.Core/scripts/02-functions/UDF_GetCountryIdByCode.sql b/src/Core/Database/Database.Migrations/scripts/02-functions/UDF_GetCountryIdByCode.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/02-functions/UDF_GetCountryIdByCode.sql rename to src/Core/Database/Database.Migrations/scripts/02-functions/UDF_GetCountryIdByCode.sql diff --git a/src/Core/Database/Database.Core/scripts/02-functions/UDF_GetStateProvinceIdByCode.sql b/src/Core/Database/Database.Migrations/scripts/02-functions/UDF_GetStateProvinceIdByCode.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/02-functions/UDF_GetStateProvinceIdByCode.sql rename to src/Core/Database/Database.Migrations/scripts/02-functions/UDF_GetStateProvinceIdByCode.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_CreateUserAccount.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_CreateUserAccount.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_CreateUserAccount.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_CreateUserAccount.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_DeleteUserAccount.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_DeleteUserAccount.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_DeleteUserAccount.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_DeleteUserAccount.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_GetAllUserAccounts.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_GetAllUserAccounts.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_GetAllUserAccounts.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_GetAllUserAccounts.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_GetUserAccountByEmail.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_GetUserAccountByEmail.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_GetUserAccountByEmail.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_GetUserAccountByEmail.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_GetUserAccountById.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_GetUserAccountById.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_GetUserAccountById.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_GetUserAccountById.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_GetUserAccountByUsername.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_GetUserAccountByUsername.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_GetUserAccountByUsername.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_GetUserAccountByUsername.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_UpdateUserAccount.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_UpdateUserAccount.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/01-UserAccount/USP_UpdateUserAccount.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/01-UserAccount/USP_UpdateUserAccount.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/02-Auth/USP_GetUserCredentialByUserAccountId.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/02-Auth/USP_GetUserCredentialByUserAccountId.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/02-Auth/USP_GetUserCredentialByUserAccountId.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/02-Auth/USP_GetUserCredentialByUserAccountId.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/02-Auth/USP_InvalidateUserCredential.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/02-Auth/USP_InvalidateUserCredential.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/02-Auth/USP_InvalidateUserCredential.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/02-Auth/USP_InvalidateUserCredential.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/02-Auth/USP_RegisterUser.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/02-Auth/USP_RegisterUser.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/02-Auth/USP_RegisterUser.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/02-Auth/USP_RegisterUser.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/02-Auth/USP_RotateUserCredential.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/02-Auth/USP_RotateUserCredential.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/02-Auth/USP_RotateUserCredential.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/02-Auth/USP_RotateUserCredential.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/03-UserVerification/USP_AddUserVerification.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/03-UserVerification/USP_AddUserVerification.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/03-UserVerification/USP_AddUserVerification.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/03-UserVerification/USP_AddUserVerification.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/04-Location/USP_CreateCity.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/04-Location/USP_CreateCity.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/04-Location/USP_CreateCity.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/04-Location/USP_CreateCity.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/04-Location/USP_CreateCountry.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/04-Location/USP_CreateCountry.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/04-Location/USP_CreateCountry.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/04-Location/USP_CreateCountry.sql diff --git a/src/Core/Database/Database.Core/scripts/03-crud/04-Location/USP_CreateStateProvince.sql b/src/Core/Database/Database.Migrations/scripts/03-crud/04-Location/USP_CreateStateProvince.sql similarity index 100% rename from src/Core/Database/Database.Core/scripts/03-crud/04-Location/USP_CreateStateProvince.sql rename to src/Core/Database/Database.Migrations/scripts/03-crud/04-Location/USP_CreateStateProvince.sql diff --git a/src/Core/Database/Database.Seed/Database.Seed.csproj b/src/Core/Database/Database.Seed/Database.Seed.csproj index e9b8521..656d3be 100644 --- a/src/Core/Database/Database.Seed/Database.Seed.csproj +++ b/src/Core/Database/Database.Seed/Database.Seed.csproj @@ -16,9 +16,9 @@ - + - + diff --git a/src/Core/Database/Database.Seed/Program.cs b/src/Core/Database/Database.Seed/Program.cs index 8612f2e..720005b 100644 --- a/src/Core/Database/Database.Seed/Program.cs +++ b/src/Core/Database/Database.Seed/Program.cs @@ -22,14 +22,14 @@ try await useMaster.ExecuteNonQueryAsync(); var dbName = "Biergarten"; - var dropDb = connection.CreateCommand(); - dropDb.CommandText = $@" - IF DB_ID(N'{dbName}') IS NOT NULL - BEGIN - ALTER DATABASE [{dbName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; - DROP DATABASE [{dbName}]; - END"; - await dropDb.ExecuteNonQueryAsync(); + var dropDb = connection.CreateCommand(); + dropDb.CommandText = $@" + IF DB_ID(N'{dbName}') IS NOT NULL + BEGIN + ALTER DATABASE [{dbName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; + DROP DATABASE [{dbName}]; + END"; + await dropDb.ExecuteNonQueryAsync(); var createDb = connection.CreateCommand(); createDb.CommandText = $@"CREATE DATABASE [{dbName}];";