From 2f0655cdc5480405ee087386f38faae71c97dd0a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 31 Jul 2024 17:17:29 -0400 Subject: [PATCH 1/4] Remove `Z.EntityFramework.Plus` Switch to using `RelationalQueryableExtensions.ExecuteDeleteAsync` for async deletes --- .../Components/Session/SessionPersistor.cs | 6 ++---- src/Tgstation.Server.Host/Controllers/ChatController.cs | 4 +--- .../Controllers/InstancePermissionSetController.cs | 4 +--- .../Controllers/UserGroupController.cs | 4 +--- src/Tgstation.Server.Host/Database/DatabaseSeeder.cs | 2 -- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 2 -- 6 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs index 5c87bfda5f..edfc6a5145 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs @@ -11,8 +11,6 @@ using Tgstation.Server.Host.Database; using Tgstation.Server.Host.Models; using Tgstation.Server.Host.System; -using Z.EntityFramework.Plus; - namespace Tgstation.Server.Host.Components.Session { /// @@ -221,7 +219,7 @@ namespace Tgstation.Server.Host.Components.Session .ReattachInformations .AsQueryable() .Where(x => x.Id == result.Id) - .DeleteAsync(cancellationToken); + .ExecuteDeleteAsync(cancellationToken); }); return null; } @@ -271,7 +269,7 @@ namespace Tgstation.Server.Host.Components.Session if (instant) await baseQuery - .DeleteAsync(cancellationToken); + .ExecuteDeleteAsync(cancellationToken); else { var results = await baseQuery.ToListAsync(cancellationToken); diff --git a/src/Tgstation.Server.Host/Controllers/ChatController.cs b/src/Tgstation.Server.Host/Controllers/ChatController.cs index 9ea7f4f5a7..fd6cf80e1d 100644 --- a/src/Tgstation.Server.Host/Controllers/ChatController.cs +++ b/src/Tgstation.Server.Host/Controllers/ChatController.cs @@ -26,8 +26,6 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; -using Z.EntityFramework.Plus; - namespace Tgstation.Server.Host.Controllers { /// @@ -189,7 +187,7 @@ namespace Tgstation.Server.Host.Controllers .ChatBots .AsQueryable() .Where(x => x.Id == id) - .DeleteAsync(cancellationToken)); + .ExecuteDeleteAsync(cancellationToken)); return null; }) diff --git a/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs b/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs index d86f0b7877..58b0170ad4 100644 --- a/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs @@ -20,8 +20,6 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; -using Z.EntityFramework.Plus; - namespace Tgstation.Server.Host.Controllers { /// @@ -259,7 +257,7 @@ namespace Tgstation.Server.Host.Controllers .Where(x => x.Id == Instance.Id) .SelectMany(x => x.InstancePermissionSets) .Where(x => x.PermissionSetId == id) - .DeleteAsync(cancellationToken); + .ExecuteDeleteAsync(cancellationToken); return numDeleted > 0 ? NoContent() : this.Gone(); } diff --git a/src/Tgstation.Server.Host/Controllers/UserGroupController.cs b/src/Tgstation.Server.Host/Controllers/UserGroupController.cs index b6f48b8197..838b7a1bcf 100644 --- a/src/Tgstation.Server.Host/Controllers/UserGroupController.cs +++ b/src/Tgstation.Server.Host/Controllers/UserGroupController.cs @@ -21,8 +21,6 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; -using Z.EntityFramework.Plus; - namespace Tgstation.Server.Host.Controllers { /// @@ -221,7 +219,7 @@ namespace Tgstation.Server.Host.Controllers .Groups .AsQueryable() .Where(x => x.Id == id && x.Users!.Count == 0) - .DeleteAsync(cancellationToken); + .ExecuteDeleteAsync(cancellationToken); if (numDeleted > 0) return NoContent(); diff --git a/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs b/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs index 694fff0c9c..4eaf4e21b9 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs @@ -14,8 +14,6 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Security; using Tgstation.Server.Host.System; -using Z.EntityFramework.Plus; - namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 197583214f..cf412dc3ce 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -124,8 +124,6 @@ - - From db50f17482b07777dba95e6a73f486692ac63501 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 31 Jul 2024 17:45:19 -0400 Subject: [PATCH 2/4] Expose `RevInfoTestMerges` and `TestMerges` in `IDatabaseContext` --- .../Database/DatabaseContext.cs | 18 ++++++++++++++++++ .../Database/IDatabaseContext.cs | 10 ++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/Tgstation.Server.Host/Database/DatabaseContext.cs b/src/Tgstation.Server.Host/Database/DatabaseContext.cs index fc9836c240..7e0ee690cf 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseContext.cs @@ -126,6 +126,12 @@ namespace Tgstation.Server.Host.Database /// IDatabaseCollection IDatabaseContext.RevisionInformations => revisionInformationsCollection; + /// + IDatabaseCollection IDatabaseContext.RevInfoTestMerges => revInfoTestMergesCollection; + + /// + IDatabaseCollection IDatabaseContext.TestMerges => testMergesCollection; + /// IDatabaseCollection IDatabaseContext.DreamMakerSettings => dreamMakerSettingsCollection; @@ -188,6 +194,16 @@ namespace Tgstation.Server.Host.Database /// readonly IDatabaseCollection revisionInformationsCollection; + /// + /// Backing field for . + /// + readonly IDatabaseCollection revInfoTestMergesCollection; + + /// + /// Backing field for . + /// + readonly IDatabaseCollection testMergesCollection; + /// /// Backing field for . /// @@ -267,6 +283,8 @@ namespace Tgstation.Server.Host.Database chatBotsCollection = new DatabaseCollection(ChatBots!); chatChannelsCollection = new DatabaseCollection(ChatChannels!); revisionInformationsCollection = new DatabaseCollection(RevisionInformations!); + revInfoTestMergesCollection = new DatabaseCollection(RevInfoTestMerges!); + testMergesCollection = new DatabaseCollection(TestMerges!); jobsCollection = new DatabaseCollection(Jobs!); reattachInformationsCollection = new DatabaseCollection(ReattachInformations!); oAuthConnections = new DatabaseCollection(OAuthConnections!); diff --git a/src/Tgstation.Server.Host/Database/IDatabaseContext.cs b/src/Tgstation.Server.Host/Database/IDatabaseContext.cs index 00b90298c6..2ca3f748f6 100644 --- a/src/Tgstation.Server.Host/Database/IDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/IDatabaseContext.cs @@ -45,6 +45,16 @@ namespace Tgstation.Server.Host.Database /// IDatabaseCollection RevisionInformations { get; } + /// + /// The s in the . + /// + IDatabaseCollection RevInfoTestMerges { get; } + + /// + /// The s in the . + /// + IDatabaseCollection TestMerges { get; } + /// /// The in the . /// From 4ad3195ffacdf8b8a7e9f0a237f6fed207eb2e50 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 31 Jul 2024 17:55:11 -0400 Subject: [PATCH 3/4] Fix the issue where you can't detach an instance due to database conflicts --- .../Controllers/InstanceController.cs | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/InstanceController.cs b/src/Tgstation.Server.Host/Controllers/InstanceController.cs index b56d5a9a7a..dbcb03b70b 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceController.cs @@ -285,8 +285,6 @@ namespace Tgstation.Server.Host.Controllers if (originalModel.Online!.Value) return Conflict(new ErrorMessageResponse(ErrorCode.InstanceDetachOnline)); - DatabaseContext.Instances.Remove(originalModel); - var originalPath = originalModel.Path!; var attachFileName = ioManager.ConcatPath(originalPath, InstanceAttachFileName); try @@ -301,7 +299,35 @@ namespace Tgstation.Server.Host.Controllers throw; } - await DatabaseContext.Save(cancellationToken); // cascades everything + try + { + // yes this is racy af. I hate it + // there's a bug where removing the root instance doesn't work sometimes + await DatabaseContext + .CompileJobs + .AsQueryable() + .Where(x => x.Job!.Instance!.Id == id) + .ExecuteDeleteAsync(cancellationToken); + await DatabaseContext + .RevInfoTestMerges + .AsQueryable() + .Where(x => x.RevisionInformation.InstanceId == id) + .ExecuteDeleteAsync(cancellationToken); + await DatabaseContext + .RevisionInformations + .AsQueryable() + .Where(x => x.InstanceId == id) + .ExecuteDeleteAsync(cancellationToken); + + DatabaseContext.Instances.Remove(originalModel); + await DatabaseContext.Save(cancellationToken); // cascades everything else + } + catch + { + await ioManager.DeleteFile(attachFileName, CancellationToken.None); // DCT: Shouldn't be cancelled + throw; + } + return NoContent(); } From f1eaf9bfebfc34e44740b19fc1b16d7ac91f7e09 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 31 Jul 2024 17:44:56 -0400 Subject: [PATCH 4/4] Add a check for dotnet tool version matches --- .github/workflows/ci-pipeline.yml | 60 ++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 2e04ae0b1e..54007f37f3 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -284,6 +284,64 @@ jobs: cd tests/DMAPI/BasicOperation $HOME/OpenDream/tgs_deploy/bin/compiler/DMCompiler --verbose --notices-enabled "basic operation_test.dme" + efcore-version-match: + name: Check Nuget Versions Match Tools + runs-on: ubuntu-latest + needs: start-ci-run-gate + if: (!(cancelled() || failure()) && needs.start-ci-run-gate.result == 'success') + steps: + - name: Checkout (Branch) + uses: actions/checkout@v4 + if: github.event_name == 'push' || github.event_name == 'schedule' + + - name: Checkout (PR Merge) + uses: actions/checkout@v4 + if: github.event_name != 'push' && github.event_name != 'schedule' + with: + ref: "refs/pull/${{ github.event.number }}/merge" + + - name: Retrieve dotnet-ef Tool Version + id: dotnet-ef-tool + run: echo "version=$(cat src/Tgstation.Server.Host/.config/dotnet-tools.json | jq -r '.tools."dotnet-ef".version')" >> $GITHUB_OUTPUT + + - name: Retrieve wix Tool Version + id: wix-tool + run: echo "version=$(cat build/package/winget/.config/dotnet-tools.json | jq -r '.tools.wix.version')" >> $GITHUB_OUTPUT + + - name: Retrieve dotnet-ef Nuget Version + id: dotnet-ef-nuget + run: | + regex='\s+' + if [[ $(cat src/Tgstation.Server.Host/Tgstation.Server.Host.csproj) =~ $regex ]]; then + echo "version=${BASH_REMATCH[1]}" >> $GITHUB_OUTPUT + else + echo "Regex search failed!" + exit 1 + fi + + - name: Retrieve wix Nuget Version + id: wix-nuget + run: | + regex='' + if [[ $(cat build/package/winget/Tgstation.Server.Host.Service.Wix/Tgstation.Server.Host.Service.Wix.wixproj) =~ $regex ]]; then + echo "version=${BASH_REMATCH[1]}" >> $GITHUB_OUTPUT + else + echo "Regex search failed!" + exit 1 + fi + + - name: Fail if dotnet-ef Versions Don't Match + if: ${{ steps.dotnet-ef-tool.outputs.version != steps.dotnet-ef-nuget.outputs.version }} + run: | + echo "${{ steps.dotnet-ef-tool.outputs.version }} != ${{ steps.dotnet-ef-nuget.outputs.version }}" + exit 1 + + - name: Fail if wix Versions Don't Match + if: ${{ steps.wix-tool.outputs.version != steps.wix-nuget.outputs.version }} + run: | + echo "${{ steps.wix-tool.outputs.version }} != ${{ steps.wix-nuget.outputs.version }}" + exit 1 + pages-build: name: Build gh-pages runs-on: ubuntu-latest @@ -1405,7 +1463,7 @@ jobs: ci-completion-gate: # This job exists so there isn't a moving target for branch protections name: CI Completion Gate - needs: [ pages-build, docker-build, build-deb, build-msi, validate-openapi-spec, upload-code-coverage, check-winget-pr-template, code-scanning ] + needs: [ pages-build, docker-build, build-deb, build-msi, validate-openapi-spec, upload-code-coverage, check-winget-pr-template, code-scanning, efcore-version-match ] runs-on: ubuntu-latest if: (!(cancelled() || failure()) && needs.pages-build.result == 'success' && needs.docker-build.result == 'success' && needs.build-deb.result == 'success' && needs.build-msi.result == 'success' && needs.validate-openapi-spec.result == 'success' && needs.upload-code-coverage.result == 'success' && needs.check-winget-pr-template.result == 'success' && needs.code-scanning.result == 'success') steps: