From 027b8db6bdf28f394fbc4f014856d29e696739a6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 12 Nov 2023 08:57:13 -0500 Subject: [PATCH 01/10] Nuget package updates --- build/TestCommon.props | 2 +- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 2 +- .../Tgstation.Server.ReleaseNotes.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/TestCommon.props b/build/TestCommon.props index 5562510f72..234e06735a 100644 --- a/build/TestCommon.props +++ b/build/TestCommon.props @@ -13,7 +13,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 4d35ef1280..d3373cd28e 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -107,7 +107,7 @@ - + diff --git a/tools/Tgstation.Server.ReleaseNotes/Tgstation.Server.ReleaseNotes.csproj b/tools/Tgstation.Server.ReleaseNotes/Tgstation.Server.ReleaseNotes.csproj index 35312949ce..4c87963970 100644 --- a/tools/Tgstation.Server.ReleaseNotes/Tgstation.Server.ReleaseNotes.csproj +++ b/tools/Tgstation.Server.ReleaseNotes/Tgstation.Server.ReleaseNotes.csproj @@ -8,7 +8,7 @@ - + From de06107751513fa34b6a49e5afea08034c5f7d84 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 12 Nov 2023 08:58:13 -0500 Subject: [PATCH 02/10] Fix signals test being a special snowflake --- .../Tgstation.Server.Host.Tests.Signals.csproj | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/Tgstation.Server.Host.Tests.Signals/Tgstation.Server.Host.Tests.Signals.csproj b/tests/Tgstation.Server.Host.Tests.Signals/Tgstation.Server.Host.Tests.Signals.csproj index d515505048..7755d96945 100644 --- a/tests/Tgstation.Server.Host.Tests.Signals/Tgstation.Server.Host.Tests.Signals.csproj +++ b/tests/Tgstation.Server.Host.Tests.Signals/Tgstation.Server.Host.Tests.Signals.csproj @@ -1,16 +1,11 @@ - + $(TgsFrameworkVersion) Exe - - - - - From 159b033a1f0477bc9077028728d6b88b05d25551 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 12 Nov 2023 08:58:47 -0500 Subject: [PATCH 03/10] Update to webpanel verison 4.27.0 --- build/ControlPanelVersion.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/ControlPanelVersion.props b/build/ControlPanelVersion.props index 02d75e7142..559fd9eeac 100644 --- a/build/ControlPanelVersion.props +++ b/build/ControlPanelVersion.props @@ -1,6 +1,6 @@ - 4.26.2 + 4.27.0 From bb06a2eff208c49f36cde0818ac98b6fbabedf31 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 15 Nov 2023 19:41:11 -0500 Subject: [PATCH 04/10] `Forbid()` before accessing instance here --- .../Controllers/DreamDaemonController.cs | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs index 097e0377d3..c438b2e7fa 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -208,6 +208,25 @@ namespace Tgstation.Server.Host.Controllers return false; } + if (CheckModified(x => x.AllowWebClient, DreamDaemonRights.SetWebClient) + || CheckModified(x => x.AutoStart, DreamDaemonRights.SetAutoStart) + || CheckModified(x => x.Port, DreamDaemonRights.SetPort) + || CheckModified(x => x.SecurityLevel, DreamDaemonRights.SetSecurity) + || CheckModified(x => x.Visibility, DreamDaemonRights.SetVisibility) + || (model.SoftRestart.HasValue && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.SoftRestart)) + || (model.SoftShutdown.HasValue && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.SoftShutdown)) + || CheckModified(x => x.StartupTimeout, DreamDaemonRights.SetStartupTimeout) + || CheckModified(x => x.HealthCheckSeconds, DreamDaemonRights.SetHealthCheckInterval) + || CheckModified(x => x.DumpOnHealthCheckRestart, DreamDaemonRights.CreateDump) + || CheckModified(x => x.TopicRequestTimeout, DreamDaemonRights.SetTopicTimeout) + || CheckModified(x => x.AdditionalParameters, DreamDaemonRights.SetAdditionalParameters) + || CheckModified(x => x.StartProfiler, DreamDaemonRights.SetProfiler) + || CheckModified(x => x.LogOutput, DreamDaemonRights.SetLogOutput) + || CheckModified(x => x.MapThreads, DreamDaemonRights.SetMapThreads)) + return Forbid(); + + await DatabaseContext.Save(cancellationToken); + return await WithComponentInstance( async instance => { @@ -216,25 +235,6 @@ namespace Tgstation.Server.Host.Controllers var oldSoftRestart = rebootState == RebootState.Restart; var oldSoftShutdown = rebootState == RebootState.Shutdown; - if (CheckModified(x => x.AllowWebClient, DreamDaemonRights.SetWebClient) - || CheckModified(x => x.AutoStart, DreamDaemonRights.SetAutoStart) - || CheckModified(x => x.Port, DreamDaemonRights.SetPort) - || CheckModified(x => x.SecurityLevel, DreamDaemonRights.SetSecurity) - || CheckModified(x => x.Visibility, DreamDaemonRights.SetVisibility) - || (model.SoftRestart.HasValue && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.SoftRestart)) - || (model.SoftShutdown.HasValue && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.SoftShutdown)) - || CheckModified(x => x.StartupTimeout, DreamDaemonRights.SetStartupTimeout) - || CheckModified(x => x.HealthCheckSeconds, DreamDaemonRights.SetHealthCheckInterval) - || CheckModified(x => x.DumpOnHealthCheckRestart, DreamDaemonRights.CreateDump) - || CheckModified(x => x.TopicRequestTimeout, DreamDaemonRights.SetTopicTimeout) - || CheckModified(x => x.AdditionalParameters, DreamDaemonRights.SetAdditionalParameters) - || CheckModified(x => x.StartProfiler, DreamDaemonRights.SetProfiler) - || CheckModified(x => x.LogOutput, DreamDaemonRights.SetLogOutput) - || CheckModified(x => x.MapThreads, DreamDaemonRights.SetMapThreads)) - return Forbid(); - - await DatabaseContext.Save(cancellationToken); - // run this second because current may be modified by it await watchdog.ChangeSettings(current, cancellationToken); From d36e2f59f8fa84d6786124a92a3b530eb85b946e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 15 Nov 2023 20:53:52 -0500 Subject: [PATCH 05/10] Add broadcasting support - Bump appropriate versions - Add DreamDaemon request field and permission bit. - Add generic failure error code. - Remove `ErrorCode` comment since they are being using in #1666. - Fix bad interop return messages. - Adjust DMAPI code to support broadcasts. - Add tests. Closes #138 --- build/Version.props | 10 ++-- docs/Features.dox | 1 + src/DMAPI/tgs.dm | 2 +- src/DMAPI/tgs/v5/__interop_version.dm | 2 +- src/DMAPI/tgs/v5/_defines.dm | 2 + src/DMAPI/tgs/v5/topic.dm | 20 +++++-- src/DMAPI/tgs/v5/undefs.dm | 4 ++ src/Tgstation.Server.Api/Models/ErrorCode.cs | 6 +- .../Models/Request/DreamDaemonRequest.cs | 4 ++ .../Rights/DreamDaemonRights.cs | 5 ++ .../Interop/Topic/TopicCommandType.cs | 5 ++ .../Interop/Topic/TopicParameters.cs | 59 +++++++++++++++---- .../Components/Session/SessionController.cs | 4 +- .../Components/Watchdog/IWatchdog.cs | 8 +++ .../Components/Watchdog/WatchdogBase.cs | 37 ++++++++++++ .../Controllers/DreamDaemonController.cs | 22 ++++--- tests/DMAPI/LongRunning/Test.dm | 4 ++ tests/DMAPI/test_prelude.dm | 3 +- .../Live/Instance/WatchdogTest.cs | 34 +++++++++++ 19 files changed, 200 insertions(+), 32 deletions(-) diff --git a/build/Version.props b/build/Version.props index 0f6cb5b904..81ddc262f7 100644 --- a/build/Version.props +++ b/build/Version.props @@ -5,12 +5,12 @@ 5.17.3 4.7.1 - 9.13.0 + 9.14.0 7.0.0 - 12.0.1 - 14.1.0 - 6.6.2 - 5.6.2 + 12.2.0 + 14.2.0 + 6.7.0 + 5.7.0 1.4.0 1.2.1 1.0.2 diff --git a/docs/Features.dox b/docs/Features.dox index 725b26d947..64eca5a3f7 100644 --- a/docs/Features.dox +++ b/docs/Features.dox @@ -87,4 +87,5 @@ tgstation-server is a BYOND server managment suite. It includes all the followin - Functions with all 3 DreamDaemon security levels - Provides notifications of TGS side events - Allows specifying the .dmb's minimum required security level + - Broadcast messages to clients */ diff --git a/src/DMAPI/tgs.dm b/src/DMAPI/tgs.dm index 0cc106ec9c..b0e97e05e9 100644 --- a/src/DMAPI/tgs.dm +++ b/src/DMAPI/tgs.dm @@ -1,6 +1,6 @@ // tgstation-server DMAPI -#define TGS_DMAPI_VERSION "6.6.2" +#define TGS_DMAPI_VERSION "6.7.0" // All functions and datums outside this document are subject to change with any version and should not be relied on. diff --git a/src/DMAPI/tgs/v5/__interop_version.dm b/src/DMAPI/tgs/v5/__interop_version.dm index 1b52b31d6a..83420d130a 100644 --- a/src/DMAPI/tgs/v5/__interop_version.dm +++ b/src/DMAPI/tgs/v5/__interop_version.dm @@ -1 +1 @@ -"5.6.2" +"5.7.0" diff --git a/src/DMAPI/tgs/v5/_defines.dm b/src/DMAPI/tgs/v5/_defines.dm index bdcd4e4dd5..48969c0c7d 100644 --- a/src/DMAPI/tgs/v5/_defines.dm +++ b/src/DMAPI/tgs/v5/_defines.dm @@ -80,6 +80,7 @@ #define DMAPI5_TOPIC_COMMAND_WATCHDOG_REATTACH 8 #define DMAPI5_TOPIC_COMMAND_SEND_CHUNK 9 #define DMAPI5_TOPIC_COMMAND_RECEIVE_CHUNK 10 +#define DMAPI5_TOPIC_COMMAND_RECEIVE_BROADCAST 11 #define DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE "commandType" #define DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND "chatCommand" @@ -89,6 +90,7 @@ #define DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME "newInstanceName" #define DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE "chatUpdate" #define DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION "newServerVersion" +#define DMAPI5_TOPIC_PARAMETER_BROADCAST_MESSAGE "broadcastMessage" #define DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE "commandResponse" #define DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE "commandResponseMessage" diff --git a/src/DMAPI/tgs/v5/topic.dm b/src/DMAPI/tgs/v5/topic.dm index d7d4712138..2ef0c70a97 100644 --- a/src/DMAPI/tgs/v5/topic.dm +++ b/src/DMAPI/tgs/v5/topic.dm @@ -94,7 +94,7 @@ if(DMAPI5_TOPIC_COMMAND_CHANGE_PORT) var/new_port = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_PORT] if (!isnum(new_port) || !(new_port > 0)) - return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_PORT]]") + return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_PORT]") if(event_handler != null) event_handler.HandleEvent(TGS_EVENT_PORT_SWAP, new_port) @@ -141,7 +141,7 @@ if(DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE) var/new_port = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_PORT] if (!isnum(new_port) || !(new_port > 0)) - return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_PORT]]") + return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_PORT]") server_port = new_port return TopicResponse() @@ -157,7 +157,7 @@ var/error_message = null if (new_port != null) if (!isnum(new_port) || !(new_port > 0)) - error_message = "Invalid [DMAPI5_TOPIC_PARAMETER_NEW_PORT]]" + error_message = "Invalid [DMAPI5_TOPIC_PARAMETER_NEW_PORT]" else server_port = new_port @@ -165,7 +165,7 @@ if (!istext(new_version_string)) if(error_message != null) error_message += ", " - error_message += "Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION]]" + error_message += "Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION]" else var/datum/tgs_version/new_version = new(new_version_string) if (event_handler) @@ -267,4 +267,16 @@ return chunk_to_send + if(DMAPI5_TOPIC_COMMAND_RECEIVE_BROADCAST) + var/message = topic_parameters[DMAPI5_TOPIC_PARAMETER_BROADCAST_MESSAGE] + if (!istext(message)) + return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_BROADCAST_MESSAGE]") + + TGS_WORLD_ANNOUNCE(message) + return TopicResponse() + return TopicResponse("Unknown command: [command]") + +/datum/tgs_api/v5/proc/WorldBroadcast(message) + set waitfor = FALSE + TGS_WORLD_ANNOUNCE(message) diff --git a/src/DMAPI/tgs/v5/undefs.dm b/src/DMAPI/tgs/v5/undefs.dm index f163adaaaf..fd1ed7e4cf 100644 --- a/src/DMAPI/tgs/v5/undefs.dm +++ b/src/DMAPI/tgs/v5/undefs.dm @@ -78,6 +78,9 @@ #undef DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE #undef DMAPI5_TOPIC_COMMAND_HEALTHCHECK #undef DMAPI5_TOPIC_COMMAND_WATCHDOG_REATTACH +#undef DMAPI5_TOPIC_COMMAND_SEND_CHUNK +#undef DMAPI5_TOPIC_COMMAND_RECEIVE_CHUNK +#undef DMAPI5_TOPIC_COMMAND_RECEIVE_BROADCAST #undef DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE #undef DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND @@ -87,6 +90,7 @@ #undef DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME #undef DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE #undef DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION +#undef DMAPI5_TOPIC_PARAMETER_BROADCAST_MESSAGE #undef DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE #undef DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE diff --git a/src/Tgstation.Server.Api/Models/ErrorCode.cs b/src/Tgstation.Server.Api/Models/ErrorCode.cs index ae2dd3341c..69f4d8dbed 100644 --- a/src/Tgstation.Server.Api/Models/ErrorCode.cs +++ b/src/Tgstation.Server.Api/Models/ErrorCode.cs @@ -629,6 +629,10 @@ namespace Tgstation.Server.Api.Models [Description("The deployment took longer than the configured timeout!")] DeploymentTimeout, - // This comment is here to remind you that there is one more unused error code above and you should use it first + /// + /// Sending a broadcast message failed. + /// + [Description("Could not send broadcast to the DMAPI. This can happen either due to there being an insufficient DMAPI version, a communication failure, or the server being offline.")] + BroadcastFailure, } } diff --git a/src/Tgstation.Server.Api/Models/Request/DreamDaemonRequest.cs b/src/Tgstation.Server.Api/Models/Request/DreamDaemonRequest.cs index 0398d69935..0e4c51e993 100644 --- a/src/Tgstation.Server.Api/Models/Request/DreamDaemonRequest.cs +++ b/src/Tgstation.Server.Api/Models/Request/DreamDaemonRequest.cs @@ -7,5 +7,9 @@ namespace Tgstation.Server.Api.Models.Request /// public sealed class DreamDaemonRequest : DreamDaemonApiBase { + /// + /// A to send to the running server's DMAPI for broadcasting. How this is displayed is up to how the DMAPI is integrated in the codebase. Requires interop version >=5.7.0. + /// + public string? BroadcastMessage { get; set; } } } diff --git a/src/Tgstation.Server.Api/Rights/DreamDaemonRights.cs b/src/Tgstation.Server.Api/Rights/DreamDaemonRights.cs index b13002bf9c..378783bf1e 100644 --- a/src/Tgstation.Server.Api/Rights/DreamDaemonRights.cs +++ b/src/Tgstation.Server.Api/Rights/DreamDaemonRights.cs @@ -112,5 +112,10 @@ namespace Tgstation.Server.Api.Rights /// User can change . /// SetMapThreads = 1 << 19, + + /// + /// User can use . + /// + BroadcastMessage = 1 << 20, } } diff --git a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicCommandType.cs b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicCommandType.cs index 29be2c9a10..286c605d07 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicCommandType.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicCommandType.cs @@ -62,5 +62,10 @@ namespace Tgstation.Server.Host.Components.Interop.Topic /// Receive additional data for a previous response. /// ReceiveChunk, + + /// + /// Sending a broadcast message. + /// + Broadcast, } } diff --git a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs index 3da7e1c34c..fff5453b0d 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs @@ -42,6 +42,11 @@ namespace Tgstation.Server.Host.Components.Interop.Topic /// public string NewInstanceName { get; } + /// + /// The message to broadcast for requests. + /// + public string BroadcastMessage { get; } + /// /// The for requests. /// @@ -68,6 +73,7 @@ namespace Tgstation.Server.Host.Components.Interop.Topic or TopicCommandType.ChangeRebootState or TopicCommandType.InstanceRenamed or TopicCommandType.ChatChannelsUpdate + or TopicCommandType.Broadcast or TopicCommandType.ServerRestarted => true, TopicCommandType.ChatCommand or TopicCommandType.HealthCheck @@ -76,6 +82,26 @@ namespace Tgstation.Server.Host.Components.Interop.Topic _ => throw new InvalidOperationException($"Invalid value for {nameof(CommandType)}: {CommandType}"), }; + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The created . + public static TopicParameters CreateInstanceRenamedTopicParameters(string newInstanceName) + => new ( + newInstanceName ?? throw new ArgumentNullException(nameof(newInstanceName)), + TopicCommandType.InstanceRenamed); + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The created . + public static TopicParameters CreateBroadcastParameters(string broadcastMessage) + => new ( + broadcastMessage ?? throw new ArgumentNullException(nameof(broadcastMessage)), + TopicCommandType.Broadcast); + /// /// Initializes a new instance of the class. /// @@ -116,16 +142,6 @@ namespace Tgstation.Server.Host.Components.Interop.Topic NewRebootState = newRebootState; } - /// - /// Initializes a new instance of the class. - /// - /// The value of . - public TopicParameters(string newInstanceName) - : this(TopicCommandType.InstanceRenamed) - { - NewInstanceName = newInstanceName ?? throw new ArgumentNullException(nameof(newInstanceName)); - } - /// /// Initializes a new instance of the class. /// @@ -175,5 +191,28 @@ namespace Tgstation.Server.Host.Components.Interop.Topic { CommandType = commandType; } + + /// + /// Initializes a new instance of the class. + /// + /// The parameter for the property designated by . + /// The value of . + TopicParameters(string stringCommand, TopicCommandType stringCommandType) + : this(stringCommandType) + { +#pragma warning disable IDE0010 // Add missing cases + switch (stringCommandType) + { + case TopicCommandType.InstanceRenamed: + NewInstanceName = stringCommand; + break; + case TopicCommandType.Broadcast: + BroadcastMessage = stringCommand; + break; + default: + throw new InvalidOperationException($"Invalid string TopicCommandType: {stringCommandType}"); + } +#pragma warning restore IDE0010 // Add missing cases + } } } diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index bf0d22fac7..93e05417a3 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -583,7 +583,9 @@ namespace Tgstation.Server.Host.Components.Session public async ValueTask InstanceRenamed(string newInstanceName, CancellationToken cancellationToken) { ReattachInformation.RuntimeInformation.InstanceName = newInstanceName; - await SendCommand(new TopicParameters(newInstanceName), cancellationToken); + await SendCommand( + TopicParameters.CreateInstanceRenamedTopicParameters(newInstanceName), + cancellationToken); } /// diff --git a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs index 360d3fcfc3..2d8d0f5d24 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs @@ -88,5 +88,13 @@ namespace Tgstation.Server.Host.Components.Watchdog /// The for the operation. /// A representing the running operation. ValueTask CreateDump(CancellationToken cancellationToken); + + /// + /// Send a broadcast to the DMAPI. + /// + /// The message to broadcast. + /// The for the operation. + /// A resulting in if the broadcast succeeded., otherwise. + ValueTask Broadcast(string message, CancellationToken cancellationToken); } } diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs index 025f3f27a8..a77496bae2 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs @@ -457,6 +457,43 @@ namespace Tgstation.Server.Host.Components.Watchdog await session.CreateDump(dumpFileName, cancellationToken); } + /// + public async ValueTask Broadcast(string message, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(message); + + var activeServer = GetActiveController(); + if (activeServer == null) + { + Logger.LogInformation("Attempted broadcast failed, no active server!"); + return false; + } + + if (!activeServer.DMApiAvailable) + { + Logger.LogInformation("Attempted broadcast failed, no DMAPI!"); + return false; + } + + var minimumRequiredVersion = new Version(5, 7, 0); + if (activeServer.DMApiVersion < minimumRequiredVersion) + { + Logger.LogInformation( + "Attempted broadcast failed, insufficient interop version: {interopVersion}. Requires {minimumRequiredVersion}!", + activeServer.DMApiVersion, + minimumRequiredVersion); + return false; + } + + Logger.LogInformation("Broadcasting: {message}", message); + + var response = await activeServer.SendCommand( + TopicParameters.CreateBroadcastParameters(message), + cancellationToken); + + return response != null && response.ErrorMessage == null; + } + /// async ValueTask IEventConsumer.HandleEvent(EventType eventType, IEnumerable parameters, bool deploymentPipeline, CancellationToken cancellationToken) { diff --git a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs index c438b2e7fa..3c946af2e0 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -148,7 +148,8 @@ namespace Tgstation.Server.Host.Controllers | DreamDaemonRights.SetVisibility | DreamDaemonRights.SetProfiler | DreamDaemonRights.SetLogOutput - | DreamDaemonRights.SetMapThreads)] + | DreamDaemonRights.SetMapThreads + | DreamDaemonRights.BroadcastMessage)] [ProducesResponseType(typeof(DreamDaemonResponse), 200)] [ProducesResponseType(typeof(ErrorMessageResponse), 410)] #pragma warning disable CA1502 // TODO: Decomplexify @@ -215,6 +216,7 @@ namespace Tgstation.Server.Host.Controllers || CheckModified(x => x.Visibility, DreamDaemonRights.SetVisibility) || (model.SoftRestart.HasValue && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.SoftRestart)) || (model.SoftShutdown.HasValue && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.SoftShutdown)) + || (model.BroadcastMessage != null && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.BroadcastMessage)) || CheckModified(x => x.StartupTimeout, DreamDaemonRights.SetStartupTimeout) || CheckModified(x => x.HealthCheckSeconds, DreamDaemonRights.SetHealthCheckInterval) || CheckModified(x => x.DumpOnHealthCheckRestart, DreamDaemonRights.CreateDump) @@ -225,19 +227,23 @@ namespace Tgstation.Server.Host.Controllers || CheckModified(x => x.MapThreads, DreamDaemonRights.SetMapThreads)) return Forbid(); - await DatabaseContext.Save(cancellationToken); - return await WithComponentInstance( async instance => { var watchdog = instance.Watchdog; + if (model.BroadcastMessage != null + && !await watchdog.Broadcast(model.BroadcastMessage, cancellationToken)) + return Conflict(new ErrorMessageResponse(ErrorCode.BroadcastFailure)); + + await DatabaseContext.Save(cancellationToken); + + // run this second because current may be modified by it + // slight race condition with request cancellation, but I CANNOT be assed right now + await watchdog.ChangeSettings(current, cancellationToken); + var rebootState = watchdog.RebootState; var oldSoftRestart = rebootState == RebootState.Restart; var oldSoftShutdown = rebootState == RebootState.Shutdown; - - // run this second because current may be modified by it - await watchdog.ChangeSettings(current, cancellationToken); - if (!oldSoftRestart && model.SoftRestart == true && watchdog.Status == WatchdogStatus.Online) await watchdog.Restart(true, cancellationToken); else if (!oldSoftShutdown && model.SoftShutdown == true) diff --git a/tests/DMAPI/LongRunning/Test.dm b/tests/DMAPI/LongRunning/Test.dm index c2e274f4d4..57b23805bc 100644 --- a/tests/DMAPI/LongRunning/Test.dm +++ b/tests/DMAPI/LongRunning/Test.dm @@ -174,6 +174,10 @@ var/run_bridge_test if(tactics8) return received_health_check ? "received health check" : "did not receive health check" + var/tactics_broadcast = data["tgs_integration_test_tactics_broadcast"] + if(tactics_broadcast) + return last_tgs_broadcast || "!!NULL!!" + var/legalize_nuclear_bombs = data["shadow_wizard_money_gang"] if(legalize_nuclear_bombs) text2file("I expect this to remain here for a while", "kajigger.txt") diff --git a/tests/DMAPI/test_prelude.dm b/tests/DMAPI/test_prelude.dm index efb84d46ae..6cb666e372 100644 --- a/tests/DMAPI/test_prelude.dm +++ b/tests/DMAPI/test_prelude.dm @@ -3,7 +3,8 @@ #define TGS_READ_GLOBAL(Name) global.##Name #define TGS_WRITE_GLOBAL(Name, Value) global.##Name = ##Value #define TGS_PROTECT_DATUM(Path) -#define TGS_WORLD_ANNOUNCE(message) world << ##message +var/last_tgs_broadcast +#define TGS_WORLD_ANNOUNCE(message) if(TRUE) { var/__tgs_announce_message_local = ##message; world << __tgs_announce_message_local; last_tgs_broadcast = __tgs_announce_message_local; } #define TGS_WARNING_LOG(message) world.log << "Warn: [##message]" #define TGS_NOTIFY_ADMINS(event) #define TGS_CLIENT_COUNT 0 diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 0a67dc8c02..b352bd28d6 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -211,12 +211,46 @@ namespace Tgstation.Server.Tests.Live.Instance await RunTest(false); } + async ValueTask BroadcastTest(CancellationToken cancellationToken) + { + var topicRequestResult = await topicClient.SendTopic( + IPAddress.Loopback, + $"tgs_integration_test_tactics_broadcast=1", + ddPort, + cancellationToken); + + Assert.IsNotNull(topicRequestResult); + Assert.AreEqual("!!NULL!!", topicRequestResult.StringData); + + const string TestBroadcastMessage = "TGS: THIS IS A TEST OF THE EMERGENCY BROADCAST SYSTEM!"; + await instanceClient.DreamDaemon.Update(new DreamDaemonRequest + { + BroadcastMessage = TestBroadcastMessage, + }, cancellationToken); + + topicRequestResult = await topicClient.SendTopic( + IPAddress.Loopback, + $"tgs_integration_test_tactics_broadcast=1", + ddPort, + cancellationToken); + + Assert.IsNotNull(topicRequestResult); + Assert.AreEqual(TestBroadcastMessage, topicRequestResult.StringData); + } + async Task InteropTestsForLongRunningDme(CancellationToken cancellationToken) { await RegressionTest1686(cancellationToken); + await ApiAssert.ThrowsException(() => instanceClient.DreamDaemon.Update(new DreamDaemonRequest + { + BroadcastMessage = "ksjfdksjf", + }, cancellationToken), ErrorCode.BroadcastFailure); + await StartAndLeaveRunning(cancellationToken); + await BroadcastTest(cancellationToken); + await RegressionTest1550(cancellationToken); var deleteJobTask = TestDeleteByondInstallErrorCasesAndQueing(cancellationToken); From 20c882c96cf7af5b37b64e65c608aeb33988d5fd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 16 Nov 2023 23:05:15 -0500 Subject: [PATCH 06/10] Fix `BroadcastMessage` controller checks --- .../Controllers/DreamDaemonController.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs index 3c946af2e0..8e57d022c5 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs @@ -216,7 +216,7 @@ namespace Tgstation.Server.Host.Controllers || CheckModified(x => x.Visibility, DreamDaemonRights.SetVisibility) || (model.SoftRestart.HasValue && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.SoftRestart)) || (model.SoftShutdown.HasValue && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.SoftShutdown)) - || (model.BroadcastMessage != null && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.BroadcastMessage)) + || (!String.IsNullOrWhiteSpace(model.BroadcastMessage) && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.BroadcastMessage)) || CheckModified(x => x.StartupTimeout, DreamDaemonRights.SetStartupTimeout) || CheckModified(x => x.HealthCheckSeconds, DreamDaemonRights.SetHealthCheckInterval) || CheckModified(x => x.DumpOnHealthCheckRestart, DreamDaemonRights.CreateDump) @@ -231,7 +231,7 @@ namespace Tgstation.Server.Host.Controllers async instance => { var watchdog = instance.Watchdog; - if (model.BroadcastMessage != null + if (!String.IsNullOrWhiteSpace(model.BroadcastMessage) && !await watchdog.Broadcast(model.BroadcastMessage, cancellationToken)) return Conflict(new ErrorMessageResponse(ErrorCode.BroadcastFailure)); From 3bd78163c76196dcfc61ad43ff5e66a9a6e42e60 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 16 Nov 2023 23:05:46 -0500 Subject: [PATCH 07/10] Update webpanel version --- build/ControlPanelVersion.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/ControlPanelVersion.props b/build/ControlPanelVersion.props index 559fd9eeac..d7783648cb 100644 --- a/build/ControlPanelVersion.props +++ b/build/ControlPanelVersion.props @@ -1,6 +1,6 @@ - 4.27.0 + 5.1.0 From 17bda5ef486fedada83cc880d2ad66c500194460 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 16 Nov 2023 23:08:54 -0500 Subject: [PATCH 08/10] Standardize naming to "Webpanel" --- build/Dockerfile | 2 +- build/Version.props | 2 +- ...ControlPanelVersion.props => WebpanelVersion.props} | 2 +- src/Tgstation.Server.Host/Core/Application.cs | 2 +- .../Properties/MasterVersionsAttribute.cs | 8 ++++---- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 8 ++++---- tests/Tgstation.Server.Tests/TestVersions.cs | 4 ++-- tgstation-server.sln | 2 +- tools/Tgstation.Server.ReleaseNotes/Program.cs | 10 +++++----- 9 files changed, 20 insertions(+), 20 deletions(-) rename build/{ControlPanelVersion.props => WebpanelVersion.props} (80%) diff --git a/build/Dockerfile b/build/Dockerfile index 5c7c7bd05a..a65df7defe 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -24,7 +24,7 @@ WORKDIR /repo/build COPY build/Common.props Common.props COPY build/NugetCommon.props NugetCommon.props COPY build/Version.props Version.props -COPY build/ControlPanelVersion.props ControlPanelVersion.props +COPY build/WebpanelVersion.props WebpanelVersion.props COPY build/SrcCommon.props SrcCommon.props WORKDIR /repo/src/Tgstation.Server.Host diff --git a/build/Version.props b/build/Version.props index 81ddc262f7..df4b800ca1 100644 --- a/build/Version.props +++ b/build/Version.props @@ -1,7 +1,7 @@ - + 5.17.3 4.7.1 diff --git a/build/ControlPanelVersion.props b/build/WebpanelVersion.props similarity index 80% rename from build/ControlPanelVersion.props rename to build/WebpanelVersion.props index d7783648cb..3e3a8aa08c 100644 --- a/build/ControlPanelVersion.props +++ b/build/WebpanelVersion.props @@ -1,6 +1,6 @@ - 5.1.0 + 5.1.0 diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index a1cdabec96..41effa0094 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -558,7 +558,7 @@ namespace Tgstation.Server.Host.Core logger.LogTrace("Configuration version: {configVersion}", GeneralConfiguration.CurrentConfigVersion); logger.LogTrace("DMAPI Interop version: {interopVersion}", DMApiConstants.InteropVersion); if (controlPanelConfiguration.Enable) - logger.LogTrace("Web control panel version: {webCPVersion}", MasterVersionsAttribute.Instance.RawControlPanelVersion); + logger.LogTrace("Webpanel version: {webCPVersion}", MasterVersionsAttribute.Instance.RawWebpanelVersion); logger.LogDebug("Starting hosting on port {httpApiPort}...", serverPortProvider.HttpApiPort); } diff --git a/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs b/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs index c9bfed3eca..d6461713bb 100644 --- a/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs +++ b/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs @@ -29,7 +29,7 @@ namespace Tgstation.Server.Host.Properties /// /// The of the control panel version built. /// - public string RawControlPanelVersion { get; } + public string RawWebpanelVersion { get; } /// /// The of the control panel version built. @@ -46,19 +46,19 @@ namespace Tgstation.Server.Host.Properties /// /// The value of . /// The value of . - /// The value of . + /// The value of . /// The value of . /// The value of . public MasterVersionsAttribute( string rawConfigurationVersion, string rawInteropVersion, - string rawControlPanelVersion, + string rawWebpanelVersion, string rawHostWatchdogVersion, string rawMariaDBRedistVersion) { RawConfigurationVersion = rawConfigurationVersion ?? throw new ArgumentNullException(nameof(rawConfigurationVersion)); RawInteropVersion = rawInteropVersion ?? throw new ArgumentNullException(nameof(rawInteropVersion)); - RawControlPanelVersion = rawControlPanelVersion ?? throw new ArgumentNullException(nameof(rawControlPanelVersion)); + RawWebpanelVersion = rawWebpanelVersion ?? throw new ArgumentNullException(nameof(rawWebpanelVersion)); RawHostWatchdogVersion = rawHostWatchdogVersion ?? throw new ArgumentNullException(nameof(rawHostWatchdogVersion)); RawMariaDBRedistVersion = rawMariaDBRedistVersion ?? throw new ArgumentNullException(nameof(rawMariaDBRedistVersion)); } diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 3c5ace62ae..bcca6637c3 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -22,17 +22,17 @@ $(DefineConstants);NO_WEBPANEL - + - + - + @@ -47,7 +47,7 @@ <_Parameter1>$(TgsConfigVersion) <_Parameter2>$(TgsInteropVersion) - <_Parameter3>$(TgsControlPanelVersion) + <_Parameter3>$(TgsWebpanelVersion) <_Parameter4>$(TgsHostWatchdogVersion) <_Parameter5>$(TgsMariaDBRedistVersion) diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 41c48a1196..a87b47b2b1 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -284,11 +284,11 @@ namespace Tgstation.Server.Tests [TestMethod] public void TestControlPanelVersion() { - var doc = XDocument.Load("../../../../../build/ControlPanelVersion.props"); + var doc = XDocument.Load("../../../../../build/WebpanelVersion.props"); var project = doc.Root; var controlPanelXmlNamespace = project.GetDefaultNamespace(); var controlPanelVersionsPropertyGroup = project.Elements().First(x => x.Name == controlPanelXmlNamespace + "PropertyGroup"); - var versionString = controlPanelVersionsPropertyGroup.Element(controlPanelXmlNamespace + "TgsControlPanelVersion").Value; + var versionString = controlPanelVersionsPropertyGroup.Element(controlPanelXmlNamespace + "TgsWebpanelVersion").Value; Assert.IsNotNull(versionString); Assert.IsTrue(Version.TryParse(versionString, out var expected)); diff --git a/tgstation-server.sln b/tgstation-server.sln index 36d9027e9d..ce57c2ea30 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -26,7 +26,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{6FF654E6 build\BuildDox.ps1 = build\BuildDox.ps1 build\ci.runsettings = build\ci.runsettings build\Common.props = build\Common.props - build\ControlPanelVersion.props = build\ControlPanelVersion.props build\Dockerfile = build\Dockerfile build\GenerateMigrations.sh = build\GenerateMigrations.sh build\logo.svg = build\logo.svg @@ -39,6 +38,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{6FF654E6 build\tgstation-server.service = build\tgstation-server.service build\uac_elevation_manifest.xml = build\uac_elevation_manifest.xml build\Version.props = build\Version.props + build\WebpanelVersion.props = build\WebpanelVersion.props EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Api", "src\Tgstation.Server.Api\Tgstation.Server.Api.csproj", "{8B4A208D-A48A-4A5D-8B94-E2661138865D}" diff --git a/tools/Tgstation.Server.ReleaseNotes/Program.cs b/tools/Tgstation.Server.ReleaseNotes/Program.cs index 21bdbc1bfa..79b594e505 100644 --- a/tools/Tgstation.Server.ReleaseNotes/Program.cs +++ b/tools/Tgstation.Server.ReleaseNotes/Program.cs @@ -223,7 +223,7 @@ namespace Tgstation.Server.ReleaseNotes string prefix; const string PropsPath = "build/Version.props"; - const string ControlPanelPropsPath = "build/ControlPanelVersion.props"; + const string ControlPanelPropsPath = "build/WebpanelVersion.props"; var doc = XDocument.Load(PropsPath); var project = doc.Root; @@ -246,7 +246,7 @@ namespace Tgstation.Server.ReleaseNotes 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 webControlVersion = Version.Parse(controlPanelVersionsPropertyGroup.Element(controlPanelXmlNamespace + "TgsWebpanelVersion").Value); var hostWatchdogVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsHostWatchdogVersion").Value); if (webControlVersion.Major == 0) @@ -608,14 +608,14 @@ namespace Tgstation.Server.ReleaseNotes dict.Add(Component.NugetApi, Parse("TgsApiLibraryVersion")); dict.Add(Component.NugetClient, Parse("TgsClientVersion")); - var webVersion = Parse("TgsControlPanelVersion"); + var webVersion = Parse("TgsWebpanelVersion"); if (webVersion != null) { dict.Add(Component.WebControlPanel, webVersion); } else { - var controlPanelVersionBytes = await RLR(() => client.Repository.Content.GetRawContentByRef(RepoOwner, RepoName, "build/ControlPanelVersion.props", mergeCommit)); + var controlPanelVersionBytes = await RLR(() => client.Repository.Content.GetRawContentByRef(RepoOwner, RepoName, "build/WebpanelVersion.props", mergeCommit)); using (var ms = new MemoryStream(controlPanelVersionBytes)) doc = XDocument.Load(ms); @@ -623,7 +623,7 @@ namespace Tgstation.Server.ReleaseNotes project = doc.Root; var controlPanelXmlNamespace = project.GetDefaultNamespace(); var controlPanelVersionsPropertyGroup = project.Elements().First(x => x.Name == controlPanelXmlNamespace + "PropertyGroup"); - dict.Add(Component.WebControlPanel, Version.Parse(controlPanelVersionsPropertyGroup.Element(controlPanelXmlNamespace + "TgsControlPanelVersion").Value)); + dict.Add(Component.WebControlPanel, Version.Parse(controlPanelVersionsPropertyGroup.Element(controlPanelXmlNamespace + "TgsWebpanelVersion").Value)); } } From 682d954262a9aa0367799d9a12384b170440a3a4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 16 Nov 2023 23:09:28 -0500 Subject: [PATCH 09/10] Fix Windows Live tests always succeeding --- .github/workflows/ci-pipeline.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 82252adb17..4439daea55 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -468,11 +468,11 @@ jobs: sleep 10 set +e test_output=$(dotnet test -c ${{ matrix.configuration }} --no-build --filter TestCategory=RequiresDatabase --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true" --collect:"XPlat Code Coverage" --settings ../../build/ci.runsettings --results-directory ../../TestResults) - succeeded=$? + retval=$? set -e cd ../.. echo $test_output > ./test_output.txt - if [[ $retVal -ne 0 ]]; then + if [[ $retval -ne 0 ]]; then echo "succeeded=NO" >> $GITHUB_OUTPUT else echo "succeeded=YES" >> $GITHUB_OUTPUT From 2fe93929347af1e3acc64deaada985525ea38e02 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 16 Nov 2023 23:09:50 -0500 Subject: [PATCH 10/10] Version bump to 5.18.0 --- build/Version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Version.props b/build/Version.props index df4b800ca1..3478f0fc6f 100644 --- a/build/Version.props +++ b/build/Version.props @@ -3,7 +3,7 @@ - 5.17.3 + 5.18.0 4.7.1 9.14.0 7.0.0