Merge pull request #2107 from tgstation/dev [TGSDeploy]

v6.13.0
This commit is contained in:
Jordan Dominion
2025-02-09 10:14:33 -05:00
committed by GitHub
52 changed files with 230 additions and 76 deletions
+3 -3
View File
@@ -3,7 +3,7 @@
<ItemGroup>
<!-- Usage: Code coverage collection -->
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@@ -18,9 +18,9 @@
<!-- Pinned: Be VERY careful about updating https://github.com/moq/moq/issues/1372 -->
<PackageReference Include="Moq" Version="4.20.72" />
<!-- Usage: MSTest execution -->
<PackageReference Include="MSTest.TestAdapter" Version="3.6.4" />
<PackageReference Include="MSTest.TestAdapter" Version="3.7.3" />
<!-- Usage: MSTest asserts etc... -->
<PackageReference Include="MSTest.TestFramework" Version="3.6.4" />
<PackageReference Include="MSTest.TestFramework" Version="3.7.3" />
</ItemGroup>
</Project>
+3 -3
View File
@@ -5,12 +5,12 @@
<PropertyGroup>
<TgsCoreVersion>6.12.3</TgsCoreVersion>
<TgsConfigVersion>5.4.0</TgsConfigVersion>
<TgsRestVersion>10.12.0</TgsRestVersion>
<TgsRestVersion>10.12.1</TgsRestVersion>
<TgsGraphQLVersion>0.5.0</TgsGraphQLVersion>
<TgsCommonLibraryVersion>7.0.0</TgsCommonLibraryVersion>
<TgsApiLibraryVersion>17.0.0</TgsApiLibraryVersion>
<TgsApiLibraryVersion>17.0.1</TgsApiLibraryVersion>
<TgsClientVersion>20.0.0</TgsClientVersion>
<TgsDmapiVersion>7.3.0</TgsDmapiVersion>
<TgsDmapiVersion>7.3.1</TgsDmapiVersion>
<TgsInteropVersion>5.10.0</TgsInteropVersion>
<TgsHostWatchdogVersion>1.6.0</TgsHostWatchdogVersion>
<TgsSwarmProtocolVersion>8.0.0</TgsSwarmProtocolVersion>
+12 -3
View File
@@ -1,6 +1,7 @@
inputs@{
config,
lib,
systemdUtils,
nixpkgs,
pkgs,
writeShellScriptBin,
@@ -53,7 +54,7 @@ in
};
username = lib.mkOption {
type = lib.types.str;
type = lib.types.nonEmptyStr;
default = "tgstation-server";
description = ''
The name of the user used to execute tgstation-server.
@@ -61,7 +62,7 @@ in
};
groupname = lib.mkOption {
type = lib.types.str;
type = lib.types.nonEmptyStr;
default = "tgstation-server";
description = ''
The name of group the user used to execute tgstation-server will belong to.
@@ -69,7 +70,7 @@ in
};
home-directory = lib.mkOption {
type = lib.types.str;
type = lib.types.nonEmptyStr;
default = "/home/tgstation-server";
description = ''
The home directory of TGS. Should be persistent.
@@ -99,6 +100,14 @@ in
Environment file as defined in {manpage}`systemd.exec(5)`
'';
};
wants = lib.mkOption {
type = lib.types.listOf systemdUtils.lib.unitNameType;
default = [];
description = ''
Start the specified units when this unit is started.
'';
};
};
};
+2 -1
View File
@@ -5,7 +5,8 @@
"documentPrivateElements": true,
"documentPrivateFields": true,
"excludeFromPunctuationCheck": [
"remarks"
"remarks",
"example"
]
},
"indentation": {
+28 -1
View File
@@ -1,7 +1,7 @@
// tgstation-server DMAPI
// The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in IETF RFC 2119.
#define TGS_DMAPI_VERSION "7.3.0"
#define TGS_DMAPI_VERSION "7.3.1"
// All functions and datums outside this document are subject to change with any version and should not be relied on.
@@ -58,6 +58,11 @@
#define TGS_FILE2TEXT_NATIVE file2text
#endif
// SpacemanDMM compatibility
#ifndef CAN_BE_REDEFINED
#define CAN_BE_REDEFINED(X)
#endif
// EVENT CODES
/// Before a reboot mode change, extras parameters are the current and new reboot mode enums.
@@ -160,6 +165,7 @@
* * http_handler - Optional user defined [/datum/tgs_http_handler].
*/
/world/proc/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE, datum/tgs_http_handler/http_handler)
CAN_BE_REDEFINED(TRUE)
return
/**
@@ -170,6 +176,7 @@
* This function should not be called before ..() in [/world/proc/New].
*/
/world/proc/TgsInitializationComplete()
CAN_BE_REDEFINED(TRUE)
return
/// Consumers MUST run this macro at the start of [/world/proc/Topic].
@@ -177,6 +184,7 @@
/// Consumers MUST call this as late as possible in [world/proc/Reboot] (BEFORE ..()).
/world/proc/TgsReboot()
CAN_BE_REDEFINED(TRUE)
return
// DATUM DEFINITIONS
@@ -214,6 +222,7 @@
* Returns [TRUE]/[FALSE] based on if the [/datum/tgs_version] contains wildcards.
*/
/datum/tgs_version/proc/Wildcard()
CAN_BE_REDEFINED(TRUE)
return
/**
@@ -222,6 +231,7 @@
* other_version - The [/datum/tgs_version] to compare against.
*/
/datum/tgs_version/proc/Equals(datum/tgs_version/other_version)
CAN_BE_REDEFINED(TRUE)
return
/// Represents a merge of a GitHub pull request.
@@ -459,16 +469,19 @@
/// Returns the maximum supported [/datum/tgs_version] of the DMAPI.
/world/proc/TgsMaximumApiVersion()
CAN_BE_REDEFINED(TRUE)
return
/// Returns the minimum supported [/datum/tgs_version] of the DMAPI.
/world/proc/TgsMinimumApiVersion()
CAN_BE_REDEFINED(TRUE)
return
/**
* Returns [TRUE] if DreamDaemon was launched under TGS, the API matches, and was properly initialized. [FALSE] will be returned otherwise.
*/
/world/proc/TgsAvailable()
CAN_BE_REDEFINED(TRUE)
return
// No function below this succeeds if it TgsAvailable() returns FALSE or if TgsNew() has yet to be called.
@@ -480,6 +493,7 @@
* If TGS has not requested a [TGS_REBOOT_MODE_SHUTDOWN] DreamDaemon will be launched again.
*/
/world/proc/TgsEndProcess()
CAN_BE_REDEFINED(TRUE)
return
/**
@@ -490,6 +504,7 @@
* admin_only: If [TRUE], message will be sent to admin connected chats. Vice-versa applies.
*/
/world/proc/TgsTargetedChatBroadcast(datum/tgs_message_content/message, admin_only = FALSE)
CAN_BE_REDEFINED(TRUE)
return
/**
@@ -500,6 +515,7 @@
* user: The [/datum/tgs_chat_user] to PM.
*/
/world/proc/TgsChatPrivateMessage(datum/tgs_message_content/message, datum/tgs_chat_user/user)
CAN_BE_REDEFINED(TRUE)
return
/**
@@ -510,42 +526,52 @@
* channels - Optional list of [/datum/tgs_chat_channel]s to restrict the message to.
*/
/world/proc/TgsChatBroadcast(datum/tgs_message_content/message, list/channels = null)
CAN_BE_REDEFINED(TRUE)
return
/// Returns the current [/datum/tgs_version] of TGS if it is running the server, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping!
/world/proc/TgsVersion()
CAN_BE_REDEFINED(TRUE)
return
/// Returns the running engine type
/world/proc/TgsEngine()
CAN_BE_REDEFINED(TRUE)
return
/// Returns the current [/datum/tgs_version] of the DMAPI being used if it was activated, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping!
/world/proc/TgsApiVersion()
CAN_BE_REDEFINED(TRUE)
return
/// Returns the name of the TGS instance running the game if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping!
/world/proc/TgsInstanceName()
CAN_BE_REDEFINED(TRUE)
return
/// Return the current [/datum/tgs_revision_information] of the running server if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping!
/world/proc/TgsRevision()
CAN_BE_REDEFINED(TRUE)
return
/// Returns the current BYOND security level as a TGS_SECURITY_ define if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping!
/world/proc/TgsSecurityLevel()
CAN_BE_REDEFINED(TRUE)
return
/// Returns the current BYOND visibility level as a TGS_VISIBILITY_ define if TGS is present, null otherwise. Requires TGS to be using interop API version 5 or higher otherwise the string "___unimplemented" wil be returned. This function may sleep if the call to [/world/proc/TgsNew] is sleeping!
/world/proc/TgsVisibility()
CAN_BE_REDEFINED(TRUE)
return
/// Returns a list of active [/datum/tgs_revision_information/test_merge]s if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping!
/world/proc/TgsTestMerges()
CAN_BE_REDEFINED(TRUE)
return
/// Returns a list of connected [/datum/tgs_chat_channel]s if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping!
/world/proc/TgsChatChannelInfo()
CAN_BE_REDEFINED(TRUE)
return
/**
@@ -556,6 +582,7 @@
* wait_for_completion - If set, this function will not return until the event has run to completion.
*/
/world/proc/TgsTriggerEvent(event_name, list/parameters, wait_for_completion = FALSE)
CAN_BE_REDEFINED(TRUE)
return
/*
+1 -1
View File
@@ -244,7 +244,7 @@ namespace Tgstation.Server.Api
else
{
var auth = authorization.First();
var splits = new List<string>(auth.Split(' '));
var splits = new List<string>(auth?.Split(' ') ?? Enumerable.Empty<string>());
var scheme = splits.First();
if (String.IsNullOrWhiteSpace(scheme))
AddError(HeaderErrorTypes.AuthorizationInvalid, "Missing authentication scheme!");
@@ -14,6 +14,7 @@ namespace Tgstation.Server.Api.Models
/// For <see cref="ChatProvider.Irc"/>, it's the IRC channel name and optional password colon separated.
/// For <see cref="ChatProvider.Discord"/>, it's the stringified Discord channel snowflake.
/// </summary>
/// <example>124823852418</example>
[Required]
[StringLength(Limits.MaximumIndexableStringLength, MinimumLength = 1)]
public string? ChannelData { get; set; }
@@ -26,12 +26,14 @@ namespace Tgstation.Server.Api.Models
/// <summary>
/// The <see cref="System.Version"/> of the engine. Currently only valid when <see cref="Engine"/> is <see cref="EngineType.Byond"/>.
/// </summary>
/// <example>516.1651.0</example>
[ResponseOptions]
public Version? Version { get; set; }
/// <summary>
/// The git commit SHA of the engine. Currently only valid when <see cref="Engine"/> is <see cref="EngineType.OpenDream"/>.
/// </summary>
/// <example>caa1e1f400c8b6a535e03cff28cf57f919e9378c</example>
[ResponseOptions]
[StringLength(Limits.MaximumCommitShaLength, MinimumLength = Limits.MaximumCommitShaLength)]
public string? SourceSHA { get; set; }
@@ -8,6 +8,7 @@
/// <summary>
/// The ID of the entity.
/// </summary>
/// <example>1</example>
[RequestOptions(FieldPresence.Required)]
[RequestOptions(FieldPresence.Ignored, PutOnly = true)]
public virtual long? Id { get; set; }
@@ -16,6 +16,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The time interval in minutes the chat bot attempts to reconnect if <see cref="Enabled"/> and disconnected. Must not be zero.
/// </summary>
/// <example>60</example>
[Required]
[Range(1, UInt32.MaxValue)]
public uint? ReconnectionInterval { get; set; }
@@ -23,6 +24,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The maximum number of <see cref="ChatChannel"/>s the <see cref="ChatBotSettings"/> may contain.
/// </summary>
/// <example>5</example>
[Required]
public ushort? ChannelLimit { get; set; }
@@ -10,18 +10,21 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// If the <see cref="ChatChannel"/> is an admin channel.
/// </summary>
/// <example>false</example>
[Required]
public bool? IsAdminChannel { get; set; }
/// <summary>
/// If the <see cref="ChatChannel"/> is a watchdog channel.
/// </summary>
/// <example>false</example>
[Required]
public bool? IsWatchdogChannel { get; set; }
/// <summary>
/// If the <see cref="ChatChannel"/> is an updates channel.
/// </summary>
/// <example>false</example>
[Required]
public bool? IsUpdatesChannel { get; set; }
@@ -34,6 +37,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// A custom tag users can define to group channels together.
/// </summary>
/// <example>system-channel-only</example>
[ResponseOptions]
[StringLength(Limits.MaximumStringLength)]
public string? Tag { get; set; }
@@ -12,6 +12,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The .dme file used for compilation.
/// </summary>
/// <example>tgstation.dme</example>
[Required]
public string? DmeName { get; set; }
@@ -36,6 +37,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The DMAPI <see cref="Version"/>.
/// </summary>
/// <example>7.3.0</example>
[NotMapped]
[ResponseOptions]
public virtual Version? DMApiVersion { get; set; }
@@ -10,6 +10,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// An incrementing ID for representing current server execution.
/// </summary>
/// <example>1</example>
[ResponseOptions]
public long? SessionId { get; set; }
@@ -22,12 +23,14 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The last known count of connected players. Requires <see cref="DreamDaemonLaunchParameters.HealthCheckSeconds"/> to not be 0 and a game server interop version >= 5.10.0 to populate.
/// </summary>
/// <example>30</example>
[ResponseOptions]
public uint? ClientCount { get; set; }
/// <summary>
/// If the server is undergoing a soft reset. This may be automatically set by changes to other fields.
/// </summary>
/// <example>false</example>
[ResponseOptions]
public bool? SoftRestart { get; set; }
@@ -11,6 +11,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// If the BYOND web client can be used to connect to the game server. No-op for <see cref="EngineType.OpenDream"/>.
/// </summary>
/// <example>false</example>
[Required]
[ResponseOptions]
public bool? AllowWebClient { get; set; }
@@ -25,6 +26,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The <see cref="DreamDaemonVisibility"/> level of DreamDaemon. No-op for <see cref="EngineType.OpenDream"/>.
/// </summary>
/// <example>2</example>
[Required]
[ResponseOptions]
[EnumDataType(typeof(DreamDaemonVisibility))]
@@ -33,6 +35,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The <see cref="DreamDaemonSecurity"/> level of DreamDaemon. No-op for <see cref="EngineType.OpenDream"/>.
/// </summary>
/// <example>1</example>
[Required]
[ResponseOptions]
[EnumDataType(typeof(DreamDaemonSecurity))]
@@ -41,6 +44,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The port DreamDaemon uses. This should be publically accessible.
/// </summary>
/// <example>1337</example>
[Required]
[ResponseOptions]
[Range(1, UInt16.MaxValue)]
@@ -49,6 +53,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The port used by <see cref="EngineType.OpenDream"/> for its topic port.
/// </summary>
/// <example>2337</example>
[Required]
[ResponseOptions]
public ushort? OpenDreamTopicPort { get; set; }
@@ -56,6 +61,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The DreamDaemon startup timeout in seconds.
/// </summary>
/// <example>5</example>
[Required]
[ResponseOptions]
[Range(1, UInt32.MaxValue)]
@@ -64,6 +70,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The number of seconds between each watchdog health check. 0 disables.
/// </summary>
/// <example>5</example>
[Required]
[ResponseOptions]
public uint? HealthCheckSeconds { get; set; }
@@ -78,6 +85,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The timeout for sending and receiving BYOND topics in milliseconds.
/// </summary>
/// <example>500</example>
[Required]
[ResponseOptions]
[Range(1, UInt32.MaxValue)]
@@ -20,6 +20,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// English description of the <see cref="Job"/>.
/// </summary>
/// <remarks>May not match the <see cref="System.ComponentModel.DescriptionAttribute"/> listed on the <see cref="Models.JobCode"/>.</remarks>
/// <example>Installing and configuring important objects.</example>
[Required]
public string? Description { get; set; }
@@ -50,6 +51,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// If the <see cref="Job"/> was cancelled.
/// </summary>
/// <example>false</example>
[Required]
public bool? Cancelled { get; set; }
@@ -10,26 +10,31 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// Minimum length of database user passwords.
/// </summary>
/// <example>20</example>
public uint MinimumPasswordLength { get; set; }
/// <summary>
/// The maximum number of <see cref="Instance"/>s allowed.
/// </summary>
/// <example>100</example>
public uint InstanceLimit { get; set; }
/// <summary>
/// The maximum number of users allowed.
/// </summary>
/// <example>100</example>
public uint UserLimit { get; set; }
/// <summary>
/// The maximum number of user groups allowed.
/// </summary>
/// <example>50</example>
public uint UserGroupLimit { get; set; }
/// <summary>
/// Limits the locations instances may be created or attached from.
/// </summary>
/// <example>["/home/tgstation-server/my-server-1", "/home/tgstation-server/my-server-2"]</example>
[ResponseOptions]
public List<string>? ValidInstancePaths { get; set; }
}
@@ -22,6 +22,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The server's identifier.
/// </summary>
/// <example>myserver-us-east</example>
[Required]
public string? Identifier { get; set; }
@@ -10,6 +10,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// If the <see cref="SwarmServerResponse"/> is the controller.
/// </summary>
/// <example>false</example>
public bool Controller { get; set; }
/// <summary>
@@ -11,6 +11,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The ID of the <see cref="TestMergeApiBase"/>.
/// </summary>
/// <example>1</example>
public long Id { get; set; }
/// <summary>
@@ -11,18 +11,21 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The title of the test merge source.
/// </summary>
/// <example>Fixes and Breaks everything</example>
[Required]
public string? TitleAtMerge { get; set; }
/// <summary>
/// The body of the test merge source.
/// </summary>
/// <example># GitHub markdown\n\rI assume?</example>
[Required]
public string? BodyAtMerge { get; set; }
/// <summary>
/// The URL of the test merge source.
/// </summary>
/// <example>https://github.com/tgstation/tgstation/pull/31026</example>
[Required]
#pragma warning disable CA1056 // Uri properties should not be strings
public string? Url { get; set; }
@@ -31,6 +34,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The author of the test merge source.
/// </summary>
/// <example>MrStonedOne</example>
[Required]
public string? Author { get; set; }
@@ -10,6 +10,7 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The latest available version of the Tgstation.Server.Host assembly from the upstream repository. If <see cref="Version.Major"/> is less than 4 the update cannot be applied due to API changes.
/// </summary>
/// <example>1.0.0</example>
public Version? LatestVersion { get; set; }
/// <summary>
@@ -10,6 +10,7 @@ namespace Tgstation.Server.Api.Models
/// <summary>
/// The name of the entity represented by the <see cref="NamedEntity"/>.
/// </summary>
/// <example>MyThingyName</example>
[Required]
[RequestOptions(FieldPresence.Required, PutOnly = true)]
[StringLength(Limits.MaximumIndexableStringLength, MinimumLength = 1)]
@@ -10,6 +10,7 @@ namespace Tgstation.Server.Api.Models.Request
/// <summary>
/// Changes the version of tgstation-server to the given version from the upstream repository.
/// </summary>
/// <example>6.12.3</example>
[RequestOptions(FieldPresence.Required)]
public Version? NewVersion { get; set; }
@@ -12,6 +12,7 @@ namespace Tgstation.Server.Api.Models.Response
/// <summary>
/// The GitHub repository the server is built to receive updates from.
/// </summary>
/// <example>https://github.com/tgstation/tgstation</example>
public Uri? TrackedRepositoryUrl { get; set; }
}
}
@@ -24,6 +24,7 @@ namespace Tgstation.Server.Api.Models.Response
/// <summary>
/// The current <see cref="WatchdogStatus"/>.
/// </summary>
/// <example>2</example>
[EnumDataType(typeof(WatchdogStatus))]
[ResponseOptions]
public WatchdogStatus? Status { get; set; }
@@ -31,6 +32,7 @@ namespace Tgstation.Server.Api.Models.Response
/// <summary>
/// The current <see cref="DreamDaemonSecurity"/>. May be upgraded. due to requirements of <see cref="ActiveCompileJob"/>.
/// </summary>
/// <example>1</example>
[EnumDataType(typeof(DreamDaemonSecurity))]
[ResponseOptions]
public DreamDaemonSecurity? CurrentSecurity { get; set; }
@@ -38,6 +40,7 @@ namespace Tgstation.Server.Api.Models.Response
/// <summary>
/// The current <see cref="DreamDaemonVisibility"/>.
/// </summary>
/// <example>2</example>
[EnumDataType(typeof(DreamDaemonVisibility))]
[ResponseOptions]
public DreamDaemonVisibility? CurrentVisibility { get; set; }
@@ -45,24 +48,28 @@ namespace Tgstation.Server.Api.Models.Response
/// <summary>
/// The port the running <see cref="DreamDaemonResponse"/> instance is set to.
/// </summary>
/// <example>1337</example>
[ResponseOptions]
public ushort? CurrentPort { get; set; }
/// <summary>
/// The <see cref="EngineType.OpenDream"/> topic port the running <see cref="DreamDaemonResponse"/> instance is set to.
/// </summary>
/// <example>3000</example>
[ResponseOptions]
public ushort? CurrentTopicPort { get; set; }
/// <summary>
/// The webclient status the running <see cref="DreamDaemonResponse"/> instance is set to.
/// </summary>
/// <example>false</example>
[ResponseOptions]
public bool? CurrentAllowWebclient { get; set; }
/// <summary>
/// The amount of RAM in use by the game server in bytes.
/// </summary>
/// <example>1073741824</example>
[ResponseOptions]
public long? ImmediateMemoryUsage { get; set; }
}
@@ -13,16 +13,19 @@ namespace Tgstation.Server.Api.Models.Response
/// <summary>
/// The version of the API the server is using.
/// </summary>
/// <example>9.3.0</example>
public Version? ServerApiVersion { get; set; }
/// <summary>
/// A human readable description of the error.
/// A human-readable description of the error.
/// </summary>
/// <example>Oopsie woopsie, we did a fucky wucky!</example>
public string? Message { get; set; }
/// <summary>
/// Additional data associated with the error message.
/// </summary>
/// <example>Error at thing.app.dependency.class.function in line 32</example>
[ResponseOptions]
public string? AdditionalData { get; set; }
@@ -8,6 +8,7 @@
/// <summary>
/// The <see cref="EntityId.Id"/> of the <see cref="Instance"/>.
/// </summary>
/// <example>1</example>
public long? InstanceId { get; set; }
/// <summary>
@@ -24,12 +25,14 @@
/// <summary>
/// Optional progress between 0 and 100 inclusive.
/// </summary>
/// <example>25</example>
[ResponseOptions]
public int? Progress { get; set; }
/// <summary>
/// Optional description of the job's current .
/// Optional description of the job's current progress.
/// </summary>
/// <example>Doing something important</example>
[ResponseOptions]
public string? Stage { get; set; }
}
@@ -10,6 +10,7 @@ namespace Tgstation.Server.Api.Models.Response
/// <summary>
/// The name of the log file.
/// </summary>
/// <example>tgs-20250118.log</example>
public string? Name { get; set; }
/// <summary>
@@ -18,16 +18,19 @@ namespace Tgstation.Server.Api.Models.Response
/// <summary>
/// The total number of pages in the query.
/// </summary>
/// <example>5</example>
public int TotalPages { get; set; }
/// <summary>
/// The current size of pages in the query.
/// </summary>
/// <example>20</example>
public int PageSize { get; set; }
/// <summary>
/// The total items across all pages.
/// </summary>
/// <example>100</example>
public int TotalItems { get; set; }
}
}
@@ -11,16 +11,19 @@ namespace Tgstation.Server.Api.Models.Response
/// <summary>
/// The version of the host.
/// </summary>
/// <example>6.12.3</example>
public Version? Version { get; set; }
/// <summary>
/// The <see cref="Api"/> version of the host.
/// </summary>
/// <example>10.12.0</example>
public Version? ApiVersion { get; set; }
/// <summary>
/// The DMAPI interop version the server uses.
/// </summary>
/// <example>7.3.0</example>
public Version? DMApiVersion { get; set; }
/// <summary>
@@ -36,6 +39,7 @@ namespace Tgstation.Server.Api.Models.Response
/// <summary>
/// If there is a server update in progress.
/// </summary>
/// <example>false</example>
public bool UpdateInProgress { get; set; }
/// <summary>
@@ -12,6 +12,7 @@ namespace Tgstation.Server.Api.Models.Response
/// <summary>
/// The version of tgstation-server pending update.
/// </summary>
/// <example>6.12.3</example>
public Version NewVersion { get; }
/// <summary>
@@ -10,6 +10,7 @@ namespace Tgstation.Server.Api.Models.Response
/// <summary>
/// The value of the JWT.
/// </summary>
/// <example>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwibmJmIjoxNzM3MDkzNDgwLCJleHAiOjE3MzcwOTQzODAsImlhdCI6MTczNzA5MzQ4MCwiaXNzIjoiVGdzdGF0aW9uLlNlcnZlci5Ib3N0IiwiYXVkIjoiVGdzdGF0aW9uLlNlcnZlci5BcGkifQ.v64KX34_YOpH-HCbwqlx1p8u-MNbb4L6a9qEyXhcNcU</example>
public string? Bearer { get; set; }
/// <summary>
@@ -10,18 +10,21 @@ namespace Tgstation.Server.Api.Models
/// <summary>
/// The number of the test merge source.
/// </summary>
/// <example>31026</example>
public int Number { get; set; }
/// <summary>
/// The sha of the test merge revision to merge. If not specified, the latest commit from the source will be used.
/// </summary>
/// <example>caa1e1f400c8b6a535e03cff28cf57f919e9378c</example>
[Required]
[StringLength(40)]
[StringLength(Limits.MaximumCommitShaLength, MinimumLength = Limits.MaximumCommitShaLength)]
public virtual string? TargetCommitSha { get; set; }
/// <summary>
/// Optional comment about the test.
/// </summary>
/// <example>this will fix everything -Admin</example>
[ResponseOptions]
[StringLength(Limits.MaximumStringLength)]
public string? Comment { get; set; }
@@ -6,6 +6,7 @@
public class UserName : NamedEntity
{
/// <inheritdoc />
/// <example>Admin</example>
[RequestOptions(FieldPresence.Optional)]
public override string? Name
{
@@ -26,12 +26,12 @@
<ItemGroup>
<!-- Usage: HTTP constants reference -->
<PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="2.3.0" />
<!-- Usage: Decoding the 'nbf' property of JWTs -->
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.3.0" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.4.0" />
<!-- Usage: Data model annotating -->
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Text.Encodings.Web" Version="9.0.0" />
<PackageReference Include="System.Text.Encodings.Web" Version="9.0.1" />
</ItemGroup>
<ItemGroup>
@@ -9,8 +9,8 @@
<ItemGroup>
<!-- GraphQL connector and code generator -->
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.0" />
<PackageReference Include="StrawberryShake.Server" Version="14.2.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.1" />
<PackageReference Include="StrawberryShake.Server" Version="15.0.3" />
</ItemGroup>
<ItemGroup>
@@ -11,7 +11,7 @@
<ItemGroup>
<!-- Usage: Connecting to SignalR hubs in API -->
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.1" />
<!-- Usage: Using target JSON serializer for API -->
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="9.0.0" />
</ItemGroup>
@@ -13,9 +13,9 @@
<ItemGroup>
<!-- Usage: Identifying if we're running under SystemD -->
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="9.0.1" />
<!-- Usage: Console logging plugin -->
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.1" />
</ItemGroup>
<ItemGroup>
@@ -21,21 +21,21 @@
<!-- Usage: Command line argument support -->
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.1.1" />
<!-- Usage: Identifies when we are running in the context of the Windows SCM -->
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.1" />
<!-- Usage: Windows event log logging plugin -->
<PackageReference Include="Microsoft.Extensions.Logging.EventLog" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.EventLog" Version="9.0.1" />
<!-- Usage: Console logging plugin -->
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.1" />
<!-- Usage: Updated transitive dependency of Core.System.ServiceProcess -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<!-- Usage: Updated transitive dependency of Core.System.ServiceProcess -->
<PackageReference Include="System.Drawing.Common" Version="9.0.0" />
<PackageReference Include="System.Drawing.Common" Version="9.0.1" />
<!-- Usage: Updated transitive dependency, unable to tell what of -->
<PackageReference Include="System.Private.Uri" Version="4.3.2" />
<!-- Usage: OS identification -->
<PackageReference Include="System.Runtime.InteropServices" Version="4.3.0" />
<!-- Usage: Windows Service Manager intergration -->
<PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.0" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.1" />
</ItemGroup>
<ItemGroup>
+17 -13
View File
@@ -177,6 +177,10 @@ namespace Tgstation.Server.Host.Watchdog
var watchdogVersion = executingAssembly.GetName().Version?.Semver().ToString();
var serializerOptions = new JsonSerializerOptions
{
WriteIndented = true,
};
while (!cancellationToken.IsCancellationRequested)
{
if (!File.Exists(assemblyPath))
@@ -214,10 +218,7 @@ namespace Tgstation.Server.Host.Watchdog
bootstrapperSettingsFile,
JsonSerializer.Serialize(
bootstrapSettings,
new JsonSerializerOptions
{
WriteIndented = true,
}),
serializerOptions),
cancellationToken);
}
}
@@ -258,6 +259,7 @@ namespace Tgstation.Server.Host.Watchdog
process.StartInfo.UseShellExecute = false; // runs in the same console
var killedHostProcess = false;
var createdShutdownFile = false;
try
{
Task? processTask = null;
@@ -279,6 +281,7 @@ namespace Tgstation.Server.Host.Watchdog
{
logger.LogInformation("Cancellation requested! Writing shutdown lock file...");
File.WriteAllBytes(updateDirectory, Array.Empty<byte>());
createdShutdownFile = true;
}
else
logger.LogWarning("Cancellation requested while update directory exists!");
@@ -330,15 +333,16 @@ namespace Tgstation.Server.Host.Watchdog
logger.LogWarning(ex2, "Error killing host process!");
}
try
{
if (File.Exists(updateDirectory))
File.Delete(updateDirectory);
}
catch (Exception ex2)
{
logger.LogWarning(ex2, "Error deleting comms file!");
}
if (createdShutdownFile)
try
{
if (File.Exists(updateDirectory))
File.Delete(updateDirectory);
}
catch (Exception ex2)
{
logger.LogWarning(ex2, "Error deleting comms file!");
}
logger.LogInformation("Host exited!");
}
@@ -173,5 +173,11 @@
/// </summary>
[EventScript("EngineInstallComplete")]
EngineInstallComplete,
/// <summary>
/// Before game server process is created. No parameters.
/// </summary>
[EventScript("DreamDaemonPreLaunch")]
DreamDaemonPreLaunch,
}
}
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
@@ -516,6 +517,14 @@ namespace Tgstation.Server.Host.Components.Session
? logFilePath
: null);
// If this isnt a staging DD (From a Deployment), fire off events
if (!apiValidate)
await eventConsumer.HandleEvent(
EventType.DreamDaemonPreLaunch,
Enumerable.Empty<string?>(),
false,
cancellationToken);
var process = await processExecutor.LaunchProcess(
engineLock.ServerExePath,
dmbProvider.Directory,
@@ -539,7 +548,6 @@ namespace Tgstation.Server.Host.Components.Session
if (!engineLock.HasStandardOutput)
networkPromptReaper.RegisterProcess(process);
// If this isnt a staging DD (From a Deployment), fire off an event
if (!apiValidate)
await eventConsumer.HandleEvent(
EventType.DreamDaemonLaunch,
@@ -527,6 +527,7 @@ namespace Tgstation.Server.Host.Core
/// <param name="assemblyInformationProvider">The <see cref="IAssemblyInformationProvider"/>.</param>
/// <param name="controlPanelConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing the <see cref="ControlPanelConfiguration"/> to use.</param>
/// <param name="generalConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing the <see cref="GeneralConfiguration"/> to use.</param>
/// <param name="databaseConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing the <see cref="DatabaseConfiguration"/> to use.</param>
/// <param name="swarmConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing the <see cref="SwarmConfiguration"/> to use.</param>
/// <param name="internalConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing the <see cref="InternalConfiguration"/> to use.</param>
/// <param name="logger">The <see cref="Microsoft.Extensions.Logging.ILogger"/> for the <see cref="Application"/>.</param>
@@ -538,6 +539,7 @@ namespace Tgstation.Server.Host.Core
IAssemblyInformationProvider assemblyInformationProvider,
IOptions<ControlPanelConfiguration> controlPanelConfigurationOptions,
IOptions<GeneralConfiguration> generalConfigurationOptions,
IOptions<DatabaseConfiguration> databaseConfigurationOptions,
IOptions<SwarmConfiguration> swarmConfigurationOptions,
IOptions<InternalConfiguration> internalConfigurationOptions,
ILogger<Application> logger)
@@ -552,11 +554,13 @@ namespace Tgstation.Server.Host.Core
var controlPanelConfiguration = controlPanelConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(controlPanelConfigurationOptions));
var generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions));
var databaseConfiguration = databaseConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(databaseConfigurationOptions));
var swarmConfiguration = swarmConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(swarmConfigurationOptions));
var internalConfiguration = internalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(internalConfigurationOptions));
ArgumentNullException.ThrowIfNull(logger);
logger.LogDebug("Database provider: {provider}", databaseConfiguration.DatabaseType);
logger.LogDebug("Content Root: {contentRoot}", hostingEnvironment.ContentRootPath);
logger.LogTrace("Web Root: {webRoot}", hostingEnvironment.WebRootPath);
@@ -65,6 +65,7 @@ namespace Tgstation.Server.Host.Extensions
applicationBuilder.ApplicationServices.GetRequiredService<IAssemblyInformationProvider>(),
applicationBuilder.ApplicationServices.GetRequiredService<IOptions<ControlPanelConfiguration>>(),
applicationBuilder.ApplicationServices.GetRequiredService<IOptions<GeneralConfiguration>>(),
applicationBuilder.ApplicationServices.GetRequiredService<IOptions<DatabaseConfiguration>>(),
applicationBuilder.ApplicationServices.GetRequiredService<IOptions<SwarmConfiguration>>(),
applicationBuilder.ApplicationServices.GetRequiredService<IOptions<InternalConfiguration>>(),
applicationBuilder.ApplicationServices.GetRequiredService<ILogger<Application>>());
@@ -38,7 +38,7 @@ namespace Tgstation.Server.Host.GraphQL
return error;
var errorBuilder = ErrorBuilder.FromError(error)
.RemoveException()
.SetException(null)
.ClearExtensions();
const string ErrorCodeFieldName = "errorCode";
@@ -100,21 +100,21 @@
<!-- Usage: GitLab interop -->
<PackageReference Include="GitLabApiClient" Version="1.8.0" />
<!-- Usage: GraphQL API Engine -->
<PackageReference Include="HotChocolate.AspNetCore" Version="14.2.0" />
<PackageReference Include="HotChocolate.AspNetCore" Version="15.0.3" />
<!-- Usage: GraphQL Authorization Plugin -->
<PackageReference Include="HotChocolate.AspNetCore.Authorization" Version="14.2.0" />
<PackageReference Include="HotChocolate.AspNetCore.Authorization" Version="15.0.3" />
<!-- Usage: GraphQL IDatabaseContext support -->
<PackageReference Include="HotChocolate.Data.EntityFramework" Version="14.2.0" />
<PackageReference Include="HotChocolate.Data.EntityFramework" Version="15.0.3" />
<!-- Usage: DataLoader source generation -->
<PackageReference Include="HotChocolate.Types.Analyzers" Version="14.2.0" />
<PackageReference Include="HotChocolate.Types.Analyzers" Version="15.0.3" />
<!-- Usage: GraphQL additional scalar type definitions -->
<PackageReference Include="HotChocolate.Types.Scalars" Version="14.2.0" />
<PackageReference Include="HotChocolate.Types.Scalars" Version="15.0.3" />
<!-- Usage: git interop -->
<PackageReference Include="LibGit2Sharp" Version="0.31.0" />
<!-- Usage: Support ""legacy"" Newotonsoft.Json in HTTP pipeline. The rest of our codebase uses Newtonsoft. -->
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.11" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.12" />
<!-- Usage: Using target JSON serializer for API -->
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="9.0.1" />
<!-- Usage: Generating dumps of dotnet engine processes -->
<PackageReference Include="Microsoft.Diagnostics.NETCore.Client" Version="0.2.553101" />
<!-- Usage: Database ORM -->
@@ -154,11 +154,11 @@
<!-- Usage: Newtonsoft.Json plugin for OpenAPI spec generator -->
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="7.2.0" />
<!-- Usage: Windows authentication plugin allowing searching for users by name -->
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="9.0.0" />
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="9.0.1" />
<!-- Usage: Identifying owning user of Windows Process objects -->
<PackageReference Include="System.Management" Version="9.0.0" />
<PackageReference Include="System.Management" Version="9.0.1" />
<!-- Usage: Temporary resolution to compatibility issues with EFCore 7 and .NET 8 -->
<PackageReference Include="System.Security.Permissions" Version="9.0.0" />
<PackageReference Include="System.Security.Permissions" Version="9.0.1" />
</ItemGroup>
<ItemGroup>
@@ -5,6 +5,7 @@ using System.Linq;
using System.Net;
using System.Net.Mime;
using System.Reflection;
using System.Text.RegularExpressions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Net.Http.Headers;
@@ -99,6 +100,7 @@ namespace Tgstation.Server.Host.Utils
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Name = HeaderNames.Authorization,
Description = "Username & Password authentication to obtain an JWT token when doing a (POST /api).",
Scheme = ApiHeaders.BasicAuthenticationScheme,
});
@@ -107,16 +109,18 @@ namespace Tgstation.Server.Host.Utils
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Name = HeaderNames.Authorization,
Description = "OAuth2 based authentication.",
Scheme = ApiHeaders.OAuthAuthenticationScheme,
});
swaggerGenOptions.AddSecurityDefinition(TokenSecuritySchemeId, new OpenApiSecurityScheme
{
BearerFormat = "JWT",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Name = HeaderNames.Authorization,
Description = "JWT Bearer token generated by the server (POST /api). You need this for most endpoints to work.",
Scheme = ApiHeaders.BearerAuthenticationScheme,
BearerFormat = "JWT",
});
}
@@ -368,14 +372,11 @@ namespace Tgstation.Server.Host.Utils
},
};
operation.Security = new List<OpenApiSecurityRequirement>
operation.Security = new List<OpenApiSecurityRequirement>()
{
new()
{
{
tokenScheme,
new List<string>()
},
{ tokenScheme, new List<string>() },
},
};
@@ -493,7 +494,6 @@ namespace Tgstation.Server.Host.Utils
var productHeaderSchema = new OpenApiSchema
{
Type = "string",
Format = "productheader",
};
swaggerDoc.Components.Parameters.Add(ApiHeaders.ApiVersionHeader, new OpenApiParameter
@@ -541,6 +541,28 @@ namespace Tgstation.Server.Host.Utils
Id = HeaderNames.UserAgent,
},
});
// flatten (Tgstation.Server.*).MyClass
if (operation.Description?.Length > 0)
operation.Description = Regex.Replace(operation.Description, @"Tgstation\.Server\.(\w+\.)+(?=\w+)", string.Empty);
if (operation.Summary?.Length > 0)
operation.Summary = Regex.Replace(operation.Summary, @"Tgstation\.Server\.(\w+\.)+(?=\w+)", string.Empty);
if (operation.RequestBody?.Description != null)
operation.RequestBody.Description = Regex.Replace(operation.RequestBody.Description, @"Tgstation\.Server\.(\w+\.)+(?=\w+)", string.Empty);
foreach (var opPar in operation.Parameters)
{
if (opPar.Description != null)
opPar.Description = Regex.Replace(opPar.Description, @"Tgstation\.Server\.(\w+\.)+(?=\w+)", string.Empty);
}
foreach (var (_, opRes) in operation.Responses)
{
if (opRes.Description != null)
opRes.Description = Regex.Replace(opRes.Description, @"Tgstation\.Server\.(\w+\.)+(?=\w+)", string.Empty);
}
}
AddDefaultResponses(swaggerDoc);
@@ -10,11 +10,11 @@
<ItemGroup>
<!-- Usage: JWT injection into HTTP pipeline -->
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.11" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.12" />
<!-- Usage: GitHub.com interop -->
<PackageReference Include="Octokit" Version="13.0.1" />
<PackageReference Include="Octokit" Version="14.0.0" />
<!-- Usage: YAML conversion of Version objects -->
<PackageReference Include="YamlDotNet" Version="16.2.1" />
<PackageReference Include="YamlDotNet" Version="16.3.0" />
</ItemGroup>
<ItemGroup>
@@ -6,7 +6,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.3.0" />
</ItemGroup>
<ItemGroup>
@@ -6,7 +6,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.1" />
</ItemGroup>
<ItemGroup>
@@ -40,39 +40,43 @@ namespace Tgstation.Server.Host.Core.Tests
Assert.ThrowsException<ArgumentNullException>(() => app.ConfigureServices(mockServiceCollection, null, null));
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(null, null, null, null, null, null, null, null, null, null));
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(null, null, null, null, null, null, null, null, null, null, null));
var mockAppBuilder = new Mock<IApplicationBuilder>();
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, null, null, null, null, null, null, null, null, null));
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, null, null, null, null, null, null, null, null, null, null));
var mockServerControl = new Mock<IServerControl>();
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, null, null, null, null, null, null, null, null));
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, null, null, null, null, null, null, null, null, null));
var mockTokenFactory = new Mock<ITokenFactory>();
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, mockTokenFactory.Object, null, null, null, null, null, null, null));
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, mockTokenFactory.Object, null, null, null, null, null, null, null, null));
var mockServerPortProvider = new Mock<IServerPortProvider>();
mockServerPortProvider.SetupGet(x => x.HttpApiPort).Returns(5345);
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, mockTokenFactory.Object, mockServerPortProvider.Object, null, null, null, null, null, null));
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, mockTokenFactory.Object, mockServerPortProvider.Object, null, null, null, null, null, null, null));
var mockAssemblyInformationProvider = Mock.Of<IAssemblyInformationProvider>();
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, mockTokenFactory.Object, mockServerPortProvider.Object, mockAssemblyInformationProvider, null, null, null, null, null));
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, mockTokenFactory.Object, mockServerPortProvider.Object, mockAssemblyInformationProvider, null, null, null, null, null, null));
var mockControlPanelOptions = new Mock<IOptions<ControlPanelConfiguration>>();
mockControlPanelOptions.SetupGet(x => x.Value).Returns(new ControlPanelConfiguration()).Verifiable();
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, mockTokenFactory.Object, mockServerPortProvider.Object, mockAssemblyInformationProvider, mockControlPanelOptions.Object, null, null, null, null));
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, mockTokenFactory.Object, mockServerPortProvider.Object, mockAssemblyInformationProvider, mockControlPanelOptions.Object, null, null, null, null, null));
var mockGeneralOptions = new Mock<IOptions<GeneralConfiguration>>();
mockGeneralOptions.SetupGet(x => x.Value).Returns(new GeneralConfiguration()).Verifiable();
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, mockTokenFactory.Object, mockServerPortProvider.Object, mockAssemblyInformationProvider, mockControlPanelOptions.Object, mockGeneralOptions.Object, null, null, null));
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, mockTokenFactory.Object, mockServerPortProvider.Object, mockAssemblyInformationProvider, mockControlPanelOptions.Object, mockGeneralOptions.Object, null, null, null, null));
var mockDatabaseOptions = new Mock<IOptions<DatabaseConfiguration>>();
mockDatabaseOptions.SetupGet(x => x.Value).Returns(new DatabaseConfiguration()).Verifiable();
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, mockTokenFactory.Object, mockServerPortProvider.Object, mockAssemblyInformationProvider, mockControlPanelOptions.Object, mockGeneralOptions.Object, mockDatabaseOptions.Object, null, null, null));
var mockSwarmOptions = new Mock<IOptions<SwarmConfiguration>>();
mockSwarmOptions.SetupGet(x => x.Value).Returns(new SwarmConfiguration()).Verifiable();
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, mockTokenFactory.Object, mockServerPortProvider.Object, mockAssemblyInformationProvider, mockControlPanelOptions.Object, mockGeneralOptions.Object, mockSwarmOptions.Object, null, null));
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, mockTokenFactory.Object, mockServerPortProvider.Object, mockAssemblyInformationProvider, mockControlPanelOptions.Object, mockGeneralOptions.Object, mockDatabaseOptions.Object, mockSwarmOptions.Object, null, null));
var mockInternalOptions = new Mock<IOptions<InternalConfiguration>>();
mockInternalOptions.SetupGet(x => x.Value).Returns(new InternalConfiguration()).Verifiable();
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, mockTokenFactory.Object, mockServerPortProvider.Object, mockAssemblyInformationProvider, mockControlPanelOptions.Object, mockGeneralOptions.Object, mockSwarmOptions.Object, mockInternalOptions.Object, null));
Assert.ThrowsException<ArgumentNullException>(() => app.Configure(mockAppBuilder.Object, mockServerControl.Object, mockTokenFactory.Object, mockServerPortProvider.Object, mockAssemblyInformationProvider, mockControlPanelOptions.Object, mockGeneralOptions.Object, mockDatabaseOptions.Object, mockSwarmOptions.Object, mockInternalOptions.Object, null));
mockControlPanelOptions.VerifyAll();
mockInternalOptions.VerifyAll();
@@ -6,7 +6,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.1" />
</ItemGroup>
<ItemGroup>