diff --git a/.github/workflows/scripts/rerunFlakyTests.js b/.github/workflows/scripts/rerunFlakyTests.js
index 3e7630f8f60..dd7e653756c 100644
--- a/.github/workflows/scripts/rerunFlakyTests.js
+++ b/.github/workflows/scripts/rerunFlakyTests.js
@@ -16,10 +16,7 @@ async function getFailedJobsForRun(github, context, workflowRunId, runAttempt) {
});
return jobs
- .filter((job) => job.conclusion === "failure")
- .filter((job) =>
- CONSIDERED_JOBS.some((title) => job.name.startsWith(title))
- );
+ .filter((job) => job.conclusion === "failure");
}
export async function rerunFlakyTests({ github, context }) {
@@ -35,12 +32,14 @@ export async function rerunFlakyTests({ github, context }) {
return;
}
- if (failingJobs.length === 0) {
- throw new Error(
- "rerunFlakyTests should not have run on a run with no failing jobs"
- );
+ const filteredFailingJobs = failingJobs.filter((job) => CONSIDERED_JOBS.some((title) => job.name.startsWith(title)));
+ if (filteredFailingJobs.length === 0) {
+ console.log("Failing jobs are NOT designated flaky. Not rerunning.");
+ return;
}
+ console.log(`Rerunning job: ${filteredFailingJobs[0].name}`);
+
github.rest.actions.reRunWorkflowFailedJobs({
owner: context.repo.owner,
repo: context.repo.repo,
diff --git a/build/TestCommon.props b/build/TestCommon.props
index 30fef503c8d..c932f8919da 100644
--- a/build/TestCommon.props
+++ b/build/TestCommon.props
@@ -18,9 +18,9 @@
-
+
-
+
diff --git a/build/Version.props b/build/Version.props
index ba966518a4e..8bbf9544b6d 100644
--- a/build/Version.props
+++ b/build/Version.props
@@ -3,12 +3,12 @@
- 6.4.1
+ 6.5.0
5.1.0
- 10.2.0
+ 10.3.0
7.0.0
- 13.2.0
- 15.2.0
+ 13.3.0
+ 15.3.0
7.1.2
5.9.0
1.4.1
@@ -17,7 +17,7 @@
netstandard2.0
8
- https://download.visualstudio.microsoft.com/download/pr/98ff0a08-a283-428f-8e54-19841d97154c/8c7d5f9600eadf264f04c82c813b7aab/dotnet-hosting-8.0.2-win.exe
+ https://download.visualstudio.microsoft.com/download/pr/00397fee-1bd9-44ef-899b-4504b26e6e96/ab9c73409659f3238d33faee304a8b7c/dotnet-hosting-8.0.4-win.exe
10.11.6
1.22.21
diff --git a/src/Tgstation.Server.Api/Models/Internal/DreamMakerSettings.cs b/src/Tgstation.Server.Api/Models/Internal/DreamMakerSettings.cs
index d6c229e6732..c7a11c1b3b3 100644
--- a/src/Tgstation.Server.Api/Models/Internal/DreamMakerSettings.cs
+++ b/src/Tgstation.Server.Api/Models/Internal/DreamMakerSettings.cs
@@ -39,5 +39,12 @@ public abstract class DreamMakerSettings
///
[Required]
public TimeSpan? Timeout { get; set; }
+
+ ///
+ /// Additional arguments added to the compiler command line.
+ ///
+ [StringLength(Limits.MaximumStringLength)]
+ [ResponseOptions]
+ public string? CompilerAdditionalArguments { get; set; }
}
}
diff --git a/src/Tgstation.Server.Api/Rights/DreamMakerRights.cs b/src/Tgstation.Server.Api/Rights/DreamMakerRights.cs
index c8852ce3386..6e7e882dd44 100644
--- a/src/Tgstation.Server.Api/Rights/DreamMakerRights.cs
+++ b/src/Tgstation.Server.Api/Rights/DreamMakerRights.cs
@@ -57,5 +57,10 @@ public enum DreamMakerRights : ulong
/// User may modify .
///
SetTimeout = 1 << 8,
+
+ ///
+ /// User may modify .
+ ///
+ SetCompilerArguments = 1 << 9,
}
}
diff --git a/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj b/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj
index 67843b79d06..502f74b2552 100644
--- a/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj
+++ b/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj
@@ -27,7 +27,7 @@
-
+
diff --git a/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj b/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj
index 8b98ec2894d..f085719f84e 100644
--- a/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj
+++ b/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj
@@ -11,9 +11,9 @@
-
+
-
+
diff --git a/src/Tgstation.Server.Host/.config/dotnet-tools.json b/src/Tgstation.Server.Host/.config/dotnet-tools.json
index c6670e9f580..8e82e300184 100644
--- a/src/Tgstation.Server.Host/.config/dotnet-tools.json
+++ b/src/Tgstation.Server.Host/.config/dotnet-tools.json
@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"dotnet-ef": {
- "version": "8.0.3",
+ "version": "8.0.4",
"commands": [
"dotnet-ef"
]
diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
index 27107f7ff85..76c415bac45 100644
--- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
+++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
@@ -571,6 +571,7 @@ async ValueTask RunCompileJob(
progressReporter.StageName = "Copying repository";
var resolvedOutputDirectory = ioManager.ResolvePath(outputDirectory);
var repoOrigin = repository.Origin;
+ var repoReference = repository.Reference;
using (repository)
await repository.CopyTo(resolvedOutputDirectory, cancellationToken);
@@ -585,6 +586,7 @@ await eventConsumer.HandleEvent(
resolvedOutputDirectory,
repoOrigin.ToString(),
engineLock.Version.ToString(),
+ repoReference,
},
true,
cancellationToken);
@@ -630,7 +632,7 @@ await eventConsumer.HandleEvent(
// run compiler
progressReporter.StageName = "Running Compiler";
- var compileSuceeded = await RunDreamMaker(engineLock, job, cancellationToken);
+ var compileSuceeded = await RunDreamMaker(engineLock, job, dreamMakerSettings.CompilerAdditionalArguments, cancellationToken);
// Session takes ownership of the lock and Disposes it so save this for later
var engineVersion = engineLock.Version;
@@ -848,12 +850,17 @@ async ValueTask VerifyApi(
///
/// The to use.
/// The for the operation.
+ /// Additional arguments to be added to the compiler.
/// The for the operation.
/// A resulting in if compilation succeeded, otherwise.
- async ValueTask RunDreamMaker(IEngineExecutableLock engineLock, Models.CompileJob job, CancellationToken cancellationToken)
+ async ValueTask RunDreamMaker(
+ IEngineExecutableLock engineLock,
+ Models.CompileJob job,
+ string? additionalCompilerArguments,
+ CancellationToken cancellationToken)
{
var environment = await engineLock.LoadEnv(logger, true, cancellationToken);
- var arguments = engineLock.FormatCompilerArguments($"{job.DmeName}.{DmeExtension}");
+ var arguments = engineLock.FormatCompilerArguments($"{job.DmeName}.{DmeExtension}", additionalCompilerArguments);
await using var dm = await processExecutor.LaunchProcess(
engineLock.CompilerExePath,
diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs
index b3ddd1cc1aa..8ee095babcd 100644
--- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs
+++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs
@@ -147,7 +147,14 @@ public override string FormatServerArguments(
}
///
- public override string FormatCompilerArguments(string dmePath)
- => $"-clean \"{dmePath ?? throw new ArgumentNullException(nameof(dmePath))}\"";
+ public override string FormatCompilerArguments(string dmePath, string? additionalArguments)
+ {
+ if (String.IsNullOrWhiteSpace(additionalArguments))
+ additionalArguments = String.Empty;
+ else
+ additionalArguments = $"{additionalArguments.Trim()} ";
+
+ return $"-clean {additionalArguments}\"{dmePath ?? throw new ArgumentNullException(nameof(dmePath))}\"";
+ }
}
}
diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs
index 3136e10aefa..3589d6c4aff 100644
--- a/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs
+++ b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs
@@ -55,7 +55,7 @@ public string FormatServerArguments(
logFilePath);
///
- public string FormatCompilerArguments(string dmePath) => Instance.FormatCompilerArguments(dmePath);
+ public string FormatCompilerArguments(string dmePath, string? additionalArguments) => Instance.FormatCompilerArguments(dmePath, additionalArguments);
///
public ValueTask StopServerProcess(ILogger logger, IProcess process, string accessIdentifier, ushort port, CancellationToken cancellationToken)
diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs
index 22c1c149878..928f8e30067 100644
--- a/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs
+++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs
@@ -78,7 +78,7 @@ public EngineInstallationBase(IIOManager installationIOManager)
}
///
- public abstract string FormatCompilerArguments(string dmePath);
+ public abstract string FormatCompilerArguments(string dmePath, string? additionalArguments);
///
public abstract string FormatServerArguments(
diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs
index bdcfe2bf90e..1d467a2881a 100644
--- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs
+++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs
@@ -74,8 +74,9 @@ string FormatServerArguments(
/// Return the command line arguments for compiling a given if compilation is necessary.
///
/// The full path to the .dme to compile.
+ /// Optional additional arguments provided to the compiler.
/// The formatted arguments .
- string FormatCompilerArguments(string dmePath);
+ string FormatCompilerArguments(string dmePath, string? additionalArguments);
///
/// Kills a given engine server .
diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs
index c522b9cedde..49c5ed1470b 100644
--- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs
+++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs
@@ -112,8 +112,15 @@ public override string FormatServerArguments(
}
///
- public override string FormatCompilerArguments(string dmePath)
- => $"--suppress-unimplemented --notices-enabled \"{dmePath ?? throw new ArgumentNullException(nameof(dmePath))}\"";
+ public override string FormatCompilerArguments(string dmePath, string? additionalArguments)
+ {
+ if (String.IsNullOrWhiteSpace(additionalArguments))
+ additionalArguments = String.Empty;
+ else
+ additionalArguments = $"{additionalArguments.Trim()} ";
+
+ return $"--suppress-unimplemented --notices-enabled {additionalArguments}\"{dmePath ?? throw new ArgumentNullException(nameof(dmePath))}\"";
+ }
///
public override async ValueTask StopServerProcess(
diff --git a/src/Tgstation.Server.Host/Components/Events/EventType.cs b/src/Tgstation.Server.Host/Components/Events/EventType.cs
index 4872998c61d..5d8c0b9054d 100644
--- a/src/Tgstation.Server.Host/Components/Events/EventType.cs
+++ b/src/Tgstation.Server.Host/Components/Events/EventType.cs
@@ -55,7 +55,7 @@ public enum EventType
EngineActiveVersionChange,
///
- /// After the repo is copied, before CodeModifications are applied. Parameters: Game directory path, origin commit sha, engine version string.
+ /// After the repo is copied, before CodeModifications are applied. Parameters: Game directory path, origin commit sha, engine version string, repository reference (or "(no branch)" if there is no reference).
///
[EventScript("PreCompile")]
CompileStart,
diff --git a/src/Tgstation.Server.Host/Components/Repository/Repository.cs b/src/Tgstation.Server.Host/Components/Repository/Repository.cs
index 2a362ff90c8..972fae31cca 100644
--- a/src/Tgstation.Server.Host/Components/Repository/Repository.cs
+++ b/src/Tgstation.Server.Host/Components/Repository/Repository.cs
@@ -46,6 +46,11 @@ sealed class Repository : DisposeInvoker, IRepository
///
public const string RemoteTemporaryBranchName = "___TGSTempBranch";
+ ///
+ /// The value of when not on a reference.
+ ///
+ public const string NoReference = "(no branch)";
+
///
/// Used when a reference cannot be determined.
///
diff --git a/src/Tgstation.Server.Host/Controllers/ApiRootController.cs b/src/Tgstation.Server.Host/Controllers/ApiRootController.cs
index fa6b3e0c4b6..9bf56a0e4d0 100644
--- a/src/Tgstation.Server.Host/Controllers/ApiRootController.cs
+++ b/src/Tgstation.Server.Host/Controllers/ApiRootController.cs
@@ -357,7 +357,7 @@ public async ValueTask CreateToken(CancellationToken cancellation
var identExpiry = token.ParseJwt().ValidTo;
identExpiry += tokenFactory.ValidationParameters.ClockSkew;
identExpiry += TimeSpan.FromSeconds(15);
- identityCache.CacheSystemIdentity(user, systemIdentity!, identExpiry);
+ await identityCache.CacheSystemIdentity(user, systemIdentity!, identExpiry);
}
Logger.LogDebug("Successfully logged in user {userId}!", user.Id);
diff --git a/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs b/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs
index 8b4cfce563c..22325779c7f 100644
--- a/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs
+++ b/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs
@@ -171,7 +171,8 @@ await jobManager.RegisterOperation(
| DreamMakerRights.SetApiValidationPort
| DreamMakerRights.SetSecurityLevel
| DreamMakerRights.SetApiValidationRequirement
- | DreamMakerRights.SetTimeout)]
+ | DreamMakerRights.SetTimeout
+ | DreamMakerRights.SetCompilerArguments)]
[ProducesResponseType(typeof(DreamMakerResponse), 200)]
[ProducesResponseType(204)]
[ProducesResponseType(typeof(ErrorMessageResponse), 410)]
@@ -196,7 +197,8 @@ public async ValueTask Update([FromBody] DreamMakerRequest model,
{
if (!dreamMakerRights.HasFlag(DreamMakerRights.SetDme))
return Forbid();
- if (model.ProjectName.Length == 0)
+
+ if (model.ProjectName.Length == 0) // can't use isnullorwhitespace because linux memes
hostModel.ProjectName = null;
else
hostModel.ProjectName = model.ProjectName;
@@ -230,6 +232,7 @@ public async ValueTask Update([FromBody] DreamMakerRequest model,
{
if (!dreamMakerRights.HasFlag(DreamMakerRights.SetSecurityLevel))
return Forbid();
+
hostModel.ApiValidationSecurityLevel = model.ApiValidationSecurityLevel;
}
@@ -237,6 +240,7 @@ public async ValueTask Update([FromBody] DreamMakerRequest model,
{
if (!dreamMakerRights.HasFlag(DreamMakerRights.SetApiValidationRequirement))
return Forbid();
+
hostModel.RequireDMApiValidation = model.RequireDMApiValidation;
}
@@ -244,9 +248,22 @@ public async ValueTask Update([FromBody] DreamMakerRequest model,
{
if (!dreamMakerRights.HasFlag(DreamMakerRights.SetTimeout))
return Forbid();
+
hostModel.Timeout = model.Timeout;
}
+ if (model.CompilerAdditionalArguments != null)
+ {
+ if (!dreamMakerRights.HasFlag(DreamMakerRights.SetCompilerArguments))
+ return Forbid();
+
+ var sanitizedArguments = model.CompilerAdditionalArguments.Trim();
+ if (sanitizedArguments.Length == 0)
+ hostModel.CompilerAdditionalArguments = null;
+ else
+ hostModel.CompilerAdditionalArguments = sanitizedArguments;
+ }
+
await DatabaseContext.Save(cancellationToken);
if (!dreamMakerRights.HasFlag(DreamMakerRights.Read))
diff --git a/src/Tgstation.Server.Host/Controllers/InstanceController.cs b/src/Tgstation.Server.Host/Controllers/InstanceController.cs
index cbc0f802dd5..e74d4fdce18 100644
--- a/src/Tgstation.Server.Host/Controllers/InstanceController.cs
+++ b/src/Tgstation.Server.Host/Controllers/InstanceController.cs
@@ -740,6 +740,7 @@ public async ValueTask GrantPermissions(long id, CancellationToke
ApiValidationSecurityLevel = DreamDaemonSecurity.Safe,
RequireDMApiValidation = true,
Timeout = TimeSpan.FromHours(1),
+ CompilerAdditionalArguments = null,
},
Name = initialSettings.Name,
Online = false,
diff --git a/src/Tgstation.Server.Host/Database/DatabaseContext.cs b/src/Tgstation.Server.Host/Database/DatabaseContext.cs
index 7dd49e7f2e9..d4fb8fe0845 100644
--- a/src/Tgstation.Server.Host/Database/DatabaseContext.cs
+++ b/src/Tgstation.Server.Host/Database/DatabaseContext.cs
@@ -375,22 +375,22 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
///
/// Used by unit tests to remind us to setup the correct MSSQL migration downgrades.
///
- internal static readonly Type MSLatestMigration = typeof(MSAddMinidumpsOption);
+ internal static readonly Type MSLatestMigration = typeof(MSAddCompilerAdditionalArguments);
///
/// Used by unit tests to remind us to setup the correct MYSQL migration downgrades.
///
- internal static readonly Type MYLatestMigration = typeof(MYAddMinidumpsOption);
+ internal static readonly Type MYLatestMigration = typeof(MYAddCompilerAdditionalArguments);
///
/// Used by unit tests to remind us to setup the correct PostgresSQL migration downgrades.
///
- internal static readonly Type PGLatestMigration = typeof(PGAddMinidumpsOption);
+ internal static readonly Type PGLatestMigration = typeof(PGAddCompilerAdditionalArguments);
///
/// Used by unit tests to remind us to setup the correct SQLite migration downgrades.
///
- internal static readonly Type SLLatestMigration = typeof(SLAddMinidumpsOption);
+ internal static readonly Type SLLatestMigration = typeof(SLAddCompilerAdditionalArguments);
///
#pragma warning disable CA1502 // Cyclomatic complexity
@@ -419,6 +419,16 @@ public async ValueTask SchemaDowngradeForServerVersion(
string BadDatabaseType() => throw new ArgumentException($"Invalid DatabaseType: {currentDatabaseType}", nameof(currentDatabaseType));
+ if (targetVersion < new Version(6, 5, 0))
+ targetMigration = currentDatabaseType switch
+ {
+ DatabaseType.MySql => nameof(MYAddMinidumpsOption),
+ DatabaseType.PostgresSql => nameof(PGAddMinidumpsOption),
+ DatabaseType.SqlServer => nameof(MSAddMinidumpsOption),
+ DatabaseType.Sqlite => nameof(SLAddMinidumpsOption),
+ _ => BadDatabaseType(),
+ };
+
if (targetVersion < new Version(6, 2, 0))
targetMigration = currentDatabaseType switch
{
diff --git a/src/Tgstation.Server.Host/Database/Migrations/20240420153929_MYNormalizeVersionUpdates.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20240420153929_MYNormalizeVersionUpdates.Designer.cs
new file mode 100644
index 00000000000..982497eff8d
--- /dev/null
+++ b/src/Tgstation.Server.Host/Database/Migrations/20240420153929_MYNormalizeVersionUpdates.Designer.cs
@@ -0,0 +1,1150 @@
+//
+using System;
+
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace Tgstation.Server.Host.Database.Migrations
+{
+ [DbContext(typeof(MySqlDatabaseContext))]
+ [Migration("20240420153929_MYNormalizeVersionUpdates")]
+ partial class MYNormalizeVersionUpdates
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.4")
+ .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+ MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("ChannelLimit")
+ .IsRequired()
+ .HasColumnType("smallint unsigned");
+
+ b.Property("ConnectionString")
+ .IsRequired()
+ .HasMaxLength(10000)
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("ConnectionString"), "utf8mb4");
+
+ b.Property("Enabled")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ b.Property("Provider")
+ .HasColumnType("int");
+
+ b.Property("ReconnectionInterval")
+ .IsRequired()
+ .HasColumnType("int unsigned");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId", "Name")
+ .IsUnique();
+
+ b.ToTable("ChatBots");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("ChatSettingsId")
+ .HasColumnType("bigint");
+
+ b.Property("DiscordChannelId")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("IrcChannel")
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("IrcChannel"), "utf8mb4");
+
+ b.Property("IsAdminChannel")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("IsSystemChannel")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("IsUpdatesChannel")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("IsWatchdogChannel")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Tag")
+ .HasMaxLength(10000)
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Tag"), "utf8mb4");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ChatSettingsId", "DiscordChannelId")
+ .IsUnique();
+
+ b.HasIndex("ChatSettingsId", "IrcChannel")
+ .IsUnique();
+
+ b.ToTable("ChatChannels");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("DMApiMajorVersion")
+ .HasColumnType("int");
+
+ b.Property("DMApiMinorVersion")
+ .HasColumnType("int");
+
+ b.Property("DMApiPatchVersion")
+ .HasColumnType("int");
+
+ b.Property("DirectoryName")
+ .IsRequired()
+ .HasColumnType("char(36)");
+
+ b.Property("DmeName")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("DmeName"), "utf8mb4");
+
+ b.Property("EngineVersion")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("EngineVersion"), "utf8mb4");
+
+ b.Property("GitHubDeploymentId")
+ .HasColumnType("int");
+
+ b.Property("GitHubRepoId")
+ .HasColumnType("bigint");
+
+ b.Property("JobId")
+ .HasColumnType("bigint");
+
+ b.Property("MinimumSecurityLevel")
+ .HasColumnType("int");
+
+ b.Property("Output")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Output"), "utf8mb4");
+
+ b.Property("RepositoryOrigin")
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("RepositoryOrigin"), "utf8mb4");
+
+ b.Property("RevisionInformationId")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DirectoryName");
+
+ b.HasIndex("JobId")
+ .IsUnique();
+
+ b.HasIndex("RevisionInformationId");
+
+ b.ToTable("CompileJobs");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("AdditionalParameters")
+ .IsRequired()
+ .HasMaxLength(10000)
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("AdditionalParameters"), "utf8mb4");
+
+ b.Property("AllowWebClient")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("AutoStart")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("DumpOnHealthCheckRestart")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("HealthCheckSeconds")
+ .IsRequired()
+ .HasColumnType("int unsigned");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("LogOutput")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("MapThreads")
+ .IsRequired()
+ .HasColumnType("int unsigned");
+
+ b.Property("Minidumps")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Port")
+ .IsRequired()
+ .HasColumnType("smallint unsigned");
+
+ b.Property("SecurityLevel")
+ .HasColumnType("int");
+
+ b.Property("StartProfiler")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("StartupTimeout")
+ .IsRequired()
+ .HasColumnType("int unsigned");
+
+ b.Property("TopicRequestTimeout")
+ .IsRequired()
+ .HasColumnType("int unsigned");
+
+ b.Property("Visibility")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId")
+ .IsUnique();
+
+ b.ToTable("DreamDaemonSettings");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("ApiValidationPort")
+ .IsRequired()
+ .HasColumnType("smallint unsigned");
+
+ b.Property("ApiValidationSecurityLevel")
+ .HasColumnType("int");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("ProjectName")
+ .HasMaxLength(10000)
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("ProjectName"), "utf8mb4");
+
+ b.Property("RequireDMApiValidation")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Timeout")
+ .IsRequired()
+ .HasColumnType("time(6)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId")
+ .IsUnique();
+
+ b.ToTable("DreamMakerSettings");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("AutoUpdateInterval")
+ .IsRequired()
+ .HasColumnType("int unsigned");
+
+ b.Property("ChatBotLimit")
+ .IsRequired()
+ .HasColumnType("smallint unsigned");
+
+ b.Property("ConfigurationType")
+ .HasColumnType("int");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Name"), "utf8mb4");
+
+ b.Property("Online")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Path")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Path"), "utf8mb4");
+
+ b.Property("SwarmIdentifer")
+ .HasColumnType("varchar(255)");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("SwarmIdentifer"), "utf8mb4");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Path", "SwarmIdentifer")
+ .IsUnique();
+
+ b.ToTable("Instances");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("ChatBotRights")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("ConfigurationRights")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("DreamDaemonRights")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("DreamMakerRights")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("EngineRights")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("InstancePermissionSetRights")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("PermissionSetId")
+ .HasColumnType("bigint");
+
+ b.Property("RepositoryRights")
+ .HasColumnType("bigint unsigned");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId");
+
+ b.HasIndex("PermissionSetId", "InstanceId")
+ .IsUnique();
+
+ b.ToTable("InstancePermissionSets");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("CancelRight")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("CancelRightsType")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("Cancelled")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("CancelledById")
+ .HasColumnType("bigint");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Description"), "utf8mb4");
+
+ b.Property("ErrorCode")
+ .HasColumnType("int unsigned");
+
+ b.Property("ExceptionDetails")
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("ExceptionDetails"), "utf8mb4");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("JobCode")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("StartedAt")
+ .IsRequired()
+ .HasColumnType("datetime(6)");
+
+ b.Property("StartedById")
+ .HasColumnType("bigint");
+
+ b.Property("StoppedAt")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CancelledById");
+
+ b.HasIndex("InstanceId");
+
+ b.HasIndex("StartedById");
+
+ b.ToTable("Jobs");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("ExternalUserId")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("ExternalUserId"), "utf8mb4");
+
+ b.Property("Provider")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.HasIndex("Provider", "ExternalUserId")
+ .IsUnique();
+
+ b.ToTable("OAuthConnections");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("AdministrationRights")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("GroupId")
+ .HasColumnType("bigint");
+
+ b.Property("InstanceManagerRights")
+ .HasColumnType("bigint unsigned");
+
+ b.Property("UserId")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("GroupId")
+ .IsUnique();
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("PermissionSets");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("AccessIdentifier")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("AccessIdentifier"), "utf8mb4");
+
+ b.Property("CompileJobId")
+ .HasColumnType("bigint");
+
+ b.Property("InitialCompileJobId")
+ .HasColumnType("bigint");
+
+ b.Property("LaunchSecurityLevel")
+ .HasColumnType("int");
+
+ b.Property("LaunchVisibility")
+ .HasColumnType("int");
+
+ b.Property("Port")
+ .HasColumnType("smallint unsigned");
+
+ b.Property("ProcessId")
+ .HasColumnType("int");
+
+ b.Property("RebootState")
+ .HasColumnType("int");
+
+ b.Property("TopicPort")
+ .HasColumnType("smallint unsigned");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CompileJobId");
+
+ b.HasIndex("InitialCompileJobId");
+
+ b.ToTable("ReattachInformations");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("AccessToken")
+ .HasMaxLength(10000)
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("AccessToken"), "utf8mb4");
+
+ b.Property("AccessUser")
+ .HasMaxLength(10000)
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("AccessUser"), "utf8mb4");
+
+ b.Property("AutoUpdatesKeepTestMerges")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("AutoUpdatesSynchronize")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("CommitterEmail")
+ .IsRequired()
+ .HasMaxLength(10000)
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("CommitterEmail"), "utf8mb4");
+
+ b.Property("CommitterName")
+ .IsRequired()
+ .HasMaxLength(10000)
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("CommitterName"), "utf8mb4");
+
+ b.Property("CreateGitHubDeployments")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("PostTestMergeComment")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("PushTestMergeCommits")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ShowTestMergeCommitters")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UpdateSubmodules")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId")
+ .IsUnique();
+
+ b.ToTable("RepositorySettings");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("RevisionInformationId")
+ .HasColumnType("bigint");
+
+ b.Property("TestMergeId")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RevisionInformationId");
+
+ b.HasIndex("TestMergeId");
+
+ b.ToTable("RevInfoTestMerges");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("CommitSha")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("CommitSha"), "utf8mb4");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("OriginCommitSha")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("OriginCommitSha"), "utf8mb4");
+
+ b.Property("Timestamp")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId", "CommitSha")
+ .IsUnique();
+
+ b.ToTable("RevisionInformations");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("Author")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Author"), "utf8mb4");
+
+ b.Property("BodyAtMerge")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("BodyAtMerge"), "utf8mb4");
+
+ b.Property("Comment")
+ .HasMaxLength(10000)
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Comment"), "utf8mb4");
+
+ b.Property("MergedAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("MergedById")
+ .HasColumnType("bigint");
+
+ b.Property("Number")
+ .HasColumnType("int");
+
+ b.Property("PrimaryRevisionInformationId")
+ .IsRequired()
+ .HasColumnType("bigint");
+
+ b.Property("TargetCommitSha")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("TargetCommitSha"), "utf8mb4");
+
+ b.Property("TitleAtMerge")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("TitleAtMerge"), "utf8mb4");
+
+ b.Property("Url")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Url"), "utf8mb4");
+
+ b.HasKey("Id");
+
+ b.HasIndex("MergedById");
+
+ b.HasIndex("PrimaryRevisionInformationId")
+ .IsUnique();
+
+ b.ToTable("TestMerges");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("CanonicalName")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("CanonicalName"), "utf8mb4");
+
+ b.Property("CreatedAt")
+ .IsRequired()
+ .HasColumnType("datetime(6)");
+
+ b.Property("CreatedById")
+ .HasColumnType("bigint");
+
+ b.Property("Enabled")
+ .IsRequired()
+ .HasColumnType("tinyint(1)");
+
+ b.Property("GroupId")
+ .HasColumnType("bigint");
+
+ b.Property("LastPasswordUpdate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Name"), "utf8mb4");
+
+ b.Property("PasswordHash")
+ .HasColumnType("longtext");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("PasswordHash"), "utf8mb4");
+
+ b.Property("SystemIdentifier")
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("SystemIdentifier"), "utf8mb4");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CanonicalName")
+ .IsUnique();
+
+ b.HasIndex("CreatedById");
+
+ b.HasIndex("GroupId");
+
+ b.HasIndex("SystemIdentifier")
+ .IsUnique();
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Name"), "utf8mb4");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name")
+ .IsUnique();
+
+ b.ToTable("Groups");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
+ .WithMany("ChatSettings")
+ .HasForeignKey("InstanceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Instance");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings")
+ .WithMany("Channels")
+ .HasForeignKey("ChatSettingsId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("ChatSettings");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.Job", "Job")
+ .WithOne()
+ .HasForeignKey("Tgstation.Server.Host.Models.CompileJob", "JobId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation")
+ .WithMany("CompileJobs")
+ .HasForeignKey("RevisionInformationId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Job");
+
+ b.Navigation("RevisionInformation");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
+ .WithOne("DreamDaemonSettings")
+ .HasForeignKey("Tgstation.Server.Host.Models.DreamDaemonSettings", "InstanceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Instance");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
+ .WithOne("DreamMakerSettings")
+ .HasForeignKey("Tgstation.Server.Host.Models.DreamMakerSettings", "InstanceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Instance");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
+ .WithMany("InstancePermissionSets")
+ .HasForeignKey("InstanceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Tgstation.Server.Host.Models.PermissionSet", "PermissionSet")
+ .WithMany("InstancePermissionSets")
+ .HasForeignKey("PermissionSetId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Instance");
+
+ b.Navigation("PermissionSet");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.User", "CancelledBy")
+ .WithMany()
+ .HasForeignKey("CancelledById");
+
+ b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
+ .WithMany("Jobs")
+ .HasForeignKey("InstanceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Tgstation.Server.Host.Models.User", "StartedBy")
+ .WithMany()
+ .HasForeignKey("StartedById")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("CancelledBy");
+
+ b.Navigation("Instance");
+
+ b.Navigation("StartedBy");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.User", "User")
+ .WithMany("OAuthConnections")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group")
+ .WithOne("PermissionSet")
+ .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "GroupId")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("Tgstation.Server.Host.Models.User", "User")
+ .WithOne("PermissionSet")
+ .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.Navigation("Group");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob")
+ .WithMany()
+ .HasForeignKey("CompileJobId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Tgstation.Server.Host.Models.CompileJob", "InitialCompileJob")
+ .WithMany()
+ .HasForeignKey("InitialCompileJobId");
+
+ b.Navigation("CompileJob");
+
+ b.Navigation("InitialCompileJob");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
+ .WithOne("RepositorySettings")
+ .HasForeignKey("Tgstation.Server.Host.Models.RepositorySettings", "InstanceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Instance");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation")
+ .WithMany("ActiveTestMerges")
+ .HasForeignKey("RevisionInformationId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Tgstation.Server.Host.Models.TestMerge", "TestMerge")
+ .WithMany("RevisonInformations")
+ .HasForeignKey("TestMergeId")
+ .OnDelete(DeleteBehavior.ClientNoAction)
+ .IsRequired();
+
+ b.Navigation("RevisionInformation");
+
+ b.Navigation("TestMerge");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance")
+ .WithMany("RevisionInformations")
+ .HasForeignKey("InstanceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Instance");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.User", "MergedBy")
+ .WithMany("TestMerges")
+ .HasForeignKey("MergedById")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "PrimaryRevisionInformation")
+ .WithOne("PrimaryTestMerge")
+ .HasForeignKey("Tgstation.Server.Host.Models.TestMerge", "PrimaryRevisionInformationId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("MergedBy");
+
+ b.Navigation("PrimaryRevisionInformation");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.User", b =>
+ {
+ b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy")
+ .WithMany("CreatedUsers")
+ .HasForeignKey("CreatedById");
+
+ b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group")
+ .WithMany("Users")
+ .HasForeignKey("GroupId");
+
+ b.Navigation("CreatedBy");
+
+ b.Navigation("Group");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
+ {
+ b.Navigation("Channels");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b =>
+ {
+ b.Navigation("ChatSettings");
+
+ b.Navigation("DreamDaemonSettings");
+
+ b.Navigation("DreamMakerSettings");
+
+ b.Navigation("InstancePermissionSets");
+
+ b.Navigation("Jobs");
+
+ b.Navigation("RepositorySettings");
+
+ b.Navigation("RevisionInformations");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b =>
+ {
+ b.Navigation("InstancePermissionSets");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b =>
+ {
+ b.Navigation("ActiveTestMerges");
+
+ b.Navigation("CompileJobs");
+
+ b.Navigation("PrimaryTestMerge");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b =>
+ {
+ b.Navigation("RevisonInformations");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.User", b =>
+ {
+ b.Navigation("CreatedUsers");
+
+ b.Navigation("OAuthConnections");
+
+ b.Navigation("PermissionSet");
+
+ b.Navigation("TestMerges");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b =>
+ {
+ b.Navigation("PermissionSet")
+ .IsRequired();
+
+ b.Navigation("Users");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/Database/Migrations/20240420153929_MYNormalizeVersionUpdates.cs b/src/Tgstation.Server.Host/Database/Migrations/20240420153929_MYNormalizeVersionUpdates.cs
new file mode 100644
index 00000000000..81cd88a0475
--- /dev/null
+++ b/src/Tgstation.Server.Host/Database/Migrations/20240420153929_MYNormalizeVersionUpdates.cs
@@ -0,0 +1,175 @@
+using System;
+
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace Tgstation.Server.Host.Database.Migrations
+{
+ ///
+ public partial class MYNormalizeVersionUpdates : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ ArgumentNullException.ThrowIfNull(migrationBuilder);
+
+ migrationBuilder.AlterColumn(
+ name: "Id",
+ table: "Users",
+ type: "bigint",
+ nullable: false,
+ oldClrType: typeof(long),
+ oldType: "bigint")
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
+
+ migrationBuilder.AlterColumn(
+ name: "Id",
+ table: "TestMerges",
+ type: "bigint",
+ nullable: false,
+ oldClrType: typeof(long),
+ oldType: "bigint")
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
+
+ migrationBuilder.AlterColumn(
+ name: "Id",
+ table: "RevisionInformations",
+ type: "bigint",
+ nullable: false,
+ oldClrType: typeof(long),
+ oldType: "bigint")
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
+
+ migrationBuilder.AlterColumn(
+ name: "Id",
+ table: "RevInfoTestMerges",
+ type: "bigint",
+ nullable: false,
+ oldClrType: typeof(long),
+ oldType: "bigint")
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
+
+ migrationBuilder.AlterColumn(
+ name: "Id",
+ table: "RepositorySettings",
+ type: "bigint",
+ nullable: false,
+ oldClrType: typeof(long),
+ oldType: "bigint")
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
+
+ migrationBuilder.AlterColumn(
+ name: "Id",
+ table: "ReattachInformations",
+ type: "bigint",
+ nullable: false,
+ oldClrType: typeof(long),
+ oldType: "bigint")
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
+
+ migrationBuilder.AlterColumn(
+ name: "Id",
+ table: "PermissionSets",
+ type: "bigint",
+ nullable: false,
+ oldClrType: typeof(long),
+ oldType: "bigint")
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
+
+ migrationBuilder.AlterColumn(
+ name: "Id",
+ table: "OAuthConnections",
+ type: "bigint",
+ nullable: false,
+ oldClrType: typeof(long),
+ oldType: "bigint")
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
+
+ migrationBuilder.AlterColumn(
+ name: "Id",
+ table: "Jobs",
+ type: "bigint",
+ nullable: false,
+ oldClrType: typeof(long),
+ oldType: "bigint")
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
+
+ migrationBuilder.AlterColumn(
+ name: "Id",
+ table: "Instances",
+ type: "bigint",
+ nullable: false,
+ oldClrType: typeof(long),
+ oldType: "bigint")
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
+
+ migrationBuilder.AlterColumn(
+ name: "Id",
+ table: "InstancePermissionSets",
+ type: "bigint",
+ nullable: false,
+ oldClrType: typeof(long),
+ oldType: "bigint")
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
+
+ migrationBuilder.AlterColumn(
+ name: "Id",
+ table: "Groups",
+ type: "bigint",
+ nullable: false,
+ oldClrType: typeof(long),
+ oldType: "bigint")
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
+
+ migrationBuilder.AlterColumn(
+ name: "Id",
+ table: "DreamMakerSettings",
+ type: "bigint",
+ nullable: false,
+ oldClrType: typeof(long),
+ oldType: "bigint")
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
+
+ migrationBuilder.AlterColumn(
+ name: "Id",
+ table: "DreamDaemonSettings",
+ type: "bigint",
+ nullable: false,
+ oldClrType: typeof(long),
+ oldType: "bigint")
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
+
+ migrationBuilder.AlterColumn(
+ name: "Id",
+ table: "CompileJobs",
+ type: "bigint",
+ nullable: false,
+ oldClrType: typeof(long),
+ oldType: "bigint")
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
+
+ migrationBuilder.AlterColumn(
+ name: "Id",
+ table: "ChatChannels",
+ type: "bigint",
+ nullable: false,
+ oldClrType: typeof(long),
+ oldType: "bigint")
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
+
+ migrationBuilder.AlterColumn(
+ name: "Id",
+ table: "ChatBots",
+ type: "bigint",
+ nullable: false,
+ oldClrType: typeof(long),
+ oldType: "bigint")
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/Database/Migrations/20240420154501_MSAddCompilerAdditionalArguments.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20240420154501_MSAddCompilerAdditionalArguments.Designer.cs
new file mode 100644
index 00000000000..904833311bf
--- /dev/null
+++ b/src/Tgstation.Server.Host/Database/Migrations/20240420154501_MSAddCompilerAdditionalArguments.Designer.cs
@@ -0,0 +1,1084 @@
+//
+using System;
+
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace Tgstation.Server.Host.Database.Migrations
+{
+ [DbContext(typeof(SqlServerDatabaseContext))]
+ [Migration("20240420154501_MSAddCompilerAdditionalArguments")]
+ partial class MSAddCompilerAdditionalArguments
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.4")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("ChannelLimit")
+ .HasColumnType("int");
+
+ b.Property("ConnectionString")
+ .IsRequired()
+ .HasMaxLength(10000)
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Enabled")
+ .HasColumnType("bit");
+
+ b.Property("InstanceId")
+ .HasColumnType("bigint");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)");
+
+ b.Property("Provider")
+ .HasColumnType("int");
+
+ b.Property("ReconnectionInterval")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InstanceId", "Name")
+ .IsUnique();
+
+ b.ToTable("ChatBots");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("ChatSettingsId")
+ .HasColumnType("bigint");
+
+ b.Property("DiscordChannelId")
+ .HasColumnType("decimal(20,0)");
+
+ b.Property("IrcChannel")
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)");
+
+ b.Property("IsAdminChannel")
+ .IsRequired()
+ .HasColumnType("bit");
+
+ b.Property("IsSystemChannel")
+ .IsRequired()
+ .HasColumnType("bit");
+
+ b.Property("IsUpdatesChannel")
+ .IsRequired()
+ .HasColumnType("bit");
+
+ b.Property("IsWatchdogChannel")
+ .IsRequired()
+ .HasColumnType("bit");
+
+ b.Property("Tag")
+ .HasMaxLength(10000)
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ChatSettingsId", "DiscordChannelId")
+ .IsUnique()
+ .HasFilter("[DiscordChannelId] IS NOT NULL");
+
+ b.HasIndex("ChatSettingsId", "IrcChannel")
+ .IsUnique()
+ .HasFilter("[IrcChannel] IS NOT NULL");
+
+ b.ToTable("ChatChannels");
+ });
+
+ modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("DMApiMajorVersion")
+ .HasColumnType("int");
+
+ b.Property("DMApiMinorVersion")
+ .HasColumnType("int");
+
+ b.Property("DMApiPatchVersion")
+ .HasColumnType("int");
+
+ b.Property("DirectoryName")
+ .IsRequired()
+ .HasColumnType("uniqueidentifier");
+
+ b.Property("DmeName")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("EngineVersion")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("GitHubDeploymentId")
+ .HasColumnType("int");
+
+ b.Property("GitHubRepoId")
+ .HasColumnType("bigint");
+
+ b.Property("JobId")
+ .HasColumnType("bigint");
+
+ b.Property