From 0b45aee96d740565d4afc31b99a049726da63063 Mon Sep 17 00:00:00 2001 From: Toutsu Date: Mon, 25 May 2026 16:27:29 +0300 Subject: [PATCH] fix(discord): declare slash commands on module methods --- .gitea/workflows/deploy.yml | 2 +- Directory.Build.props | 2 +- compose.yaml | 6 +-- .../Sessions/DiscordListSessionsCommand.cs | 2 +- .../Sessions/DiscordNewSessionCommand.cs | 2 +- .../Sessions/DiscordRescheduleCommand.cs | 2 +- .../Components/Layout/NavMenu.razor | 2 +- .../Discord/DiscordProjectStructureTests.cs | 14 +++---- .../Discord/DiscordStartupTests.cs | 37 +++++++++++++++++++ 9 files changed, 53 insertions(+), 16 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 8627ba9..aef72d3 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -6,7 +6,7 @@ on: - main env: - VERSION: 3.0.2 + VERSION: 3.0.3 jobs: # ЧАСТЬ 1: Собираем образы и кладем в Gitea (чтобы делиться с ребятами) diff --git a/Directory.Build.props b/Directory.Build.props index e14bc3a..b5a75ae 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - 3.0.2 + 3.0.3 net10.0 preview enable diff --git a/compose.yaml b/compose.yaml index ea51a2f..c1625b7 100644 --- a/compose.yaml +++ b/compose.yaml @@ -49,7 +49,7 @@ services: crond -f bot: - image: git.codeanddice.ru/toutsu/gmrelay-bot:3.0.2 + image: git.codeanddice.ru/toutsu/gmrelay-bot:3.0.3 restart: always depends_on: db: @@ -67,7 +67,7 @@ services: retries: 3 discord: - image: git.codeanddice.ru/toutsu/gmrelay-discord-bot:3.0.2 + image: git.codeanddice.ru/toutsu/gmrelay-discord-bot:3.0.3 restart: always depends_on: db: @@ -84,7 +84,7 @@ services: retries: 3 web: - image: git.codeanddice.ru/toutsu/gmrelay-web:3.0.2 + image: git.codeanddice.ru/toutsu/gmrelay-web:3.0.3 restart: always depends_on: db: diff --git a/src/GmRelay.DiscordBot/Features/Sessions/DiscordListSessionsCommand.cs b/src/GmRelay.DiscordBot/Features/Sessions/DiscordListSessionsCommand.cs index 9dd107a..5ce9d6f 100644 --- a/src/GmRelay.DiscordBot/Features/Sessions/DiscordListSessionsCommand.cs +++ b/src/GmRelay.DiscordBot/Features/Sessions/DiscordListSessionsCommand.cs @@ -3,7 +3,6 @@ using NetCord.Services.ApplicationCommands; namespace GmRelay.DiscordBot.Features.Sessions; -[SlashCommand("listsessions", "Show upcoming game sessions in this server")] public class DiscordListSessionsCommand : ApplicationCommandModule { private readonly DiscordListSessionsHandler _handler; @@ -13,6 +12,7 @@ public class DiscordListSessionsCommand : ApplicationCommandModule { private readonly DiscordNewSessionHandler _handler; @@ -16,6 +15,7 @@ public class DiscordNewSessionCommand : ApplicationCommandModule { private readonly DiscordRescheduleHandler _handler; @@ -15,6 +14,7 @@ public class DiscordRescheduleCommand : ApplicationCommandModule - + diff --git a/tests/GmRelay.Bot.Tests/Discord/DiscordProjectStructureTests.cs b/tests/GmRelay.Bot.Tests/Discord/DiscordProjectStructureTests.cs index 7eaff1b..9367541 100644 --- a/tests/GmRelay.Bot.Tests/Discord/DiscordProjectStructureTests.cs +++ b/tests/GmRelay.Bot.Tests/Discord/DiscordProjectStructureTests.cs @@ -61,7 +61,7 @@ public sealed class DiscordProjectStructureTests var prChecks = File.ReadAllText(Path.Combine(repoRoot, ".gitea", "workflows", "pr-checks.yml")); var deploy = File.ReadAllText(Path.Combine(repoRoot, ".gitea", "workflows", "deploy.yml")); - Assert.Contains("gmrelay-discord-bot:3.0.2", compose); + Assert.Contains("gmrelay-discord-bot:3.0.3", compose); Assert.Contains("Discord__Token=${DISCORD_BOT_TOKEN:?Set DISCORD_BOT_TOKEN in .env}", compose); Assert.Contains("src/GmRelay.DiscordBot/Dockerfile", deploy); Assert.Contains("DISCORD_BOT_TOKEN", deploy); @@ -75,13 +75,13 @@ public sealed class DiscordProjectStructureTests { var repoRoot = GetRepoRoot(); - Assert.Contains("3.0.2", File.ReadAllText(Path.Combine(repoRoot, "Directory.Build.props"))); - Assert.Contains("VERSION: 3.0.2", File.ReadAllText(Path.Combine(repoRoot, ".gitea", "workflows", "deploy.yml"))); - Assert.Contains("gmrelay-bot:3.0.2", File.ReadAllText(Path.Combine(repoRoot, "compose.yaml"))); - Assert.Contains("gmrelay-web:3.0.2", File.ReadAllText(Path.Combine(repoRoot, "compose.yaml"))); - Assert.Contains("gmrelay-discord-bot:3.0.2", File.ReadAllText(Path.Combine(repoRoot, "compose.yaml"))); + Assert.Contains("3.0.3", File.ReadAllText(Path.Combine(repoRoot, "Directory.Build.props"))); + Assert.Contains("VERSION: 3.0.3", File.ReadAllText(Path.Combine(repoRoot, ".gitea", "workflows", "deploy.yml"))); + Assert.Contains("gmrelay-bot:3.0.3", File.ReadAllText(Path.Combine(repoRoot, "compose.yaml"))); + Assert.Contains("gmrelay-web:3.0.3", File.ReadAllText(Path.Combine(repoRoot, "compose.yaml"))); + Assert.Contains("gmrelay-discord-bot:3.0.3", File.ReadAllText(Path.Combine(repoRoot, "compose.yaml"))); Assert.Contains( - "v3.0.2", + "v3.0.3", File.ReadAllText(Path.Combine(repoRoot, "src", "GmRelay.Web", "Components", "Layout", "NavMenu.razor"))); } diff --git a/tests/GmRelay.Bot.Tests/Discord/DiscordStartupTests.cs b/tests/GmRelay.Bot.Tests/Discord/DiscordStartupTests.cs index 84c7cbe..f625356 100644 --- a/tests/GmRelay.Bot.Tests/Discord/DiscordStartupTests.cs +++ b/tests/GmRelay.Bot.Tests/Discord/DiscordStartupTests.cs @@ -1,5 +1,8 @@ using System; using System.IO; +using System.Reflection; +using GmRelay.DiscordBot.Features.Sessions; +using NetCord.Services.ApplicationCommands; namespace GmRelay.Bot.Tests.Discord; @@ -50,6 +53,40 @@ public sealed class DiscordStartupTests Assert.Contains("AddModules(typeof(Program).Assembly)", program); } + [Theory] + [InlineData(typeof(DiscordNewSessionCommand), "newsession")] + [InlineData(typeof(DiscordListSessionsCommand), "listsessions")] + [InlineData(typeof(DiscordRescheduleCommand), "reschedule")] + public void DiscordSessionSlashCommands_ShouldBeDeclaredOnModuleMethods(Type moduleType, string commandName) + { + var executeMethod = moduleType.GetMethod("ExecuteAsync", BindingFlags.Instance | BindingFlags.Public); + + Assert.NotNull(executeMethod); + + var methodAttribute = Assert.Single(executeMethod.GetCustomAttributes(inherit: false)); + var nameProperty = typeof(SlashCommandAttribute).GetProperty("Name") + ?? throw new InvalidOperationException("SlashCommandAttribute should expose command name."); + + Assert.Equal(commandName, nameProperty.GetValue(methodAttribute)); + Assert.Empty(moduleType.GetCustomAttributes(inherit: false)); + } + + [Fact] + public void DiscordSessionSlashCommands_ShouldBeDiscoverableByNetCordService() + { + var service = new ApplicationCommandService(); + + service.AddModules(typeof(DiscordNewSessionCommand).Assembly); + + var commandNames = service.GetCommands() + .Select(command => command.Name) + .ToArray(); + + Assert.Contains("newsession", commandNames); + Assert.Contains("listsessions", commandNames); + Assert.Contains("reschedule", commandNames); + } + [Fact] public void LifecycleLogger_ShouldLogGatewayLifecycleEventsWithoutTokenValues() {