diff --git a/src/DMAPI/tgs.dm b/src/DMAPI/tgs.dm
index 4493aef72c..d0cf1618a6 100644
--- a/src/DMAPI/tgs.dm
+++ b/src/DMAPI/tgs.dm
@@ -95,6 +95,8 @@
#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
+// #define TGS_EVENT_WATCHDOG_LAUNCH 17
// OTHER ENUMS
diff --git a/src/Tgstation.Server.Api/Models/Internal/RevisionInformation.cs b/src/Tgstation.Server.Api/Models/Internal/RevisionInformation.cs
index efdb763aa2..1ee31b1993 100644
--- a/src/Tgstation.Server.Api/Models/Internal/RevisionInformation.cs
+++ b/src/Tgstation.Server.Api/Models/Internal/RevisionInformation.cs
@@ -11,14 +11,14 @@ namespace Tgstation.Server.Api.Models.Internal
/// The revision sha
///
[Required]
- [StringLength(40)]
+ [StringLength(Limits.MaximumCommitShaLength)]
public string? CommitSha { get; set; }
///
/// The sha of the most recent remote commit
///
[Required]
- [StringLength(40)]
+ [StringLength(Limits.MaximumCommitShaLength)]
public string? OriginCommitSha { get; set; }
}
}
diff --git a/src/Tgstation.Server.Api/Models/Limits.cs b/src/Tgstation.Server.Api/Models/Limits.cs
index be61530fe7..249ecd0763 100644
--- a/src/Tgstation.Server.Api/Models/Limits.cs
+++ b/src/Tgstation.Server.Api/Models/Limits.cs
@@ -14,5 +14,10 @@
/// Length limit for s.
///
public const int MaximumIndexableStringLength = 100;
+
+ ///
+ /// Length limit for git commit SHAs.
+ ///
+ public const int MaximumCommitShaLength = 40;
}
}
\ No newline at end of file
diff --git a/src/Tgstation.Server.Api/Models/Repository.cs b/src/Tgstation.Server.Api/Models/Repository.cs
index 26a3e1fa46..88b53ab95c 100644
--- a/src/Tgstation.Server.Api/Models/Repository.cs
+++ b/src/Tgstation.Server.Api/Models/Repository.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
namespace Tgstation.Server.Api.Models
{
@@ -12,9 +13,15 @@ namespace Tgstation.Server.Api.Models
///
public string? Origin { get; set; }
+ ///
+ /// If submodules should be recursively cloned.
+ ///
+ public bool? RecurseSubmodules { get; set; }
+
///
/// The commit HEAD should point to. Not populated in responses, use instead for retrieval
///
+ [StringLength(Limits.MaximumCommitShaLength)]
public string? CheckoutSha { get; set; }
///
@@ -45,6 +52,7 @@ namespace Tgstation.Server.Api.Models
///
/// The branch or tag HEAD points to
///
+ [StringLength(Limits.MaximumStringLength)]
public string? Reference { get; set; }
///
diff --git a/src/Tgstation.Server.Client/Components/InstanceClient.cs b/src/Tgstation.Server.Client/Components/InstanceClient.cs
index 2bf76eca71..f5f31907ec 100644
--- a/src/Tgstation.Server.Client/Components/InstanceClient.cs
+++ b/src/Tgstation.Server.Client/Components/InstanceClient.cs
@@ -33,19 +33,16 @@ namespace Tgstation.Server.Client.Components
///
public IJobsClient Jobs { get; }
- ///
- /// The for the
- ///
- readonly IApiClient apiClient;
-
///
/// Construct a
///
- /// The value of
+ /// The used to construct component clients.
/// The value of
public InstanceClient(IApiClient apiClient, Instance instance)
{
- this.apiClient = apiClient ?? throw new ArgumentNullException(nameof(apiClient));
+ if (apiClient == null)
+ throw new ArgumentNullException(nameof(apiClient));
+
Metadata = instance ?? throw new ArgumentNullException(nameof(instance));
Byond = new ByondClient(apiClient, instance);
diff --git a/src/Tgstation.Server.Host/Components/Events/EventType.cs b/src/Tgstation.Server.Host/Components/Events/EventType.cs
index 419fb9ec3b..9b648382c9 100644
--- a/src/Tgstation.Server.Host/Components/Events/EventType.cs
+++ b/src/Tgstation.Server.Host/Components/Events/EventType.cs
@@ -106,5 +106,11 @@
///
[EventScript("WatchdogDetach")]
WatchdogDetach,
+
+ ///
+ /// Before the watchdog launches. No parameters.
+ ///
+ [EventScript("WatchdogLaunch")]
+ WatchdogLaunch
}
}
diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs
index 15876d33cd..cad5c38fa7 100644
--- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs
+++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs
@@ -250,6 +250,7 @@ namespace Tgstation.Server.Host.Components
sessionControllerFactory,
gameIoManager,
diagnosticsIOManager,
+ eventConsumer,
metadata.CloneMetadata(),
metadata.DreamDaemonSettings);
eventConsumer.SetWatchdog(watchdog);
diff --git a/src/Tgstation.Server.Host/Components/Repository/IRepositoryManager.cs b/src/Tgstation.Server.Host/Components/Repository/IRepositoryManager.cs
index 2f9c59df69..06bf3fb467 100644
--- a/src/Tgstation.Server.Host/Components/Repository/IRepositoryManager.cs
+++ b/src/Tgstation.Server.Host/Components/Repository/IRepositoryManager.cs
@@ -15,7 +15,7 @@ namespace Tgstation.Server.Host.Components.Repository
bool InUse { get; }
///
- /// If a operation is in progress
+ /// If a operation is in progress.
///
bool CloneInProgress { get; }
@@ -34,9 +34,17 @@ namespace Tgstation.Server.Host.Components.Repository
/// The username to clone from
/// The password to clone from
/// A function to report 0-100 progress of the clone
+ /// If submodules should be recusively cloned and initialized.
/// The for the operation
/// The newly cloned , if one already exists
- Task CloneRepository(Uri url, string initialBranch, string username, string password, Action progressReporter, CancellationToken cancellationToken);
+ Task CloneRepository(
+ Uri url,
+ string initialBranch,
+ string username,
+ string password,
+ Action progressReporter,
+ bool recurseSubmodules,
+ CancellationToken cancellationToken);
///
/// Delete the current repository
diff --git a/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs b/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs
index 4c5fefc314..55c19fdc82 100644
--- a/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs
+++ b/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs
@@ -89,7 +89,14 @@ namespace Tgstation.Server.Host.Components.Repository
}
///
- public async Task CloneRepository(Uri url, string initialBranch, string username, string password, Action progressReporter, CancellationToken cancellationToken)
+ public async Task CloneRepository(
+ Uri url,
+ string initialBranch,
+ string username,
+ string password,
+ Action progressReporter,
+ bool recurseSubmodules,
+ CancellationToken cancellationToken)
{
if (url == null)
throw new ArgumentNullException(nameof(url));
@@ -122,7 +129,7 @@ namespace Tgstation.Server.Host.Components.Repository
progressReporter((int)percentage);
return !cancellationToken.IsCancellationRequested;
},
- RecurseSubmodules = true,
+ RecurseSubmodules = recurseSubmodules,
OnUpdateTips = (a, b, c) => !cancellationToken.IsCancellationRequested,
RepositoryOperationStarting = (a) => !cancellationToken.IsCancellationRequested,
BranchName = initialBranch,
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs
index 73d7a74d22..63cdb20557 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Tgstation.Server.Api.Models.Internal;
using Tgstation.Server.Host.Components.Chat;
using Tgstation.Server.Host.Components.Deployment;
+using Tgstation.Server.Host.Components.Events;
using Tgstation.Server.Host.Components.Session;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.Database;
@@ -51,6 +52,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// The for the .
/// The for the .
/// The for the .
+ /// The for the .
/// The for the .
/// The for the .
/// The for the .
@@ -65,6 +67,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
IServerControl serverControl,
IAsyncDelayer asyncDelayer,
IIOManager diagnosticsIOManager,
+ IEventConsumer eventConsumer,
ILogger logger,
DreamDaemonLaunchParameters initialLaunchParameters,
Api.Models.Instance instance,
@@ -79,6 +82,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
serverControl,
asyncDelayer,
diagnosticsIOManager,
+ eventConsumer,
logger,
initialLaunchParameters,
instance,
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/ExperimentalWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/ExperimentalWatchdog.cs
index 0addffef36..95d2fc12b2 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/ExperimentalWatchdog.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/ExperimentalWatchdog.cs
@@ -8,6 +8,7 @@ using System.Threading.Tasks;
using Tgstation.Server.Api.Models.Internal;
using Tgstation.Server.Host.Components.Chat;
using Tgstation.Server.Host.Components.Deployment;
+using Tgstation.Server.Host.Components.Events;
using Tgstation.Server.Host.Components.Session;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.Database;
@@ -62,6 +63,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// The for the .
/// The for the .
/// The for the .
+ /// The for the .
/// The for the .
/// The for the .
/// The for the .
@@ -76,6 +78,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
IServerControl serverControl,
IAsyncDelayer asyncDelayer,
IIOManager diagnosticsIOManager,
+ IEventConsumer eventConsumer,
ILogger logger,
DreamDaemonLaunchParameters initialLaunchParameters,
Api.Models.Instance instance, bool autoStart)
@@ -89,6 +92,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
serverControl,
asyncDelayer,
diagnosticsIOManager,
+ eventConsumer,
logger,
initialLaunchParameters,
instance,
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdogFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdogFactory.cs
index 63f30ec362..134628b460 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdogFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdogFactory.cs
@@ -1,6 +1,7 @@
using Tgstation.Server.Api.Models.Internal;
using Tgstation.Server.Host.Components.Chat;
using Tgstation.Server.Host.Components.Deployment;
+using Tgstation.Server.Host.Components.Events;
using Tgstation.Server.Host.Components.Session;
using Tgstation.Server.Host.IO;
@@ -20,6 +21,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// The for the
/// The pointing to the Game directory for the .
/// The pointing to the Diagnostics directory for the .
+ /// The for the .
/// The for the
/// The initial for the
/// A new
@@ -30,6 +32,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
ISessionControllerFactory sessionControllerFactory,
IIOManager gameIOManager,
IIOManager diagnosticsIOManager,
+ IEventConsumer eventConsumer,
Api.Models.Instance instance,
DreamDaemonSettings settings);
}
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
index d8e6139afa..f95eb8111b 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
@@ -120,6 +120,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
///
readonly IIOManager diagnosticsIOManager;
+ ///
+ /// The that is not the
+ ///
+ readonly IEventConsumer eventConsumer;
+
///
/// used for .
///
@@ -177,6 +182,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// The to populate with
/// The value of .
/// The value of .
+ /// The value of .
/// The value of
/// The initial value of . May be modified
/// The value of
@@ -191,6 +197,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
IServerControl serverControl,
IAsyncDelayer asyncDelayer,
IIOManager diagnosticsIOManager,
+ IEventConsumer eventConsumer,
ILogger logger,
DreamDaemonLaunchParameters initialLaunchParameters,
Api.Models.Instance instance,
@@ -204,6 +211,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));
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
ActiveLaunchParameters = initialLaunchParameters ?? throw new ArgumentNullException(nameof(initialLaunchParameters));
this.instance = instance ?? throw new ArgumentNullException(nameof(instance));
@@ -255,7 +263,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
return;
if (!graceful)
{
- var eventTask = HandleEvent(releaseServers ? EventType.WatchdogDetach : EventType.WatchdogShutdown, null, cancellationToken);
+ var eventTask = eventConsumer.HandleEvent(releaseServers ? EventType.WatchdogDetach : EventType.WatchdogShutdown, null, cancellationToken);
var chatTask = announce ? Chat.SendWatchdogMessage("Shutting down...", false, cancellationToken) : Task.CompletedTask;
@@ -353,13 +361,19 @@ namespace Tgstation.Server.Host.Components.Watchdog
throw new JobException(ErrorCode.WatchdogCompileJobCorrupted);
// this is necessary, the monitor could be in it's sleep loop trying to restart, if so cancel THAT monitor and start our own with blackjack and hookers
- Task chatTask;
+ Task announceTask;
if (startMonitor && await StopMonitor().ConfigureAwait(false))
- chatTask = Chat.SendWatchdogMessage("Automatic retry sequence cancelled by manual launch. Restarting...", false, cancellationToken);
+ announceTask = Chat.SendWatchdogMessage("Automatic retry sequence cancelled by manual launch. Restarting...", false, cancellationToken);
else if (announce)
- chatTask = Chat.SendWatchdogMessage(reattachInfo == null ? "Launching..." : "Reattaching...", false, cancellationToken); // simple announce
+ {
+ announceTask = Chat.SendWatchdogMessage(reattachInfo == null ? "Launching..." : "Reattaching...", false, cancellationToken); // simple announce
+ if (reattachInfo == null)
+ announceTask = Task.WhenAll(
+ eventConsumer.HandleEvent(EventType.WatchdogLaunch, Enumerable.Empty(), cancellationToken),
+ announceTask);
+ }
else
- chatTask = Task.CompletedTask; // no announce
+ announceTask = Task.CompletedTask; // no announce
// since neither server is running, this is safe to do
LastLaunchParameters = ActiveLaunchParameters;
@@ -369,11 +383,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
var recursiveCallToHappen = false;
try
{
- await InitControllers(() => recursiveCallToHappen = true, chatTask, reattachInfo, cancellationToken).ConfigureAwait(false);
+ await InitControllers(() => recursiveCallToHappen = true, announceTask, reattachInfo, cancellationToken).ConfigureAwait(false);
if (recursiveCallToHappen)
return;
- await chatTask.ConfigureAwait(false);
+ await announceTask.ConfigureAwait(false);
Logger.LogInformation("Launched servers successfully");
Running = true;
@@ -389,14 +403,14 @@ namespace Tgstation.Server.Host.Components.Watchdog
// don't try to send chat tasks or warning logs if were suppressing exceptions or cancelled
if (!recursiveCallToHappen && !cancellationToken.IsCancellationRequested)
{
- var originalChatTask = chatTask;
+ var originalChatTask = announceTask;
async Task ChainChatTaskWithErrorMessage()
{
await originalChatTask.ConfigureAwait(false);
await Chat.SendWatchdogMessage("Startup failed!", false, cancellationToken).ConfigureAwait(false);
}
- chatTask = ChainChatTaskWithErrorMessage();
+ announceTask = ChainChatTaskWithErrorMessage();
Logger.LogWarning("Failed to start watchdog: {0}", e.ToString());
}
@@ -407,9 +421,12 @@ namespace Tgstation.Server.Host.Components.Watchdog
// finish the chat task that's in flight
try
{
- await chatTask.ConfigureAwait(false);
+ await announceTask.ConfigureAwait(false);
+ }
+ catch (OperationCanceledException)
+ {
+ Logger.LogTrace("Announcement task canceled!");
}
- catch (OperationCanceledException) { }
}
}
@@ -751,8 +768,9 @@ namespace Tgstation.Server.Host.Components.Watchdog
}
///
- public async Task HandleEvent(EventType eventType, IEnumerable parameters, CancellationToken cancellationToken)
+ async Task IEventConsumer.HandleEvent(EventType eventType, IEnumerable parameters, CancellationToken cancellationToken)
{
+ // Method explicitly implemented to prevent accidental calls when this.eventConsumer should be used.
var activeServer = GetActiveController();
// Server may have ended
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs
index b7fcaaa3bd..abbe180c96 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs
@@ -4,6 +4,7 @@ using System;
using Tgstation.Server.Api.Models.Internal;
using Tgstation.Server.Host.Components.Chat;
using Tgstation.Server.Host.Components.Deployment;
+using Tgstation.Server.Host.Components.Events;
using Tgstation.Server.Host.Components.Session;
using Tgstation.Server.Host.Configuration;
using Tgstation.Server.Host.Core;
@@ -79,6 +80,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
ISessionControllerFactory sessionControllerFactory,
IIOManager gameIOManager,
IIOManager diagnosticsIOManager,
+ IEventConsumer eventConsumer,
Api.Models.Instance instance,
DreamDaemonSettings settings)
{
@@ -93,6 +95,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
ServerControl,
AsyncDelayer,
diagnosticsIOManager,
+ eventConsumer,
LoggerFactory.CreateLogger(),
settings,
instance,
@@ -105,6 +108,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
sessionControllerFactory,
gameIOManager,
diagnosticsIOManager,
+ eventConsumer,
instance,
settings);
}
@@ -118,6 +122,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// The for the
/// The pointing to the Game directory for the .
/// The pointing to the Diagnostics directory for the .
+ /// The for the .
/// The for the
/// The initial for the
/// A new
@@ -128,6 +133,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
ISessionControllerFactory sessionControllerFactory,
IIOManager gameIOManager,
IIOManager diagnosticsIOManager,
+ IEventConsumer eventConsumer,
Api.Models.Instance instance,
DreamDaemonSettings settings)
=> new BasicWatchdog(
@@ -140,6 +146,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
ServerControl,
AsyncDelayer,
diagnosticsIOManager,
+ eventConsumer,
LoggerFactory.CreateLogger(),
settings,
instance,
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs
index 206995886c..aa59fc3d35 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
using Tgstation.Server.Api.Models.Internal;
using Tgstation.Server.Host.Components.Chat;
using Tgstation.Server.Host.Components.Deployment;
+using Tgstation.Server.Host.Components.Events;
using Tgstation.Server.Host.Components.Session;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.Database;
@@ -55,6 +56,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// The for the .
/// The for the .
/// The for the .
+ /// The for the .
/// The value of .
/// The value of .
/// The for the .
@@ -71,6 +73,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
IServerControl serverControl,
IAsyncDelayer asyncDelayer,
IIOManager diagnosticsIOManager,
+ IEventConsumer eventConsumer,
IIOManager gameIOManager,
ISymlinkFactory symlinkFactory,
ILogger logger,
@@ -86,6 +89,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
serverControl,
asyncDelayer,
diagnosticsIOManager,
+ eventConsumer,
logger,
initialLaunchParameters,
instance,
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdogFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdogFactory.cs
index d8c4314280..f1f23e22f6 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdogFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdogFactory.cs
@@ -4,6 +4,7 @@ using System;
using Tgstation.Server.Api.Models.Internal;
using Tgstation.Server.Host.Components.Chat;
using Tgstation.Server.Host.Components.Deployment;
+using Tgstation.Server.Host.Components.Events;
using Tgstation.Server.Host.Components.Session;
using Tgstation.Server.Host.Configuration;
using Tgstation.Server.Host.Core;
@@ -60,6 +61,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
ISessionControllerFactory sessionControllerFactory,
IIOManager gameIOManager,
IIOManager diagnosticsIOManager,
+ IEventConsumer eventConsumer,
Api.Models.Instance instance,
DreamDaemonSettings settings)
=> new WindowsWatchdog(
@@ -72,6 +74,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
ServerControl,
AsyncDelayer,
diagnosticsIOManager,
+ eventConsumer,
gameIOManager,
symlinkFactory,
LoggerFactory.CreateLogger(),
diff --git a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs
index d6536518e3..0094cb8764 100644
--- a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs
+++ b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs
@@ -204,7 +204,15 @@ namespace Tgstation.Server.Host.Controllers
var api = currentModel.ToApi();
await jobManager.RegisterOperation(job, async (paramJob, databaseContextFactory, progressReporter, ct) =>
{
- using var repos = await repoManager.CloneRepository(new Uri(origin), cloneBranch, currentModel.AccessUser, currentModel.AccessToken, progressReporter, ct).ConfigureAwait(false);
+ using var repos = await repoManager.CloneRepository(
+ new Uri(origin),
+ cloneBranch,
+ currentModel.AccessUser,
+ currentModel.AccessToken,
+ progressReporter,
+ model.RecurseSubmodules ?? true,
+ ct)
+ .ConfigureAwait(false);
if (repos == null)
throw new JobException(ErrorCode.RepoExists);
var instance = new Models.Instance