From 253acf08b41a69a65e9d27f6bfe8f3e44efd3006 Mon Sep 17 00:00:00 2001 From: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Date: Sat, 9 Jan 2021 22:26:14 +0000 Subject: [PATCH 01/42] DNM - Initial Commit --- .../Components/Events/EventType.cs | 8 +++++++- .../Components/InstanceFactory.cs | 3 ++- .../Components/Session/SessionController.cs | 13 +++++++++++-- .../Components/Watchdog/README.md | 2 +- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Events/EventType.cs b/src/Tgstation.Server.Host/Components/Events/EventType.cs index 9085c6e215..93fe022964 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventType.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventType.cs @@ -111,6 +111,12 @@ namespace Tgstation.Server.Host.Components.Events /// Before the watchdog launches. No parameters. /// [EventScript("WatchdogLaunch")] - WatchdogLaunch + WatchdogLaunch, + + /// + /// Inbetween DD restarts if the process has been force-ended by the DMAPI + /// + [EventScript("DDEndProcess")] + DDEndProcess } } diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index cd04474fb4..8296da7f35 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -273,7 +273,8 @@ namespace Tgstation.Server.Host.Components serverPortProvider, loggerFactory, loggerFactory.CreateLogger(), - metadata.CloneMetadata()); + metadata.CloneMetadata(), + eventConsumer); var dmbFactory = new DmbFactory( databaseContextFactory, diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index 1462b6cd50..47317b6474 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -14,6 +14,7 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Components.Byond; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Deployment; +using Tgstation.Server.Host.Components.Events; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Components.Interop.Bridge; using Tgstation.Server.Host.Components.Interop.Topic; @@ -168,6 +169,11 @@ namespace Tgstation.Server.Host.Components.Session /// bool released; + /// + /// The + /// + readonly IEventConsumer eventConsumer; + /// /// Construct a /// @@ -185,6 +191,7 @@ namespace Tgstation.Server.Host.Components.Session /// The optional time to wait before failing the /// If this is a reattached session. /// If this is a DMAPI validation session. + /// The value of . public SessionController( ReattachInformation reattachInformation, Api.Models.Instance metadata, @@ -199,7 +206,8 @@ namespace Tgstation.Server.Host.Components.Session Func postLifetimeCallback, uint? startupTimeout, bool reattached, - bool apiValidate) + bool apiValidate, + IEventConsumer eventConsumer) { this.reattachInformation = reattachInformation ?? throw new ArgumentNullException(nameof(reattachInformation)); this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); @@ -211,7 +219,7 @@ namespace Tgstation.Server.Host.Components.Session throw new ArgumentNullException(nameof(bridgeRegistrar)); this.chat = chat ?? throw new ArgumentNullException(nameof(chat)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - + this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer)); portClosedForReboot = false; disposed = false; apiValidationStatus = ApiValidationStatus.NeverValidated; @@ -393,6 +401,7 @@ namespace Tgstation.Server.Host.Components.Session logger.LogInformation("Bridge requested process termination!"); TerminationWasRequested = true; process.Terminate(); + eventConsumer.HandleEvent(EventType.DDEndProcess, Enumerable.Empty(), cancellationToken); break; case BridgeCommandType.PortUpdate: lock (synchronizationLock) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/README.md b/src/Tgstation.Server.Host/Components/Watchdog/README.md index f9846a0db7..229dc45032 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/README.md +++ b/src/Tgstation.Server.Host/Components/Watchdog/README.md @@ -29,7 +29,7 @@ From the perspective of `WatchdogBase` Watchdog monitoring takes place in the `MonitorLifetimes()` functiona and is entirely event based. It responds to a set of [MonitorActivationReason](./MonitorActivationReason.cs)s and takes the apporprate action. This includes: - When a server crashes. -- When a server calls `/world/prod/Reboot()`. +- When a server calls `/world/proc/Reboot()`. - When a new .dmb is deployed. - When DreamDaemon settings are changed via the API. - When it is time to make a heartbeat. From 129d1e7b631b051e9034ac458e3e23d3016f0c5b Mon Sep 17 00:00:00 2001 From: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Date: Sun, 10 Jan 2021 13:19:58 +0000 Subject: [PATCH 02/42] Revert "DNM - Initial Commit" This reverts commit 253acf08b41a69a65e9d27f6bfe8f3e44efd3006. --- .../Components/Events/EventType.cs | 8 +------- .../Components/InstanceFactory.cs | 3 +-- .../Components/Session/SessionController.cs | 13 ++----------- .../Components/Watchdog/README.md | 2 +- 4 files changed, 5 insertions(+), 21 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Events/EventType.cs b/src/Tgstation.Server.Host/Components/Events/EventType.cs index 93fe022964..9085c6e215 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventType.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventType.cs @@ -111,12 +111,6 @@ namespace Tgstation.Server.Host.Components.Events /// Before the watchdog launches. No parameters. /// [EventScript("WatchdogLaunch")] - WatchdogLaunch, - - /// - /// Inbetween DD restarts if the process has been force-ended by the DMAPI - /// - [EventScript("DDEndProcess")] - DDEndProcess + WatchdogLaunch } } diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index 8296da7f35..cd04474fb4 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -273,8 +273,7 @@ namespace Tgstation.Server.Host.Components serverPortProvider, loggerFactory, loggerFactory.CreateLogger(), - metadata.CloneMetadata(), - eventConsumer); + metadata.CloneMetadata()); var dmbFactory = new DmbFactory( databaseContextFactory, diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index 47317b6474..1462b6cd50 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -14,7 +14,6 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Components.Byond; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Deployment; -using Tgstation.Server.Host.Components.Events; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Components.Interop.Bridge; using Tgstation.Server.Host.Components.Interop.Topic; @@ -169,11 +168,6 @@ namespace Tgstation.Server.Host.Components.Session /// bool released; - /// - /// The - /// - readonly IEventConsumer eventConsumer; - /// /// Construct a /// @@ -191,7 +185,6 @@ namespace Tgstation.Server.Host.Components.Session /// The optional time to wait before failing the /// If this is a reattached session. /// If this is a DMAPI validation session. - /// The value of . public SessionController( ReattachInformation reattachInformation, Api.Models.Instance metadata, @@ -206,8 +199,7 @@ namespace Tgstation.Server.Host.Components.Session Func postLifetimeCallback, uint? startupTimeout, bool reattached, - bool apiValidate, - IEventConsumer eventConsumer) + bool apiValidate) { this.reattachInformation = reattachInformation ?? throw new ArgumentNullException(nameof(reattachInformation)); this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); @@ -219,7 +211,7 @@ namespace Tgstation.Server.Host.Components.Session throw new ArgumentNullException(nameof(bridgeRegistrar)); this.chat = chat ?? throw new ArgumentNullException(nameof(chat)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer)); + portClosedForReboot = false; disposed = false; apiValidationStatus = ApiValidationStatus.NeverValidated; @@ -401,7 +393,6 @@ namespace Tgstation.Server.Host.Components.Session logger.LogInformation("Bridge requested process termination!"); TerminationWasRequested = true; process.Terminate(); - eventConsumer.HandleEvent(EventType.DDEndProcess, Enumerable.Empty(), cancellationToken); break; case BridgeCommandType.PortUpdate: lock (synchronizationLock) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/README.md b/src/Tgstation.Server.Host/Components/Watchdog/README.md index 229dc45032..f9846a0db7 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/README.md +++ b/src/Tgstation.Server.Host/Components/Watchdog/README.md @@ -29,7 +29,7 @@ From the perspective of `WatchdogBase` Watchdog monitoring takes place in the `MonitorLifetimes()` functiona and is entirely event based. It responds to a set of [MonitorActivationReason](./MonitorActivationReason.cs)s and takes the apporprate action. This includes: - When a server crashes. -- When a server calls `/world/proc/Reboot()`. +- When a server calls `/world/prod/Reboot()`. - When a new .dmb is deployed. - When DreamDaemon settings are changed via the API. - When it is time to make a heartbeat. From a447dd323dcf07b57c7b79b590ccefc7f485712d Mon Sep 17 00:00:00 2001 From: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Date: Sun, 10 Jan 2021 14:06:02 +0000 Subject: [PATCH 03/42] V2 --- src/Tgstation.Server.Host/Components/Events/EventType.cs | 8 +++++++- .../Components/Watchdog/BasicWatchdog.cs | 4 ++++ .../Components/Watchdog/WatchdogBase.cs | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Events/EventType.cs b/src/Tgstation.Server.Host/Components/Events/EventType.cs index 9085c6e215..4e20113171 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventType.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventType.cs @@ -111,6 +111,12 @@ namespace Tgstation.Server.Host.Components.Events /// Before the watchdog launches. No parameters. /// [EventScript("WatchdogLaunch")] - WatchdogLaunch + WatchdogLaunch, + + /// + /// Inbetween DD restarts if the process has been force-ended by the DMAPI (TgsEndProcess()) + /// + [EventScript("WorldEndProcess")] + WorldEndProcess, } } diff --git a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs index c364a8cf65..4a83eab388 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Logging; using System; using System.Globalization; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Tgstation.Server.Api.Models.Internal; @@ -91,6 +92,9 @@ namespace Tgstation.Server.Host.Components.Watchdog switch (reason) { case MonitorActivationReason.ActiveServerCrashed: + if (Server.TerminationWasRequested) + await eventConsumer.HandleEvent(EventType.WorldEndProcess, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); + string exitWord = Server.TerminationWasRequested ? "exited" : "crashed"; if (Server.RebootState == Session.RebootState.Shutdown) { diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs index 5a24b01076..e1c8336752 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs @@ -121,7 +121,7 @@ namespace Tgstation.Server.Host.Components.Watchdog /// /// The that is not the /// - readonly IEventConsumer eventConsumer; + public IEventConsumer eventConsumer; /// /// The for the . From f678d6c0d6476591f076f2ce9b17b9386423e341 Mon Sep 17 00:00:00 2001 From: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Date: Sun, 10 Jan 2021 18:52:15 +0000 Subject: [PATCH 04/42] Cybertweaks --- build/Version.props | 2 +- src/DMAPI/tgs.dm | 4 +++- .../Components/Events/EventType.cs | 2 +- .../Components/Watchdog/BasicWatchdog.cs | 2 +- .../Components/Watchdog/WatchdogBase.cs | 18 +++++++-------- .../PublishProfiles/FolderProfile.pubxml | 22 +++++++++++++++++++ 6 files changed, 37 insertions(+), 13 deletions(-) create mode 100644 src/Tgstation.Server.Host/Properties/PublishProfiles/FolderProfile.pubxml diff --git a/build/Version.props b/build/Version.props index 44647f7611..7214e884f4 100644 --- a/build/Version.props +++ b/build/Version.props @@ -7,7 +7,7 @@ 2.2.0 8.2.0 9.1.1 - 5.2.10 + 5.2.11 1.1.0 1.2.0 diff --git a/src/DMAPI/tgs.dm b/src/DMAPI/tgs.dm index 3225f14d8c..e1eac9f291 100644 --- a/src/DMAPI/tgs.dm +++ b/src/DMAPI/tgs.dm @@ -1,6 +1,6 @@ // tgstation-server DMAPI -#define TGS_DMAPI_VERSION "5.2.10" +#define TGS_DMAPI_VERSION "5.2.11" // All functions and datums outside this document are subject to change with any version and should not be relied on. @@ -97,6 +97,8 @@ #define TGS_EVENT_WATCHDOG_DETACH 16 // We don't actually implement this value as the DMAPI can never receive it // #define TGS_EVENT_WATCHDOG_LAUNCH 17 +// Same here. We don't actually implement this value as the DMAPI can never receive it +// #define TGS_EVENT_WORLD_END_PROCESS 18 // OTHER ENUMS diff --git a/src/Tgstation.Server.Host/Components/Events/EventType.cs b/src/Tgstation.Server.Host/Components/Events/EventType.cs index 4e20113171..f22c1db8e0 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventType.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventType.cs @@ -114,7 +114,7 @@ namespace Tgstation.Server.Host.Components.Events WatchdogLaunch, /// - /// Inbetween DD restarts if the process has been force-ended by the DMAPI (TgsEndProcess()) + /// In between DD restarts if the process has been force-ended by the DMAPI (TgsEndProcess()) /// [EventScript("WorldEndProcess")] WorldEndProcess, diff --git a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs index 4a83eab388..433680a941 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs @@ -93,7 +93,7 @@ namespace Tgstation.Server.Host.Components.Watchdog { case MonitorActivationReason.ActiveServerCrashed: if (Server.TerminationWasRequested) - await eventConsumer.HandleEvent(EventType.WorldEndProcess, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); + await EventConsumer.HandleEvent(EventType.WorldEndProcess, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); string exitWord = Server.TerminationWasRequested ? "exited" : "crashed"; if (Server.RebootState == Session.RebootState.Shutdown) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs index e1c8336752..f6a7ed6160 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs @@ -83,6 +83,11 @@ namespace Tgstation.Server.Host.Components.Watchdog /// protected IAsyncDelayer AsyncDelayer { get; } + /// + /// The that is not the + /// + protected IEventConsumer EventConsumer { get; } + /// /// The for the . /// @@ -118,11 +123,6 @@ namespace Tgstation.Server.Host.Components.Watchdog /// readonly IIOManager diagnosticsIOManager; - /// - /// The that is not the - /// - public IEventConsumer eventConsumer; - /// /// The for the . /// @@ -179,7 +179,7 @@ namespace Tgstation.Server.Host.Components.Watchdog /// The to populate with /// The value of . /// The value of . - /// The value of . + /// The value of . /// The value of . /// The value of /// The initial value of . May be modified @@ -208,7 +208,7 @@ namespace Tgstation.Server.Host.Components.Watchdog this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager)); AsyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.diagnosticsIOManager = diagnosticsIOManager ?? throw new ArgumentNullException(nameof(diagnosticsIOManager)); - this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer)); + EventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer)); this.remoteDeploymentManagerFactory = remoteDeploymentManagerFactory ?? throw new ArgumentNullException(nameof(remoteDeploymentManagerFactory)); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); ActiveLaunchParameters = initialLaunchParameters ?? throw new ArgumentNullException(nameof(initialLaunchParameters)); @@ -267,7 +267,7 @@ namespace Tgstation.Server.Host.Components.Watchdog return; if (!graceful) { - var eventTask = eventConsumer.HandleEvent(releaseServers ? EventType.WatchdogDetach : EventType.WatchdogShutdown, null, cancellationToken); + var eventTask = EventConsumer.HandleEvent(releaseServers ? EventType.WatchdogDetach : EventType.WatchdogShutdown, null, cancellationToken); var chatTask = announce ? Chat.QueueWatchdogMessage("Shutting down...", cancellationToken) : Task.CompletedTask; @@ -378,7 +378,7 @@ namespace Tgstation.Server.Host.Components.Watchdog cancellationToken); // simple announce if (reattachInfo == null) announceTask = Task.WhenAll( - eventConsumer.HandleEvent(EventType.WatchdogLaunch, Enumerable.Empty(), cancellationToken), + EventConsumer.HandleEvent(EventType.WatchdogLaunch, Enumerable.Empty(), cancellationToken), announceTask); } else diff --git a/src/Tgstation.Server.Host/Properties/PublishProfiles/FolderProfile.pubxml b/src/Tgstation.Server.Host/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000000..a23e825bed --- /dev/null +++ b/src/Tgstation.Server.Host/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,22 @@ + + + + + FileSystem + FileSystem + Release + Any CPU + + True + False + netcoreapp3.1 + linux-x64 + 2b69ad6d-2b5a-4023-8ead-0bd1b18e028a + false + bin\Release\netcoreapp3.1\publish\ + False + + \ No newline at end of file From 95906f3bbbbb28a87ed1a345f52e3d5b41ee62dd Mon Sep 17 00:00:00 2001 From: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Date: Sun, 10 Jan 2021 19:25:14 +0000 Subject: [PATCH 05/42] VS Why --- .../PublishProfiles/FolderProfile.pubxml | 22 ------------------- 1 file changed, 22 deletions(-) delete mode 100644 src/Tgstation.Server.Host/Properties/PublishProfiles/FolderProfile.pubxml diff --git a/src/Tgstation.Server.Host/Properties/PublishProfiles/FolderProfile.pubxml b/src/Tgstation.Server.Host/Properties/PublishProfiles/FolderProfile.pubxml deleted file mode 100644 index a23e825bed..0000000000 --- a/src/Tgstation.Server.Host/Properties/PublishProfiles/FolderProfile.pubxml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - FileSystem - FileSystem - Release - Any CPU - - True - False - netcoreapp3.1 - linux-x64 - 2b69ad6d-2b5a-4023-8ead-0bd1b18e028a - false - bin\Release\netcoreapp3.1\publish\ - False - - \ No newline at end of file From 9ef486c083b0b46b0579e3416be94b52f2165d5a Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Sun, 10 Jan 2021 15:06:31 -0500 Subject: [PATCH 06/42] Release notes now credit authors --- tools/ReleaseNotes/Program.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/ReleaseNotes/Program.cs b/tools/ReleaseNotes/Program.cs index 65760f4b8d..7477895cdf 100644 --- a/tools/ReleaseNotes/Program.cs +++ b/tools/ReleaseNotes/Program.cs @@ -72,7 +72,7 @@ namespace ReleaseNotes Task milestoneTask = null; var milestoneTaskLock = new object(); - var releaseDictionary = new Dictionary>>(StringComparer.OrdinalIgnoreCase); + var releaseDictionary = new Dictionary>>(StringComparer.OrdinalIgnoreCase); var authorizedUsers = new Dictionary>(); bool postControlPanelMessage = false; @@ -136,7 +136,7 @@ namespace ReleaseNotes foreach (var I in notes) Console.WriteLine(component + " #" + fullPR.Number + " - " + I + " (@" + user.Login + ")"); - var tupleSelector = notes.Select(note => Tuple.Create(note, fullPR.Number)); + var tupleSelector = notes.Select(note => Tuple.Create(note, fullPR.Number, user.Login)); if (releaseDictionary.TryGetValue(component, out var currentValues)) currentValues.AddRange(tupleSelector); else @@ -169,6 +169,7 @@ namespace ReleaseNotes } if (trimmedLine.Length == 0) continue; + notes.Add(trimmedLine); } } @@ -325,6 +326,8 @@ namespace ReleaseNotes newNotes.Append(noteTuple.Item1); newNotes.Append(" (#"); newNotes.Append(noteTuple.Item2); + newNotes.Append(" @"); + newNotes.Append(noteTuple.Item3); newNotes.Append(')'); } From 2236a5614953879a507379e0872059963dd8735d Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Mon, 11 Jan 2021 21:50:05 -0500 Subject: [PATCH 07/42] Infinitely cache .js files served from /app --- .../Controllers/ControlPanelController.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs b/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs index 275acbe91a..28f68d21d7 100644 --- a/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs +++ b/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs @@ -1,6 +1,8 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.StaticFiles; +using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; using System; using System.Net.Mime; using Tgstation.Server.Host.Core; @@ -42,6 +44,10 @@ namespace Tgstation.Server.Host.Controllers var contentTypeProvider = new FileExtensionContentTypeProvider(); if (!contentTypeProvider.TryGetContentType(fileInfo.Name, out var contentType)) contentType = MediaTypeNames.Application.Octet; + else if (contentType == MediaTypeNames.Application.Json) + Response.Headers.Add( + HeaderNames.CacheControl, + new StringValues(new[] { "public", "max-age=31536000", "immutable" })); return File(appRoute, contentType); } From c3f66394631c89db4b6ab8437c2ebb5c8a55bd6b Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Tue, 12 Jan 2021 12:53:28 -0500 Subject: [PATCH 08/42] Adds Timestamp to RevisionInformation --- build/Version.props | 4 +- src/DMAPI/tgs.dm | 4 +- src/DMAPI/tgs/v5/_defines.dm | 1 + src/DMAPI/tgs/v5/api.dm | 2 + src/DMAPI/tgs/v5/undefs.dm | 1 + .../Models/Internal/RevisionInformation.cs | 10 +- .../Components/Deployment/DreamMaker.cs | 3 +- .../Components/Instance.cs | 1 + .../Interop/Bridge/RuntimeInformation.cs | 1 + .../Components/Repository/IRepository.cs | 8 + .../Components/Repository/Repository.cs | 13 + .../Controllers/RepositoryController.cs | 1 + .../Database/DatabaseContext.cs | 17 +- ...12154040_MSAddRevInfoTimestamp.Designer.cs | 902 ++++++++++++++++++ .../20210112154040_MSAddRevInfoTimestamp.cs | 35 + ...12154123_MYAddRevInfoTimestamp.Designer.cs | 886 +++++++++++++++++ .../20210112154123_MYAddRevInfoTimestamp.cs | 35 + ...12154203_PGAddRevInfoTimestamp.Designer.cs | 896 +++++++++++++++++ .../20210112154203_PGAddRevInfoTimestamp.cs | 35 + ...12154243_SLAddRevInfoTimestamp.Designer.cs | 885 +++++++++++++++++ .../20210112154243_SLAddRevInfoTimestamp.cs | 69 ++ .../MySqlDatabaseContextModelSnapshot.cs | 3 + ...PostgresSqlDatabaseContextModelSnapshot.cs | 3 + .../SqlServerDatabaseContextModelSnapshot.cs | 3 + .../SqliteDatabaseContextModelSnapshot.cs | 3 + .../Models/RevisionInformation.cs | 1 + .../Instance/RepositoryTest.cs | 1 + 27 files changed, 3812 insertions(+), 11 deletions(-) create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20210112154040_MSAddRevInfoTimestamp.Designer.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20210112154040_MSAddRevInfoTimestamp.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20210112154123_MYAddRevInfoTimestamp.Designer.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20210112154123_MYAddRevInfoTimestamp.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20210112154203_PGAddRevInfoTimestamp.Designer.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20210112154203_PGAddRevInfoTimestamp.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20210112154243_SLAddRevInfoTimestamp.Designer.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20210112154243_SLAddRevInfoTimestamp.cs diff --git a/build/Version.props b/build/Version.props index 2ff2ac18e2..8d1bf5b98a 100644 --- a/build/Version.props +++ b/build/Version.props @@ -5,9 +5,9 @@ 4.7.3 2.2.0 - 8.2.0 + 8.3.0 9.1.2 - 5.2.11 + 5.3.0 1.1.0 1.2.0 diff --git a/src/DMAPI/tgs.dm b/src/DMAPI/tgs.dm index e1eac9f291..fb6261a9bc 100644 --- a/src/DMAPI/tgs.dm +++ b/src/DMAPI/tgs.dm @@ -1,6 +1,6 @@ // tgstation-server DMAPI -#define TGS_DMAPI_VERSION "5.2.11" +#define TGS_DMAPI_VERSION "5.3.0" // All functions and datums outside this document are subject to change with any version and should not be relied on. @@ -154,6 +154,8 @@ /datum/tgs_revision_information /// Full SHA of the commit. var/commit + /// ISO8601 timestamp of the commit + var/timestamp /// Full sha of last known remote commit. This may be null if the TGS repository is not currently tracking a remote branch. var/origin_commit diff --git a/src/DMAPI/tgs/v5/_defines.dm b/src/DMAPI/tgs/v5/_defines.dm index 8fd84e19fa..10bc4cbe40 100644 --- a/src/DMAPI/tgs/v5/_defines.dm +++ b/src/DMAPI/tgs/v5/_defines.dm @@ -79,6 +79,7 @@ #define DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES "chatResponses" #define DMAPI5_REVISION_INFORMATION_COMMIT_SHA "commitSha" +#define DMAPI5_REVISION_INFORMATION_TIMESTAMP "timestamp" #define DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA "originCommitSha" #define DMAPI5_CHAT_USER_ID "id" diff --git a/src/DMAPI/tgs/v5/api.dm b/src/DMAPI/tgs/v5/api.dm index 7a2ff694e0..c5b5257fb5 100644 --- a/src/DMAPI/tgs/v5/api.dm +++ b/src/DMAPI/tgs/v5/api.dm @@ -48,6 +48,7 @@ if(istype(revisionData)) revision = new revision.commit = revisionData[DMAPI5_REVISION_INFORMATION_COMMIT_SHA] + revision.timestamp = revisionData[DMAPI5_REVISION_INFORMATION_TIMESTAMP] revision.origin_commit = revisionData[DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA] else TGS_ERROR_LOG("Failed to decode [DMAPI5_RUNTIME_INFORMATION_REVISION] from runtime information!") @@ -62,6 +63,7 @@ var/list/revInfo = entry[DMAPI5_TEST_MERGE_REVISION] if(revInfo) tm.commit = revisionData[DMAPI5_REVISION_INFORMATION_COMMIT_SHA] + tm.timestamp = revisionData[DMAPI5_REVISION_INFORMATION_TIMESTAMP] tm.origin_commit = revisionData[DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA] else TGS_WARNING_LOG("Failed to decode [DMAPI5_TEST_MERGE_REVISION] from test merge #[tm.number]!") diff --git a/src/DMAPI/tgs/v5/undefs.dm b/src/DMAPI/tgs/v5/undefs.dm index 34fc481d36..5885a60e75 100644 --- a/src/DMAPI/tgs/v5/undefs.dm +++ b/src/DMAPI/tgs/v5/undefs.dm @@ -79,6 +79,7 @@ #undef DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES #undef DMAPI5_REVISION_INFORMATION_COMMIT_SHA +#undef DMAPI5_REVISION_INFORMATION_TIMESTAMP #undef DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA #undef DMAPI5_CHAT_USER_ID diff --git a/src/Tgstation.Server.Api/Models/Internal/RevisionInformation.cs b/src/Tgstation.Server.Api/Models/Internal/RevisionInformation.cs index 6d45f3e42a..18acf71ae9 100644 --- a/src/Tgstation.Server.Api/Models/Internal/RevisionInformation.cs +++ b/src/Tgstation.Server.Api/Models/Internal/RevisionInformation.cs @@ -1,3 +1,4 @@ +using System; using System.ComponentModel.DataAnnotations; namespace Tgstation.Server.Api.Models.Internal @@ -8,14 +9,19 @@ namespace Tgstation.Server.Api.Models.Internal public class RevisionInformation { /// - /// The revision sha + /// The revision SHA. /// [Required] [StringLength(Limits.MaximumCommitShaLength)] public string? CommitSha { get; set; } /// - /// The sha of the most recent remote commit + /// The timestamp of the revision. + /// + public DateTimeOffset Timestamp { get; set; } + + /// + /// The SHA of the most recent remote commit. /// [Required] [StringLength(Limits.MaximumCommitShaLength)] diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index 7b2d5f1b07..04b80d802c 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -525,10 +525,8 @@ namespace Tgstation.Server.Host.Components.Deployment Action progressReporter, CancellationToken cancellationToken) { -#pragma warning disable IDE0016 // Use 'throw' expression if (job == null) throw new ArgumentNullException(nameof(job)); -#pragma warning restore IDE0016 // Use 'throw' expression if (databaseContextFactory == null) throw new ArgumentNullException(nameof(databaseContextFactory)); if (progressReporter == null) @@ -625,6 +623,7 @@ namespace Tgstation.Server.Host.Components.Deployment revInfo = new Models.RevisionInformation { CommitSha = repoSha, + Timestamp = await repo.TimestampCommit(repoSha, cancellationToken).ConfigureAwait(false), OriginCommitSha = repoSha, Instance = new Models.Instance { diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index 3c4b3f437f..1bbc2d6975 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -248,6 +248,7 @@ namespace Tgstation.Server.Host.Components currentRevInfo = new RevisionInformation { CommitSha = currentHead, + Timestamp = await repo.TimestampCommit(currentHead, cancellationToken).ConfigureAwait(false), OriginCommitSha = onOrigin ? currentHead : await repo.GetOriginSha(cancellationToken).ConfigureAwait(false), diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/RuntimeInformation.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/RuntimeInformation.cs index 77fb040e37..a54398a512 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/RuntimeInformation.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/RuntimeInformation.cs @@ -76,6 +76,7 @@ namespace Tgstation.Server.Host.Components.Interop.Bridge Revision = new Api.Models.Internal.RevisionInformation { CommitSha = dmbProvider.CompileJob.RevisionInformation.CommitSha, + Timestamp = dmbProvider.CompileJob.RevisionInformation.Timestamp, OriginCommitSha = dmbProvider.CompileJob.RevisionInformation.OriginCommitSha }; diff --git a/src/Tgstation.Server.Host/Components/Repository/IRepository.cs b/src/Tgstation.Server.Host/Components/Repository/IRepository.cs index e2caa16611..e1c0bd0af1 100644 --- a/src/Tgstation.Server.Host/Components/Repository/IRepository.cs +++ b/src/Tgstation.Server.Host/Components/Repository/IRepository.cs @@ -133,5 +133,13 @@ namespace Tgstation.Server.Host.Components.Repository /// The for the operation. /// A resulting in the tracked origin reference's SHA. Task GetOriginSha(CancellationToken cancellationToken); + + /// + /// Gets the a given was created on. + /// + /// The SHA to timestamp. + /// The for the operation. + /// A resulting in the that was created on. + Task TimestampCommit(string sha, CancellationToken cancellationToken); } } diff --git a/src/Tgstation.Server.Host/Components/Repository/Repository.cs b/src/Tgstation.Server.Host/Components/Repository/Repository.cs index 3ab698c381..89c958eb70 100644 --- a/src/Tgstation.Server.Host/Components/Repository/Repository.cs +++ b/src/Tgstation.Server.Host/Components/Repository/Repository.cs @@ -777,5 +777,18 @@ namespace Tgstation.Server.Host.Components.Repository parameters, repositorySettings, cancellationToken); + + /// + public Task TimestampCommit(string sha, CancellationToken cancellationToken) => Task.Factory.StartNew(() => + { + if (sha == null) + throw new ArgumentNullException(nameof(sha)); + + var commit = libGitRepo.Lookup(sha); + if (commit == null) + throw new JobException($"Commit {sha} does not exist in the repository!"); + + return commit.Committer.When; + }, cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current); } } diff --git a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs index c76b40682b..1114813a45 100644 --- a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs +++ b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs @@ -91,6 +91,7 @@ namespace Tgstation.Server.Host.Controllers { Instance = instance, CommitSha = repoSha, + Timestamp = await repository.TimestampCommit(repoSha, cancellationToken).ConfigureAwait(false), CompileJobs = new List(), ActiveTestMerges = new List() // non null vals for api returns }; diff --git a/src/Tgstation.Server.Host/Database/DatabaseContext.cs b/src/Tgstation.Server.Host/Database/DatabaseContext.cs index 9de0ffa3f2..7992a475cc 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseContext.cs @@ -377,22 +377,22 @@ namespace Tgstation.Server.Host.Database /// /// Used by unit tests to remind us to setup the correct MSSQL migration downgrades. /// - internal static readonly Type MSLatestMigration = typeof(MSAddSwarmIdentifer); + internal static readonly Type MSLatestMigration = typeof(MSAddRevInfoTimestamp); /// /// Used by unit tests to remind us to setup the correct MYSQL migration downgrades. /// - internal static readonly Type MYLatestMigration = typeof(MYAddSwarmIdentifer); + internal static readonly Type MYLatestMigration = typeof(MYAddRevInfoTimestamp); /// /// Used by unit tests to remind us to setup the correct PostgresSQL migration downgrades. /// - internal static readonly Type PGLatestMigration = typeof(PGAddSwarmIdentifer); + internal static readonly Type PGLatestMigration = typeof(PGAddRevInfoTimestamp); /// /// Used by unit tests to remind us to setup the correct SQLite migration downgrades. /// - internal static readonly Type SLLatestMigration = typeof(SLAddSwarmIdentifer); + internal static readonly Type SLLatestMigration = typeof(SLAddRevInfoTimestamp); /// #pragma warning disable CA1502 // Cyclomatic complexity @@ -420,6 +420,15 @@ namespace Tgstation.Server.Host.Database // Update this with new migrations as they are made string targetMigration = null; + if (targetVersion < new Version(4, 8, 0)) + targetMigration = currentDatabaseType switch + { + DatabaseType.MySql => nameof(MYAddSwarmIdentifer), + DatabaseType.PostgresSql => nameof(PGAddSwarmIdentifer), + DatabaseType.SqlServer => nameof(MSAddSwarmIdentifer), + DatabaseType.Sqlite => nameof(SLAddSwarmIdentifer), + _ => throw new ArgumentException($"Invalid DatabaseType: {currentDatabaseType}", nameof(currentDatabaseType)), + }; if (targetVersion < new Version(4, 7, 0)) targetMigration = currentDatabaseType switch { diff --git a/src/Tgstation.Server.Host/Database/Migrations/20210112154040_MSAddRevInfoTimestamp.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20210112154040_MSAddRevInfoTimestamp.Designer.cs new file mode 100644 index 0000000000..3691118827 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20210112154040_MSAddRevInfoTimestamp.Designer.cs @@ -0,0 +1,902 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tgstation.Server.Host.Database.Migrations +{ + [DbContext(typeof(SqlServerDatabaseContext))] + [Migration("20210112154040_MSAddRevInfoTimestamp")] + partial class MSAddRevInfoTimestamp + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.10") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ChannelLimit") + .HasColumnType("int"); + + b.Property("ConnectionString") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(10000); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(100)") + .HasMaxLength(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") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ChatSettingsId") + .HasColumnType("bigint"); + + b.Property("DiscordChannelId") + .HasColumnType("decimal(20,0)"); + + b.Property("IrcChannel") + .HasColumnType("nvarchar(100)") + .HasMaxLength(100); + + b.Property("IsAdminChannel") + .IsRequired() + .HasColumnType("bit"); + + b.Property("IsUpdatesChannel") + .IsRequired() + .HasColumnType("bit"); + + b.Property("IsWatchdogChannel") + .IsRequired() + .HasColumnType("bit"); + + b.Property("Tag") + .HasColumnType("nvarchar(max)") + .HasMaxLength(10000); + + 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") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ByondVersion") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + 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("GitHubDeploymentId") + .HasColumnType("int"); + + b.Property("GitHubRepoId") + .HasColumnType("bigint"); + + b.Property("JobId") + .HasColumnType("bigint"); + + b.Property("MinimumSecurityLevel") + .HasColumnType("int"); + + b.Property("Output") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RepositoryOrigin") + .HasColumnType("nvarchar(max)"); + + 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") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("AdditionalParameters") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(10000); + + b.Property("AllowWebClient") + .IsRequired() + .HasColumnType("bit"); + + b.Property("AutoStart") + .IsRequired() + .HasColumnType("bit"); + + b.Property("HeartbeatSeconds") + .HasColumnType("bigint"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("Port") + .HasColumnType("int"); + + b.Property("SecurityLevel") + .HasColumnType("int"); + + b.Property("StartupTimeout") + .HasColumnType("bigint"); + + b.Property("TopicRequestTimeout") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamDaemonSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ApiValidationPort") + .HasColumnType("int"); + + b.Property("ApiValidationSecurityLevel") + .HasColumnType("int"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("ProjectName") + .HasColumnType("nvarchar(max)") + .HasMaxLength(10000); + + b.Property("RequireDMApiValidation") + .IsRequired() + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamMakerSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("AutoUpdateInterval") + .HasColumnType("bigint"); + + b.Property("ChatBotLimit") + .HasColumnType("int"); + + b.Property("ConfigurationType") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(10000); + + b.Property("Online") + .IsRequired() + .HasColumnType("bit"); + + b.Property("Path") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SwarmIdentifer") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Path", "SwarmIdentifer") + .IsUnique() + .HasFilter("[SwarmIdentifer] IS NOT NULL"); + + b.ToTable("Instances"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ByondRights") + .HasColumnType("decimal(20,0)"); + + b.Property("ChatBotRights") + .HasColumnType("decimal(20,0)"); + + b.Property("ConfigurationRights") + .HasColumnType("decimal(20,0)"); + + b.Property("DreamDaemonRights") + .HasColumnType("decimal(20,0)"); + + b.Property("DreamMakerRights") + .HasColumnType("decimal(20,0)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("InstancePermissionSetRights") + .HasColumnType("decimal(20,0)"); + + b.Property("PermissionSetId") + .HasColumnType("bigint"); + + b.Property("RepositoryRights") + .HasColumnType("decimal(20,0)"); + + 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") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("CancelRight") + .HasColumnType("decimal(20,0)"); + + b.Property("CancelRightsType") + .HasColumnType("decimal(20,0)"); + + b.Property("Cancelled") + .IsRequired() + .HasColumnType("bit"); + + b.Property("CancelledById") + .HasColumnType("bigint"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ErrorCode") + .HasColumnType("bigint"); + + b.Property("ExceptionDetails") + .HasColumnType("nvarchar(max)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("StartedAt") + .IsRequired() + .HasColumnType("datetimeoffset"); + + b.Property("StartedById") + .HasColumnType("bigint"); + + b.Property("StoppedAt") + .HasColumnType("datetimeoffset"); + + 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") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ExternalUserId") + .IsRequired() + .HasColumnType("nvarchar(100)") + .HasMaxLength(100); + + 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") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("AdministrationRights") + .HasColumnType("decimal(20,0)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("InstanceManagerRights") + .HasColumnType("decimal(20,0)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("GroupId") + .IsUnique() + .HasFilter("[GroupId] IS NOT NULL"); + + b.HasIndex("UserId") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("PermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("AccessIdentifier") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CompileJobId") + .HasColumnType("bigint"); + + b.Property("LaunchSecurityLevel") + .HasColumnType("int"); + + b.Property("Port") + .HasColumnType("int"); + + b.Property("ProcessId") + .HasColumnType("int"); + + b.Property("RebootState") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CompileJobId"); + + b.ToTable("ReattachInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("AccessToken") + .HasColumnType("nvarchar(max)") + .HasMaxLength(10000); + + b.Property("AccessUser") + .HasColumnType("nvarchar(max)") + .HasMaxLength(10000); + + b.Property("AutoUpdatesKeepTestMerges") + .IsRequired() + .HasColumnType("bit"); + + b.Property("AutoUpdatesSynchronize") + .IsRequired() + .HasColumnType("bit"); + + b.Property("CommitterEmail") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(10000); + + b.Property("CommitterName") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(10000); + + b.Property("CreateGitHubDeployments") + .IsRequired() + .HasColumnType("bit"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("PostTestMergeComment") + .IsRequired() + .HasColumnType("bit"); + + b.Property("PushTestMergeCommits") + .IsRequired() + .HasColumnType("bit"); + + b.Property("ShowTestMergeCommitters") + .IsRequired() + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("RepositorySettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + 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") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("CommitSha") + .IsRequired() + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("OriginCommitSha") + .IsRequired() + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("Timestamp") + .HasColumnType("datetimeoffset"); + + 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") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Author") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("BodyAtMerge") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Comment") + .HasColumnType("nvarchar(max)") + .HasMaxLength(10000); + + b.Property("MergedAt") + .HasColumnType("datetimeoffset"); + + b.Property("MergedById") + .HasColumnType("bigint"); + + b.Property("Number") + .HasColumnType("int"); + + b.Property("PrimaryRevisionInformationId") + .IsRequired() + .HasColumnType("bigint"); + + b.Property("TargetCommitSha") + .IsRequired() + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("TitleAtMerge") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Url") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + 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") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("CanonicalName") + .IsRequired() + .HasColumnType("nvarchar(100)") + .HasMaxLength(100); + + b.Property("CreatedAt") + .IsRequired() + .HasColumnType("datetimeoffset"); + + b.Property("CreatedById") + .HasColumnType("bigint"); + + b.Property("Enabled") + .IsRequired() + .HasColumnType("bit"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastPasswordUpdate") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(100)") + .HasMaxLength(100); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("SystemIdentifier") + .HasColumnType("nvarchar(100)") + .HasMaxLength(100); + + b.HasKey("Id"); + + b.HasIndex("CanonicalName") + .IsUnique(); + + b.HasIndex("CreatedById"); + + b.HasIndex("GroupId"); + + b.HasIndex("SystemIdentifier") + .IsUnique() + .HasFilter("[SystemIdentifier] IS NOT NULL"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(100)") + .HasMaxLength(100); + + 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(); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings") + .WithMany("Channels") + .HasForeignKey("ChatSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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.ClientNoAction) + .IsRequired(); + }); + + 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(); + }); + + 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(); + }); + + 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(); + }); + + 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(); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithMany("OAuthConnections") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + 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); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob") + .WithMany() + .HasForeignKey("CompileJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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(); + }); + + 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(); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("RevisionInformations") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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(); + }); + + 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"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20210112154040_MSAddRevInfoTimestamp.cs b/src/Tgstation.Server.Host/Database/Migrations/20210112154040_MSAddRevInfoTimestamp.cs new file mode 100644 index 0000000000..73f94d358b --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20210112154040_MSAddRevInfoTimestamp.cs @@ -0,0 +1,35 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tgstation.Server.Host.Database.Migrations +{ + /// + /// Add the Timestamp column to RevisionInformations for MSSQL. + /// + public partial class MSAddRevInfoTimestamp : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + if (migrationBuilder == null) + throw new ArgumentNullException(nameof(migrationBuilder)); + + migrationBuilder.AddColumn( + name: "Timestamp", + table: "RevisionInformations", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + if (migrationBuilder == null) + throw new ArgumentNullException(nameof(migrationBuilder)); + + migrationBuilder.DropColumn( + name: "Timestamp", + table: "RevisionInformations"); + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20210112154123_MYAddRevInfoTimestamp.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20210112154123_MYAddRevInfoTimestamp.Designer.cs new file mode 100644 index 0000000000..35e54bb9e7 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20210112154123_MYAddRevInfoTimestamp.Designer.cs @@ -0,0 +1,886 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tgstation.Server.Host.Database.Migrations +{ + [DbContext(typeof(MySqlDatabaseContext))] + [Migration("20210112154123_MYAddRevInfoTimestamp")] + partial class MYAddRevInfoTimestamp + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.10") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("ChannelLimit") + .IsRequired() + .HasColumnType("smallint unsigned"); + + b.Property("ConnectionString") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(10000); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(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"); + + b.Property("ChatSettingsId") + .HasColumnType("bigint"); + + b.Property("DiscordChannelId") + .HasColumnType("bigint unsigned"); + + b.Property("IrcChannel") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("IsAdminChannel") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("IsUpdatesChannel") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("IsWatchdogChannel") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("Tag") + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(10000); + + 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"); + + b.Property("ByondVersion") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + 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 CHARACTER SET 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 CHARACTER SET utf8mb4"); + + b.Property("RepositoryOrigin") + .HasColumnType("longtext CHARACTER SET 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"); + + b.Property("AdditionalParameters") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(10000); + + b.Property("AllowWebClient") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("AutoStart") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("HeartbeatSeconds") + .IsRequired() + .HasColumnType("int unsigned"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("Port") + .IsRequired() + .HasColumnType("smallint unsigned"); + + b.Property("SecurityLevel") + .HasColumnType("int"); + + b.Property("StartupTimeout") + .IsRequired() + .HasColumnType("int unsigned"); + + b.Property("TopicRequestTimeout") + .IsRequired() + .HasColumnType("int unsigned"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamDaemonSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("ApiValidationPort") + .IsRequired() + .HasColumnType("smallint unsigned"); + + b.Property("ApiValidationSecurityLevel") + .HasColumnType("int"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("ProjectName") + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(10000); + + b.Property("RequireDMApiValidation") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamMakerSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AutoUpdateInterval") + .IsRequired() + .HasColumnType("int unsigned"); + + b.Property("ChatBotLimit") + .IsRequired() + .HasColumnType("smallint unsigned"); + + b.Property("ConfigurationType") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(10000); + + b.Property("Online") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("Path") + .IsRequired() + .HasColumnType("varchar(255) CHARACTER SET utf8mb4"); + + b.Property("SwarmIdentifer") + .HasColumnType("varchar(255) CHARACTER SET 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"); + + b.Property("ByondRights") + .HasColumnType("bigint unsigned"); + + 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("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"); + + 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 CHARACTER SET utf8mb4"); + + b.Property("ErrorCode") + .HasColumnType("int unsigned"); + + b.Property("ExceptionDetails") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + 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"); + + b.Property("ExternalUserId") + .IsRequired() + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + 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"); + + 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"); + + b.Property("AccessIdentifier") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CompileJobId") + .HasColumnType("bigint"); + + b.Property("LaunchSecurityLevel") + .HasColumnType("int"); + + b.Property("Port") + .HasColumnType("smallint unsigned"); + + b.Property("ProcessId") + .HasColumnType("int"); + + b.Property("RebootState") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CompileJobId"); + + b.ToTable("ReattachInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AccessToken") + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(10000); + + b.Property("AccessUser") + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(10000); + + b.Property("AutoUpdatesKeepTestMerges") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("AutoUpdatesSynchronize") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("CommitterEmail") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(10000); + + b.Property("CommitterName") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(10000); + + 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.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("RepositorySettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + 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"); + + b.Property("CommitSha") + .IsRequired() + .HasColumnType("varchar(40) CHARACTER SET utf8mb4") + .HasMaxLength(40); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("OriginCommitSha") + .IsRequired() + .HasColumnType("varchar(40) CHARACTER SET utf8mb4") + .HasMaxLength(40); + + 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"); + + b.Property("Author") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("BodyAtMerge") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("Comment") + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(10000); + + 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() + .HasColumnType("varchar(40) CHARACTER SET utf8mb4") + .HasMaxLength(40); + + b.Property("TitleAtMerge") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("Url") + .IsRequired() + .HasColumnType("longtext CHARACTER SET 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"); + + b.Property("CanonicalName") + .IsRequired() + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + 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() + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("PasswordHash") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("SystemIdentifier") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + 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"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + 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(); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings") + .WithMany("Channels") + .HasForeignKey("ChatSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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(); + }); + + 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(); + }); + + 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(); + }); + + 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(); + }); + + 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(); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithMany("OAuthConnections") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + 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); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob") + .WithMany() + .HasForeignKey("CompileJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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(); + }); + + 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(); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("RevisionInformations") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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(); + }); + + 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"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20210112154123_MYAddRevInfoTimestamp.cs b/src/Tgstation.Server.Host/Database/Migrations/20210112154123_MYAddRevInfoTimestamp.cs new file mode 100644 index 0000000000..3c7576ba70 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20210112154123_MYAddRevInfoTimestamp.cs @@ -0,0 +1,35 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tgstation.Server.Host.Database.Migrations +{ + /// + /// Add the Timestamp column to RevisionInformations for MYSQL. + /// + public partial class MYAddRevInfoTimestamp : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + if (migrationBuilder == null) + throw new ArgumentNullException(nameof(migrationBuilder)); + + migrationBuilder.AddColumn( + name: "Timestamp", + table: "RevisionInformations", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + if (migrationBuilder == null) + throw new ArgumentNullException(nameof(migrationBuilder)); + + migrationBuilder.DropColumn( + name: "Timestamp", + table: "RevisionInformations"); + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20210112154203_PGAddRevInfoTimestamp.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20210112154203_PGAddRevInfoTimestamp.Designer.cs new file mode 100644 index 0000000000..0cb1f21fa1 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20210112154203_PGAddRevInfoTimestamp.Designer.cs @@ -0,0 +1,896 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace Tgstation.Server.Host.Database.Migrations +{ + [DbContext(typeof(PostgresSqlDatabaseContext))] + [Migration("20210112154203_PGAddRevInfoTimestamp")] + partial class PGAddRevInfoTimestamp + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .HasAnnotation("ProductVersion", "3.1.10") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ChannelLimit") + .HasColumnType("integer"); + + b.Property("ConnectionString") + .IsRequired() + .HasColumnType("character varying(10000)") + .HasMaxLength(10000); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("character varying(100)") + .HasMaxLength(100); + + b.Property("Provider") + .HasColumnType("integer"); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ChatSettingsId") + .HasColumnType("bigint"); + + b.Property("DiscordChannelId") + .HasColumnType("numeric(20,0)"); + + b.Property("IrcChannel") + .HasColumnType("character varying(100)") + .HasMaxLength(100); + + b.Property("IsAdminChannel") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("IsUpdatesChannel") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("IsWatchdogChannel") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("Tag") + .HasColumnType("character varying(10000)") + .HasMaxLength(10000); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ByondVersion") + .IsRequired() + .HasColumnType("text"); + + b.Property("DMApiMajorVersion") + .HasColumnType("integer"); + + b.Property("DMApiMinorVersion") + .HasColumnType("integer"); + + b.Property("DMApiPatchVersion") + .HasColumnType("integer"); + + b.Property("DirectoryName") + .IsRequired() + .HasColumnType("uuid"); + + b.Property("DmeName") + .IsRequired() + .HasColumnType("text"); + + b.Property("GitHubDeploymentId") + .HasColumnType("integer"); + + b.Property("GitHubRepoId") + .HasColumnType("bigint"); + + b.Property("JobId") + .HasColumnType("bigint"); + + b.Property("MinimumSecurityLevel") + .HasColumnType("integer"); + + b.Property("Output") + .IsRequired() + .HasColumnType("text"); + + b.Property("RepositoryOrigin") + .HasColumnType("text"); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("AdditionalParameters") + .IsRequired() + .HasColumnType("character varying(10000)") + .HasMaxLength(10000); + + b.Property("AllowWebClient") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("AutoStart") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("HeartbeatSeconds") + .HasColumnType("bigint"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("Port") + .HasColumnType("integer"); + + b.Property("SecurityLevel") + .HasColumnType("integer"); + + b.Property("StartupTimeout") + .HasColumnType("bigint"); + + b.Property("TopicRequestTimeout") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamDaemonSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ApiValidationPort") + .HasColumnType("integer"); + + b.Property("ApiValidationSecurityLevel") + .HasColumnType("integer"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("ProjectName") + .HasColumnType("character varying(10000)") + .HasMaxLength(10000); + + b.Property("RequireDMApiValidation") + .IsRequired() + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamMakerSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("AutoUpdateInterval") + .HasColumnType("bigint"); + + b.Property("ChatBotLimit") + .HasColumnType("integer"); + + b.Property("ConfigurationType") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("character varying(10000)") + .HasMaxLength(10000); + + b.Property("Online") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text"); + + b.Property("SwarmIdentifer") + .HasColumnType("text"); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ByondRights") + .HasColumnType("numeric(20,0)"); + + b.Property("ChatBotRights") + .HasColumnType("numeric(20,0)"); + + b.Property("ConfigurationRights") + .HasColumnType("numeric(20,0)"); + + b.Property("DreamDaemonRights") + .HasColumnType("numeric(20,0)"); + + b.Property("DreamMakerRights") + .HasColumnType("numeric(20,0)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("InstancePermissionSetRights") + .HasColumnType("numeric(20,0)"); + + b.Property("PermissionSetId") + .HasColumnType("bigint"); + + b.Property("RepositoryRights") + .HasColumnType("numeric(20,0)"); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("CancelRight") + .HasColumnType("numeric(20,0)"); + + b.Property("CancelRightsType") + .HasColumnType("numeric(20,0)"); + + b.Property("Cancelled") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("CancelledById") + .HasColumnType("bigint"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("ErrorCode") + .HasColumnType("bigint"); + + b.Property("ExceptionDetails") + .HasColumnType("text"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("StartedAt") + .IsRequired() + .HasColumnType("timestamp with time zone"); + + b.Property("StartedById") + .HasColumnType("bigint"); + + b.Property("StoppedAt") + .HasColumnType("timestamp with time zone"); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ExternalUserId") + .IsRequired() + .HasColumnType("character varying(100)") + .HasMaxLength(100); + + b.Property("Provider") + .HasColumnType("integer"); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("AdministrationRights") + .HasColumnType("numeric(20,0)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("InstanceManagerRights") + .HasColumnType("numeric(20,0)"); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("AccessIdentifier") + .IsRequired() + .HasColumnType("text"); + + b.Property("CompileJobId") + .HasColumnType("bigint"); + + b.Property("LaunchSecurityLevel") + .HasColumnType("integer"); + + b.Property("Port") + .HasColumnType("integer"); + + b.Property("ProcessId") + .HasColumnType("integer"); + + b.Property("RebootState") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CompileJobId"); + + b.ToTable("ReattachInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("AccessToken") + .HasColumnType("character varying(10000)") + .HasMaxLength(10000); + + b.Property("AccessUser") + .HasColumnType("character varying(10000)") + .HasMaxLength(10000); + + b.Property("AutoUpdatesKeepTestMerges") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("AutoUpdatesSynchronize") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("CommitterEmail") + .IsRequired() + .HasColumnType("character varying(10000)") + .HasMaxLength(10000); + + b.Property("CommitterName") + .IsRequired() + .HasColumnType("character varying(10000)") + .HasMaxLength(10000); + + b.Property("CreateGitHubDeployments") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("PostTestMergeComment") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("PushTestMergeCommits") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("ShowTestMergeCommitters") + .IsRequired() + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("RepositorySettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("CommitSha") + .IsRequired() + .HasColumnType("character varying(40)") + .HasMaxLength(40); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("OriginCommitSha") + .IsRequired() + .HasColumnType("character varying(40)") + .HasMaxLength(40); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("Author") + .IsRequired() + .HasColumnType("text"); + + b.Property("BodyAtMerge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Comment") + .HasColumnType("character varying(10000)") + .HasMaxLength(10000); + + b.Property("MergedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("MergedById") + .HasColumnType("bigint"); + + b.Property("Number") + .HasColumnType("integer"); + + b.Property("PrimaryRevisionInformationId") + .IsRequired() + .HasColumnType("bigint"); + + b.Property("TargetCommitSha") + .IsRequired() + .HasColumnType("character varying(40)") + .HasMaxLength(40); + + b.Property("TitleAtMerge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Url") + .IsRequired() + .HasColumnType("text"); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("CanonicalName") + .IsRequired() + .HasColumnType("character varying(100)") + .HasMaxLength(100); + + b.Property("CreatedAt") + .IsRequired() + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedById") + .HasColumnType("bigint"); + + b.Property("Enabled") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastPasswordUpdate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("character varying(100)") + .HasMaxLength(100); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("SystemIdentifier") + .HasColumnType("character varying(100)") + .HasMaxLength(100); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("Name") + .IsRequired() + .HasColumnType("character varying(100)") + .HasMaxLength(100); + + 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(); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings") + .WithMany("Channels") + .HasForeignKey("ChatSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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(); + }); + + 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(); + }); + + 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(); + }); + + 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(); + }); + + 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(); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithMany("OAuthConnections") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + 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); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob") + .WithMany() + .HasForeignKey("CompileJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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(); + }); + + 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(); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("RevisionInformations") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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(); + }); + + 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"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20210112154203_PGAddRevInfoTimestamp.cs b/src/Tgstation.Server.Host/Database/Migrations/20210112154203_PGAddRevInfoTimestamp.cs new file mode 100644 index 0000000000..0db9ccf53d --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20210112154203_PGAddRevInfoTimestamp.cs @@ -0,0 +1,35 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tgstation.Server.Host.Database.Migrations +{ + /// + /// Add the Timestamp column to RevisionInformations for PostgresSQL. + /// + public partial class PGAddRevInfoTimestamp : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + if (migrationBuilder == null) + throw new ArgumentNullException(nameof(migrationBuilder)); + + migrationBuilder.AddColumn( + name: "Timestamp", + table: "RevisionInformations", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + if (migrationBuilder == null) + throw new ArgumentNullException(nameof(migrationBuilder)); + + migrationBuilder.DropColumn( + name: "Timestamp", + table: "RevisionInformations"); + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20210112154243_SLAddRevInfoTimestamp.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20210112154243_SLAddRevInfoTimestamp.Designer.cs new file mode 100644 index 0000000000..61cbdf5fa9 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20210112154243_SLAddRevInfoTimestamp.Designer.cs @@ -0,0 +1,885 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tgstation.Server.Host.Database.Migrations +{ + [DbContext(typeof(SqliteDatabaseContext))] + [Migration("20210112154243_SLAddRevInfoTimestamp")] + partial class SLAddRevInfoTimestamp + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.10"); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelLimit") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ConnectionString") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(10000); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(100); + + b.Property("Provider") + .HasColumnType("INTEGER"); + + b.Property("ReconnectionInterval") + .IsRequired() + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId", "Name") + .IsUnique(); + + b.ToTable("ChatBots"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChatSettingsId") + .HasColumnType("INTEGER"); + + b.Property("DiscordChannelId") + .HasColumnType("INTEGER"); + + b.Property("IrcChannel") + .HasColumnType("TEXT") + .HasMaxLength(100); + + b.Property("IsAdminChannel") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("IsUpdatesChannel") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("IsWatchdogChannel") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Tag") + .HasColumnType("TEXT") + .HasMaxLength(10000); + + 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("INTEGER"); + + b.Property("ByondVersion") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DMApiMajorVersion") + .HasColumnType("INTEGER"); + + b.Property("DMApiMinorVersion") + .HasColumnType("INTEGER"); + + b.Property("DMApiPatchVersion") + .HasColumnType("INTEGER"); + + b.Property("DirectoryName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DmeName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("GitHubDeploymentId") + .HasColumnType("INTEGER"); + + b.Property("GitHubRepoId") + .HasColumnType("INTEGER"); + + b.Property("JobId") + .HasColumnType("INTEGER"); + + b.Property("MinimumSecurityLevel") + .HasColumnType("INTEGER"); + + b.Property("Output") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RepositoryOrigin") + .HasColumnType("TEXT"); + + b.Property("RevisionInformationId") + .HasColumnType("INTEGER"); + + 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("INTEGER"); + + b.Property("AdditionalParameters") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(10000); + + b.Property("AllowWebClient") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("AutoStart") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("HeartbeatSeconds") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("Port") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("SecurityLevel") + .HasColumnType("INTEGER"); + + b.Property("StartupTimeout") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("TopicRequestTimeout") + .IsRequired() + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamDaemonSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ApiValidationPort") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ApiValidationSecurityLevel") + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("ProjectName") + .HasColumnType("TEXT") + .HasMaxLength(10000); + + b.Property("RequireDMApiValidation") + .IsRequired() + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamMakerSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AutoUpdateInterval") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ChatBotLimit") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ConfigurationType") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(10000); + + b.Property("Online") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("SwarmIdentifer") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Path", "SwarmIdentifer") + .IsUnique(); + + b.ToTable("Instances"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ByondRights") + .HasColumnType("INTEGER"); + + b.Property("ChatBotRights") + .HasColumnType("INTEGER"); + + b.Property("ConfigurationRights") + .HasColumnType("INTEGER"); + + b.Property("DreamDaemonRights") + .HasColumnType("INTEGER"); + + b.Property("DreamMakerRights") + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("InstancePermissionSetRights") + .HasColumnType("INTEGER"); + + b.Property("PermissionSetId") + .HasColumnType("INTEGER"); + + b.Property("RepositoryRights") + .HasColumnType("INTEGER"); + + 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("INTEGER"); + + b.Property("CancelRight") + .HasColumnType("INTEGER"); + + b.Property("CancelRightsType") + .HasColumnType("INTEGER"); + + b.Property("Cancelled") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("CancelledById") + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ErrorCode") + .HasColumnType("INTEGER"); + + b.Property("ExceptionDetails") + .HasColumnType("TEXT"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("StartedAt") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StartedById") + .HasColumnType("INTEGER"); + + b.Property("StoppedAt") + .HasColumnType("TEXT"); + + 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("INTEGER"); + + b.Property("ExternalUserId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(100); + + b.Property("Provider") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + 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("INTEGER"); + + b.Property("AdministrationRights") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.Property("InstanceManagerRights") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + 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("INTEGER"); + + b.Property("AccessIdentifier") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CompileJobId") + .HasColumnType("INTEGER"); + + b.Property("LaunchSecurityLevel") + .HasColumnType("INTEGER"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.Property("ProcessId") + .HasColumnType("INTEGER"); + + b.Property("RebootState") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("CompileJobId"); + + b.ToTable("ReattachInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .HasColumnType("TEXT") + .HasMaxLength(10000); + + b.Property("AccessUser") + .HasColumnType("TEXT") + .HasMaxLength(10000); + + b.Property("AutoUpdatesKeepTestMerges") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("AutoUpdatesSynchronize") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("CommitterEmail") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(10000); + + b.Property("CommitterName") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(10000); + + b.Property("CreateGitHubDeployments") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("PostTestMergeComment") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("PushTestMergeCommits") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ShowTestMergeCommitters") + .IsRequired() + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("RepositorySettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("RevisionInformationId") + .HasColumnType("INTEGER"); + + b.Property("TestMergeId") + .HasColumnType("INTEGER"); + + 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("INTEGER"); + + b.Property("CommitSha") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(40); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("OriginCommitSha") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(40); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId", "CommitSha") + .IsUnique(); + + b.ToTable("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Author") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("BodyAtMerge") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasColumnType("TEXT") + .HasMaxLength(10000); + + b.Property("MergedAt") + .HasColumnType("TEXT"); + + b.Property("MergedById") + .HasColumnType("INTEGER"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("PrimaryRevisionInformationId") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("TargetCommitSha") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(40); + + b.Property("TitleAtMerge") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Url") + .IsRequired() + .HasColumnType("TEXT"); + + 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("INTEGER"); + + b.Property("CanonicalName") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(100); + + b.Property("CreatedAt") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("Enabled") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.Property("LastPasswordUpdate") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(100); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("SystemIdentifier") + .HasColumnType("TEXT") + .HasMaxLength(100); + + 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("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(100); + + 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(); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings") + .WithMany("Channels") + .HasForeignKey("ChatSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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.ClientNoAction) + .IsRequired(); + }); + + 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(); + }); + + 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(); + }); + + 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(); + }); + + 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(); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithMany("OAuthConnections") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + 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); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob") + .WithMany() + .HasForeignKey("CompileJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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(); + }); + + 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(); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("RevisionInformations") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + 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(); + }); + + 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"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20210112154243_SLAddRevInfoTimestamp.cs b/src/Tgstation.Server.Host/Database/Migrations/20210112154243_SLAddRevInfoTimestamp.cs new file mode 100644 index 0000000000..c351857d88 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20210112154243_SLAddRevInfoTimestamp.cs @@ -0,0 +1,69 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tgstation.Server.Host.Database.Migrations +{ + /// + /// Add the Timestamp column to RevisionInformations for SQLite. + /// + public partial class SLAddRevInfoTimestamp : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + if (migrationBuilder == null) + throw new ArgumentNullException(nameof(migrationBuilder)); + + migrationBuilder.AddColumn( + name: "Timestamp", + table: "RevisionInformations", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + if (migrationBuilder == null) + throw new ArgumentNullException(nameof(migrationBuilder)); + + migrationBuilder.RenameTable( + name: "RevisionInformations", + newName: "RevisionInformations_down"); + + migrationBuilder.CreateTable( + name: "RevisionInformations", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + CommitSha = table.Column(maxLength: 40, nullable: false), + OriginCommitSha = table.Column(maxLength: 40, nullable: false), + InstanceId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_RevisionInformations", x => x.Id); + table.ForeignKey( + name: "FK_RevisionInformations_Instances_InstanceId", + column: x => x.InstanceId, + principalTable: "Instances", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.Sql("INSERT INTO RevisionInformations (Id, CommitSha, OriginCommitSha, InstanceId) SELECT Id, CommitSha, OriginCommitSha, InstanceId FROM RevisionInformations_down"); + + migrationBuilder.DropTable( + name: "RevisionInformations_down"); + + migrationBuilder.RenameTable( + name: "RevisionInformations", + newName: "RevisionInformations_down"); + + migrationBuilder.RenameTable( + name: "RevisionInformations_down", + newName: "RevisionInformations"); + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs index 8707171228..f01161f68e 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs @@ -566,6 +566,9 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("varchar(40) CHARACTER SET utf8mb4") .HasMaxLength(40); + b.Property("Timestamp") + .HasColumnType("datetime(6)"); + b.HasKey("Id"); b.HasIndex("InstanceId", "CommitSha") diff --git a/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs index a4d189000e..4668521f4a 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs @@ -573,6 +573,9 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("character varying(40)") .HasMaxLength(40); + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + b.HasKey("Id"); b.HasIndex("InstanceId", "CommitSha") diff --git a/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs index 5f77127198..608266d424 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs @@ -578,6 +578,9 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("nvarchar(40)") .HasMaxLength(40); + b.Property("Timestamp") + .HasColumnType("datetimeoffset"); + b.HasKey("Id"); b.HasIndex("InstanceId", "CommitSha") diff --git a/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs index ca51e0514a..b12e593740 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs @@ -565,6 +565,9 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("TEXT") .HasMaxLength(40); + b.Property("Timestamp") + .HasColumnType("TEXT"); + b.HasKey("Id"); b.HasIndex("InstanceId", "CommitSha") diff --git a/src/Tgstation.Server.Host/Models/RevisionInformation.cs b/src/Tgstation.Server.Host/Models/RevisionInformation.cs index 3b99e8c26e..feeced9571 100644 --- a/src/Tgstation.Server.Host/Models/RevisionInformation.cs +++ b/src/Tgstation.Server.Host/Models/RevisionInformation.cs @@ -42,6 +42,7 @@ namespace Tgstation.Server.Host.Models public Api.Models.RevisionInformation ToApi() => new Api.Models.RevisionInformation { CommitSha = CommitSha, + Timestamp = Timestamp, OriginCommitSha = OriginCommitSha, PrimaryTestMerge = PrimaryTestMerge?.ToApi(), ActiveTestMerges = ActiveTestMerges.Select(x => x.TestMerge.ToApi()).ToList(), diff --git a/tests/Tgstation.Server.Tests/Instance/RepositoryTest.cs b/tests/Tgstation.Server.Tests/Instance/RepositoryTest.cs index 36f2da7900..52918f5e76 100644 --- a/tests/Tgstation.Server.Tests/Instance/RepositoryTest.cs +++ b/tests/Tgstation.Server.Tests/Instance/RepositoryTest.cs @@ -79,6 +79,7 @@ namespace Tgstation.Server.Tests.Instance Assert.IsNotNull(readAfterClone.RevisionInformation.OriginCommitSha); Assert.IsNull(readAfterClone.RevisionInformation.PrimaryTestMerge); Assert.AreEqual(readAfterClone.RevisionInformation.CommitSha, readAfterClone.RevisionInformation.OriginCommitSha); + Assert.AreNotEqual(default, readAfterClone.RevisionInformation.Timestamp); readAfterClone.Origin = new Uri("https://github.com/tgstation/tgstation"); await ApiAssert.ThrowsException(() => repositoryClient.Update(readAfterClone, cancellationToken), ErrorCode.RepoCantChangeOrigin); From a6caed51e88d02581c9d89c91d08c48bed1d8ab5 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 14 Jan 2021 11:30:21 -0500 Subject: [PATCH 09/42] Re-add tgs.dm to .sln --- tgstation-server.sln | 1 + 1 file changed, 1 insertion(+) diff --git a/tgstation-server.sln b/tgstation-server.sln index 7e771b4b01..32dabe36ba 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -65,6 +65,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tgs", "tgs", "{F7765A4B-021 src\DMAPI\tgs\includes.dm = src\DMAPI\tgs\includes.dm src\DMAPI\tgs\LICENSE = src\DMAPI\tgs\LICENSE src\DMAPI\tgs\README.md = src\DMAPI\tgs\README.md + src\DMAPI\tgs.dm = src\DMAPI\tgs.dm EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "core", "core", "{DCCBA9DA-47BA-4C70-823B-E99A3ACA0377}" From e9e4439a861290eee2918bf5c03e6de5b85d3b18 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 14 Jan 2021 11:38:19 -0500 Subject: [PATCH 10/42] Adds a few event types - Improves watchdog monitoring logic so events that happen while one is already processing are no longer dropped. --- src/DMAPI/tgs.dm | 7 +-- .../Components/Events/EventType.cs | 14 ++++- .../Components/Session/ISessionController.cs | 4 +- .../Components/Watchdog/BasicWatchdog.cs | 8 ++- .../Watchdog/MonitorActivationReason.cs | 7 ++- .../Components/Watchdog/WatchdogBase.cs | 53 ++++++++++++++++--- 6 files changed, 78 insertions(+), 15 deletions(-) diff --git a/src/DMAPI/tgs.dm b/src/DMAPI/tgs.dm index fb6261a9bc..f54d519b9e 100644 --- a/src/DMAPI/tgs.dm +++ b/src/DMAPI/tgs.dm @@ -95,10 +95,12 @@ #define TGS_EVENT_WATCHDOG_SHUTDOWN 15 /// Before the watchdog detaches for a TGS update/restart. No parameters. #define TGS_EVENT_WATCHDOG_DETACH 16 -// We don't actually implement this value as the DMAPI can never receive it +// We don't actually implement these 3 events as the DMAPI can never receive them. // #define TGS_EVENT_WATCHDOG_LAUNCH 17 -// Same here. We don't actually implement this value as the DMAPI can never receive it // #define TGS_EVENT_WORLD_END_PROCESS 18 +// #define TGS_EVENT_WORLD_DEL 19 +/// Watchdog event when TgsInitializationComplete() is called. No parameters. + #define TGS_EVENT_WORLD_PRIME 20 // OTHER ENUMS @@ -132,7 +134,6 @@ * * This may use [/world/var/sleep_offline] to make this happen so ensure no changes are made to it while this call is running. * Afterwards, consider explicitly setting it to what you want to avoid this BYOND bug: http://www.byond.com/forum/post/2575184 - * Before this point, note that any static files or directories may be in use by another server. Your code should account for this. * This function should not be called before ..() in [/world/proc/New]. */ /world/proc/TgsInitializationComplete() diff --git a/src/Tgstation.Server.Host/Components/Events/EventType.cs b/src/Tgstation.Server.Host/Components/Events/EventType.cs index f22c1db8e0..d99ee079e2 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventType.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventType.cs @@ -114,9 +114,21 @@ namespace Tgstation.Server.Host.Components.Events WatchdogLaunch, /// - /// In between DD restarts if the process has been force-ended by the DMAPI (TgsEndProcess()) + /// In between watchdog DreamDaemon restarts if the process has been force-ended by the DMAPI (TgsEndProcess()). No parameters. /// [EventScript("WorldEndProcess")] WorldEndProcess, + + /// + /// After any sort of watchdog DreamDaemon closure or reboot. Reboots only supported with DMAPI. Not synchronous. Called after . No parameters. + /// + [EventScript("WorldDel")] + WorldDel, + + /// + /// Watchdog event when TgsInitializationComplete() is called. No parameters. + /// + [EventScript("WorldPrime")] + WorldPrime, } } diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs index 778c39ba38..9c7a43cb3a 100644 --- a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs @@ -49,12 +49,12 @@ namespace Tgstation.Server.Host.Components.Session RebootState RebootState { get; } /// - /// A that completes when the server calls /world/Reboot() + /// A that completes when the server calls /world/TgsReboot(). /// Task OnReboot { get; } /// - /// A that completes when the server calls /world/TgsInitializationsComplete() + /// A that completes when the server calls /world/TgsInitializationComplete() /// Task OnPrime { get; } diff --git a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs index 433680a941..d8db5b4163 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs @@ -95,6 +95,8 @@ namespace Tgstation.Server.Host.Components.Watchdog if (Server.TerminationWasRequested) await EventConsumer.HandleEvent(EventType.WorldEndProcess, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); + await EventConsumer.HandleEvent(EventType.WorldDel, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); + string exitWord = Server.TerminationWasRequested ? "exited" : "crashed"; if (Server.RebootState == Session.RebootState.Shutdown) { @@ -128,6 +130,8 @@ namespace Tgstation.Server.Host.Components.Watchdog gracefulRebootRequired = false; Server.ResetRebootState(); + await EventConsumer.HandleEvent(EventType.WorldDel, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); + switch (rebootState) { case Session.RebootState.Normal: @@ -144,7 +148,6 @@ namespace Tgstation.Server.Host.Components.Watchdog default: throw new InvalidOperationException($"Invalid reboot state: {rebootState}"); } - case MonitorActivationReason.ActiveLaunchParametersUpdated: await Server.SetRebootState(Session.RebootState.Restart, cancellationToken).ConfigureAwait(false); gracefulRebootRequired = true; @@ -152,6 +155,9 @@ namespace Tgstation.Server.Host.Components.Watchdog case MonitorActivationReason.NewDmbAvailable: await HandleNewDmbAvailable(cancellationToken).ConfigureAwait(false); break; + case MonitorActivationReason.ActiveServerPrimed: + await EventConsumer.HandleEvent(EventType.WorldPrime, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); + break; case MonitorActivationReason.Heartbeat: default: throw new InvalidOperationException($"Invalid activation reason: {reason}"); diff --git a/src/Tgstation.Server.Host/Components/Watchdog/MonitorActivationReason.cs b/src/Tgstation.Server.Host/Components/Watchdog/MonitorActivationReason.cs index 4b0d046561..4f1073e742 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/MonitorActivationReason.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/MonitorActivationReason.cs @@ -1,4 +1,4 @@ -namespace Tgstation.Server.Host.Components.Watchdog +namespace Tgstation.Server.Host.Components.Watchdog { /// /// Reasons for the monitor to wake up @@ -29,5 +29,10 @@ /// A heartbeat is required. /// Heartbeat, + + /// + /// Server primed. + /// + ActiveServerPrimed, } } diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs index f6a7ed6160..3e89293cb3 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs @@ -609,6 +609,7 @@ namespace Tgstation.Server.Host.Components.Watchdog /// /// The for the operation. /// A representing the running operation. + #pragma warning disable CA1502 private async Task MonitorLifetimes(CancellationToken cancellationToken) { Logger.LogTrace("Entered MonitorLifetimes"); @@ -619,6 +620,12 @@ namespace Tgstation.Server.Host.Components.Watchdog try { MonitorAction nextAction = MonitorAction.Continue; + Task activeServerLifetime = null, + activeServerReboot = null, + serverPrimed = null, + activeLaunchParametersChanged = null, + newDmbAvailable = null; + ISessionController lastController = null; for (ulong iteration = 1; nextAction != MonitorAction.Exit; ++iteration) using (LogContext.PushProperty("Monitor", iteration)) try @@ -627,17 +634,44 @@ namespace Tgstation.Server.Host.Components.Watchdog nextAction = MonitorAction.Continue; var controller = GetActiveController(); - Task activeServerLifetime = controller.Lifetime; - var activeServerReboot = controller.OnReboot; - Task activeLaunchParametersChanged = ActiveParametersUpdated.Task; - var newDmbAvailable = DmbFactory.OnNewerDmb; + void UpdateMonitoredTasks() + { + static void TryUpdateTask(ref Task oldTask, Task newTask) + { + if (oldTask?.IsCompleted == true) + return; + + oldTask = newTask; + } + + if (lastController == controller) + { + TryUpdateTask(ref activeServerLifetime, controller.Lifetime); + TryUpdateTask(ref activeServerReboot, controller.OnReboot); + TryUpdateTask(ref serverPrimed, controller.OnPrime); + } + else + { + activeServerLifetime = controller.Lifetime; + activeServerReboot = controller.OnReboot; + serverPrimed = controller.OnPrime; + lastController = controller; + } + + TryUpdateTask(ref activeLaunchParametersChanged, ActiveParametersUpdated.Task); + TryUpdateTask(ref newDmbAvailable, DmbFactory.OnNewerDmb); + } + + UpdateMonitoredTasks(); var heartbeatSeconds = ActiveLaunchParameters.HeartbeatSeconds.Value; var heartbeat = heartbeatSeconds == 0 || !controller.DMApiAvailable ? Extensions.TaskExtensions.InfiniteTask() - : Task.Delay(TimeSpan.FromSeconds(heartbeatSeconds), cancellationToken); + : Task.Delay( + TimeSpan.FromSeconds(heartbeatSeconds), + cancellationToken); // cancel waiting if requested var cancelTcs = new TaskCompletionSource(); @@ -647,7 +681,8 @@ namespace Tgstation.Server.Host.Components.Watchdog heartbeat, newDmbAvailable, cancelTcs.Task, - activeLaunchParametersChanged); + activeLaunchParametersChanged, + serverPrimed); // wait for something to happen using (cancellationToken.Register(() => cancelTcs.SetCanceled())) @@ -688,7 +723,10 @@ namespace Tgstation.Server.Host.Components.Watchdog || CheckActivationReason(ref activeServerReboot, MonitorActivationReason.ActiveServerRebooted) || CheckActivationReason(ref newDmbAvailable, MonitorActivationReason.NewDmbAvailable) || CheckActivationReason(ref activeLaunchParametersChanged, MonitorActivationReason.ActiveLaunchParametersUpdated) - || CheckActivationReason(ref heartbeat, MonitorActivationReason.Heartbeat); + || CheckActivationReason(ref heartbeat, MonitorActivationReason.Heartbeat) + || CheckActivationReason(ref serverPrimed, MonitorActivationReason.ActiveServerPrimed); + + UpdateMonitoredTasks(); if (!anyActivation) moreActivationsToProcess = false; @@ -769,6 +807,7 @@ namespace Tgstation.Server.Host.Components.Watchdog Logger.LogTrace("Monitor exiting..."); } + #pragma warning restore CA1502 /// /// Starts all s. From a04b1cccf7048855392dca8e65d5b395c21b8177 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 14 Jan 2021 13:32:24 -0500 Subject: [PATCH 11/42] Do not call WorldDel on crashes --- src/Tgstation.Server.Host/Components/Events/EventType.cs | 4 ++-- .../Components/Watchdog/BasicWatchdog.cs | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Events/EventType.cs b/src/Tgstation.Server.Host/Components/Events/EventType.cs index d99ee079e2..38aed033d9 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventType.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventType.cs @@ -120,13 +120,13 @@ namespace Tgstation.Server.Host.Components.Events WorldEndProcess, /// - /// After any sort of watchdog DreamDaemon closure or reboot. Reboots only supported with DMAPI. Not synchronous. Called after . No parameters. + /// Watchdog event when TgsReboot() is called. Not synchronous. Called after . No parameters. /// [EventScript("WorldDel")] WorldDel, /// - /// Watchdog event when TgsInitializationComplete() is called. No parameters. + /// Watchdog event when TgsInitializationsComplete() is called. No parameters. /// [EventScript("WorldPrime")] WorldPrime, diff --git a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs index d8db5b4163..176ed5b106 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs @@ -95,8 +95,6 @@ namespace Tgstation.Server.Host.Components.Watchdog if (Server.TerminationWasRequested) await EventConsumer.HandleEvent(EventType.WorldEndProcess, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); - await EventConsumer.HandleEvent(EventType.WorldDel, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); - string exitWord = Server.TerminationWasRequested ? "exited" : "crashed"; if (Server.RebootState == Session.RebootState.Shutdown) { From afcdafa564f1bcf3d002c518f45ea926be71ac2b Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 14 Jan 2021 13:35:47 -0500 Subject: [PATCH 12/42] Add a seperate event for unexpected DreamDaemon exits --- src/DMAPI/tgs.dm | 7 ++++--- src/Tgstation.Server.Host/Components/Events/EventType.cs | 6 ++++++ .../Components/Watchdog/BasicWatchdog.cs | 8 +++++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/DMAPI/tgs.dm b/src/DMAPI/tgs.dm index f54d519b9e..c08b5d1ae2 100644 --- a/src/DMAPI/tgs.dm +++ b/src/DMAPI/tgs.dm @@ -97,10 +97,11 @@ #define TGS_EVENT_WATCHDOG_DETACH 16 // We don't actually implement these 3 events as the DMAPI can never receive them. // #define TGS_EVENT_WATCHDOG_LAUNCH 17 -// #define TGS_EVENT_WORLD_END_PROCESS 18 -// #define TGS_EVENT_WORLD_DEL 19 +// #define TGS_EVENT_WATCHDOG_CRASH 18 +// #define TGS_EVENT_WORLD_END_PROCESS 19 +// #define TGS_EVENT_WORLD_DEL 20 /// Watchdog event when TgsInitializationComplete() is called. No parameters. - #define TGS_EVENT_WORLD_PRIME 20 + #define TGS_EVENT_WORLD_PRIME 21 // OTHER ENUMS diff --git a/src/Tgstation.Server.Host/Components/Events/EventType.cs b/src/Tgstation.Server.Host/Components/Events/EventType.cs index 38aed033d9..d0a6b2b4be 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventType.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventType.cs @@ -113,6 +113,12 @@ namespace Tgstation.Server.Host.Components.Events [EventScript("WatchdogLaunch")] WatchdogLaunch, + /// + /// Watchdog event when DreamDaemon exits unexpectedly. No parameters. + /// + [EventScript("WatchdogLaunch")] + WatchdogCrash, + /// /// In between watchdog DreamDaemon restarts if the process has been force-ended by the DMAPI (TgsEndProcess()). No parameters. /// diff --git a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs index 176ed5b106..e334bdc63b 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs @@ -92,10 +92,12 @@ namespace Tgstation.Server.Host.Components.Watchdog switch (reason) { case MonitorActivationReason.ActiveServerCrashed: - if (Server.TerminationWasRequested) - await EventConsumer.HandleEvent(EventType.WorldEndProcess, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); + var eventType = Server.TerminationWasRequested + ? EventType.WorldEndProcess + : EventType.WatchdogCrash; + await EventConsumer.HandleEvent(eventType, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); - string exitWord = Server.TerminationWasRequested ? "exited" : "crashed"; + var exitWord = Server.TerminationWasRequested ? "exited" : "crashed"; if (Server.RebootState == Session.RebootState.Shutdown) { // the time for graceful shutdown is now From 944a6a4f2f53163fc80de743cf1fa9242ed94fdf Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 14 Jan 2021 14:00:13 -0500 Subject: [PATCH 13/42] Why am I calling it Del? --- src/DMAPI/tgs.dm | 2 +- src/Tgstation.Server.Host/Components/Events/EventType.cs | 6 +++--- .../Components/Watchdog/BasicWatchdog.cs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/DMAPI/tgs.dm b/src/DMAPI/tgs.dm index c08b5d1ae2..7ef3268322 100644 --- a/src/DMAPI/tgs.dm +++ b/src/DMAPI/tgs.dm @@ -99,7 +99,7 @@ // #define TGS_EVENT_WATCHDOG_LAUNCH 17 // #define TGS_EVENT_WATCHDOG_CRASH 18 // #define TGS_EVENT_WORLD_END_PROCESS 19 -// #define TGS_EVENT_WORLD_DEL 20 +// #define TGS_EVENT_WORLD_REBOOT 20 /// Watchdog event when TgsInitializationComplete() is called. No parameters. #define TGS_EVENT_WORLD_PRIME 21 diff --git a/src/Tgstation.Server.Host/Components/Events/EventType.cs b/src/Tgstation.Server.Host/Components/Events/EventType.cs index d0a6b2b4be..090c5c6982 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventType.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventType.cs @@ -96,7 +96,7 @@ namespace Tgstation.Server.Host.Components.Events DeploymentComplete, /// - /// Before the watchdog shutsdown. Not sent for graceful shutdowns. No parameters. + /// Before the watchdog shuts down. Not sent for graceful shutdowns. No parameters. /// [EventScript("WatchdogShutdown")] WatchdogShutdown, @@ -128,8 +128,8 @@ namespace Tgstation.Server.Host.Components.Events /// /// Watchdog event when TgsReboot() is called. Not synchronous. Called after . No parameters. /// - [EventScript("WorldDel")] - WorldDel, + [EventScript("WorldReboot")] + WorldReboot, /// /// Watchdog event when TgsInitializationsComplete() is called. No parameters. diff --git a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs index e334bdc63b..3cddd03a02 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs @@ -130,7 +130,7 @@ namespace Tgstation.Server.Host.Components.Watchdog gracefulRebootRequired = false; Server.ResetRebootState(); - await EventConsumer.HandleEvent(EventType.WorldDel, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); + await EventConsumer.HandleEvent(EventType.WorldReboot, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); switch (rebootState) { From 453ddacd0c169381af290ad7e569f7a4a9a4eb84 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 14 Jan 2021 14:24:23 -0500 Subject: [PATCH 14/42] Fix duplicate script name --- src/Tgstation.Server.Host/Components/Events/EventType.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Events/EventType.cs b/src/Tgstation.Server.Host/Components/Events/EventType.cs index 090c5c6982..dabb822de7 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventType.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventType.cs @@ -116,7 +116,7 @@ namespace Tgstation.Server.Host.Components.Events /// /// Watchdog event when DreamDaemon exits unexpectedly. No parameters. /// - [EventScript("WatchdogLaunch")] + [EventScript("WatchdogCrash")] WatchdogCrash, /// From e77e8dae56c90198fe458c34909a41657c36f7e4 Mon Sep 17 00:00:00 2001 From: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Date: Sat, 16 Jan 2021 12:40:14 +0000 Subject: [PATCH 15/42] Yaml config files --- README.md | 12 ++++++------ build/Version.props | 2 +- src/Tgstation.Server.Host/ServerFactory.cs | 6 +++++- src/Tgstation.Server.Host/Setup/SetupWizard.cs | 14 +++++++++----- .../Tgstation.Server.Host.csproj | 1 + 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 36be4c01b0..cc7de2d763 100644 --- a/README.md +++ b/README.md @@ -78,19 +78,19 @@ Note that this container is meant to be long running. Updates are handled intern Note that automatic configuration reloading is currently not supported in the container. See #1143 -If using manual configuration, before starting your container make sure the aforementioned `appsettings.Production.json` is setup properly. See below +If using manual configuration, before starting your container make sure the aforementioned `appsettings.Production.yml` is setup properly. See below ### Configuring -The first time you run TGS4 you should be prompted with a configuration wizard which will guide you through setting up your appsettings.Production.json +The first time you run TGS4 you should be prompted with a configuration wizard which will guide you through setting up your `appsettings.Production.yml` -This wizard will, generally, run whenever the server is launched without detecting the config json. Follow the instructions below to perform this process manually. +This wizard will, generally, run whenever the server is launched without detecting the config yml. Follow the instructions below to perform this process manually. #### Configuration Methods There are 3 primary supported ways to configure TGS: -- Modify the `appsettings.Production.json` file (Recommended). +- Modify the `appsettings.Production.yml` file (Recommended). - Set environment variables in the form `Section__Subsection=value` or `Section__ArraySubsection__0=value` for arrays. - Set command line arguments in the form `--Section:Subsection=value` or `--Section:ArraySubsection:0=value` for arrays. @@ -98,7 +98,7 @@ The latter two are not recommended as they cannot be dynamically changed at runt #### Manual Configuration -Create an `appsettings.Production.json` file next to `appsettings.json`. This will override the default settings in appsettings.json with your production settings. There are a few keys meant to be changed by hosts. Modifying any config files while the server is running will trigger a safe restart (Keeps DreamDaemon instances running). Note these are all case-sensitive: +Create an `appsettings.Production.yml` file next to `appsettings.json`. This will override the default settings in `appsettings.json` with your production settings. There are a few keys meant to be changed by hosts. Modifying any config files while the server is running will trigger a safe restart (Keeps DreamDaemon instances running). Note these are all case-sensitive: - `General:ConfigVersion`: Suppresses warnings about out of date config versions. You should change this after updating TGS to one with a new config version. The current version can be found on the releases page for your server version (This field did not exist before v4.4.0). @@ -250,7 +250,7 @@ var/global/client_count = 0 ## Remote Access -tgstation-server is an [ASP.Net Core](https://docs.microsoft.com/en-us/aspnet/core/) app based on the Kestrel web server. This section is meant to serve as a general use case overview, but the entire Kestrel configuration can be modified to your liking with the configuration JSON. See [the official documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel) for details. +tgstation-server is an [ASP.Net Core](https://docs.microsoft.com/en-us/aspnet/core/) app based on the Kestrel web server. This section is meant to serve as a general use case overview, but the entire Kestrel configuration can be modified to your liking with the configuration YAML. See [the official documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel) for details. Exposing the builtin Kestrel server to the internet directly over HTTP is highly not reccommended due to the lack of security. The recommended way to expose tgstation-server to the internet is to host it through a reverse proxy with HTTPS support. Here are some step by step examples to achieve this for major web servers. diff --git a/build/Version.props b/build/Version.props index 222901410b..e51d2af857 100644 --- a/build/Version.props +++ b/build/Version.props @@ -4,7 +4,7 @@ 4.7.0 - 2.2.0 + 2.3.0 8.1.1 9.1.1 5.2.10 diff --git a/src/Tgstation.Server.Host/ServerFactory.cs b/src/Tgstation.Server.Host/ServerFactory.cs index 55bbd24e3a..72d601c73d 100644 --- a/src/Tgstation.Server.Host/ServerFactory.cs +++ b/src/Tgstation.Server.Host/ServerFactory.cs @@ -49,7 +49,11 @@ namespace Tgstation.Server.Host var basePath = IOManager.ResolvePath(); IHostBuilder CreateDefaultBuilder() => Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args) - .ConfigureAppConfiguration((context, configuration) => configuration.SetBasePath(basePath)); + .ConfigureAppConfiguration((context, builder) => { + builder.AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true) + .AddYamlFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.yml", optional: true, reloadOnChange: true); //Allow both appsettings.json and appsettings.yml for backwards compat + + }); var setupWizardHostBuilder = CreateDefaultBuilder() .UseSetupApplication(); diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index 6a7c99e03b..927cb43982 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -22,6 +22,7 @@ using Tgstation.Server.Host.Core; using Tgstation.Server.Host.Database; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.System; +using YamlDotNet.Serialization; namespace Tgstation.Server.Host.Setup { @@ -841,8 +842,11 @@ namespace Tgstation.Server.Host.Setup { SwarmConfiguration.Section, swarmConfiguration }, }; - var json = JsonConvert.SerializeObject(map, Formatting.Indented); - var configBytes = Encoding.UTF8.GetBytes(json); + var serializer = new SerializerBuilder().Build(); + + var serializedYaml = serializer.Serialize(map); + + var configBytes = Encoding.UTF8.GetBytes(serializedYaml); reloadTcs = new TaskCompletionSource(); @@ -863,9 +867,9 @@ namespace Tgstation.Server.Host.Setup { await console.WriteAsync(e.Message, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false); - await console.WriteAsync("For your convienence, here's the json we tried to write out:", true, cancellationToken).ConfigureAwait(false); + await console.WriteAsync("For your convienence, here's the yaml we tried to write out:", true, cancellationToken).ConfigureAwait(false); await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false); - await console.WriteAsync(json, true, cancellationToken).ConfigureAwait(false); + await console.WriteAsync(serializedYaml, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false); await console.WriteAsync("Press any key to exit...", true, cancellationToken).ConfigureAwait(false); await console.PressAnyKeyAsync(cancellationToken).ConfigureAwait(false); @@ -930,7 +934,7 @@ namespace Tgstation.Server.Host.Setup return; } - var userConfigFileName = String.Format(CultureInfo.InvariantCulture, "appsettings.{0}.json", hostingEnvironment.EnvironmentName); + var userConfigFileName = String.Format(CultureInfo.InvariantCulture, "appsettings.{0}.yml", hostingEnvironment.EnvironmentName); async Task HandleSetupCancel() { diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 3951c10411..b322b33c24 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -83,6 +83,7 @@ + From 89d4781a79e60740d39ab4f53869ab688c7a570f Mon Sep 17 00:00:00 2001 From: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Date: Sat, 16 Jan 2021 16:47:30 +0000 Subject: [PATCH 16/42] Cybertweaks --- README.md | 23 +++---- docs/Architecture.dox | 2 +- .../Tgstation.Server.Host.Watchdog.csproj | 2 +- .../Watchdog.cs | 8 +-- .../Configuration/README.md | 4 +- src/Tgstation.Server.Host/README.md | 2 +- src/Tgstation.Server.Host/ServerFactory.cs | 3 +- .../Setup/SetupWizard.cs | 1 - .../Tgstation.Server.Host.csproj | 7 +- src/Tgstation.Server.Host/appsettings.json | 66 ------------------- src/Tgstation.Server.Host/appsettings.yml | 52 +++++++++++++++ 11 files changed, 77 insertions(+), 93 deletions(-) delete mode 100644 src/Tgstation.Server.Host/appsettings.json create mode 100644 src/Tgstation.Server.Host/appsettings.yml diff --git a/README.md b/README.md index 30268af309..e6fc63514e 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ The latter two are not recommended as they cannot be dynamically changed at runt #### Manual Configuration -Create an `appsettings.Production.yml` file next to `appsettings.json`. This will override the default settings in `appsettings.json` with your production settings. There are a few keys meant to be changed by hosts. Modifying any config files while the server is running will trigger a safe restart (Keeps DreamDaemon instances running). Note these are all case-sensitive: +Create an `appsettings.Production.yml` file next to `appsettings.yml`. This will override the default settings in `appsettings.yml` with your production settings. There are a few keys meant to be changed by hosts. Modifying any config files while the server is running will trigger a safe restart (Keeps DreamDaemon instances running). Note these are all case-sensitive: - `General:ConfigVersion`: Suppresses warnings about out of date config versions. You should change this after updating TGS to one with a new config version. The current version can be found on the releases page for your server version (This field did not exist before v4.4.0). @@ -141,19 +141,14 @@ Create an `appsettings.Production.yml` file next to `appsettings.json`. This wil - `Swarm:Identifier` should be set uniquely on all swarmed servers. Used to identify the current server. This is also used to select which instances exist on the current machine and should not be changed post-setup. - `Security:OAuth:`: Sets the OAuth client ID and secret for a given ``. The currently supported providers are `GitHub`, `Discord`, and `TGForums`. Setting these fields to `null` disables logins with the provider, but does not stop users from associating their accounts using the API. Sample Entry: -```json -{ - "Security": { - "OAuth": { - "Keycloak": { - "ClientId": "...", - "ClientSecret": "...", - "RedirectUrl": "...", - "ServerUrl": "..." - } - } - } -} +```yml +Security: + OAuth: + Keycloak: + ClientId: "..." + ClientSecret: "..." + RedirectUrl: "..." + ServerUrl: "..." ``` The following providers use the `RedirectUrl` setting: diff --git a/docs/Architecture.dox b/docs/Architecture.dox index b13c7de06e..e45b40ad70 100644 --- a/docs/Architecture.dox +++ b/docs/Architecture.dox @@ -23,7 +23,7 @@ This is a second process spawned by the Host Watchdog which facilitates the vast The server's entrypoint is in the @ref Tgstation.Server.Host.Program class. This class mainly determines if the Host watchdog is present and creates and runs the @ref Tgstation.Server.Host.Server class. That class then builds an ASP.NET Core web host using the @ref Tgstation.Server.Host.Core.Application class. -The @ref Tgstation.Server.Host.Core.Application class has two methods called by the framework. First the @ref Tgstation.Server.Host.Core.Application.ConfigureServices method sets up dependency injection of interfaces for Controllers, the @ref Tgstation.Server.Host.Database.DatabaseContext, and the component factories of the server. The framework handles constructing these things once the application starts. Configuration is loaded from the appropriate appSettings.json into the @ref Tgstation.Server.Host.Configuration classes for injection as well. Then @ref Tgstation.Server.Host.Core.Application.Configure method is run which sets up the web request pipeline which currently has the following stack of handlers: +The @ref Tgstation.Server.Host.Core.Application class has two methods called by the framework. First the @ref Tgstation.Server.Host.Core.Application.ConfigureServices method sets up dependency injection of interfaces for Controllers, the @ref Tgstation.Server.Host.Database.DatabaseContext, and the component factories of the server. The framework handles constructing these things once the application starts. Configuration is loaded from the appropriate appSettings.yml into the @ref Tgstation.Server.Host.Configuration classes for injection as well. Then @ref Tgstation.Server.Host.Core.Application.Configure method is run which sets up the web request pipeline which currently has the following stack of handlers: - Catch any exceptions and respond with 500 and detailed HTML error page - Respond with 503 if the application is still starting or shutting down diff --git a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj index dc6ff60c72..c2d59ccd7a 100644 --- a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj +++ b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj @@ -33,7 +33,7 @@ - + PreserveNewest diff --git a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs index 4f2e4ae68d..d9ab43cfb6 100644 --- a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs @@ -96,10 +96,10 @@ namespace Tgstation.Server.Host.Watchdog foreach (string newPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories)) File.Copy(newPath, newPath.Replace(sourcePath, defaultAssemblyPath), true); - const string AppSettingsJson = "appsettings.json"; - var rootJson = Path.Combine(rootLocation, AppSettingsJson); - File.Delete(rootJson); - File.Move(Path.Combine(defaultAssemblyPath, AppSettingsJson), rootJson); + const string AppSettingsYaml = "appsettings.yml"; + var rootYaml = Path.Combine(rootLocation, AppSettingsYaml); + File.Delete(rootYaml); + File.Move(Path.Combine(defaultAssemblyPath, AppSettingsYaml), rootYaml); } else Directory.CreateDirectory(assemblyStoragePath); diff --git a/src/Tgstation.Server.Host/Configuration/README.md b/src/Tgstation.Server.Host/Configuration/README.md index 50f05e1290..83fdf539b9 100644 --- a/src/Tgstation.Server.Host/Configuration/README.md +++ b/src/Tgstation.Server.Host/Configuration/README.md @@ -1,5 +1,5 @@ # Configuration Classes -These types map directly to the settings used in the [appsettings.json](../appsettings.json) file and its derivatives. See the [Microsoft Docs on the ASP .NET Core configuration system](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1) for details. +These types map directly to the settings used in the [appsettings.yml](../appsettings.yml) file and its derivatives. See the [Microsoft Docs on the ASP .NET Core configuration system](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1) for details. -When making changes here, it's important to also update the config version in [build/Version.props](../../../build/Version.props) according to semver semantics. You'll also need to update the constant in [GeneralConfiguration.cs](./GeneralConfigration.cs). \ No newline at end of file +When making changes here, it's important to also update the config version in [build/Version.props](../../../build/Version.props) according to semver semantics. You'll also need to update the constant in [GeneralConfiguration.cs](./GeneralConfigration.cs). diff --git a/src/Tgstation.Server.Host/README.md b/src/Tgstation.Server.Host/README.md index 83f08f4798..5f1aeca63c 100644 --- a/src/Tgstation.Server.Host/README.md +++ b/src/Tgstation.Server.Host/README.md @@ -25,7 +25,7 @@ Here's a breakdown of things in this directory - [.config](./.config) contains the dotnet-tools.json. At the time of writing, this is only used to set the version of the [dotnet ef tools](https://docs.microsoft.com/en-us/ef/core/miscellaneous/cli/) used to create database migrations. - [ClientApp](./ClientApp) contains scripts to build and deploy the web control panel with TGS. - [Components](./Components) is where the bulk of the TGS implementation lives. -- [Configuration](./Configuration) contains classes that partly make up the configuration json files (i.e. [appsettings.json](./appsettings.json)). +- [Configuration](./Configuration) contains classes that partly make up the configuration yaml files (i.e. [appsettings.yml](./appsettings.yml)). - [Controllers](./Controllers) is where HTTP API code lives and bridges it with component code. - [Core](./Core) contains [Application.cs](./Core/Application.cs) and other various helpers that don't belong anywhere else. - [Database](./Database) contains all database related code. diff --git a/src/Tgstation.Server.Host/ServerFactory.cs b/src/Tgstation.Server.Host/ServerFactory.cs index 72d601c73d..734834c8f5 100644 --- a/src/Tgstation.Server.Host/ServerFactory.cs +++ b/src/Tgstation.Server.Host/ServerFactory.cs @@ -50,8 +50,7 @@ namespace Tgstation.Server.Host var basePath = IOManager.ResolvePath(); IHostBuilder CreateDefaultBuilder() => Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((context, builder) => { - builder.AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true) - .AddYamlFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.yml", optional: true, reloadOnChange: true); //Allow both appsettings.json and appsettings.yml for backwards compat + builder.AddYamlFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.yml", optional: true, reloadOnChange: true); //Allow both appsettings.json and appsettings.yml for backwards compat }); diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index 927cb43982..0f2beb86d4 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -4,7 +4,6 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using MySql.Data.MySqlClient; -using Newtonsoft.Json; using Npgsql; using System; using System.Collections.Generic; diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index b322b33c24..08581354e9 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -115,11 +115,16 @@ + - + + + + + PreserveNewest diff --git a/src/Tgstation.Server.Host/appsettings.json b/src/Tgstation.Server.Host/appsettings.json deleted file mode 100644 index efc04c7461..0000000000 --- a/src/Tgstation.Server.Host/appsettings.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "General": { - "MinimumPasswordLength": 15, - "GitHubAccessToken": null, - "SetupWizardMode": "AutoDetect", - "ByondTopicTimeout": 5000, - "RestartTimeout": 60000, - "ApiPort": 5000, - "UseBasicWatchdog": false, - "UserLimit": 100, - "UserGroupLimit": 25, - "InstanceLimit": 10, - "ValidInstancePaths": null, - "HostApiDocumentation": false - }, - "FileLogging": { - "Directory": null, - "Disable": false, - "LogLevel": "Debug", - "MicrosoftLogLevel": "Warning" - }, - "Logging": { - "IncludeScopes": false, - "Debug": { - "LogLevel": { - "Default": "Debug", - "Microsoft": "Information" - } - }, - "Console": { - "LogLevel": { - "Default": "Trace", - "Microsoft": "Warning" - } - } - }, - "ControlPanel": { - "Enable": false, - "AllowAnyOrigin": false, - "AllowedOrigins": [] - }, - "Updates": { - "GitHubRepositoryId": 92952846, - "GitTagPrefix": "tgstation-server-v", - "UpdatePackageAssetName": "ServerUpdatePackage.zip" - }, - "Database": { - "DropDatabase": false, - "DatabaseType": "SqlServer", - "ResetAdminPassword": false, - "ServerVersion": null, - "ConnectionString": "Data Source=(local);Initial Catalog=TGS;Integrated Security=True" - }, - "Security": { - "TokenExpiryMinutes": 15, - "TokenClockSkewMinutes": 1, - "TokenSigningKeyByteAmount": 256, - "CustomTokenSigningKeyBase64": null, - "OAuth": { - "GitHub": null, - "Discord": null, - "TGForums": null, - "Keycloak": null - } - } -} diff --git a/src/Tgstation.Server.Host/appsettings.yml b/src/Tgstation.Server.Host/appsettings.yml new file mode 100644 index 0000000000..b53cd2832a --- /dev/null +++ b/src/Tgstation.Server.Host/appsettings.yml @@ -0,0 +1,52 @@ +General: + MinimumPasswordLength: 15 + GitHubAccessToken: + SetupWizardMode: AutoDetect + ByondTopicTimeout: 5000 + RestartTimeout: 60000 + ApiPort: 5000 + UseBasicWatchdog: false + UserLimit: 100 + UserGroupLimit: 25 + InstanceLimit: 10 + ValidInstancePaths: + HostApiDocumentation: false +FileLogging: + Directory: + Disable: false + LogLevel: Debug + MicrosoftLogLevel: Warning +Logging: + IncludeScopes: false + Debug: + LogLevel: + Default: Debug + Microsoft: Information + Console: + LogLevel: + Default: Trace + Microsoft: Warning +ControlPanel: + Enable: false + AllowAnyOrigin: false + AllowedOrigins: [] +Updates: + GitHubRepositoryId: 92952846 + GitTagPrefix: tgstation-server-v + UpdatePackageAssetName: ServerUpdatePackage.zip +Database: + DropDatabase: false + DatabaseType: SqlServer + ResetAdminPassword: false + ServerVersion: + ConnectionString: Data Source=(local);Initial Catalog=TGS;Integrated Security=True +Security: + TokenExpiryMinutes: 15 + TokenClockSkewMinutes: 1 + TokenSigningKeyByteAmount: 256 + CustomTokenSigningKeyBase64: + OAuth: + GitHub: + Discord: + TGForums: + Keycloak: From 0f78c17f21fd7bfd66b61b8e5ee73926f6dcd5db Mon Sep 17 00:00:00 2001 From: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Date: Sat, 16 Jan 2021 18:05:02 +0000 Subject: [PATCH 17/42] Last cybertweak --- src/Tgstation.Server.Host/ServerFactory.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/ServerFactory.cs b/src/Tgstation.Server.Host/ServerFactory.cs index 734834c8f5..d310dc8ae2 100644 --- a/src/Tgstation.Server.Host/ServerFactory.cs +++ b/src/Tgstation.Server.Host/ServerFactory.cs @@ -50,7 +50,8 @@ namespace Tgstation.Server.Host var basePath = IOManager.ResolvePath(); IHostBuilder CreateDefaultBuilder() => Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((context, builder) => { - builder.AddYamlFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.yml", optional: true, reloadOnChange: true); //Allow both appsettings.json and appsettings.yml for backwards compat + builder.AddYamlFile("appsettings.yml", optional: true, reloadOnChange: true) + .AddYamlFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.yml", optional: true, reloadOnChange: true); }); From 62d1d3806c11a7ec68ecf4ddbeaf144e5ce7f6b6 Mon Sep 17 00:00:00 2001 From: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Date: Mon, 18 Jan 2021 18:22:23 +0000 Subject: [PATCH 18/42] Lets give this a shot --- docs/Architecture.dox | 2 +- .../Database/MySqlDatabaseContext.cs | 3 ++- src/Tgstation.Server.Host/ServerFactory.cs | 11 ++++++++++- .../Tgstation.Server.Host.csproj | 5 ----- tests/Tgstation.Server.Tests/TestingServer.cs | 2 +- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/docs/Architecture.dox b/docs/Architecture.dox index e45b40ad70..6c5bdeea1d 100644 --- a/docs/Architecture.dox +++ b/docs/Architecture.dox @@ -23,7 +23,7 @@ This is a second process spawned by the Host Watchdog which facilitates the vast The server's entrypoint is in the @ref Tgstation.Server.Host.Program class. This class mainly determines if the Host watchdog is present and creates and runs the @ref Tgstation.Server.Host.Server class. That class then builds an ASP.NET Core web host using the @ref Tgstation.Server.Host.Core.Application class. -The @ref Tgstation.Server.Host.Core.Application class has two methods called by the framework. First the @ref Tgstation.Server.Host.Core.Application.ConfigureServices method sets up dependency injection of interfaces for Controllers, the @ref Tgstation.Server.Host.Database.DatabaseContext, and the component factories of the server. The framework handles constructing these things once the application starts. Configuration is loaded from the appropriate appSettings.yml into the @ref Tgstation.Server.Host.Configuration classes for injection as well. Then @ref Tgstation.Server.Host.Core.Application.Configure method is run which sets up the web request pipeline which currently has the following stack of handlers: +The @ref Tgstation.Server.Host.Core.Application class has two methods called by the framework. First the @ref Tgstation.Server.Host.Core.Application.ConfigureServices method sets up dependency injection of interfaces for Controllers, the @ref Tgstation.Server.Host.Database.DatabaseContext, and the component factories of the server. The framework handles constructing these things once the application starts. Configuration is loaded from the appropriate appsettings.yml into the @ref Tgstation.Server.Host.Configuration classes for injection as well. Then @ref Tgstation.Server.Host.Core.Application.Configure method is run which sets up the web request pipeline which currently has the following stack of handlers: - Catch any exceptions and respond with 500 and detailed HTML error page - Respond with 503 if the application is still starting or shutting down diff --git a/src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs b/src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs index 46bd93309c..933b129983 100644 --- a/src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs @@ -1,4 +1,4 @@ -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; using Pomelo.EntityFrameworkCore.MySql.Infrastructure; using System; using Tgstation.Server.Host.Configuration; @@ -42,6 +42,7 @@ namespace Tgstation.Server.Host.Database mySqlOptions.EnableRetryOnFailure(); if (!String.IsNullOrEmpty(databaseConfiguration.ServerVersion)) + Console.WriteLine("SQLVERSION: " + databaseConfiguration.DatabaseType); mySqlOptions.ServerVersion( Version.Parse(databaseConfiguration.ServerVersion), databaseConfiguration.DatabaseType == DatabaseType.MariaDB diff --git a/src/Tgstation.Server.Host/ServerFactory.cs b/src/Tgstation.Server.Host/ServerFactory.cs index d310dc8ae2..b94e29b140 100644 --- a/src/Tgstation.Server.Host/ServerFactory.cs +++ b/src/Tgstation.Server.Host/ServerFactory.cs @@ -52,7 +52,16 @@ namespace Tgstation.Server.Host .ConfigureAppConfiguration((context, builder) => { builder.AddYamlFile("appsettings.yml", optional: true, reloadOnChange: true) .AddYamlFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.yml", optional: true, reloadOnChange: true); - + // reorganize the builder so our yaml configs don't override the env/cmdline configs + // values obtained via debugger + var envConfig = builder.Sources[3]; + var cmdLineConfig = builder.Sources[4]; + var baseYmlConfig = builder.Sources[5]; + var environmentYmlConfig = builder.Sources[6]; + builder.Sources[3] = baseYmlConfig; + builder.Sources[4] = environmentYmlConfig; + builder.Sources[5] = envConfig; + builder.Sources[6] = cmdLineConfig; }); var setupWizardHostBuilder = CreateDefaultBuilder() diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 08581354e9..4c2a80535e 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -115,14 +115,9 @@ - - - - - PreserveNewest diff --git a/tests/Tgstation.Server.Tests/TestingServer.cs b/tests/Tgstation.Server.Tests/TestingServer.cs index f35f5c38ad..de938a16e0 100644 --- a/tests/Tgstation.Server.Tests/TestingServer.cs +++ b/tests/Tgstation.Server.Tests/TestingServer.cs @@ -110,7 +110,7 @@ namespace Tgstation.Server.Tests args.Add($"Security:OAuth=null"); // SPECIFICALLY DELETE THE DEV APPSETTINGS, WE DON'T WANT IT IN THE WAY - File.Delete("appsettings.Development.json"); + File.Delete("appsettings.Development.yml"); if (!String.IsNullOrEmpty(gitHubAccessToken)) args.Add(String.Format(CultureInfo.InvariantCulture, "General:GitHubAccessToken={0}", gitHubAccessToken)); From 0c67d64708ce021dc938d9bb4528c4ce3718358c Mon Sep 17 00:00:00 2001 From: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Date: Mon, 18 Jan 2021 18:30:15 +0000 Subject: [PATCH 19/42] I actually hate docker --- build/tgs.docker.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/tgs.docker.sh b/build/tgs.docker.sh index 490f318a42..d07e183573 100755 --- a/build/tgs.docker.sh +++ b/build/tgs.docker.sh @@ -5,8 +5,8 @@ SCRIPT_VERSION="1.2.0" echo "tgstation-server 4 container startup script v$SCRIPT_VERSION" echo "PWD: $PWD" -PROD_CONFIG=/config_data/appsettings.Production.json -HOST_CONFIG=/app/appsettings.Production.json +PROD_CONFIG=/config_data/appsettings.Production.yml +HOST_CONFIG=/app/appsettings.Production.yml if [ ! -f $PROD_CONFIG ]; then echo "$PROD_CONFIG not detected! Creating empty and running setup wizard..." From 6206755343868cc2fe694d7088d65939efa361eb Mon Sep 17 00:00:00 2001 From: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Date: Mon, 18 Jan 2021 18:44:51 +0000 Subject: [PATCH 20/42] More changes --- .gitignore | 1 + src/Tgstation.Server.Host/ServerFactory.cs | 12 +++++++----- .../Tgstation.Server.Host.csproj | 4 ++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index c09ef4b2ac..ce8eb6d9de 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ artifacts/ /tests/DMAPI/travistester.int /tests/DMAPI/travistester.dmb /src/Tgstation.Server.Host/appsettings.*.json +/src/Tgstation.Server.Host/appsettings.*.yml /src/Tgstation.Server.Host/wwwroot /src/Tgstation.Server.Host/ClientApp /tools/ReleaseNotes/release_notes.md diff --git a/src/Tgstation.Server.Host/ServerFactory.cs b/src/Tgstation.Server.Host/ServerFactory.cs index b94e29b140..9e75399f37 100644 --- a/src/Tgstation.Server.Host/ServerFactory.cs +++ b/src/Tgstation.Server.Host/ServerFactory.cs @@ -51,17 +51,19 @@ namespace Tgstation.Server.Host IHostBuilder CreateDefaultBuilder() => Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((context, builder) => { builder.AddYamlFile("appsettings.yml", optional: true, reloadOnChange: true) - .AddYamlFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.yml", optional: true, reloadOnChange: true); + .AddYamlFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.yml", optional: true, reloadOnChange: true); // reorganize the builder so our yaml configs don't override the env/cmdline configs // values obtained via debugger + var baseEnvironmentConfig = builder.Sources[2]; var envConfig = builder.Sources[3]; var cmdLineConfig = builder.Sources[4]; var baseYmlConfig = builder.Sources[5]; var environmentYmlConfig = builder.Sources[6]; - builder.Sources[3] = baseYmlConfig; - builder.Sources[4] = environmentYmlConfig; - builder.Sources[5] = envConfig; - builder.Sources[6] = cmdLineConfig; + builder.Sources[2] = baseYmlConfig; + builder.Sources[3] = environmentYmlConfig; + builder.Sources[4] = envConfig; + builder.Sources[5] = cmdLineConfig; + builder.Sources[6] = baseEnvironmentConfig; }); var setupWizardHostBuilder = CreateDefaultBuilder() diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 4c2a80535e..df28ae4642 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -118,6 +118,10 @@ + + + + PreserveNewest From 24c84d75566aa748a137f98484eb0d7595882634 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Tue, 19 Jan 2021 22:03:29 -0500 Subject: [PATCH 21/42] Add missing console logging to service configuring - Let people know they're missing the .NET runtime --- src/Tgstation.Server.Host.Service/Program.cs | 8 +++++--- .../Tgstation.Server.Host.Service.csproj | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host.Service/Program.cs b/src/Tgstation.Server.Host.Service/Program.cs index ac37e65e5a..f86b67243c 100644 --- a/src/Tgstation.Server.Host.Service/Program.cs +++ b/src/Tgstation.Server.Host.Service/Program.cs @@ -1,4 +1,4 @@ -using McMaster.Extensions.CommandLineUtils; +using McMaster.Extensions.CommandLineUtils; using Microsoft.Extensions.Logging; using System; using System.Collections.Specialized; @@ -20,12 +20,10 @@ namespace Tgstation.Server.Host.Service /// sealed class Program { -#pragma warning disable SA1401 // Fields should be private /// /// The for the /// internal static IWatchdogFactory WatchdogFactory = new WatchdogFactory(); -#pragma warning restore SA1401 // Fields should be private /// /// The --uninstall or -u option @@ -151,6 +149,10 @@ namespace Tgstation.Server.Host.Service if (Configure) { +#pragma warning disable CS0618 // Type or member is obsolete + loggerFactory.AddConsole(); +#pragma warning restore CS0618 // Type or member is obsolete + // DCT: None available await WatchdogFactory.CreateWatchdog(loggerFactory).RunAsync(true, Array.Empty(), default).ConfigureAwait(false); } diff --git a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj index d2bb63a992..d6dbaf8980 100644 --- a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj +++ b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj @@ -30,6 +30,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + From 5ebf42fd1ec7f4d1ec403c9d65e80b4f4fe2f80d Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Tue, 19 Jan 2021 22:05:35 -0500 Subject: [PATCH 22/42] Bump host watchdog version --- build/Version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Version.props b/build/Version.props index 8d1bf5b98a..69cdcdc070 100644 --- a/build/Version.props +++ b/build/Version.props @@ -8,7 +8,7 @@ 8.3.0 9.1.2 5.3.0 - 1.1.0 + 1.1.1 1.2.0 From 8e40b826f667f5e29f6bf68396900ca3cc8bfef6 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Wed, 20 Jan 2021 11:34:26 -0500 Subject: [PATCH 23/42] Fix HostWatchdogVersion handling --- src/Tgstation.Server.Host/Program.cs | 3 ++- .../Properties/MasterVersionsAttribute.cs | 10 +++++++++- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Program.cs b/src/Tgstation.Server.Host/Program.cs index fa83a096a9..ffe02ba262 100644 --- a/src/Tgstation.Server.Host/Program.cs +++ b/src/Tgstation.Server.Host/Program.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Tgstation.Server.Host.Core; +using Tgstation.Server.Host.Properties; using Tgstation.Server.Host.System; namespace Tgstation.Server.Host @@ -17,7 +18,7 @@ namespace Tgstation.Server.Host /// /// The expected host watchdog . /// - internal static readonly Version HostWatchdogVersion = new Version(1, 1, 0); + internal static Version HostWatchdogVersion => Version.Parse(MasterVersionsAttribute.Instance.RawHostWatchdogVersion); /// /// The to use. diff --git a/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs b/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs index 20cc04786c..b378207b14 100644 --- a/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs +++ b/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs @@ -31,20 +31,28 @@ namespace Tgstation.Server.Host.Properties /// public string RawControlPanelVersion { get; } + /// + /// The of the control panel version built. + /// + public string RawHostWatchdogVersion { get; } + /// /// Initializes a new instance of the . /// /// The value of . /// The value of . /// The value of . + /// The value of . public MasterVersionsAttribute( string rawConfigurationVersion, string rawDMApiVersion, - string rawControlPanelVersion) + string rawControlPanelVersion, + string rawHostWatchdogVersion) { RawConfigurationVersion = rawConfigurationVersion ?? throw new ArgumentNullException(nameof(rawConfigurationVersion)); RawDMApiVersion = rawDMApiVersion ?? throw new ArgumentNullException(nameof(rawDMApiVersion)); RawControlPanelVersion = rawControlPanelVersion ?? throw new ArgumentNullException(nameof(rawControlPanelVersion)); + RawHostWatchdogVersion = rawHostWatchdogVersion ?? throw new ArgumentNullException(nameof(rawHostWatchdogVersion)); } } } diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 3951c10411..490dc30a94 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -51,6 +51,7 @@ <_Parameter1>$(TgsConfigVersion) <_Parameter2>$(TgsDmapiVersion) <_Parameter3>$(TgsControlPanelVersion) + <_Parameter4>$(TgsHostWatchdogVersion) From 9f57b3d93712d3e3f56fd0a310e0f149bdeddbb0 Mon Sep 17 00:00:00 2001 From: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Date: Wed, 20 Jan 2021 18:38:59 +0000 Subject: [PATCH 24/42] Fix this atleast --- src/Tgstation.Server.Host/ServerFactory.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/ServerFactory.cs b/src/Tgstation.Server.Host/ServerFactory.cs index 9e75399f37..a273d1507c 100644 --- a/src/Tgstation.Server.Host/ServerFactory.cs +++ b/src/Tgstation.Server.Host/ServerFactory.cs @@ -54,16 +54,16 @@ namespace Tgstation.Server.Host .AddYamlFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.yml", optional: true, reloadOnChange: true); // reorganize the builder so our yaml configs don't override the env/cmdline configs // values obtained via debugger - var baseEnvironmentConfig = builder.Sources[2]; + var environmentJsonConfig = builder.Sources[2]; var envConfig = builder.Sources[3]; var cmdLineConfig = builder.Sources[4]; var baseYmlConfig = builder.Sources[5]; var environmentYmlConfig = builder.Sources[6]; builder.Sources[2] = baseYmlConfig; - builder.Sources[3] = environmentYmlConfig; - builder.Sources[4] = envConfig; - builder.Sources[5] = cmdLineConfig; - builder.Sources[6] = baseEnvironmentConfig; + builder.Sources[3] = environmentJsonConfig; + builder.Sources[4] = environmentYmlConfig; + builder.Sources[5] = envConfig; + builder.Sources[6] = cmdLineConfig; }); var setupWizardHostBuilder = CreateDefaultBuilder() From ed0a04c4a064c6d1b88ee2424c06d8853ecbe069 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 21 Jan 2021 11:52:22 -0500 Subject: [PATCH 25/42] Serparate the DMAPI version from Interop Version --- build/Version.props | 3 ++- src/DMAPI/tgs.dm | 10 ++++------ src/DMAPI/tgs/v4/api.dm | 4 ++-- src/DMAPI/tgs/v5/api.dm | 7 ++++--- src/DMAPI/tgs/v5/interop_version.dm | 1 + src/Tgstation.Server.Api/Models/ServerInformation.cs | 2 +- .../Components/Interop/DMApiConstants.cs | 4 ++-- .../Components/Session/SessionController.cs | 4 ++-- .../Components/Session/SessionControllerFactory.cs | 2 +- .../Controllers/HomeController.cs | 2 +- src/Tgstation.Server.Host/Core/Application.cs | 2 +- .../Properties/MasterVersionsAttribute.cs | 10 +++++----- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 2 +- tests/DMAPI/BasicOperation/basic_operation_test.dme | 2 +- .../Tgstation.Server.Tests/Instance/RepositoryTest.cs | 2 +- tests/Tgstation.Server.Tests/Instance/WatchdogTest.cs | 8 ++++---- tests/Tgstation.Server.Tests/VersionsTest.cs | 9 ++++++++- tgstation-server.sln | 1 + tools/ReleaseNotes/Program.cs | 3 ++- 19 files changed, 44 insertions(+), 34 deletions(-) create mode 100644 src/DMAPI/tgs/v5/interop_version.dm diff --git a/build/Version.props b/build/Version.props index 8d1bf5b98a..4a41529110 100644 --- a/build/Version.props +++ b/build/Version.props @@ -7,7 +7,8 @@ 2.2.0 8.3.0 9.1.2 - 5.3.0 + 6.0.0 + 5.3.0 1.1.0 1.2.0 diff --git a/src/DMAPI/tgs.dm b/src/DMAPI/tgs.dm index 7ef3268322..26704ef57f 100644 --- a/src/DMAPI/tgs.dm +++ b/src/DMAPI/tgs.dm @@ -1,6 +1,6 @@ // tgstation-server DMAPI -#define TGS_DMAPI_VERSION "5.3.0" +#define TGS_DMAPI_VERSION "6.0.0" // All functions and datums outside this document are subject to change with any version and should not be relied on. @@ -144,7 +144,7 @@ #define TGS_TOPIC var/tgs_topic_return = TgsTopic(args[1]); if(tgs_topic_return) return tgs_topic_return /** - * Call this at the beginning of [world/proc/Reboot]. + * Call this as late as possible in [world/proc/Reboot]. */ /world/proc/TgsReboot() return @@ -156,7 +156,7 @@ /datum/tgs_revision_information /// Full SHA of the commit. var/commit - /// ISO8601 timestamp of the commit + /// ISO 8601 timestamp of when the commit was created var/timestamp /// Full sha of last known remote commit. This may be null if the TGS repository is not currently tracking a remote branch. var/origin_commit @@ -207,9 +207,7 @@ /// An http URL to the test merge source. var/url /// The SHA of the test merge when that was merged. - var/pull_request_commit - /// ISO 8601 timestamp of when the test merge was created on TGS. - var/time_merged + var/head_commit /// Optional comment left by the TGS user who initiated the merge. var/comment diff --git a/src/DMAPI/tgs/v4/api.dm b/src/DMAPI/tgs/v4/api.dm index 081543828e..4eb8e67d92 100644 --- a/src/DMAPI/tgs/v4/api.dm +++ b/src/DMAPI/tgs/v4/api.dm @@ -92,7 +92,7 @@ var/list/json = cached_json["testMerges"] for(var/entry in json) var/datum/tgs_revision_information/test_merge/tm = new - tm.time_merged = text2num(entry["timeMerged"]) + tm.timestamp = text2num(entry["timeMerged"]) var/list/revInfo = entry["revision"] if(revInfo) @@ -104,7 +104,7 @@ tm.url = entry["url"] tm.author = entry["author"] tm.number = entry["number"] - tm.pull_request_commit = entry["pullRequestRevision"] + tm.head_commit = entry["pullRequestRevision"] tm.comment = entry["comment"] cached_test_merges += tm diff --git a/src/DMAPI/tgs/v5/api.dm b/src/DMAPI/tgs/v5/api.dm index c5b5257fb5..65bc231e21 100644 --- a/src/DMAPI/tgs/v5/api.dm +++ b/src/DMAPI/tgs/v5/api.dm @@ -18,7 +18,9 @@ var/initialized = FALSE /datum/tgs_api/v5/ApiVersion() - return new /datum/tgs_version(TGS_DMAPI_VERSION) + return new /datum/tgs_version( + #include "interop_version.dm" + ) /datum/tgs_api/v5/OnWorldNew(minimum_required_security_level) server_port = world.params[DMAPI5_PARAM_SERVER_PORT] @@ -63,12 +65,11 @@ var/list/revInfo = entry[DMAPI5_TEST_MERGE_REVISION] if(revInfo) tm.commit = revisionData[DMAPI5_REVISION_INFORMATION_COMMIT_SHA] - tm.timestamp = revisionData[DMAPI5_REVISION_INFORMATION_TIMESTAMP] tm.origin_commit = revisionData[DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA] else TGS_WARNING_LOG("Failed to decode [DMAPI5_TEST_MERGE_REVISION] from test merge #[tm.number]!") - tm.time_merged = text2num(entry[DMAPI5_TEST_MERGE_TIME_MERGED]) + tm.timestamp = entry[DMAPI5_TEST_MERGE_TIME_MERGED] tm.title = entry[DMAPI5_TEST_MERGE_TITLE_AT_MERGE] tm.body = entry[DMAPI5_TEST_MERGE_BODY_AT_MERGE] tm.url = entry[DMAPI5_TEST_MERGE_URL] diff --git a/src/DMAPI/tgs/v5/interop_version.dm b/src/DMAPI/tgs/v5/interop_version.dm new file mode 100644 index 0000000000..c7bf62ecae --- /dev/null +++ b/src/DMAPI/tgs/v5/interop_version.dm @@ -0,0 +1 @@ +"5.3.0" diff --git a/src/Tgstation.Server.Api/Models/ServerInformation.cs b/src/Tgstation.Server.Api/Models/ServerInformation.cs index 16b7ea0732..ed0509d76b 100644 --- a/src/Tgstation.Server.Api/Models/ServerInformation.cs +++ b/src/Tgstation.Server.Api/Models/ServerInformation.cs @@ -19,7 +19,7 @@ namespace Tgstation.Server.Api.Models public Version? ApiVersion { get; set; } /// - /// The DMAPI version of the host. + /// The DMAPI interop version the server uses. /// public Version? DMApiVersion { get; set; } diff --git a/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs b/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs index c910a8a1e2..b4697d8952 100644 --- a/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs +++ b/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs @@ -32,9 +32,9 @@ namespace Tgstation.Server.Host.Components.Interop public const string TopicData = "tgs_data"; /// - /// The DMAPI being used. + /// The DMAPI being used. /// - public static readonly Version Version = Version.Parse(MasterVersionsAttribute.Instance.RawDMApiVersion); + public static readonly Version InteropVersion = Version.Parse(MasterVersionsAttribute.Instance.RawInteropVersion); /// /// for use when communicating with the DMAPI. diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index 1462b6cd50..0de14b9df4 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -66,7 +66,7 @@ namespace Tgstation.Server.Host.Components.Session public Task OnPrime => primeTcs.Task; /// - public bool DMApiAvailable => reattachInformation.Dmb.CompileJob.DMApiVersion?.Major == DMApiConstants.Version.Major; + public bool DMApiAvailable => reattachInformation.Dmb.CompileJob.DMApiVersion?.Major == DMApiConstants.InteropVersion.Major; /// /// The up to date @@ -431,7 +431,7 @@ namespace Tgstation.Server.Host.Components.Session return Error("Missing dmApiVersion field!"); DMApiVersion = parameters.Version; - if (DMApiVersion.Major != DMApiConstants.Version.Major) + if (DMApiVersion.Major != DMApiConstants.InteropVersion.Major) { apiValidationStatus = ApiValidationStatus.Incompatible; return Error("Incompatible dmApiVersion!"); diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 698510757b..41a6616835 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -229,7 +229,7 @@ namespace Tgstation.Server.Host.Components.Session // set command line options // more sanitization here cause it uses the same scheme - var parameters = $"{DMApiConstants.ParamApiVersion}={byondTopicSender.SanitizeString(DMApiConstants.Version.Semver().ToString())}&{byondTopicSender.SanitizeString(DMApiConstants.ParamServerPort)}={serverPortProvider.HttpApiPort}&{byondTopicSender.SanitizeString(DMApiConstants.ParamAccessIdentifier)}={byondTopicSender.SanitizeString(accessIdentifier)}"; + var parameters = $"{DMApiConstants.ParamApiVersion}={byondTopicSender.SanitizeString(DMApiConstants.InteropVersion.Semver().ToString())}&{byondTopicSender.SanitizeString(DMApiConstants.ParamServerPort)}={serverPortProvider.HttpApiPort}&{byondTopicSender.SanitizeString(DMApiConstants.ParamAccessIdentifier)}={byondTopicSender.SanitizeString(accessIdentifier)}"; if (!String.IsNullOrEmpty(launchParameters.AdditionalParameters)) parameters = $"{parameters}&{launchParameters.AdditionalParameters}"; diff --git a/src/Tgstation.Server.Host/Controllers/HomeController.cs b/src/Tgstation.Server.Host/Controllers/HomeController.cs index 4dcad917d2..e8302baa4b 100644 --- a/src/Tgstation.Server.Host/Controllers/HomeController.cs +++ b/src/Tgstation.Server.Host/Controllers/HomeController.cs @@ -198,7 +198,7 @@ namespace Tgstation.Server.Host.Controllers { Version = assemblyInformationProvider.Version, ApiVersion = ApiHeaders.Version, - DMApiVersion = DMApiConstants.Version, + DMApiVersion = DMApiConstants.InteropVersion, MinimumPasswordLength = generalConfiguration.MinimumPasswordLength, InstanceLimit = generalConfiguration.InstanceLimit, UserLimit = generalConfiguration.UserLimit, diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 8d0a203961..f16e31fe9c 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -492,7 +492,7 @@ namespace Tgstation.Server.Host.Core // End of request pipeline setup var masterVersionsAttribute = MasterVersionsAttribute.Instance; logger.LogTrace("Configuration version: {0}", masterVersionsAttribute.RawConfigurationVersion); - logger.LogTrace("DMAPI version: {0}", masterVersionsAttribute.RawDMApiVersion); + logger.LogTrace("DMAPI Interop version: {0}", masterVersionsAttribute.RawInteropVersion); logger.LogTrace("Web control panel version: {0}", masterVersionsAttribute.RawControlPanelVersion); logger.LogDebug("Starting hosting on port {0}...", serverPortProvider.HttpApiPort); diff --git a/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs b/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs index 20cc04786c..62875303b3 100644 --- a/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs +++ b/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs @@ -22,9 +22,9 @@ namespace Tgstation.Server.Host.Properties public string RawConfigurationVersion { get; } /// - /// The of the DMAPI version built. + /// The of the DMAPI interop version used. /// - public string RawDMApiVersion { get; } + public string RawInteropVersion { get; } /// /// The of the control panel version built. @@ -35,15 +35,15 @@ namespace Tgstation.Server.Host.Properties /// Initializes a new instance of the . /// /// The value of . - /// The value of . + /// The value of . /// The value of . public MasterVersionsAttribute( string rawConfigurationVersion, - string rawDMApiVersion, + string rawInteropVersion, string rawControlPanelVersion) { RawConfigurationVersion = rawConfigurationVersion ?? throw new ArgumentNullException(nameof(rawConfigurationVersion)); - RawDMApiVersion = rawDMApiVersion ?? throw new ArgumentNullException(nameof(rawDMApiVersion)); + RawInteropVersion = rawInteropVersion ?? throw new ArgumentNullException(nameof(rawInteropVersion)); RawControlPanelVersion = rawControlPanelVersion ?? throw new ArgumentNullException(nameof(rawControlPanelVersion)); } } diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 3951c10411..7533898170 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -49,7 +49,7 @@ <_Parameter1>$(TgsConfigVersion) - <_Parameter2>$(TgsDmapiVersion) + <_Parameter2>$(TgsInteropVersion) <_Parameter3>$(TgsControlPanelVersion) diff --git a/tests/DMAPI/BasicOperation/basic_operation_test.dme b/tests/DMAPI/BasicOperation/basic_operation_test.dme index 92781c7e16..9f50643e42 100644 --- a/tests/DMAPI/BasicOperation/basic_operation_test.dme +++ b/tests/DMAPI/BasicOperation/basic_operation_test.dme @@ -12,6 +12,6 @@ // BEGIN_INCLUDE #include "Config.dm" -#include "..\tgs_include.dm" #include "Test.dm" +#include "S:\Documents\Actual Documents\DA Git\tgstation-server\tests\DMAPI\tgs_include.dm" // END_INCLUDE diff --git a/tests/Tgstation.Server.Tests/Instance/RepositoryTest.cs b/tests/Tgstation.Server.Tests/Instance/RepositoryTest.cs index 52918f5e76..f83c916ad6 100644 --- a/tests/Tgstation.Server.Tests/Instance/RepositoryTest.cs +++ b/tests/Tgstation.Server.Tests/Instance/RepositoryTest.cs @@ -64,7 +64,7 @@ namespace Tgstation.Server.Tests.Instance clone = await repositoryClient.Clone(initalRepo, cancellationToken).ConfigureAwait(false); - await WaitForJob(clone.ActiveJob, 900, false, null, cancellationToken).ConfigureAwait(false); + await WaitForJob(clone.ActiveJob, 9000, false, null, cancellationToken).ConfigureAwait(false); var readAfterClone = await repositoryClient.Read(cancellationToken); Assert.AreEqual(initalRepo.Origin, readAfterClone.Origin); diff --git a/tests/Tgstation.Server.Tests/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Instance/WatchdogTest.cs index 7203d1c646..5cd9871d7b 100644 --- a/tests/Tgstation.Server.Tests/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Instance/WatchdogTest.cs @@ -144,7 +144,7 @@ namespace Tgstation.Server.Tests.Instance Assert.IsNotNull(newerCompileJob); Assert.AreNotEqual(initialCompileJob.Id, newerCompileJob.Id); Assert.AreEqual(DreamDaemonSecurity.Safe, newerCompileJob.MinimumSecurityLevel); - Assert.AreEqual(DMApiConstants.Version, daemonStatus.StagedCompileJob.DMApiVersion); + Assert.AreEqual(DMApiConstants.InteropVersion, daemonStatus.StagedCompileJob.DMApiVersion); await instanceClient.DreamDaemon.Shutdown(cancellationToken); } @@ -162,7 +162,7 @@ namespace Tgstation.Server.Tests.Instance Assert.AreEqual(WatchdogStatus.Offline, daemonStatus.Status.Value); Assert.IsNotNull(daemonStatus.ActiveCompileJob); Assert.IsNull(daemonStatus.StagedCompileJob); - Assert.AreEqual(DMApiConstants.Version, daemonStatus.ActiveCompileJob.DMApiVersion); + Assert.AreEqual(DMApiConstants.InteropVersion, daemonStatus.ActiveCompileJob.DMApiVersion); Assert.AreEqual(DreamDaemonSecurity.Safe, daemonStatus.ActiveCompileJob.MinimumSecurityLevel); Job startJob; @@ -307,7 +307,7 @@ namespace Tgstation.Server.Tests.Instance Assert.AreEqual(WatchdogStatus.Offline, daemonStatus.Status.Value); Assert.IsNotNull(daemonStatus.ActiveCompileJob); Assert.IsNull(daemonStatus.StagedCompileJob); - Assert.AreEqual(DMApiConstants.Version, daemonStatus.ActiveCompileJob.DMApiVersion); + Assert.AreEqual(DMApiConstants.InteropVersion, daemonStatus.ActiveCompileJob.DMApiVersion); Assert.AreEqual(DreamDaemonSecurity.Ultrasafe, daemonStatus.ActiveCompileJob.MinimumSecurityLevel); var startJob = await StartDD(cancellationToken).ConfigureAwait(false); @@ -347,7 +347,7 @@ namespace Tgstation.Server.Tests.Instance Assert.AreEqual(WatchdogStatus.Offline, daemonStatus.Status.Value); Assert.IsNotNull(daemonStatus.ActiveCompileJob); Assert.IsNull(daemonStatus.StagedCompileJob); - Assert.AreEqual(DMApiConstants.Version, daemonStatus.ActiveCompileJob.DMApiVersion); + Assert.AreEqual(DMApiConstants.InteropVersion, daemonStatus.ActiveCompileJob.DMApiVersion); Assert.AreEqual(DreamDaemonSecurity.Ultrasafe, daemonStatus.ActiveCompileJob.MinimumSecurityLevel); var startJob = await StartDD(cancellationToken).ConfigureAwait(false); diff --git a/tests/Tgstation.Server.Tests/VersionsTest.cs b/tests/Tgstation.Server.Tests/VersionsTest.cs index 1a1cf908da..6c3a0efa4f 100644 --- a/tests/Tgstation.Server.Tests/VersionsTest.cs +++ b/tests/Tgstation.Server.Tests/VersionsTest.cs @@ -99,7 +99,14 @@ namespace Tgstation.Server.Tests Assert.IsTrue(Version.TryParse(versionLine, out var actual)); Assert.AreEqual(expected, actual); - Assert.AreEqual(expected, DMApiConstants.Version); + } + + public void TestInteropVersion() + { + var versionString = versionsPropertyGroup.Element(xmlNamespace + "TgsInteropVersion").Value; + Assert.IsNotNull(versionString); + Assert.IsTrue(Version.TryParse(versionString, out var expected)); + Assert.AreEqual(expected, DMApiConstants.InteropVersion); } [TestMethod] diff --git a/tgstation-server.sln b/tgstation-server.sln index 32dabe36ba..6ff1e7bb44 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -135,6 +135,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "v5", "v5", "{FAEAD3B5-2EAB- src\DMAPI\tgs\v5\_defines.dm = src\DMAPI\tgs\v5\_defines.dm src\DMAPI\tgs\v5\api.dm = src\DMAPI\tgs\v5\api.dm src\DMAPI\tgs\v5\commands.dm = src\DMAPI\tgs\v5\commands.dm + src\DMAPI\tgs\v5\interop_version.dm = src\DMAPI\tgs\v5\interop_version.dm src\DMAPI\tgs\v5\README.md = src\DMAPI\tgs\v5\README.md src\DMAPI\tgs\v5\undefs.dm = src\DMAPI\tgs\v5\undefs.dm EndProjectSection diff --git a/tools/ReleaseNotes/Program.cs b/tools/ReleaseNotes/Program.cs index 7477895cdf..8522b4066b 100644 --- a/tools/ReleaseNotes/Program.cs +++ b/tools/ReleaseNotes/Program.cs @@ -256,13 +256,14 @@ namespace ReleaseNotes var apiVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsApiVersion").Value); var configVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsConfigVersion").Value); var dmApiVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsDmapiVersion").Value); + var interopVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsInteropVersion").Value); var webControlVersion = Version.Parse(controlPanelVersionsPropertyGroup.Element(controlPanelXmlNamespace + "TgsControlPanelVersion").Value); var hostWatchdogVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsHostWatchdogVersion").Value); if (webControlVersion.Major == 0) postControlPanelMessage = true; - prefix = $"Please refer to the [README](https://github.com/tgstation/tgstation-server#setup) for setup instructions.{Environment.NewLine}{Environment.NewLine}#### Component Versions\nCore: {coreVersion}\nConfiguration: {configVersion}\nHTTP API: {apiVersion}\nDreamMaker API: {dmApiVersion}\n[Web Control Panel](https://github.com/tgstation/tgstation-server-control-panel): {webControlVersion}\nHost Watchdog: {hostWatchdogVersion}"; + prefix = $"Please refer to the [README](https://github.com/tgstation/tgstation-server#setup) for setup instructions.{Environment.NewLine}{Environment.NewLine}#### Component Versions\nCore: {coreVersion}\nConfiguration: {configVersion}\nHTTP API: {apiVersion}\nDreamMaker API: {dmApiVersion} (Interop: {interopVersion})\n[Web Control Panel](https://github.com/tgstation/tgstation-server-control-panel): {webControlVersion}\nHost Watchdog: {hostWatchdogVersion}"; break; case 3: prefix = "The /tg/station server suite"; From 59750f632d9e87848fb65421f8a8a2e41d1fbf0c Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 21 Jan 2021 12:26:42 -0500 Subject: [PATCH 26/42] Suppress a bad IDE warning --- .../Extensions/TestServiceCollectionExtensions.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Host.Tests/Extensions/TestServiceCollectionExtensions.cs b/tests/Tgstation.Server.Host.Tests/Extensions/TestServiceCollectionExtensions.cs index 67004ad997..09c2bd502d 100644 --- a/tests/Tgstation.Server.Host.Tests/Extensions/TestServiceCollectionExtensions.cs +++ b/tests/Tgstation.Server.Host.Tests/Extensions/TestServiceCollectionExtensions.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -16,7 +16,9 @@ namespace Tgstation.Server.Host.Extensions.Tests class BadConfig1 { +#pragma warning disable IDE0051 // Remove unused private members const string Section = "asdf"; +#pragma warning restore IDE0051 // Remove unused private members } class BadConfig2 From 7055a3879649382ba87d97639f48ca708c04fa24 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 21 Jan 2021 12:42:56 -0500 Subject: [PATCH 27/42] Modernizes and adds YAML support to VersionConverter --- .../Extensions/Converters/VersionConverter.cs | 70 +++++++++++++++++-- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/Converters/VersionConverter.cs b/src/Tgstation.Server.Host/Extensions/Converters/VersionConverter.cs index 9d5ebeec77..3c18ce50e8 100644 --- a/src/Tgstation.Server.Host/Extensions/Converters/VersionConverter.cs +++ b/src/Tgstation.Server.Host/Extensions/Converters/VersionConverter.cs @@ -1,14 +1,35 @@ using Newtonsoft.Json; using System; using Tgstation.Server.Api; +using YamlDotNet.Core; +using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; namespace Tgstation.Server.Host.Extensions.Converters { /// - /// for serializing s for BYOND. + /// and for serializing s for BYOND. /// - sealed class VersionConverter : JsonConverter + sealed class VersionConverter : JsonConverter, IYamlTypeConverter { + /// + /// Check if the supports (de)serializing a given . + /// + /// The to check. + /// If the method should if validation fails. + /// if is a , otherwise. + static bool CheckSupportsType(Type type, bool validate) + { + if (type == null) + throw new ArgumentNullException(nameof(type)); + + var supported = type == typeof(global::System.Version); + if (!supported && validate) + throw new NotSupportedException($"{nameof(VersionConverter)} does not convert {type}s!"); + + return supported; + } + /// public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { @@ -16,7 +37,7 @@ namespace Tgstation.Server.Host.Extensions.Converters { writer.WriteNull(); } - else if (value is Version version) + else if (value is global::System.Version version) { writer.WriteValue(version.Semver().ToString()); } @@ -29,6 +50,11 @@ namespace Tgstation.Server.Host.Extensions.Converters /// public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { + if (reader == null) + throw new ArgumentNullException(nameof(reader)); + + CheckSupportsType(objectType, true); + if (reader.TokenType == JsonToken.Null) return null; @@ -36,7 +62,7 @@ namespace Tgstation.Server.Host.Extensions.Converters { try { - Version v = new Version((string)reader.Value); + var v = global::System.Version.Parse((string)reader.Value); return v.Semver(); } catch (Exception ex) @@ -50,6 +76,40 @@ namespace Tgstation.Server.Host.Extensions.Converters } /// - public override bool CanConvert(Type objectType) => objectType == typeof(Version); + public override bool CanConvert(Type objectType) => CheckSupportsType(objectType, false); + + /// + public bool Accepts(Type type) => CheckSupportsType(type, false); + + /// + public object ReadYaml(IParser parser, Type type) + { + if (parser == null) + throw new ArgumentNullException(nameof(parser)); + + CheckSupportsType(type, true); + + var scalar = parser.Consume(); + if (scalar == null) + return null; + + return global::System.Version.Parse(scalar.Value); + } + + /// + public void WriteYaml(IEmitter emitter, object value, Type type) + { + if (emitter == null) + throw new ArgumentNullException(nameof(emitter)); + + CheckSupportsType(type, true); + + var version = (global::System.Version)value; + emitter.Emit( + new Scalar( + version + ?.Semver() + .ToString())); + } } } From caec6e95471ef4c32433fb5963ee9fd4cdeb077b Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 21 Jan 2021 12:43:09 -0500 Subject: [PATCH 28/42] YAML unit tests for VersionConverter --- .../Converters/TestVersionConverter.cs | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 tests/Tgstation.Server.Host.Tests/Extensions/Converters/TestVersionConverter.cs diff --git a/tests/Tgstation.Server.Host.Tests/Extensions/Converters/TestVersionConverter.cs b/tests/Tgstation.Server.Host.Tests/Extensions/Converters/TestVersionConverter.cs new file mode 100644 index 0000000000..a650c0e97f --- /dev/null +++ b/tests/Tgstation.Server.Host.Tests/Extensions/Converters/TestVersionConverter.cs @@ -0,0 +1,52 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using Tgstation.Server.Api; +using YamlDotNet.Serialization; + +namespace Tgstation.Server.Host.Extensions.Converters.Tests +{ + [TestClass] + public sealed class TestVersionConverter + { + class TestObject + { + public Version Version { get; set; } + } + + readonly Version testVersion; + readonly string testYaml; + + public TestVersionConverter() + { + testVersion = new Version(1, 2, 3); + testYaml = $@"{nameof(TestObject.Version)}: {testVersion.Semver()}"; + } + + [TestMethod] + public void TestYamlSerialization() + { + var testObj = new TestObject + { + Version = testVersion + }; + + var serializedString = new SerializerBuilder() + .WithTypeConverter(new VersionConverter()) + .Build() + .Serialize(testObj); + + Assert.AreEqual(testYaml, serializedString.Trim()); + } + + [TestMethod] + public void TestYamlDeserialization() + { + var deserialized = new DeserializerBuilder() + .WithTypeConverter(new VersionConverter()) + .Build() + .Deserialize(testYaml); + + Assert.AreEqual(testVersion, deserialized.Version); + } + } +} From 91bf7e7f1c693ff35c7199dd9f4c618d226d1183 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 21 Jan 2021 12:44:27 -0500 Subject: [PATCH 29/42] Properly serializes General:ConfigVersion in setup --- src/Tgstation.Server.Host/Setup/SetupWizard.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index 0f2beb86d4..af806cab3f 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -19,6 +19,7 @@ using System.Threading.Tasks; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Core; using Tgstation.Server.Host.Database; +using Tgstation.Server.Host.Extensions.Converters; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.System; using YamlDotNet.Serialization; @@ -841,7 +842,9 @@ namespace Tgstation.Server.Host.Setup { SwarmConfiguration.Section, swarmConfiguration }, }; - var serializer = new SerializerBuilder().Build(); + var serializer = new SerializerBuilder() + .WithTypeConverter(new VersionConverter()) + .Build(); var serializedYaml = serializer.Serialize(map); From 22ea6d24345d212c25b108b96ea3ef53739e3a77 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 21 Jan 2021 14:59:30 -0500 Subject: [PATCH 30/42] Revert the basepath change Pretty certain this is needed to make production configs work --- src/Tgstation.Server.Host/ServerFactory.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/ServerFactory.cs b/src/Tgstation.Server.Host/ServerFactory.cs index a273d1507c..e739d5c75f 100644 --- a/src/Tgstation.Server.Host/ServerFactory.cs +++ b/src/Tgstation.Server.Host/ServerFactory.cs @@ -49,7 +49,10 @@ namespace Tgstation.Server.Host var basePath = IOManager.ResolvePath(); IHostBuilder CreateDefaultBuilder() => Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args) - .ConfigureAppConfiguration((context, builder) => { + .ConfigureAppConfiguration((context, builder) => + { + builder.SetBasePath(basePath); + builder.AddYamlFile("appsettings.yml", optional: true, reloadOnChange: true) .AddYamlFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.yml", optional: true, reloadOnChange: true); // reorganize the builder so our yaml configs don't override the env/cmdline configs From eed120ed098126078fa50b763a37b3fe0969189b Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 21 Jan 2021 15:01:00 -0500 Subject: [PATCH 31/42] Remove stray #include --- tests/DMAPI/BasicOperation/basic_operation_test.dme | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/DMAPI/BasicOperation/basic_operation_test.dme b/tests/DMAPI/BasicOperation/basic_operation_test.dme index 9f50643e42..52b9c46b7c 100644 --- a/tests/DMAPI/BasicOperation/basic_operation_test.dme +++ b/tests/DMAPI/BasicOperation/basic_operation_test.dme @@ -13,5 +13,4 @@ // BEGIN_INCLUDE #include "Config.dm" #include "Test.dm" -#include "S:\Documents\Actual Documents\DA Git\tgstation-server\tests\DMAPI\tgs_include.dm" // END_INCLUDE From 9dfe6e0fefab4a9a58c693e4c0a486fbd0368e27 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 21 Jan 2021 15:09:53 -0500 Subject: [PATCH 32/42] Fix compile errors --- src/DMAPI/tgs/v5/api.dm | 2 +- tests/DMAPI/BasicOperation/basic_operation_test.dme | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/DMAPI/tgs/v5/api.dm b/src/DMAPI/tgs/v5/api.dm index 65bc231e21..dfa1b6f948 100644 --- a/src/DMAPI/tgs/v5/api.dm +++ b/src/DMAPI/tgs/v5/api.dm @@ -74,7 +74,7 @@ tm.body = entry[DMAPI5_TEST_MERGE_BODY_AT_MERGE] tm.url = entry[DMAPI5_TEST_MERGE_URL] tm.author = entry[DMAPI5_TEST_MERGE_AUTHOR] - tm.pull_request_commit = entry[DMAPI5_TEST_MERGE_PULL_REQUEST_REVISION] + tm.head_commit = entry[DMAPI5_TEST_MERGE_PULL_REQUEST_REVISION] tm.comment = entry[DMAPI5_TEST_MERGE_COMMENT] test_merges += tm diff --git a/tests/DMAPI/BasicOperation/basic_operation_test.dme b/tests/DMAPI/BasicOperation/basic_operation_test.dme index 52b9c46b7c..92781c7e16 100644 --- a/tests/DMAPI/BasicOperation/basic_operation_test.dme +++ b/tests/DMAPI/BasicOperation/basic_operation_test.dme @@ -12,5 +12,6 @@ // BEGIN_INCLUDE #include "Config.dm" +#include "..\tgs_include.dm" #include "Test.dm" // END_INCLUDE From c352fc6f3eebf242ecec041e9244929f205694f9 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 21 Jan 2021 15:10:16 -0500 Subject: [PATCH 33/42] Update .gitignore with DM artifacts --- .gitignore | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index c09ef4b2ac..b9e643ec76 100644 --- a/.gitignore +++ b/.gitignore @@ -11,9 +11,9 @@ artifacts/ *DS_Store *.sln.ide /TestResults -/tests/DMAPI/travistester.lk -/tests/DMAPI/travistester.int -/tests/DMAPI/travistester.dmb +*.dmb +*.int +*.lk /src/Tgstation.Server.Host/appsettings.*.json /src/Tgstation.Server.Host/wwwroot /src/Tgstation.Server.Host/ClientApp From 2e92b8dea1e09bfb5fd8b4893a28e485c6e75055 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 21 Jan 2021 16:21:49 -0500 Subject: [PATCH 34/42] More missed references to appsettings.json --- .dockerignore | 1 + .github/CONTRIBUTING.md | 2 +- src/Tgstation.Server.Host/Setup/SetupWizardMode.cs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.dockerignore b/.dockerignore index de4eb887ed..4a54e2617a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -26,6 +26,7 @@ src/DMAPI src/Tgstation.Server.Host/ClientApp src/Tgstation.Server.Host/wwwroot src/Tgstation.Server.Host/appsettings.Development.json +src/Tgstation.Server.Host/appsettings.Development.yml src/Tgstation.Server.Host/tgs.bat src/Tgstation.Server.Host/tgs.sh src/Tgstation.Server.Client diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 96eb6e3108..a096c248c4 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -197,7 +197,7 @@ OAuth providers are hardcoded but it is fairly easy to add new ones. The flow do 1. Create an implementation of [IOAuthValidator](../src/Tgstation.Server.Host/Security/OAuth/IOAuthValidator.cs). - Most providers can simply override the [GenericOAuthValidator](../src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs). 1. Construct the implementation in the [OAuthProviders](../src/Tgstation.Server.Host/Security/OAuth/OAuthProviders.cs) class. -1. Add a null entry to the default [appsettings.json](../src/Tgstation.Server.Host/appsettings.json). +1. Add a null entry to the default [appsettings.yml](../src/Tgstation.Server.Host/appsettings.yml). 1. Update the main [README.md](../README.md) to indicate the new provider. 1. Update the [API documentation](../docs/API.dox) to indicate the new provider. diff --git a/src/Tgstation.Server.Host/Setup/SetupWizardMode.cs b/src/Tgstation.Server.Host/Setup/SetupWizardMode.cs index 8d0798b88f..2de9926e82 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizardMode.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizardMode.cs @@ -6,7 +6,7 @@ namespace Tgstation.Server.Host.Setup public enum SetupWizardMode { /// - /// Run the wizard if the appsettings.{Environment}.json is not present or empty. + /// Run the wizard if the appsettings.{Environment}.yml is not present or empty. /// Autodetect, From 9aa4bd0c8ca3d2d23fcf8eef1d972c593c8b06aa Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Thu, 21 Jan 2021 16:22:05 -0500 Subject: [PATCH 35/42] Remove Console debug line that broke logic --- src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs b/src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs index 933b129983..9c4f6dab09 100644 --- a/src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs @@ -42,7 +42,6 @@ namespace Tgstation.Server.Host.Database mySqlOptions.EnableRetryOnFailure(); if (!String.IsNullOrEmpty(databaseConfiguration.ServerVersion)) - Console.WriteLine("SQLVERSION: " + databaseConfiguration.DatabaseType); mySqlOptions.ServerVersion( Version.Parse(databaseConfiguration.ServerVersion), databaseConfiguration.DatabaseType == DatabaseType.MariaDB From 108e4ed274eadc12d4ad39e89d2183da5c0db8a1 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Fri, 22 Jan 2021 10:12:49 -0500 Subject: [PATCH 36/42] Fix `-public` always being set in DD command line --- .../Components/Session/SessionControllerFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 41a6616835..1cc3960a7a 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -240,7 +240,7 @@ namespace Tgstation.Server.Host.Components.Session Guid? logFileGuid = null; var arguments = String.Format( CultureInfo.InvariantCulture, - "{0} -port {1} -ports 1-65535 {2}-close -{3} -{4}{5} -public -params \"{6}\"", + "{0} -port {1} -ports 1-65535 {2}-close -{3} -{4}{5} -params \"{6}\"", dmbProvider.DmbName, launchParameters.Port.Value, launchParameters.AllowWebClient.Value ? "-webclient " : String.Empty, From badd6dca8dced1c78382701830c94cddcc48b3f8 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Fri, 22 Jan 2021 10:23:04 -0500 Subject: [PATCH 37/42] Fix DMAPI test version comparison --- tests/DMAPI/BasicOperation/Test.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/DMAPI/BasicOperation/Test.dm b/tests/DMAPI/BasicOperation/Test.dm index bd8fedaa91..cac9cab680 100644 --- a/tests/DMAPI/BasicOperation/Test.dm +++ b/tests/DMAPI/BasicOperation/Test.dm @@ -15,9 +15,9 @@ world.TgsTargetedChatBroadcast("Sample admin-only message", TRUE) world.log << "Validating API sleep" - // Validate TGS_DMAPI_VERSION against DMAPI version used + // Validate current DMAPI version against DMAPI version used var/datum/tgs_version/active_version = world.TgsApiVersion() - var/datum/tgs_version/dmapi_version = new /datum/tgs_version(TGS_DMAPI_VERSION) + var/datum/tgs_version/dmapi_version = world.TgsMaximumApiVersion() if(!active_version.Equals(dmapi_version)) text2file("DMAPI version [TGS_DMAPI_VERSION] does not match active API version [active_version.raw_parameter]", "test_fail_reason.txt") From 44b6057d0155019f8bfb8958f3d735e38faaef0b Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Fri, 22 Jan 2021 10:44:34 -0500 Subject: [PATCH 38/42] Improve capitalization on Maximum and Minimum DMAPI versions --- src/DMAPI/tgs.dm | 4 ++-- src/DMAPI/tgs/core/core.dm | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/DMAPI/tgs.dm b/src/DMAPI/tgs.dm index 26704ef57f..a8d824a797 100644 --- a/src/DMAPI/tgs.dm +++ b/src/DMAPI/tgs.dm @@ -267,11 +267,11 @@ // API FUNCTIONS /// Returns the maximum supported [/datum/tgs_version] of the DMAPI. -/world/proc/TgsMaximumAPIVersion() +/world/proc/TgsMaximumApiVersion() return /// Returns the minimum supported [/datum/tgs_version] of the DMAPI. -/world/proc/TgsMinimumAPIVersion() +/world/proc/TgsMinimumApiVersion() return /** diff --git a/src/DMAPI/tgs/core/core.dm b/src/DMAPI/tgs/core/core.dm index f75e7837af..41a0473394 100644 --- a/src/DMAPI/tgs/core/core.dm +++ b/src/DMAPI/tgs/core/core.dm @@ -40,7 +40,7 @@ if(5) api_datum = /datum/tgs_api/v5 - var/datum/tgs_version/max_api_version = TgsMaximumAPIVersion(); + var/datum/tgs_version/max_api_version = TgsMaximumApiVersion(); if(version.suite != null && version.minor != null && version.patch != null && version.deprecated_patch != null && version.deprefixed_parameter > max_api_version.deprefixed_parameter) TGS_ERROR_LOG("Detected unknown API version! Defaulting to latest. Update the DMAPI to fix this problem.") api_datum = /datum/tgs_api/latest @@ -64,10 +64,10 @@ TGS_WRITE_GLOBAL(tgs, null) TGS_ERROR_LOG("Failed to activate API!") -/world/TgsMaximumAPIVersion() +/world/TgsMaximumApiVersion() return new /datum/tgs_version("5.x.x") -/world/TgsMinimumAPIVersion() +/world/TgsMinimumApiVersion() return new /datum/tgs_version("3.2.x") /world/TgsInitializationComplete() From 99f8129db786f427dcfe77e9014a4af675b01b3b Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Fri, 22 Jan 2021 10:45:01 -0500 Subject: [PATCH 39/42] Remove unneeded DMAPI version test --- tests/DMAPI/BasicOperation/Test.dm | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/DMAPI/BasicOperation/Test.dm b/tests/DMAPI/BasicOperation/Test.dm index cac9cab680..23dbc6295c 100644 --- a/tests/DMAPI/BasicOperation/Test.dm +++ b/tests/DMAPI/BasicOperation/Test.dm @@ -14,13 +14,6 @@ sleep(50) world.TgsTargetedChatBroadcast("Sample admin-only message", TRUE) - world.log << "Validating API sleep" - // Validate current DMAPI version against DMAPI version used - var/datum/tgs_version/active_version = world.TgsApiVersion() - var/datum/tgs_version/dmapi_version = world.TgsMaximumApiVersion() - if(!active_version.Equals(dmapi_version)) - text2file("DMAPI version [TGS_DMAPI_VERSION] does not match active API version [active_version.raw_parameter]", "test_fail_reason.txt") - var/list/world_params = params2list(world.params) if(!("test" in world_params) || world_params["test"] != "bababooey") text2file("Expected parameter test=bababooey but did not receive", "test_fail_reason.txt") From 741e752450a00047041f3beea598b038ffcdf455 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Fri, 22 Jan 2021 13:29:02 -0500 Subject: [PATCH 40/42] Add missing [TestMethod] --- tests/Tgstation.Server.Tests/VersionsTest.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Tgstation.Server.Tests/VersionsTest.cs b/tests/Tgstation.Server.Tests/VersionsTest.cs index 6c3a0efa4f..a7fde50140 100644 --- a/tests/Tgstation.Server.Tests/VersionsTest.cs +++ b/tests/Tgstation.Server.Tests/VersionsTest.cs @@ -101,6 +101,7 @@ namespace Tgstation.Server.Tests Assert.AreEqual(expected, actual); } + [TestMethod] public void TestInteropVersion() { var versionString = versionsPropertyGroup.Element(xmlNamespace + "TgsInteropVersion").Value; From 6351229037b2c56b92386d5c182ebf8987fa6677 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Fri, 22 Jan 2021 14:00:52 -0500 Subject: [PATCH 41/42] Version bump to 4.8.0 --- build/Version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Version.props b/build/Version.props index 897d100a57..5aa8c48b9b 100644 --- a/build/Version.props +++ b/build/Version.props @@ -3,7 +3,7 @@ - 4.7.3 + 4.8.0 2.3.0 8.3.0 9.1.2 From 7fcb999ddfd71d2debc9bb95c4db2a3b1283fa95 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Fri, 22 Jan 2021 14:01:59 -0500 Subject: [PATCH 42/42] Client version bump to 9.2.0 --- build/Version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Version.props b/build/Version.props index 5aa8c48b9b..a9aeadfbdf 100644 --- a/build/Version.props +++ b/build/Version.props @@ -6,7 +6,7 @@ 4.8.0 2.3.0 8.3.0 - 9.1.2 + 9.2.0 6.0.0 5.3.0 1.1.1