From 5f353b4e2bd286490ad4963a6516297683aaa800 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 24 Jun 2023 02:05:46 -0400 Subject: [PATCH 001/160] .msi + `winget` package initial support --- .codecov.yml | 1 + .github/CONTRIBUTING.md | 2 +- .github/workflows/ci-suite.yml | 48 +- .gitignore | 1 + README.md | 36 +- .../manifest.xml | 22 +- .../package/{deb => }/appsettings.Initial.yml | 0 .../Program.cs | 96 ++ ...ation.Server.Host.Service.Configure.csproj | 14 + .../Tgstation.Server.Host.Service.Msi.vdproj | 1042 +++++++++++++++++ build/package/winget/build_package.ps1 | 21 + build/package/winget/install_banner.jpg | Bin 0 -> 11811 bytes .../manifest/Tgstation.Server.installer.yaml | 28 + .../Tgstation.Server.locale.en-US.yaml | 12 + .../winget/manifest/Tgstation.Server.yaml | 8 + .../Tgstation.Server.Host.Console.csproj | 1 + src/Tgstation.Server.Host.Service/Program.cs | 60 +- .../Tgstation.Server.Host.Service.csproj | 1 + .../Tgstation.Server.Host.csproj | 25 +- tgstation-server.sln | 40 +- 20 files changed, 1410 insertions(+), 48 deletions(-) rename {src/Tgstation.Server.Host => build}/manifest.xml (97%) rename build/package/{deb => }/appsettings.Initial.yml (100%) create mode 100644 build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs create mode 100644 build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj create mode 100644 build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj create mode 100644 build/package/winget/build_package.ps1 create mode 100644 build/package/winget/install_banner.jpg create mode 100644 build/package/winget/manifest/Tgstation.Server.installer.yaml create mode 100644 build/package/winget/manifest/Tgstation.Server.locale.en-US.yaml create mode 100644 build/package/winget/manifest/Tgstation.Server.yaml diff --git a/.codecov.yml b/.codecov.yml index 86207739c5..a55ee4d34f 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -8,6 +8,7 @@ coverage: comment: layout: "header, diff, changes" ignore: + - "build" - "src/Tgstation.Server.Host/Database/Design" - "src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs" - "src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs" diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e6c9393e81..a9eff3af35 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -34,7 +34,7 @@ You can of course, as always, ask for help at [#coderbus](irc://irc.rizon.net/co ### Development Environment -You need the Dotnet 6.0 SDK and npm>=v5.7 (in your PATH) to compile the server. In order to build the service version you also need a .NET 4.7.1 build chain +You need the Dotnet 6.0 SDK and npm>=v5.7 (in your PATH) to compile the server. In order to build the service version you also need a .NET 4.7.2 build chain. In order to build the .msi installer, you'll need [Visual Studio 2022](https://visualstudio.microsoft.com/vs/) or greater and the [Visual Studio Installer Projects Extension](https://marketplace.visualstudio.com/items?itemName=VisualStudioClient.MicrosoftVisualStudio2022InstallerProjects). The recommended IDE is Visual Studio 2019 which has installation options for both of these. diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 0f88ac9211..08afc555d0 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -920,11 +920,39 @@ jobs: name: packaging-debian path: tgstation-server-v${{ env.TGS_VERSION }}.debian.packaging.tar.xz + build-msi: + name: Build .msi Package + needs: start-ci-run-gate + runs-on: windows-latest + if: "!(cancelled() || failure()) && needs.start-ci-run-gate.result == 'success'" + steps: + - name: Setup dotnet + uses: actions/setup-dotnet@v2 + with: + dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + + - name: Setup VS Dev Environment + uses: seanmiddleditch/gha-setup-vsdevenv@v4 + + - name: Disable Out of Process Building + working-directory: C:/Program Files/Microsoft Visual Studio/2022/Enterprise/Common7/IDE/CommonExtensions/Microsoft/VSI/DisableOutOfProcBuild + run: ./DisableOutOfProcBuild.exe + + - name: Build .vdproj + shell: powershell + run: build/package/winget/build_package.ps1 + + - name: Upload .msi + uses: actions/upload-artifact@v3 + with: + name: packaging-windows + path: packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi + deployment-gate: name: Deployment Gate - needs: [ dox-build, docker-build, build-deb, validate-openapi-spec, upload-code-coverage ] + needs: [ dox-build, docker-build, build-deb, validate-openapi-spec, upload-code-coverage, build-msi ] runs-on: ubuntu-latest - if: "!(cancelled() || failure()) && needs.dox-build.result == 'success' && needs.docker-build.result == 'success' && needs.build-deb.result == 'success' && needs.validate-openapi-spec.result == 'success' && needs.upload-code-coverage.result == 'success' && github.event_name == 'push'" + if: "!(cancelled() || failure()) && needs.dox-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' && github.event_name == 'push'" steps: - name: GitHub Requires at Least One Step for a Job run: exit 0 @@ -1120,6 +1148,12 @@ jobs: name: packaging-debian path: packaging-debian + - name: Retrieve .msi + uses: actions/download-artifact@v3 + with: + name: packaging-windows + path: packaging-windows + - name: Zip Artifacts shell: powershell run: | @@ -1203,6 +1237,16 @@ jobs: asset_name: tgstation-server-v${{ env.TGS_VERSION }}.debian.packaging.tar.xz asset_content_type: application/x-tar + - name: Upload .msi + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./packaging-windows/tgstation-server.msi + asset_name: tgstation-server.msi + asset_content_type: application/octet-stream + deploy-docker: name: Deploy TGS (Docker) needs: deploy-tgs diff --git a/.gitignore b/.gitignore index 9d6c8caecd..607abbf4c2 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ release_notes.md *nupkg *.sqlite3 packaging/ +build/package/winget/Tgstation.Server.Host.Service.Msi/Release/ diff --git a/README.md b/README.md index bb07b4281e..c73f4d905a 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,39 @@ Follow the instructions for your OS below. #### Windows -Download and install the [ASP .NET Core Runtime (>= v6.0)](https://dotnet.microsoft.com/download/dotnet/6.0) (Choose the option to `Run Server Apps` for your system). If you plan to install tgstation-server as a Windows service, you should also ensure that your .NET Framework runtime version is >= v4.7.2 (Most modern systems have it by default. Download can be found on same page). Ensure that the `dotnet` executable file is in your system's `PATH` variable (or that of the user's that will be running the server), you can test this by opening a command prompt and running `dotnet --list-runtimes`. +##### Installer + +If you don't have it installed already, download and install the [ASP .NET Core Runtime (>= v6.0)](https://dotnet.microsoft.com/download/dotnet/6.0). Ensure that the `dotnet` executable file is in your system's `PATH` variable (or that of the user's that will be running the server). You can test this by opening a command prompt and running `dotnet --list-runtimes`. + +You should also ensure that your .NET Framework runtime version is >= v4.7.2. Most modern systems have it by default so this isn't much of a concern. If, somehow, you don't have it installed, it can be downloaded [here](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net472). + +[Download the latest release .msi](https://github.com/tgstation/tgstation-server/releases/latest). Executing it will take you through the process of installing and configuring your server. + +##### winget + +If you have [winget]() installed. You can easily install the latest version of tgstation-server (provided Microsoft has approved the most recent package manifest). + +Simply run the following command: +```sh +winget install tgstation-server +``` + +If you get an error like `This file does not have an app associated with it for performing this action.` run with the `--silent` flag: +```sh +winget install tgstation-server --silent +``` + +You won't be prompted to run the setup wizard. However, you can do so immediately after via the shortcut placed on your desktop. + +NOTE: + +`winget` should, theoretically, install the ASP .NET Core 6.0 Runtime as a pre-reqiusite. At the time of this writing, this functionality is untested (TODO). If the runtime isn't automatically installed for you, see above or below for steps on how to download and install it manually. + +##### Manual + +If you don't have it installed already, download and install the [ASP .NET Core Runtime (>= v6.0)](https://dotnet.microsoft.com/download/dotnet/6.0). Ensure that the `dotnet` executable file is in your system's `PATH` variable (or that of the user's that will be running the server). You can test this by opening a command prompt and running `dotnet --list-runtimes`. + +You should also ensure that your .NET Framework runtime version is >= v4.7.2. Most modern systems have it by default so this isn't much of a concern. If, somehow, you don't have it installed, it can be downloaded [here](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net472). [Download the latest release .zip](https://github.com/tgstation/tgstation-server/releases/latest). You probably want the `ServerService` package. Choose `ServerConsole` if you prefer not to use the Windows service. @@ -36,7 +68,7 @@ If you wish to install the TGS as a service, run `Tgstation.Server.Host.Service. Should you want a clean start, be sure to first uninstall the service by running `Tgstation.Server.Host.Service.exe -u` from the command line. -If using the console version, run ./tgs.bat in the root of the installation directory. Ctrl+C will close the server, terminating all live game instances. +If using the console version, run `./tgs.bat` in the root of the installation directory. Ctrl+C will close the server, terminating all live game instances. #### Linux diff --git a/src/Tgstation.Server.Host/manifest.xml b/build/manifest.xml similarity index 97% rename from src/Tgstation.Server.Host/manifest.xml rename to build/manifest.xml index 5173bf8331..05ddda9c2a 100644 --- a/src/Tgstation.Server.Host/manifest.xml +++ b/build/manifest.xml @@ -1,11 +1,11 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/build/package/deb/appsettings.Initial.yml b/build/package/appsettings.Initial.yml similarity index 100% rename from build/package/deb/appsettings.Initial.yml rename to build/package/appsettings.Initial.yml diff --git a/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs b/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs new file mode 100644 index 0000000000..c55662074b --- /dev/null +++ b/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs @@ -0,0 +1,96 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; + +using var process = new Process(); + +var installDir = Path.GetDirectoryName( + Assembly.GetExecutingAssembly().Location)!; + +process.StartInfo.WorkingDirectory = installDir; +process.StartInfo.FileName = Path.Combine( + process.StartInfo.WorkingDirectory, + "Tgstation.Server.Host.Service.exe"); + +/* +https://www.roelvanlisdonk.nl/2009/11/13/how-to-detect-unattended-installation-msiexec-quit-or-qn-in-youre-custom-action-with-c/ +msiUILevelNoChange 0 Does not change UI level. +msiUILevelDefault 1 Uses default UI level. +msiUILevelNone 2 Silent installation. +msiUILevelBasic 3 Simple progress and error handling. +msiUILevelReduced 4 Authored UI and wizard dialog boxes suppressed. +msiUILevelFull 5 Authored UI with wizards, progress, and errors. +msiUILevelHideCancel 32 If combined with the msiUILevelBasic value, the installer shows progress dialog boxes but does not display a Cancel button on the dialog box to prevent users from canceling the installation. +msiUILevelProgressOnly 64 If combined with the msiUILevelBasic value, the installer displays progress dialog boxes but does not display any modal dialog boxes or error dialog boxes. +msiUILevelEndDialog 128 If combined with any above value, the installer displays a modal dialog box at the end of a successful installation or if there has been an error. No dialog box is displayed if the user cancels. +*/ +var uiLevel = Int32.Parse(args[0]); + +// leave it to MS to overcomplicate things +var interactive = uiLevel switch +{ + 0 or 1 or 4 or 5 => true, + _ => false, +}; + +var silent = uiLevel == 2; + +var uninstall = args + .Any(arg => arg.Equals("--uninstall", StringComparison.OrdinalIgnoreCase)); + +var shortcut = uiLevel == 42069; + +process.StartInfo.Arguments = uninstall + ? "-u" + : shortcut + ? "-c" + : $"-i -f {(interactive ? "-c" : String.Empty)} {(silent ? "-s" : String.Empty)}"; + +process.Start(); + +await process.WaitForExitAsync(CancellationToken.None); // DCT: None available + +foreach (var installLogFile in Directory.EnumerateFiles(installDir, "*.log")) + File.Delete(installLogFile); + +if (uninstall) +{ + Directory.Delete( + Path.Combine(installDir, "lib"), + true); +} + +if(shortcut && process.ExitCode == 0) +{ + Console.WriteLine(); + Console.Write("tgstation-server is now configured. Would you like to (re)start the service? (Y/n): "); + var keyInfo = Console.ReadKey(); + Console.WriteLine(); + if (keyInfo.Key == ConsoleKey.Y || keyInfo.Key == ConsoleKey.Enter) + { + using (var stopService = new Process()) + { + stopService.StartInfo.FileName = "sc"; + stopService.StartInfo.Arguments = "stop tgstation-server"; + stopService.Start(); + await stopService.WaitForExitAsync(CancellationToken.None); // DCT: None available + } + + using var startService = new Process(); + startService.StartInfo.FileName = "sc"; + startService.StartInfo.Arguments = "start tgstation-server"; + startService.Start(); + await startService.WaitForExitAsync(CancellationToken.None); // DCT: None available + } + + Console.WriteLine("Press any key to exit this program..."); + Console.ReadKey(); + Console.WriteLine(); +} + +// returning non-zero can make the installation uninstallable, no thanks +return uninstall ? 0 : process.ExitCode; diff --git a/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj b/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj new file mode 100644 index 0000000000..15716db084 --- /dev/null +++ b/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj @@ -0,0 +1,14 @@ + + + + Exe + net6.0 + enable + ../../../manifest.xml + ../../../tgs.ico + + + + + + diff --git a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj new file mode 100644 index 0000000000..8ea9bf88b6 --- /dev/null +++ b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj @@ -0,0 +1,1042 @@ +"DeployProject" +{ +"VSVersion" = "3:800" +"ProjectType" = "8:{978C614F-708E-4E1A-B201-565925725DBA}" +"IsWebType" = "8:FALSE" +"ProjectName" = "8:Tgstation.Server.Host.Service.Msi" +"LanguageId" = "3:1033" +"CodePage" = "3:1252" +"UILanguageId" = "3:1033" +"SccProjectName" = "8:" +"SccLocalPath" = "8:" +"SccAuxPath" = "8:" +"SccProvider" = "8:" + "Hierarchy" + { + "Entry" + { + "MsmKey" = "8:_11E0E9B45549402D92B039FCCD0783B8" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_137A5E0CCDBF4E4A9549C03C74D3988C" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_415514E8CEF94645B44E5665C5B9D8F5" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_4F14AB1FF9E24F9EBCC13DECAD76B526" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_8F775F391C394240882C33EF95C853E3" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_B0A2BC595A554F188D336702686A821E" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_E3B62CFD59F3484BACCB88E834824355" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_E9F7402DCE77463F9B7319647D3C16F2" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + } + "Configurations" + { + "Release" + { + "DisplayName" = "8:Release" + "IsDebugOnly" = "11:FALSE" + "IsReleaseOnly" = "11:TRUE" + "OutputFilename" = "8:Release\\tgstation-server.msi" + "PackageFilesAs" = "3:2" + "PackageFileSize" = "3:-2147483648" + "CabType" = "3:1" + "Compression" = "3:3" + "SignOutput" = "11:FALSE" + "CertificateFile" = "8:" + "PrivateKeyFile" = "8:" + "TimeStampServer" = "8:" + "InstallerBootstrapper" = "3:2" + "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" + { + "Enabled" = "11:TRUE" + "PromptEnabled" = "11:TRUE" + "PrerequisitesLocation" = "2:1" + "Url" = "8:" + "ComponentsUrl" = "8:" + "Items" + { + "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.7.2" + { + "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)" + "ProductCode" = "8:.NETFramework,Version=v4.7.2" + } + "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:Microsoft.NetCore.CoreRuntime.6.0.x64" + { + "Name" = "8:.NET Runtime 6.0.18 (x64)" + "ProductCode" = "8:Microsoft.NetCore.CoreRuntime.6.0.x64" + } + } + } + } + } + "Deployable" + { + "CustomAction" + { + "{4AA51A2D-7D85-4A59-BA75-B0809FC8B380}:_A53906ED15374112AC84662B6F2E8041" + { + "Name" = "8:Publish Items from Tgstation.Server.Host.Service.Configure (Active)" + "Condition" = "8:" + "Object" = "8:_E9F7402DCE77463F9B7319647D3C16F2" + "FileType" = "3:2" + "InstallAction" = "3:1" + "Arguments" = "8:[UILevel]" + "EntryPoint" = "8:" + "Sequence" = "3:1" + "Identifier" = "8:_B09766E4_1B68_49DE_9726_68FD609D967B" + "InstallerClass" = "11:FALSE" + "CustomActionData" = "8:" + "Run64Bit" = "11:TRUE" + } + "{4AA51A2D-7D85-4A59-BA75-B0809FC8B380}:_A953E29077C84B36ADF6660A83C8B004" + { + "Name" = "8:Publish Items from Tgstation.Server.Host.Service.Configure (Active)" + "Condition" = "8:" + "Object" = "8:_E9F7402DCE77463F9B7319647D3C16F2" + "FileType" = "3:2" + "InstallAction" = "3:4" + "Arguments" = "8:[UILevel] --uninstall" + "EntryPoint" = "8:" + "Sequence" = "3:1" + "Identifier" = "8:_6B8510E1_5DAE_4023_AD93_B9DD1AC65C45" + "InstallerClass" = "11:FALSE" + "CustomActionData" = "8:" + "Run64Bit" = "11:TRUE" + } + } + "DefaultFeature" + { + "Name" = "8:DefaultFeature" + "Title" = "8:" + "Description" = "8:" + } + "ExternalPersistence" + { + "LaunchCondition" + { + "{A06ECF26-33A3-4562-8140-9B0E340D4F24}:_C5FA609714B64925A18859A195267F9F" + { + "Name" = "8:.NET Core" + "Message" = "8:[VSDNETCOREMSG]" + "AllowLaterVersions" = "11:FALSE" + "InstallUrl" = "8:https://dotnet.microsoft.com/download/dotnet-core/[NetCoreVerMajorDotMinor]" + "IsNETCore" = "11:TRUE" + "Architecture" = "2:0" + "Runtime" = "2:0" + } + } + } + "File" + { + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_137A5E0CCDBF4E4A9549C03C74D3988C" + { + "SourcePath" = "8:..\\..\\..\\..\\src\\Tgstation.Server.Host\\appsettings.yml" + "TargetName" = "8:appsettings.yml" + "Tag" = "8:" + "Folder" = "8:_B28C4FD80D0245E08AEDCFEECACB6493" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4F14AB1FF9E24F9EBCC13DECAD76B526" + { + "SourcePath" = "8:..\\install_banner.jpg" + "TargetName" = "8:install_banner.jpg" + "Tag" = "8:" + "Folder" = "8:_EB2DCEE6D3F74230A9827AC9B6F47F53" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8F775F391C394240882C33EF95C853E3" + { + "SourcePath" = "8:..\\install_banner.jpg" + "TargetName" = "8:install_banner.jpg" + "Tag" = "8:" + "Folder" = "8:_EB2DCEE6D3F74230A9827AC9B6F47F53" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:TRUE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B0A2BC595A554F188D336702686A821E" + { + "SourcePath" = "8:..\\..\\..\\..\\LICENSE" + "TargetName" = "8:LICENSE" + "Tag" = "8:" + "Folder" = "8:_B28C4FD80D0245E08AEDCFEECACB6493" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:TRUE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E3B62CFD59F3484BACCB88E834824355" + { + "SourcePath" = "8:..\\..\\appsettings.Initial.yml" + "TargetName" = "8:appsettings.Production.yml" + "Tag" = "8:" + "Folder" = "8:_B28C4FD80D0245E08AEDCFEECACB6493" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + } + "FileType" + { + } + "Folder" + { + "{3C67513D-01DD-4637-8A68-80971EB9504F}:_B28C4FD80D0245E08AEDCFEECACB6493" + { + "DefaultLocation" = "8:[ProgramFiles64Folder][Manufacturer]\\[ProductName]" + "Name" = "8:#1925" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:TARGETDIR" + "Folders" + { + "{9EF0B969-E518-4E46-987F-47570745A589}:_D8FD06A5721D4746BD1D087E6329F3CF" + { + "Name" = "8:lib" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:_1760E07222D34C3ABECB83B8D17A7256" + "Folders" + { + "{9EF0B969-E518-4E46-987F-47570745A589}:_44E17B6EBB30432E9D4FBB976D7E029A" + { + "Name" = "8:Default" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:_40C981E76FB44E748278A84D5E727464" + "Folders" + { + } + } + } + } + } + } + "{1525181F-901A-416C-8A58-119130FE478E}:_BD1E6451115645479FB57AD1F0BB6A8B" + { + "Name" = "8:#1916" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:DesktopFolder" + "Folders" + { + } + } + "{1525181F-901A-416C-8A58-119130FE478E}:_D53B13F517CB437C874C9E216C3F8F5F" + { + "Name" = "8:#1937" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:CommonFiles64Folder" + "Folders" + { + } + } + "{994432C3-9487-495D-8656-3E829A8DBDDE}:_EB2DCEE6D3F74230A9827AC9B6F47F53" + { + "DefaultLocation" = "8:[TARGETDIR]" + "Name" = "8:Install Resources" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:NEWPROPERTY1" + "Folders" + { + } + } + } + "LaunchCondition" + { + } + "Locator" + { + } + "MsiBootstrapper" + { + "LangId" = "3:1033" + "RequiresElevation" = "11:FALSE" + } + "Product" + { + "Name" = "8:Microsoft Visual Studio" + "ProductName" = "8:tgstation-server" + "ProductCode" = "8:{D24887FA-3228-4509-B5F3-4E07E349F278}" + "PackageCode" = "8:{5740BC0C-02EE-42AB-8B50-BCCAF4AF0322}" + "UpgradeCode" = "8:{151FE9F8-72CF-48D5-8E55-B7FB6BA9693E}" + "AspNetVersion" = "8:4.0.30319.0" + "RestartWWWService" = "11:FALSE" + "RemovePreviousVersions" = "11:TRUE" + "DetectNewerInstalledVersion" = "11:TRUE" + "InstallAllUsers" = "11:TRUE" + "ProductVersion" = "8:22.47.5" + "Manufacturer" = "8:tgstation" + "ARPHELPTELEPHONE" = "8:" + "ARPHELPLINK" = "8:" + "Title" = "8:Tgstation.Server.Host.Service.Setup" + "Subject" = "8:" + "ARPCONTACT" = "8:Dominon/Cyberboss" + "Keywords" = "8:" + "ARPCOMMENTS" = "8:" + "ARPURLINFOABOUT" = "8:https://tgstation13.org" + "ARPPRODUCTICON" = "8:" + "ARPIconIndex" = "3:0" + "SearchPath" = "8:" + "UseSystemSearchPath" = "11:TRUE" + "TargetPlatform" = "3:1" + "PreBuildEvent" = "8:" + "PostBuildEvent" = "8:" + "RunPostBuildEvent" = "3:0" + } + "Registry" + { + "HKLM" + { + "Keys" + { + "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_BB4EE4F5EF8A4C1BA6BAA85FE34E56C4" + { + "Name" = "8:Software" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_05C235158E3A4664B285EA29511EF02D" + { + "Name" = "8:[Manufacturer]" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + } + "Values" + { + } + } + } + "Values" + { + } + } + } + } + "HKCU" + { + "Keys" + { + "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_0379B7F8F5504CDA9DB9B9D546DB606D" + { + "Name" = "8:Software" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_6E60244E84834632A09C938ACAAC308D" + { + "Name" = "8:[Manufacturer]" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + } + "Values" + { + } + } + } + "Values" + { + } + } + } + } + "HKCR" + { + "Keys" + { + } + } + "HKU" + { + "Keys" + { + } + } + "HKPU" + { + "Keys" + { + } + } + } + "Sequences" + { + } + "Shortcut" + { + "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_86C54A96871E40B6B517685DB09F223A" + { + "Name" = "8:Configure and Start tgstation-server" + "Arguments" = "8:42069 " + "Description" = "8:Runs the TGS setup wizard and optionally restarts the Windows service" + "ShowCmd" = "3:1" + "IconIndex" = "3:0" + "Transitive" = "11:FALSE" + "Target" = "8:_E9F7402DCE77463F9B7319647D3C16F2" + "Folder" = "8:_BD1E6451115645479FB57AD1F0BB6A8B" + "WorkingFolder" = "8:_B28C4FD80D0245E08AEDCFEECACB6493" + "Icon" = "8:" + "Feature" = "8:" + } + } + "UserInterface" + { + "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_0E30589D83D5457EA1590BDA4DB93D03" + { + "UseDynamicProperties" = "11:FALSE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdBasicDialogs.wim" + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_109A5A97F789460AB73CDF166664A916" + { + "Name" = "8:#1902" + "Sequence" = "3:2" + "Attributes" = "3:3" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_76284EF5FA104F46A0644EE9513C0A4D" + { + "Sequence" = "3:100" + "DisplayName" = "8:Finished" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminFinishedDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:2" + "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_278559DEB3E24BBCAA1C9B3F68673761" + { + "Name" = "8:#1900" + "Sequence" = "3:1" + "Attributes" = "3:1" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_7CD912AA05C244CB8A903FBFD33E29A8" + { + "Sequence" = "3:300" + "DisplayName" = "8:Confirm Installation" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdConfirmDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:2" + "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_B3748469032C440CA8C833C645EF67F9" + { + "Sequence" = "3:100" + "DisplayName" = "8:Welcome" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdWelcomeDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:2" + "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "UsePlugInResources" = "11:TRUE" + } + "CopyrightWarning" + { + "Name" = "8:CopyrightWarning" + "DisplayName" = "8:#1002" + "Description" = "8:#1102" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1202" + "DefaultValue" = "8:#1202" + "UsePlugInResources" = "11:TRUE" + } + "Welcome" + { + "Name" = "8:Welcome" + "DisplayName" = "8:#1003" + "Description" = "8:#1103" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1203" + "DefaultValue" = "8:#1203" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_BE9B710186F946AC828F528A90F9B1CA" + { + "Sequence" = "3:200" + "DisplayName" = "8:Installation Folder" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdFolderDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:2" + "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "UsePlugInResources" = "11:TRUE" + } + "InstallAllUsersVisible" + { + "Name" = "8:InstallAllUsersVisible" + "DisplayName" = "8:#1059" + "Description" = "8:#1159" + "Type" = "3:5" + "ContextData" = "8:1;True=1;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:1" + "DefaultValue" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_2C7325D993884C978B1A4381E1143564" + { + "Name" = "8:#1901" + "Sequence" = "3:2" + "Attributes" = "3:2" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_FB014E47DC3540A2AA6B4B1B109BDA09" + { + "Sequence" = "3:100" + "DisplayName" = "8:Progress" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminProgressDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:2" + "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "UsePlugInResources" = "11:TRUE" + } + "ShowProgress" + { + "Name" = "8:ShowProgress" + "DisplayName" = "8:#1009" + "Description" = "8:#1109" + "Type" = "3:5" + "ContextData" = "8:1;True=1;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:1" + "DefaultValue" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_34AD1EE11A4C483C8F39A6F57C055D1C" + { + "Name" = "8:#1900" + "Sequence" = "3:2" + "Attributes" = "3:1" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_0C069DDECE324687A9F07480971F4EA1" + { + "Sequence" = "3:200" + "DisplayName" = "8:Installation Folder" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminFolderDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:2" + "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_566942A0B14E44D2ABECDB1CCA6B4229" + { + "Sequence" = "3:300" + "DisplayName" = "8:Confirm Installation" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminConfirmDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:2" + "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_CDECB4E7DDE84A4DB72B528A15D01E47" + { + "Sequence" = "3:110" + "DisplayName" = "8:Welcome" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminWelcomeDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:2" + "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "UsePlugInResources" = "11:TRUE" + } + "CopyrightWarning" + { + "Name" = "8:CopyrightWarning" + "DisplayName" = "8:#1002" + "Description" = "8:#1102" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1202" + "DefaultValue" = "8:#1202" + "UsePlugInResources" = "11:TRUE" + } + "Welcome" + { + "Name" = "8:Welcome" + "DisplayName" = "8:#1003" + "Description" = "8:#1103" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1203" + "DefaultValue" = "8:#1203" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_C1FAAD9180D249AE930209CFFDE47E92" + { + "Name" = "8:#1902" + "Sequence" = "3:1" + "Attributes" = "3:3" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_F066076B6F3F439D9B70A2243DCC8D99" + { + "Sequence" = "3:100" + "DisplayName" = "8:Finished" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdFinishedDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:2" + "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "UsePlugInResources" = "11:TRUE" + } + "UpdateText" + { + "Name" = "8:UpdateText" + "DisplayName" = "8:#1058" + "Description" = "8:#1158" + "Type" = "3:15" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:2" + "Value" = "8:You can now start tgstation-server from your Services control panel. Press Win+R and enter 'services.msc' to access it. Then navigate to http://localhost: to manage your server." + "DefaultValue" = "8:#1258" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_CDC222C0F1734F22A35CE4BE55CD389D" + { + "UseDynamicProperties" = "11:FALSE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdUserInterface.wim" + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_E2FF183010DC4AD5868B1B6BB4835C7F" + { + "Name" = "8:#1901" + "Sequence" = "3:1" + "Attributes" = "3:2" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_9C81E7707FD24FA98CE1C7DAAB793AB6" + { + "Sequence" = "3:100" + "DisplayName" = "8:Progress" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdProgressDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:2" + "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "UsePlugInResources" = "11:TRUE" + } + "ShowProgress" + { + "Name" = "8:ShowProgress" + "DisplayName" = "8:#1009" + "Description" = "8:#1109" + "Type" = "3:5" + "ContextData" = "8:1;True=1;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:1" + "DefaultValue" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + } + "MergeModule" + { + } + "ProjectOutput" + { + "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_11E0E9B45549402D92B039FCCD0783B8" + { + "SourcePath" = "8:..\\..\\..\\..\\src\\Tgstation.Server.Host\\obj\\Release\\net6.0\\apphost.exe" + "TargetName" = "8:" + "Tag" = "8:" + "Folder" = "8:_44E17B6EBB30432E9D4FBB976D7E029A" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + "ProjectOutputGroupRegister" = "3:1" + "OutputConfiguration" = "8:" + "OutputGroupCanonicalName" = "8:PublishItems" + "OutputProjectGuid" = "8:{2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}" + "ShowKeyOutput" = "11:TRUE" + "ExcludeFilters" + { + "ExcludeFilter" = "8:appsettings.yml" + } + } + "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_415514E8CEF94645B44E5665C5B9D8F5" + { + "SourcePath" = "8:..\\..\\..\\..\\src\\Tgstation.Server.Api\\bin\\Release\\netstandard2.0\\Tgstation.Server.Api.xml" + "TargetName" = "8:" + "Tag" = "8:" + "Folder" = "8:_44E17B6EBB30432E9D4FBB976D7E029A" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + "ProjectOutputGroupRegister" = "3:1" + "OutputConfiguration" = "8:" + "OutputGroupCanonicalName" = "8:Documentation" + "OutputProjectGuid" = "8:{8B4A208D-A48A-4A5D-8B94-E2661138865D}" + "ShowKeyOutput" = "11:TRUE" + "ExcludeFilters" + { + } + } + "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_5222E155071449818AC7AD899B0BD0EE" + { + "SourcePath" = "8:" + "TargetName" = "8:" + "Tag" = "8:" + "Folder" = "8:_44E17B6EBB30432E9D4FBB976D7E029A" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + "ProjectOutputGroupRegister" = "3:1" + "OutputConfiguration" = "8:" + "OutputGroupCanonicalName" = "8:ContentFiles" + "OutputProjectGuid" = "8:{2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}" + "ShowKeyOutput" = "11:TRUE" + "ExcludeFilters" + { + "ExcludeFilter" = "8:appsettings.yml" + } + } + "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_B2B80DADC2EA4646A8E8E8E54F2AE2EE" + { + "SourcePath" = "8:" + "TargetName" = "8:" + "Tag" = "8:" + "Folder" = "8:_B28C4FD80D0245E08AEDCFEECACB6493" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:TRUE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + "ProjectOutputGroupRegister" = "3:1" + "OutputConfiguration" = "8:" + "OutputGroupCanonicalName" = "8:PublishItems" + "OutputProjectGuid" = "8:{29927416-3B78-49A7-A560-5CCAA638B6B4}" + "ShowKeyOutput" = "11:TRUE" + "ExcludeFilters" + { + } + } + "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_E9F7402DCE77463F9B7319647D3C16F2" + { + "SourcePath" = "8:..\\Tgstation.Server.Host.Service.Configure\\obj\\Release\\net6.0\\apphost.exe" + "TargetName" = "8:" + "Tag" = "8:" + "Folder" = "8:_B28C4FD80D0245E08AEDCFEECACB6493" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + "ProjectOutputGroupRegister" = "3:1" + "OutputConfiguration" = "8:" + "OutputGroupCanonicalName" = "8:PublishItems" + "OutputProjectGuid" = "8:{6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}" + "ShowKeyOutput" = "11:TRUE" + "ExcludeFilters" + { + } + } + } + } +} diff --git a/build/package/winget/build_package.ps1 b/build/package/winget/build_package.ps1 new file mode 100644 index 0000000000..940d1aad62 --- /dev/null +++ b/build/package/winget/build_package.ps1 @@ -0,0 +1,21 @@ +$currentCommit=git rev-parse HEAD + +Remove-Item -Recurse -Force packaging + +git worktree remove -f packaging + +$ErrorActionPreference="Stop" + +git worktree add -f packaging $currentCommit +cd packaging +Remove-Item -Recurse -Force .git + +[XML]$versionXML = Get-Content build/Version.props +$tgsVersion = $versionXML.Project.PropertyGroup.TgsCoreVersion + +(Get-Content build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj).Replace('22.47.5', $tgsVersion) | Set-Content build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj + +# We make _some_ assumptions +DevEnv tgstation-server.sln /Project build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj /build Release + +cd .. diff --git a/build/package/winget/install_banner.jpg b/build/package/winget/install_banner.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4bbe3f134ca548b4e035f377bf55db0f2ef49414 GIT binary patch literal 11811 zcmd6NXH-*Pzh>wiq(pjAs?t(^llKpGXexBbx)CuYw85ydU`qrCPpTvzmu7TjfI(+m6?f&m4lU)jU60J zESy{%?3{nE|9;8e$NxSBe%P6rnE&4K|2C*!A>7Q6_q5$~G^Zi7+%$CDG}Ly8I0Qn& z0Iv4$g8yUC(9+Q}FoH{BWdm=hIsq=9j*b>wECW3~cy|!^e+WG{1J9}Rx{SQ$_nA&V z<-71QF^5@Fue=3nF-VkBdEgbo!g`WlKu}0pMpo|3Syi=*>KdAt^sgEi8X22hv%F<> z+uG)it>eQ-PR=f_Zr;y)eEm@V0k1;C!XqN1qLY%}q@t0)Oki8U2~@UPkB#Yc*)GCmzY!D!Xl|+L4-c= z8e}~wr8+N7`fJ+1Ec^Ei3;F-D>^}|rUv^DF*y(7%;L&kIV31?-hiEy-KW&yF7x_D3 zY?J{U+b&KBHEdT-+zcaYJsuB;&qWAV}NJzsV|OF}8{>a=Kt5>%qlvX=}Z{B1SMS zjCntZdlgT-IRI!XFB)~>r@ZiY0j-4~@A-(A+VU#-5spl$PNRl~9zM(y+LkH=dcFC@ zxM1_Tn1(~9^$se8>1m(~;N`wfkpb($J}vCH(C`YhuwC`ccC zeGp-?E5xZCFTZ;0#WU zkOkwiU50N8?W;`f=G#}gA(@s`h${@xT-mb)IQLK1i`6ZNN7d(@dSftOs+#fWHC?4z zM@#gD&_zY=WXKY&q5MJkhdOlmsy70mUwrfcr&zfQvxB(~09u$u{&vZy&O}^`7!>e! zlsKD~wmvnR*BtvX^oddc!3810p84=#oXopO;e-RDME!8P^sDP=^RE3{cgydm6+$7JwXTYUXtzGRNT&U!Wa_$m3x9{Y<=^S2Dd z2J;`kr|_?4s}ddR92a10K=g$D+F@MAM)ZQp>wvjpdB)p@G>IuGFCIxe8zp}NqbrD> ztC;;8-MfM2l_V{L&S2oar0~FNBB4|?DoF^e=aUcxGw9zR00YJA{J6^lg zwx+jlo=rFnuMBZ=4ps0zNPM~Myd;&J$<>dGgAs32AybZfA;`pqggE>O55-NDl_?uH z_m7i3EZ>D@$9p1UcZ8p4S%(2sNS7_PgG=;}gUq<6%!tnbH)5dZH@{c8tCELIVqU7D zY|@>{D4qP~tm7ouT%>pPFpDo5c3bePHN!yYtRn`-_`iRbrUZl8`mZK!+jP%`mbu{d#s z3Yoyn1@3JHUO%pDge@>%xuc}mDENqetMI!ZU5oS@M+@Egm7M7*%y{8(8v5!a%)E3j zrODQ4IqR9j89;XdPY2i;jjLhVfEc4eZ3C_;)l$79v-H_<%NQxo5bK*?%B;d~CZ_15 z98Djwp<8Hh50t08+bAc293mJVZXGF>D%3+zzj3jc?b8Euyw*m*0RC!Dd=5B z%UX5uk{Sxjpbwk{eb3%i$i6e=o}FcWuUmr4{hPF1%iI+p$Ef}Kwe0L<<9&HUe6evuAZ&*gnon)~q2aVJ|Z6CA^Xr(vqMPvHMh&BO7w( zy@K&~f6Z+h+*}g=vpSilxWzYE21s$7ugf#?toV&SQ3WRm?w+)-GcI`|k(DNq2ra)S zEE}I9GMj8G8{FP2_bI#7u8#Z@Wj(JP-RLvl?`-pftg^u2XiQvZ{Bygxd^o?hdiWGQ zoz&Lpl&A|m>Y8*4mysCkS_24fuU^9*plMbkS`T$07P-76~gx&?2phMoCjYT8|*eho5X}p`I$Bwq zy#(mD|E>-wd7Xb@x>{e#-zg6IvC8-zp7B;oX>c6_DZlAC_AbCP}PgDbv=(ROK)-BYgSuC}l_e)TP^SW3kyB@AY zc+QRN92I6fP8~mC{KepOc8C3~SHI7UwGI{Ye;6-PeQM=u;br}Se)DhH;V z_kxJ<_RE5|FRORfOXpY6>)k(7&D;J(;7)|_qLbWDT0v$B?r1{sV!G=j#!*nFEF@Yk z@7zC$x?p<{z$N_N#85MTaK~*7)3YYGjz&9@@U7|~xLNeA=NaxYGtEC9`Y;7PFpVUn zm_Uq+&(Vk7x5W`{xd4rVHe9*Z9|U_dcU44;j^b6UYfxb-uWL4UhQ__c#HY_P6J)g{ z(Yv83E_Mf#z&nz9J4~?g`6pCvNBUUqf;czQyQ-g(i`FuG>T_zN&wuR&(-jCEgvMda zF0H%!c6OBeFH~LXeJH;VaPKMCtMLjQ@Ezw_balhxk#I{+*DGzKPSKuDQg(x$aN+ldgxXU&)Eg-*2 zORcFeF@4;m`selAslVIT!__qCiZq?1-@TB}iMYRZ>Zti)AacYexYSCJIvG|=6F#~El>JRrl=iWfy~&pRY8 zD4#?Qx+$Uy`=9%Zq%mH;vBB5Vb)m5R=?5ay%ArO}?97yt~px zj6yfxmqxFS29IU=+A_T_JOb!*%@RL0w9jJ^t~F81Gi&=ib~oOyAakMjF@XeVZP7(H@6cwh0x7u&;9nEs&>xT#p6-Q#2z64tGJh<>-mN~}9@ zoIa*$!>VgeSL^DAJcJ3fS1tU$N!BJU+q}5y_9NuVBj{ljq8$VJF|$IvuP&h7r*Ev|FNqL=kRFcl#!Yb#Vxymk3;&AFK9+{;3P{+PlMa|2XCcGaBsj}(`9joT;_CB*|yV7?%yjWUqA z7^t7&-G)g_kN$aIh4zZ`-Lg&6eAZLqCw*WH%`B*zy%-=P4^aO)D?X}iz7XeuINN*U zb7-$>J8j==boBcQtrLZx`r0AJ6tKqT!l@9VAq#BoErp?$#2*uA^t>$a8c8v#y1AmN z!7C6>} zv9ieYE$8qJ8?hO2y55>Q5({cyrFGr=)U8*;0>>N^-c09;^5FXp?>5i~NZZ=h)FjU1 ziI$iH!!80F74mSn9dn4R!!CZnm7{?(1LR!Cy)Y`|i|YdXSncOHY0%zZxkcGB`4X_W zioT8~y48?B#1Bw9n=B7H5P4Py4O9qYF}g=?oeEh;j>0mn4h*dn zdoPbMWXU7TK(TRcy2XCkBfnM$$+%M^k99`Xuv1VelUx3;>y2xlS#Et^i+=~*LX-9V zkNDApf>cOvjXf2zG<6gm-3k4qYs-Ti%(xM!+3@|$VQ$oM7R(vWNa@BgK0`#{xOUKh z5&6{oXv(uAuBri_y{8I8aM?{+zr+fuGQ5h2$JehA&Z+3LA{l;?*w)=f zXDa0W^yaZ#0A*Yr$OX2k5b54d^qy!l6*3fo^^}@LE02&=nsT;}xkd&63FY-&Z15q(M*)f8>TBpz0tOEUik)H)~AA0GYQ3F6`ES$qmh4C0VNP))6voqbJ1n;8v_>GEZ+U zkC5j5RbA}RZ{Vj-mcQ4&PA?t$KBq@l1iIx0dRbV!Qu#O;&Vybn`-O{-rgVVuDu8Xp zB~0;Cx(lLUJLBGnE`#TSf9t&Kd$Y!&_`l0(65=V^$8bjmGIM~$hiLgXzggw~Qn#m| zx6TGWJC4D5Y)0bQ$cpo@(D6g2P|pw56}6+!`t|I(tx9v=yc5!z_>ncly#=y~u|{#q z>D}XxuvKFKbase4sJT+rR@>yUaz*mUU;f+ua)vjQ4*kUkm17$1@&TsSfc%D%S>62A zL&dzB{c-P$6NGzFY~7M#J)iQDSLFc=5V3HJl-ADSZ4)P?vFon4Kr*i{Ofr1JHLSMV zMVJOR{*B`t&=c>)XzPgyQB|c}ZDO1wtim(AZ6_6-J<&DqQ%$5&{jQTcRg_wvT+1p> zICC6@n|p^4!p-H>Tq+=+#V}DJt-7u`rhK+p>r-*1DNQevwft0vPCd9H>&Ez)_NhZN z9ow!;kB{vLi8O&N={c8|9r4GHEcg|+@Pqt}3i;fbOoe>#Ku+N1*0IreVko*rWe3OA zb;l)0S4Jn5BGxbUGy?dXtHO<_8j)PW;)(hC#Ud;|19wq!rjh4d}>fEJ_ zz?|S=5p&M#)5QH2DFz)b;#fw`YhhoVex%6d=f~fxepbwM$3Hl!sVH?JyJ|l!(7??r%t+AFo3J_(yH;d`1o7dH zP#B;274YJ}ccRauiQdYDCRu_Nm^54?fszIG+MqJlNJ4pyo$Km#*MD*;w03>gEstr$ z_6&Ay2$zBblvc<*T{d7Mdj*fG+lIy9-S8ZgQ+MG-t3sLU+a{ipnyw`tQXmz-Fv)Im z!LVmi@fXAHmteU2rl&iXtj5Zo&c^r%;L(KK<2p`N#<^pr+2%J}dj(}`JO$iHQ!{t3 z=HyjWTzOQVb!+Z?{H$gkBr)slH>`9ioE|l84Imd4W!oLZN3g0v-ueyEpe$&vdfjz7 zlca%KG875F4SDrjeofl%WNzK|Q&$ts$LPlnY((EQ;%3VfJYvUG?%52#UPT1_b7klQ zEj!drBM~H}=R=`bYi02w7C5~^hUy!Gwq*zRojiwz-kw+F3C9^ootr*sHx|n^7F{eN>byDzGEBi|AIg02Ou;0ztEDV^|ZOPqPZ1> zND$Xr289D``Moip1Y2U`pU@h`JJC3Gu$kt0U?7S)jteN*j>Z`mcXgq~f(yz+DD;<4 zm>WQQe8l@A$S245n1MACg2I|XifGq42`H1C+tV3~KIuwl7kotN-)yXCFn9L&n47Bc zPK43oLf#fL0Rc*mwsM>+{7@Ym4+HevFysfg@&NgXg3KG-=F7J7VwbOH^Jb)}jQ*s^ zQ4|9iNdsRmyIltNdNz`C$gW^ofbE|tgU$?Z_Bi(R=*HG`Rtjw3&tdvCDW3EZ{7H~JkukSA? zN9d>zyKnBq`A!a-Q@Rq~Yz5z>+R;h`6_x4RZN0&E^%J^$wCS!K)b?ei}dy`k;I6QTnWf-Y9ZVA?*oJ1GR+EXJ5YlTJ#Xwx~F^GE}Zh#aX;2V zyKL*v+*oVvf~Zi?&gChMj|!JcEvpN*Wsgw7z3TXK7$JhhHt)WZd}EetOscA?Hbt-7 z&uPvSsU;_MCTZ6Ap#*On(2bQUg^Qr@HbC0qWxI9@bq@n(CqngK*#?a&Islod}j^OgD0Ozrm#FJLAMxEA#NG=db^vI37{b0Dw7!5J+@#( zJK>Jo9fK#uzrbT~_Xnob+i~nUQRIsX zr+;C1?K67`(_8C}eX^JeaT=aHKhS~@kiods=Uqz8$?Xp)r_ui0Xl^EQ9q2v##kePL z{(8Kj`b9J|a{Y155D zIY43cBMQo8^C32Q4zY~OJ_9qT!HBc+hqKs)u002mI{6f$64%z`>^rcI;a#g~z%?w- zTs;8K7m!Ccu)>$(3IzSdzMIO-%N=BcM20~VgsaEFKX7|y+90LRZ%C(Hl0V`HGbWP? z>A47VK^)0sOHm=i_Wfv4=wK3=XIFC@8?O_w)Bk@8D?|qFzv{2We|426TF|s&k#ZlR zmoI@$%lEYZp1kq?m%Jfv|4ZIX4*)7?iV1%g{D|EZb|~`;cMdmK4XcDlqg}9|F6?9> zn-vY9#Y45>g@C1TSp4bXbp?-KA#%A6(VSzxU9GqLM7UY**QBTNixnYHN+8eYl?z|B{kDZ}H z0F{jSe2jP-CeGn}kj`k;ohn6`VfgL`MpTY*Ub=A#DaFt^>YZ+zz>iGAU7tnydezLa z6&cQuQY+o{;CxCOqC6oKb`L&@X#?|+-=nx-wVc1936-Lx_PnbledB@7PW)^h!QiU+ zSvj#f11M=IIr&%W%0%Z``BW{Cq*&biCsZT22ATtqJ2RmG-^=~puOZzu3G{gC7Tj1N{X32Mus#g z5jl|Y;bop15z0=1&7LQVxBU$4?1~i19Mey_EQh_y<^1$@i5pRl`#eAvZCZpeRE0;8 zwp)FhRffm8dl%qb9is7{XdYZonj%+kpWr;t{~BW6CXx)y82F8~4VRRf-<{8iEHaqQ zC_lCj^gC{7<_n(15KVAX%Iydcee;3rvEKRo=9<0kdSQa%(ok8CVn@SEDZ6S7i{2`7 z^^^@Q^1uK)3Io+V*z2IMo&kFxgP;alU?rE7UFU#avn&uzMkG$gm;7$cGVvHD5B!^~ zW2GG5g(=z*P@dBt6c!3FpT7U0Ay~gxR+^oSfdVM09tcT`*PSUv1EC z@JY`F{u*%Gl)s(<2S z5k$gzy>ITLON68;RAz3DSRYq8)=@fr&nv?2CuzG-2Q~1q1Z@G5@HBEx?i}v;=_qbz zI|%XEnk1SJo`gCKK6b3C7~6er>QeDV&QmI0wY$6Z)yr;K5~$?oU4dLm_~qvy`tVR8 zBr7#9Kh3&rkLhU&^XdxgiJQxl(l|2RkrqHAt+b*m)LVm)owMrW3W2csCdSDPkFv6l zHZ4;hLtR*emjm66#}(G~UYOA0Vg|%fZ&Bl20b`%b1*~u5vUdz`1mZ3j20Bk`6slpN zZrRdXR7j!ciSJ%YJe)+}|vn)*wx+L?TV4f~(OjTsmq%#@=6Y ztwWi>@HEO6DJ3k3a++zZS@(NFzt+?-e-nQAX|VkGkl14g*GDAnTVHVa*{xbKWU9jN zd)X#A$t?JD@DB%$35^=ln(!6$08DiKtwO8g91^cvw!TuNwYvq`j!1(%R)- z;AwdF+y3`3Q~)`nxOK9}hu`|Z_26f$)uMo95dRAHfB|iYAiDTPI1Yo7GLv#~3&##t4=Eq#nzwowv{(AcjfdI&@%npYOibEkZpoW> z-X22C&=v@yN7s7OqWGj1g{2_ZMNFHxku#6r{+&Kb!CuS?4AFY)n35=YLB=cALQTt# zUE>>cAfx}RNYmu-8-sfCtkDeEr46jxnK$6ON%K#c4$?=D!0yMTU=9jC_#~wt$e9b0 zb*KyH<;X6J+6%I~A%0%WYy_2ZOXcKN_xTD(FZFACQ)hF}7|bg5y)!WJ>b4gjNFWfv zfMt+%f!m%{n=i#qB`nB9h^_JKj%I5qdeAS0nFQNCPl7B_mZLOoIU*A4t5ba5|E{^M zKDIqMJK6K&uI>ear4R$@JA&}DUqhI+L*$QMU{|^*oM3Av>!@lDk0ktgUaG^2g>k9NZ!q=(bBv(o{u`)g*CC{Y>3j_VIfn<- zBPc9So#&5WLS%Jdci|`j+UNdkhOWKbPQ}P8tgqu1T;^Njdw~?z>(T0G?q`Zmic>f@ zhzSW48By6q{KnprWTtHuD8K5OH0eG_DjmqI0Bb0w2onRzhFZ$g}CZ+M2h1 zG;dxDh_PluB|>QEtvk>}8&5!rYyHpBeHV2cuZ|Qd1V1kxS=sO~`cG$~y)KfYRgO() zHg6(6kp1)ti@Wq!maQznQklr0uu7A>DJ-PL0m4AIjzZJmVr?Sg=8%(2ko;{{X4-{` zta!atnog;kUC1+<1;Nt@qB%MSd}%5{gaf&Nj=}mwx-YpZs7A8X3{{qpA{F1PTgK9^ zTsTMPU9EEW+197Z-`je=_J>(1Dz-jnyuR}X)r-3$z$C55aQYPIr?sN1$G_V9nQDJ* zukkHEzxyqI%W7^ZXya-2C1&)3a1#?Ho(kDRgAc@_$pJW}Rjld67!`uSglOa4jVM7B zg<}H*pf22cTQkk#_)9ayX0ouiPkG)Qw?EpGFjkMF4O9UW4+Ps5nGJZ18Wj@7OBqA( zJ#)UWdZ-ik_?5oNI0s*Ud0x$d{gZyhzB&1D8^PB?o5Sh^W(84 z>0tZ7L8<&X+r&s%B2CL3#|O-JB%gedyhnIu`6`-FSRkmn5jy17N705M5rC|0hw`NI z-dhr)&0fE?ey`4dz5%BsOi(dP{e`!v_TkZeDtM)h$MD;<_Z#WN&plu7p^$rw0AW%6 z(IADDY&-hS+W%zmi4oaTD8YmK+FqLb*!BA8z1u!oc4?NK{tC*$?p%wNpzD=zu2+YZ zl%)VVQqt_ykW9KYre!Kri`&qo?J5_<7t5B;U;QpOQAktrK}pHE9;2H^rRXQ4Bm|ic zLt!=}!YQmOj?atjU7rG63s>>l!HR>5DNeP)=*2C_ZLRkvf=<)Q-*O&VebX}kZkh6_ zSXokNQpLPU-R~Fr%romzutpJpWLhT{kg2YbnmzYp+?Mz_>8vfP!T=PE`HK4%x6caA zIz0Vib@%l&Tj5XeWIn_f-69qY9(lD~s~SNwtRiy(oil<;true ../../build/analyzers.ruleset bin/$(Configuration)/$(TargetFramework)/$(AssemblyName).xml + ../../build/tgs.ico diff --git a/src/Tgstation.Server.Host.Service/Program.cs b/src/Tgstation.Server.Host.Service/Program.cs index e1e6e2f992..f0e70eb10b 100644 --- a/src/Tgstation.Server.Host.Service/Program.cs +++ b/src/Tgstation.Server.Host.Service/Program.cs @@ -43,6 +43,18 @@ namespace Tgstation.Server.Host.Service [Option(ShortName = "i")] public bool Install { get; set; } + /// + /// The --force or -f option. + /// + [Option(ShortName = "f")] + public bool Force { get; set; } + + /// + /// The --silent or -s option. + /// + [Option(ShortName = "s")] + public bool Silent { get; set; } + /// /// The --configure or -c option. /// @@ -82,14 +94,16 @@ namespace Tgstation.Server.Host.Service /// /// Attempt to install the TGS Service. /// - static void RunServiceInstall() + void RunServiceInstall() { // First check if the service already exists - if (Environment.UserInteractive) + if (Force || Environment.UserInteractive) foreach (ServiceController sc in ServiceController.GetServices()) if (sc.ServiceName == "tgstation-server" || sc.ServiceName == "tgstation-server-4") { - DialogResult result = MessageBox.Show($"You already have another TGS service installed ({sc.ServiceName}). Would you like to uninstall it now? Pressing \"No\" will cancel this install.", "TGS Service", MessageBoxButtons.YesNo); + DialogResult result = !Force + ? MessageBox.Show($"You already have another TGS service installed ({sc.ServiceName}). Would you like to uninstall it now? Pressing \"No\" will cancel this install.", "TGS Service", MessageBoxButtons.YesNo) + : DialogResult.Yes; if (result != DialogResult.Yes) return; // is this needed after exit? @@ -103,6 +117,10 @@ namespace Tgstation.Server.Host.Service // And remove it using var serviceInstaller = new ServiceInstaller(); serviceInstaller.Context = new InstallContext($"old-{sc.ServiceName}-uninstall.log", null); + + if (Silent) + serviceInstaller.Context.Parameters["LogToConsole"] = false.ToString(); + serviceInstaller.ServiceName = sc.ServiceName; serviceInstaller.Uninstall(null); } @@ -112,8 +130,10 @@ namespace Tgstation.Server.Host.Service processInstaller.Account = ServiceAccount.LocalSystem; installer.Context = new InstallContext("tgs-install.log", new string[] { String.Format(CultureInfo.InvariantCulture, "/assemblypath={0}", Assembly.GetEntryAssembly().Location) }); - installer.Description = "/tg/station 13 server running as a windows service"; - installer.DisplayName = "/tg/station server"; + if (Silent) + installer.Context.Parameters["LogToConsole"] = false.ToString(); + installer.Description = "tgstation-server running as a windows service"; + installer.DisplayName = "tgstation-server"; installer.StartType = ServiceStartMode.Automatic; installer.ServicesDependedOn = new string[] { "Tcpip", "Dhcp", "Dnscache" }; installer.ServiceName = ServerService.Name; @@ -149,7 +169,7 @@ namespace Tgstation.Server.Host.Service { UseShellExecute = true, Verb = "runas", - Arguments = String.Format(CultureInfo.InvariantCulture, "{0} {1}", Install ? "-i" : Uninstall ? "-u" : String.Empty, Configure ? "-c" : String.Empty), + Arguments = $"{(Install ? "-i" : Uninstall ? "-u" : String.Empty)} {(Configure ? "-c" : String.Empty)} {(Force ? "-f" : String.Empty)}", FileName = exe, WorkingDirectory = Environment.CurrentDirectory, }; @@ -165,16 +185,16 @@ namespace Tgstation.Server.Host.Service RunServiceInstall(); - if (Configure) - { + if (Configure && !Silent) Console.WriteLine("For this first run we'll launch the console runner so you may use the setup wizard."); - Console.WriteLine("If it starts successfully, feel free to close it and then start the service from the Windows control panel."); - } } else if (Uninstall) using (var installer = new ServiceInstaller()) { installer.Context = new InstallContext("tgs-uninstall.log", null); + if (Silent) + installer.Context.Parameters["LogToConsole"] = false.ToString(); + installer.ServiceName = ServerService.Name; installer.Uninstall(null); } @@ -185,11 +205,23 @@ namespace Tgstation.Server.Host.Service } if (Configure) + await RunConfigure(CancellationToken.None); // DCT: None available + } + + /// + /// Runs the host application with the setup wizard. + /// + /// The for the operation. + /// A representing the running operation. + async Task RunConfigure(CancellationToken cancellationToken) + { + using var loggerFactory = LoggerFactory.Create(builder => { - using var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole()); - await WatchdogFactory.CreateWatchdog(loggerFactory) - .RunAsync(true, Array.Empty(), CancellationToken.None); // DCT: None available - } + if (!Silent) + builder.AddConsole(); + }); + await WatchdogFactory.CreateWatchdog(loggerFactory) + .RunAsync(true, Array.Empty(), cancellationToken); } } } diff --git a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj index 83630ddc2e..d8200f9ecc 100644 --- a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj +++ b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj @@ -9,6 +9,7 @@ true ../../build/analyzers.ruleset bin/$(Configuration)/$(TargetFramework)/$(RuntimeIdentifier)/$(AssemblyName).xml + ../../build/tgs.ico diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index a9e8b35652..6c63de35d2 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -9,6 +9,11 @@ ../../build/analyzers.ruleset bin/$(Configuration)/$(TargetFramework)/$(AssemblyName).xml API1000 + ClientApp/node_modules + ClientApp/node_modules/.install-stamp + Linux + ..\.. + ../../build/manifest.xml @@ -16,14 +21,6 @@ - - ClientApp/node_modules - ClientApp/node_modules/.install-stamp - Linux - ..\.. - manifest.xml - - $(DefineConstants);WATCHDOG_FREE_RESTART @@ -86,7 +83,6 @@ - all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -117,7 +113,6 @@ - all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -143,15 +138,11 @@ - - - - - - - + + + diff --git a/tgstation-server.sln b/tgstation-server.sln index 8c700d5f29..807b3e708e 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -30,6 +30,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{6FF654E6 build\coverlet.runsettings = build\coverlet.runsettings build\Dockerfile = build\Dockerfile build\GenerateMigrations.sh = build\GenerateMigrations.sh + build\manifest.xml = build\manifest.xml build\NugetCommon.props = build\NugetCommon.props build\OpenApiValidationSettings.json = build\OpenApiValidationSettings.json build\stylecop.json = build\stylecop.json @@ -201,11 +202,14 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Common", "src\Tgstation.Server.Common\Tgstation.Server.Common.csproj", "{70CD9A98-D31A-44A4-81D1-D02764CEEEFD}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "package", "package", "{2648A85F-61AE-428E-95E1-66D06C7A3768}" + ProjectSection(SolutionItems) = preProject + build\package\appsettings.Initial.yml = build\package\appsettings.Initial.yml + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deb", "deb", "{457A1F89-6201-4430-BCC6-2F4438A54B9E}" ProjectSection(SolutionItems) = preProject - build\package\deb\appsettings.Initial.yml = build\package\deb\appsettings.Initial.yml build\package\deb\build_package.sh = build\package\deb\build_package.sh + build\package\deb\install_artifacts.sh = build\package\deb\install_artifacts.sh build\package\deb\MakeInstall = build\package\deb\MakeInstall build\package\deb\tgs-configure = build\package\deb\tgs-configure build\package\deb\wrap_gpg.sh = build\package\deb\wrap_gpg.sh @@ -216,6 +220,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "debian", "debian", "{08E7C6 build\package\deb\debian\changelog = build\package\deb\debian\changelog build\package\deb\debian\control = build\package\deb\debian\control build\package\deb\debian\copyright = build\package\deb\debian\copyright + build\package\deb\install_artifacts.sh = build\package\deb\install_artifacts.sh build\package\deb\debian\links = build\package\deb\debian\links build\package\deb\debian\postinst = build\package\deb\debian\postinst build\package\deb\debian\prerm = build\package\deb\debian\prerm @@ -227,6 +232,22 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "upstream", "upstream", "{B4 build\package\deb\debian\upstream\metadata = build\package\deb\debian\upstream\metadata EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "winget", "winget", "{506B9092-AF88-4DA2-84FD-C11646B695B0}" + ProjectSection(SolutionItems) = preProject + build\package\winget\build_package.ps1 = build\package\winget\build_package.ps1 + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Service.Configure", "build\package\winget\Tgstation.Server.Host.Service.Configure\Tgstation.Server.Host.Service.Configure.csproj", "{6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "manifest", "manifest", "{3F141E03-6ABB-46A8-AA24-1B4B6814E58F}" + ProjectSection(SolutionItems) = preProject + build\package\winget\manifest\Tgstation.Server.installer.yaml = build\package\winget\manifest\Tgstation.Server.installer.yaml + build\package\winget\manifest\Tgstation.Server.locale.en-US.yaml = build\package\winget\manifest\Tgstation.Server.locale.en-US.yaml + build\package\winget\manifest\Tgstation.Server.yaml = build\package\winget\manifest\Tgstation.Server.yaml + EndProjectSection +EndProject +Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "Tgstation.Server.Host.Service.Msi", "build\package\winget\Tgstation.Server.Host.Service.Msi\Tgstation.Server.Host.Service.Msi.vdproj", "{73F75AAF-7885-490A-8262-B5C852AC8A47}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -383,6 +404,19 @@ Global {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Release|Any CPU.Build.0 = Release|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU + {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Debug|Any CPU.ActiveCfg = Release|Any CPU + {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.DebugNoService|Any CPU.ActiveCfg = Release|Any CPU + {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Release|Any CPU.Build.0 = Release|Any CPU + {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU + {73F75AAF-7885-490A-8262-B5C852AC8A47}.Debug|Any CPU.ActiveCfg = Release + {73F75AAF-7885-490A-8262-B5C852AC8A47}.Debug|Any CPU.Build.0 = Release + {73F75AAF-7885-490A-8262-B5C852AC8A47}.DebugNoService|Any CPU.ActiveCfg = Release + {73F75AAF-7885-490A-8262-B5C852AC8A47}.DebugNoService|Any CPU.Build.0 = Release + {73F75AAF-7885-490A-8262-B5C852AC8A47}.Release|Any CPU.ActiveCfg = Release + {73F75AAF-7885-490A-8262-B5C852AC8A47}.Release|Any CPU.Build.0 = Release + {73F75AAF-7885-490A-8262-B5C852AC8A47}.ReleaseNoService|Any CPU.ActiveCfg = Release + {73F75AAF-7885-490A-8262-B5C852AC8A47}.ReleaseNoService|Any CPU.Build.0 = Release EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -415,6 +449,10 @@ Global {457A1F89-6201-4430-BCC6-2F4438A54B9E} = {2648A85F-61AE-428E-95E1-66D06C7A3768} {08E7C650-A447-4DE2-974E-ED123B50F8D6} = {457A1F89-6201-4430-BCC6-2F4438A54B9E} {B4B5570C-8071-46DE-BB55-64C13480C606} = {08E7C650-A447-4DE2-974E-ED123B50F8D6} + {506B9092-AF88-4DA2-84FD-C11646B695B0} = {2648A85F-61AE-428E-95E1-66D06C7A3768} + {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315} = {506B9092-AF88-4DA2-84FD-C11646B695B0} + {3F141E03-6ABB-46A8-AA24-1B4B6814E58F} = {506B9092-AF88-4DA2-84FD-C11646B695B0} + {73F75AAF-7885-490A-8262-B5C852AC8A47} = {506B9092-AF88-4DA2-84FD-C11646B695B0} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DFD36C95-3E49-41C7-ACDB-86BAF5B18A79} From 036a079b517f3074ba2917efd06cf3c96c4dddd0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 24 Jun 2023 08:53:10 -0400 Subject: [PATCH 002/160] Add missing checkout to build-msi and build-deb --- .github/workflows/ci-suite.yml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 08afc555d0..4250043b1a 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -892,8 +892,15 @@ jobs: echo ${{ secrets.PACKAGING_PRIVATE_KEY_PASSPHRASE }} | gpg --batch --yes --passphrase-fd 0 --import private.pgp rm private.pgp - - name: Checkout + - name: Checkout (Branch) uses: actions/checkout@v3 + if: github.event_name == 'push' || github.event_name == 'schedule' + + - name: Checkout (PR Merge) + uses: actions/checkout@v3 + if: github.event_name != 'push' && github.event_name != 'schedule' + with: + ref: "refs/pull/${{ github.event.number }}/merge" - name: Execute Build Script env: @@ -938,6 +945,16 @@ jobs: working-directory: C:/Program Files/Microsoft Visual Studio/2022/Enterprise/Common7/IDE/CommonExtensions/Microsoft/VSI/DisableOutOfProcBuild run: ./DisableOutOfProcBuild.exe + - name: Checkout (Branch) + uses: actions/checkout@v3 + if: github.event_name == 'push' || github.event_name == 'schedule' + + - name: Checkout (PR Merge) + uses: actions/checkout@v3 + if: github.event_name != 'push' && github.event_name != 'schedule' + with: + ref: "refs/pull/${{ github.event.number }}/merge" + - name: Build .vdproj shell: powershell run: build/package/winget/build_package.ps1 From 8ee8baf897a3081a46dd1baf70942c141ecc63ee Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 24 Jun 2023 09:25:34 -0400 Subject: [PATCH 003/160] Standalone .sln for .Msi project Fixes it breaking all the other CI builds --- .../Tgstation.Server.Host.Service.Msi.vdproj | 4 +- build/package/winget/build_package.ps1 | 6 ++- build/package/winget/installer.sln | 50 +++++++++++++++++++ tgstation-server.sln | 20 ++++---- 4 files changed, 67 insertions(+), 13 deletions(-) create mode 100644 build/package/winget/installer.sln diff --git a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj index 8ea9bf88b6..8ec92efff7 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj @@ -1,4 +1,4 @@ -"DeployProject" +"DeployProject" { "VSVersion" = "3:800" "ProjectType" = "8:{978C614F-708E-4E1A-B201-565925725DBA}" @@ -363,7 +363,7 @@ "Manufacturer" = "8:tgstation" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:" - "Title" = "8:Tgstation.Server.Host.Service.Setup" + "Title" = "8:Tgstation.Server.Host.Service.Msi" "Subject" = "8:" "ARPCONTACT" = "8:Dominon/Cyberboss" "Keywords" = "8:" diff --git a/build/package/winget/build_package.ps1 b/build/package/winget/build_package.ps1 index 940d1aad62..8d92adb8a0 100644 --- a/build/package/winget/build_package.ps1 +++ b/build/package/winget/build_package.ps1 @@ -15,7 +15,11 @@ $tgsVersion = $versionXML.Project.PropertyGroup.TgsCoreVersion (Get-Content build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj).Replace('22.47.5', $tgsVersion) | Set-Content build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +dotnet restore +cd build/package/winget +dotnet build -c Release Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure + # We make _some_ assumptions -DevEnv tgstation-server.sln /Project build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj /build Release +DevEnv installer.sln /Project Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj /build Release cd .. diff --git a/build/package/winget/installer.sln b/build/package/winget/installer.sln new file mode 100644 index 0000000000..fef08dbe57 --- /dev/null +++ b/build/package/winget/installer.sln @@ -0,0 +1,50 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33801.468 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Service.Configure", "Tgstation.Server.Host.Service.Configure\Tgstation.Server.Host.Service.Configure.csproj", "{6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}" +EndProject +Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "Tgstation.Server.Host.Service.Msi", "Tgstation.Server.Host.Service.Msi\Tgstation.Server.Host.Service.Msi.vdproj", "{C7BE7AC6-D020-4497-84DE-282C24BA575D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Api", "..\..\..\src\Tgstation.Server.Api\Tgstation.Server.Api.csproj", "{8B4A208D-A48A-4A5D-8B94-E2661138865D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Common", "..\..\..\src\Tgstation.Server.Common\Tgstation.Server.Common.csproj", "{70CD9A98-D31A-44A4-81D1-D02764CEEEFD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Common", "..\..\..\src\Tgstation.Server.Host.Common\Tgstation.Server.Host.Common.csproj", "{CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Service", "..\..\..\src\Tgstation.Server.Host.Service\Tgstation.Server.Host.Service.csproj", "{29927416-3B78-49A7-A560-5CCAA638B6B4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Watchdog", "..\..\..\src\Tgstation.Server.Host.Watchdog\Tgstation.Server.Host.Watchdog.csproj", "{5D2D682C-6BF0-439C-850B-6AB945BBEAEA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host", "..\..\..\src\Tgstation.Server.Host\Tgstation.Server.Host.csproj", "{2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Release|Any CPU.Build.0 = Release|Any CPU + {C7BE7AC6-D020-4497-84DE-282C24BA575D}.Release|Any CPU.ActiveCfg = Release + {C7BE7AC6-D020-4497-84DE-282C24BA575D}.Release|Any CPU.Build.0 = Release + {8B4A208D-A48A-4A5D-8B94-E2661138865D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8B4A208D-A48A-4A5D-8B94-E2661138865D}.Release|Any CPU.Build.0 = Release|Any CPU + {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Release|Any CPU.Build.0 = Release|Any CPU + {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Release|Any CPU.Build.0 = Release|Any CPU + {29927416-3B78-49A7-A560-5CCAA638B6B4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {29927416-3B78-49A7-A560-5CCAA638B6B4}.Release|Any CPU.Build.0 = Release|Any CPU + {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Release|Any CPU.Build.0 = Release|Any CPU + {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EBC981CA-0309-468F-984F-067BA2A6DF99} + EndGlobalSection +EndGlobal diff --git a/tgstation-server.sln b/tgstation-server.sln index 807b3e708e..d8d4450452 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -235,9 +235,14 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "winget", "winget", "{506B9092-AF88-4DA2-84FD-C11646B695B0}" ProjectSection(SolutionItems) = preProject build\package\winget\build_package.ps1 = build\package\winget\build_package.ps1 + build\package\winget\installer.sln = build\package\winget\installer.sln + build\package\winget\install_banner.jpg = build\package\winget\install_banner.jpg EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Service.Configure", "build\package\winget\Tgstation.Server.Host.Service.Configure\Tgstation.Server.Host.Service.Configure.csproj", "{6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}" + ProjectSection(ProjectDependencies) = postProject + {29927416-3B78-49A7-A560-5CCAA638B6B4} = {29927416-3B78-49A7-A560-5CCAA638B6B4} + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "manifest", "manifest", "{3F141E03-6ABB-46A8-AA24-1B4B6814E58F}" ProjectSection(SolutionItems) = preProject @@ -246,7 +251,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "manifest", "manifest", "{3F build\package\winget\manifest\Tgstation.Server.yaml = build\package\winget\manifest\Tgstation.Server.yaml EndProjectSection EndProject -Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "Tgstation.Server.Host.Service.Msi", "build\package\winget\Tgstation.Server.Host.Service.Msi\Tgstation.Server.Host.Service.Msi.vdproj", "{73F75AAF-7885-490A-8262-B5C852AC8A47}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tgstation.Server.Host.Service.Msi", "Tgstation.Server.Host.Service.Msi", "{F5B9D394-229B-44A1-AD12-D8C078F06814}" + ProjectSection(SolutionItems) = preProject + build\package\winget\Tgstation.Server.Host.Service.Msi\Tgstation.Server.Host.Service.Msi.vdproj = build\package\winget\Tgstation.Server.Host.Service.Msi\Tgstation.Server.Host.Service.Msi.vdproj + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -409,14 +417,6 @@ Global {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Release|Any CPU.ActiveCfg = Release|Any CPU {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Release|Any CPU.Build.0 = Release|Any CPU {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {73F75AAF-7885-490A-8262-B5C852AC8A47}.Debug|Any CPU.ActiveCfg = Release - {73F75AAF-7885-490A-8262-B5C852AC8A47}.Debug|Any CPU.Build.0 = Release - {73F75AAF-7885-490A-8262-B5C852AC8A47}.DebugNoService|Any CPU.ActiveCfg = Release - {73F75AAF-7885-490A-8262-B5C852AC8A47}.DebugNoService|Any CPU.Build.0 = Release - {73F75AAF-7885-490A-8262-B5C852AC8A47}.Release|Any CPU.ActiveCfg = Release - {73F75AAF-7885-490A-8262-B5C852AC8A47}.Release|Any CPU.Build.0 = Release - {73F75AAF-7885-490A-8262-B5C852AC8A47}.ReleaseNoService|Any CPU.ActiveCfg = Release - {73F75AAF-7885-490A-8262-B5C852AC8A47}.ReleaseNoService|Any CPU.Build.0 = Release EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -452,7 +452,7 @@ Global {506B9092-AF88-4DA2-84FD-C11646B695B0} = {2648A85F-61AE-428E-95E1-66D06C7A3768} {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315} = {506B9092-AF88-4DA2-84FD-C11646B695B0} {3F141E03-6ABB-46A8-AA24-1B4B6814E58F} = {506B9092-AF88-4DA2-84FD-C11646B695B0} - {73F75AAF-7885-490A-8262-B5C852AC8A47} = {506B9092-AF88-4DA2-84FD-C11646B695B0} + {F5B9D394-229B-44A1-AD12-D8C078F06814} = {506B9092-AF88-4DA2-84FD-C11646B695B0} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DFD36C95-3E49-41C7-ACDB-86BAF5B18A79} From 547edb165bd24199f84079a2a1144f7985a0e79d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 24 Jun 2023 09:27:02 -0400 Subject: [PATCH 004/160] Fix Service project build errors --- src/Tgstation.Server.Host.Service/Program.cs | 104 +++++++++---------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/src/Tgstation.Server.Host.Service/Program.cs b/src/Tgstation.Server.Host.Service/Program.cs index f0e70eb10b..db02337785 100644 --- a/src/Tgstation.Server.Host.Service/Program.cs +++ b/src/Tgstation.Server.Host.Service/Program.cs @@ -91,58 +91,6 @@ namespace Tgstation.Server.Host.Service /// A resulting in the 's exit code. static Task Main(string[] args) => CommandLineApplication.ExecuteAsync(args); - /// - /// Attempt to install the TGS Service. - /// - void RunServiceInstall() - { - // First check if the service already exists - if (Force || Environment.UserInteractive) - foreach (ServiceController sc in ServiceController.GetServices()) - if (sc.ServiceName == "tgstation-server" || sc.ServiceName == "tgstation-server-4") - { - DialogResult result = !Force - ? MessageBox.Show($"You already have another TGS service installed ({sc.ServiceName}). Would you like to uninstall it now? Pressing \"No\" will cancel this install.", "TGS Service", MessageBoxButtons.YesNo) - : DialogResult.Yes; - if (result != DialogResult.Yes) - return; // is this needed after exit? - - // Stop it first to give it some cleanup time - if (sc.Status == ServiceControllerStatus.Running) - { - sc.Stop(); - sc.WaitForStatus(ServiceControllerStatus.Stopped); - } - - // And remove it - using var serviceInstaller = new ServiceInstaller(); - serviceInstaller.Context = new InstallContext($"old-{sc.ServiceName}-uninstall.log", null); - - if (Silent) - serviceInstaller.Context.Parameters["LogToConsole"] = false.ToString(); - - serviceInstaller.ServiceName = sc.ServiceName; - serviceInstaller.Uninstall(null); - } - - using var processInstaller = new ServiceProcessInstaller(); - using var installer = new ServiceInstaller(); - processInstaller.Account = ServiceAccount.LocalSystem; - - installer.Context = new InstallContext("tgs-install.log", new string[] { String.Format(CultureInfo.InvariantCulture, "/assemblypath={0}", Assembly.GetEntryAssembly().Location) }); - if (Silent) - installer.Context.Parameters["LogToConsole"] = false.ToString(); - installer.Description = "tgstation-server running as a windows service"; - installer.DisplayName = "tgstation-server"; - installer.StartType = ServiceStartMode.Automatic; - installer.ServicesDependedOn = new string[] { "Tcpip", "Dhcp", "Dnscache" }; - installer.ServiceName = ServerService.Name; - installer.Parent = processInstaller; - - var state = new ListDictionary(); - installer.Install(state); - } - /// /// Command line handler, always runs. /// @@ -208,6 +156,58 @@ namespace Tgstation.Server.Host.Service await RunConfigure(CancellationToken.None); // DCT: None available } + /// + /// Attempt to install the TGS Service. + /// + void RunServiceInstall() + { + // First check if the service already exists + if (Force || Environment.UserInteractive) + foreach (ServiceController sc in ServiceController.GetServices()) + if (sc.ServiceName == "tgstation-server" || sc.ServiceName == "tgstation-server-4") + { + DialogResult result = !Force + ? MessageBox.Show($"You already have another TGS service installed ({sc.ServiceName}). Would you like to uninstall it now? Pressing \"No\" will cancel this install.", "TGS Service", MessageBoxButtons.YesNo) + : DialogResult.Yes; + if (result != DialogResult.Yes) + return; // is this needed after exit? + + // Stop it first to give it some cleanup time + if (sc.Status == ServiceControllerStatus.Running) + { + sc.Stop(); + sc.WaitForStatus(ServiceControllerStatus.Stopped); + } + + // And remove it + using var serviceInstaller = new ServiceInstaller(); + serviceInstaller.Context = new InstallContext($"old-{sc.ServiceName}-uninstall.log", null); + + if (Silent) + serviceInstaller.Context.Parameters["LogToConsole"] = false.ToString(); + + serviceInstaller.ServiceName = sc.ServiceName; + serviceInstaller.Uninstall(null); + } + + using var processInstaller = new ServiceProcessInstaller(); + using var installer = new ServiceInstaller(); + processInstaller.Account = ServiceAccount.LocalSystem; + + installer.Context = new InstallContext("tgs-install.log", new string[] { String.Format(CultureInfo.InvariantCulture, "/assemblypath={0}", Assembly.GetEntryAssembly().Location) }); + if (Silent) + installer.Context.Parameters["LogToConsole"] = false.ToString(); + installer.Description = "tgstation-server running as a windows service"; + installer.DisplayName = "tgstation-server"; + installer.StartType = ServiceStartMode.Automatic; + installer.ServicesDependedOn = new string[] { "Tcpip", "Dhcp", "Dnscache" }; + installer.ServiceName = ServerService.Name; + installer.Parent = processInstaller; + + var state = new ListDictionary(); + installer.Install(state); + } + /// /// Runs the host application with the setup wizard. /// From bc87686f97a94e5a9f339fd891dd28c8becd744a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 24 Jun 2023 09:28:23 -0400 Subject: [PATCH 005/160] Remove installer prequisites - It's just a useless prompt --- .../Tgstation.Server.Host.Service.Msi.vdproj | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj index 8ec92efff7..2acb895c4d 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj @@ -93,11 +93,6 @@ "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)" "ProductCode" = "8:.NETFramework,Version=v4.7.2" } - "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:Microsoft.NetCore.CoreRuntime.6.0.x64" - { - "Name" = "8:.NET Runtime 6.0.18 (x64)" - "ProductCode" = "8:Microsoft.NetCore.CoreRuntime.6.0.x64" - } } } } @@ -352,7 +347,7 @@ "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:tgstation-server" "ProductCode" = "8:{D24887FA-3228-4509-B5F3-4E07E349F278}" - "PackageCode" = "8:{5740BC0C-02EE-42AB-8B50-BCCAF4AF0322}" + "PackageCode" = "8:{FD82FA4A-3794-439D-9871-4D17F4913958}" "UpgradeCode" = "8:{151FE9F8-72CF-48D5-8E55-B7FB6BA9693E}" "AspNetVersion" = "8:4.0.30319.0" "RestartWWWService" = "11:FALSE" From 55a7d656a9212c117195341448b9719b1c89a0fd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 24 Jun 2023 09:29:25 -0400 Subject: [PATCH 006/160] Remove useless install folder --- .../Tgstation.Server.Host.Service.Msi.vdproj | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj index 2acb895c4d..29d022afc4 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj @@ -307,17 +307,6 @@ { } } - "{1525181F-901A-416C-8A58-119130FE478E}:_D53B13F517CB437C874C9E216C3F8F5F" - { - "Name" = "8:#1937" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:CommonFiles64Folder" - "Folders" - { - } - } "{994432C3-9487-495D-8656-3E829A8DBDDE}:_EB2DCEE6D3F74230A9827AC9B6F47F53" { "DefaultLocation" = "8:[TARGETDIR]" From b2414fa92d8425725a7bef6a1b0d11b9709b6668 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 24 Jun 2023 09:30:44 -0400 Subject: [PATCH 007/160] Installer should now be x86 compatible --- .../Tgstation.Server.Host.Service.Msi.vdproj | 8 ++++---- .../winget/manifest/Tgstation.Server.installer.yaml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj index 29d022afc4..24d9931bf6 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj @@ -264,7 +264,7 @@ { "{3C67513D-01DD-4637-8A68-80971EB9504F}:_B28C4FD80D0245E08AEDCFEECACB6493" { - "DefaultLocation" = "8:[ProgramFiles64Folder][Manufacturer]\\[ProductName]" + "DefaultLocation" = "8:[ProgramFilesFolder][Manufacturer]\\[ProductName]" "Name" = "8:#1925" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" @@ -336,7 +336,7 @@ "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:tgstation-server" "ProductCode" = "8:{D24887FA-3228-4509-B5F3-4E07E349F278}" - "PackageCode" = "8:{FD82FA4A-3794-439D-9871-4D17F4913958}" + "PackageCode" = "8:{F5E9572F-EBD8-43D4-AEF4-9EB8A70C7A0F}" "UpgradeCode" = "8:{151FE9F8-72CF-48D5-8E55-B7FB6BA9693E}" "AspNetVersion" = "8:4.0.30319.0" "RestartWWWService" = "11:FALSE" @@ -351,13 +351,13 @@ "Subject" = "8:" "ARPCONTACT" = "8:Dominon/Cyberboss" "Keywords" = "8:" - "ARPCOMMENTS" = "8:" + "ARPCOMMENTS" = "8:Installer for tgstation-server" "ARPURLINFOABOUT" = "8:https://tgstation13.org" "ARPPRODUCTICON" = "8:" "ARPIconIndex" = "3:0" "SearchPath" = "8:" "UseSystemSearchPath" = "11:TRUE" - "TargetPlatform" = "3:1" + "TargetPlatform" = "3:0" "PreBuildEvent" = "8:" "PostBuildEvent" = "8:" "RunPostBuildEvent" = "3:0" diff --git a/build/package/winget/manifest/Tgstation.Server.installer.yaml b/build/package/winget/manifest/Tgstation.Server.installer.yaml index b70a79ec82..ad85341185 100644 --- a/build/package/winget/manifest/Tgstation.Server.installer.yaml +++ b/build/package/winget/manifest/Tgstation.Server.installer.yaml @@ -6,7 +6,7 @@ PackageVersion: 0.0.0 # Set before publish by wingetcreate Installers: - InstallerUrl: https://github.com/tgstation/tgstation-server/releases/download/tgstation-server-v0.0.0/tgstation-server.msi # Set before publish by wingetcreate InstallerLocale: en-US - Architecture: x64 + Architecture: x86 InstallerType: msi Scope: machine InstallerSha256: F749672C1BDBAC8CD8AEF7352B97E54C21CF389D798D0ED245CA75EC72521460 From 108e04d485b83df0914cdfeba4d09110ebff17aa Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 24 Jun 2023 09:39:04 -0400 Subject: [PATCH 008/160] Rename -NoService configs to -NoFramework Better represents of what they are --- .github/workflows/ci-suite.yml | 12 +-- .github/workflows/code-scanning.yml | 2 +- .vscode/tasks.json | 4 +- build/package/deb/debian/rules | 2 +- omnisharp.json | 2 +- tgstation-server.sln | 157 ++++++++++++++-------------- 6 files changed, 91 insertions(+), 88 deletions(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 4250043b1a..3067a6225c 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -220,10 +220,10 @@ jobs: ref: "refs/pull/${{ github.event.number }}/merge" - name: Build - run: dotnet build -c ${{ matrix.configuration }}NoService + run: dotnet build -c ${{ matrix.configuration }}NoFramework - name: Run Unit Tests - run: sudo dotnet test --no-build --logger GitHubActions --filter FullyQualifiedName!~TestLiveServer -c ${{ matrix.configuration }}NoService --collect:"XPlat Code Coverage" --settings build/coverlet.runsettings --results-directory ./TestResults tgstation-server.sln + run: sudo dotnet test --no-build --logger GitHubActions --filter FullyQualifiedName!~TestLiveServer -c ${{ matrix.configuration }}NoFramework --collect:"XPlat Code Coverage" --settings build/coverlet.runsettings --results-directory ./TestResults tgstation-server.sln - name: Store Code Coverage uses: actions/upload-artifact@v3 @@ -543,13 +543,13 @@ jobs: ref: "refs/pull/${{ github.event.number }}/merge" - name: Build - run: dotnet build -c ${{ matrix.configuration }}NoService tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj + run: dotnet build -c ${{ matrix.configuration }}NoFramework tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj - name: Run Live Tests run: | cd tests/Tgstation.Server.Tests sleep 10 - dotnet test -c ${{ matrix.configuration }}NoService --filter FullyQualifiedName~TestLiveServer --logger GitHubActions --no-build --collect:"XPlat Code Coverage" --settings ../../build/coverlet.runsettings --results-directory ../../TestResults + dotnet test -c ${{ matrix.configuration }}NoFramework --filter FullyQualifiedName~TestLiveServer --logger GitHubActions --no-build --collect:"XPlat Code Coverage" --settings ../../build/coverlet.runsettings --results-directory ../../TestResults - name: Store Code Coverage uses: actions/upload-artifact@v3 @@ -563,7 +563,7 @@ jobs: cd src/Tgstation.Server.Host.Console dotnet publish -c ${{ matrix.configuration }} -o ../../Artifacts/Console cd ../Tgstation.Server.Host - dotnet publish -c ${{ matrix.configuration }}NoService --no-build -o ../../Artifacts/Console/lib/Default + dotnet publish -c ${{ matrix.configuration }}NoFramework --no-build -o ../../Artifacts/Console/lib/Default mv ../../Artifacts/Console/lib/Default/appsettings.yml ../../Artifacts/Console/appsettings.yml rm ../../Artifacts/Console/lib/Default/Tgstation.Server.Host rm ../../Artifacts/Console/Tgstation.Server.Host.Console @@ -572,7 +572,7 @@ jobs: if: ${{ matrix.configuration == 'Release' && matrix.watchdog-type == 'System' && matrix.database-type == 'PostgresSql' }} run: | cd src/Tgstation.Server.Host - dotnet publish -c ${{ matrix.configuration }}NoService --no-build -o ../../Artifacts/ServerUpdate + dotnet publish -c ${{ matrix.configuration }}NoFramework --no-build -o ../../Artifacts/ServerUpdate rm ../../Artifacts/ServerUpdate/appsettings.yml rm ../../Artifacts/ServerUpdate/Tgstation.Server.Host diff --git a/.github/workflows/code-scanning.yml b/.github/workflows/code-scanning.yml index e69d6ed259..00cf4bb1cc 100644 --- a/.github/workflows/code-scanning.yml +++ b/.github/workflows/code-scanning.yml @@ -35,7 +35,7 @@ jobs: languages: csharp - name: Build - run: dotnet build -c ReleaseNoService + run: dotnet build -c ReleaseNoFramework - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 2582679179..b020c9051a 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -7,7 +7,7 @@ "type": "process", "args": [ "msbuild", - "-p:Configuration=DebugNoService" + "-p:Configuration=DebugNoFramework" ], "problemMatcher": "$msCompile", "group": { @@ -21,7 +21,7 @@ "type": "process", "args": [ "test", - "-p:Configuration=DebugNoService" + "-p:Configuration=DebugNoFramework" ], "problemMatcher": "$msCompile", "group": { diff --git a/build/package/deb/debian/rules b/build/package/deb/debian/rules index 8e185ba247..04fd945580 100755 --- a/build/package/deb/debian/rules +++ b/build/package/deb/debian/rules @@ -7,7 +7,7 @@ export DH_VERBOSE = 1 override_dh_auto_clean: rm -rf artifacts - dotnet clean -c ReleaseNoService + dotnet clean -c ReleaseNoFramework override_dh_auto_build: dotnet restore diff --git a/omnisharp.json b/omnisharp.json index c214653d78..6aa6229abc 100644 --- a/omnisharp.json +++ b/omnisharp.json @@ -1,6 +1,6 @@ { "msbuild": { - "Configuration": "DebugNoService", + "Configuration": "DebugNoFramework", "EnablePackageAutoRestore" : true } } diff --git a/tgstation-server.sln b/tgstation-server.sln index d8d4450452..6ef86a9d6b 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -259,164 +259,167 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU - DebugNoService|Any CPU = DebugNoService|Any CPU + DebugNoFramework|Any CPU = DebugNoFramework|Any CPU Release|Any CPU = Release|Any CPU - ReleaseNoService|Any CPU = ReleaseNoService|Any CPU + ReleaseNoFramework|Any CPU = ReleaseNoFramework|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU - {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.DebugNoService|Any CPU.Build.0 = Debug|Any CPU + {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Release|Any CPU.ActiveCfg = Release|Any CPU {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Release|Any CPU.Build.0 = Release|Any CPU - {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU + {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU - {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.DebugNoService|Any CPU.Build.0 = Debug|Any CPU + {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.Release|Any CPU.ActiveCfg = Release|Any CPU {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.Release|Any CPU.Build.0 = Release|Any CPU - {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU + {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU {D36B99C4-E771-42D6-A95F-1102B3E236DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D36B99C4-E771-42D6-A95F-1102B3E236DF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D36B99C4-E771-42D6-A95F-1102B3E236DF}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU - {D36B99C4-E771-42D6-A95F-1102B3E236DF}.DebugNoService|Any CPU.Build.0 = Debug|Any CPU + {D36B99C4-E771-42D6-A95F-1102B3E236DF}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {D36B99C4-E771-42D6-A95F-1102B3E236DF}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU {D36B99C4-E771-42D6-A95F-1102B3E236DF}.Release|Any CPU.ActiveCfg = Release|Any CPU {D36B99C4-E771-42D6-A95F-1102B3E236DF}.Release|Any CPU.Build.0 = Release|Any CPU - {D36B99C4-E771-42D6-A95F-1102B3E236DF}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {D36B99C4-E771-42D6-A95F-1102B3E236DF}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU + {D36B99C4-E771-42D6-A95F-1102B3E236DF}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {D36B99C4-E771-42D6-A95F-1102B3E236DF}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU {8B4A208D-A48A-4A5D-8B94-E2661138865D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8B4A208D-A48A-4A5D-8B94-E2661138865D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8B4A208D-A48A-4A5D-8B94-E2661138865D}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU - {8B4A208D-A48A-4A5D-8B94-E2661138865D}.DebugNoService|Any CPU.Build.0 = Debug|Any CPU + {8B4A208D-A48A-4A5D-8B94-E2661138865D}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {8B4A208D-A48A-4A5D-8B94-E2661138865D}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU {8B4A208D-A48A-4A5D-8B94-E2661138865D}.Release|Any CPU.ActiveCfg = Release|Any CPU {8B4A208D-A48A-4A5D-8B94-E2661138865D}.Release|Any CPU.Build.0 = Release|Any CPU - {8B4A208D-A48A-4A5D-8B94-E2661138865D}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {8B4A208D-A48A-4A5D-8B94-E2661138865D}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU + {8B4A208D-A48A-4A5D-8B94-E2661138865D}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {8B4A208D-A48A-4A5D-8B94-E2661138865D}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU {29927416-3B78-49A7-A560-5CCAA638B6B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {29927416-3B78-49A7-A560-5CCAA638B6B4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {29927416-3B78-49A7-A560-5CCAA638B6B4}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU + {29927416-3B78-49A7-A560-5CCAA638B6B4}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU {29927416-3B78-49A7-A560-5CCAA638B6B4}.Release|Any CPU.ActiveCfg = Release|Any CPU {29927416-3B78-49A7-A560-5CCAA638B6B4}.Release|Any CPU.Build.0 = Release|Any CPU - {29927416-3B78-49A7-A560-5CCAA638B6B4}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU + {29927416-3B78-49A7-A560-5CCAA638B6B4}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU - {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.DebugNoService|Any CPU.Build.0 = Debug|Any CPU + {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.Release|Any CPU.ActiveCfg = Release|Any CPU {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.Release|Any CPU.Build.0 = Release|Any CPU - {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU + {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU - {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.DebugNoService|Any CPU.Build.0 = Debug|Any CPU + {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.Release|Any CPU.ActiveCfg = Release|Any CPU {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.Release|Any CPU.Build.0 = Release|Any CPU - {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU + {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU - {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.DebugNoService|Any CPU.Build.0 = Debug|Any CPU + {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.Release|Any CPU.ActiveCfg = Release|Any CPU {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.Release|Any CPU.Build.0 = Release|Any CPU - {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU + {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU - {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.DebugNoService|Any CPU.Build.0 = Debug|Any CPU + {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.Release|Any CPU.ActiveCfg = Release|Any CPU {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.Release|Any CPU.Build.0 = Release|Any CPU - {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU + {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU - {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.DebugNoService|Any CPU.Build.0 = Debug|Any CPU + {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Release|Any CPU.ActiveCfg = Release|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Release|Any CPU.Build.0 = Release|Any CPU - {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU + {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU {7500F776-4384-4B5F-A8D8-22461CAD108B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7500F776-4384-4B5F-A8D8-22461CAD108B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7500F776-4384-4B5F-A8D8-22461CAD108B}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU - {7500F776-4384-4B5F-A8D8-22461CAD108B}.DebugNoService|Any CPU.Build.0 = Debug|Any CPU + {7500F776-4384-4B5F-A8D8-22461CAD108B}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {7500F776-4384-4B5F-A8D8-22461CAD108B}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU {7500F776-4384-4B5F-A8D8-22461CAD108B}.Release|Any CPU.ActiveCfg = Release|Any CPU {7500F776-4384-4B5F-A8D8-22461CAD108B}.Release|Any CPU.Build.0 = Release|Any CPU - {7500F776-4384-4B5F-A8D8-22461CAD108B}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {7500F776-4384-4B5F-A8D8-22461CAD108B}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU + {7500F776-4384-4B5F-A8D8-22461CAD108B}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {7500F776-4384-4B5F-A8D8-22461CAD108B}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU + {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.Release|Any CPU.ActiveCfg = Release|Any CPU {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.Release|Any CPU.Build.0 = Release|Any CPU - {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU + {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU {09056964-1C74-445A-96EC-33F6DFC07916}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {09056964-1C74-445A-96EC-33F6DFC07916}.Debug|Any CPU.Build.0 = Debug|Any CPU - {09056964-1C74-445A-96EC-33F6DFC07916}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU - {09056964-1C74-445A-96EC-33F6DFC07916}.DebugNoService|Any CPU.Build.0 = Debug|Any CPU + {09056964-1C74-445A-96EC-33F6DFC07916}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {09056964-1C74-445A-96EC-33F6DFC07916}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU {09056964-1C74-445A-96EC-33F6DFC07916}.Release|Any CPU.ActiveCfg = Release|Any CPU {09056964-1C74-445A-96EC-33F6DFC07916}.Release|Any CPU.Build.0 = Release|Any CPU - {09056964-1C74-445A-96EC-33F6DFC07916}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {09056964-1C74-445A-96EC-33F6DFC07916}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU + {09056964-1C74-445A-96EC-33F6DFC07916}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {09056964-1C74-445A-96EC-33F6DFC07916}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU - {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.DebugNoService|Any CPU.Build.0 = Debug|Any CPU + {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.Release|Any CPU.ActiveCfg = Release|Any CPU {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.Release|Any CPU.Build.0 = Release|Any CPU - {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU + {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU {5813CC33-B16C-485D-A74D-20204DDF6542}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5813CC33-B16C-485D-A74D-20204DDF6542}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5813CC33-B16C-485D-A74D-20204DDF6542}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU - {5813CC33-B16C-485D-A74D-20204DDF6542}.DebugNoService|Any CPU.Build.0 = Debug|Any CPU + {5813CC33-B16C-485D-A74D-20204DDF6542}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {5813CC33-B16C-485D-A74D-20204DDF6542}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU {5813CC33-B16C-485D-A74D-20204DDF6542}.Release|Any CPU.ActiveCfg = Release|Any CPU {5813CC33-B16C-485D-A74D-20204DDF6542}.Release|Any CPU.Build.0 = Release|Any CPU - {5813CC33-B16C-485D-A74D-20204DDF6542}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {5813CC33-B16C-485D-A74D-20204DDF6542}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU + {5813CC33-B16C-485D-A74D-20204DDF6542}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {5813CC33-B16C-485D-A74D-20204DDF6542}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU {CE499888-B22B-457C-891E-0EA9DC317228}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CE499888-B22B-457C-891E-0EA9DC317228}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CE499888-B22B-457C-891E-0EA9DC317228}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU - {CE499888-B22B-457C-891E-0EA9DC317228}.DebugNoService|Any CPU.Build.0 = Debug|Any CPU + {CE499888-B22B-457C-891E-0EA9DC317228}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {CE499888-B22B-457C-891E-0EA9DC317228}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU {CE499888-B22B-457C-891E-0EA9DC317228}.Release|Any CPU.ActiveCfg = Release|Any CPU {CE499888-B22B-457C-891E-0EA9DC317228}.Release|Any CPU.Build.0 = Release|Any CPU - {CE499888-B22B-457C-891E-0EA9DC317228}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {CE499888-B22B-457C-891E-0EA9DC317228}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU + {CE499888-B22B-457C-891E-0EA9DC317228}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {CE499888-B22B-457C-891E-0EA9DC317228}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU - {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.DebugNoService|Any CPU.Build.0 = Debug|Any CPU + {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.Release|Any CPU.ActiveCfg = Release|Any CPU {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.Release|Any CPU.Build.0 = Release|Any CPU - {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU + {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU - {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.DebugNoService|Any CPU.Build.0 = Debug|Any CPU + {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Release|Any CPU.ActiveCfg = Release|Any CPU {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Release|Any CPU.Build.0 = Release|Any CPU - {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU + {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.DebugNoService|Any CPU.ActiveCfg = Debug|Any CPU - {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.DebugNoService|Any CPU.Build.0 = Debug|Any CPU + {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Release|Any CPU.ActiveCfg = Release|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Release|Any CPU.Build.0 = Release|Any CPU - {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU - {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.ReleaseNoService|Any CPU.Build.0 = Release|Any CPU - {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Debug|Any CPU.ActiveCfg = Release|Any CPU - {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.DebugNoService|Any CPU.ActiveCfg = Release|Any CPU + {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.DebugNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.DebugNoFramework|Any CPU.Build.0 = Release|Any CPU {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Release|Any CPU.ActiveCfg = Release|Any CPU {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Release|Any CPU.Build.0 = Release|Any CPU - {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.ReleaseNoService|Any CPU.ActiveCfg = Release|Any CPU + {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 61078532787859344090e88c963891486562d957 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 24 Jun 2023 09:40:06 -0400 Subject: [PATCH 009/160] Remove vscode files until someone decides to maintain them --- .gitignore | 1 + .vscode/extensions.json | 9 --------- .vscode/launch.json | 21 --------------------- .vscode/tasks.json | 33 --------------------------------- omnisharp.json | 6 ------ 5 files changed, 1 insertion(+), 69 deletions(-) delete mode 100644 .vscode/extensions.json delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/tasks.json delete mode 100644 omnisharp.json diff --git a/.gitignore b/.gitignore index 607abbf4c2..df800dc16b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ _ReSharper.* packages/ artifacts/ .vs/ +.vscode/ *.user *.suo *.userprefs diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index 884b701d57..0000000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "recommendations": [ - "gbasood.byond-dm-language-support", - "ms-vscode.csharp", - "k--kato.docomment", - "peterjausovec.vscode-docker", - "bbenoist.doxygen" - ] -} diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index fadbf977fe..0000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - // Use IntelliSense to find out which attributes exist for C# debugging - // Use hover for the description of the existing attributes - // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md - "version": "0.2.0", - "configurations": [ - { - "name": "Debug Server", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceFolder}/src/Tgstation.Server.Host/bin/Debug/net6.0/Tgstation.Server.Host.dll", - "args": [], - "cwd": "${workspaceFolder}/src/Tgstation.Server.Host", - // For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window - "console": "externalTerminal", - "stopAtEntry": false - } - ] -} diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index b020c9051a..0000000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "build", - "command": "dotnet", - "type": "process", - "args": [ - "msbuild", - "-p:Configuration=DebugNoFramework" - ], - "problemMatcher": "$msCompile", - "group": { - "kind": "build", - "isDefault": true - } - }, - { - "label": "test", - "command": "dotnet", - "type": "process", - "args": [ - "test", - "-p:Configuration=DebugNoFramework" - ], - "problemMatcher": "$msCompile", - "group": { - "kind": "test", - "isDefault": true - } - } - ] -} diff --git a/omnisharp.json b/omnisharp.json deleted file mode 100644 index 6aa6229abc..0000000000 --- a/omnisharp.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "msbuild": { - "Configuration": "DebugNoFramework", - "EnablePackageAutoRestore" : true - } -} From 15a996f785ff0c2f5f8522c8c4e390c23109058c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 24 Jun 2023 09:48:37 -0400 Subject: [PATCH 010/160] Add .msi variables README.md --- .../package/winget/Tgstation.Server.Host.Service.Msi/README.md | 3 +++ tgstation-server.sln | 1 + 2 files changed, 4 insertions(+) create mode 100644 build/package/winget/Tgstation.Server.Host.Service.Msi/README.md diff --git a/build/package/winget/Tgstation.Server.Host.Service.Msi/README.md b/build/package/winget/Tgstation.Server.Host.Service.Msi/README.md new file mode 100644 index 0000000000..a7d88b76cf --- /dev/null +++ b/build/package/winget/Tgstation.Server.Host.Service.Msi/README.md @@ -0,0 +1,3 @@ +# .msi Installer Project + +Useful reference for variables: https://learn.microsoft.com/en-us/windows/win32/msi/property-reference?redirectedfrom=MSDN diff --git a/tgstation-server.sln b/tgstation-server.sln index 6ef86a9d6b..402b3ed787 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -253,6 +253,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "manifest", "manifest", "{3F EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tgstation.Server.Host.Service.Msi", "Tgstation.Server.Host.Service.Msi", "{F5B9D394-229B-44A1-AD12-D8C078F06814}" ProjectSection(SolutionItems) = preProject + build\package\winget\Tgstation.Server.Host.Service.Msi\README.md = build\package\winget\Tgstation.Server.Host.Service.Msi\README.md build\package\winget\Tgstation.Server.Host.Service.Msi\Tgstation.Server.Host.Service.Msi.vdproj = build\package\winget\Tgstation.Server.Host.Service.Msi\Tgstation.Server.Host.Service.Msi.vdproj EndProjectSection EndProject From e5858d02f4e90c3cbbbd26f1c64e38d1f8a25486 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 24 Jun 2023 09:57:51 -0400 Subject: [PATCH 011/160] Enable (roughly) upgrading the installation --- .../Tgstation.Server.Host.Service.Msi.vdproj | 2 +- build/package/winget/build_package.ps1 | 8 ++++++-- .../winget/manifest/Tgstation.Server.installer.yaml | 1 - 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj index 24d9931bf6..9314561825 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj @@ -343,7 +343,7 @@ "RemovePreviousVersions" = "11:TRUE" "DetectNewerInstalledVersion" = "11:TRUE" "InstallAllUsers" = "11:TRUE" - "ProductVersion" = "8:22.47.5" + "ProductVersion" = "8:0.22.475" "Manufacturer" = "8:tgstation" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:" diff --git a/build/package/winget/build_package.ps1 b/build/package/winget/build_package.ps1 index 8d92adb8a0..438f727fb9 100644 --- a/build/package/winget/build_package.ps1 +++ b/build/package/winget/build_package.ps1 @@ -13,11 +13,15 @@ Remove-Item -Recurse -Force .git [XML]$versionXML = Get-Content build/Version.props $tgsVersion = $versionXML.Project.PropertyGroup.TgsCoreVersion -(Get-Content build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj).Replace('22.47.5', $tgsVersion) | Set-Content build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +$devProductCode = 'D24887FA-3228-4509-B5F3-4E07E349F278' +$devVersion = '0.22.475' + +(Get-Content build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj).Replace($devVersion, $tgsVersion) | Set-Content build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +(Get-Content build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj).Replace($devProductCode, [guid]::NewGuid().ToString().ToUpperInvariant()) | Set-Content build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj dotnet restore cd build/package/winget -dotnet build -c Release Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure +dotnet build -c Release Tgstation.Server.Host.Service.Configure # We make _some_ assumptions DevEnv installer.sln /Project Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj /build Release diff --git a/build/package/winget/manifest/Tgstation.Server.installer.yaml b/build/package/winget/manifest/Tgstation.Server.installer.yaml index ad85341185..8b35539915 100644 --- a/build/package/winget/manifest/Tgstation.Server.installer.yaml +++ b/build/package/winget/manifest/Tgstation.Server.installer.yaml @@ -13,7 +13,6 @@ Installers: InstallModes: - interactive - silent - UpgradeBehavior: uninstallPrevious ProductCode: '{D24887FA-3228-4509-B5F3-4E07E349F278}' RequireExplicitUpgrade: true UnsupportedOSArchitectures: From 8614b07a9e373a201863230a67f6777e9ab44a7f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 10:02:13 -0400 Subject: [PATCH 012/160] Start service if configured during installation --- .../Program.cs | 43 ++++++++++++------- .../Tgstation.Server.Host.Service.Msi.vdproj | 4 +- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs b/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs index c55662074b..0739060cfe 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs +++ b/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Reflection; using System.Threading; -using System.Threading.Tasks; using var process = new Process(); @@ -64,22 +63,31 @@ if (uninstall) true); } -if(shortcut && process.ExitCode == 0) +if ((shortcut || (interactive && !uninstall)) && process.ExitCode == 0) { - Console.WriteLine(); - Console.Write("tgstation-server is now configured. Would you like to (re)start the service? (Y/n): "); - var keyInfo = Console.ReadKey(); - Console.WriteLine(); - if (keyInfo.Key == ConsoleKey.Y || keyInfo.Key == ConsoleKey.Enter) + var startServer = interactive; + if (shortcut) { - using (var stopService = new Process()) + Console.WriteLine(); + Console.Write("tgstation-server is now configured. Would you like to (re)start the service? (Y/n): "); + var keyInfo = Console.ReadKey(); + Console.WriteLine(); + if (keyInfo.Key == ConsoleKey.Y || keyInfo.Key == ConsoleKey.Enter) { - stopService.StartInfo.FileName = "sc"; - stopService.StartInfo.Arguments = "stop tgstation-server"; - stopService.Start(); - await stopService.WaitForExitAsync(CancellationToken.None); // DCT: None available - } + using (var stopService = new Process()) + { + stopService.StartInfo.FileName = "sc"; + stopService.StartInfo.Arguments = "stop tgstation-server"; + stopService.Start(); + await stopService.WaitForExitAsync(CancellationToken.None); // DCT: None available + } + startServer = true; + } + } + + if (startServer) + { using var startService = new Process(); startService.StartInfo.FileName = "sc"; startService.StartInfo.Arguments = "start tgstation-server"; @@ -87,9 +95,12 @@ if(shortcut && process.ExitCode == 0) await startService.WaitForExitAsync(CancellationToken.None); // DCT: None available } - Console.WriteLine("Press any key to exit this program..."); - Console.ReadKey(); - Console.WriteLine(); + if (shortcut) + { + Console.WriteLine("Press any key to exit this program..."); + Console.ReadKey(); + Console.WriteLine(); + } } // returning non-zero can make the installation uninstallable, no thanks diff --git a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj index 9314561825..aca2f4920e 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj @@ -336,7 +336,7 @@ "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:tgstation-server" "ProductCode" = "8:{D24887FA-3228-4509-B5F3-4E07E349F278}" - "PackageCode" = "8:{F5E9572F-EBD8-43D4-AEF4-9EB8A70C7A0F}" + "PackageCode" = "8:{7B5CC9A0-D69D-41A1-956E-B9B3788ED3DC}" "UpgradeCode" = "8:{151FE9F8-72CF-48D5-8E55-B7FB6BA9693E}" "AspNetVersion" = "8:4.0.30319.0" "RestartWWWService" = "11:FALSE" @@ -814,7 +814,7 @@ "ContextData" = "8:" "Attributes" = "3:0" "Setting" = "3:2" - "Value" = "8:You can now start tgstation-server from your Services control panel. Press Win+R and enter 'services.msc' to access it. Then navigate to http://localhost: to manage your server." + "Value" = "8:You can now navigate to http://localhost: to manage your server." "DefaultValue" = "8:#1258" "UsePlugInResources" = "11:TRUE" } From f1f9a2b62fa053f05075b666c19b1468c73e2934 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 10:03:13 -0400 Subject: [PATCH 013/160] Test .msi installation in CI --- .github/workflows/ci-suite.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 3067a6225c..5c9629cd51 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -959,6 +959,17 @@ jobs: shell: powershell run: build/package/winget/build_package.ps1 + - name: Test Installation # Sanity checks the .deps.json exists, which the installation is broken without + shell: powershell # If it's missing, I found that in elements were the problem + run: | + $file = "packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi" + $log = "install.log" + $procMain = Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru + $procLog = Start-Process "powershell" "Get-Content -Path `"$log`" -Wait" -NoNewWindow -PassThru + $procMain.WaitForExit() + $procLog.Kill() + Get-Content C:/Program Files (x86)/tgstation/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json + - name: Upload .msi uses: actions/upload-artifact@v3 with: From 8e0b8ce4eb548bd9cd66a5db6d8d803bf14534a3 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 10:31:03 -0400 Subject: [PATCH 014/160] Fix .deb build --- build/package/deb/MakeInstall | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package/deb/MakeInstall b/build/package/deb/MakeInstall index ac109ab592..ddbb512673 100755 --- a/build/package/deb/MakeInstall +++ b/build/package/deb/MakeInstall @@ -2,6 +2,6 @@ install: build/package/deb/install_artifacts.sh "$(DESTDIR)" - install -D build/package/deb/appsettings.Initial.yml "$(DESTDIR)/etc/tgstation-server/appsettings.Production.yml" + install -D build/package/appsettings.Initial.yml "$(DESTDIR)/etc/tgstation-server/appsettings.Production.yml" install src/Tgstation.Server.Host/appsettings.yml "$(DESTDIR)/etc/tgstation-server/appsettings.ex.yml" install -D build/package/deb/tgs-configure "$(DESTDIR)/usr/bin/tgs-configure" From 2c2797134d127f4d3f3d2a90633ab685e89a00ab Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 10:35:32 -0400 Subject: [PATCH 015/160] Fix .msi packaging failing due to non-existent dir --- build/package/winget/build_package.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package/winget/build_package.ps1 b/build/package/winget/build_package.ps1 index 438f727fb9..eece34452f 100644 --- a/build/package/winget/build_package.ps1 +++ b/build/package/winget/build_package.ps1 @@ -1,6 +1,6 @@ $currentCommit=git rev-parse HEAD -Remove-Item -Recurse -Force packaging +Remove-Item -Recurse -Force -ErrorAction SilentlyContinue packaging git worktree remove -f packaging From 8956a43e03ce4cf867c9ee59dd81bf648c486fb6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 10:40:35 -0400 Subject: [PATCH 016/160] Test uninstall .msi in CI --- .github/workflows/ci-suite.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 5c9629cd51..8d5e268f37 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -959,8 +959,8 @@ jobs: shell: powershell run: build/package/winget/build_package.ps1 - - name: Test Installation # Sanity checks the .deps.json exists, which the installation is broken without - shell: powershell # If it's missing, I found that in elements were the problem + - name: Test Install and Uninstall # Sanity checks the .deps.json exists, which the installation is broken without + shell: powershell # If it's missing, I found that in elements were the problem run: | $file = "packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi" $log = "install.log" @@ -969,6 +969,17 @@ jobs: $procMain.WaitForExit() $procLog.Kill() Get-Content C:/Program Files (x86)/tgstation/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json + Get-Service -Name tgstation-server -ErrorAction SilentlyContinue + $log = "uninstall.log" + $procMain = Start-Process "msiexec" "/u `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru + $procLog = Start-Process "powershell" "Get-Content -Path `"$log`" -Wait" -NoNewWindow -PassThru + $procMain.WaitForExit() + $procLog.Kill() + $service=Get-Service -Name tgstation-server -ErrorAction SilentlyContinue + if ($service.Length -gt 0) { + echo $service + exit 1 + } - name: Upload .msi uses: actions/upload-artifact@v3 From 84ccd19295888497bc17f3d6caa88a420bae976f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 11:24:06 -0400 Subject: [PATCH 017/160] Test deb install and uninstall --- .github/workflows/ci-suite.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 8d5e268f37..4fb9375c24 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -918,6 +918,24 @@ jobs: gpg --verify tgstation-server_${{ env.TGS_VERSION }}-1_amd64.changes gpg --verify tgstation-server_${{ env.TGS_VERSION }}-1_amd64.buildinfo + - name: Test Install and Uninstall + run: | + sudo dpkg --add-architecture i386 + sudo apt-get update + sudo apt-get install -y tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb + systemctl status tgstation-server + sudo ls -al /etc/tgstation-server + sudo cat /etc/tgstation-server/appsettings.Production.yml + sudo cat /opt/tgstation-server/appsettings.Production.yml + cat /opt/tgstation-server/appsettings.yml + cat /opt/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json + cat /usr/bin/tgs-configure + sudo apt-get remove -y tgstation-server + if [[ -d "/opt/tgstation-server" ]]; then + ls -al /opt/tgstation-server + exit 1 + fi + - name: Create Packaging Archive run: tar cfJ tgstation-server-v${{ env.TGS_VERSION }}.debian.packaging.tar.xz tgstation-server_* From 54a524b0375ae4d539d613402322e751e6b3bfee Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 11:28:13 -0400 Subject: [PATCH 018/160] Add missing manifest.xml to docker context --- .dockerignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.dockerignore b/.dockerignore index 384f226cd7..84eec5900b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -23,6 +23,7 @@ build/** !build/ControlPanelVersion.props !build/Common.props !build/NugetCommon.props +!build/manifest.xml docs src/DMAPI src/Tgstation.Server.Host/ClientApp From 5202a79d8153b04b146095570351ba878b8a6727 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 11:29:09 -0400 Subject: [PATCH 019/160] Rename manifest.xml to uac_elevation_manifest.xml --- .dockerignore | 2 +- .../Tgstation.Server.Host.Service.Configure.csproj | 4 ++-- build/{manifest.xml => uac_elevation_manifest.xml} | 0 src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 4 ++-- tgstation-server.sln | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) rename build/{manifest.xml => uac_elevation_manifest.xml} (100%) diff --git a/.dockerignore b/.dockerignore index 84eec5900b..0a5c0e76af 100644 --- a/.dockerignore +++ b/.dockerignore @@ -23,7 +23,7 @@ build/** !build/ControlPanelVersion.props !build/Common.props !build/NugetCommon.props -!build/manifest.xml +!build/uac_elevation_manifest.xml docs src/DMAPI src/Tgstation.Server.Host/ClientApp diff --git a/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj b/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj index 15716db084..e85561e603 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj @@ -4,11 +4,11 @@ Exe net6.0 enable - ../../../manifest.xml + ../../../uac_elevation_manifest.xml ../../../tgs.ico - + diff --git a/build/manifest.xml b/build/uac_elevation_manifest.xml similarity index 100% rename from build/manifest.xml rename to build/uac_elevation_manifest.xml diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 6c63de35d2..eebc126c92 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -13,7 +13,7 @@ ClientApp/node_modules/.install-stamp Linux ..\.. - ../../build/manifest.xml + ../../build/uac_elevation_manifest.xml @@ -142,7 +142,7 @@ - + diff --git a/tgstation-server.sln b/tgstation-server.sln index 402b3ed787..7dac32ea6d 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -30,7 +30,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{6FF654E6 build\coverlet.runsettings = build\coverlet.runsettings build\Dockerfile = build\Dockerfile build\GenerateMigrations.sh = build\GenerateMigrations.sh - build\manifest.xml = build\manifest.xml + build\uac_elevation_manifest.xml = build\uac_elevation_manifest.xml build\NugetCommon.props = build\NugetCommon.props build\OpenApiValidationSettings.json = build\OpenApiValidationSettings.json build\stylecop.json = build\stylecop.json From cde647bc6379ef1ce49f4e567caac06995dcbdb3 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 11:47:21 -0400 Subject: [PATCH 020/160] Fix .msi shortcut icon --- .../Tgstation.Server.Host.Service.Msi.vdproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj index aca2f4920e..281b7aac22 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj @@ -336,7 +336,7 @@ "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:tgstation-server" "ProductCode" = "8:{D24887FA-3228-4509-B5F3-4E07E349F278}" - "PackageCode" = "8:{7B5CC9A0-D69D-41A1-956E-B9B3788ED3DC}" + "PackageCode" = "8:{300FB19F-E886-410D-8281-F0EB723E07D7}" "UpgradeCode" = "8:{151FE9F8-72CF-48D5-8E55-B7FB6BA9693E}" "AspNetVersion" = "8:4.0.30319.0" "RestartWWWService" = "11:FALSE" @@ -458,16 +458,16 @@ { "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_86C54A96871E40B6B517685DB09F223A" { - "Name" = "8:Configure and Start tgstation-server" + "Name" = "8:Configure and Restart tgstation-server" "Arguments" = "8:42069 " "Description" = "8:Runs the TGS setup wizard and optionally restarts the Windows service" "ShowCmd" = "3:1" - "IconIndex" = "3:0" + "IconIndex" = "3:32512" "Transitive" = "11:FALSE" "Target" = "8:_E9F7402DCE77463F9B7319647D3C16F2" "Folder" = "8:_BD1E6451115645479FB57AD1F0BB6A8B" "WorkingFolder" = "8:_B28C4FD80D0245E08AEDCFEECACB6493" - "Icon" = "8:" + "Icon" = "8:_E9F7402DCE77463F9B7319647D3C16F2" "Feature" = "8:" } } From 1a472a4cf1dd7c1a844d8078afdb70eaa475f8b0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 11:49:18 -0400 Subject: [PATCH 021/160] Add configure shortcut to start menu --- .../Tgstation.Server.Host.Service.Msi.vdproj | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj index 281b7aac22..4d93de3c4d 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj @@ -262,6 +262,17 @@ } "Folder" { + "{1525181F-901A-416C-8A58-119130FE478E}:_758C42B61089428A950F84AD33260664" + { + "Name" = "8:#1921" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:StartMenuFolder" + "Folders" + { + } + } "{3C67513D-01DD-4637-8A68-80971EB9504F}:_B28C4FD80D0245E08AEDCFEECACB6493" { "DefaultLocation" = "8:[ProgramFilesFolder][Manufacturer]\\[ProductName]" @@ -456,6 +467,20 @@ } "Shortcut" { + "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_8033129B5D1D4BB0904586D539B32765" + { + "Name" = "8:Configure and Restart tgstation-server" + "Arguments" = "8:42069" + "Description" = "8:Runs the TGS setup wizard and optionally restarts the Windows service" + "ShowCmd" = "3:1" + "IconIndex" = "3:32512" + "Transitive" = "11:FALSE" + "Target" = "8:_E9F7402DCE77463F9B7319647D3C16F2" + "Folder" = "8:_758C42B61089428A950F84AD33260664" + "WorkingFolder" = "8:_B28C4FD80D0245E08AEDCFEECACB6493" + "Icon" = "8:_E9F7402DCE77463F9B7319647D3C16F2" + "Feature" = "8:" + } "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_86C54A96871E40B6B517685DB09F223A" { "Name" = "8:Configure and Restart tgstation-server" From 2760060969f89cfb9f609403550f49235fddc1c6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 12:24:56 -0400 Subject: [PATCH 022/160] dotnet commands here do not speed up the build --- .github/workflows/ci-suite.yml | 5 ----- build/package/winget/build_package.ps1 | 10 ++++------ 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 4fb9375c24..7caec6d41a 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -951,11 +951,6 @@ jobs: runs-on: windows-latest if: "!(cancelled() || failure()) && needs.start-ci-run-gate.result == 'success'" steps: - - name: Setup dotnet - uses: actions/setup-dotnet@v2 - with: - dotnet-version: ${{ env.TGS_DOTNET_VERSION }} - - name: Setup VS Dev Environment uses: seanmiddleditch/gha-setup-vsdevenv@v4 diff --git a/build/package/winget/build_package.ps1 b/build/package/winget/build_package.ps1 index eece34452f..22db5bb83f 100644 --- a/build/package/winget/build_package.ps1 +++ b/build/package/winget/build_package.ps1 @@ -13,15 +13,13 @@ Remove-Item -Recurse -Force .git [XML]$versionXML = Get-Content build/Version.props $tgsVersion = $versionXML.Project.PropertyGroup.TgsCoreVersion +cd build/package/winget + $devProductCode = 'D24887FA-3228-4509-B5F3-4E07E349F278' $devVersion = '0.22.475' -(Get-Content build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj).Replace($devVersion, $tgsVersion) | Set-Content build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj -(Get-Content build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj).Replace($devProductCode, [guid]::NewGuid().ToString().ToUpperInvariant()) | Set-Content build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj - -dotnet restore -cd build/package/winget -dotnet build -c Release Tgstation.Server.Host.Service.Configure +(Get-Content Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj).Replace($devVersion, $tgsVersion) | Set-Content Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +(Get-Content Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj).Replace($devProductCode, [guid]::NewGuid().ToString().ToUpperInvariant()) | Set-Content Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj # We make _some_ assumptions DevEnv installer.sln /Project Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj /build Release From ebadd12cc4f5982b5c2a8fee510a12094b46b8fc Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 12:34:16 -0400 Subject: [PATCH 023/160] Use windows targeted net6.0 for configure project --- .../Tgstation.Server.Host.Service.Configure.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj b/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj index e85561e603..e0c822ad1b 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net6.0-windows enable ../../../uac_elevation_manifest.xml ../../../tgs.ico From 4f0d3876e36a5805ee67ca1d6a11f88370856480 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 12:34:33 -0400 Subject: [PATCH 024/160] Set ACL info in configure script --- .../Program.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs b/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs index 0739060cfe..13b2ae64c3 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs +++ b/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; +using System.Security.AccessControl; using System.Threading; using var process = new Process(); @@ -57,14 +58,27 @@ foreach (var installLogFile in Directory.EnumerateFiles(installDir, "*.log")) File.Delete(installLogFile); if (uninstall) -{ Directory.Delete( Path.Combine(installDir, "lib"), true); -} if ((shortcut || (interactive && !uninstall)) && process.ExitCode == 0) { + // try and lockdown the appsettings file + var fileInfo = new FileInfo("appsettings.Production.yml"); + + //get security access + FileSecurity fs = fileInfo.GetAccessControl(); + + //remove inherited access + fs.SetAccessRuleProtection(true, false); + + // Explicitly grant admins and SYSTEM + fs.AddAccessRule(new FileSystemAccessRule("Administrators", FileSystemRights.FullControl, AccessControlType.Allow)); + fs.AddAccessRule(new FileSystemAccessRule("SYSTEM", FileSystemRights.Read, AccessControlType.Allow)); + + fileInfo.SetAccessControl(fs); + var startServer = interactive; if (shortcut) { From 375895a5cd88ec96b817a9985e3405a9a0dee260 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 12:37:09 -0400 Subject: [PATCH 025/160] A bunch of .vdproj fixups I can't read the diff because of this fucking project format --- .../Tgstation.Server.Host.Service.Msi.vdproj | 106 +++++++----------- 1 file changed, 40 insertions(+), 66 deletions(-) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj index 4d93de3c4d..73255a2210 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj @@ -33,18 +33,6 @@ } "Entry" { - "MsmKey" = "8:_4F14AB1FF9E24F9EBCC13DECAD76B526" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_8F775F391C394240882C33EF95C853E3" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { "MsmKey" = "8:_B0A2BC595A554F188D336702686A821E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -61,6 +49,12 @@ "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } + "Entry" + { + "MsmKey" = "8:_F78AE830495A499099776F774CAB3D6D" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } } "Configurations" { @@ -176,46 +170,6 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4F14AB1FF9E24F9EBCC13DECAD76B526" - { - "SourcePath" = "8:..\\install_banner.jpg" - "TargetName" = "8:install_banner.jpg" - "Tag" = "8:" - "Folder" = "8:_EB2DCEE6D3F74230A9827AC9B6F47F53" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8F775F391C394240882C33EF95C853E3" - { - "SourcePath" = "8:..\\install_banner.jpg" - "TargetName" = "8:install_banner.jpg" - "Tag" = "8:" - "Folder" = "8:_EB2DCEE6D3F74230A9827AC9B6F47F53" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:TRUE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B0A2BC595A554F188D336702686A821E" { "SourcePath" = "8:..\\..\\..\\..\\LICENSE" @@ -256,6 +210,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F78AE830495A499099776F774CAB3D6D" + { + "SourcePath" = "8:..\\install_banner.jpg" + "TargetName" = "8:install_banner.jpg" + "Tag" = "8:" + "Folder" = "8:_EB2DCEE6D3F74230A9827AC9B6F47F53" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:TRUE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } } "FileType" { @@ -346,15 +320,15 @@ { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:tgstation-server" - "ProductCode" = "8:{D24887FA-3228-4509-B5F3-4E07E349F278}" - "PackageCode" = "8:{300FB19F-E886-410D-8281-F0EB723E07D7}" + "ProductCode" = "8:{879A86CB-D12C-4D31-9386-0D5CE8C53FC4}" + "PackageCode" = "8:{D078B8A7-E5C3-48EE-85B0-56C355FCBB43}" "UpgradeCode" = "8:{151FE9F8-72CF-48D5-8E55-B7FB6BA9693E}" "AspNetVersion" = "8:4.0.30319.0" "RestartWWWService" = "11:FALSE" "RemovePreviousVersions" = "11:TRUE" "DetectNewerInstalledVersion" = "11:TRUE" "InstallAllUsers" = "11:TRUE" - "ProductVersion" = "8:0.22.475" + "ProductVersion" = "8:5.12.6" "Manufacturer" = "8:tgstation" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:" @@ -529,7 +503,7 @@ "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:2" - "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "Value" = "8:_F78AE830495A499099776F774CAB3D6D" "UsePlugInResources" = "11:TRUE" } } @@ -561,7 +535,7 @@ "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:2" - "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "Value" = "8:_F78AE830495A499099776F774CAB3D6D" "UsePlugInResources" = "11:TRUE" } } @@ -584,7 +558,7 @@ "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:2" - "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "Value" = "8:_F78AE830495A499099776F774CAB3D6D" "UsePlugInResources" = "11:TRUE" } "CopyrightWarning" @@ -633,7 +607,7 @@ "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:2" - "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "Value" = "8:_F78AE830495A499099776F774CAB3D6D" "UsePlugInResources" = "11:TRUE" } "InstallAllUsersVisible" @@ -678,7 +652,7 @@ "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:2" - "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "Value" = "8:_F78AE830495A499099776F774CAB3D6D" "UsePlugInResources" = "11:TRUE" } "ShowProgress" @@ -723,7 +697,7 @@ "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:2" - "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "Value" = "8:_F78AE830495A499099776F774CAB3D6D" "UsePlugInResources" = "11:TRUE" } } @@ -746,7 +720,7 @@ "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:2" - "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "Value" = "8:_F78AE830495A499099776F774CAB3D6D" "UsePlugInResources" = "11:TRUE" } } @@ -769,7 +743,7 @@ "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:2" - "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "Value" = "8:_F78AE830495A499099776F774CAB3D6D" "UsePlugInResources" = "11:TRUE" } "CopyrightWarning" @@ -827,7 +801,7 @@ "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:2" - "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "Value" = "8:_F78AE830495A499099776F774CAB3D6D" "UsePlugInResources" = "11:TRUE" } "UpdateText" @@ -878,7 +852,7 @@ "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:2" - "Value" = "8:_8F775F391C394240882C33EF95C853E3" + "Value" = "8:_F78AE830495A499099776F774CAB3D6D" "UsePlugInResources" = "11:TRUE" } "ShowProgress" @@ -1020,7 +994,7 @@ } "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_E9F7402DCE77463F9B7319647D3C16F2" { - "SourcePath" = "8:..\\Tgstation.Server.Host.Service.Configure\\obj\\Release\\net6.0\\apphost.exe" + "SourcePath" = "8:..\\Tgstation.Server.Host.Service.Configure\\obj\\Release\\net6.0-windows\\apphost.exe" "TargetName" = "8:" "Tag" = "8:" "Folder" = "8:_B28C4FD80D0245E08AEDCFEECACB6493" From de7d93d218eedd3b99991d5c5fbb418eb472f7b8 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 12:42:09 -0400 Subject: [PATCH 026/160] Fix cd backup in `build_package.ps1` --- build/package/winget/build_package.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package/winget/build_package.ps1 b/build/package/winget/build_package.ps1 index 22db5bb83f..3ded22efd0 100644 --- a/build/package/winget/build_package.ps1 +++ b/build/package/winget/build_package.ps1 @@ -24,4 +24,4 @@ $devVersion = '0.22.475' # We make _some_ assumptions DevEnv installer.sln /Project Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj /build Release -cd .. +cd ../../../.. From a6c85366ae74b7909f2c8e3a25d2467b0f513e68 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 19:12:40 -0400 Subject: [PATCH 027/160] Add Windows service commands 128, 129, and 130 - 128 triggers a server shutdown. - 129 and 130 are identical to SIGUSR1 and SIGUSR2 respectively, triggering a graceful shutdown and detaching shutdown respectively. - These are implemented via pipes and are preferred to using the update path going forward. Should eventually replace the param entirely at the next possibility. - New service params to detach and restart any running server as opposed to stopping entirely. - Defer all service control to Service executable from Configure app. - Console runner returns non-zero on error. - Fix setting ACL of appsettings.Production.yml. --- .../Program.cs | 65 ++++------ .../PipeCommands.cs | 35 ++++++ .../PosixSignalChecker.cs} | 29 +++-- src/Tgstation.Server.Host.Console/Program.cs | 25 +++- .../NoopSignalChecker.cs | 21 ++++ src/Tgstation.Server.Host.Service/Program.cs | 80 +++++++++---- .../ServerService.cs | 113 ++++++++++++++++-- .../ISignalChecker.cs | 20 ++++ .../IWatchdog.cs | 4 +- .../IWatchdogFactory.cs | 3 +- .../Watchdog.cs | 42 ++++--- .../WatchdogFactory.cs | 6 +- .../Configuration/InternalConfiguration.cs | 18 +++ src/Tgstation.Server.Host/Core/Application.cs | 10 +- .../Core/CommandPipeReader.cs | 109 +++++++++++++++++ src/Tgstation.Server.Host/Server.cs | 17 ++- .../TestProgram.cs | 6 +- .../TestServerService.cs | 4 +- .../TestWatchdog.cs | 8 +- .../TestWatchdogFactory.cs | 7 +- 20 files changed, 496 insertions(+), 126 deletions(-) create mode 100644 src/Tgstation.Server.Host.Common/PipeCommands.cs rename src/{Tgstation.Server.Host.Watchdog/SignalChecker.cs => Tgstation.Server.Host.Console/PosixSignalChecker.cs} (70%) create mode 100644 src/Tgstation.Server.Host.Service/NoopSignalChecker.cs create mode 100644 src/Tgstation.Server.Host.Watchdog/ISignalChecker.cs create mode 100644 src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs create mode 100644 src/Tgstation.Server.Host/Core/CommandPipeReader.cs diff --git a/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs b/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs index 13b2ae64c3..9d5c5bb53b 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs +++ b/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs @@ -13,7 +13,7 @@ var installDir = Path.GetDirectoryName( process.StartInfo.WorkingDirectory = installDir; process.StartInfo.FileName = Path.Combine( - process.StartInfo.WorkingDirectory, + installDir, "Tgstation.Server.Host.Service.exe"); /* @@ -44,11 +44,22 @@ var uninstall = args var shortcut = uiLevel == 42069; +bool startService; +if (shortcut) +{ + Console.WriteLine(); + Console.WriteLine("This program will configure tgstation-server. Would you like to restart the service after doing so?"); + Console.Write("A restart is required to apply changes. It will not kill your DreamDaemon instances provided you are running a version >=5.13.0 (Y/n): "); + var keyInfo = Console.ReadKey(); + startService = keyInfo.Key == ConsoleKey.Enter || keyInfo.Key == ConsoleKey.Y; + Console.WriteLine(); +} +else + startService = interactive; + process.StartInfo.Arguments = uninstall ? "-u" - : shortcut - ? "-c" - : $"-i -f {(interactive ? "-c" : String.Empty)} {(silent ? "-s" : String.Empty)}"; + : $"-i -f -x{(startService ? " -r" : String.Empty)}{((interactive || shortcut) ? " -c" : String.Empty)}{(silent ? " -s" : String.Empty)}"; process.Start(); @@ -65,7 +76,7 @@ if (uninstall) if ((shortcut || (interactive && !uninstall)) && process.ExitCode == 0) { // try and lockdown the appsettings file - var fileInfo = new FileInfo("appsettings.Production.yml"); + var fileInfo = new FileInfo(Path.Combine(installDir, "appsettings.Production.yml")); //get security access FileSecurity fs = fileInfo.GetAccessControl(); @@ -75,46 +86,16 @@ if ((shortcut || (interactive && !uninstall)) && process.ExitCode == 0) // Explicitly grant admins and SYSTEM fs.AddAccessRule(new FileSystemAccessRule("Administrators", FileSystemRights.FullControl, AccessControlType.Allow)); - fs.AddAccessRule(new FileSystemAccessRule("SYSTEM", FileSystemRights.Read, AccessControlType.Allow)); + fs.AddAccessRule(new FileSystemAccessRule("NT AUTHORITY\\SYSTEM", FileSystemRights.Read, AccessControlType.Allow)); fileInfo.SetAccessControl(fs); +} - var startServer = interactive; - if (shortcut) - { - Console.WriteLine(); - Console.Write("tgstation-server is now configured. Would you like to (re)start the service? (Y/n): "); - var keyInfo = Console.ReadKey(); - Console.WriteLine(); - if (keyInfo.Key == ConsoleKey.Y || keyInfo.Key == ConsoleKey.Enter) - { - using (var stopService = new Process()) - { - stopService.StartInfo.FileName = "sc"; - stopService.StartInfo.Arguments = "stop tgstation-server"; - stopService.Start(); - await stopService.WaitForExitAsync(CancellationToken.None); // DCT: None available - } - - startServer = true; - } - } - - if (startServer) - { - using var startService = new Process(); - startService.StartInfo.FileName = "sc"; - startService.StartInfo.Arguments = "start tgstation-server"; - startService.Start(); - await startService.WaitForExitAsync(CancellationToken.None); // DCT: None available - } - - if (shortcut) - { - Console.WriteLine("Press any key to exit this program..."); - Console.ReadKey(); - Console.WriteLine(); - } +if (shortcut) +{ + Console.WriteLine("Press any key to exit this program..."); + Console.ReadKey(); + Console.WriteLine(); } // returning non-zero can make the installation uninstallable, no thanks diff --git a/src/Tgstation.Server.Host.Common/PipeCommands.cs b/src/Tgstation.Server.Host.Common/PipeCommands.cs new file mode 100644 index 0000000000..10390cbfbc --- /dev/null +++ b/src/Tgstation.Server.Host.Common/PipeCommands.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; + +namespace Tgstation.Server.Host.Common +{ + /// + /// Values able to be passed via the update file path. + /// + public static class PipeCommands + { + /// + /// Stops the server ASAP, shutting down any running instances. + /// + public const string CommandStop = "stop"; + + /// + /// Stops the server eventually, waiting for the games in any running instances to reboot. + /// + public const string CommandGracefulShutdown = "graceful"; + + /// + /// Stops the server ASAP, detaching the watchdog for any running instances. + /// + public const string CommandDetachingShutdown = "detach"; + + /// + /// All of the represented as a . + /// + public static IReadOnlyList AllCommands { get; } = new[] + { + CommandStop, + CommandGracefulShutdown, + CommandDetachingShutdown, + }; + } +} diff --git a/src/Tgstation.Server.Host.Watchdog/SignalChecker.cs b/src/Tgstation.Server.Host.Console/PosixSignalChecker.cs similarity index 70% rename from src/Tgstation.Server.Host.Watchdog/SignalChecker.cs rename to src/Tgstation.Server.Host.Console/PosixSignalChecker.cs index 3be780fb39..a2ffceb69f 100644 --- a/src/Tgstation.Server.Host.Watchdog/SignalChecker.cs +++ b/src/Tgstation.Server.Host.Console/PosixSignalChecker.cs @@ -7,22 +7,33 @@ using Microsoft.Extensions.Logging; using Mono.Unix; using Mono.Unix.Native; -namespace Tgstation.Server.Host.Watchdog +using Tgstation.Server.Host.Watchdog; + +namespace Tgstation.Server.Host.Console { /// - /// Helper for checking POSIX signals. + /// for checking POSIX signals. /// - static class SignalChecker + sealed class PosixSignalChecker : ISignalChecker { /// - /// Forwards certain signals to a given . + /// The for the . /// - /// The to write to. - /// The of the process to forward signals to. - /// The for the operation. - /// A representing the running operation. - public static async Task CheckSignals(ILogger logger, int childPid, CancellationToken cancellationToken) + readonly ILogger logger; + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + public PosixSignalChecker(ILogger logger) { + this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + + /// + public async Task CheckSignals(Func startChild, CancellationToken cancellationToken) + { + var (childPid, _) = startChild?.Invoke(null) ?? throw new ArgumentNullException(nameof(startChild)); var signalTcs = new TaskCompletionSource(); async Task CheckSignal(Signum signum) { diff --git a/src/Tgstation.Server.Host.Console/Program.cs b/src/Tgstation.Server.Host.Console/Program.cs index c1c9c4dbc7..1a3c02cd72 100644 --- a/src/Tgstation.Server.Host.Console/Program.cs +++ b/src/Tgstation.Server.Host.Console/Program.cs @@ -32,17 +32,26 @@ namespace Tgstation.Server.Host.Console /// /// The arguments for the . /// A representing the running operation. - internal static async Task Main(string[] args) + internal static async Task Main(string[] args) { - using var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole()); var arguments = new List(args); var trace = arguments.Remove("--trace-host-watchdog"); var debug = arguments.Remove("--debug-host-watchdog"); + using var loggerFactory = LoggerFactory.Create(builder => + { + if (trace) + builder.SetMinimumLevel(LogLevel.Trace); + else if (debug) + builder.SetMinimumLevel(LogLevel.Debug); + + builder.AddConsole(); + }); + if (trace && debug) { loggerFactory.CreateLogger(nameof(Program)).LogCritical("Please specify only 1 of --trace-host-watchdog or --debug-host-watchdog!"); - return; + return 2; } using var cts = new CancellationTokenSource(); @@ -55,7 +64,15 @@ namespace Tgstation.Server.Host.Console b.Cancel = true; cts.Cancel(); }; - await WatchdogFactory.CreateWatchdog(loggerFactory).RunAsync(false, arguments.ToArray(), cts.Token); + + var watchdog = WatchdogFactory.CreateWatchdog( + new PosixSignalChecker( + loggerFactory.CreateLogger()), + loggerFactory); + + return await watchdog.RunAsync(false, arguments.ToArray(), cts.Token) + ? 0 + : 1; } finally { diff --git a/src/Tgstation.Server.Host.Service/NoopSignalChecker.cs b/src/Tgstation.Server.Host.Service/NoopSignalChecker.cs new file mode 100644 index 0000000000..485d8f152e --- /dev/null +++ b/src/Tgstation.Server.Host.Service/NoopSignalChecker.cs @@ -0,0 +1,21 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +using Tgstation.Server.Host.Watchdog; + +namespace Tgstation.Server.Host.Service +{ + /// + /// No-op . + /// + sealed class NoopSignalChecker : ISignalChecker + { + /// + public Task CheckSignals(Func startChild, CancellationToken cancellationToken) + { + startChild(null); + return Task.CompletedTask; + } + } +} diff --git a/src/Tgstation.Server.Host.Service/Program.cs b/src/Tgstation.Server.Host.Service/Program.cs index db02337785..f2f78bc9a8 100644 --- a/src/Tgstation.Server.Host.Service/Program.cs +++ b/src/Tgstation.Server.Host.Service/Program.cs @@ -15,6 +15,7 @@ using McMaster.Extensions.CommandLineUtils; using Microsoft.Extensions.Logging; +using Tgstation.Server.Host.Common; using Tgstation.Server.Host.Watchdog; namespace Tgstation.Server.Host.Service @@ -37,6 +38,18 @@ namespace Tgstation.Server.Host.Service [Option(ShortName = "u")] public bool Uninstall { get; } + /// + /// The --detach or -x option. Valid only with . + /// + [Option(ShortName = "x")] + public bool Detach { get; } + + /// + /// The --resume or -r option. + /// + [Option(ShortName = "r")] + public bool Resume { get; } + /// /// The --install or -i option. /// @@ -97,9 +110,11 @@ namespace Tgstation.Server.Host.Service /// A representing the running operation. public async Task OnExecuteAsync() { + var standardRun = !Install && !Uninstall && !Configure; + if (Environment.UserInteractive) { - if (!Install && !Uninstall && !Configure) + if (standardRun) { var result = MessageBox.Show("You are running the TGS windows service executable directly. It should only be run by the service control manager. Would you like to install and configure the service in this location?", "TGS Service", MessageBoxButtons.YesNo); if (result != DialogResult.Yes) @@ -112,12 +127,13 @@ namespace Tgstation.Server.Host.Service { // try to restart as admin // its windows, first arg is .exe name guaranteed - var exe = Environment.GetCommandLineArgs().First(); + var args = Environment.GetCommandLineArgs(); + var exe = args.First(); var startInfo = new ProcessStartInfo { UseShellExecute = true, Verb = "runas", - Arguments = $"{(Install ? "-i" : Uninstall ? "-u" : String.Empty)} {(Configure ? "-c" : String.Empty)} {(Force ? "-f" : String.Empty)}", + Arguments = String.Join(" ", args.Skip(1)), FileName = exe, WorkingDirectory = Environment.CurrentDirectory, }; @@ -126,17 +142,10 @@ namespace Tgstation.Server.Host.Service } } - if (Install) - { - if (Uninstall) - return; // oh no, it's retarded... + if (Configure) + await RunConfigure(CancellationToken.None); // DCT: None available - RunServiceInstall(); - - if (Configure && !Silent) - Console.WriteLine("For this first run we'll launch the console runner so you may use the setup wizard."); - } - else if (Uninstall) + if (Uninstall) using (var installer = new ServiceInstaller()) { installer.Context = new InstallContext("tgs-uninstall.log", null); @@ -146,36 +155,56 @@ namespace Tgstation.Server.Host.Service installer.ServiceName = ServerService.Name; installer.Uninstall(null); } - else if (!Configure) + + if (Install) + { + RunServiceInstall(); + } + + if (standardRun) { using var service = new ServerService(WatchdogFactory, Trace ? LogLevel.Trace : Debug ? LogLevel.Debug : LogLevel.Information); ServiceBase.Run(service); } - if (Configure) - await RunConfigure(CancellationToken.None); // DCT: None available + if (Resume) + foreach (ServiceController sc in ServiceController.GetServices()) + if (sc.ServiceName == ServerService.Name) + { + sc.Start(); + break; + } } /// /// Attempt to install the TGS Service. /// - void RunServiceInstall() + /// if the service was stopped or detached as a result, otherwise. + bool RunServiceInstall() { // First check if the service already exists + bool serviceStopped = false; if (Force || Environment.UserInteractive) foreach (ServiceController sc in ServiceController.GetServices()) - if (sc.ServiceName == "tgstation-server" || sc.ServiceName == "tgstation-server-4") + if (sc.ServiceName == ServerService.Name || sc.ServiceName == "tgstation-server-4") { DialogResult result = !Force ? MessageBox.Show($"You already have another TGS service installed ({sc.ServiceName}). Would you like to uninstall it now? Pressing \"No\" will cancel this install.", "TGS Service", MessageBoxButtons.YesNo) : DialogResult.Yes; if (result != DialogResult.Yes) - return; // is this needed after exit? + return false; // is this needed after exit? // Stop it first to give it some cleanup time if (sc.Status == ServiceControllerStatus.Running) { - sc.Stop(); + if (Detach) + sc.ExecuteCommand( + ServerService.GetCommand( + PipeCommands.CommandDetachingShutdown) + .Value); + else + sc.Stop(); + sc.WaitForStatus(ServiceControllerStatus.Stopped); } @@ -188,6 +217,8 @@ namespace Tgstation.Server.Host.Service serviceInstaller.ServiceName = sc.ServiceName; serviceInstaller.Uninstall(null); + + serviceStopped = true; } using var processInstaller = new ServiceProcessInstaller(); @@ -198,7 +229,7 @@ namespace Tgstation.Server.Host.Service if (Silent) installer.Context.Parameters["LogToConsole"] = false.ToString(); installer.Description = "tgstation-server running as a windows service"; - installer.DisplayName = "tgstation-server"; + installer.DisplayName = ServerService.Name; installer.StartType = ServiceStartMode.Automatic; installer.ServicesDependedOn = new string[] { "Tcpip", "Dhcp", "Dnscache" }; installer.ServiceName = ServerService.Name; @@ -206,6 +237,8 @@ namespace Tgstation.Server.Host.Service var state = new ListDictionary(); installer.Install(state); + + return serviceStopped; } /// @@ -220,8 +253,9 @@ namespace Tgstation.Server.Host.Service if (!Silent) builder.AddConsole(); }); - await WatchdogFactory.CreateWatchdog(loggerFactory) - .RunAsync(true, Array.Empty(), cancellationToken); + + var watchdog = WatchdogFactory.CreateWatchdog(new NoopSignalChecker(), loggerFactory); + await watchdog.RunAsync(true, Array.Empty(), cancellationToken); } } } diff --git a/src/Tgstation.Server.Host.Service/ServerService.cs b/src/Tgstation.Server.Host.Service/ServerService.cs index 775946d42c..b5a7434c68 100644 --- a/src/Tgstation.Server.Host.Service/ServerService.cs +++ b/src/Tgstation.Server.Host.Service/ServerService.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; -using System.Globalization; +using System.IO; +using System.IO.Pipes; using System.ServiceProcess; using System.Threading; using System.Threading.Tasks; @@ -8,6 +9,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.EventLog; +using Tgstation.Server.Host.Common; using Tgstation.Server.Host.Watchdog; namespace Tgstation.Server.Host.Service @@ -15,7 +17,7 @@ namespace Tgstation.Server.Host.Service /// /// Represents a as a . /// - sealed class ServerService : ServiceBase + sealed class ServerService : ServiceBase, ISignalChecker { /// /// The canonical windows service name. @@ -33,12 +35,17 @@ namespace Tgstation.Server.Host.Service readonly LogLevel minimumLogLevel; /// - /// The used by the service. + /// The used by the . /// ILoggerFactory loggerFactory; /// - /// The that represents the running service. + /// The for the . + /// + ILogger logger; + + /// + /// The that represents the running . /// Task watchdogTask; @@ -47,6 +54,25 @@ namespace Tgstation.Server.Host.Service /// CancellationTokenSource cancellationTokenSource; + /// + /// The the server process is using. + /// + AnonymousPipeServerStream pipeServer; + + /// + /// Gets the value of a given . + /// + /// The . + /// The value of the command or if it was unrecognized. + public static int? GetCommand(string command) + => command switch + { + PipeCommands.CommandStop => 128, // Windows only allows commands 128-256: https://stackoverflow.com/a/62858106 + PipeCommands.CommandGracefulShutdown => 129, + PipeCommands.CommandDetachingShutdown => 130, + _ => null, + }; + /// /// Initializes a new instance of the class. /// @@ -59,14 +85,47 @@ namespace Tgstation.Server.Host.Service ServiceName = Name; } + /// + public async Task CheckSignals(Func startChildAndGetPid, CancellationToken cancellationToken) + { + using (pipeServer = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable)) + { + var (_, lifetimeTask) = startChildAndGetPid($"--Internal:CommandPipe={pipeServer.GetClientHandleAsString()}"); + pipeServer.DisposeLocalCopyOfClientHandle(); + await lifetimeTask; + } + } + /// protected override void Dispose(bool disposing) { - loggerFactory?.Dispose(); - cancellationTokenSource?.Dispose(); + if (disposing) + { + loggerFactory?.Dispose(); + cancellationTokenSource?.Dispose(); + pipeServer?.Dispose(); + } + base.Dispose(disposing); } + /// + protected override void OnCustomCommand(int command) + { + var commandsToCheck = PipeCommands.AllCommands; + foreach (var stringCommand in commandsToCheck) + { + var commandId = GetCommand(stringCommand); + if (command == commandId) + { + SendCommandToUpdatePath(stringCommand); + return; + } + } + + logger.LogWarning("Received unknown service command: {command}", command); + } + /// protected override void OnStart(string[] args) { @@ -79,9 +138,11 @@ namespace Tgstation.Server.Host.Service SourceName = EventLog.Source, Filter = (message, logLevel) => logLevel >= minimumLogLevel, })); + + logger = loggerFactory.CreateLogger(); } - var watchdog = watchdogFactory.CreateWatchdog(loggerFactory); + var watchdog = watchdogFactory.CreateWatchdog(this, loggerFactory); cancellationTokenSource?.Dispose(); cancellationTokenSource = new CancellationTokenSource(); @@ -105,24 +166,50 @@ namespace Tgstation.Server.Host.Service /// A representing the running operation. async Task RunWatchdog(IWatchdog watchdog, string[] args, CancellationToken cancellationToken) { - await watchdog.RunAsync(false, args, cancellationTokenSource.Token); + await watchdog.RunAsync(false, args, cancellationToken); - void StopServiceAsync() + async void StopServiceAsync() { try { - Task.Run(Stop, cancellationToken); + await Task.Run(Stop, cancellationToken); // DCT intentional } - catch (OperationCanceledException) + catch (OperationCanceledException ex) { + logger.LogTrace(ex, "Stopping service cancelled!"); } - catch (Exception e) + catch (Exception ex) { - EventLog.WriteEntry(String.Format(CultureInfo.InvariantCulture, "Error stopping service! Exception: {0}", e)); + logger.LogError(ex, "Error stopping service!"); } } StopServiceAsync(); } + + /// + /// Sends a command to the main server process. + /// + /// One of the . + void SendCommandToUpdatePath(string command) + { + var localPipeServer = pipeServer; + if (localPipeServer == null) + { + logger.LogWarning("Unable to send command \"{command}\" to main server process. Is the service running?", command); + return; + } + + logger.LogDebug("Send command: {command}", command); + try + { + using var streamWriter = new StreamWriter(localPipeServer); + streamWriter.WriteLine(command); + } + catch (Exception ex) + { + logger.LogError(ex, "Error attempting to send command \"{command}\"", command); + } + } } } diff --git a/src/Tgstation.Server.Host.Watchdog/ISignalChecker.cs b/src/Tgstation.Server.Host.Watchdog/ISignalChecker.cs new file mode 100644 index 0000000000..8ab3b06df6 --- /dev/null +++ b/src/Tgstation.Server.Host.Watchdog/ISignalChecker.cs @@ -0,0 +1,20 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Tgstation.Server.Host.Watchdog +{ + /// + /// For relaying signals received to the host process. + /// + public interface ISignalChecker + { + /// + /// Relays signals received to the host process. + /// + /// An to start the main process. It accepts an optional additional command line argument as a paramter and returns it's and lifetime . + /// The for the operation. + /// A representing the running operation. + Task CheckSignals(Func startChild, CancellationToken cancellationToken); + } +} diff --git a/src/Tgstation.Server.Host.Watchdog/IWatchdog.cs b/src/Tgstation.Server.Host.Watchdog/IWatchdog.cs index cb587dfddc..e99f09e31b 100644 --- a/src/Tgstation.Server.Host.Watchdog/IWatchdog.cs +++ b/src/Tgstation.Server.Host.Watchdog/IWatchdog.cs @@ -14,7 +14,7 @@ namespace Tgstation.Server.Host.Watchdog /// If the should just run the host configuration wizard and exit. /// The arguments for the . /// The for the operation. - /// A representing the running operation. - Task RunAsync(bool runConfigure, string[] args, CancellationToken cancellationToken); + /// A resulting in if there were no errors, otherwise. + Task RunAsync(bool runConfigure, string[] args, CancellationToken cancellationToken); } } diff --git a/src/Tgstation.Server.Host.Watchdog/IWatchdogFactory.cs b/src/Tgstation.Server.Host.Watchdog/IWatchdogFactory.cs index c4dfe2bd00..3569139fdd 100644 --- a/src/Tgstation.Server.Host.Watchdog/IWatchdogFactory.cs +++ b/src/Tgstation.Server.Host.Watchdog/IWatchdogFactory.cs @@ -10,8 +10,9 @@ namespace Tgstation.Server.Host.Watchdog /// /// Create a . /// + /// The to use for relaying signals. /// The to use for error reporting. /// A new . - IWatchdog CreateWatchdog(ILoggerFactory loggerFactory); + IWatchdog CreateWatchdog(ISignalChecker signalChecker, ILoggerFactory loggerFactory); } } diff --git a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs index 1afd2cad85..26bac6d658 100644 --- a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs @@ -19,6 +19,11 @@ namespace Tgstation.Server.Host.Watchdog /// This is a HACK but it works. Try not to break it if you wish to change it. Remember, this code doesn't get updated with the rest of the server. sealed class Watchdog : IWatchdog { + /// + /// The for the . + /// + readonly ISignalChecker signalChecker; + /// /// The for the . /// @@ -27,16 +32,18 @@ namespace Tgstation.Server.Host.Watchdog /// /// Initializes a new instance of the class. /// + /// The value of . /// The value of . - public Watchdog(ILogger logger) + public Watchdog(ISignalChecker signalChecker, ILogger logger) { + this.signalChecker = signalChecker ?? throw new ArgumentNullException(nameof(signalChecker)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); } /// #pragma warning disable CA1502 // TODO: Decomplexify #pragma warning disable CA1506 - public async Task RunAsync(bool runConfigure, string[] args, CancellationToken cancellationToken) + public async Task RunAsync(bool runConfigure, string[] args, CancellationToken cancellationToken) { logger.LogInformation("Host watchdog starting..."); int currentProcessId; @@ -52,7 +59,7 @@ namespace Tgstation.Server.Host.Watchdog if (dotnetPath == default) { logger.LogCritical("Unable to locate dotnet executable in PATH! Please ensure the .NET Core runtime is installed and is in your PATH!"); - return; + return false; } logger.LogInformation("Detected dotnet executable at {dotnetPath}", dotnetPath); @@ -93,13 +100,13 @@ namespace Tgstation.Server.Host.Watchdog if (assemblyPath.Contains("\"")) { logger.LogCritical("Running from paths with \"'s in the name is not supported!"); - return; + return false; } if (!File.Exists(assemblyPath)) { logger.LogCritical("Unable to locate host assembly!"); - return; + return false; } var watchdogVersion = executingAssembly.GetName().Version.ToString(); @@ -148,8 +155,15 @@ namespace Tgstation.Server.Host.Watchdog var killedHostProcess = false; try { - process.Start(); - var childPid = process.Id; + var processTask = tcs.Task; + (int, Task) StartProcess(string additionalArg) + { + if (additionalArg != null) + process.StartInfo.Arguments += $" {additionalArg}"; + + process.Start(); + return (process.Id, processTask); + } using (var processCts = new CancellationTokenSource()) using (processCts.Token.Register(() => tcs.TrySetResult(null))) @@ -176,12 +190,9 @@ namespace Tgstation.Server.Host.Watchdog } })) { - var processTask = tcs.Task; using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - var checkerTask = isWindows - ? Task.CompletedTask - : SignalChecker.CheckSignals(logger, childPid, cts.Token); + var checkerTask = signalChecker.CheckSignals(StartProcess, cts.Token); try { await processTask; @@ -228,14 +239,14 @@ namespace Tgstation.Server.Host.Watchdog if (runConfigure) { - logger.LogInformation("Exiting due to configuration check..."); - return; + logger.LogInformation("Exiting due to configure intent..."); + return true; } switch ((HostExitCode)process.ExitCode) { case HostExitCode.CompleteExecution: - return; + return true; case HostExitCode.RestartRequested: if (!cancellationToken.IsCancellationRequested) logger.LogInformation("Watchdog will restart host..."); // just a restart @@ -331,11 +342,14 @@ namespace Tgstation.Server.Host.Watchdog catch (Exception ex) { logger.LogCritical(ex, "Host watchdog error!"); + return false; } finally { logger.LogInformation("Host watchdog exiting..."); } + + return true; } #pragma warning restore CA1502 #pragma warning restore CA1506 diff --git a/src/Tgstation.Server.Host.Watchdog/WatchdogFactory.cs b/src/Tgstation.Server.Host.Watchdog/WatchdogFactory.cs index 083d89eafb..4b2fc89147 100644 --- a/src/Tgstation.Server.Host.Watchdog/WatchdogFactory.cs +++ b/src/Tgstation.Server.Host.Watchdog/WatchdogFactory.cs @@ -8,6 +8,10 @@ namespace Tgstation.Server.Host.Watchdog public sealed class WatchdogFactory : IWatchdogFactory { /// - public IWatchdog CreateWatchdog(ILoggerFactory loggerFactory) => new Watchdog(loggerFactory?.CreateLogger() ?? throw new ArgumentNullException(nameof(loggerFactory))); + public IWatchdog CreateWatchdog( + ISignalChecker signalChecker, + ILoggerFactory loggerFactory) => new Watchdog( + signalChecker ?? throw new ArgumentNullException(nameof(signalChecker)), + loggerFactory?.CreateLogger() ?? throw new ArgumentNullException(nameof(loggerFactory))); } } diff --git a/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs b/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs new file mode 100644 index 0000000000..81bc785e16 --- /dev/null +++ b/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs @@ -0,0 +1,18 @@ +namespace Tgstation.Server.Host.Configuration +{ + /// + /// Unstable configuration options used internally by TGS. + /// + public sealed class InternalConfiguration + { + /// + /// The key for the the resides in. + /// + public const string Section = "Internal"; + + /// + /// The name of the pipe opened by the host watchdog, if any. + /// + public string CommandPipe { get; set; } + } +} diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index ef312928a0..efd9da1238 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -132,6 +132,7 @@ namespace Tgstation.Server.Host.Core services.UseStandardConfig(Configuration); services.UseStandardConfig(Configuration); services.UseStandardConfig(Configuration); + services.UseStandardConfig(Configuration); // enable options which give us config reloading services.AddOptions(); @@ -335,10 +336,8 @@ namespace Tgstation.Server.Host.Core services.AddSingleton(x => new Lazy(() => x.GetRequiredService(), true)); services.AddSingleton(); - services.AddSingleton(); - - services.AddSingleton(); - services.AddSingleton(x => x.GetRequiredService()); + services.AddHostedService(); + services.AddHostedService(); } // configure file transfer services @@ -368,10 +367,11 @@ namespace Tgstation.Server.Host.Core // configure misc services services.AddSingleton(); services.AddSingleton(); - services.AddFileDownloader(); services.AddSingleton(); services.AddSingleton(); + services.AddHostedService(); + services.AddFileDownloader(); services.AddGitHub(); // configure root services diff --git a/src/Tgstation.Server.Host/Core/CommandPipeReader.cs b/src/Tgstation.Server.Host/Core/CommandPipeReader.cs new file mode 100644 index 0000000000..a1afa80cbe --- /dev/null +++ b/src/Tgstation.Server.Host/Core/CommandPipeReader.cs @@ -0,0 +1,109 @@ +using System; +using System.IO; +using System.IO.Pipes; +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +using Tgstation.Server.Host.Common; +using Tgstation.Server.Host.Configuration; +using Tgstation.Server.Host.Extensions; + +namespace Tgstation.Server.Host.Core +{ + /// + /// Reads from the command pipe opened by the host watchdog. + /// + sealed class CommandPipeReader : BackgroundService + { + /// + /// The for the . + /// + readonly IServerControl serverControl; + + /// + /// The for the . + /// + readonly ILogger logger; + + /// + /// The for the . + /// + readonly InternalConfiguration internalConfiguration; + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The containing the value of . + /// The value of . + public CommandPipeReader( + IServerControl serverControl, + IOptions internalConfigurationOptions, + ILogger logger) + { + this.serverControl = serverControl ?? throw new ArgumentNullException(nameof(serverControl)); + internalConfiguration = internalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(internalConfigurationOptions)); + this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + + /// + protected override async Task ExecuteAsync(CancellationToken cancellationToken) + { + logger.LogTrace("Starting..."); + + var pipeName = internalConfiguration.CommandPipe; + if (string.IsNullOrWhiteSpace(pipeName)) + { + logger.LogDebug("No command pipe name specified in configuration"); + return; + } + + try + { + await using var pipeClient = new AnonymousPipeClientStream(PipeDirection.In, pipeName); + using var streamReader = new StreamReader(pipeClient, leaveOpen: true); + while (!cancellationToken.IsCancellationRequested) + { + logger.LogTrace("Waiting to read command line..."); + var line = await streamReader.ReadLineAsync().WithToken(cancellationToken); + + logger?.LogInformation("Received pipe command: {command}", line); + switch (line) + { + case PipeCommands.CommandStop: + await serverControl.Die(null); + break; + case PipeCommands.CommandGracefulShutdown: + await serverControl.GracefulShutdown(false); + break; + case PipeCommands.CommandDetachingShutdown: + await serverControl.GracefulShutdown(true); + break; + case null: + logger.LogDebug("Read null from pipe"); + return; + default: + logger?.LogWarning("Unrecognized pipe command: {command}", line); + break; + } + } + } + catch (OperationCanceledException ex) + { + logger?.LogTrace(ex, "Command read task cancelled!"); + } + catch (Exception ex) + { + logger?.LogError(ex, "Command read task errored!"); + } + finally + { + logger?.LogTrace("Command read task exiting..."); + } + } + } +} diff --git a/src/Tgstation.Server.Host/Server.cs b/src/Tgstation.Server.Host/Server.cs index 1a42d25b40..b76891e3ec 100644 --- a/src/Tgstation.Server.Host/Server.cs +++ b/src/Tgstation.Server.Host/Server.cs @@ -114,8 +114,12 @@ namespace Tgstation.Server.Host using (cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) using (var fsWatcher = updatePath != null ? new FileSystemWatcher(Path.GetDirectoryName(updatePath)) : null) { - if (fsWatcher != null) + if (updatePath != null) { + // If ever there is a NECESSARY update to the Host Watchdog, change this to use a pipe + // I don't know why I'm only realizing this in 2023 when this is 2019 code + // As it stands, FSWatchers use async I/O on Windows and block a new thread on Linux + // That's an acceptable, if saddening, resource loss for now fsWatcher.Created += WatchForShutdownFileCreation; fsWatcher.EnableRaisingEvents = true; } @@ -241,7 +245,14 @@ namespace Tgstation.Server.Host public Task GracefulShutdown(bool detach) => RestartImpl(null, null, false, detach); /// - public Task Die(Exception exception) => RestartImpl(null, exception, false, true); + public Task Die(Exception exception) + { + if (exception != null) + return RestartImpl(null, exception, false, true); + + StopServerImmediate(); + return Task.CompletedTask; + } /// /// Throws an if the cannot be used. @@ -377,7 +388,7 @@ namespace Tgstation.Server.Host void StopServerImmediate() { shutdownInProgress = true; - logger.LogTrace("Stopping host..."); + logger.LogDebug("Stopping host..."); cancellationTokenSource.Cancel(); } } diff --git a/tests/Tgstation.Server.Host.Console.Tests/TestProgram.cs b/tests/Tgstation.Server.Host.Console.Tests/TestProgram.cs index edb19af15e..0fc337843c 100644 --- a/tests/Tgstation.Server.Host.Console.Tests/TestProgram.cs +++ b/tests/Tgstation.Server.Host.Console.Tests/TestProgram.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using System; @@ -17,9 +17,9 @@ namespace Tgstation.Server.Host.Console.Tests { var mockServer = new Mock(); var args = Array.Empty(); - mockServer.Setup(x => x.RunAsync(false, args, It.IsAny())).Returns(Task.CompletedTask).Verifiable(); + mockServer.Setup(x => x.RunAsync(false, args, It.IsAny())).Returns(Task.FromResult(true)).Verifiable(); var mockServerFactory = new Mock(); - mockServerFactory.Setup(x => x.CreateWatchdog(It.IsAny())).Returns(mockServer.Object).Verifiable(); + mockServerFactory.Setup(x => x.CreateWatchdog(It.IsNotNull(), It.IsNotNull())).Returns(mockServer.Object).Verifiable(); Program.WatchdogFactory = mockServerFactory.Object; await Program.Main(args); mockServer.VerifyAll(); diff --git a/tests/Tgstation.Server.Host.Service.Tests/TestServerService.cs b/tests/Tgstation.Server.Host.Service.Tests/TestServerService.cs index 03846f15a6..13fb19381e 100644 --- a/tests/Tgstation.Server.Host.Service.Tests/TestServerService.cs +++ b/tests/Tgstation.Server.Host.Service.Tests/TestServerService.cs @@ -34,9 +34,9 @@ namespace Tgstation.Server.Host.Service.Tests var mockWatchdog = new Mock(); var args = Array.Empty(); CancellationToken cancellationToken; - mockWatchdog.Setup(x => x.RunAsync(false, args, It.IsAny())).Callback((bool x, string[] _, CancellationToken token) => cancellationToken = token).Returns(Task.CompletedTask).Verifiable(); + mockWatchdog.Setup(x => x.RunAsync(false, args, It.IsAny())).Callback((bool x, string[] _, CancellationToken token) => cancellationToken = token).Returns(Task.FromResult(true)).Verifiable(); var mockWatchdogFactory = new Mock(); - mockWatchdogFactory.Setup(x => x.CreateWatchdog(It.IsNotNull())).Returns(mockWatchdog.Object).Verifiable(); + mockWatchdogFactory.Setup(x => x.CreateWatchdog(It.IsNotNull(), It.IsNotNull())).Returns(mockWatchdog.Object).Verifiable(); using (var service = new ServerService(mockWatchdogFactory.Object, default)) { diff --git a/tests/Tgstation.Server.Host.Watchdog.Tests/TestWatchdog.cs b/tests/Tgstation.Server.Host.Watchdog.Tests/TestWatchdog.cs index 67c3eb9289..0ba2e31764 100644 --- a/tests/Tgstation.Server.Host.Watchdog.Tests/TestWatchdog.cs +++ b/tests/Tgstation.Server.Host.Watchdog.Tests/TestWatchdog.cs @@ -13,9 +13,11 @@ namespace Tgstation.Server.Host.Watchdog.Tests [TestMethod] public void TestConstruction() { - Assert.ThrowsException(() => new Watchdog(null)); - var mockLogger = new LoggerFactory().CreateLogger(); - var wd = new Watchdog(mockLogger); + Assert.ThrowsException(() => new Watchdog(null, null)); + var mockSignalChecker = Mock.Of(); + Assert.ThrowsException(() => new Watchdog(mockSignalChecker, null)); + var mockLogger = Mock.Of>(); + var wd = new Watchdog(mockSignalChecker, mockLogger); } } } diff --git a/tests/Tgstation.Server.Host.Watchdog.Tests/TestWatchdogFactory.cs b/tests/Tgstation.Server.Host.Watchdog.Tests/TestWatchdogFactory.cs index afc5f24c62..f3bededdba 100644 --- a/tests/Tgstation.Server.Host.Watchdog.Tests/TestWatchdogFactory.cs +++ b/tests/Tgstation.Server.Host.Watchdog.Tests/TestWatchdogFactory.cs @@ -1,6 +1,8 @@ using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + namespace Tgstation.Server.Host.Watchdog.Tests { /// @@ -13,7 +15,10 @@ namespace Tgstation.Server.Host.Watchdog.Tests public void TestCreateWatchdog() { var factory = new WatchdogFactory(); - Assert.IsNotNull(factory.CreateWatchdog(new LoggerFactory())); + Assert.IsNotNull( + factory.CreateWatchdog( + Mock.Of(), + Mock.Of())); } } } From 7fcc1e820817499d24ed78a4cc8a4bbea0f92c84 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 19:13:28 -0400 Subject: [PATCH 028/160] Fix .vdproj ProductCode and ProductVersion Also change installation folder name to just `tgstation-server` --- .../Tgstation.Server.Host.Service.Msi.vdproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj index 73255a2210..001385aba2 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj @@ -249,7 +249,7 @@ } "{3C67513D-01DD-4637-8A68-80971EB9504F}:_B28C4FD80D0245E08AEDCFEECACB6493" { - "DefaultLocation" = "8:[ProgramFilesFolder][Manufacturer]\\[ProductName]" + "DefaultLocation" = "8:[ProgramFilesFolder][ProductName]" "Name" = "8:#1925" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" @@ -320,7 +320,7 @@ { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:tgstation-server" - "ProductCode" = "8:{879A86CB-D12C-4D31-9386-0D5CE8C53FC4}" + "ProductCode" = "8:{D24887FA-3228-4509-B5F3-4E07E349F278}" "PackageCode" = "8:{D078B8A7-E5C3-48EE-85B0-56C355FCBB43}" "UpgradeCode" = "8:{151FE9F8-72CF-48D5-8E55-B7FB6BA9693E}" "AspNetVersion" = "8:4.0.30319.0" @@ -328,7 +328,7 @@ "RemovePreviousVersions" = "11:TRUE" "DetectNewerInstalledVersion" = "11:TRUE" "InstallAllUsers" = "11:TRUE" - "ProductVersion" = "8:5.12.6" + "ProductVersion" = "8:0.22.475" "Manufacturer" = "8:tgstation" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:" From f7a52c98ff9bcb467dbeb72b8308a7fcb8eea796 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 19:13:58 -0400 Subject: [PATCH 029/160] Fix BYOND installer creating BYOND directory in Windows service installation --- .../Components/Byond/ByondManager.cs | 51 +++++++++++-------- .../Components/Byond/WindowsByondInstaller.cs | 6 ++- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs b/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs index da057c1ead..664ffb4a02 100644 --- a/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs +++ b/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs @@ -302,26 +302,28 @@ namespace Tgstation.Server.Host.Components.Byond var activeVersionBytesTask = GetActiveVersion(); - using (await SemaphoreSlimContext.Lock(UserFilesSemaphore, cancellationToken)) - { - // Create local cfg directory in case it doesn't exist - var localCfgDirectory = ioManager.ConcatPath( - byondInstaller.PathToUserByondFolder, - CfgDirectoryName); - await ioManager.CreateDirectory( - localCfgDirectory, - cancellationToken); - - // Delete trusted.txt so it doesn't grow too large - var trustedFilePath = - ioManager.ConcatPath( + var byondDir = byondInstaller.PathToUserByondFolder; + if (byondDir != null) + using (await SemaphoreSlimContext.Lock(UserFilesSemaphore, cancellationToken)) + { + // Create local cfg directory in case it doesn't exist + var localCfgDirectory = ioManager.ConcatPath( + byondDir, + CfgDirectoryName); + await ioManager.CreateDirectory( localCfgDirectory, - TrustedDmbFileName); - logger.LogTrace("Deleting trusted .dmbs file {trustedFilePath}", trustedFilePath); - await ioManager.DeleteFile( - trustedFilePath, - cancellationToken); - } + cancellationToken); + + // Delete trusted.txt so it doesn't grow too large + var trustedFilePath = + ioManager.ConcatPath( + localCfgDirectory, + TrustedDmbFileName); + logger.LogTrace("Deleting trusted .dmbs file {trustedFilePath}", trustedFilePath); + await ioManager.DeleteFile( + trustedFilePath, + cancellationToken); + } await ioManager.CreateDirectory(DefaultIOManager.CurrentDirectory, cancellationToken); var directories = await ioManager.GetDirectories(DefaultIOManager.CurrentDirectory, cancellationToken); @@ -616,8 +618,15 @@ namespace Tgstation.Server.Host.Components.Byond /// A representing the running operation. async Task TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken) { + var byondDir = byondInstaller.PathToUserByondFolder; + if (String.IsNullOrWhiteSpace(byondDir)) + { + logger.LogTrace("No relevant user BYOND directory to install a \"{fileName}\" in", TrustedDmbFileName); + return; + } + var trustedFilePath = ioManager.ConcatPath( - byondInstaller.PathToUserByondFolder, + byondDir, CfgDirectoryName, TrustedDmbFileName); @@ -633,9 +642,7 @@ namespace Tgstation.Server.Host.Components.Byond trustedFileText = $"{trustedFileText.Trim()}{Environment.NewLine}"; } else - { trustedFileText = String.Empty; - } if (trustedFileText.Contains(fullDmbPath, StringComparison.Ordinal)) return; diff --git a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs index 3bd1e64db1..91f9412a34 100644 --- a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs @@ -94,7 +94,11 @@ namespace Tgstation.Server.Host.Components.Byond this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); - PathToUserByondFolder = IOManager.ResolvePath(IOManager.ConcatPath(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "BYOND")); + var documentsDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + if (String.IsNullOrWhiteSpace(documentsDirectory)) + PathToUserByondFolder = null; // happens with the service account + else + PathToUserByondFolder = IOManager.ResolvePath(IOManager.ConcatPath(documentsDirectory, "BYOND")); semaphore = new SemaphoreSlim(1); installedDirectX = false; From 3be3d81a795e272266e9137f007715baabea67ca Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 19:20:24 -0400 Subject: [PATCH 030/160] Remove the need for DesignTime config --- .../Configuration/DatabaseConfiguration.cs | 5 ----- .../DesignTimeDbContextFactoryHelpers.cs | 1 - .../Design/SqliteDesignTimeDbContextFactory.cs | 4 ++-- .../Database/SqliteDatabaseContext.cs | 18 ++++++++++++------ 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Tgstation.Server.Host/Configuration/DatabaseConfiguration.cs b/src/Tgstation.Server.Host/Configuration/DatabaseConfiguration.cs index e076bc03cb..d5adce7577 100644 --- a/src/Tgstation.Server.Host/Configuration/DatabaseConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/DatabaseConfiguration.cs @@ -34,11 +34,6 @@ namespace Tgstation.Server.Host.Configuration /// public bool DropDatabase { get; set; } - /// - /// Used to indicate that the database is being loaded to generate migrations. Should not be used in production!. - /// - public bool DesignTime { get; set; } - /// /// The form of the of the target server. /// diff --git a/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs b/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs index a0569aafe3..54d79bddc3 100644 --- a/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs +++ b/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs @@ -26,7 +26,6 @@ namespace Tgstation.Server.Host.Database.Design { var dbConfig = new DatabaseConfiguration { - DesignTime = true, DatabaseType = databaseType, ConnectionString = connectionString, ServerVersion = serverVersion, diff --git a/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs index b855f8ad9c..924d8934f9 100644 --- a/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs +++ b/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs @@ -12,11 +12,11 @@ namespace Tgstation.Server.Host.Database.Design /// public SqliteDatabaseContext CreateDbContext(string[] args) { - SqliteDatabaseContext.DesignTime = true; return new SqliteDatabaseContext( DesignTimeDbContextFactoryHelpers.CreateDatabaseContextOptions( DatabaseType.Sqlite, - "Data Source=tgs_design.sqlite3;Mode=ReadWriteCreate")); + "Data Source=tgs_design.sqlite3;Mode=ReadWriteCreate"), + true); } } } diff --git a/src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs b/src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs index 0076efe2c2..c13ebf2027 100644 --- a/src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs @@ -14,16 +14,21 @@ namespace Tgstation.Server.Host.Database sealed class SqliteDatabaseContext : DatabaseContext { /// - /// Static property to receive the configured value of . + /// If the database context is running in design time mode. /// - public static bool DesignTime { get; set; } + readonly bool designTime; /// /// Initializes a new instance of the class. /// /// The for the . - public SqliteDatabaseContext(DbContextOptions dbContextOptions) : base(dbContextOptions) + /// The value of . + public SqliteDatabaseContext( + DbContextOptions dbContextOptions, + bool designTime = false) + : base(dbContextOptions) { + this.designTime = designTime; } /// @@ -31,7 +36,9 @@ namespace Tgstation.Server.Host.Database /// /// The to configure. /// The . - public static void ConfigureWith(DbContextOptionsBuilder options, DatabaseConfiguration databaseConfiguration) + public static void ConfigureWith( + DbContextOptionsBuilder options, + DatabaseConfiguration databaseConfiguration) { ArgumentNullException.ThrowIfNull(options); ArgumentNullException.ThrowIfNull(databaseConfiguration); @@ -39,7 +46,6 @@ namespace Tgstation.Server.Host.Database if (databaseConfiguration.DatabaseType != DatabaseType.Sqlite) throw new InvalidOperationException($"Invalid DatabaseType for {nameof(SqliteDatabaseContext)}!"); - DesignTime = databaseConfiguration.DesignTime; options.UseSqlite(databaseConfiguration.ConnectionString, sqliteOptions => sqliteOptions.UseQuerySplittingBehavior(QuerySplittingBehavior.SingleQuery)); } @@ -56,7 +62,7 @@ namespace Tgstation.Server.Host.Database // use the DateTimeOffsetToBinaryConverter // Based on: https://github.com/aspnet/EntityFrameworkCore/issues/10784#issuecomment-415769754 // This only supports millisecond precision, but should be sufficient for most use cases. - if (!DesignTime) + if (!designTime) foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { var properties = entityType From 96d65d1f2003111b13a5c88b83cb81ba5427ecb5 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 19:21:04 -0400 Subject: [PATCH 031/160] Do not inject `IGitHubService`, require factory --- .../Controllers/AdministrationController.cs | 11 ++++++----- src/Tgstation.Server.Host/Core/ServerUpdater.cs | 11 ++++++----- .../Extensions/ServiceCollectionExtensions.cs | 1 - .../Utils/GitHub/GitHubClientFactory.cs | 1 - 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/AdministrationController.cs b/src/Tgstation.Server.Host/Controllers/AdministrationController.cs index 104f1736b9..636aa182a2 100644 --- a/src/Tgstation.Server.Host/Controllers/AdministrationController.cs +++ b/src/Tgstation.Server.Host/Controllers/AdministrationController.cs @@ -41,9 +41,9 @@ namespace Tgstation.Server.Host.Controllers const string OctokitException = "Bad GitHub API response, check configuration!"; /// - /// The for the . + /// The for the . /// - readonly IGitHubService gitHubService; + readonly IGitHubServiceFactory gitHubServiceFactory; /// /// The for the . @@ -85,7 +85,7 @@ namespace Tgstation.Server.Host.Controllers /// /// The for the . /// The for the . - /// The value of . + /// The value of . /// The value of . /// The value of . /// The value of . @@ -97,7 +97,7 @@ namespace Tgstation.Server.Host.Controllers public AdministrationController( IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, - IGitHubService gitHubService, + IGitHubServiceFactory gitHubServiceFactory, IServerControl serverControl, IServerUpdateInitiator serverUpdateInitiator, IAssemblyInformationProvider assemblyInformationProvider, @@ -112,7 +112,7 @@ namespace Tgstation.Server.Host.Controllers logger, true) { - this.gitHubService = gitHubService ?? throw new ArgumentNullException(nameof(gitHubService)); + this.gitHubServiceFactory = gitHubServiceFactory ?? throw new ArgumentNullException(nameof(gitHubServiceFactory)); this.serverControl = serverControl ?? throw new ArgumentNullException(nameof(serverControl)); this.serverUpdateInitiator = serverUpdateInitiator ?? throw new ArgumentNullException(nameof(serverUpdateInitiator)); this.assemblyInformationProvider = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider)); @@ -143,6 +143,7 @@ namespace Tgstation.Server.Host.Controllers Uri repoUrl = null; try { + var gitHubService = gitHubServiceFactory.CreateService(); var repositoryUrlTask = gitHubService.GetUpdatesRepositoryUrl(cancellationToken); var releases = await gitHubService.GetTgsReleases(cancellationToken); diff --git a/src/Tgstation.Server.Host/Core/ServerUpdater.cs b/src/Tgstation.Server.Host/Core/ServerUpdater.cs index d04386a9b6..570b613b70 100644 --- a/src/Tgstation.Server.Host/Core/ServerUpdater.cs +++ b/src/Tgstation.Server.Host/Core/ServerUpdater.cs @@ -17,9 +17,9 @@ namespace Tgstation.Server.Host.Core sealed class ServerUpdater : IServerUpdater, IServerUpdateExecutor { /// - /// The for the . + /// The for the . /// - readonly IGitHubService gitHubService; + readonly IGitHubServiceFactory gitHubServiceFactory; /// /// The for the . @@ -64,7 +64,7 @@ namespace Tgstation.Server.Host.Core /// /// Initializes a new instance of the class. /// - /// The value of . + /// The value of . /// The value of . /// The value of . /// The value of . @@ -72,7 +72,7 @@ namespace Tgstation.Server.Host.Core /// The containing the value of . /// The containing the value of . public ServerUpdater( - IGitHubService gitHubService, + IGitHubServiceFactory gitHubServiceFactory, IIOManager ioManager, IFileDownloader fileDownloader, IServerControl serverControl, @@ -80,7 +80,7 @@ namespace Tgstation.Server.Host.Core IOptions generalConfigurationOptions, IOptions updatesConfigurationOptions) { - this.gitHubService = gitHubService ?? throw new ArgumentNullException(nameof(gitHubService)); + this.gitHubServiceFactory = gitHubServiceFactory ?? throw new ArgumentNullException(nameof(gitHubServiceFactory)); this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader)); this.serverControl = serverControl ?? throw new ArgumentNullException(nameof(serverControl)); @@ -288,6 +288,7 @@ namespace Tgstation.Server.Host.Core { logger.LogDebug("Looking for GitHub releases version {version}...", newVersion); + var gitHubService = gitHubServiceFactory.CreateService(); var releases = await gitHubService.GetTgsReleases(cancellationToken); foreach (var kvp in releases) { diff --git a/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs b/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs index d3f70f6a28..b894c78639 100644 --- a/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs @@ -105,7 +105,6 @@ namespace Tgstation.Server.Host.Extensions serviceCollection.AddSingleton(); serviceCollection.AddSingleton(typeof(IGitHubServiceFactory), gitHubServiceFactoryType); - serviceCollection.AddSingleton(x => x.GetRequiredService().CreateService()); return serviceCollection; } diff --git a/src/Tgstation.Server.Host/Utils/GitHub/GitHubClientFactory.cs b/src/Tgstation.Server.Host/Utils/GitHub/GitHubClientFactory.cs index 5fbd22f2de..2e9abee967 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/GitHubClientFactory.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/GitHubClientFactory.cs @@ -96,7 +96,6 @@ namespace Tgstation.Server.Host.Utils.GitHub var now = DateTimeOffset.UtcNow; if (!cacheHit) { - logger.LogTrace("Creating new GitHubClient..."); client = new GitHubClient( new ProductHeaderValue( assemblyInformationProvider.ProductInfoHeaderValue.Product.Name, From 13d9a92abb2f9c2adce0f2d0bc67beb9ab5aa5a5 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 19:28:11 -0400 Subject: [PATCH 032/160] Run configure app as winforms to be non-intrusive --- .../Program.cs | 22 +++++-------------- ...ation.Server.Host.Service.Configure.csproj | 4 +++- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs b/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs index 9d5c5bb53b..bf8710aa15 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs +++ b/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Reflection; using System.Security.AccessControl; using System.Threading; +using System.Windows.Forms; using var process = new Process(); @@ -44,22 +45,18 @@ var uninstall = args var shortcut = uiLevel == 42069; -bool startService; +bool restartService; if (shortcut) { - Console.WriteLine(); - Console.WriteLine("This program will configure tgstation-server. Would you like to restart the service after doing so?"); - Console.Write("A restart is required to apply changes. It will not kill your DreamDaemon instances provided you are running a version >=5.13.0 (Y/n): "); - var keyInfo = Console.ReadKey(); - startService = keyInfo.Key == ConsoleKey.Enter || keyInfo.Key == ConsoleKey.Y; - Console.WriteLine(); + var result = MessageBox.Show($"This program will configure tgstation-server. Would you like to restart the service after doing so?{Environment.NewLine}{Environment.NewLine}A restart is required to apply changes. It will not kill your DreamDaemon instances provided you are running a version >=5.13.0 (Always true if you've never downgraded)", "Restart TGS After Configuring?", MessageBoxButtons.YesNo); + restartService = result == DialogResult.Yes; } else - startService = interactive; + restartService = interactive; process.StartInfo.Arguments = uninstall ? "-u" - : $"-i -f -x{(startService ? " -r" : String.Empty)}{((interactive || shortcut) ? " -c" : String.Empty)}{(silent ? " -s" : String.Empty)}"; + : $"-i -f -x{(restartService ? " -r" : String.Empty)}{((interactive || shortcut) ? " -c" : String.Empty)}{(silent ? " -s" : String.Empty)}"; process.Start(); @@ -91,12 +88,5 @@ if ((shortcut || (interactive && !uninstall)) && process.ExitCode == 0) fileInfo.SetAccessControl(fs); } -if (shortcut) -{ - Console.WriteLine("Press any key to exit this program..."); - Console.ReadKey(); - Console.WriteLine(); -} - // returning non-zero can make the installation uninstallable, no thanks return uninstall ? 0 : process.ExitCode; diff --git a/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj b/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj index e0c822ad1b..af4c4af760 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj @@ -1,8 +1,9 @@ - Exe + WinExe net6.0-windows + true enable ../../../uac_elevation_manifest.xml ../../../tgs.ico @@ -11,4 +12,5 @@ + From 5e80f0259fd5f409f9d201737779560338884d4c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 19:32:20 -0400 Subject: [PATCH 033/160] Fix the implementation of `-r` in service project --- src/Tgstation.Server.Host.Service/Program.cs | 51 +++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/src/Tgstation.Server.Host.Service/Program.cs b/src/Tgstation.Server.Host.Service/Program.cs index f2f78bc9a8..0ff0dda89c 100644 --- a/src/Tgstation.Server.Host.Service/Program.cs +++ b/src/Tgstation.Server.Host.Service/Program.cs @@ -45,10 +45,10 @@ namespace Tgstation.Server.Host.Service public bool Detach { get; } /// - /// The --resume or -r option. + /// The --restart or -r option. /// [Option(ShortName = "r")] - public bool Resume { get; } + public bool Restart { get; } /// /// The --install or -i option. @@ -145,7 +145,9 @@ namespace Tgstation.Server.Host.Service if (Configure) await RunConfigure(CancellationToken.None); // DCT: None available + bool stopped = false; if (Uninstall) + { using (var installer = new ServiceInstaller()) { installer.Context = new InstallContext("tgs-uninstall.log", null); @@ -156,21 +158,25 @@ namespace Tgstation.Server.Host.Service installer.Uninstall(null); } - if (Install) - { - RunServiceInstall(); + stopped = true; } + if (Install) + stopped |= RunServiceInstall(); + if (standardRun) { using var service = new ServerService(WatchdogFactory, Trace ? LogLevel.Trace : Debug ? LogLevel.Debug : LogLevel.Information); ServiceBase.Run(service); } - if (Resume) + if (Restart) foreach (ServiceController sc in ServiceController.GetServices()) if (sc.ServiceName == ServerService.Name) { + if (!stopped) + RestartService(sc); + sc.Start(); break; } @@ -195,18 +201,7 @@ namespace Tgstation.Server.Host.Service return false; // is this needed after exit? // Stop it first to give it some cleanup time - if (sc.Status == ServiceControllerStatus.Running) - { - if (Detach) - sc.ExecuteCommand( - ServerService.GetCommand( - PipeCommands.CommandDetachingShutdown) - .Value); - else - sc.Stop(); - - sc.WaitForStatus(ServiceControllerStatus.Stopped); - } + RestartService(sc); // And remove it using var serviceInstaller = new ServiceInstaller(); @@ -241,6 +236,26 @@ namespace Tgstation.Server.Host.Service return serviceStopped; } + /// + /// Restarts a service using a given . + /// + /// The for the service to restart. + void RestartService(ServiceController serviceController) + { + if (serviceController.Status != ServiceControllerStatus.Running) + return; + + if (Detach) + serviceController.ExecuteCommand( + ServerService.GetCommand( + PipeCommands.CommandDetachingShutdown) + .Value); + else + serviceController.Stop(); + + serviceController.WaitForStatus(ServiceControllerStatus.Stopped); + } + /// /// Runs the host application with the setup wizard. /// From 3d17597ddc2de76013a6acd5b8581ce973c2c26d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 19:33:34 -0400 Subject: [PATCH 034/160] We should now be implicitly upgradable in `winget` --- build/package/winget/manifest/Tgstation.Server.installer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package/winget/manifest/Tgstation.Server.installer.yaml b/build/package/winget/manifest/Tgstation.Server.installer.yaml index 8b35539915..5c9afee773 100644 --- a/build/package/winget/manifest/Tgstation.Server.installer.yaml +++ b/build/package/winget/manifest/Tgstation.Server.installer.yaml @@ -14,7 +14,7 @@ Installers: - interactive - silent ProductCode: '{D24887FA-3228-4509-B5F3-4E07E349F278}' - RequireExplicitUpgrade: true + RequireExplicitUpgrade: false UnsupportedOSArchitectures: - arm - arm64 From 1da9370a44649e36b3524b70d706c67c51c8c8ec Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 19:52:13 -0400 Subject: [PATCH 035/160] Use SystemD journal if file logging is disabled --- build/tgstation-server.service | 4 +- .../Configuration/InternalConfiguration.cs | 5 +++ src/Tgstation.Server.Host/Core/Application.cs | 18 +++++++- .../Extensions/ServiceCollectionExtensions.cs | 43 ++++++++----------- .../Setup/IPostSetupServices.cs | 5 +++ .../Setup/PostSetupServices.cs | 15 ++++++- .../Setup/SetupApplication.cs | 1 + 7 files changed, 59 insertions(+), 32 deletions(-) diff --git a/build/tgstation-server.service b/build/tgstation-server.service index 837d8fb21f..b09873cc99 100644 --- a/build/tgstation-server.service +++ b/build/tgstation-server.service @@ -10,15 +10,13 @@ After=mssql-server.service Type=notify-reload NotifyAccess=all WorkingDirectory=/opt/tgstation-server -ExecStart=/usr/bin/dotnet Tgstation.Server.Host.Console.dll --General:SetupWizardMode=Never +ExecStart=/usr/bin/dotnet Tgstation.Server.Host.Console.dll --General:SetupWizardMode=Never --Internal:UsingSystemD=true TimeoutStartSec=600 Restart=Always KillMode=process ReloadSignal=SIGUSR2 RestartKillSignal=SIGUSR2 AmbientCapabilities=CAP_SYS_NICE -StandardOutput=null -StandardError=null WatchdogSec=60 WatchdogSignal=SIGTERM diff --git a/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs b/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs index 81bc785e16..d97c8a501c 100644 --- a/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs @@ -14,5 +14,10 @@ /// The name of the pipe opened by the host watchdog, if any. /// public string CommandPipe { get; set; } + + /// + /// If the server is running under SystemD. + /// + public bool UsingSystemD { get; set; } } } diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index efd9da1238..34fba6906e 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -6,6 +6,8 @@ using System.Linq; using Cyberboss.AspNetCore.AsyncInitializer; +using Elastic.CommonSchema.Serilog; + using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors.Infrastructure; @@ -23,6 +25,7 @@ using Newtonsoft.Json; using Serilog; using Serilog.Events; using Serilog.Formatting.Display; +using Serilog.Sinks.Elasticsearch; using Tgstation.Server.Api; using Tgstation.Server.Common.Http; @@ -132,7 +135,6 @@ namespace Tgstation.Server.Host.Core services.UseStandardConfig(Configuration); services.UseStandardConfig(Configuration); services.UseStandardConfig(Configuration); - services.UseStandardConfig(Configuration); // enable options which give us config reloading services.AddOptions(); @@ -155,6 +157,7 @@ namespace Tgstation.Server.Host.Core }; var microsoftEventLevel = ConvertSeriLogLevel(postSetupServices.FileLoggingConfiguration.MicrosoftLogLevel); + var elasticsearchConfiguration = postSetupServices.ElasticsearchConfiguration; services.SetupLogging( config => { @@ -192,7 +195,18 @@ namespace Tgstation.Server.Host.Core rollingInterval: RollingInterval.Day, rollOnFileSizeLimit: true); }, - postSetupServices.ElasticsearchConfiguration); + elasticsearchConfiguration.Enable + ? new ElasticsearchSinkOptions(new Uri(elasticsearchConfiguration.Host ?? throw new InvalidOperationException())) + { + // Yes I know this means they cannot use a self signed cert unless they also have authentication, but lets be real here + // No one is going to be doing one of thsoe but not the other + ModifyConnectionSettings = connectionConfigration => (!string.IsNullOrEmpty(elasticsearchConfiguration.Username) && !string.IsNullOrEmpty(elasticsearchConfiguration.Password)) ? connectionConfigration.BasicAuthentication(elasticsearchConfiguration.Username, elasticsearchConfiguration.Password).ServerCertificateValidationCallback((o, certificate, arg3, arg4) => { return true; }) : null, + CustomFormatter = new EcsTextFormatter(), + AutoRegisterTemplate = true, + AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv7, + IndexFormat = "tgs-logs", + } + : null); // configure bearer token validation services diff --git a/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs b/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs index b894c78639..f11e54c0b0 100644 --- a/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs @@ -2,7 +2,6 @@ using System.Diagnostics; using System.Globalization; -using Elastic.CommonSchema.Serilog; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -110,7 +109,7 @@ namespace Tgstation.Server.Host.Extensions } /// - /// Add an additional to s that call . + /// Add an additional to s that call . /// /// The of to add. public static void UseAdditionalLoggerProvider() where TLoggerProvider : class, ILoggerProvider @@ -164,14 +163,22 @@ namespace Tgstation.Server.Host.Extensions /// The to configure. /// Additional configuration for a given . /// Additional configuration for a given . - /// Configuration for a given . + /// The to use, if any. + /// The active , if any. + /// The active , if any. Must be set if is passed in. /// The updated . public static IServiceCollection SetupLogging( this IServiceCollection serviceCollection, Action configurationAction, Action sinkConfigurationAction = null, - ElasticsearchConfiguration elasticsearchConfiguration = null) - => serviceCollection.AddLogging(builder => + ElasticsearchSinkOptions elasticsearchSinkOptions = null, + InternalConfiguration internalConfiguration = null, + FileLoggingConfiguration fileLoggingConfiguration = null) + { + if (internalConfiguration != null) + ArgumentNullException.ThrowIfNull(fileLoggingConfiguration); + + return serviceCollection.AddLogging(builder => { builder.ClearProviders(); @@ -189,29 +196,14 @@ namespace Tgstation.Server.Host.Extensions var template = "[{Timestamp:HH:mm:ss}] {Level:w3}: {SourceContext:l} (" + SerilogContextHelper.Template + "){NewLine} {Message:lj}{NewLine}{Exception}"; - sinkConfiguration.Console(outputTemplate: template, formatProvider: CultureInfo.InvariantCulture); + + if (!((internalConfiguration?.UsingSystemD ?? false) && fileLoggingConfiguration.Disable)) + sinkConfiguration.Console(outputTemplate: template, formatProvider: CultureInfo.InvariantCulture); sinkConfigurationAction?.Invoke(sinkConfiguration); }); - if (elasticsearchConfiguration != null) - { - if (elasticsearchConfiguration.Enable) - { - if (elasticsearchConfiguration.Host == null) - throw new InvalidOperationException("Elasticsearch endpoint is null!"); - - configuration.WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri(elasticsearchConfiguration.Host)) - { - // Yes I know this means they cannot use a self signed cert unless they also have authentication, but lets be real here - // No one is going to be doing one of thsoe but not the other - ModifyConnectionSettings = x => (!string.IsNullOrEmpty(elasticsearchConfiguration.Username) && !string.IsNullOrEmpty(elasticsearchConfiguration.Password)) ? x.BasicAuthentication(elasticsearchConfiguration.Username, elasticsearchConfiguration.Password).ServerCertificateValidationCallback((o, certificate, arg3, arg4) => { return true; }) : null, - CustomFormatter = new EcsTextFormatter(), - AutoRegisterTemplate = true, - AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv7, - IndexFormat = "tgs-logs", - }); - } - } + if (elasticsearchSinkOptions != null) + configuration.WriteTo.Elasticsearch(elasticsearchSinkOptions); builder.AddSerilog(configuration.CreateLogger(), true); @@ -221,6 +213,7 @@ namespace Tgstation.Server.Host.Extensions if (additionalLoggerProvider != null) builder.Services.TryAddEnumerable(additionalLoggerProvider); }); + } /// /// Set the modifiable services to their default types. diff --git a/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs b/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs index 8f4e161179..21264d9277 100644 --- a/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs +++ b/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs @@ -33,6 +33,11 @@ namespace Tgstation.Server.Host.Setup /// ElasticsearchConfiguration ElasticsearchConfiguration { get; } + /// + /// The . + /// + InternalConfiguration InternalConfiguration { get; } + /// /// The . /// diff --git a/src/Tgstation.Server.Host/Setup/PostSetupServices.cs b/src/Tgstation.Server.Host/Setup/PostSetupServices.cs index 808b2030d9..c1ace340ec 100644 --- a/src/Tgstation.Server.Host/Setup/PostSetupServices.cs +++ b/src/Tgstation.Server.Host/Setup/PostSetupServices.cs @@ -14,6 +14,9 @@ namespace Tgstation.Server.Host.Setup /// public IPlatformIdentifier PlatformIdentifier { get; } + /// + public ILogger Logger { get; } + /// public GeneralConfiguration GeneralConfiguration => generalConfigurationOptions.Value; @@ -27,7 +30,7 @@ namespace Tgstation.Server.Host.Setup public FileLoggingConfiguration FileLoggingConfiguration => fileLoggingConfigurationOptions.Value; /// - public ILogger Logger { get; } + public InternalConfiguration InternalConfiguration => internalConfigurationOptions.Value; /// public ElasticsearchConfiguration ElasticsearchConfiguration => elasticsearchConfigurationOptions.Value; @@ -57,6 +60,11 @@ namespace Tgstation.Server.Host.Setup /// readonly IOptions elasticsearchConfigurationOptions; + /// + /// Backing for . + /// + readonly IOptions internalConfigurationOptions; + /// /// Initializes a new instance of the class. /// @@ -67,6 +75,7 @@ namespace Tgstation.Server.Host.Setup /// The containing the value of . /// The containing the value of . /// The containing the value of . + /// The containing the value of . public PostSetupServices( IPlatformIdentifier platformIdentifier, ILoggerFactory loggerFactory, @@ -74,7 +83,8 @@ namespace Tgstation.Server.Host.Setup IOptions databaseConfigurationOptions, IOptions securityConfigurationOptions, IOptions fileLoggingConfigurationOptions, - IOptions elasticsearchConfigurationOptions) + IOptions elasticsearchConfigurationOptions, + IOptions internalConfigurationOptions) { PlatformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); ArgumentNullException.ThrowIfNull(loggerFactory); @@ -85,6 +95,7 @@ namespace Tgstation.Server.Host.Setup this.securityConfigurationOptions = securityConfigurationOptions ?? throw new ArgumentNullException(nameof(securityConfigurationOptions)); this.fileLoggingConfigurationOptions = fileLoggingConfigurationOptions ?? throw new ArgumentNullException(nameof(fileLoggingConfigurationOptions)); this.elasticsearchConfigurationOptions = elasticsearchConfigurationOptions ?? throw new ArgumentNullException(nameof(elasticsearchConfigurationOptions)); + this.internalConfigurationOptions = internalConfigurationOptions ?? throw new ArgumentNullException(nameof(internalConfigurationOptions)); } } } diff --git a/src/Tgstation.Server.Host/Setup/SetupApplication.cs b/src/Tgstation.Server.Host/Setup/SetupApplication.cs index 4c85e43a60..56c590ce7d 100644 --- a/src/Tgstation.Server.Host/Setup/SetupApplication.cs +++ b/src/Tgstation.Server.Host/Setup/SetupApplication.cs @@ -61,6 +61,7 @@ namespace Tgstation.Server.Host.Setup services.UseStandardConfig(Configuration); services.UseStandardConfig(Configuration); services.UseStandardConfig(Configuration); + services.UseStandardConfig(Configuration); ConfigureHostedService(services); } From 141a944bf0ec585563e40657b68f23ba010bc74c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 19:54:50 -0400 Subject: [PATCH 036/160] Remove unnecessary .sln build dependency --- tgstation-server.sln | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tgstation-server.sln b/tgstation-server.sln index 7dac32ea6d..2002e30885 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -30,7 +30,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{6FF654E6 build\coverlet.runsettings = build\coverlet.runsettings build\Dockerfile = build\Dockerfile build\GenerateMigrations.sh = build\GenerateMigrations.sh - build\uac_elevation_manifest.xml = build\uac_elevation_manifest.xml build\NugetCommon.props = build\NugetCommon.props build\OpenApiValidationSettings.json = build\OpenApiValidationSettings.json build\stylecop.json = build\stylecop.json @@ -38,6 +37,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{6FF654E6 build\tgs.ico = build\tgs.ico build\tgs.png = build\tgs.png build\tgstation-server.service = build\tgstation-server.service + build\uac_elevation_manifest.xml = build\uac_elevation_manifest.xml build\Version.props = build\Version.props EndProjectSection EndProject @@ -240,9 +240,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "winget", "winget", "{506B90 EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Service.Configure", "build\package\winget\Tgstation.Server.Host.Service.Configure\Tgstation.Server.Host.Service.Configure.csproj", "{6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}" - ProjectSection(ProjectDependencies) = postProject - {29927416-3B78-49A7-A560-5CCAA638B6B4} = {29927416-3B78-49A7-A560-5CCAA638B6B4} - EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "manifest", "manifest", "{3F141E03-6ABB-46A8-AA24-1B4B6814E58F}" ProjectSection(SolutionItems) = preProject From 7940d301d3dced007c18f017fd5ccdc163ba1cb4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 20:03:41 -0400 Subject: [PATCH 037/160] Fix service closing pipe after sending command --- src/Tgstation.Server.Host.Service/ServerService.cs | 14 +++++++++++++- .../Core/CommandPipeReader.cs | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host.Service/ServerService.cs b/src/Tgstation.Server.Host.Service/ServerService.cs index b5a7434c68..c615bc592c 100644 --- a/src/Tgstation.Server.Host.Service/ServerService.cs +++ b/src/Tgstation.Server.Host.Service/ServerService.cs @@ -2,7 +2,9 @@ using System.Diagnostics; using System.IO; using System.IO.Pipes; +using System.Linq; using System.ServiceProcess; +using System.Text; using System.Threading; using System.Threading.Tasks; @@ -203,7 +205,17 @@ namespace Tgstation.Server.Host.Service logger.LogDebug("Send command: {command}", command); try { - using var streamWriter = new StreamWriter(localPipeServer); + var encoding = Encoding.UTF8; + using var streamWriter = new StreamWriter( + localPipeServer, + encoding, + PipeCommands + .AllCommands + .Select( + command => encoding.GetByteCount( + command + Environment.NewLine)) + .Max(), + true); streamWriter.WriteLine(command); } catch (Exception ex) diff --git a/src/Tgstation.Server.Host/Core/CommandPipeReader.cs b/src/Tgstation.Server.Host/Core/CommandPipeReader.cs index a1afa80cbe..073f5a1e42 100644 --- a/src/Tgstation.Server.Host/Core/CommandPipeReader.cs +++ b/src/Tgstation.Server.Host/Core/CommandPipeReader.cs @@ -84,7 +84,7 @@ namespace Tgstation.Server.Host.Core await serverControl.GracefulShutdown(true); break; case null: - logger.LogDebug("Read null from pipe"); + logger.LogError("Read null from pipe!"); return; default: logger?.LogWarning("Unrecognized pipe command: {command}", line); From 12e71119c5d822c640412647005320532df82414 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 20:13:03 -0400 Subject: [PATCH 038/160] Add missing restore to packaging script --- build/package/winget/build_package.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/package/winget/build_package.ps1 b/build/package/winget/build_package.ps1 index 3ded22efd0..be603b1de6 100644 --- a/build/package/winget/build_package.ps1 +++ b/build/package/winget/build_package.ps1 @@ -10,6 +10,8 @@ git worktree add -f packaging $currentCommit cd packaging Remove-Item -Recurse -Force .git +dotnet restore + [XML]$versionXML = Get-Content build/Version.props $tgsVersion = $versionXML.Project.PropertyGroup.TgsCoreVersion From 3861d2db8d2585e940335a38db9743f816829fcd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 20:59:34 -0400 Subject: [PATCH 039/160] Disallow msi upgrades See https://stackoverflow.com/a/14736573 Also set some additional .vdproj fields --- .../Tgstation.Server.Host.Service.Msi.vdproj | 10 +++++----- build/package/winget/build_package.ps1 | 2 -- .../winget/manifest/Tgstation.Server.installer.yaml | 3 ++- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj index 001385aba2..e0c4b6f0c0 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj @@ -331,15 +331,15 @@ "ProductVersion" = "8:0.22.475" "Manufacturer" = "8:tgstation" "ARPHELPTELEPHONE" = "8:" - "ARPHELPLINK" = "8:" - "Title" = "8:Tgstation.Server.Host.Service.Msi" + "ARPHELPLINK" = "8:https://github.com/tgstation/tgstation-server/discussions/categories/q-a" + "Title" = "8:tgstation-server" "Subject" = "8:" "ARPCONTACT" = "8:Dominon/Cyberboss" "Keywords" = "8:" "ARPCOMMENTS" = "8:Installer for tgstation-server" - "ARPURLINFOABOUT" = "8:https://tgstation13.org" - "ARPPRODUCTICON" = "8:" - "ARPIconIndex" = "3:0" + "ARPURLINFOABOUT" = "8:https://github.com/tgstation/tgstation-server" + "ARPPRODUCTICON" = "8:_E9F7402DCE77463F9B7319647D3C16F2" + "ARPIconIndex" = "3:32512" "SearchPath" = "8:" "UseSystemSearchPath" = "11:TRUE" "TargetPlatform" = "3:0" diff --git a/build/package/winget/build_package.ps1 b/build/package/winget/build_package.ps1 index be603b1de6..891ffbab4b 100644 --- a/build/package/winget/build_package.ps1 +++ b/build/package/winget/build_package.ps1 @@ -17,11 +17,9 @@ $tgsVersion = $versionXML.Project.PropertyGroup.TgsCoreVersion cd build/package/winget -$devProductCode = 'D24887FA-3228-4509-B5F3-4E07E349F278' $devVersion = '0.22.475' (Get-Content Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj).Replace($devVersion, $tgsVersion) | Set-Content Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj -(Get-Content Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj).Replace($devProductCode, [guid]::NewGuid().ToString().ToUpperInvariant()) | Set-Content Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj # We make _some_ assumptions DevEnv installer.sln /Project Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj /build Release diff --git a/build/package/winget/manifest/Tgstation.Server.installer.yaml b/build/package/winget/manifest/Tgstation.Server.installer.yaml index 5c9afee773..68b4a1457d 100644 --- a/build/package/winget/manifest/Tgstation.Server.installer.yaml +++ b/build/package/winget/manifest/Tgstation.Server.installer.yaml @@ -14,7 +14,8 @@ Installers: - interactive - silent ProductCode: '{D24887FA-3228-4509-B5F3-4E07E349F278}' - RequireExplicitUpgrade: false + RequireExplicitUpgrade: true + UpgradeBehavior: uninstallPrevious UnsupportedOSArchitectures: - arm - arm64 From 52fdaf3955fe9dce0da80371630c5be09be4582d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 21:32:10 -0400 Subject: [PATCH 040/160] Add sane defaults to SetupWizard yes/no prompts --- .../Setup/SetupWizard.cs | 75 ++++++++++++++----- .../Setup/TestSetupWizard.cs | 6 +- 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index 15f2b82e48..775cbe98e0 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -5,6 +5,7 @@ using System.Data.SqlClient; using System.Globalization; using System.IO; using System.Linq; +using System.Net; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -141,19 +142,29 @@ namespace Tgstation.Server.Host.Setup /// A prompt for a yes or no value. /// /// The question . + /// The optional default response if the user doesn't enter anything. /// The for the operation. /// A resulting in if the user replied yes, otherwise. - async Task PromptYesNo(string question, CancellationToken cancellationToken) + async Task PromptYesNo(string question, bool? defaultResponse, CancellationToken cancellationToken) { do { - await console.WriteAsync(question, false, cancellationToken); + await console.WriteAsync($"{question} ({(defaultResponse == true ? 'Y' : 'y')}/{(defaultResponse == false ? 'N' : 'n')}): ", false, cancellationToken); var responseString = await console.ReadLineAsync(false, cancellationToken); - var upperResponse = responseString.ToUpperInvariant(); - if (upperResponse == "Y" || upperResponse == "YES") - return true; - else if (upperResponse == "N" || upperResponse == "NO") - return false; + if (responseString.Length == 0) + { + if (defaultResponse.HasValue) + return defaultResponse.Value; + } + else + { + var upperResponse = responseString.ToUpperInvariant(); + if (upperResponse == "Y" || upperResponse == "YES") + return true; + else if (upperResponse == "N" || upperResponse == "NO") + return false; + } + await console.WriteAsync("Invalid response!", true, cancellationToken); } while (true); @@ -316,7 +327,8 @@ namespace Tgstation.Server.Host.Setup await console.WriteAsync("Note, this relative path (currently) resolves to the following:", true, cancellationToken); await console.WriteAsync(resolvedPath, true, cancellationToken); bool writeResolved = await PromptYesNo( - "Would you like to save the relative path in the configuration? If not, the full path will be saved. (y/n): ", + "Would you like to save the relative path in the configuration? If not, the full path will be saved.", + null, cancellationToken); if (writeResolved) @@ -405,6 +417,7 @@ namespace Tgstation.Server.Host.Setup ushort? serverPort = null; bool isSqliteDB = databaseConfiguration.DatabaseType == DatabaseType.Sqlite; + IPHostEntry serverAddressEntry = null; if (!isSqliteDB) do { @@ -430,7 +443,20 @@ namespace Tgstation.Server.Host.Setup } } - break; + try + { + if (serverAddress != null) + { + await console.WriteAsync("Attempting to resolve address...", true, cancellationToken); + serverAddressEntry = await Dns.GetHostEntryAsync(serverAddress, cancellationToken); + } + + break; + } + catch (Exception ex) + { + await console.WriteAsync($"Unable to resolve address: {ex.Message}", true, cancellationToken); + } } while (true); @@ -451,7 +477,10 @@ namespace Tgstation.Server.Host.Setup databaseName = await ValidateNonExistantSqliteDBName(databaseName, cancellationToken); } else - dbExists = await PromptYesNo("Does this database already exist? If not, we will attempt to CREATE it. (y/n): ", cancellationToken); + dbExists = await PromptYesNo( + "Does this database already exist? If not, we will attempt to CREATE it.", + null, + cancellationToken); } if (String.IsNullOrWhiteSpace(databaseName)) @@ -463,7 +492,12 @@ namespace Tgstation.Server.Host.Setup bool useWinAuth; if (databaseConfiguration.DatabaseType == DatabaseType.SqlServer && platformIdentifier.IsWindows) - useWinAuth = await PromptYesNo("Use Windows Authentication? (y/n): ", cancellationToken); + { + var defaultResponse = serverAddressEntry.AddressList.Any(IPAddress.IsLoopback) + ? (bool?)true + : null; + useWinAuth = await PromptYesNo("Use Windows Authentication?", defaultResponse, cancellationToken); + } else useWinAuth = false; @@ -648,7 +682,7 @@ namespace Tgstation.Server.Host.Setup if (String.IsNullOrWhiteSpace(newGeneralConfiguration.GitHubAccessToken)) newGeneralConfiguration.GitHubAccessToken = null; - newGeneralConfiguration.HostApiDocumentation = await PromptYesNo("Host API Documentation? (y/n): ", cancellationToken); + newGeneralConfiguration.HostApiDocumentation = await PromptYesNo("Host API Documentation?", false, cancellationToken); return newGeneralConfiguration; } @@ -662,7 +696,7 @@ namespace Tgstation.Server.Host.Setup { var fileLoggingConfiguration = new FileLoggingConfiguration(); await console.WriteAsync(null, true, cancellationToken); - fileLoggingConfiguration.Disable = !await PromptYesNo("Enable file logging? (y/n): ", cancellationToken); + fileLoggingConfiguration.Disable = !await PromptYesNo("Enable file logging?", true, cancellationToken); if (!fileLoggingConfiguration.Disable) { @@ -747,7 +781,7 @@ namespace Tgstation.Server.Host.Setup { var elasticsearchConfiguration = new ElasticsearchConfiguration(); await console.WriteAsync(null, true, cancellationToken); - elasticsearchConfiguration.Enable = await PromptYesNo("Enable logging to an external ElasticSearch server? (y/n): ", cancellationToken); + elasticsearchConfiguration.Enable = await PromptYesNo("Enable logging to an external ElasticSearch server?", false, cancellationToken); if (elasticsearchConfiguration.Enable) { @@ -797,8 +831,11 @@ namespace Tgstation.Server.Host.Setup { var config = new ControlPanelConfiguration { - Enable = await PromptYesNo("Enable the web control panel? (y/n): ", cancellationToken), - AllowAnyOrigin = await PromptYesNo("Allow web control panels hosted elsewhere to access the server? (Access-Control-Allow-Origin: *) (y/n): ", cancellationToken), + Enable = await PromptYesNo("Enable the web control panel?", true, cancellationToken), + AllowAnyOrigin = await PromptYesNo( + "Allow web control panels hosted elsewhere to access the server? (Access-Control-Allow-Origin: *)", + true, + cancellationToken), }; if (!config.AllowAnyOrigin) @@ -822,7 +859,7 @@ namespace Tgstation.Server.Host.Setup /// A resulting in the new . async Task ConfigureSwarm(CancellationToken cancellationToken) { - var enable = await PromptYesNo("Enable swarm mode? (y/n): ", cancellationToken); + var enable = await PromptYesNo("Enable swarm mode?", false, cancellationToken); if (!enable) return null; @@ -860,7 +897,7 @@ namespace Tgstation.Server.Host.Setup } while (String.IsNullOrWhiteSpace(privateKey)); - var controller = await PromptYesNo("Is this server the swarm's controller? (y/n): ", cancellationToken); + var controller = await PromptYesNo("Is this server the swarm's controller? (y/n): ", null, cancellationToken); Uri controllerAddress = null; if (!controller) controllerAddress = await ParseAddress("Enter the swarm controller's HTTP(S) address: "); @@ -1065,7 +1102,7 @@ namespace Tgstation.Server.Host.Setup { await console.WriteAsync(String.Format(CultureInfo.InvariantCulture, "The configuration settings are requesting the setup wizard be run, but you already appear to have a configuration file ({0})!", userConfigFileName), true, cancellationToken); - forceRun = await PromptYesNo("Continue running setup wizard? (y/n): ", cancellationToken); + forceRun = await PromptYesNo("Continue running setup wizard?", false, cancellationToken); } if (!forceRun) diff --git a/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs b/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs index 841f97bfd1..8edbf59c70 100644 --- a/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs +++ b/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs @@ -152,14 +152,14 @@ namespace Tgstation.Server.Host.Setup.Tests "666", "FakeDBType", nameof(DatabaseType.SqlServer), - "this isn't validated", + "localhost", "nor is this", "no", //test winauth "yes", //sql server will always fail so reconfigure with maria nameof(DatabaseType.MariaDB), - "bleh", + "127.0.0.1", "blah", "NO", "user", @@ -187,7 +187,7 @@ namespace Tgstation.Server.Host.Setup.Tests String.Empty, //test MySQL errors nameof(DatabaseType.MySql), - String.Empty, + "::1", String.Empty, "DbName", "n", From d869c60f7c2e3e5a8095eab5861e8637812fd532 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 21:40:38 -0400 Subject: [PATCH 041/160] Configure project in main solution breaks CodeQL Removes it --- tgstation-server.sln | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/tgstation-server.sln b/tgstation-server.sln index 2002e30885..010e08c860 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -239,8 +239,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "winget", "winget", "{506B90 build\package\winget\install_banner.jpg = build\package\winget\install_banner.jpg EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Service.Configure", "build\package\winget\Tgstation.Server.Host.Service.Configure\Tgstation.Server.Host.Service.Configure.csproj", "{6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "manifest", "manifest", "{3F141E03-6ABB-46A8-AA24-1B4B6814E58F}" ProjectSection(SolutionItems) = preProject build\package\winget\manifest\Tgstation.Server.installer.yaml = build\package\winget\manifest\Tgstation.Server.installer.yaml @@ -254,6 +252,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tgstation.Server.Host.Servi build\package\winget\Tgstation.Server.Host.Service.Msi\Tgstation.Server.Host.Service.Msi.vdproj = build\package\winget\Tgstation.Server.Host.Service.Msi\Tgstation.Server.Host.Service.Msi.vdproj EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tgstation.Server.Host.Service.Configure", "Tgstation.Server.Host.Service.Configure", "{5DDA72D5-DBFD-4FB2-9EAB-61D047145246}" + ProjectSection(SolutionItems) = preProject + build\package\winget\Tgstation.Server.Host.Service.Configure\Program.cs = build\package\winget\Tgstation.Server.Host.Service.Configure\Program.cs + build\package\winget\Tgstation.Server.Host.Service.Configure\Tgstation.Server.Host.Service.Configure.csproj = build\package\winget\Tgstation.Server.Host.Service.Configure\Tgstation.Server.Host.Service.Configure.csproj + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -410,14 +414,6 @@ Global {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Release|Any CPU.Build.0 = Release|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU - {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.DebugNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.DebugNoFramework|Any CPU.Build.0 = Release|Any CPU - {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Release|Any CPU.Build.0 = Release|Any CPU - {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -451,9 +447,9 @@ Global {08E7C650-A447-4DE2-974E-ED123B50F8D6} = {457A1F89-6201-4430-BCC6-2F4438A54B9E} {B4B5570C-8071-46DE-BB55-64C13480C606} = {08E7C650-A447-4DE2-974E-ED123B50F8D6} {506B9092-AF88-4DA2-84FD-C11646B695B0} = {2648A85F-61AE-428E-95E1-66D06C7A3768} - {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315} = {506B9092-AF88-4DA2-84FD-C11646B695B0} {3F141E03-6ABB-46A8-AA24-1B4B6814E58F} = {506B9092-AF88-4DA2-84FD-C11646B695B0} {F5B9D394-229B-44A1-AD12-D8C078F06814} = {506B9092-AF88-4DA2-84FD-C11646B695B0} + {5DDA72D5-DBFD-4FB2-9EAB-61D047145246} = {506B9092-AF88-4DA2-84FD-C11646B695B0} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DFD36C95-3E49-41C7-ACDB-86BAF5B18A79} From b0c8917b620111092f0a7f94ad4c08e9c3a87918 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 21:41:41 -0400 Subject: [PATCH 042/160] Rename .vdproj CI build step --- .github/workflows/ci-suite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 7caec6d41a..f9058ad09c 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -968,7 +968,7 @@ jobs: with: ref: "refs/pull/${{ github.event.number }}/merge" - - name: Build .vdproj + - name: Execute Build Script shell: powershell run: build/package/winget/build_package.ps1 From 337258d3dcf0419b0d3487489b9e9a81b1c2d48c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 22:20:13 -0400 Subject: [PATCH 043/160] Fix .deb installation command --- .github/workflows/ci-suite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index f9058ad09c..6b3e620209 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -922,7 +922,7 @@ jobs: run: | sudo dpkg --add-architecture i386 sudo apt-get update - sudo apt-get install -y tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb + sudo apt-get install -y ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb systemctl status tgstation-server sudo ls -al /etc/tgstation-server sudo cat /etc/tgstation-server/appsettings.Production.yml From e0e9d9bce1094658f0ac00f7b252a42fc8c5664b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 22:39:57 -0400 Subject: [PATCH 044/160] Fix SystemD log suppression --- src/Tgstation.Server.Host/Core/Application.cs | 8 ++++++-- .../Extensions/ServiceCollectionExtensions.cs | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 34fba6906e..793c2e474d 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -206,7 +206,9 @@ namespace Tgstation.Server.Host.Core AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv7, IndexFormat = "tgs-logs", } - : null); + : null, + postSetupServices.InternalConfiguration, + postSetupServices.FileLoggingConfiguration); // configure bearer token validation services @@ -351,9 +353,11 @@ namespace Tgstation.Server.Host.Core services.AddSingleton(); services.AddHostedService(); - services.AddHostedService(); } + if (postSetupServices.InternalConfiguration.UsingSystemD) + services.AddHostedService(); + // configure file transfer services services.AddSingleton(); services.AddSingleton(x => x.GetRequiredService()); diff --git a/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs b/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs index f11e54c0b0..5acfd9abb3 100644 --- a/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs @@ -197,7 +197,7 @@ namespace Tgstation.Server.Host.Extensions + SerilogContextHelper.Template + "){NewLine} {Message:lj}{NewLine}{Exception}"; - if (!((internalConfiguration?.UsingSystemD ?? false) && fileLoggingConfiguration.Disable)) + if (!((internalConfiguration?.UsingSystemD ?? false) && !fileLoggingConfiguration.Disable)) sinkConfiguration.Console(outputTemplate: template, formatProvider: CultureInfo.InvariantCulture); sinkConfigurationAction?.Invoke(sinkConfiguration); }); From 2a3a72a1e74bc63b23355cb0b35ca20de04939b8 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 22:57:42 -0400 Subject: [PATCH 045/160] Convert to `BackgroundService` where applicable Also fix case of localhost SqlServer in SetupWizard --- .../Setup/SetupWizard.cs | 9 ++-- .../System/SystemDManager.cs | 51 +++---------------- .../System/WindowsNetworkPromptReaper.cs | 43 ++-------------- .../Setup/TestSetupWizard.cs | 21 +++++--- 4 files changed, 28 insertions(+), 96 deletions(-) diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index 775cbe98e0..f5e4deb0f8 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -32,7 +32,7 @@ using YamlDotNet.Serialization; namespace Tgstation.Server.Host.Setup { /// - sealed class SetupWizard : IHostedService + sealed class SetupWizard : BackgroundService { /// /// The for the . @@ -129,15 +129,12 @@ namespace Tgstation.Server.Host.Setup } /// - public async Task StartAsync(CancellationToken cancellationToken) + protected override async Task ExecuteAsync(CancellationToken cancellationToken) { await CheckRunWizard(cancellationToken); applicationLifetime.StopApplication(); } - /// - public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; - /// /// A prompt for a yes or no value. /// @@ -493,7 +490,7 @@ namespace Tgstation.Server.Host.Setup bool useWinAuth; if (databaseConfiguration.DatabaseType == DatabaseType.SqlServer && platformIdentifier.IsWindows) { - var defaultResponse = serverAddressEntry.AddressList.Any(IPAddress.IsLoopback) + var defaultResponse = serverAddressEntry?.AddressList.Any(IPAddress.IsLoopback) ?? false ? (bool?)true : null; useWinAuth = await PromptYesNo("Use Windows Authentication?", defaultResponse, cancellationToken); diff --git a/src/Tgstation.Server.Host/System/SystemDManager.cs b/src/Tgstation.Server.Host/System/SystemDManager.cs index 99f4ade686..9ce09a1387 100644 --- a/src/Tgstation.Server.Host/System/SystemDManager.cs +++ b/src/Tgstation.Server.Host/System/SystemDManager.cs @@ -17,7 +17,7 @@ namespace Tgstation.Server.Host.System /// /// Implements the SystemD notify service protocol. /// - sealed class SystemDManager : IHostedService, IRestartHandler, IDisposable + sealed class SystemDManager : BackgroundService, IRestartHandler, IDisposable { /// /// The sd_notify command for notifying the watchdog we are alive. @@ -44,16 +44,6 @@ namespace Tgstation.Server.Host.System /// readonly ILogger logger; - /// - /// The for . - /// - readonly CancellationTokenSource watchdogCts; - - /// - /// The main task executing in the . - /// - Task runTask; - /// /// If TGS is going to restart. /// @@ -87,22 +77,13 @@ namespace Tgstation.Server.Host.System this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); restartRegistration = serverControl.RegisterForRestart(this); - try - { - watchdogCts = new CancellationTokenSource(); - } - catch - { - restartRegistration.Dispose(); - throw; - } } /// - public void Dispose() + public override void Dispose() { + base.Dispose(); restartRegistration.Dispose(); - watchdogCts.Dispose(); } /// @@ -114,36 +95,16 @@ namespace Tgstation.Server.Host.System } /// - public Task StartAsync(CancellationToken cancellationToken) + protected override async Task ExecuteAsync(CancellationToken cancellationToken) { if (SendSDNotify(SDNotifyWatchdog)) - { - logger.LogDebug("SystemD detected"); - runTask = RunAsync(watchdogCts.Token); - } - else { logger.LogDebug("SystemD not detected"); - runTask = Task.CompletedTask; + return; } - return Task.CompletedTask; - } + logger.LogDebug("SystemD detected"); - /// - public async Task StopAsync(CancellationToken cancellationToken) - { - watchdogCts.Cancel(); - await runTask.WithToken(cancellationToken); - } - - /// - /// Runs the . - /// - /// The for the operation. - /// A representing the running operation. - async Task RunAsync(CancellationToken cancellationToken) - { if (applicationLifetime.ApplicationStarted.IsCancellationRequested) throw new InvalidOperationException("RunAsync called after application started!"); diff --git a/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs b/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs index ce0fa3a88b..6578457672 100644 --- a/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs +++ b/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs @@ -16,7 +16,7 @@ using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Host.System { /// - sealed class WindowsNetworkPromptReaper : IHostedService, INetworkPromptReaper, IDisposable + sealed class WindowsNetworkPromptReaper : BackgroundService, INetworkPromptReaper { /// /// Number of times to send the button click message. Should be at least 2 or it may fail to focus the window. @@ -38,21 +38,11 @@ namespace Tgstation.Server.Host.System /// readonly ILogger logger; - /// - /// The for the . - /// - readonly CancellationTokenSource cancellationTokenSource; - /// /// The list of s registered. /// readonly List registeredProcesses; - /// - /// The representing the lifetime of the . - /// - Task runTask; - /// /// Callback for . /// @@ -106,26 +96,6 @@ namespace Tgstation.Server.Host.System this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); registeredProcesses = new List(); - cancellationTokenSource = new CancellationTokenSource(); - } - - /// - public void Dispose() => cancellationTokenSource.Dispose(); - - /// - public Task StartAsync(CancellationToken cancellationToken) - { - runTask = Run(cancellationTokenSource.Token); - return Task.CompletedTask; - } - - /// - public async Task StopAsync(CancellationToken cancellationToken) - { - logger.LogTrace("Stopping network prompt reaper..."); - cancellationTokenSource.Cancel(); - await runTask; - registeredProcesses.Clear(); } /// @@ -150,12 +120,8 @@ namespace Tgstation.Server.Host.System }, TaskScheduler.Current); } - /// - /// Main loop for the . - /// - /// The for the operation. - /// A representing the running operation. - async Task Run(CancellationToken cancellationToken) + /// + protected override async Task ExecuteAsync(CancellationToken cancellationToken) { logger.LogDebug("Starting network prompt reaper..."); try @@ -221,7 +187,8 @@ namespace Tgstation.Server.Host.System } finally { - logger.LogDebug("Exiting network prompt reaper..."); + registeredProcesses.Clear(); + logger.LogTrace("Exiting network prompt reaper..."); } } } diff --git a/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs b/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs index 8edbf59c70..4ee9dfd632 100644 --- a/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs +++ b/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs @@ -91,13 +91,13 @@ namespace Tgstation.Server.Host.Setup.Tests mockPlatformIdentifier.SetupGet(x => x.IsWindows).Returns(true).Verifiable(); mockAsyncDelayer.Setup(x => x.Delay(It.IsAny(), It.IsAny())).Returns(Task.CompletedTask).Verifiable(); - await wizard.StartAsync(default); + await RunWizard(); testGeneralConfig.SetupWizardMode = SetupWizardMode.Force; - await Assert.ThrowsExceptionAsync(() => wizard.StartAsync(default)); + await Assert.ThrowsExceptionAsync(() => RunWizard()); testGeneralConfig.SetupWizardMode = SetupWizardMode.Only; - await Assert.ThrowsExceptionAsync(() => wizard.StartAsync(default)); + await Assert.ThrowsExceptionAsync(() => RunWizard()); mockConsole.SetupGet(x => x.Available).Returns(true).Verifiable(); mockIOManager.Setup(x => x.FileExists(It.IsNotNull(), It.IsAny())).Returns(Task.FromResult(true)).Verifiable(); @@ -279,13 +279,20 @@ namespace Tgstation.Server.Host.Setup.Tests .Returns(Task.CompletedTask) .Verifiable(); - await wizard.StartAsync(default); + async Task RunWizard() + { + await wizard.StartAsync(default); + await wizard.ExecuteTask; + await wizard.StopAsync(default); + } + + await RunWizard(); //first real run - await wizard.StartAsync(default); + await RunWizard(); //second run mockIOManager.Setup(x => x.ReadAllBytes(It.IsNotNull(), It.IsAny())).Returns(Task.FromResult(Encoding.UTF8.GetBytes(String.Empty))).Verifiable(); - await wizard.StartAsync(default); + await RunWizard(); //third run testGeneralConfig.SetupWizardMode = SetupWizardMode.Autodetect; @@ -309,7 +316,7 @@ namespace Tgstation.Server.Host.Setup.Tests return Task.CompletedTask; }).Verifiable(); - await Assert.ThrowsExceptionAsync(() => wizard.StartAsync(default)); + await Assert.ThrowsExceptionAsync(() => RunWizard()); Assert.AreEqual(finalInputSequence.Count, inputPos); mockFailCommand.VerifyAll(); From 9301b504e2a5b1ea7d429f53be767a010106ba81 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 23:00:16 -0400 Subject: [PATCH 046/160] Fix paths in Windows CI test --- .github/workflows/ci-suite.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 6b3e620209..133fdaca01 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -975,15 +975,15 @@ jobs: - name: Test Install and Uninstall # Sanity checks the .deps.json exists, which the installation is broken without shell: powershell # If it's missing, I found that in elements were the problem run: | - $file = "packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi" - $log = "install.log" + $file = [System.IO.Path]::GetFullPath("packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi") + $log = [System.IO.Path]::GetFullPath("install.log") $procMain = Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru $procLog = Start-Process "powershell" "Get-Content -Path `"$log`" -Wait" -NoNewWindow -PassThru $procMain.WaitForExit() $procLog.Kill() Get-Content C:/Program Files (x86)/tgstation/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json Get-Service -Name tgstation-server -ErrorAction SilentlyContinue - $log = "uninstall.log" + $log = [System.IO.Path]::GetFullPath("uninstall.log") $procMain = Start-Process "msiexec" "/u `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru $procLog = Start-Process "powershell" "Get-Content -Path `"$log`" -Wait" -NoNewWindow -PassThru $procMain.WaitForExit() From 8a4328bb4eb748946893bbdb13222a6012c75813 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 23:02:59 -0400 Subject: [PATCH 047/160] Switch from `.WithToken` to `.WaitAsync` --- .../Components/Byond/ByondManager.cs | 4 +- .../Components/Chat/ChatManager.cs | 6 +-- .../Components/Chat/Providers/IrcProvider.cs | 4 +- .../Components/Chat/Providers/Provider.cs | 2 +- .../Components/Deployment/DreamMaker.cs | 4 +- .../Remote/GitLabRemoteDeploymentManager.cs | 4 +- .../Components/InstanceManager.cs | 2 +- .../Repository/GitLabRemoteFeatures.cs | 2 +- .../Components/Session/SessionController.cs | 2 +- .../Components/Watchdog/WatchdogBase.cs | 6 +-- src/Tgstation.Server.Host/Core/Application.cs | 2 +- .../Core/CommandPipeReader.cs | 2 +- .../Extensions/TaskExtensions.cs | 45 +------------------ src/Tgstation.Server.Host/IO/Console.cs | 2 +- .../IO/DefaultIOManager.cs | 2 +- src/Tgstation.Server.Host/Jobs/JobHandler.cs | 2 +- src/Tgstation.Server.Host/Jobs/JobService.cs | 4 +- .../Swarm/SwarmService.cs | 2 +- .../System/ProcessExecutor.cs | 2 +- .../System/SystemDManager.cs | 2 +- .../Transfer/FileTransferService.cs | 2 +- .../Transfer/FileUploadProvider.cs | 2 +- .../Utils/GitHub/GitHubService.cs | 20 ++++----- .../Program.cs | 6 +-- .../Live/DummyGitHubService.cs | 4 +- .../Live/Instance/WatchdogTest.cs | 2 +- .../Live/TestLiveServer.cs | 2 +- .../TestSystemInteraction.cs | 4 +- 28 files changed, 50 insertions(+), 93 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs b/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs index 664ffb4a02..6a70782af1 100644 --- a/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs +++ b/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs @@ -235,7 +235,7 @@ namespace Tgstation.Server.Host.Components.Byond await Task.WhenAny( containerTask, activeVersionUpdate) - .WithToken(cancellationToken); + .WaitAsync(cancellationToken); if (containerTask.IsCompleted) logger.LogTrace("All BYOND locks for {version} are gone", version); @@ -455,7 +455,7 @@ namespace Tgstation.Server.Host.Components.Byond if (neededForLock && !installation.InstallationTask.IsCompleted) logger.LogWarning("The required BYOND version ({version}) is not readily available! We will have to wait for it to install.", version); - await installation.InstallationTask.WithToken(cancellationToken); + await installation.InstallationTask.WaitAsync(cancellationToken); return installLock; } diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs index 91cfdcade9..b8038dfe5b 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs @@ -482,7 +482,7 @@ namespace Tgstation.Server.Host.Components.Chat if (waitingForInitialConnection) { logger.LogTrace("Waiting for initial chat bot connections before updating tracking contexts..."); - await initialProviderConnectionsTask.WithToken(cancellationToken); + await initialProviderConnectionsTask.WaitAsync(cancellationToken); } List tasks; @@ -932,7 +932,7 @@ namespace Tgstation.Server.Host.Components.Chat if (messageTasks.Count == 0) { logger.LogTrace("No providers active, pausing messsage monitoring..."); - await updatedTask.WithToken(cancellationToken); + await updatedTask.WaitAsync(cancellationToken); logger.LogTrace("Resuming message monitoring..."); continue; } @@ -1073,7 +1073,7 @@ namespace Tgstation.Server.Host.Components.Chat { var cancellationToken = handlerCts.Token; if (waitForConnections) - await initialProviderConnectionsTask.WithToken(cancellationToken); + await initialProviderConnectionsTask.WaitAsync(cancellationToken); await SendMessage( channelIdsFactory(), diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index 5e496dba40..30b1e86d88 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -377,7 +377,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current) - .WithToken(cancellationToken); + .WaitAsync(cancellationToken); cancellationToken.ThrowIfCancellationRequested(); @@ -584,7 +584,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers cancellationToken, TaskCreationOptions.None, TaskScheduler.Current) - .WithToken(cancellationToken); + .WaitAsync(cancellationToken); /// /// Run SASL authentication on . diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs index 1fad402354..6cc52173d9 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs @@ -149,7 +149,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers { while (true) { - await nextMessage.Task.WithToken(cancellationToken); + await nextMessage.Task.WaitAsync(cancellationToken); lock (messageQueue) if (messageQueue.Count > 0) { diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index 38ee725a01..611b03ec13 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -806,10 +806,10 @@ namespace Tgstation.Server.Host.Components.Deployment using (var provider = new TemporaryDmbProvider(ioManager.ResolvePath(job.DirectoryName.ToString()), String.Concat(job.DmeName, DmbExtension), job)) await using (var controller = await sessionControllerFactory.LaunchNew(provider, byondLock, launchParameters, true, cancellationToken)) { - var launchResult = await controller.LaunchResult.WithToken(cancellationToken); + var launchResult = await controller.LaunchResult.WaitAsync(cancellationToken); if (launchResult.StartupTime.HasValue) - await controller.Lifetime.WithToken(cancellationToken); + await controller.Lifetime.WaitAsync(cancellationToken); if (!controller.Lifetime.IsCompleted) await controller.DisposeAsync(); diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs index afce81718d..c1f90d5f12 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs @@ -59,7 +59,7 @@ namespace Tgstation.Server.Host.Components.Deployment.Remote .GetAsync( $"{repository.RemoteRepositoryOwner}/{repository.RemoteRepositoryName}", x.TestMerge.Number) - .WithToken(cancellationToken)); + .WaitAsync(cancellationToken)); try { await Task.WhenAll(tasks); @@ -138,7 +138,7 @@ namespace Tgstation.Server.Host.Components.Deployment.Remote $"{remoteRepositoryOwner}/{remoteRepositoryName}", testMergeNumber, new CreateMergeRequestNoteRequest(comment)) - .WithToken(cancellationToken); + .WaitAsync(cancellationToken); } /// diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index b82bec8f03..23172671dc 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -323,7 +323,7 @@ namespace Tgstation.Server.Host.Components try { - await container.OnZeroReferences.WithToken(cancellationToken); + await container.OnZeroReferences.WaitAsync(cancellationToken); // we are the one responsible for cancelling his jobs var tasks = new List(); diff --git a/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs b/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs index fbb43a62ef..166383353f 100644 --- a/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs +++ b/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs @@ -66,7 +66,7 @@ namespace Tgstation.Server.Host.Components.Repository var mr = await client .MergeRequests .GetAsync($"{RemoteRepositoryOwner}/{RemoteRepositoryName}", parameters.Number) - .WithToken(cancellationToken); + .WaitAsync(cancellationToken); var revisionToUse = parameters.TargetCommitSha == null || mr.Sha.StartsWith(parameters.TargetCommitSha, StringComparison.OrdinalIgnoreCase) diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index f3b8d481d1..8f7e4fa82a 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -779,7 +779,7 @@ namespace Tgstation.Server.Host.Components.Session } Interlocked.Exchange(ref rebootTcs, new TaskCompletionSource()).SetResult(); - await RebootGate.WithToken(cancellationToken); + await RebootGate.WaitAsync(cancellationToken); } finally { diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs index c13ea5bfb7..a1f1091807 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs @@ -411,7 +411,7 @@ namespace Tgstation.Server.Host.Components.Watchdog if (Status != WatchdogStatus.Offline) { Logger.LogDebug("Waiting for server to gracefully shut down."); - await monitorTask.WithToken(cancellationToken); + await monitorTask.WaitAsync(cancellationToken); } else Logger.LogTrace("Graceful shutdown requested but server is already offline."); @@ -589,7 +589,7 @@ namespace Tgstation.Server.Host.Components.Watchdog /// A representing the running operation. protected async Task CheckLaunchResult(ISessionController controller, string serverName, CancellationToken cancellationToken) { - var launchResult = await controller.LaunchResult.WithToken(cancellationToken); + var launchResult = await controller.LaunchResult.WaitAsync(cancellationToken); // Dead sessions won't trigger this if (launchResult.ExitCode.HasValue) // you killed us ray... @@ -872,7 +872,7 @@ namespace Tgstation.Server.Host.Components.Watchdog serverPrimed); // wait for something to happen - await toWaitOn.WithToken(cancellationToken); + await toWaitOn.WaitAsync(cancellationToken); cancellationToken.ThrowIfCancellationRequested(); Logger.LogTrace("Monitor activated"); diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 793c2e474d..213a55e02a 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -456,7 +456,7 @@ namespace Tgstation.Server.Host.Core // 503 requests made while the application is starting applicationBuilder.UseAsyncInitialization( - (instanceManager, cancellationToken) => instanceManager.Ready.WithToken(cancellationToken)); + (instanceManager, cancellationToken) => instanceManager.Ready.WaitAsync(cancellationToken)); if (generalConfiguration.HostApiDocumentation) { diff --git a/src/Tgstation.Server.Host/Core/CommandPipeReader.cs b/src/Tgstation.Server.Host/Core/CommandPipeReader.cs index 073f5a1e42..61bad2b474 100644 --- a/src/Tgstation.Server.Host/Core/CommandPipeReader.cs +++ b/src/Tgstation.Server.Host/Core/CommandPipeReader.cs @@ -69,7 +69,7 @@ namespace Tgstation.Server.Host.Core while (!cancellationToken.IsCancellationRequested) { logger.LogTrace("Waiting to read command line..."); - var line = await streamReader.ReadLineAsync().WithToken(cancellationToken); + var line = await streamReader.ReadLineAsync().WaitAsync(cancellationToken); logger?.LogInformation("Received pipe command: {command}", line); switch (line) diff --git a/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs b/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs index e2dbb8f8ff..a81619a512 100644 --- a/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs @@ -1,6 +1,4 @@ -using System; -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; namespace Tgstation.Server.Host.Extensions { @@ -18,46 +16,5 @@ namespace Tgstation.Server.Host.Extensions /// Gets a that never completes. /// public static Task InfiniteTask => InfiniteTaskCompletionSource.Task; - - /// - /// Create a that can be awaited while respecting a given . - /// - /// The to add cancel support to. - /// The for the operation. - /// A representing the running operation. - public static Task WithToken(this Task task, CancellationToken cancellationToken) - { - ArgumentNullException.ThrowIfNull(task); - - async Task Wrap() - { - await task; - return null; - } - - return Wrap().WithToken(cancellationToken); - } - - /// - /// Create a that can be awaited while respecting a given . - /// - /// The result of the . - /// The to add cancel support to. - /// The for the operation. - /// A resulting in the result of . - public static async Task WithToken(this Task task, CancellationToken cancellationToken) - { - ArgumentNullException.ThrowIfNull(task); - - var cancelTcs = new TaskCompletionSource(); - Task completedTask; - using (cancellationToken.Register(() => cancelTcs.SetCanceled(cancellationToken))) - completedTask = await Task.WhenAny(task, cancelTcs.Task); - - if (completedTask != task) - await cancelTcs.Task; - - return await task; - } } } diff --git a/src/Tgstation.Server.Host/IO/Console.cs b/src/Tgstation.Server.Host/IO/Console.cs index efe70e46a3..1b9e5fc8f9 100644 --- a/src/Tgstation.Server.Host/IO/Console.cs +++ b/src/Tgstation.Server.Host/IO/Console.cs @@ -102,7 +102,7 @@ namespace Tgstation.Server.Host.IO cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current) - .WithToken(cancellationToken); + .WaitAsync(cancellationToken); /// public Task WriteAsync(string text, bool newLine, CancellationToken cancellationToken) => Task.Factory.StartNew( diff --git a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs index e6e6c1ca0f..fd01d2aa38 100644 --- a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs +++ b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs @@ -389,7 +389,7 @@ namespace Tgstation.Server.Host.IO async Task CopyThisFile() { - await subdirCreationTask.WithToken(cancellationToken); + await subdirCreationTask.WaitAsync(cancellationToken); using var lockContext = semaphore != null ? await SemaphoreSlimContext.Lock(semaphore, cancellationToken) : null; diff --git a/src/Tgstation.Server.Host/Jobs/JobHandler.cs b/src/Tgstation.Server.Host/Jobs/JobHandler.cs index 98cbe88651..1bf64380f4 100644 --- a/src/Tgstation.Server.Host/Jobs/JobHandler.cs +++ b/src/Tgstation.Server.Host/Jobs/JobHandler.cs @@ -64,7 +64,7 @@ namespace Tgstation.Server.Host.Jobs if (task == null) throw new InvalidOperationException("Job not started!"); - return task.WithToken(cancellationToken); + return task.WaitAsync(cancellationToken); } /// diff --git a/src/Tgstation.Server.Host/Jobs/JobService.cs b/src/Tgstation.Server.Host/Jobs/JobService.cs index 6f8b3901fe..e33851c41a 100644 --- a/src/Tgstation.Server.Host/Jobs/JobService.cs +++ b/src/Tgstation.Server.Host/Jobs/JobService.cs @@ -265,7 +265,7 @@ namespace Tgstation.Server.Host.Jobs } if (noMoreJobsShouldStart && !handler.Started) - await Extensions.TaskExtensions.InfiniteTask.WithToken(cancellationToken); + await Extensions.TaskExtensions.InfiniteTask.WaitAsync(cancellationToken); Task cancelTask = null; using (jobCancellationToken.Register(() => cancelTask = CancelJob(job, canceller, true, cancellationToken))) @@ -320,7 +320,7 @@ namespace Tgstation.Server.Host.Jobs } } - var instanceCoreProvider = await activationTcs.Task.WithToken(cancellationToken); + var instanceCoreProvider = await activationTcs.Task.WaitAsync(cancellationToken); logger.LogTrace("Starting job..."); await operation( diff --git a/src/Tgstation.Server.Host/Swarm/SwarmService.cs b/src/Tgstation.Server.Host/Swarm/SwarmService.cs index a41b0cba00..b2b2b34fb0 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmService.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmService.cs @@ -282,7 +282,7 @@ namespace Tgstation.Server.Host.Swarm ? asyncDelayer.Delay( TimeSpan.FromMinutes(SwarmConstants.UpdateCommitTimeoutMinutes), cancellationToken) - : Extensions.TaskExtensions.InfiniteTask.WithToken(cancellationToken); + : Extensions.TaskExtensions.InfiniteTask.WaitAsync(cancellationToken); var commitTask = Task.WhenAny(localUpdateOperation.CommitGate, timeoutTask); diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs index 2ee26f2089..af4f01c421 100644 --- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs @@ -262,7 +262,7 @@ namespace Tgstation.Server.Host.System if (errorOpen && errorReadTask == null) errorReadTask = stdErrHandle.ReadLineAsync(); - var completedTask = await Task.WhenAny(outputReadTask ?? errorReadTask, errorReadTask ?? outputReadTask).WithToken(disposeToken); + var completedTask = await Task.WhenAny(outputReadTask ?? errorReadTask, errorReadTask ?? outputReadTask).WaitAsync(disposeToken); var line = await completedTask; if (completedTask == outputReadTask) { diff --git a/src/Tgstation.Server.Host/System/SystemDManager.cs b/src/Tgstation.Server.Host/System/SystemDManager.cs index 9ce09a1387..d7b852ae58 100644 --- a/src/Tgstation.Server.Host/System/SystemDManager.cs +++ b/src/Tgstation.Server.Host/System/SystemDManager.cs @@ -128,7 +128,7 @@ namespace Tgstation.Server.Host.System try { - await instanceManager.Ready.WithToken(cancellationToken); + await instanceManager.Ready.WaitAsync(cancellationToken); CheckReady(); var watchdogUsec = Environment.GetEnvironmentVariable("WATCHDOG_USEC"); diff --git a/src/Tgstation.Server.Host/Transfer/FileTransferService.cs b/src/Tgstation.Server.Host/Transfer/FileTransferService.cs index 0b7bdb497a..eabb99e445 100644 --- a/src/Tgstation.Server.Host/Transfer/FileTransferService.cs +++ b/src/Tgstation.Server.Host/Transfer/FileTransferService.cs @@ -258,7 +258,7 @@ namespace Tgstation.Server.Host.Transfer var expireAt = DateTimeOffset.UtcNow + TimeSpan.FromMinutes(TicketValidityMinutes); try { - await oldExpireTask.WithToken(disposeCts.Token); + await oldExpireTask.WaitAsync(disposeCts.Token); var now = DateTimeOffset.UtcNow; if (now < expireAt) diff --git a/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs b/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs index 402cd6b951..af3ad3229f 100644 --- a/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs +++ b/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs @@ -126,7 +126,7 @@ namespace Tgstation.Server.Host.Transfer { streamTcs.TrySetResult(bufferedStream ?? stream); - await completionTcs.Task.WithToken(cancellationToken); + await completionTcs.Task.WaitAsync(cancellationToken); return errorMessage; } } diff --git a/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs b/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs index 0bf56b6f9d..7375db59b2 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs @@ -65,7 +65,7 @@ namespace Tgstation.Server.Host.Utils.GitHub { RedirectUri = oAuthConfiguration.RedirectUrl, }) - .WithToken(cancellationToken); + .WaitAsync(cancellationToken); var token = response.AccessToken; return token; @@ -79,7 +79,7 @@ namespace Tgstation.Server.Host.Utils.GitHub .Repository .Release .GetAll(updatesConfiguration.GitHubRepositoryId) - .WithToken(cancellationToken); + .WaitAsync(cancellationToken); logger.LogTrace("{totalReleases} total releases", allReleases.Count); var releases = allReleases @@ -123,7 +123,7 @@ namespace Tgstation.Server.Host.Utils.GitHub var repository = await gitHubClient .Repository .Get(updatesConfiguration.GitHubRepositoryId) - .WithToken(cancellationToken); + .WaitAsync(cancellationToken); var repoUrl = new Uri(repository.HtmlUrl); logger.LogTrace("Maps to {repostioryUrl}", repoUrl); @@ -136,7 +136,7 @@ namespace Tgstation.Server.Host.Utils.GitHub { logger.LogTrace("CreateOAuthAccessToken"); - var userDetails = await gitHubClient.User.Current().WithToken(cancellationToken); + var userDetails = await gitHubClient.User.Current().WaitAsync(cancellationToken); return userDetails.Id; } @@ -159,7 +159,7 @@ namespace Tgstation.Server.Host.Utils.GitHub repoName, issueNumber, comment) - .WithToken(cancellationToken); + .WaitAsync(cancellationToken); } /// @@ -176,7 +176,7 @@ namespace Tgstation.Server.Host.Utils.GitHub .Get( repoOwner, repoName) - .WithToken(cancellationToken); + .WaitAsync(cancellationToken); return repo.Id; } @@ -199,7 +199,7 @@ namespace Tgstation.Server.Host.Utils.GitHub repoOwner, repoName, newDeployment) - .WithToken(cancellationToken); + .WaitAsync(cancellationToken); return deployment.Id; } @@ -223,7 +223,7 @@ namespace Tgstation.Server.Host.Utils.GitHub repoName, deploymentId, newDeploymentStatus) - .WithToken(cancellationToken); + .WaitAsync(cancellationToken); } /// @@ -240,7 +240,7 @@ namespace Tgstation.Server.Host.Utils.GitHub repoId, deploymentId, newDeploymentStatus) - .WithToken(cancellationToken); + .WaitAsync(cancellationToken); } /// @@ -258,7 +258,7 @@ namespace Tgstation.Server.Host.Utils.GitHub repoOwner, repoName, pullRequestNumber) - .WithToken(cancellationToken); + .WaitAsync(cancellationToken); } } } diff --git a/tests/Tgstation.Server.Host.Tests.Signals/Program.cs b/tests/Tgstation.Server.Host.Tests.Signals/Program.cs index 995031cc4e..dc222f6331 100644 --- a/tests/Tgstation.Server.Host.Tests.Signals/Program.cs +++ b/tests/Tgstation.Server.Host.Tests.Signals/Program.cs @@ -40,17 +40,17 @@ namespace Tgstation.Server.Host.Tests.Signals Assert.IsFalse(tcs.Task.IsCompleted); using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); - await signalHandler.StopAsync(default).WithToken(cts.Token); + await signalHandler.StopAsync(default).WaitAsync(cts.Token); Assert.IsFalse(tcs.Task.IsCompleted); using var signalHandler2 = new PosixSignalHandler(mockServerControl.Object, mockAsyncDelayer.Object, Mock.Of>()); await signalHandler2.StartAsync(default); using var cts2 = new CancellationTokenSource(TimeSpan.FromSeconds(20)); - await tcs.Task.WithToken(cts2.Token); + await tcs.Task.WaitAsync(cts2.Token); using var cts3 = new CancellationTokenSource(TimeSpan.FromSeconds(5)); - await signalHandler2.StopAsync(default).WithToken(cts3.Token); + await signalHandler2.StopAsync(default).WaitAsync(cts3.Token); } } } diff --git a/tests/Tgstation.Server.Tests/Live/DummyGitHubService.cs b/tests/Tgstation.Server.Tests/Live/DummyGitHubService.cs index c1bcd2903e..35f62867c9 100644 --- a/tests/Tgstation.Server.Tests/Live/DummyGitHubService.cs +++ b/tests/Tgstation.Server.Tests/Live/DummyGitHubService.cs @@ -45,7 +45,7 @@ namespace Tgstation.Server.Tests.Live .Repository .Release .GetAll("tgstation", "tgstation-server") - .WithToken(cancellationToken); + .WaitAsync(cancellationToken); targetRelease = releases.FirstOrDefault(release => release.TagName == $"{new UpdatesConfiguration().GitTagPrefix}{TestLiveServer.TestUpdateVersion}"); } @@ -59,7 +59,7 @@ namespace Tgstation.Server.Tests.Live testPr = await gitHubClient .PullRequest .Get("Cyberboss", "common_core", 2) - .WithToken(cancellationToken); + .WaitAsync(cancellationToken); ServiceCollectionExtensions.UseGitHubServiceFactory(); } diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 004b0f3e8e..82d61d7b05 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -590,7 +590,7 @@ namespace Tgstation.Server.Tests.Live.Instance var bridgeTestTopicResult = await TopicClient.SendTopic(IPAddress.Loopback, "tgs_integration_test_tactics2=1", TestLiveServer.DDPort, cancellationToken); Assert.AreEqual("ack2", bridgeTestTopicResult.StringData); - await bridgeTestsTcs.Task.WithToken(cancellationToken); + await bridgeTestsTcs.Task.WaitAsync(cancellationToken); } BridgeController.LogContent = true; diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 015e6fcdf1..d373e2916e 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1303,7 +1303,7 @@ namespace Tgstation.Server.Tests.Live serverCts.Cancel(); try { - await serverTask.WithToken(hardCancellationToken); + await serverTask.WaitAsync(hardCancellationToken); } catch (OperationCanceledException) { } diff --git a/tests/Tgstation.Server.Tests/TestSystemInteraction.cs b/tests/Tgstation.Server.Tests/TestSystemInteraction.cs index abf97749ef..a7b41aba76 100644 --- a/tests/Tgstation.Server.Tests/TestSystemInteraction.cs +++ b/tests/Tgstation.Server.Tests/TestSystemInteraction.cs @@ -30,7 +30,7 @@ namespace Tgstation.Server.Tests await using var process = await processExecutor.LaunchProcess("test." + platformIdentifier.ScriptFileExtension, ".", string.Empty, null, true, true); using var cts = new CancellationTokenSource(); cts.CancelAfter(3000); - var exitCode = await process.Lifetime.WithToken(cts.Token); + var exitCode = await process.Lifetime.WaitAsync(cts.Token); Assert.AreEqual(0, exitCode); var result = (await process.GetCombinedOutput(default)).Trim(); @@ -59,7 +59,7 @@ namespace Tgstation.Server.Tests { using var cts = new CancellationTokenSource(); cts.CancelAfter(3000); - var exitCode = await process.Lifetime.WithToken(cts.Token); + var exitCode = await process.Lifetime.WaitAsync(cts.Token); await process.GetCombinedOutput(cts.Token); From d139106bf2f4f970a7905fbff139f384a8db6c88 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 23:24:53 -0400 Subject: [PATCH 048/160] Fix .git clean ignoring `ClientApp` directory --- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index eebc126c92..631c08977b 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -29,6 +29,7 @@ + From b16cdb5c858c292f39d5c6943e3ac757f549f2a0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 23:29:14 -0400 Subject: [PATCH 049/160] Fix deb install command again --- .github/workflows/ci-suite.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 133fdaca01..e1ec6e29af 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -918,11 +918,11 @@ jobs: gpg --verify tgstation-server_${{ env.TGS_VERSION }}-1_amd64.changes gpg --verify tgstation-server_${{ env.TGS_VERSION }}-1_amd64.buildinfo - - name: Test Install and Uninstall + - name: Test Install and Uninstall # Has to use `apt` on install because apt-get doesn't do the dependencies run: | sudo dpkg --add-architecture i386 sudo apt-get update - sudo apt-get install -y ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb + sudo apt install -y ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb systemctl status tgstation-server sudo ls -al /etc/tgstation-server sudo cat /etc/tgstation-server/appsettings.Production.yml From 4f2209963982ba448269a8b922a4d06f6314292c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Jun 2023 23:34:43 -0400 Subject: [PATCH 050/160] Simplify .msi test installation --- .github/workflows/ci-suite.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index e1ec6e29af..447b51bca0 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -978,16 +978,12 @@ jobs: $file = [System.IO.Path]::GetFullPath("packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi") $log = [System.IO.Path]::GetFullPath("install.log") $procMain = Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru - $procLog = Start-Process "powershell" "Get-Content -Path `"$log`" -Wait" -NoNewWindow -PassThru $procMain.WaitForExit() - $procLog.Kill() Get-Content C:/Program Files (x86)/tgstation/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json Get-Service -Name tgstation-server -ErrorAction SilentlyContinue $log = [System.IO.Path]::GetFullPath("uninstall.log") $procMain = Start-Process "msiexec" "/u `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru - $procLog = Start-Process "powershell" "Get-Content -Path `"$log`" -Wait" -NoNewWindow -PassThru $procMain.WaitForExit() - $procLog.Kill() $service=Get-Service -Name tgstation-server -ErrorAction SilentlyContinue if ($service.Length -gt 0) { echo $service From 206e24135be627b24c052b7b87372f8e95c442f7 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 00:06:19 -0400 Subject: [PATCH 051/160] Properly quote install path --- .github/workflows/ci-suite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 447b51bca0..9cd7244ba5 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -979,7 +979,7 @@ jobs: $log = [System.IO.Path]::GetFullPath("install.log") $procMain = Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru $procMain.WaitForExit() - Get-Content C:/Program Files (x86)/tgstation/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json + Get-Content "C:/Program Files (x86)/tgstation/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json" Get-Service -Name tgstation-server -ErrorAction SilentlyContinue $log = [System.IO.Path]::GetFullPath("uninstall.log") $procMain = Start-Process "msiexec" "/u `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru From ee2932bc1534301ea52b318a0f5529e827e35e4d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 00:09:58 -0400 Subject: [PATCH 052/160] Remove unnecessary CI matrix --- .github/workflows/ci-suite.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 9cd7244ba5..e812cbb533 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -875,14 +875,10 @@ jobs: fail_ci_if_error: true build-deb: - name: Build .deb Package + name: Build .deb Package # Can't do i386 due to https://github.com/dotnet/core/issues/4595 needs: start-ci-run-gate runs-on: ubuntu-latest if: "!(cancelled() || failure()) && needs.start-ci-run-gate.result == 'success'" - strategy: - fail-fast: false - matrix: - arch: [ 'amd64' ] # Can't do i386 due to https://github.com/dotnet/core/issues/4595 steps: - name: Import GPG Key run: | From 315a32ce736f2248cbe2ba86b1726f01da5ed5fc Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 00:12:54 -0400 Subject: [PATCH 053/160] Rename `build_package.ps1` to `build_msi.ps1` --- .github/workflows/ci-suite.yml | 2 +- build/package/winget/{build_package.ps1 => build_msi.ps1} | 0 tgstation-server.sln | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename build/package/winget/{build_package.ps1 => build_msi.ps1} (100%) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index e812cbb533..970a0b79d1 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -966,7 +966,7 @@ jobs: - name: Execute Build Script shell: powershell - run: build/package/winget/build_package.ps1 + run: build/package/winget/build_msi.ps1 - name: Test Install and Uninstall # Sanity checks the .deps.json exists, which the installation is broken without shell: powershell # If it's missing, I found that in elements were the problem diff --git a/build/package/winget/build_package.ps1 b/build/package/winget/build_msi.ps1 similarity index 100% rename from build/package/winget/build_package.ps1 rename to build/package/winget/build_msi.ps1 diff --git a/tgstation-server.sln b/tgstation-server.sln index 010e08c860..0e87b7b999 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -234,8 +234,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "upstream", "upstream", "{B4 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "winget", "winget", "{506B9092-AF88-4DA2-84FD-C11646B695B0}" ProjectSection(SolutionItems) = preProject - build\package\winget\build_package.ps1 = build\package\winget\build_package.ps1 build\package\winget\installer.sln = build\package\winget\installer.sln + build\package\winget\build_msi.ps1 = build\package\winget\build_msi.ps1 build\package\winget\install_banner.jpg = build\package\winget\install_banner.jpg EndProjectSection EndProject From 6585610461c4cc7b89847dd4ccf06047ebf58979 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 00:46:15 -0400 Subject: [PATCH 054/160] Hopefully fixes .deb installs in CI --- .github/workflows/ci-suite.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 970a0b79d1..d8ddcc6149 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -914,11 +914,11 @@ jobs: gpg --verify tgstation-server_${{ env.TGS_VERSION }}-1_amd64.changes gpg --verify tgstation-server_${{ env.TGS_VERSION }}-1_amd64.buildinfo - - name: Test Install and Uninstall # Has to use `apt` on install because apt-get doesn't do the dependencies + - name: Test Install and Uninstall run: | sudo dpkg --add-architecture i386 sudo apt-get update - sudo apt install -y ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb + sudo apt-get install -y APT::Immediate-Configure=0 libgcc-s1:i386 ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb systemctl status tgstation-server sudo ls -al /etc/tgstation-server sudo cat /etc/tgstation-server/appsettings.Production.yml From ed0786ce65eaa4846a68222a8aeb3477dcf0414c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 01:47:38 -0400 Subject: [PATCH 055/160] Working winget push into deploy CI --- .github/workflows/ci-suite.yml | 42 +++++++++++++++++-- build/package/winget/build_msi.ps1 | 10 +++-- .../manifest/Tgstation.Server.installer.yaml | 7 ++-- .../Tgstation.Server.locale.en-US.yaml | 11 ++++- .../winget/manifest/Tgstation.Server.yaml | 2 +- build/package/winget/push_manifest.ps1 | 40 ++++++++++++++++++ tgstation-server.sln | 1 + 7 files changed, 100 insertions(+), 13 deletions(-) create mode 100644 build/package/winget/push_manifest.ps1 diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index d8ddcc6149..47e1f7686b 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -21,6 +21,9 @@ env: TGS_DOTNET_VERSION: 6.0.x TGS_TEST_GITHUB_TOKEN: ${{ secrets.LIVE_TESTS_TOKEN }} TGS_RELEASE_NOTES_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} + WINGET_PUSH_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} + PACKAGING_KEYGRIP: ${{ vars.PACKAGING_KEYGRIP }} + PACKAGING_PRIVATE_KEY_PASSPHRASE: ${{ secrets.PACKAGING_PRIVATE_KEY_PASSPHRASE }} CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} concurrency: @@ -899,9 +902,6 @@ jobs: ref: "refs/pull/${{ github.event.number }}/merge" - name: Execute Build Script - env: - PACKAGING_KEYGRIP: ${{ vars.PACKAGING_KEYGRIP }} - PACKAGING_PRIVATE_KEY_PASSPHRASE: ${{ secrets.PACKAGING_PRIVATE_KEY_PASSPHRASE }} run: sudo -E build/package/deb/build_package.sh - name: Parse TGS version @@ -964,6 +964,9 @@ jobs: with: ref: "refs/pull/${{ github.event.number }}/merge" + - name: Validate winget Manifest + run: winget validate --manifest build/package/winget/manifest + - name: Execute Build Script shell: powershell run: build/package/winget/build_msi.ps1 @@ -1333,3 +1336,36 @@ jobs: - name: Trigger tgstation-ppa workflow run: | curl -XPOST -u "${{ vars.DEV_PUSH_USERNAME }}:${{ secrets.DEV_PUSH_TOKEN }}" -H "Accept: application/vnd.github.everest-preview+json" -H "Content-Type: application/json" https://api.github.com/repos/tgstation/tgstation-ppa/actions/workflows/add_tgs_version.yml/dispatches --data '{"ref":"main","inputs":{"tgs_semver": "${{ env.TGS_VERSION }}"}}' + + deploy-winget: + name: Deploy TGS (winget) + needs: deploy-tgs + if: "!(cancelled() || failure()) && needs.deploy-tgs.result == 'success'" + runs-on: ubuntu-latest + steps: + - name: Setup dotnet + uses: actions/setup-dotnet@v2 + with: + dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + + - name: Install wingetcreate + run: winget install wingetcreate + + - name: Checkout + uses: actions/checkout@v3 + + - name: Build ReleaseNotes + run: dotnet build -c Release --project tools/ReleaseNotes + + - name: Retrieve .msi + uses: actions/download-artifact@v3 + with: + name: packaging-windows + path: packaging-windows + + - name: Execute Push Script + shell: powershell + run: build/package/winget/push_manifest.ps1 -MsiPath packaging-windows/tgstation-server.msi + + - name: Run ReleaseNotes with --link-winget + run: dotnet run -c Release --project tools/ReleaseNotes --link-winget ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/build/package/winget/build_msi.ps1 b/build/package/winget/build_msi.ps1 index 891ffbab4b..a1da7c23a5 100644 --- a/build/package/winget/build_msi.ps1 +++ b/build/package/winget/build_msi.ps1 @@ -4,24 +4,26 @@ Remove-Item -Recurse -Force -ErrorAction SilentlyContinue packaging git worktree remove -f packaging -$ErrorActionPreference="Stop" - git worktree add -f packaging $currentCommit cd packaging Remove-Item -Recurse -Force .git dotnet restore -[XML]$versionXML = Get-Content build/Version.props +[XML]$versionXML = Get-Content build/Version.props -ErrorAction Stop + $tgsVersion = $versionXML.Project.PropertyGroup.TgsCoreVersion cd build/package/winget $devVersion = '0.22.475' -(Get-Content Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj).Replace($devVersion, $tgsVersion) | Set-Content Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +(Get-Content Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj -ErrorAction Stop).Replace($devVersion, $tgsVersion) | Set-Content Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj -ErrorAction Stop # We make _some_ assumptions DevEnv installer.sln /Project Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj /build Release +if (-Not $?) { + exit $lastexitcode +} cd ../../../.. diff --git a/build/package/winget/manifest/Tgstation.Server.installer.yaml b/build/package/winget/manifest/Tgstation.Server.installer.yaml index 68b4a1457d..31f2517b77 100644 --- a/build/package/winget/manifest/Tgstation.Server.installer.yaml +++ b/build/package/winget/manifest/Tgstation.Server.installer.yaml @@ -2,14 +2,14 @@ # yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.4.0.schema.json PackageIdentifier: Tgstation.Server -PackageVersion: 0.0.0 # Set before publish by wingetcreate +PackageVersion: 0.22.475 # Set before publish by push_manifest.ps1 Installers: -- InstallerUrl: https://github.com/tgstation/tgstation-server/releases/download/tgstation-server-v0.0.0/tgstation-server.msi # Set before publish by wingetcreate +- InstallerUrl: https://github.com/tgstation/tgstation-server/releases/download/tgstation-server-v0.22.475/tgstation-server.msi # Set before publish by push_manifest.ps1 InstallerLocale: en-US Architecture: x86 InstallerType: msi Scope: machine - InstallerSha256: F749672C1BDBAC8CD8AEF7352B97E54C21CF389D798D0ED245CA75EC72521460 + InstallerSha256: F749672C1BDBAC8CD8AEF7352B97E54C21CF389D798D0ED245CA75EC72521460 # Set before publish by push_manifest.ps1 InstallModes: - interactive - silent @@ -19,7 +19,6 @@ Installers: UnsupportedOSArchitectures: - arm - arm64 - ElevationRequirement: elevationRequired Dependencies: PackageDependencies: - PackageIdentifier: Microsoft.DotNet.AspNetCore.6 diff --git a/build/package/winget/manifest/Tgstation.Server.locale.en-US.yaml b/build/package/winget/manifest/Tgstation.Server.locale.en-US.yaml index 827c431db8..67b00590d8 100644 --- a/build/package/winget/manifest/Tgstation.Server.locale.en-US.yaml +++ b/build/package/winget/manifest/Tgstation.Server.locale.en-US.yaml @@ -2,11 +2,20 @@ # yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.4.0.schema.json PackageIdentifier: Tgstation.Server -PackageVersion: 0.0.0 # Set before publish by wingetcreate +PackageVersion: 0.22.475 # Set before publish by push_manifest.ps1 PackageLocale: en-US Publisher: /tg/station 13 +PublisherUrl: https://github.com/tgstation/tgstation-server +PublisherSupportUrl: https://github.com/tgstation/tgstation-server/discussions/categories/q-a +Author: Dominion/Cyberboss PackageName: tgstation-server License: AGPL-3.0 ShortDescription: A production scale tool for BYOND server management +Moniker: tgstation-server +Documentations: + - DocumentLabel: README.md + DocumentUrl: https://github.com/tgstation/tgstation-server/blob/tgstation-server-v0.22.475/README.md +ReleaseNotesUrl: https://github.com/tgstation/tgstation-server/releases/tag/tgstation-server-v0.22.475 +PurchaseUrl: https://github.com/sponsors/Cyberboss ManifestType: defaultLocale ManifestVersion: 1.4.0 diff --git a/build/package/winget/manifest/Tgstation.Server.yaml b/build/package/winget/manifest/Tgstation.Server.yaml index e543e57585..c23541ad90 100644 --- a/build/package/winget/manifest/Tgstation.Server.yaml +++ b/build/package/winget/manifest/Tgstation.Server.yaml @@ -2,7 +2,7 @@ # yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.4.0.schema.json PackageIdentifier: Tgstation.Server -PackageVersion: 0.0.0 # Set before publish by wingetcreate +PackageVersion: 0.22.475 # Set before publish by push_manifest.ps1 DefaultLocale: en-US ManifestType: version ManifestVersion: 1.4.0 diff --git a/build/package/winget/push_manifest.ps1 b/build/package/winget/push_manifest.ps1 new file mode 100644 index 0000000000..f2a7154533 --- /dev/null +++ b/build/package/winget/push_manifest.ps1 @@ -0,0 +1,40 @@ +param( + [string]$MsiPath = 'packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi' +) + +$ErrorActionPreference="Stop" + +[XML]$versionXML = Get-Content build/Version.props -ErrorAction Stop + +$tgsVersion = $versionXML.Project.PropertyGroup.TgsCoreVersion + +$installerHash = Get-FileHash -Path $MsiPath -ErrorAction Stop # SHA256 is the default + +cd build/package/winget/manifest + +$devHash = 'F749672C1BDBAC8CD8AEF7352B97E54C21CF389D798D0ED245CA75EC72521460' +$devVersion = '0.22.475' +$devReleaseDate = '2023-06-24' +$releaseDate = Get-Date -format "yyyy-MM-dd" + +(Get-Content Tgstation.Server.installer.yaml -ErrorAction Stop).Replace($devHash, $installerHash.Hash).Replace($devReleaseDate, $releaseDate).Replace($devVersion, $tgsVersion) | Set-Content Tgstation.Server.installer.yaml -ErrorAction Stop +(Get-Content Tgstation.Server.locale.en-US.yaml -ErrorAction Stop).Replace($devVersion, $tgsVersion) | Set-Content Tgstation.Server.locale.en-US.yaml -ErrorAction Stop +(Get-Content Tgstation.Server.yaml -ErrorAction Stop).Replace($devVersion, $tgsVersion) | Set-Content Tgstation.Server.yaml -ErrorAction Stop + +winget validate --manifest . +if (-Not $?) { + exit $lastexitcode +} + +# I know this is late, but we actually need the package online to install it +winget install -m . -h --disable-interactivity +if (-Not $?) { + exit $lastexitcode +} + +wingetcreate submit -t $Env:WINGET_PUSH_TOKEN . +if (-Not $?) { + exit $lastexitcode +} + +cd ../../../.. diff --git a/tgstation-server.sln b/tgstation-server.sln index 0e87b7b999..3e5c8b76c8 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -237,6 +237,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "winget", "winget", "{506B90 build\package\winget\installer.sln = build\package\winget\installer.sln build\package\winget\build_msi.ps1 = build\package\winget\build_msi.ps1 build\package\winget\install_banner.jpg = build\package\winget\install_banner.jpg + build\package\winget\push_manifest.ps1 = build\package\winget\push_manifest.ps1 EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "manifest", "manifest", "{3F141E03-6ABB-46A8-AA24-1B4B6814E58F}" From b309cdb621abb7c0e6b02267f9381837682ee7e3 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 01:49:04 -0400 Subject: [PATCH 056/160] Fix CI Windows installation path --- .github/workflows/ci-suite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 47e1f7686b..2f7dec0636 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -978,7 +978,7 @@ jobs: $log = [System.IO.Path]::GetFullPath("install.log") $procMain = Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru $procMain.WaitForExit() - Get-Content "C:/Program Files (x86)/tgstation/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json" + Get-Content "C:/Program Files (x86)/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json" Get-Service -Name tgstation-server -ErrorAction SilentlyContinue $log = [System.IO.Path]::GetFullPath("uninstall.log") $procMain = Start-Process "msiexec" "/u `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru From cb236cf2b0b7adfa93e2795b46b0513165b8feda Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 02:15:15 -0400 Subject: [PATCH 057/160] Install winget in CI --- .github/workflows/ci-suite.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 2f7dec0636..b48ceedb04 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -954,6 +954,18 @@ jobs: working-directory: C:/Program Files/Microsoft Visual Studio/2022/Enterprise/Common7/IDE/CommonExtensions/Microsoft/VSI/DisableOutOfProcBuild run: ./DisableOutOfProcBuild.exe + - name: Install winget + shell: powershell + run: | + $progressPreference = 'silentlyContinue' + $latestWingetMsixBundleUri = $(Invoke-RestMethod https://api.github.com/repos/microsoft/winget-cli/releases/latest).assets.browser_download_url | Where-Object {$_.EndsWith(".msixbundle")} + $latestWingetMsixBundle = $latestWingetMsixBundleUri.Split("/")[-1] + Write-Information "Downloading winget to artifacts directory..." + Invoke-WebRequest -Uri $latestWingetMsixBundleUri -OutFile "./$latestWingetMsixBundle" + Invoke-WebRequest -Uri https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx -OutFile Microsoft.VCLibs.x64.14.00.Desktop.appx + Add-AppxPackage Microsoft.VCLibs.x64.14.00.Desktop.appx + Add-AppxPackage $latestWingetMsixBundle + - name: Checkout (Branch) uses: actions/checkout@v3 if: github.event_name == 'push' || github.event_name == 'schedule' @@ -1348,6 +1360,18 @@ jobs: with: dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + - name: Install winget + shell: powershell + run: | + $progressPreference = 'silentlyContinue' + $latestWingetMsixBundleUri = $(Invoke-RestMethod https://api.github.com/repos/microsoft/winget-cli/releases/latest).assets.browser_download_url | Where-Object {$_.EndsWith(".msixbundle")} + $latestWingetMsixBundle = $latestWingetMsixBundleUri.Split("/")[-1] + Write-Information "Downloading winget to artifacts directory..." + Invoke-WebRequest -Uri $latestWingetMsixBundleUri -OutFile "./$latestWingetMsixBundle" + Invoke-WebRequest -Uri https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx -OutFile Microsoft.VCLibs.x64.14.00.Desktop.appx + Add-AppxPackage Microsoft.VCLibs.x64.14.00.Desktop.appx + Add-AppxPackage $latestWingetMsixBundle + - name: Install wingetcreate run: winget install wingetcreate From 588146704c9bb2bf66a843afca56e77fa4b137ba Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 08:32:58 -0400 Subject: [PATCH 058/160] Add missing apt-get parameter --- .github/workflows/ci-suite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index b48ceedb04..9f2d48bfe7 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -918,7 +918,7 @@ jobs: run: | sudo dpkg --add-architecture i386 sudo apt-get update - sudo apt-get install -y APT::Immediate-Configure=0 libgcc-s1:i386 ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb + sudo apt-get install -y -o APT::Immediate-Configure=0 libgcc-s1:i386 ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb systemctl status tgstation-server sudo ls -al /etc/tgstation-server sudo cat /etc/tgstation-server/appsettings.Production.yml From a053c6a02d5abceb8e0a93068ed96dcc9b08eab3 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 08:42:42 -0400 Subject: [PATCH 059/160] Hopefully fixes winget install dependency issue --- .github/workflows/ci-suite.yml | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 9f2d48bfe7..cf8d71aa47 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -954,17 +954,24 @@ jobs: working-directory: C:/Program Files/Microsoft Visual Studio/2022/Enterprise/Common7/IDE/CommonExtensions/Microsoft/VSI/DisableOutOfProcBuild run: ./DisableOutOfProcBuild.exe - - name: Install winget - shell: powershell + - name: Install winget # Hacked together https://github.com/microsoft/winget-cli/issues/1861#issuecomment-1352784247 + shell: powershell # https://github.com/microsoft/winget-cli/issues/700#issuecomment-874084714 run: | + Invoke-WebRequest -Uri https://www.nuget.org/api/v2/package/Microsoft.UI.Xaml/2.7.3 -OutFile .\microsoft.ui.xaml.2.7.3.zip + Expand-Archive .\microsoft.ui.xaml.2.7.3.zip + Add-AppxPackage .\microsoft.ui.xaml.2.7.3\tools\AppX\x64\Release\Microsoft.UI.Xaml.2.7.appx $progressPreference = 'silentlyContinue' - $latestWingetMsixBundleUri = $(Invoke-RestMethod https://api.github.com/repos/microsoft/winget-cli/releases/latest).assets.browser_download_url | Where-Object {$_.EndsWith(".msixbundle")} + $wingetReleaseAssets = $latestWingetMsixBundleUri = $(Invoke-RestMethod https://api.github.com/repos/microsoft/winget-cli/releases/latest).assets + $latestWingetMsixBundleUri = $wingetReleaseAssets.browser_download_url | Where-Object {$_.EndsWith(".msixbundle")} $latestWingetMsixBundle = $latestWingetMsixBundleUri.Split("/")[-1] + $latestWingetLicenseXmlUri = $wingetReleaseAssets.browser_download_url | Where-Object {$_.EndsWith("License1.xml")} + $latestWingetLicenseXml = $latestWingetLicenseXmlUri.Split("/")[-1] Write-Information "Downloading winget to artifacts directory..." Invoke-WebRequest -Uri $latestWingetMsixBundleUri -OutFile "./$latestWingetMsixBundle" Invoke-WebRequest -Uri https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx -OutFile Microsoft.VCLibs.x64.14.00.Desktop.appx + Invoke-WebRequest -Uri $latestWingetLicenseXmlUri -OutFile "./$latestWingetLicenseXml" Add-AppxPackage Microsoft.VCLibs.x64.14.00.Desktop.appx - Add-AppxPackage $latestWingetMsixBundle + Add-AppxProvisionedPackage -Online -PackagePath ./$latestWingetMsixBundle -LicensePath ./$latestWingetLicenseXml - name: Checkout (Branch) uses: actions/checkout@v3 @@ -1360,17 +1367,24 @@ jobs: with: dotnet-version: ${{ env.TGS_DOTNET_VERSION }} - - name: Install winget - shell: powershell + - name: Install winget # Hacked together https://github.com/microsoft/winget-cli/issues/1861#issuecomment-1352784247 + shell: powershell # https://github.com/microsoft/winget-cli/issues/700#issuecomment-874084714 run: | + Invoke-WebRequest -Uri https://www.nuget.org/api/v2/package/Microsoft.UI.Xaml/2.7.3 -OutFile .\microsoft.ui.xaml.2.7.3.zip + Expand-Archive .\microsoft.ui.xaml.2.7.3.zip + Add-AppxPackage .\microsoft.ui.xaml.2.7.3\tools\AppX\x64\Release\Microsoft.UI.Xaml.2.7.appx $progressPreference = 'silentlyContinue' - $latestWingetMsixBundleUri = $(Invoke-RestMethod https://api.github.com/repos/microsoft/winget-cli/releases/latest).assets.browser_download_url | Where-Object {$_.EndsWith(".msixbundle")} + $wingetReleaseAssets = $latestWingetMsixBundleUri = $(Invoke-RestMethod https://api.github.com/repos/microsoft/winget-cli/releases/latest).assets + $latestWingetMsixBundleUri = $wingetReleaseAssets.browser_download_url | Where-Object {$_.EndsWith(".msixbundle")} $latestWingetMsixBundle = $latestWingetMsixBundleUri.Split("/")[-1] + $latestWingetLicenseXmlUri = $wingetReleaseAssets.browser_download_url | Where-Object {$_.EndsWith("License1.xml")} + $latestWingetLicenseXml = $latestWingetLicenseXmlUri.Split("/")[-1] Write-Information "Downloading winget to artifacts directory..." Invoke-WebRequest -Uri $latestWingetMsixBundleUri -OutFile "./$latestWingetMsixBundle" Invoke-WebRequest -Uri https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx -OutFile Microsoft.VCLibs.x64.14.00.Desktop.appx + Invoke-WebRequest -Uri $latestWingetLicenseXmlUri -OutFile "./$latestWingetLicenseXml" Add-AppxPackage Microsoft.VCLibs.x64.14.00.Desktop.appx - Add-AppxPackage $latestWingetMsixBundle + Add-AppxProvisionedPackage -Online -PackagePath ./$latestWingetMsixBundle -LicensePath ./$latestWingetLicenseXml - name: Install wingetcreate run: winget install wingetcreate From f1ec76f73da7130452e8d86782f73b63e1e522f2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 08:57:33 -0400 Subject: [PATCH 060/160] Fix apt, you fucking win Specify installing libstdc++6:i386 manually --- .github/workflows/ci-suite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index cf8d71aa47..61a819615e 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -918,7 +918,7 @@ jobs: run: | sudo dpkg --add-architecture i386 sudo apt-get update - sudo apt-get install -y -o APT::Immediate-Configure=0 libgcc-s1:i386 ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb + sudo apt-get install -y -o APT::Immediate-Configure=0 libstdc++6:i386 libgcc-s1:i386 ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb systemctl status tgstation-server sudo ls -al /etc/tgstation-server sudo cat /etc/tgstation-server/appsettings.Production.yml From 16fe30368bfda043d3d4cf363a10fd4f6268d635 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 09:32:18 -0400 Subject: [PATCH 061/160] Fix SqliteDatabaseContext injection --- .../Database/SqliteDatabaseContext.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs b/src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs index c13ebf2027..98a58190d9 100644 --- a/src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs @@ -22,10 +22,20 @@ namespace Tgstation.Server.Host.Database /// Initializes a new instance of the class. /// /// The for the . - /// The value of . public SqliteDatabaseContext( + DbContextOptions dbContextOptions) + : this(dbContextOptions, false) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The for the . + /// The value of . + internal SqliteDatabaseContext( DbContextOptions dbContextOptions, - bool designTime = false) + bool designTime) : base(dbContextOptions) { this.designTime = designTime; From 69b51dfbfe9442b3d7e52d2617b5830834c6eadc Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 09:35:31 -0400 Subject: [PATCH 062/160] Preconfigure during CI installs --- .github/workflows/ci-suite.yml | 5 ++++- build/package/appsettings.GitHub.yml | 3 +++ tgstation-server.sln | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 build/package/appsettings.GitHub.yml diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 61a819615e..69a2afdfbd 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -916,6 +916,7 @@ jobs: - name: Test Install and Uninstall run: | + sudo install -D build/package/appsettings.GitHub.yml /etc/tgstation-server/appsettings.Production.yml sudo dpkg --add-architecture i386 sudo apt-get update sudo apt-get install -y -o APT::Immediate-Configure=0 libstdc++6:i386 libgcc-s1:i386 ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb @@ -993,12 +994,14 @@ jobs: - name: Test Install and Uninstall # Sanity checks the .deps.json exists, which the installation is broken without shell: powershell # If it's missing, I found that in elements were the problem run: | + mkdir "C:/Program Files (x86)/tgstation-server" + cp build/package/appsettings.GitHub.yml "C:/Program Files (x86)/tgstation-server/appsettings.Production.yml" $file = [System.IO.Path]::GetFullPath("packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi") $log = [System.IO.Path]::GetFullPath("install.log") $procMain = Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru $procMain.WaitForExit() Get-Content "C:/Program Files (x86)/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json" - Get-Service -Name tgstation-server -ErrorAction SilentlyContinue + Get-Service -Name tgstation-server $log = [System.IO.Path]::GetFullPath("uninstall.log") $procMain = Start-Process "msiexec" "/u `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru $procMain.WaitForExit() diff --git a/build/package/appsettings.GitHub.yml b/build/package/appsettings.GitHub.yml new file mode 100644 index 0000000000..e916396a95 --- /dev/null +++ b/build/package/appsettings.GitHub.yml @@ -0,0 +1,3 @@ +Database: + DatabaseType: Sqlite + ConnectionString: Data Source=/tgs.sqlite3;Mode=ReadWriteCreate diff --git a/tgstation-server.sln b/tgstation-server.sln index 3e5c8b76c8..00b15f676c 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -203,6 +203,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Common", " EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "package", "package", "{2648A85F-61AE-428E-95E1-66D06C7A3768}" ProjectSection(SolutionItems) = preProject + build\package\appsettings.GitHub.yml = build\package\appsettings.GitHub.yml build\package\appsettings.Initial.yml = build\package\appsettings.Initial.yml EndProjectSection EndProject @@ -234,8 +235,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "upstream", "upstream", "{B4 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "winget", "winget", "{506B9092-AF88-4DA2-84FD-C11646B695B0}" ProjectSection(SolutionItems) = preProject - build\package\winget\installer.sln = build\package\winget\installer.sln build\package\winget\build_msi.ps1 = build\package\winget\build_msi.ps1 + build\package\winget\installer.sln = build\package\winget\installer.sln build\package\winget\install_banner.jpg = build\package\winget\install_banner.jpg build\package\winget\push_manifest.ps1 = build\package\winget\push_manifest.ps1 EndProjectSection From fdec2b3d177ba50a073917d592dcef0f76bb777e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 10:22:38 -0400 Subject: [PATCH 063/160] Hopefully fix swarm test spurious errors Also add more logging --- .../Swarm/TestSwarmProtocol.cs | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/tests/Tgstation.Server.Host.Tests/Swarm/TestSwarmProtocol.cs b/tests/Tgstation.Server.Host.Tests/Swarm/TestSwarmProtocol.cs index be23a3bce7..80ef9bd8f0 100644 --- a/tests/Tgstation.Server.Host.Tests/Swarm/TestSwarmProtocol.cs +++ b/tests/Tgstation.Server.Host.Tests/Swarm/TestSwarmProtocol.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -21,6 +22,7 @@ namespace Tgstation.Server.Host.Swarm.Tests { static readonly HashSet usedPorts = new (); static ILoggerFactory loggerFactory; + static ILogger logger; static ISeekableFileStreamProvider updateFileStreamProvider; @@ -33,6 +35,8 @@ namespace Tgstation.Server.Host.Swarm.Tests builder.AddConsole(); }); + logger = loggerFactory.CreateLogger(); + var ms = new MemoryStream(new byte[] { 1, 2, 3, 4 }); updateFileStreamProvider = new BufferedFileStreamProvider(ms); @@ -122,14 +126,16 @@ namespace Tgstation.Server.Host.Swarm.Tests await using var node1 = GenNode(controller); TestableSwarmNode.Link(controller, node1); - Assert.AreEqual(SwarmRegistrationResult.Success, await controller.TryInit()); + + node1.RpcMapper.AsyncRequests = false; Assert.AreEqual(SwarmRegistrationResult.Success, await node1.TryInit()); + node1.RpcMapper.AsyncRequests = true; Assert.AreEqual(2, controller.Service.GetSwarmServers().Count); Assert.AreEqual(1, node1.Service.GetSwarmServers().Count); - await DelayMax(() => Assert.AreEqual(2, node1.Service.GetSwarmServers().Count)); + await DelayMax(() => Assert.AreEqual(2, node1.Service.GetSwarmServers().Count), 15); // node checks every 5 minutes, delays are 100ms await controller.SimulateReboot(default); Assert.AreEqual(SwarmRegistrationResult.Success, await controller.TryInit()); @@ -283,20 +289,38 @@ namespace Tgstation.Server.Host.Swarm.Tests return new TestableSwarmNode(loggerFactory, config, version); } - static async Task DelayMax(Action assertion, ulong seconds = 1) + static async Task DelayMax(Action assertion, long seconds = 1) { - for (var i = 0U; i < (seconds * 10); ++i) + var id = Guid.NewGuid(); + logger.LogInformation("Begin DelayMax {id}: {seconds}", id, seconds); + var stopwatch = Stopwatch.StartNew(); + do { try { assertion(); + logger.LogInformation("End DelayMax {id} after {milliseconds}ms", id, stopwatch.ElapsedMilliseconds); return; } - catch (AssertFailedException) { } + catch (AssertFailedException) + { + } + await Task.Delay(TimeSpan.FromMilliseconds(100)); } + while (stopwatch.ElapsedMilliseconds < (seconds * 1000)); - assertion(); + try + { + assertion(); + } + catch + { + logger.LogError("Fail DelayMax {id} after {milliseconds}ms", id, stopwatch.ElapsedMilliseconds); + throw; + } + + logger.LogInformation("End DelayMax {id} after {milliseconds}ms", id, stopwatch.ElapsedMilliseconds); } } } From b7ac1f62386ca66c891af66541385558aa37f0f4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 10:23:08 -0400 Subject: [PATCH 064/160] Fix stylecop applying to test projects --- build/package/winget/installer.sln | 4 ++-- .../Tgstation.Server.Host.csproj | 15 ++++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/build/package/winget/installer.sln b/build/package/winget/installer.sln index fef08dbe57..882fd39d42 100644 --- a/build/package/winget/installer.sln +++ b/build/package/winget/installer.sln @@ -38,8 +38,8 @@ Global {29927416-3B78-49A7-A560-5CCAA638B6B4}.Release|Any CPU.Build.0 = Release|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Release|Any CPU.ActiveCfg = Release|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Release|Any CPU.Build.0 = Release|Any CPU - {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Release|Any CPU.Build.0 = Release|Any CPU + {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Release|Any CPU.ActiveCfg = Installer|Any CPU + {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Release|Any CPU.Build.0 = Installer|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 631c08977b..570dda9d41 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -14,9 +14,10 @@ Linux ..\.. ../../build/uac_elevation_manifest.xml + Debug;Release;Installer - + true @@ -112,10 +113,6 @@ - - - runtime; build; native; contentfiles; analyzers; buildtransitive - @@ -132,6 +129,14 @@ + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + From fb1d8b5b7c36043463d51dce6eead6bd9c2cd5bc Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 10:23:14 -0400 Subject: [PATCH 065/160] Remove unused using --- src/Tgstation.Server.Host/Swarm/SwarmService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Swarm/SwarmService.cs b/src/Tgstation.Server.Host/Swarm/SwarmService.cs index b2b2b34fb0..a1368f9c30 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmService.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmService.cs @@ -20,7 +20,6 @@ using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Core; using Tgstation.Server.Host.Database; -using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.System; using Tgstation.Server.Host.Transfer; From 5dc3ce17638f97079628e9dc4944f4cca1d155b6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 10:46:45 -0400 Subject: [PATCH 066/160] Switch to Cyberboss/InstallWinget --- .github/workflows/ci-suite.yml | 40 ++++------------------------------ 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 69a2afdfbd..326ff11cb6 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -955,24 +955,8 @@ jobs: working-directory: C:/Program Files/Microsoft Visual Studio/2022/Enterprise/Common7/IDE/CommonExtensions/Microsoft/VSI/DisableOutOfProcBuild run: ./DisableOutOfProcBuild.exe - - name: Install winget # Hacked together https://github.com/microsoft/winget-cli/issues/1861#issuecomment-1352784247 - shell: powershell # https://github.com/microsoft/winget-cli/issues/700#issuecomment-874084714 - run: | - Invoke-WebRequest -Uri https://www.nuget.org/api/v2/package/Microsoft.UI.Xaml/2.7.3 -OutFile .\microsoft.ui.xaml.2.7.3.zip - Expand-Archive .\microsoft.ui.xaml.2.7.3.zip - Add-AppxPackage .\microsoft.ui.xaml.2.7.3\tools\AppX\x64\Release\Microsoft.UI.Xaml.2.7.appx - $progressPreference = 'silentlyContinue' - $wingetReleaseAssets = $latestWingetMsixBundleUri = $(Invoke-RestMethod https://api.github.com/repos/microsoft/winget-cli/releases/latest).assets - $latestWingetMsixBundleUri = $wingetReleaseAssets.browser_download_url | Where-Object {$_.EndsWith(".msixbundle")} - $latestWingetMsixBundle = $latestWingetMsixBundleUri.Split("/")[-1] - $latestWingetLicenseXmlUri = $wingetReleaseAssets.browser_download_url | Where-Object {$_.EndsWith("License1.xml")} - $latestWingetLicenseXml = $latestWingetLicenseXmlUri.Split("/")[-1] - Write-Information "Downloading winget to artifacts directory..." - Invoke-WebRequest -Uri $latestWingetMsixBundleUri -OutFile "./$latestWingetMsixBundle" - Invoke-WebRequest -Uri https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx -OutFile Microsoft.VCLibs.x64.14.00.Desktop.appx - Invoke-WebRequest -Uri $latestWingetLicenseXmlUri -OutFile "./$latestWingetLicenseXml" - Add-AppxPackage Microsoft.VCLibs.x64.14.00.Desktop.appx - Add-AppxProvisionedPackage -Online -PackagePath ./$latestWingetMsixBundle -LicensePath ./$latestWingetLicenseXml + - name: Install winget + uses: Cyberboss/InstallWinget@v1 - name: Checkout (Branch) uses: actions/checkout@v3 @@ -1370,24 +1354,8 @@ jobs: with: dotnet-version: ${{ env.TGS_DOTNET_VERSION }} - - name: Install winget # Hacked together https://github.com/microsoft/winget-cli/issues/1861#issuecomment-1352784247 - shell: powershell # https://github.com/microsoft/winget-cli/issues/700#issuecomment-874084714 - run: | - Invoke-WebRequest -Uri https://www.nuget.org/api/v2/package/Microsoft.UI.Xaml/2.7.3 -OutFile .\microsoft.ui.xaml.2.7.3.zip - Expand-Archive .\microsoft.ui.xaml.2.7.3.zip - Add-AppxPackage .\microsoft.ui.xaml.2.7.3\tools\AppX\x64\Release\Microsoft.UI.Xaml.2.7.appx - $progressPreference = 'silentlyContinue' - $wingetReleaseAssets = $latestWingetMsixBundleUri = $(Invoke-RestMethod https://api.github.com/repos/microsoft/winget-cli/releases/latest).assets - $latestWingetMsixBundleUri = $wingetReleaseAssets.browser_download_url | Where-Object {$_.EndsWith(".msixbundle")} - $latestWingetMsixBundle = $latestWingetMsixBundleUri.Split("/")[-1] - $latestWingetLicenseXmlUri = $wingetReleaseAssets.browser_download_url | Where-Object {$_.EndsWith("License1.xml")} - $latestWingetLicenseXml = $latestWingetLicenseXmlUri.Split("/")[-1] - Write-Information "Downloading winget to artifacts directory..." - Invoke-WebRequest -Uri $latestWingetMsixBundleUri -OutFile "./$latestWingetMsixBundle" - Invoke-WebRequest -Uri https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx -OutFile Microsoft.VCLibs.x64.14.00.Desktop.appx - Invoke-WebRequest -Uri $latestWingetLicenseXmlUri -OutFile "./$latestWingetLicenseXml" - Add-AppxPackage Microsoft.VCLibs.x64.14.00.Desktop.appx - Add-AppxProvisionedPackage -Online -PackagePath ./$latestWingetMsixBundle -LicensePath ./$latestWingetLicenseXml + - name: Install winget + uses: Cyberboss/InstallWinget@v1 - name: Install wingetcreate run: winget install wingetcreate From 82b274cab2258e572c31acf6175e3d2134c6f1dc Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 10:51:50 -0400 Subject: [PATCH 067/160] Fuck it, manually install all the .deb dependencies. Idk why apt-get is being so stubborn about it --- .github/workflows/ci-suite.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 326ff11cb6..ca3ed276c3 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -919,7 +919,7 @@ jobs: sudo install -D build/package/appsettings.GitHub.yml /etc/tgstation-server/appsettings.Production.yml sudo dpkg --add-architecture i386 sudo apt-get update - sudo apt-get install -y -o APT::Immediate-Configure=0 libstdc++6:i386 libgcc-s1:i386 ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb + sudo apt-get install -y -o APT::Immediate-Configure=0 libstdc++6:i386 libgcc-s1:i386 aspnetcore-runtime-6.0 gcc-multilib libsystemd0 ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb systemctl status tgstation-server sudo ls -al /etc/tgstation-server sudo cat /etc/tgstation-server/appsettings.Production.yml @@ -984,7 +984,9 @@ jobs: $log = [System.IO.Path]::GetFullPath("install.log") $procMain = Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru $procMain.WaitForExit() - Get-Content "C:/Program Files (x86)/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json" + if (-Not (Test-Path -Path "C:/Program Files (x86)/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json" -PathType Leaf)) { + exit 2 + } Get-Service -Name tgstation-server $log = [System.IO.Path]::GetFullPath("uninstall.log") $procMain = Start-Process "msiexec" "/u `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru From 3b47519bf8133299d4e66008d1780330195edc52 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 10:57:03 -0400 Subject: [PATCH 068/160] Cleanup msi install steps --- .github/workflows/ci-suite.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index ca3ed276c3..810a3f8276 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -987,10 +987,19 @@ jobs: if (-Not (Test-Path -Path "C:/Program Files (x86)/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json" -PathType Leaf)) { exit 2 } - Get-Service -Name tgstation-server + if (Test-Path -Path $log -PathType Leaf) { + Get-Content $log + } + $service=Get-Service -Name tgstation-server + if ($service.Length -eq 0) { + exit 3 + } $log = [System.IO.Path]::GetFullPath("uninstall.log") $procMain = Start-Process "msiexec" "/u `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru $procMain.WaitForExit() + if (Test-Path -Path $log -PathType Leaf) { + Get-Content $log + } $service=Get-Service -Name tgstation-server -ErrorAction SilentlyContinue if ($service.Length -gt 0) { echo $service From 3c9dc9927d94d6fca2754cf4ec0e300277b72b54 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 11:07:31 -0400 Subject: [PATCH 069/160] Setup dotnet manually for .deb test install GitHub is being fucky with their ubuntu image --- .github/workflows/ci-suite.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 810a3f8276..8da0a14337 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -914,12 +914,17 @@ jobs: gpg --verify tgstation-server_${{ env.TGS_VERSION }}-1_amd64.changes gpg --verify tgstation-server_${{ env.TGS_VERSION }}-1_amd64.buildinfo + - name: Setup dotnet because apt-get on actions is bone head stupid + uses: actions/setup-dotnet@v2 + with: + dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + - name: Test Install and Uninstall run: | sudo install -D build/package/appsettings.GitHub.yml /etc/tgstation-server/appsettings.Production.yml sudo dpkg --add-architecture i386 sudo apt-get update - sudo apt-get install -y -o APT::Immediate-Configure=0 libstdc++6:i386 libgcc-s1:i386 aspnetcore-runtime-6.0 gcc-multilib libsystemd0 ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb + sudo apt-get install -y -o APT::Immediate-Configure=0 libstdc++6:i386 libgcc-s1:i386 ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb systemctl status tgstation-server sudo ls -al /etc/tgstation-server sudo cat /etc/tgstation-server/appsettings.Production.yml From dc7ed4262eee3f18bf6a9a7e31f9824e265ae6c6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 11:20:58 -0400 Subject: [PATCH 070/160] Give up on preconfiguring CI installs --- .github/workflows/ci-suite.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 8da0a14337..7874fefeff 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -914,20 +914,21 @@ jobs: gpg --verify tgstation-server_${{ env.TGS_VERSION }}-1_amd64.changes gpg --verify tgstation-server_${{ env.TGS_VERSION }}-1_amd64.buildinfo - - name: Setup dotnet because apt-get on actions is bone head stupid - uses: actions/setup-dotnet@v2 - with: - dotnet-version: ${{ env.TGS_DOTNET_VERSION }} - - name: Test Install and Uninstall run: | - sudo install -D build/package/appsettings.GitHub.yml /etc/tgstation-server/appsettings.Production.yml sudo dpkg --add-architecture i386 sudo apt-get update sudo apt-get install -y -o APT::Immediate-Configure=0 libstdc++6:i386 libgcc-s1:i386 ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb + set +e systemctl status tgstation-server + $EXIT_CODE=$? + set -e + if [ $EXIT_CODE != 0 ] && [ $EXIT_CODE != '3' ]; then + exit $EXIT_CODE + fi sudo ls -al /etc/tgstation-server sudo cat /etc/tgstation-server/appsettings.Production.yml + ls -al /opt/tgstation-server sudo cat /opt/tgstation-server/appsettings.Production.yml cat /opt/tgstation-server/appsettings.yml cat /opt/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json @@ -983,8 +984,6 @@ jobs: - name: Test Install and Uninstall # Sanity checks the .deps.json exists, which the installation is broken without shell: powershell # If it's missing, I found that in elements were the problem run: | - mkdir "C:/Program Files (x86)/tgstation-server" - cp build/package/appsettings.GitHub.yml "C:/Program Files (x86)/tgstation-server/appsettings.Production.yml" $file = [System.IO.Path]::GetFullPath("packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi") $log = [System.IO.Path]::GetFullPath("install.log") $procMain = Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru From f26e770730a49a5176c95846a2870256c9bfa9e2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 11:21:15 -0400 Subject: [PATCH 071/160] Cleanup configure app --- .../Program.cs | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs b/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs index bf8710aa15..16df955876 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs +++ b/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs @@ -66,27 +66,28 @@ foreach (var installLogFile in Directory.EnumerateFiles(installDir, "*.log")) File.Delete(installLogFile); if (uninstall) +{ Directory.Delete( Path.Combine(installDir, "lib"), true); -if ((shortcut || (interactive && !uninstall)) && process.ExitCode == 0) -{ - // try and lockdown the appsettings file - var fileInfo = new FileInfo(Path.Combine(installDir, "appsettings.Production.yml")); - - //get security access - FileSecurity fs = fileInfo.GetAccessControl(); - - //remove inherited access - fs.SetAccessRuleProtection(true, false); - - // Explicitly grant admins and SYSTEM - fs.AddAccessRule(new FileSystemAccessRule("Administrators", FileSystemRights.FullControl, AccessControlType.Allow)); - fs.AddAccessRule(new FileSystemAccessRule("NT AUTHORITY\\SYSTEM", FileSystemRights.Read, AccessControlType.Allow)); - - fileInfo.SetAccessControl(fs); + // returning non-zero can make the installation uninstallable, no thanks + return 0; } -// returning non-zero can make the installation uninstallable, no thanks -return uninstall ? 0 : process.ExitCode; +// try and lockdown the appsettings file +var fileInfo = new FileInfo(Path.Combine(installDir, "appsettings.Production.yml")); + +//get security access +FileSecurity fs = fileInfo.GetAccessControl(); + +//remove inherited access +fs.SetAccessRuleProtection(true, false); + +// Explicitly grant admins and SYSTEM +fs.AddAccessRule(new FileSystemAccessRule("Administrators", FileSystemRights.FullControl, AccessControlType.Allow)); +fs.AddAccessRule(new FileSystemAccessRule("NT AUTHORITY\\SYSTEM", FileSystemRights.Read, AccessControlType.Allow)); + +fileInfo.SetAccessControl(fs); + +return process.ExitCode; From 8f40790d9a1938d948af6200b3911118c381a7d5 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 11:43:23 -0400 Subject: [PATCH 072/160] Fix Get-Service crashing the build? Idkwtf is going on with these runners --- .github/workflows/ci-suite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 7874fefeff..b3084447b0 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -994,7 +994,7 @@ jobs: if (Test-Path -Path $log -PathType Leaf) { Get-Content $log } - $service=Get-Service -Name tgstation-server + $service=Get-Service -Name tgstation-server -ErrorAction SilentlyContinue if ($service.Length -eq 0) { exit 3 } From 66b667a5f62ce3804fb37693e46b75b457bc2eec Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 12:10:47 -0400 Subject: [PATCH 073/160] Break up installer test steps Not sure what's erroring exactly --- .github/workflows/ci-suite.yml | 66 +++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index b3084447b0..b54127b6f2 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -885,8 +885,9 @@ jobs: steps: - name: Import GPG Key run: | + sudo dpkg --add-architecture i386 sudo apt-get update - sudo apt-get install -y gnupg2 + sudo apt-get install -y -o APT::Immediate-Configure=0 libstdc++6:i386 libgcc-s1:i386 gnupg2 echo "${{ secrets.PACKAGING_PRIVATE_KEY }}" > private.pgp echo ${{ secrets.PACKAGING_PRIVATE_KEY_PASSPHRASE }} | gpg --batch --yes --passphrase-fd 0 --import private.pgp rm private.pgp @@ -914,18 +915,9 @@ jobs: gpg --verify tgstation-server_${{ env.TGS_VERSION }}-1_amd64.changes gpg --verify tgstation-server_${{ env.TGS_VERSION }}-1_amd64.buildinfo - - name: Test Install and Uninstall + - name: Test Install run: | - sudo dpkg --add-architecture i386 - sudo apt-get update - sudo apt-get install -y -o APT::Immediate-Configure=0 libstdc++6:i386 libgcc-s1:i386 ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb - set +e - systemctl status tgstation-server - $EXIT_CODE=$? - set -e - if [ $EXIT_CODE != 0 ] && [ $EXIT_CODE != '3' ]; then - exit $EXIT_CODE - fi + sudo apt-get install -y ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb sudo ls -al /etc/tgstation-server sudo cat /etc/tgstation-server/appsettings.Production.yml ls -al /opt/tgstation-server @@ -933,10 +925,23 @@ jobs: cat /opt/tgstation-server/appsettings.yml cat /opt/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json cat /usr/bin/tgs-configure + + - name: Test Service + run: | + set +e + systemctl status tgstation-server + $EXIT_CODE=$? + set -e + if [ $EXIT_CODE != 0 ] && [ $EXIT_CODE != '3' ]; then + exit $EXIT_CODE + fi + + - name: Test Uninstall + run: | sudo apt-get remove -y tgstation-server if [[ -d "/opt/tgstation-server" ]]; then ls -al /opt/tgstation-server - exit 1 + exit 2 fi - name: Create Packaging Archive @@ -981,33 +986,52 @@ jobs: shell: powershell run: build/package/winget/build_msi.ps1 - - name: Test Install and Uninstall # Sanity checks the .deps.json exists, which the installation is broken without - shell: powershell # If it's missing, I found that in elements were the problem + - name: Test Install # Sanity checks the .deps.json exists, which the installation is broken without + shell: powershell # If it's missing, I found that in elements were the problem run: | $file = [System.IO.Path]::GetFullPath("packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi") $log = [System.IO.Path]::GetFullPath("install.log") - $procMain = Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru + $procMain = Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru -Wait $procMain.WaitForExit() - if (-Not (Test-Path -Path "C:/Program Files (x86)/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json" -PathType Leaf)) { - exit 2 - } if (Test-Path -Path $log -PathType Leaf) { Get-Content $log } + $installCode = $procMain.ExitCode + if($installCode -ne 0) { + Write-Host "ERROR INSTALLER EXIT CODE $installCode" + exit 3 + } + if (-Not (Test-Path -Path "C:/Program Files (x86)/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json" -PathType Leaf)) { + exit 2 + } + + - name: Test Service + shell: powershell + run: | $service=Get-Service -Name tgstation-server -ErrorAction SilentlyContinue if ($service.Length -eq 0) { exit 3 } + + - name: Test Uninstall # Sanity checks the .deps.json exists, which the installation is broken without + shell: powershell # If it's missing, I found that in elements were the problem + run: | + $file = [System.IO.Path]::GetFullPath("packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi") $log = [System.IO.Path]::GetFullPath("uninstall.log") - $procMain = Start-Process "msiexec" "/u `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru + $procMain = Start-Process "msiexec" "/u `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru -Wait $procMain.WaitForExit() if (Test-Path -Path $log -PathType Leaf) { Get-Content $log } + $installCode = $procMain.ExitCode + if($installCode -ne 0) { + Write-Host "ERROR INSTALLER EXIT CODE $installCode" + exit 3 + } $service=Get-Service -Name tgstation-server -ErrorAction SilentlyContinue if ($service.Length -gt 0) { echo $service - exit 1 + exit 2 } - name: Upload .msi From 562ab45a7a4f4de2ffc381e333f0c096e499a427 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 13:06:56 -0400 Subject: [PATCH 074/160] Fix OS for `deploy-winget` job --- .github/workflows/ci-suite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index b54127b6f2..ee069bbdad 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -1386,7 +1386,7 @@ jobs: name: Deploy TGS (winget) needs: deploy-tgs if: "!(cancelled() || failure()) && needs.deploy-tgs.result == 'success'" - runs-on: ubuntu-latest + runs-on: windows-latest steps: - name: Setup dotnet uses: actions/setup-dotnet@v2 From f79777daec97c4869d026a206b6d95e5c45ccbb1 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 13:15:04 -0400 Subject: [PATCH 075/160] Add missing silent flag to uninstall --- .../winget/Tgstation.Server.Host.Service.Configure/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs b/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs index 16df955876..9de5d54edd 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs +++ b/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs @@ -55,7 +55,7 @@ else restartService = interactive; process.StartInfo.Arguments = uninstall - ? "-u" + ? $"-u{(silent ? " -s" : String.Empty)}" : $"-i -f -x{(restartService ? " -r" : String.Empty)}{((interactive || shortcut) ? " -c" : String.Empty)}{(silent ? " -s" : String.Empty)}"; process.Start(); From 6d428ce8ad523ab85789d140adb3d41910b3ecc3 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 13:17:46 -0400 Subject: [PATCH 076/160] Fix wingetcreate command --- .github/workflows/ci-suite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index ee069bbdad..fe3934565b 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -1397,7 +1397,7 @@ jobs: uses: Cyberboss/InstallWinget@v1 - name: Install wingetcreate - run: winget install wingetcreate + run: winget install wingetcreate --disable-interactivity --accept-source-agreements - name: Checkout uses: actions/checkout@v3 From 13ba8f346a0c8e35b2754fb149aeb7625d8c9741 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 13:21:08 -0400 Subject: [PATCH 077/160] Fix references to `install-winget` --- .github/workflows/ci-suite.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index fe3934565b..078dd4095f 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -967,7 +967,7 @@ jobs: run: ./DisableOutOfProcBuild.exe - name: Install winget - uses: Cyberboss/InstallWinget@v1 + uses: Cyberboss/install-winget@v1 - name: Checkout (Branch) uses: actions/checkout@v3 @@ -1394,7 +1394,7 @@ jobs: dotnet-version: ${{ env.TGS_DOTNET_VERSION }} - name: Install winget - uses: Cyberboss/InstallWinget@v1 + uses: Cyberboss/install-winget@v1 - name: Install wingetcreate run: winget install wingetcreate --disable-interactivity --accept-source-agreements From f4df9f2f27a601b1824eea2308d37ad052da6be1 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 14:09:46 -0400 Subject: [PATCH 078/160] ReleaseNotes updates for `winget` - Validate the SHA of the PR template so it doesn't go out of date - Add implementation of `--link-winget` action - README.md update --- .github/workflows/ci-suite.yml | 35 ++++++++++++- tools/ReleaseNotes/Program.cs | 95 +++++++++++++++++++++++++++++++++- tools/ReleaseNotes/README.md | 16 +++++- 3 files changed, 142 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 078dd4095f..0b07e08a81 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -1040,9 +1040,42 @@ jobs: name: packaging-windows path: packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi + check-winget-pr-template: + name: Check winget-pkgs Pull Request Template is up to date + needs: start-ci-run-gate + runs-on: ubuntu-latest + steps: + - name: Setup dotnet + uses: actions/setup-dotnet@v2 + with: + dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + + - name: Retrieve winget-pkgs PULL_REQUEST_TEMPLATE commit history from GitHub API + id: get-json + run: | + echo "commits-response=$(curl -L -u "${{ vars.DEV_PUSH_USERNAME }}:${{ secrets.DEV_PUSH_TOKEN }}" -H "Accept: application/vnd.github.everest-preview+json" -H "Content-Type: application/json" https://api.github.com/repos/microsoft/winget-pkgs/commits?path=.github/PULL_REQUEST_TEMPLATE.md)" >> $GITHUB_OUTPUT + + - name: Output Latest SHA for winget-pkgs PULL_REQUEST_TEMPLATE + id: get-sha + run: | + echo "pr_template_sha=$(echo ${{ steps.get-json.outputs.commits-response[0].sha }})" >> $GITHUB_OUTPUT + + - name: Checkout (Branch) + uses: actions/checkout@v3 + if: github.event_name == 'push' || github.event_name == 'schedule' + + - name: Checkout (PR Merge) + uses: actions/checkout@v3 + if: github.event_name != 'push' && github.event_name != 'schedule' + with: + ref: "refs/pull/${{ github.event.number }}/merge" + + - name: Run ReleaseNotes Check + run: dotnet run -c Release --project tools/ReleaseNotes --winget-template-check ${{ steps.get-sha.outputs.pr_template_sha }} + deployment-gate: name: Deployment Gate - needs: [ dox-build, docker-build, build-deb, validate-openapi-spec, upload-code-coverage, build-msi ] + needs: [ dox-build, docker-build, build-deb, validate-openapi-spec, upload-code-coverage, build-msi, check-winget-pr-template ] runs-on: ubuntu-latest if: "!(cancelled() || failure()) && needs.dox-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' && github.event_name == 'push'" steps: diff --git a/tools/ReleaseNotes/Program.cs b/tools/ReleaseNotes/Program.cs index 7a6d8cc000..8c5904704b 100644 --- a/tools/ReleaseNotes/Program.cs +++ b/tools/ReleaseNotes/Program.cs @@ -31,9 +31,11 @@ namespace ReleaseNotes } var versionString = args[0]; - var ensureRelease = versionString == "--ensure-release"; + var ensureRelease = versionString.Equals("--ensure-release", StringComparison.OrdinalIgnoreCase); + var linkWinget = versionString.Equals("--link-winget", StringComparison.OrdinalIgnoreCase); + var shaCheck = versionString.Equals("--winget-template-check", StringComparison.OrdinalIgnoreCase); - if ((!Version.TryParse(versionString, out var version) || version.Revision != -1) && !ensureRelease) + if ((!Version.TryParse(versionString, out var version) || version.Revision != -1) && !ensureRelease && !linkWinget && !shaCheck) { Console.WriteLine("Invalid version: " + versionString); return 2; @@ -60,6 +62,28 @@ namespace ReleaseNotes if (ensureRelease) return await EnsureRelease(client); + if (linkWinget) + { + if (args.Length < 2 || !Uri.TryCreate(args[1], new UriCreationOptions(), out var actionsUrl)) + { + Console.WriteLine("Missing/Invalid actions URL!"); + return 30; + } + + return await Winget(client, actionsUrl, null); + } + + if (shaCheck) + { + if(args.Length < 2) + { + Console.WriteLine("Missing SHA for PR template!"); + return 32; + } + + return await Winget(client, null, args[1]); + } + var releasesTask = client.Repository.Release.GetAll(RepoOwner, RepoName); Console.WriteLine("Getting merged pull requests in milestone " + versionString + "..."); @@ -479,5 +503,72 @@ namespace ReleaseNotes return 0; } + + static async Task Winget(IGitHubClient client, Uri actionUrl, string expectedTemplateSha) + { + const string PropsPath = "build/Version.props"; + + var doc = XDocument.Load(PropsPath); + var project = doc.Root; + var xmlNamespace = project.GetDefaultNamespace(); + var versionsPropertyGroup = project.Elements().First(x => x.Name == xmlNamespace + "PropertyGroup"); + var coreVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsCoreVersion").Value); + + const string BodyForPRSha = "596da68f8da0926ae17a1497328e368d7b83aac2"; + var prBody = $@"# Automated Pull Request + +This pull request was generated by our [deployment pipeline]({actionUrl}) as a result of the release of [tgstation-server-v{coreVersion}](https://github.com/tgstation/tgstation-server/releases/tag/tgstation-server-v{coreVersion}). Validation was performed as part of the process. + +The user account that created this pull request is available to correct any issues. + +- [x] Have you signed the [Contributor License Agreement](https://cla.opensource.microsoft.com/microsoft/winget-pkgs)? +- [x] Have you checked that there aren't other open [pull requests](https://github.com/microsoft/winget-pkgs/pulls) for the same manifest update/change? + - This PR is generated as a direct result of a new release of `tgstation-server` this should be impossible +- [x] This PR only modifies one (1) manifest +- [x] Have you [validated](https://github.com/microsoft/winget-pkgs/blob/master/AUTHORING_MANIFESTS.md#validation) your manifest locally with `winget validate --manifest `? + - Validation is performed as a prerequisite to deployment. +- [x] Have you tested your manifest locally with `winget install --manifest `? + - Manifest installation and uninstallation is performed as a prerequisite to deployment. +- [x] Does your manifest conform to the [1.4 schema](https://github.com/microsoft/winget-pkgs/tree/master/doc/manifest/schema/1.4.0)?"; + + if (expectedTemplateSha != null) + { + if (expectedTemplateSha != BodyForPRSha) + { + Console.WriteLine("winget-pkgs pull request template has updated. This tool will need to be updated to match!"); + Console.WriteLine($"Expected {BodyForPRSha} found {expectedTemplateSha}"); + return 33; + } + + return 0; + } + + var clientUser = await client.User.Current(); + + var userPrsOnWingetRepo = await client.Search.SearchIssues(new SearchIssuesRequest + { + Author = clientUser.Name, + Is = new List { IssueIsQualifier.PullRequest }, + State = ItemState.Open, + Repos = new RepositoryCollection + { + { "microsoft", "winget-pkgs" }, + }, + }); + + var prToModify = userPrsOnWingetRepo.Items.OrderByDescending(pr => pr.Number).FirstOrDefault(); + if(prToModify == null) + { + Console.WriteLine("Could not find open winget-pkgs PR!"); + return 31; + } + + await client.Issue.Update(prToModify.Repository.Id, prToModify.Number, new IssueUpdate + { + Body = prBody, + }); + + return 0; + } } } diff --git a/tools/ReleaseNotes/README.md b/tools/ReleaseNotes/README.md index 63aa900ef3..2a71aad6e0 100644 --- a/tools/ReleaseNotes/README.md +++ b/tools/ReleaseNotes/README.md @@ -1,7 +1,21 @@ -This is a small tool to generate TGS release notes from PR descriptions +This is a small tool to automate generating TGS releases Requires environment variable `TGS_RELEASE_NOTES_TOKEN` Run it with `dotnet run [--no-close (optionally doesn't close the milestone, USE WHILE DEBUGGING)]` Will close the release milestone and output `release_notes.md` with the updated release notes + +Alternative modes + +`dotnet run --ensure-release` + +Ensures the latest GitHub release is a TGS release + +`dotnet run --link-winget ` + +Updates an existing https://github.com/microsoft/winget-pkgs manifest update pull request with the TGS template. The PR updated is the last one opened by the user + +`dotnet run --winget-template-check ` + +Validates the template we are PRing is up-to-date. From dc453daef24d8af8607cc27e14c8dddefe3bee6d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 14:14:20 -0400 Subject: [PATCH 079/160] Add `ci-completion-gate` to simplify branch protection rules --- .github/workflows/ci-suite.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 0b07e08a81..230cd25634 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -1073,11 +1073,20 @@ jobs: - name: Run ReleaseNotes Check run: dotnet run -c Release --project tools/ReleaseNotes --winget-template-check ${{ steps.get-sha.outputs.pr_template_sha }} + ci-completion-gate: # This job exists so there isn't a moving target for branch protections + name: CI Completion Gate + needs: [ dox-build, docker-build, build-deb, build-msi, validate-openapi-spec, upload-code-coverage, check-winget-pr-template ] + runs-on: ubuntu-latest + if: "!(cancelled() || failure()) && needs.dox-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'" + steps: + - name: GitHub Requires at Least One Step for a Job + run: exit 0 + deployment-gate: name: Deployment Gate - needs: [ dox-build, docker-build, build-deb, validate-openapi-spec, upload-code-coverage, build-msi, check-winget-pr-template ] + needs: ci-completion-gate runs-on: ubuntu-latest - if: "!(cancelled() || failure()) && needs.dox-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' && github.event_name == 'push'" + if: "!(cancelled() || failure()) && needs.ci-completion-gate.result == 'success' && github.event_name == 'push'" steps: - name: GitHub Requires at Least One Step for a Job run: exit 0 From aa8ae78167042d084fab04f44843751f55de5deb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 14:21:47 -0400 Subject: [PATCH 080/160] Fix CI msiexec uninstall flag Also remove useless calls and assignments --- .github/workflows/ci-suite.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 230cd25634..92d740655d 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -991,8 +991,7 @@ jobs: run: | $file = [System.IO.Path]::GetFullPath("packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi") $log = [System.IO.Path]::GetFullPath("install.log") - $procMain = Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru -Wait - $procMain.WaitForExit() + Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru -Wait if (Test-Path -Path $log -PathType Leaf) { Get-Content $log } @@ -1018,8 +1017,7 @@ jobs: run: | $file = [System.IO.Path]::GetFullPath("packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi") $log = [System.IO.Path]::GetFullPath("uninstall.log") - $procMain = Start-Process "msiexec" "/u `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru -Wait - $procMain.WaitForExit() + Start-Process "msiexec" "/x `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru -Wait if (Test-Path -Path $log -PathType Leaf) { Get-Content $log } From f0e5736fb310052e5ee5beb49fc0cd603b2f3bf5 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 14:32:43 -0400 Subject: [PATCH 081/160] CI Suite -> CI Pipeline. Document a little --- .../{ci-suite.yml => ci-pipeline.yml} | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) rename .github/workflows/{ci-suite.yml => ci-pipeline.yml} (98%) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-pipeline.yml similarity index 98% rename from .github/workflows/ci-suite.yml rename to .github/workflows/ci-pipeline.yml index 92d740655d..a618c35eb1 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1,4 +1,21 @@ -name: 'CI' +# THE MAIN BIG CHUNGUS +# Does CI on push/PR/cron. Deployments on push when triggered +# - Validates Documentation +# - Builds C# and DMAPI +# - Tests everything on massive matrix +# - Packages +# - Tests package installs/services/uninstalls +# - Properly versions everything based on build/Version.props +# - Checks commit tags for deployment intents +# - Deploys DreamMaker API zip [DMDeploy] (dev/master) +# - Deploys Nuget Packages [NugetDeploy] (dev/master) +# - Deploys HTTP API swagger.json [APIDeploy] (dev/master) +# - Deploys tgstation-server [TGSDeploy] (master) +# - GitHub Releases: https://github.com/tgstation/tgstation-server/releases +# - Docker: https://hub.docker.com/r/tgstation/server +# - apt repo: https://github.com/tgstation/tgstation-ppa +# - winget: https://github.com/microsoft/winget-pkgs/tree/master/manifests/t/Tgstation/Server +name: 'CI Pipeline' on: schedule: From e5143932306ab3a1c44e7223e258cb571eb1ab7c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 14:34:56 -0400 Subject: [PATCH 082/160] Add missing winget-cli link to README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c73f4d905a..fa61ba5b9f 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ You should also ensure that your .NET Framework runtime version is >= v4.7.2. Mo ##### winget -If you have [winget]() installed. You can easily install the latest version of tgstation-server (provided Microsoft has approved the most recent package manifest). +If you have [winget](https://github.com/microsoft/winget-cli) installed. You can easily install the latest version of tgstation-server (provided Microsoft has approved the most recent package manifest). Simply run the following command: ```sh @@ -50,7 +50,7 @@ winget install tgstation-server --silent You won't be prompted to run the setup wizard. However, you can do so immediately after via the shortcut placed on your desktop. -NOTE: +NOTE: `winget` should, theoretically, install the ASP .NET Core 6.0 Runtime as a pre-reqiusite. At the time of this writing, this functionality is untested (TODO). If the runtime isn't automatically installed for you, see above or below for steps on how to download and install it manually. From bcf3bb4a37f0877ca92bce325f72a1d0a1a74fd4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 14:39:43 -0400 Subject: [PATCH 083/160] Make winget the first choice for installation --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index fa61ba5b9f..6e2e4e77c0 100644 --- a/README.md +++ b/README.md @@ -26,14 +26,6 @@ Follow the instructions for your OS below. #### Windows -##### Installer - -If you don't have it installed already, download and install the [ASP .NET Core Runtime (>= v6.0)](https://dotnet.microsoft.com/download/dotnet/6.0). Ensure that the `dotnet` executable file is in your system's `PATH` variable (or that of the user's that will be running the server). You can test this by opening a command prompt and running `dotnet --list-runtimes`. - -You should also ensure that your .NET Framework runtime version is >= v4.7.2. Most modern systems have it by default so this isn't much of a concern. If, somehow, you don't have it installed, it can be downloaded [here](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net472). - -[Download the latest release .msi](https://github.com/tgstation/tgstation-server/releases/latest). Executing it will take you through the process of installing and configuring your server. - ##### winget If you have [winget](https://github.com/microsoft/winget-cli) installed. You can easily install the latest version of tgstation-server (provided Microsoft has approved the most recent package manifest). @@ -52,7 +44,15 @@ You won't be prompted to run the setup wizard. However, you can do so immediatel NOTE: -`winget` should, theoretically, install the ASP .NET Core 6.0 Runtime as a pre-reqiusite. At the time of this writing, this functionality is untested (TODO). If the runtime isn't automatically installed for you, see above or below for steps on how to download and install it manually. +`winget` should, theoretically, install the ASP .NET Core 6.0 Runtime as a pre-reqiusite. At the time of this writing, this functionality is untested (TODO). If the runtime isn't automatically installed for you, see below for steps on how to download and install it manually. + +##### Installer + +If you don't have it installed already, download and install the [ASP .NET Core Runtime (>= v6.0)](https://dotnet.microsoft.com/download/dotnet/6.0). Ensure that the `dotnet` executable file is in your system's `PATH` variable (or that of the user's that will be running the server). You can test this by opening a command prompt and running `dotnet --list-runtimes`. + +You should also ensure that your .NET Framework runtime version is >= v4.7.2. Most modern systems have it by default so this isn't much of a concern. If, somehow, you don't have it installed, it can be downloaded [here](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net472). + +[Download the latest release .msi](https://github.com/tgstation/tgstation-server/releases/latest). Executing it will take you through the process of installing and configuring your server. ##### Manual From 009a9301380227cecea8ea9aaf8e6e46f9c05d2f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 14:44:19 -0400 Subject: [PATCH 084/160] Fix trigger for `check-winget-pr-template` --- .github/workflows/ci-pipeline.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index a618c35eb1..45fa220989 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1058,6 +1058,7 @@ jobs: check-winget-pr-template: name: Check winget-pkgs Pull Request Template is up to date needs: start-ci-run-gate + if: "!(cancelled() || failure()) && needs.start-ci-run-gate.result == 'success'" runs-on: ubuntu-latest steps: - name: Setup dotnet From 7c62bdd6ab46944fb4a48391b99bf728b2d42274 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 14:56:39 -0400 Subject: [PATCH 085/160] Fix `check-winget-pr-template` SHA parsing --- .github/workflows/ci-pipeline.yml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 45fa220989..8c6d8583a5 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1066,15 +1066,11 @@ jobs: with: dotnet-version: ${{ env.TGS_DOTNET_VERSION }} - - name: Retrieve winget-pkgs PULL_REQUEST_TEMPLATE commit history from GitHub API - id: get-json - run: | - echo "commits-response=$(curl -L -u "${{ vars.DEV_PUSH_USERNAME }}:${{ secrets.DEV_PUSH_TOKEN }}" -H "Accept: application/vnd.github.everest-preview+json" -H "Content-Type: application/json" https://api.github.com/repos/microsoft/winget-pkgs/commits?path=.github/PULL_REQUEST_TEMPLATE.md)" >> $GITHUB_OUTPUT - - - name: Output Latest SHA for winget-pkgs PULL_REQUEST_TEMPLATE + - name: Retrieve Latest winget-pkgs PULL_REQUEST_TEMPLATE commit SHA from GitHub API id: get-sha run: | - echo "pr_template_sha=$(echo ${{ steps.get-json.outputs.commits-response[0].sha }})" >> $GITHUB_OUTPUT + curl -L -u "${{ vars.DEV_PUSH_USERNAME }}:${{ secrets.DEV_PUSH_TOKEN }}" -H "Accept: application/vnd.github.everest-preview+json" -H "Content-Type: application/json" -o commits.json https://api.github.com/repos/microsoft/winget-pkgs/commits?path=.github/PULL_REQUEST_TEMPLATE.md + echo "pr_template_sha=$(cat commits.json | jq '.[0].sha')" >> $GITHUB_OUTPUT - name: Checkout (Branch) uses: actions/checkout@v3 @@ -1438,7 +1434,7 @@ jobs: - name: Trigger tgstation-ppa workflow run: | - curl -XPOST -u "${{ vars.DEV_PUSH_USERNAME }}:${{ secrets.DEV_PUSH_TOKEN }}" -H "Accept: application/vnd.github.everest-preview+json" -H "Content-Type: application/json" https://api.github.com/repos/tgstation/tgstation-ppa/actions/workflows/add_tgs_version.yml/dispatches --data '{"ref":"main","inputs":{"tgs_semver": "${{ env.TGS_VERSION }}"}}' + curl -XPOST -u "${{ vars.DEV_PUSH_USERNAME }}:${{ secrets.DEV_PUSH_TOKEN }}" -H "Accept: application/vnd.github.everest-preview+json" -H "Content-Type: application/json" https://api.github.com/repos/tgstation/tgstation-ppa/actions/workflows/add_tgs_version.yml/dispatches --data '{"ref":"main","inputs":{"tgs_semver": "${{ env.TGS_VERSION }}"} deploy-winget: name: Deploy TGS (winget) From f48076899619c5a828e2fd1dc87988f9f9a9d3f6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 15:46:07 -0400 Subject: [PATCH 086/160] Forgot we were checking the exit codes here --- .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 8c6d8583a5..2d5f742e45 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1008,7 +1008,7 @@ jobs: run: | $file = [System.IO.Path]::GetFullPath("packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi") $log = [System.IO.Path]::GetFullPath("install.log") - Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru -Wait + $procMain = Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru -Wait if (Test-Path -Path $log -PathType Leaf) { Get-Content $log } @@ -1034,7 +1034,7 @@ jobs: run: | $file = [System.IO.Path]::GetFullPath("packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi") $log = [System.IO.Path]::GetFullPath("uninstall.log") - Start-Process "msiexec" "/x `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru -Wait + $procMain = Start-Process "msiexec" "/x `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru -Wait if (Test-Path -Path $log -PathType Leaf) { Get-Content $log } From 7455c0cb913d9385368d34e9f64d1899f623a8f0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 17:08:35 -0400 Subject: [PATCH 087/160] Fix invocations of dotnet for ReleaseNotes --- .github/workflows/ci-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 2d5f742e45..d93f8711ad 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1457,7 +1457,7 @@ jobs: uses: actions/checkout@v3 - name: Build ReleaseNotes - run: dotnet build -c Release --project tools/ReleaseNotes + run: dotnet build -c Release tools/ReleaseNotes - name: Retrieve .msi uses: actions/download-artifact@v3 From c4fb8b8247ca9d4711856244362787d41f33fe15 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 17:31:33 -0400 Subject: [PATCH 088/160] Fix race condition when in TriggerHealthCheck --- src/Tgstation.Server.Host/Swarm/SwarmService.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Swarm/SwarmService.cs b/src/Tgstation.Server.Host/Swarm/SwarmService.cs index a1368f9c30..8c4d66122c 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmService.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmService.cs @@ -1158,8 +1158,7 @@ namespace Tgstation.Server.Host.Swarm /// the result of the call to . bool TriggerHealthCheck() { - var currentTcs = forceHealthCheckTcs; - forceHealthCheckTcs = new TaskCompletionSource(); + var currentTcs = Interlocked.Exchange(ref forceHealthCheckTcs, new TaskCompletionSource()); return currentTcs.TrySetResult(); } From fa10d59c338707c3b22f7bf981478e3f58a5d082 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 18:28:41 -0400 Subject: [PATCH 089/160] Soften the stance towards SQLite --- README.md | 20 ++++++++++++++++++- .../Setup/SetupWizard.cs | 13 ++---------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 6e2e4e77c0..d3e1f8d084 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,25 @@ Older server versions can be found in the V# branches of this repository. Note t ### Pre-Requisites -- A [MariaDB](https://downloads.mariadb.org/), MySQL, [PostgresSQL](https://www.postgresql.org/download/), or [Microsoft SQL Server](https://www.microsoft.com/en-us/download/details.aspx?id=55994) database engine is required +tgstation-server needs a relational database to store it's data. + +If you're just a hobbyist server host, you can probably get away with using SQLite for this. SQLite is bundled with TGS and simply requires you to specify where on your machine you want to store the data. + +_HOWEVER_ + +SQLite is not a battle-ready relational database. It doesn't scale well for any use case. TGS *strongly* recommends you use one of its supported standalone databases. Setting one of these up is more involved but worth the effort. + +The supported standalone databases are: + +- [MariaDB](https://downloads.mariadb.org/) _- NOTE: If you plan on hosting SpaceStation 13, this is the database most codebases support, making it an ideal choice_ +- [PostgresSQL](https://www.postgresql.org/download/) +- [Microsoft SQL Server](https://www.microsoft.com/en-us/download/details.aspx?id=55994) +- MySQL + +TGS will require either: +- No pre-existing database WITH schema creation permissions. +or +- Exclusive access to a database schema that TGS has full control over. ### Installation diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index f5e4deb0f8..c0fbbbb042 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -348,22 +348,13 @@ namespace Tgstation.Server.Host.Setup { await console.WriteAsync(String.Empty, true, cancellationToken); await console.WriteAsync( - "NOTE: It is HIGHLY reccommended that TGS runs on a complete relational database, specfically *NOT* Sqlite.", + "NOTE: If you are serious about hosting public servers, it is HIGHLY reccommended that TGS runs on a database *OTHER THAN* Sqlite.", true, cancellationToken); await console.WriteAsync( - "Sqlite, by nature cannot perform several DDL operations. Because of this future compatiblility cannot be guaranteed.", + "It is, however, the easiest option to get started with and will pose few if any problems in a single user scenario.", true, cancellationToken); - await console.WriteAsync( - "This means that you may not be able to update to the next minor version of TGS without a clean re-installation!", - true, - cancellationToken); - await console.WriteAsync( - "Please consider taking the time to set up a relational database if this is meant to be a long-standing server.", - true, - cancellationToken); - await console.WriteAsync(String.Empty, true, cancellationToken); await asyncDelayer.Delay(TimeSpan.FromSeconds(3), cancellationToken); } From 7a70695e9bf2a760c6eb4c7355ada23343b73dd6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 19:05:20 -0400 Subject: [PATCH 090/160] Enable winget LocalManifestFiles --- .github/workflows/ci-pipeline.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index d93f8711ad..3bb8af3087 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1453,6 +1453,9 @@ jobs: - name: Install wingetcreate run: winget install wingetcreate --disable-interactivity --accept-source-agreements + - name: Enable LocalManifestFiles + run: winget settings --enable LocalManifestFiles + - name: Checkout uses: actions/checkout@v3 From a60a51eb8b7e6e918dba1b958c3f0ef43fd89c49 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 23:17:09 -0400 Subject: [PATCH 091/160] Fix issues with ReleaseNotes --link-winget --- tools/ReleaseNotes/Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/ReleaseNotes/Program.cs b/tools/ReleaseNotes/Program.cs index 8c5904704b..12874a308a 100644 --- a/tools/ReleaseNotes/Program.cs +++ b/tools/ReleaseNotes/Program.cs @@ -547,7 +547,7 @@ The user account that created this pull request is available to correct any issu var userPrsOnWingetRepo = await client.Search.SearchIssues(new SearchIssuesRequest { - Author = clientUser.Name, + Author = clientUser.Login, Is = new List { IssueIsQualifier.PullRequest }, State = ItemState.Open, Repos = new RepositoryCollection @@ -563,7 +563,7 @@ The user account that created this pull request is available to correct any issu return 31; } - await client.Issue.Update(prToModify.Repository.Id, prToModify.Number, new IssueUpdate + await client.Issue.Update("microsoft", "winget-pkgs", prToModify.Number, new IssueUpdate { Body = prBody, }); From 99236112955f80c37d34c5b996ca1aebcfaaf6f7 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 23:20:11 -0400 Subject: [PATCH 092/160] Verbegging --- tools/ReleaseNotes/Program.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/ReleaseNotes/Program.cs b/tools/ReleaseNotes/Program.cs index 12874a308a..94a58bdb58 100644 --- a/tools/ReleaseNotes/Program.cs +++ b/tools/ReleaseNotes/Program.cs @@ -521,6 +521,8 @@ This pull request was generated by our [deployment pipeline]({actionUrl}) as a r The user account that created this pull request is available to correct any issues. +**_We would like to be verified as the publisher of this software but we cannot find documentation on how to do so._** + - [x] Have you signed the [Contributor License Agreement](https://cla.opensource.microsoft.com/microsoft/winget-pkgs)? - [x] Have you checked that there aren't other open [pull requests](https://github.com/microsoft/winget-pkgs/pulls) for the same manifest update/change? - This PR is generated as a direct result of a new release of `tgstation-server` this should be impossible From bbc17a62cfa474bbba2d8486afd481b1ae4a4c4c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 23:55:45 -0400 Subject: [PATCH 093/160] Publish configure project with runtime identifier Give it its own directory too because it's chonky now --- .../Program.cs | 3 ++- ...station.Server.Host.Service.Configure.csproj | 1 + .../Tgstation.Server.Host.Service.Msi.vdproj | 17 ++++++++++++++--- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs b/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs index 9de5d54edd..4f36aa3890 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs +++ b/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs @@ -10,7 +10,8 @@ using System.Windows.Forms; using var process = new Process(); var installDir = Path.GetDirectoryName( - Assembly.GetExecutingAssembly().Location)!; + Path.GetDirectoryName( + Assembly.GetExecutingAssembly().Location))!; process.StartInfo.WorkingDirectory = installDir; process.StartInfo.FileName = Path.Combine( diff --git a/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj b/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj index af4c4af760..2fabb8e117 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj @@ -3,6 +3,7 @@ WinExe net6.0-windows + win-x86 true enable ../../../uac_elevation_manifest.xml diff --git a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj index e0c4b6f0c0..14ac7a6978 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj @@ -257,6 +257,17 @@ "Property" = "8:TARGETDIR" "Folders" { + "{9EF0B969-E518-4E46-987F-47570745A589}:_0CFAD254CCC645209154DD4D85649AEA" + { + "Name" = "8:configure" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:_21324B7571BE4E9E8B14F4D2BD470581" + "Folders" + { + } + } "{9EF0B969-E518-4E46-987F-47570745A589}:_D8FD06A5721D4746BD1D087E6329F3CF" { "Name" = "8:lib" @@ -880,7 +891,7 @@ { "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_11E0E9B45549402D92B039FCCD0783B8" { - "SourcePath" = "8:..\\..\\..\\..\\src\\Tgstation.Server.Host\\obj\\Release\\net6.0\\apphost.exe" + "SourcePath" = "8:..\\..\\..\\..\\src\\Tgstation.Server.Host\\obj\\Installer\\net6.0\\apphost.exe" "TargetName" = "8:" "Tag" = "8:" "Folder" = "8:_44E17B6EBB30432E9D4FBB976D7E029A" @@ -994,10 +1005,10 @@ } "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_E9F7402DCE77463F9B7319647D3C16F2" { - "SourcePath" = "8:..\\Tgstation.Server.Host.Service.Configure\\obj\\Release\\net6.0-windows\\apphost.exe" + "SourcePath" = "8:..\\Tgstation.Server.Host.Service.Configure\\obj\\Release\\net6.0-windows\\win-x86\\apphost.exe" "TargetName" = "8:" "Tag" = "8:" - "Folder" = "8:_B28C4FD80D0245E08AEDCFEECACB6493" + "Folder" = "8:_0CFAD254CCC645209154DD4D85649AEA" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" From 61644065c051e78ae8afc6adf159bc1e18d4f410 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 28 Jun 2023 19:15:39 -0400 Subject: [PATCH 094/160] Remove net472 Dependency - Replace service message boxes with P/Invoke. - Replace service installer with `sc.exe` invocations. - Add automatic UAC elevation to service. - Remove unneeded GlobalSuppressions.cs. - Upgrade Host.Watchdog/Host.Service/Host.Common/Host.Service.Tests to net6.0(-windows). - Update docs. --- .github/CONTRIBUTING.md | 2 +- README.md | 4 - .../Tgstation.Server.Host.Common.csproj | 2 +- .../GlobalSuppressions.cs | 11 -- .../NativeMethods.cs | 44 +++++ src/Tgstation.Server.Host.Service/Program.cs | 164 ++++++++---------- .../Tgstation.Server.Host.Service.csproj | 17 +- .../Tgstation.Server.Host.Watchdog.csproj | 2 +- .../Watchdog.cs | 6 +- ...Tgstation.Server.Host.Service.Tests.csproj | 7 +- tools/Tgstation.Server.Migrator/Program.cs | 4 +- 11 files changed, 136 insertions(+), 127 deletions(-) delete mode 100644 src/Tgstation.Server.Host.Service/GlobalSuppressions.cs create mode 100644 src/Tgstation.Server.Host.Service/NativeMethods.cs diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a9eff3af35..7f651ed937 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -34,7 +34,7 @@ You can of course, as always, ask for help at [#coderbus](irc://irc.rizon.net/co ### Development Environment -You need the Dotnet 6.0 SDK and npm>=v5.7 (in your PATH) to compile the server. In order to build the service version you also need a .NET 4.7.2 build chain. In order to build the .msi installer, you'll need [Visual Studio 2022](https://visualstudio.microsoft.com/vs/) or greater and the [Visual Studio Installer Projects Extension](https://marketplace.visualstudio.com/items?itemName=VisualStudioClient.MicrosoftVisualStudio2022InstallerProjects). +You need the Dotnet 6.0 SDK and npm>=v5.7 (in your PATH) to compile the server. In order to build the service version you need a to run on Windows. In order to build the .msi installer, you'll need [Visual Studio 2022](https://visualstudio.microsoft.com/vs/) or greater and the [Visual Studio Installer Projects Extension](https://marketplace.visualstudio.com/items?itemName=VisualStudioClient.MicrosoftVisualStudio2022InstallerProjects). The recommended IDE is Visual Studio 2019 which has installation options for both of these. diff --git a/README.md b/README.md index d3e1f8d084..7c24120d7f 100644 --- a/README.md +++ b/README.md @@ -68,16 +68,12 @@ NOTE: If you don't have it installed already, download and install the [ASP .NET Core Runtime (>= v6.0)](https://dotnet.microsoft.com/download/dotnet/6.0). Ensure that the `dotnet` executable file is in your system's `PATH` variable (or that of the user's that will be running the server). You can test this by opening a command prompt and running `dotnet --list-runtimes`. -You should also ensure that your .NET Framework runtime version is >= v4.7.2. Most modern systems have it by default so this isn't much of a concern. If, somehow, you don't have it installed, it can be downloaded [here](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net472). - [Download the latest release .msi](https://github.com/tgstation/tgstation-server/releases/latest). Executing it will take you through the process of installing and configuring your server. ##### Manual If you don't have it installed already, download and install the [ASP .NET Core Runtime (>= v6.0)](https://dotnet.microsoft.com/download/dotnet/6.0). Ensure that the `dotnet` executable file is in your system's `PATH` variable (or that of the user's that will be running the server). You can test this by opening a command prompt and running `dotnet --list-runtimes`. -You should also ensure that your .NET Framework runtime version is >= v4.7.2. Most modern systems have it by default so this isn't much of a concern. If, somehow, you don't have it installed, it can be downloaded [here](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net472). - [Download the latest release .zip](https://github.com/tgstation/tgstation-server/releases/latest). You probably want the `ServerService` package. Choose `ServerConsole` if you prefer not to use the Windows service. Extract the .zip file to where you want the server to run from. Note the account running the server must have write and delete access to the `lib` subdirectory. diff --git a/src/Tgstation.Server.Host.Common/Tgstation.Server.Host.Common.csproj b/src/Tgstation.Server.Host.Common/Tgstation.Server.Host.Common.csproj index dbe6263f1d..92e7dae859 100644 --- a/src/Tgstation.Server.Host.Common/Tgstation.Server.Host.Common.csproj +++ b/src/Tgstation.Server.Host.Common/Tgstation.Server.Host.Common.csproj @@ -2,7 +2,7 @@ - netstandard2.0 + $(TgsNetVersion) $(TgsCoreVersion) false true diff --git a/src/Tgstation.Server.Host.Service/GlobalSuppressions.cs b/src/Tgstation.Server.Host.Service/GlobalSuppressions.cs deleted file mode 100644 index 7771d518bc..0000000000 --- a/src/Tgstation.Server.Host.Service/GlobalSuppressions.cs +++ /dev/null @@ -1,11 +0,0 @@ -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2232:MarkWindowsFormsEntryPointsWithStaThread", Justification = "No don't, it breaks shit")] - -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. -// -// To add a suppression to this file, right-click the message in the -// Code Analysis results, point to "Suppress Message", and click -// "In Suppression File". -// You do not need to add suppressions to this file manually. diff --git a/src/Tgstation.Server.Host.Service/NativeMethods.cs b/src/Tgstation.Server.Host.Service/NativeMethods.cs new file mode 100644 index 0000000000..f6a9dc739e --- /dev/null +++ b/src/Tgstation.Server.Host.Service/NativeMethods.cs @@ -0,0 +1,44 @@ +using System.Runtime.InteropServices; + +namespace Tgstation.Server.Host.Service +{ + /// + /// Native methods used by the code. + /// + static class NativeMethods + { + /// + /// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox. + /// + public enum MessageBoxButtons : uint + { + /// + /// The message box contains two push buttons: Yes and No. + /// + YesNo = 0x00000004, + } + + /// + /// The result of a call to . + /// + public enum DialogResult : int + { + /// + /// The Yes button was selected. + /// + Yes = 6, + } + + /// + /// Displays a modal dialog box that contains a system icon, a set of buttons, and a brief application-specific message, such as status or error information. The message box returns an integer value that indicates which button the user clicked. + /// + /// A handle to the owner window of the message box to be created. If this parameter is NULL, the message box has no owner window. + /// The message to be displayed. If the string consists of more than one line, you can separate the lines using a carriage return and/or linefeed character between each line. + /// The dialog box title. If this parameter is NULL, the default title is Error. + /// The . + /// The resulting . + /// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox. + [DllImport("user32.dll", CharSet = CharSet.Unicode)] + public static extern DialogResult MessageBox(HandleRef hWnd, string text, string caption, MessageBoxButtons type); + } +} diff --git a/src/Tgstation.Server.Host.Service/Program.cs b/src/Tgstation.Server.Host.Service/Program.cs index 0ff0dda89c..7d365e7ad6 100644 --- a/src/Tgstation.Server.Host.Service/Program.cs +++ b/src/Tgstation.Server.Host.Service/Program.cs @@ -1,15 +1,10 @@ using System; -using System.Collections.Specialized; -using System.Configuration.Install; using System.Diagnostics; -using System.Globalization; -using System.Linq; +using System.IO; using System.Reflection; -using System.Security.Principal; using System.ServiceProcess; using System.Threading; using System.Threading.Tasks; -using System.Windows.Forms; using McMaster.Extensions.CommandLineUtils; @@ -86,17 +81,6 @@ namespace Tgstation.Server.Host.Service [Option(ShortName = "d")] public bool Debug { get; set; } - /// - /// Check if the running user is a system administrator. - /// - /// if the running user is a system administrator, otherwise. - static bool IsAdministrator() - { - var user = WindowsIdentity.GetCurrent(); - var principal = new WindowsPrincipal(user); - return principal.IsInRole(WindowsBuiltInRole.Administrator); - } - /// /// Entrypoint for the application. /// @@ -104,6 +88,32 @@ namespace Tgstation.Server.Host.Service /// A resulting in the 's exit code. static Task Main(string[] args) => CommandLineApplication.ExecuteAsync(args); + /// + /// Runs sc.exe to either uninstall a given or install the running . + /// + /// The name of a service to uninstall. + /// A representing the running operation. + static async ValueTask InvokeSC(string serviceToUninstall) + { + using var process = new Process(); + process.StartInfo.FileName = "C:/Windows/System32/sc.exe"; + + var fullPathToAssembly = Path.GetFullPath( + Assembly.GetExecutingAssembly().Location); + + var assemblyDirectory = Path.GetDirectoryName(fullPathToAssembly); + var assemblyNameWithoutExtension = Path.GetFileNameWithoutExtension(fullPathToAssembly); + var exePath = Path.Combine(assemblyDirectory, $"{assemblyNameWithoutExtension}.exe"); + + process.StartInfo.Arguments = serviceToUninstall == null + ? $"create tgstation-server binPath=\"{exePath}\" start=auto depend=Tcpip/Dhcp/Dnscache" + : $"delete {serviceToUninstall}"; + + process.Start(); + + await process.WaitForExitAsync(); + } + /// /// Command line handler, always runs. /// @@ -112,34 +122,19 @@ namespace Tgstation.Server.Host.Service { var standardRun = !Install && !Uninstall && !Configure; - if (Environment.UserInteractive) + if (Environment.UserInteractive && standardRun) { - if (standardRun) - { - var result = MessageBox.Show("You are running the TGS windows service executable directly. It should only be run by the service control manager. Would you like to install and configure the service in this location?", "TGS Service", MessageBoxButtons.YesNo); - if (result != DialogResult.Yes) - return; - Install = true; - Configure = true; - } + var result = NativeMethods.MessageBox( + default, + "You are running the TGS windows service executable directly. It should only be run by the service control manager. Would you like to install and configure the service in this location?", + "TGS Service", + NativeMethods.MessageBoxButtons.YesNo); - if (!IsAdministrator()) - { - // try to restart as admin - // its windows, first arg is .exe name guaranteed - var args = Environment.GetCommandLineArgs(); - var exe = args.First(); - var startInfo = new ProcessStartInfo - { - UseShellExecute = true, - Verb = "runas", - Arguments = String.Join(" ", args.Skip(1)), - FileName = exe, - WorkingDirectory = Environment.CurrentDirectory, - }; - using (Process.Start(startInfo)) - return; - } + if (result != NativeMethods.DialogResult.Yes) + return; + + Install = true; + Configure = true; } if (Configure) @@ -148,21 +143,19 @@ namespace Tgstation.Server.Host.Service bool stopped = false; if (Uninstall) { - using (var installer = new ServiceInstaller()) - { - installer.Context = new InstallContext("tgs-uninstall.log", null); - if (Silent) - installer.Context.Parameters["LogToConsole"] = false.ToString(); - - installer.ServiceName = ServerService.Name; - installer.Uninstall(null); - } + foreach (ServiceController sc in ServiceController.GetServices()) + if (sc.ServiceName == ServerService.Name) + { + RestartService(sc); + await InvokeSC(ServerService.Name); + break; + } stopped = true; } if (Install) - stopped |= RunServiceInstall(); + stopped |= await RunServiceInstall(); if (standardRun) { @@ -185,53 +178,36 @@ namespace Tgstation.Server.Host.Service /// /// Attempt to install the TGS Service. /// - /// if the service was stopped or detached as a result, otherwise. - bool RunServiceInstall() + /// A resulting in if the service was stopped or detached as a result, otherwise. + async ValueTask RunServiceInstall() { // First check if the service already exists bool serviceStopped = false; if (Force || Environment.UserInteractive) foreach (ServiceController sc in ServiceController.GetServices()) - if (sc.ServiceName == ServerService.Name || sc.ServiceName == "tgstation-server-4") + { + var serviceName = sc.ServiceName; + if (serviceName == ServerService.Name || serviceName == "tgstation-server-4") { - DialogResult result = !Force - ? MessageBox.Show($"You already have another TGS service installed ({sc.ServiceName}). Would you like to uninstall it now? Pressing \"No\" will cancel this install.", "TGS Service", MessageBoxButtons.YesNo) - : DialogResult.Yes; - if (result != DialogResult.Yes) + NativeMethods.DialogResult result = !Force + ? NativeMethods.MessageBox( + default, + $"You already have another TGS service installed ({sc.ServiceName}). Would you like to uninstall it now? Pressing \"No\" will cancel this install.", + "TGS Service", + NativeMethods.MessageBoxButtons.YesNo) + : NativeMethods.DialogResult.Yes; + if (result != NativeMethods.DialogResult.Yes) return false; // is this needed after exit? // Stop it first to give it some cleanup time RestartService(sc); // And remove it - using var serviceInstaller = new ServiceInstaller(); - serviceInstaller.Context = new InstallContext($"old-{sc.ServiceName}-uninstall.log", null); - - if (Silent) - serviceInstaller.Context.Parameters["LogToConsole"] = false.ToString(); - - serviceInstaller.ServiceName = sc.ServiceName; - serviceInstaller.Uninstall(null); - - serviceStopped = true; + await InvokeSC(sc.ServiceName); } + } - using var processInstaller = new ServiceProcessInstaller(); - using var installer = new ServiceInstaller(); - processInstaller.Account = ServiceAccount.LocalSystem; - - installer.Context = new InstallContext("tgs-install.log", new string[] { String.Format(CultureInfo.InvariantCulture, "/assemblypath={0}", Assembly.GetEntryAssembly().Location) }); - if (Silent) - installer.Context.Parameters["LogToConsole"] = false.ToString(); - installer.Description = "tgstation-server running as a windows service"; - installer.DisplayName = ServerService.Name; - installer.StartType = ServiceStartMode.Automatic; - installer.ServicesDependedOn = new string[] { "Tcpip", "Dhcp", "Dnscache" }; - installer.ServiceName = ServerService.Name; - installer.Parent = processInstaller; - - var state = new ListDictionary(); - installer.Install(state); + await InvokeSC(null); return serviceStopped; } @@ -245,15 +221,23 @@ namespace Tgstation.Server.Host.Service if (serviceController.Status != ServiceControllerStatus.Running) return; - if (Detach) + var stop = !Detach; + if (!stop) + { serviceController.ExecuteCommand( ServerService.GetCommand( PipeCommands.CommandDetachingShutdown) .Value); - else - serviceController.Stop(); + serviceController.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30)); + if (serviceController.Status != ServiceControllerStatus.Stopped) + stop = true; + } - serviceController.WaitForStatus(ServiceControllerStatus.Stopped); + if (stop) + { + serviceController.Stop(); + serviceController.WaitForStatus(ServiceControllerStatus.Stopped); + } } /// diff --git a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj index d8200f9ecc..8cbff0695e 100644 --- a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj +++ b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj @@ -2,14 +2,16 @@ - Exe - net472 - win + WinExe + $(TgsNetVersion)-windows $(TgsCoreVersion) true + + false ../../build/analyzers.ruleset bin/$(Configuration)/$(TargetFramework)/$(RuntimeIdentifier)/$(AssemblyName).xml ../../build/tgs.ico + ../../build/uac_elevation_manifest.xml @@ -35,6 +37,7 @@ + @@ -43,11 +46,7 @@ + - - - - - - + diff --git a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj index 0277b02fdd..633515ec07 100644 --- a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj +++ b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj @@ -2,7 +2,7 @@ - netstandard2.0 + $(TgsNetVersion) Full false $(TgsHostWatchdogVersion) diff --git a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs index 26bac6d658..f4fa2ab1b0 100644 --- a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs @@ -81,10 +81,10 @@ namespace Tgstation.Server.Host.Watchdog var sourcePath = "../../../../Tgstation.Server.Host/bin/Debug/net6.0"; foreach (string dirPath in Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories)) - Directory.CreateDirectory(dirPath.Replace(sourcePath, defaultAssemblyPath)); + Directory.CreateDirectory(dirPath.Replace(sourcePath, defaultAssemblyPath, StringComparison.Ordinal)); foreach (string newPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories)) - File.Copy(newPath, newPath.Replace(sourcePath, defaultAssemblyPath), true); + File.Copy(newPath, newPath.Replace(sourcePath, defaultAssemblyPath, StringComparison.Ordinal), true); const string AppSettingsYaml = "appsettings.yml"; var rootYaml = Path.Combine(rootLocation, AppSettingsYaml); @@ -97,7 +97,7 @@ namespace Tgstation.Server.Host.Watchdog var assemblyName = String.Join(".", nameof(Tgstation), nameof(Server), nameof(Host), "dll"); var assemblyPath = Path.Combine(defaultAssemblyPath, assemblyName); - if (assemblyPath.Contains("\"")) + if (assemblyPath.Contains('"', StringComparison.Ordinal)) { logger.LogCritical("Running from paths with \"'s in the name is not supported!"); return false; diff --git a/tests/Tgstation.Server.Host.Service.Tests/Tgstation.Server.Host.Service.Tests.csproj b/tests/Tgstation.Server.Host.Service.Tests/Tgstation.Server.Host.Service.Tests.csproj index 721a869ca1..ddd3745a96 100644 --- a/tests/Tgstation.Server.Host.Service.Tests/Tgstation.Server.Host.Service.Tests.csproj +++ b/tests/Tgstation.Server.Host.Service.Tests/Tgstation.Server.Host.Service.Tests.csproj @@ -1,7 +1,8 @@ + - net472 + $(TgsNetVersion)-windows @@ -29,8 +30,4 @@ - - - - diff --git a/tools/Tgstation.Server.Migrator/Program.cs b/tools/Tgstation.Server.Migrator/Program.cs index 5f7fb006c1..e0760c9d77 100644 --- a/tools/Tgstation.Server.Migrator/Program.cs +++ b/tools/Tgstation.Server.Migrator/Program.cs @@ -225,8 +225,8 @@ try Directory.CreateDirectory(tgsInstallPath); // ASP.NET 6.0 RUNTIME CHECK - Console.WriteLine("Next step, we need to ensure the .NET 4.7.2 and ASP.NET Core 6 runtimes are installed on your machine."); - Console.WriteLine("We are assuming you already have .NET 4.7.2 installed if you're running TGS3 and this program. So we're going to download .NET 6 for you."); + Console.WriteLine("Next step, we need to ensure the ASP.NET Core 6 runtime is installed on your machine."); + Console.WriteLine("We're going to download it for you."); Console.WriteLine("Yes, this program runs .NET 6, but it contains the entire runtime embedded into it. You will need a system-wide install for TGS."); var runtimeInstalled = true; // assume for now From 5bf73b8ef1f2baa244d0536739960a8825bd89b0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 28 Jun 2023 19:19:24 -0400 Subject: [PATCH 095/160] Prevent Host and Host.Console projects from generating executables --- .github/workflows/ci-pipeline.yml | 4 ---- build/package/deb/debian/rules | 2 -- .../Tgstation.Server.Host.Console.csproj | 2 +- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 1 + 4 files changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 3bb8af3087..17341c5168 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -429,7 +429,6 @@ jobs: cd ../Tgstation.Server.Host dotnet publish -c ${{ matrix.configuration }} --no-build -o ../../Artifacts/Service/lib/Default mv ../../Artifacts/Service/lib/Default/appsettings.yml ../../Artifacts/Service/appsettings.yml - rm ../../Artifacts/Service/lib/Default/Tgstation.Server.Host.exe - name: Store Server Service if: ${{ matrix.configuration == 'Release' && matrix.watchdog-type == 'Basic' }} @@ -585,8 +584,6 @@ jobs: cd ../Tgstation.Server.Host dotnet publish -c ${{ matrix.configuration }}NoFramework --no-build -o ../../Artifacts/Console/lib/Default mv ../../Artifacts/Console/lib/Default/appsettings.yml ../../Artifacts/Console/appsettings.yml - rm ../../Artifacts/Console/lib/Default/Tgstation.Server.Host - rm ../../Artifacts/Console/Tgstation.Server.Host.Console - name: Package Server Update Package if: ${{ matrix.configuration == 'Release' && matrix.watchdog-type == 'System' && matrix.database-type == 'PostgresSql' }} @@ -594,7 +591,6 @@ jobs: cd src/Tgstation.Server.Host dotnet publish -c ${{ matrix.configuration }}NoFramework --no-build -o ../../Artifacts/ServerUpdate rm ../../Artifacts/ServerUpdate/appsettings.yml - rm ../../Artifacts/ServerUpdate/Tgstation.Server.Host - name: Store Server Console if: ${{ matrix.configuration == 'Release' && matrix.watchdog-type == 'System' && matrix.database-type == 'MariaDB' }} diff --git a/build/package/deb/debian/rules b/build/package/deb/debian/rules index 04fd945580..39506708ae 100755 --- a/build/package/deb/debian/rules +++ b/build/package/deb/debian/rules @@ -14,8 +14,6 @@ override_dh_auto_build: cd src/Tgstation.Server.Host.Console && dotnet publish -c Release -o ../../artifacts cd src/Tgstation.Server.Host && dotnet publish -c Release -o ../../artifacts/lib/Default mv artifacts/lib/Default/appsettings.yml artifacts/appsettings.yml - rm artifacts/lib/Default/Tgstation.Server.Host - rm artifacts/Tgstation.Server.Host.Console override_dh_auto_install: cp build/package/deb/MakeInstall ./Makefile diff --git a/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj b/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj index 851f31fb19..1270c970f9 100644 --- a/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj +++ b/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj @@ -5,11 +5,11 @@ Exe $(TgsNetVersion) $(TgsCoreVersion) + false false true ../../build/analyzers.ruleset bin/$(Configuration)/$(TargetFramework)/$(AssemblyName).xml - ../../build/tgs.ico diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 570dda9d41..e7abd5846f 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -6,6 +6,7 @@ $(TgsCoreVersion) true true + false ../../build/analyzers.ruleset bin/$(Configuration)/$(TargetFramework)/$(AssemblyName).xml API1000 From 190a41872229e1759101a3e551c37243abfee457 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 28 Jun 2023 19:20:20 -0400 Subject: [PATCH 096/160] Add UAC elevation to console project --- .../Tgstation.Server.Host.Console.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj b/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj index 1270c970f9..71c3694644 100644 --- a/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj +++ b/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj @@ -10,6 +10,7 @@ true ../../build/analyzers.ruleset bin/$(Configuration)/$(TargetFramework)/$(AssemblyName).xml + ../../build/uac_elevation_manifest.xml @@ -48,5 +49,6 @@ + From 629a7a7f73043cd42cd508c842f990a36013db6c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 28 Jun 2023 19:25:38 -0400 Subject: [PATCH 097/160] Correct documentation of `NativeMethods` --- src/Tgstation.Server.Host/System/NativeMethods.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/System/NativeMethods.cs b/src/Tgstation.Server.Host/System/NativeMethods.cs index dacb4351bc..dc5046d133 100644 --- a/src/Tgstation.Server.Host/System/NativeMethods.cs +++ b/src/Tgstation.Server.Host/System/NativeMethods.cs @@ -5,7 +5,7 @@ using System.Text; namespace Tgstation.Server.Host.System { /// - /// Native Windows methods used by the code. + /// Native methods used by the code. /// #pragma warning disable SA1602 #pragma warning disable SA1611 From 4edb87dbc2e96dbe5e76cd199df14d44416ca06f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 28 Jun 2023 19:55:21 -0400 Subject: [PATCH 098/160] Update winget docs & specify right hosting bundle --- README.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 7c24120d7f..5787ea470f 100644 --- a/README.md +++ b/README.md @@ -48,16 +48,12 @@ Follow the instructions for your OS below. If you have [winget](https://github.com/microsoft/winget-cli) installed. You can easily install the latest version of tgstation-server (provided Microsoft has approved the most recent package manifest). -Simply run the following command: +Simply run the following commands: ```sh +winget install Microsoft.DotNet.HostingBundle.6 winget install tgstation-server ``` -If you get an error like `This file does not have an app associated with it for performing this action.` run with the `--silent` flag: -```sh -winget install tgstation-server --silent -``` - You won't be prompted to run the setup wizard. However, you can do so immediately after via the shortcut placed on your desktop. NOTE: @@ -66,13 +62,13 @@ NOTE: ##### Installer -If you don't have it installed already, download and install the [ASP .NET Core Runtime (>= v6.0)](https://dotnet.microsoft.com/download/dotnet/6.0). Ensure that the `dotnet` executable file is in your system's `PATH` variable (or that of the user's that will be running the server). You can test this by opening a command prompt and running `dotnet --list-runtimes`. +If you don't have it installed already, download and install the [ASP .NET Core Runtime Hosting Bundle (>= v6.0)](https://dotnet.microsoft.com/download/dotnet/6.0). Ensure that the `dotnet` executable file is in your system's `PATH` variable (or that of the user's that will be running the server). You can test this by opening a command prompt and running `dotnet --list-runtimes`. [Download the latest release .msi](https://github.com/tgstation/tgstation-server/releases/latest). Executing it will take you through the process of installing and configuring your server. ##### Manual -If you don't have it installed already, download and install the [ASP .NET Core Runtime (>= v6.0)](https://dotnet.microsoft.com/download/dotnet/6.0). Ensure that the `dotnet` executable file is in your system's `PATH` variable (or that of the user's that will be running the server). You can test this by opening a command prompt and running `dotnet --list-runtimes`. +If you don't have it installed already, download and install the [ASP .NET Core Runtime Hosting Bundle (>= v6.0)](https://dotnet.microsoft.com/download/dotnet/6.0). Ensure that the `dotnet` executable file is in your system's `PATH` variable (or that of the user's that will be running the server). You can test this by opening a command prompt and running `dotnet --list-runtimes`. [Download the latest release .zip](https://github.com/tgstation/tgstation-server/releases/latest). You probably want the `ServerService` package. Choose `ServerConsole` if you prefer not to use the Windows service. From 0b2636c9b1513db2ba8f723ce3b5de163d49da65 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 28 Jun 2023 20:09:30 -0400 Subject: [PATCH 099/160] More `winget` docs --- README.md | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5787ea470f..725fc06605 100644 --- a/README.md +++ b/README.md @@ -44,12 +44,29 @@ Follow the instructions for your OS below. #### Windows -##### winget +##### winget (Windows 10 or later) -If you have [winget](https://github.com/microsoft/winget-cli) installed. You can easily install the latest version of tgstation-server (provided Microsoft has approved the most recent package manifest). +[winget](https://github.com/microsoft/winget-cli) installed is the easiest way to install the latest version of tgstation-server (provided Microsoft has approved the most recent package manifest). -Simply run the following commands: -```sh +Check if you have `winget` by running the following command. +``` +winget --version +``` + +If it returns an error that means you don't have winget. You can easily install it by running the following powershell commands: +``` +Invoke-WebRequest -Uri https://www.nuget.org/api/v2/package/Microsoft.UI.Xaml/2.7.3 -OutFile .\microsoft.ui.xaml.2.7.3.zip +Expand-Archive .\microsoft.ui.xaml.2.7.3.zip +Add-AppxPackage .\microsoft.ui.xaml.2.7.3\tools\AppX\x64\Release\Microsoft.UI.Xaml.2.7.appx +Add-AppxPackage -Path "https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx" +Add-AppxPackage -Path "https://github.com/microsoft/winget-cli/releases/latest/download/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle" +Remove-Item .\microsoft.ui.xaml.2.7.3\ -r +Remove-Item .\microsoft.ui.xaml.2.7.3.zip +``` + +Once winget is installed, simply run the following commands, accepting any prompts that may appear: + +```ps winget install Microsoft.DotNet.HostingBundle.6 winget install tgstation-server ``` From 4a2a0ee6b97ffb4845de64d0af1d96f951fcbe75 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 28 Jun 2023 20:12:11 -0400 Subject: [PATCH 100/160] More `winget` documentation updates --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 725fc06605..cabcb02197 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,9 @@ Check if you have `winget` by running the following command. winget --version ``` -If it returns an error that means you don't have winget. You can easily install it by running the following powershell commands: +If it returns an error that means you don't have winget. You can easily install it by running the following Windows Powershell commands: ``` +Import-Module Appx Invoke-WebRequest -Uri https://www.nuget.org/api/v2/package/Microsoft.UI.Xaml/2.7.3 -OutFile .\microsoft.ui.xaml.2.7.3.zip Expand-Archive .\microsoft.ui.xaml.2.7.3.zip Add-AppxPackage .\microsoft.ui.xaml.2.7.3\tools\AppX\x64\Release\Microsoft.UI.Xaml.2.7.appx From 5d1e7bc27ecfd3699ad1cdff43ae02d8f793bbb2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 28 Jun 2023 20:48:16 -0400 Subject: [PATCH 101/160] Remove .NET 4.7.2 prereq from the installer --- .../Tgstation.Server.Host.Service.Msi.vdproj | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj index 14ac7a6978..db8383c96b 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj @@ -75,18 +75,13 @@ "InstallerBootstrapper" = "3:2" "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" { - "Enabled" = "11:TRUE" + "Enabled" = "11:FALSE" "PromptEnabled" = "11:TRUE" "PrerequisitesLocation" = "2:1" "Url" = "8:" "ComponentsUrl" = "8:" "Items" { - "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.7.2" - { - "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)" - "ProductCode" = "8:.NETFramework,Version=v4.7.2" - } } } } @@ -891,7 +886,7 @@ { "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_11E0E9B45549402D92B039FCCD0783B8" { - "SourcePath" = "8:..\\..\\..\\..\\src\\Tgstation.Server.Host\\obj\\Installer\\net6.0\\apphost.exe" + "SourcePath" = "8:" "TargetName" = "8:" "Tag" = "8:" "Folder" = "8:_44E17B6EBB30432E9D4FBB976D7E029A" @@ -977,7 +972,7 @@ } "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_B2B80DADC2EA4646A8E8E8E54F2AE2EE" { - "SourcePath" = "8:" + "SourcePath" = "8:..\\..\\..\\..\\src\\Tgstation.Server.Host.Service\\obj\\Release\\net6.0-windows\\apphost.exe" "TargetName" = "8:" "Tag" = "8:" "Folder" = "8:_B28C4FD80D0245E08AEDCFEECACB6493" From c9a73c2af9997bbf0cbc5ceecd6e8984ebcb0e43 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 03:42:10 -0400 Subject: [PATCH 102/160] Add wix exclusions to .gitignore --- .editorconfig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.editorconfig b/.editorconfig index 5c4a83ecd1..55e95ea69f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,6 +12,14 @@ indent_size = 4 indent_style = space indent_size = 2 +[*.wxs] +indent_style = space +indent_size = 2 + +[*.wixproj] +indent_style = space +indent_size = 2 + [*.dm] indent_style = tab indent_size = 4 From e13aa79efe75aa0c4d2cfd6907f8ef3ae5a9a95d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 03:43:36 -0400 Subject: [PATCH 103/160] Add Wix dotnet-tools.json --- build/package/winget/.config/dotnet-tools.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 build/package/winget/.config/dotnet-tools.json diff --git a/build/package/winget/.config/dotnet-tools.json b/build/package/winget/.config/dotnet-tools.json new file mode 100644 index 0000000000..6d50916bb0 --- /dev/null +++ b/build/package/winget/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "wix": { + "version": "4.0.1", + "commands": [ + "wix" + ] + } + } +} From d0d9e7b2ba33b4991e6822540acf23a032c497fa Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 03:54:39 -0400 Subject: [PATCH 104/160] Switch from `.vdproj` to `.wixproj`s Wix is just better, it drives the fucking Visual Studio installer for gods' sakes. Thankfully, v4 is a whole lot better than v3 in that it's native dotnet tooling. - Added ability to set base path for loading configuration files. - Added Service command descriptions for help text. - New `.exe` installer also installs dotnet dependencies. - New `.msi` properly invokes configure, sets up and controls service, sends detach stop signal on upgrades, and uses ProgramData for configs with appropriate permissions. - Remove .deb symlinks in favor of explicitly setting config directory. - Adjust CI pipeline with new installer changes. - Appropriately bump TGS migrator version. --- .github/workflows/ci-pipeline.yml | 103 +- .github/workflows/code-scanning.yml | 2 +- .gitignore | 1 - build/Common.props | 2 +- build/Version.props | 6 +- build/package/appsettings.GitHub.yml | 23 + build/package/appsettings.Initial.yml | 2 +- build/package/deb/MakeInstall | 2 +- build/package/deb/debian/links | 1 - build/package/deb/debian/rules | 4 +- .../Program.cs | 94 -- ...ation.Server.Host.Service.Configure.csproj | 17 - .../README.md | 3 - .../Tgstation.Server.Host.Service.Msi.vdproj | 1031 ----------------- .../Bundle.wxs | 22 + ...ion.Server.Host.Service.Wix.Bundle.wixproj | 16 + .../CustomAction.config | 7 + .../InstallationExtensions.cs | 76 ++ ....Server.Host.Service.Wix.Extensions.csproj | 27 + .../Package.en-us.wxl | 11 + .../Package.wxs | 86 ++ .../Tgstation.Server.Host.Service.Wix.wixproj | 34 + build/package/winget/build_msi.ps1 | 29 - build/package/winget/installer.sln | 50 - .../manifest/Tgstation.Server.installer.yaml | 12 +- .../prepare_installer_input_artifacts.ps1 | 43 + build/package/winget/push_manifest.ps1 | 2 +- build/tgstation-server.service | 2 +- src/Tgstation.Server.Host.Common/Constants.cs | 13 + .../PipeCommands.cs | 24 +- .../Tgstation.Server.Host.Common.csproj | 2 +- .../Tgstation.Server.Host.Console.csproj | 2 +- src/Tgstation.Server.Host.Service/Program.cs | 146 +-- .../ServerService.cs | 47 +- .../Tgstation.Server.Host.Service.csproj | 5 +- .../Tgstation.Server.Host.Watchdog.csproj | 2 +- .../Configuration/FileLoggingConfiguration.cs | 3 +- .../Configuration/InternalConfiguration.cs | 5 + src/Tgstation.Server.Host/ServerFactory.cs | 20 +- .../Setup/SetupWizard.cs | 34 +- .../Tgstation.Server.Host.csproj | 2 +- .../Tgstation.Server.Api.Tests.csproj | 2 +- .../Tgstation.Server.Client.Tests.csproj | 2 +- ...Tgstation.Server.Host.Console.Tests.csproj | 2 +- .../TestServerService.cs | 7 +- ...Tgstation.Server.Host.Service.Tests.csproj | 2 +- ...Tgstation.Server.Host.Tests.Signals.csproj | 2 +- .../Setup/TestSetupWizard.cs | 47 +- .../Tgstation.Server.Host.Tests.csproj | 2 +- ...gstation.Server.Host.Watchdog.Tests.csproj | 2 +- .../Tgstation.Server.Tests.csproj | 2 +- tgstation-server.sln | 189 +-- tools/ReleaseNotes/ReleaseNotes.csproj | 2 +- tools/Tgstation.Server.Migrator/Program.cs | 8 +- .../Tgstation.Server.Migrator.csproj | 8 +- 55 files changed, 781 insertions(+), 1509 deletions(-) delete mode 100644 build/package/deb/debian/links delete mode 100644 build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs delete mode 100644 build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj delete mode 100644 build/package/winget/Tgstation.Server.Host.Service.Msi/README.md delete mode 100644 build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj create mode 100644 build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Bundle.wxs create mode 100644 build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Tgstation.Server.Host.Service.Wix.Bundle.wixproj create mode 100644 build/package/winget/Tgstation.Server.Host.Service.Wix.Extensions/CustomAction.config create mode 100644 build/package/winget/Tgstation.Server.Host.Service.Wix.Extensions/InstallationExtensions.cs create mode 100644 build/package/winget/Tgstation.Server.Host.Service.Wix.Extensions/Tgstation.Server.Host.Service.Wix.Extensions.csproj create mode 100644 build/package/winget/Tgstation.Server.Host.Service.Wix/Package.en-us.wxl create mode 100644 build/package/winget/Tgstation.Server.Host.Service.Wix/Package.wxs create mode 100644 build/package/winget/Tgstation.Server.Host.Service.Wix/Tgstation.Server.Host.Service.Wix.wixproj delete mode 100644 build/package/winget/build_msi.ps1 delete mode 100644 build/package/winget/installer.sln create mode 100644 build/package/winget/prepare_installer_input_artifacts.ps1 create mode 100644 src/Tgstation.Server.Host.Common/Constants.cs diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 17341c5168..cc5b1d0156 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -240,10 +240,10 @@ jobs: ref: "refs/pull/${{ github.event.number }}/merge" - name: Build - run: dotnet build -c ${{ matrix.configuration }}NoFramework + run: dotnet build -c ${{ matrix.configuration }}NoWindows - name: Run Unit Tests - run: sudo dotnet test --no-build --logger GitHubActions --filter FullyQualifiedName!~TestLiveServer -c ${{ matrix.configuration }}NoFramework --collect:"XPlat Code Coverage" --settings build/coverlet.runsettings --results-directory ./TestResults tgstation-server.sln + run: sudo dotnet test --no-build --logger GitHubActions --filter FullyQualifiedName!~TestLiveServer -c ${{ matrix.configuration }}NoWindows --collect:"XPlat Code Coverage" --settings build/coverlet.runsettings --results-directory ./TestResults tgstation-server.sln - name: Store Code Coverage uses: actions/upload-artifact@v3 @@ -562,13 +562,13 @@ jobs: ref: "refs/pull/${{ github.event.number }}/merge" - name: Build - run: dotnet build -c ${{ matrix.configuration }}NoFramework tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj + run: dotnet build -c ${{ matrix.configuration }}NoWindows tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj - name: Run Live Tests run: | cd tests/Tgstation.Server.Tests sleep 10 - dotnet test -c ${{ matrix.configuration }}NoFramework --filter FullyQualifiedName~TestLiveServer --logger GitHubActions --no-build --collect:"XPlat Code Coverage" --settings ../../build/coverlet.runsettings --results-directory ../../TestResults + dotnet test -c ${{ matrix.configuration }}NoWindows --filter FullyQualifiedName~TestLiveServer --logger GitHubActions --no-build --collect:"XPlat Code Coverage" --settings ../../build/coverlet.runsettings --results-directory ../../TestResults - name: Store Code Coverage uses: actions/upload-artifact@v3 @@ -582,14 +582,14 @@ jobs: cd src/Tgstation.Server.Host.Console dotnet publish -c ${{ matrix.configuration }} -o ../../Artifacts/Console cd ../Tgstation.Server.Host - dotnet publish -c ${{ matrix.configuration }}NoFramework --no-build -o ../../Artifacts/Console/lib/Default + dotnet publish -c ${{ matrix.configuration }}NoWindows --no-build -o ../../Artifacts/Console/lib/Default mv ../../Artifacts/Console/lib/Default/appsettings.yml ../../Artifacts/Console/appsettings.yml - name: Package Server Update Package if: ${{ matrix.configuration == 'Release' && matrix.watchdog-type == 'System' && matrix.database-type == 'PostgresSql' }} run: | cd src/Tgstation.Server.Host - dotnet publish -c ${{ matrix.configuration }}NoFramework --no-build -o ../../Artifacts/ServerUpdate + dotnet publish -c ${{ matrix.configuration }}NoWindows --no-build -o ../../Artifacts/ServerUpdate rm ../../Artifacts/ServerUpdate/appsettings.yml - name: Store Server Console @@ -930,27 +930,24 @@ jobs: - name: Test Install run: | + sudo mkdir /etc/tgstation-server + sudo cp build/package/appsettings.GitHub.yml /etc/tgstation-server/appsettings.Production.yml sudo apt-get install -y ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb sudo ls -al /etc/tgstation-server sudo cat /etc/tgstation-server/appsettings.Production.yml ls -al /opt/tgstation-server - sudo cat /opt/tgstation-server/appsettings.Production.yml cat /opt/tgstation-server/appsettings.yml cat /opt/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json cat /usr/bin/tgs-configure - name: Test Service run: | - set +e systemctl status tgstation-server - $EXIT_CODE=$? - set -e - if [ $EXIT_CODE != 0 ] && [ $EXIT_CODE != '3' ]; then - exit $EXIT_CODE - fi - - name: Test Uninstall + - name: Test Uninstall # Wait 10s for service to initialize + shell: bash run: | + sleep 10 sudo apt-get remove -y tgstation-server if [[ -d "/opt/tgstation-server" ]]; then ls -al /opt/tgstation-server @@ -967,21 +964,19 @@ jobs: path: tgstation-server-v${{ env.TGS_VERSION }}.debian.packaging.tar.xz build-msi: - name: Build .msi Package + name: Build Windows Installer .exe needs: start-ci-run-gate runs-on: windows-latest if: "!(cancelled() || failure()) && needs.start-ci-run-gate.result == 'success'" steps: - - name: Setup VS Dev Environment - uses: seanmiddleditch/gha-setup-vsdevenv@v4 - - - name: Disable Out of Process Building - working-directory: C:/Program Files/Microsoft Visual Studio/2022/Enterprise/Common7/IDE/CommonExtensions/Microsoft/VSI/DisableOutOfProcBuild - run: ./DisableOutOfProcBuild.exe - - name: Install winget uses: Cyberboss/install-winget@v1 + - name: Setup dotnet + uses: actions/setup-dotnet@v2 + with: + dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + - name: Checkout (Branch) uses: actions/checkout@v3 if: github.event_name == 'push' || github.event_name == 'schedule' @@ -995,16 +990,27 @@ jobs: - name: Validate winget Manifest run: winget validate --manifest build/package/winget/manifest - - name: Execute Build Script + - name: Build Service + run: dotnet build -c Release src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj + + - name: Prepare Artifacts shell: powershell - run: build/package/winget/build_msi.ps1 + run: build/package/winget/prepare_installer_input_artifacts.ps1 + + - name: Build Installer + run: | + cd build/package/winget + dotnet tool restore + dotnet build -c Release Tgstation.Server.Service.Wix.Bundle - name: Test Install # Sanity checks the .deps.json exists, which the installation is broken without shell: powershell # If it's missing, I found that in elements were the problem run: | - $file = [System.IO.Path]::GetFullPath("packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi") + mkdir C:/ProgramData/tgstation-server + cp build/package/appsettings.GitHub.yml C:/ProgramData/tgstation-server/appsettings.Production.yml + $file = [System.IO.Path]::GetFullPath("build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin/x86/Release/tgstation-server-installer.exe") $log = [System.IO.Path]::GetFullPath("install.log") - $procMain = Start-Process "msiexec" "/i `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru -Wait + $procMain = Start-Process "$file" "/install /silent /log `"$log`"" -NoNewWindow -PassThru -Wait if (Test-Path -Path $log -PathType Leaf) { Get-Content $log } @@ -1016,6 +1022,9 @@ jobs: if (-Not (Test-Path -Path "C:/Program Files (x86)/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json" -PathType Leaf)) { exit 2 } + if (-Not (Test-Path -Path "C:/ProgramData/tgstation-server/appsettings.Production.json" -PathType Leaf)) { + exit 4 + } - name: Test Service shell: powershell @@ -1024,13 +1033,16 @@ jobs: if ($service.Length -eq 0) { exit 3 } + if ($service[0].Status -ne "Running") { + exit 4 + } - name: Test Uninstall # Sanity checks the .deps.json exists, which the installation is broken without - shell: powershell # If it's missing, I found that in elements were the problem + shell: powershell run: | - $file = [System.IO.Path]::GetFullPath("packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi") + $file = [System.IO.Path]::GetFullPath("build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin/x86/Release/tgstation-server-installer.exe") $log = [System.IO.Path]::GetFullPath("uninstall.log") - $procMain = Start-Process "msiexec" "/x `"$file`" /qn /l*! `"$log`"" -NoNewWindow -PassThru -Wait + $procMain = Start-Process "$file" "/install /silent /log `"$log`"" -NoNewWindow -PassThru -Wait if (Test-Path -Path $log -PathType Leaf) { Get-Content $log } @@ -1045,11 +1057,11 @@ jobs: exit 2 } - - name: Upload .msi + - name: Upload Installer .exe uses: actions/upload-artifact@v3 with: name: packaging-windows - path: packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi + path: build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin/x86/Release/tgstation-server-installer.exe check-winget-pr-template: name: Check winget-pkgs Pull Request Template is up to date @@ -1078,8 +1090,11 @@ jobs: with: ref: "refs/pull/${{ github.event.number }}/merge" + - name: Build ReleaseNotes + run: dotnet build -c Release tools/ReleaseNotes/ReleaseNotes.csproj + - name: Run ReleaseNotes Check - run: dotnet run -c Release --project tools/ReleaseNotes --winget-template-check ${{ steps.get-sha.outputs.pr_template_sha }} + run: dotnet run -c Release --no-build --project tools/ReleaseNotes --winget-template-check ${{ steps.get-sha.outputs.pr_template_sha }} ci-completion-gate: # This job exists so there isn't a moving target for branch protections name: CI Completion Gate @@ -1236,8 +1251,11 @@ jobs: - name: Checkout uses: actions/checkout@v3 + - name: Build ReleaseNotes + run: dotnet build -c Release tools/ReleaseNotes/ReleaseNotes.csproj + - name: Run ReleaseNotes with --ensure-release - run: dotnet run -c Release --project tools/ReleaseNotes --ensure-release + run: dotnet run -c Release --no-build --project tools/ReleaseNotes --ensure-release deploy-tgs: name: Deploy TGS @@ -1253,6 +1271,9 @@ jobs: - name: Checkout uses: actions/checkout@v3 + - name: Build ReleaseNotes + run: dotnet build -c Release tools/ReleaseNotes/ReleaseNotes.csproj + - name: Parse TGS version shell: powershell run: | @@ -1290,7 +1311,7 @@ jobs: name: packaging-debian path: packaging-debian - - name: Retrieve .msi + - name: Retrieve Installer .exe uses: actions/download-artifact@v3 with: name: packaging-windows @@ -1306,7 +1327,7 @@ jobs: &"C:/Program Files/7-Zip/7z.exe" a ServerUpdatePackage.zip ./ServerUpdatePackage/* -tzip - name: Generate Release Notes - run: dotnet run -c Release --project tools/ReleaseNotes ${{ env.TGS_VERSION }} + run: dotnet run -c Release --no-build --project tools/ReleaseNotes ${{ env.TGS_VERSION }} - name: Create GitHub Release uses: actions/create-release@v1 @@ -1379,14 +1400,14 @@ jobs: asset_name: tgstation-server-v${{ env.TGS_VERSION }}.debian.packaging.tar.xz asset_content_type: application/x-tar - - name: Upload .msi + - name: Upload Installer .exe uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./packaging-windows/tgstation-server.msi - asset_name: tgstation-server.msi + asset_path: ./packaging-windows/tgstation-server-installer.exe + asset_name: tgstation-server-installer.exe asset_content_type: application/octet-stream deploy-docker: @@ -1458,7 +1479,7 @@ jobs: - name: Build ReleaseNotes run: dotnet build -c Release tools/ReleaseNotes - - name: Retrieve .msi + - name: Retrieve Installer .exe uses: actions/download-artifact@v3 with: name: packaging-windows @@ -1466,7 +1487,7 @@ jobs: - name: Execute Push Script shell: powershell - run: build/package/winget/push_manifest.ps1 -MsiPath packaging-windows/tgstation-server.msi + run: build/package/winget/push_manifest.ps1 -InstallerPath packaging-windows/tgstation-server-installer.exe - name: Run ReleaseNotes with --link-winget - run: dotnet run -c Release --project tools/ReleaseNotes --link-winget ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + run: dotnet run -c Release --no-build --project tools/ReleaseNotes --link-winget ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/.github/workflows/code-scanning.yml b/.github/workflows/code-scanning.yml index 00cf4bb1cc..8e130eddf4 100644 --- a/.github/workflows/code-scanning.yml +++ b/.github/workflows/code-scanning.yml @@ -35,7 +35,7 @@ jobs: languages: csharp - name: Build - run: dotnet build -c ReleaseNoFramework + run: dotnet build -c ReleaseNoWindows - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 diff --git a/.gitignore b/.gitignore index df800dc16b..56aae9a8b9 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,3 @@ release_notes.md *nupkg *.sqlite3 packaging/ -build/package/winget/Tgstation.Server.Host.Service.Msi/Release/ diff --git a/build/Common.props b/build/Common.props index 95ade51555..89b88f109b 100644 --- a/build/Common.props +++ b/build/Common.props @@ -2,7 +2,7 @@ - net6.0 + net$(TgsNetMajorVersion).0 netstandard2.0 latest Full diff --git a/build/Version.props b/build/Version.props index f3102f5c76..f8038e8242 100644 --- a/build/Version.props +++ b/build/Version.props @@ -13,6 +13,10 @@ 5.6.1 1.3.0 1.2.1 - 1.0.1 + 1.0.2 + 6 + + + https://dotnetcli.azureedge.net/dotnet/aspnetcore/Runtime/6.0.19/dotnet-hosting-6.0.19-win.exe diff --git a/build/package/appsettings.GitHub.yml b/build/package/appsettings.GitHub.yml index e916396a95..610a2ccd76 100644 --- a/build/package/appsettings.GitHub.yml +++ b/build/package/appsettings.GitHub.yml @@ -1,3 +1,26 @@ +# Barebones config file used for testing service installs in GitHub actions Database: DatabaseType: Sqlite ConnectionString: Data Source=/tgs.sqlite3;Mode=ReadWriteCreate +General: + ConfigVersion: 4.6.0 + ApiPort: 5000 + GitHubAccessToken: + SetupWizardMode: Never + ByondTopicTimeout: 5000 + RestartTimeoutMinutes: 1 + ShutdownTimeoutMinutes: 300 + UseBasicWatchdog: false + HostApiDocumentation: true + SkipAddingByondFirewallException: false + DeploymentDirectoryCopyTasksPerCore: + MinimumPasswordLength: 15 + InstanceLimit: 10 + UserLimit: 100 + UserGroupLimit: 25 + ValidInstancePaths: +FileLogging: + Directory: + Disable: false + LogLevel: Trace + MicrosoftLogLevel: Warning diff --git a/build/package/appsettings.Initial.yml b/build/package/appsettings.Initial.yml index 575df3fd32..1996a8a881 100644 --- a/build/package/appsettings.Initial.yml +++ b/build/package/appsettings.Initial.yml @@ -1,2 +1,2 @@ # tgstation-server configuration file -# See /opt/tgstation-server/appsettings.yml for details on individual configuration options +# See appsettings.yml or README.md for details on individual configuration options diff --git a/build/package/deb/MakeInstall b/build/package/deb/MakeInstall index ddbb512673..f0d34e6963 100755 --- a/build/package/deb/MakeInstall +++ b/build/package/deb/MakeInstall @@ -3,5 +3,5 @@ install: build/package/deb/install_artifacts.sh "$(DESTDIR)" install -D build/package/appsettings.Initial.yml "$(DESTDIR)/etc/tgstation-server/appsettings.Production.yml" - install src/Tgstation.Server.Host/appsettings.yml "$(DESTDIR)/etc/tgstation-server/appsettings.ex.yml" + install src/Tgstation.Server.Host/appsettings.yml "$(DESTDIR)/etc/tgstation-server/appsettings.yml" install -D build/package/deb/tgs-configure "$(DESTDIR)/usr/bin/tgs-configure" diff --git a/build/package/deb/debian/links b/build/package/deb/debian/links deleted file mode 100644 index 8a960e0a76..0000000000 --- a/build/package/deb/debian/links +++ /dev/null @@ -1 +0,0 @@ -/etc/tgstation-server/appsettings.Production.yml /opt/tgstation-server/appsettings.Production.yml diff --git a/build/package/deb/debian/rules b/build/package/deb/debian/rules index 39506708ae..7fd8d564fa 100755 --- a/build/package/deb/debian/rules +++ b/build/package/deb/debian/rules @@ -7,13 +7,13 @@ export DH_VERBOSE = 1 override_dh_auto_clean: rm -rf artifacts - dotnet clean -c ReleaseNoFramework + dotnet clean -c ReleaseNoWindows override_dh_auto_build: dotnet restore cd src/Tgstation.Server.Host.Console && dotnet publish -c Release -o ../../artifacts cd src/Tgstation.Server.Host && dotnet publish -c Release -o ../../artifacts/lib/Default - mv artifacts/lib/Default/appsettings.yml artifacts/appsettings.yml + rm artifacts/lib/Default/appsettings.yml override_dh_auto_install: cp build/package/deb/MakeInstall ./Makefile diff --git a/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs b/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs deleted file mode 100644 index 4f36aa3890..0000000000 --- a/build/package/winget/Tgstation.Server.Host.Service.Configure/Program.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Security.AccessControl; -using System.Threading; -using System.Windows.Forms; - -using var process = new Process(); - -var installDir = Path.GetDirectoryName( - Path.GetDirectoryName( - Assembly.GetExecutingAssembly().Location))!; - -process.StartInfo.WorkingDirectory = installDir; -process.StartInfo.FileName = Path.Combine( - installDir, - "Tgstation.Server.Host.Service.exe"); - -/* -https://www.roelvanlisdonk.nl/2009/11/13/how-to-detect-unattended-installation-msiexec-quit-or-qn-in-youre-custom-action-with-c/ -msiUILevelNoChange 0 Does not change UI level. -msiUILevelDefault 1 Uses default UI level. -msiUILevelNone 2 Silent installation. -msiUILevelBasic 3 Simple progress and error handling. -msiUILevelReduced 4 Authored UI and wizard dialog boxes suppressed. -msiUILevelFull 5 Authored UI with wizards, progress, and errors. -msiUILevelHideCancel 32 If combined with the msiUILevelBasic value, the installer shows progress dialog boxes but does not display a Cancel button on the dialog box to prevent users from canceling the installation. -msiUILevelProgressOnly 64 If combined with the msiUILevelBasic value, the installer displays progress dialog boxes but does not display any modal dialog boxes or error dialog boxes. -msiUILevelEndDialog 128 If combined with any above value, the installer displays a modal dialog box at the end of a successful installation or if there has been an error. No dialog box is displayed if the user cancels. -*/ -var uiLevel = Int32.Parse(args[0]); - -// leave it to MS to overcomplicate things -var interactive = uiLevel switch -{ - 0 or 1 or 4 or 5 => true, - _ => false, -}; - -var silent = uiLevel == 2; - -var uninstall = args - .Any(arg => arg.Equals("--uninstall", StringComparison.OrdinalIgnoreCase)); - -var shortcut = uiLevel == 42069; - -bool restartService; -if (shortcut) -{ - var result = MessageBox.Show($"This program will configure tgstation-server. Would you like to restart the service after doing so?{Environment.NewLine}{Environment.NewLine}A restart is required to apply changes. It will not kill your DreamDaemon instances provided you are running a version >=5.13.0 (Always true if you've never downgraded)", "Restart TGS After Configuring?", MessageBoxButtons.YesNo); - restartService = result == DialogResult.Yes; -} -else - restartService = interactive; - -process.StartInfo.Arguments = uninstall - ? $"-u{(silent ? " -s" : String.Empty)}" - : $"-i -f -x{(restartService ? " -r" : String.Empty)}{((interactive || shortcut) ? " -c" : String.Empty)}{(silent ? " -s" : String.Empty)}"; - -process.Start(); - -await process.WaitForExitAsync(CancellationToken.None); // DCT: None available - -foreach (var installLogFile in Directory.EnumerateFiles(installDir, "*.log")) - File.Delete(installLogFile); - -if (uninstall) -{ - Directory.Delete( - Path.Combine(installDir, "lib"), - true); - - // returning non-zero can make the installation uninstallable, no thanks - return 0; -} - -// try and lockdown the appsettings file -var fileInfo = new FileInfo(Path.Combine(installDir, "appsettings.Production.yml")); - -//get security access -FileSecurity fs = fileInfo.GetAccessControl(); - -//remove inherited access -fs.SetAccessRuleProtection(true, false); - -// Explicitly grant admins and SYSTEM -fs.AddAccessRule(new FileSystemAccessRule("Administrators", FileSystemRights.FullControl, AccessControlType.Allow)); -fs.AddAccessRule(new FileSystemAccessRule("NT AUTHORITY\\SYSTEM", FileSystemRights.Read, AccessControlType.Allow)); - -fileInfo.SetAccessControl(fs); - -return process.ExitCode; diff --git a/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj b/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj deleted file mode 100644 index 2fabb8e117..0000000000 --- a/build/package/winget/Tgstation.Server.Host.Service.Configure/Tgstation.Server.Host.Service.Configure.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - WinExe - net6.0-windows - win-x86 - true - enable - ../../../uac_elevation_manifest.xml - ../../../tgs.ico - - - - - - - diff --git a/build/package/winget/Tgstation.Server.Host.Service.Msi/README.md b/build/package/winget/Tgstation.Server.Host.Service.Msi/README.md deleted file mode 100644 index a7d88b76cf..0000000000 --- a/build/package/winget/Tgstation.Server.Host.Service.Msi/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# .msi Installer Project - -Useful reference for variables: https://learn.microsoft.com/en-us/windows/win32/msi/property-reference?redirectedfrom=MSDN diff --git a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj b/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj deleted file mode 100644 index db8383c96b..0000000000 --- a/build/package/winget/Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj +++ /dev/null @@ -1,1031 +0,0 @@ -"DeployProject" -{ -"VSVersion" = "3:800" -"ProjectType" = "8:{978C614F-708E-4E1A-B201-565925725DBA}" -"IsWebType" = "8:FALSE" -"ProjectName" = "8:Tgstation.Server.Host.Service.Msi" -"LanguageId" = "3:1033" -"CodePage" = "3:1252" -"UILanguageId" = "3:1033" -"SccProjectName" = "8:" -"SccLocalPath" = "8:" -"SccAuxPath" = "8:" -"SccProvider" = "8:" - "Hierarchy" - { - "Entry" - { - "MsmKey" = "8:_11E0E9B45549402D92B039FCCD0783B8" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_137A5E0CCDBF4E4A9549C03C74D3988C" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_415514E8CEF94645B44E5665C5B9D8F5" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_B0A2BC595A554F188D336702686A821E" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_E3B62CFD59F3484BACCB88E834824355" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_E9F7402DCE77463F9B7319647D3C16F2" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_F78AE830495A499099776F774CAB3D6D" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - } - "Configurations" - { - "Release" - { - "DisplayName" = "8:Release" - "IsDebugOnly" = "11:FALSE" - "IsReleaseOnly" = "11:TRUE" - "OutputFilename" = "8:Release\\tgstation-server.msi" - "PackageFilesAs" = "3:2" - "PackageFileSize" = "3:-2147483648" - "CabType" = "3:1" - "Compression" = "3:3" - "SignOutput" = "11:FALSE" - "CertificateFile" = "8:" - "PrivateKeyFile" = "8:" - "TimeStampServer" = "8:" - "InstallerBootstrapper" = "3:2" - "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" - { - "Enabled" = "11:FALSE" - "PromptEnabled" = "11:TRUE" - "PrerequisitesLocation" = "2:1" - "Url" = "8:" - "ComponentsUrl" = "8:" - "Items" - { - } - } - } - } - "Deployable" - { - "CustomAction" - { - "{4AA51A2D-7D85-4A59-BA75-B0809FC8B380}:_A53906ED15374112AC84662B6F2E8041" - { - "Name" = "8:Publish Items from Tgstation.Server.Host.Service.Configure (Active)" - "Condition" = "8:" - "Object" = "8:_E9F7402DCE77463F9B7319647D3C16F2" - "FileType" = "3:2" - "InstallAction" = "3:1" - "Arguments" = "8:[UILevel]" - "EntryPoint" = "8:" - "Sequence" = "3:1" - "Identifier" = "8:_B09766E4_1B68_49DE_9726_68FD609D967B" - "InstallerClass" = "11:FALSE" - "CustomActionData" = "8:" - "Run64Bit" = "11:TRUE" - } - "{4AA51A2D-7D85-4A59-BA75-B0809FC8B380}:_A953E29077C84B36ADF6660A83C8B004" - { - "Name" = "8:Publish Items from Tgstation.Server.Host.Service.Configure (Active)" - "Condition" = "8:" - "Object" = "8:_E9F7402DCE77463F9B7319647D3C16F2" - "FileType" = "3:2" - "InstallAction" = "3:4" - "Arguments" = "8:[UILevel] --uninstall" - "EntryPoint" = "8:" - "Sequence" = "3:1" - "Identifier" = "8:_6B8510E1_5DAE_4023_AD93_B9DD1AC65C45" - "InstallerClass" = "11:FALSE" - "CustomActionData" = "8:" - "Run64Bit" = "11:TRUE" - } - } - "DefaultFeature" - { - "Name" = "8:DefaultFeature" - "Title" = "8:" - "Description" = "8:" - } - "ExternalPersistence" - { - "LaunchCondition" - { - "{A06ECF26-33A3-4562-8140-9B0E340D4F24}:_C5FA609714B64925A18859A195267F9F" - { - "Name" = "8:.NET Core" - "Message" = "8:[VSDNETCOREMSG]" - "AllowLaterVersions" = "11:FALSE" - "InstallUrl" = "8:https://dotnet.microsoft.com/download/dotnet-core/[NetCoreVerMajorDotMinor]" - "IsNETCore" = "11:TRUE" - "Architecture" = "2:0" - "Runtime" = "2:0" - } - } - } - "File" - { - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_137A5E0CCDBF4E4A9549C03C74D3988C" - { - "SourcePath" = "8:..\\..\\..\\..\\src\\Tgstation.Server.Host\\appsettings.yml" - "TargetName" = "8:appsettings.yml" - "Tag" = "8:" - "Folder" = "8:_B28C4FD80D0245E08AEDCFEECACB6493" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B0A2BC595A554F188D336702686A821E" - { - "SourcePath" = "8:..\\..\\..\\..\\LICENSE" - "TargetName" = "8:LICENSE" - "Tag" = "8:" - "Folder" = "8:_B28C4FD80D0245E08AEDCFEECACB6493" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:TRUE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E3B62CFD59F3484BACCB88E834824355" - { - "SourcePath" = "8:..\\..\\appsettings.Initial.yml" - "TargetName" = "8:appsettings.Production.yml" - "Tag" = "8:" - "Folder" = "8:_B28C4FD80D0245E08AEDCFEECACB6493" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F78AE830495A499099776F774CAB3D6D" - { - "SourcePath" = "8:..\\install_banner.jpg" - "TargetName" = "8:install_banner.jpg" - "Tag" = "8:" - "Folder" = "8:_EB2DCEE6D3F74230A9827AC9B6F47F53" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:TRUE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } - } - "FileType" - { - } - "Folder" - { - "{1525181F-901A-416C-8A58-119130FE478E}:_758C42B61089428A950F84AD33260664" - { - "Name" = "8:#1921" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:StartMenuFolder" - "Folders" - { - } - } - "{3C67513D-01DD-4637-8A68-80971EB9504F}:_B28C4FD80D0245E08AEDCFEECACB6493" - { - "DefaultLocation" = "8:[ProgramFilesFolder][ProductName]" - "Name" = "8:#1925" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:TARGETDIR" - "Folders" - { - "{9EF0B969-E518-4E46-987F-47570745A589}:_0CFAD254CCC645209154DD4D85649AEA" - { - "Name" = "8:configure" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:_21324B7571BE4E9E8B14F4D2BD470581" - "Folders" - { - } - } - "{9EF0B969-E518-4E46-987F-47570745A589}:_D8FD06A5721D4746BD1D087E6329F3CF" - { - "Name" = "8:lib" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:_1760E07222D34C3ABECB83B8D17A7256" - "Folders" - { - "{9EF0B969-E518-4E46-987F-47570745A589}:_44E17B6EBB30432E9D4FBB976D7E029A" - { - "Name" = "8:Default" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:_40C981E76FB44E748278A84D5E727464" - "Folders" - { - } - } - } - } - } - } - "{1525181F-901A-416C-8A58-119130FE478E}:_BD1E6451115645479FB57AD1F0BB6A8B" - { - "Name" = "8:#1916" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:DesktopFolder" - "Folders" - { - } - } - "{994432C3-9487-495D-8656-3E829A8DBDDE}:_EB2DCEE6D3F74230A9827AC9B6F47F53" - { - "DefaultLocation" = "8:[TARGETDIR]" - "Name" = "8:Install Resources" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:NEWPROPERTY1" - "Folders" - { - } - } - } - "LaunchCondition" - { - } - "Locator" - { - } - "MsiBootstrapper" - { - "LangId" = "3:1033" - "RequiresElevation" = "11:FALSE" - } - "Product" - { - "Name" = "8:Microsoft Visual Studio" - "ProductName" = "8:tgstation-server" - "ProductCode" = "8:{D24887FA-3228-4509-B5F3-4E07E349F278}" - "PackageCode" = "8:{D078B8A7-E5C3-48EE-85B0-56C355FCBB43}" - "UpgradeCode" = "8:{151FE9F8-72CF-48D5-8E55-B7FB6BA9693E}" - "AspNetVersion" = "8:4.0.30319.0" - "RestartWWWService" = "11:FALSE" - "RemovePreviousVersions" = "11:TRUE" - "DetectNewerInstalledVersion" = "11:TRUE" - "InstallAllUsers" = "11:TRUE" - "ProductVersion" = "8:0.22.475" - "Manufacturer" = "8:tgstation" - "ARPHELPTELEPHONE" = "8:" - "ARPHELPLINK" = "8:https://github.com/tgstation/tgstation-server/discussions/categories/q-a" - "Title" = "8:tgstation-server" - "Subject" = "8:" - "ARPCONTACT" = "8:Dominon/Cyberboss" - "Keywords" = "8:" - "ARPCOMMENTS" = "8:Installer for tgstation-server" - "ARPURLINFOABOUT" = "8:https://github.com/tgstation/tgstation-server" - "ARPPRODUCTICON" = "8:_E9F7402DCE77463F9B7319647D3C16F2" - "ARPIconIndex" = "3:32512" - "SearchPath" = "8:" - "UseSystemSearchPath" = "11:TRUE" - "TargetPlatform" = "3:0" - "PreBuildEvent" = "8:" - "PostBuildEvent" = "8:" - "RunPostBuildEvent" = "3:0" - } - "Registry" - { - "HKLM" - { - "Keys" - { - "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_BB4EE4F5EF8A4C1BA6BAA85FE34E56C4" - { - "Name" = "8:Software" - "Condition" = "8:" - "AlwaysCreate" = "11:FALSE" - "DeleteAtUninstall" = "11:FALSE" - "Transitive" = "11:FALSE" - "Keys" - { - "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_05C235158E3A4664B285EA29511EF02D" - { - "Name" = "8:[Manufacturer]" - "Condition" = "8:" - "AlwaysCreate" = "11:FALSE" - "DeleteAtUninstall" = "11:FALSE" - "Transitive" = "11:FALSE" - "Keys" - { - } - "Values" - { - } - } - } - "Values" - { - } - } - } - } - "HKCU" - { - "Keys" - { - "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_0379B7F8F5504CDA9DB9B9D546DB606D" - { - "Name" = "8:Software" - "Condition" = "8:" - "AlwaysCreate" = "11:FALSE" - "DeleteAtUninstall" = "11:FALSE" - "Transitive" = "11:FALSE" - "Keys" - { - "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_6E60244E84834632A09C938ACAAC308D" - { - "Name" = "8:[Manufacturer]" - "Condition" = "8:" - "AlwaysCreate" = "11:FALSE" - "DeleteAtUninstall" = "11:FALSE" - "Transitive" = "11:FALSE" - "Keys" - { - } - "Values" - { - } - } - } - "Values" - { - } - } - } - } - "HKCR" - { - "Keys" - { - } - } - "HKU" - { - "Keys" - { - } - } - "HKPU" - { - "Keys" - { - } - } - } - "Sequences" - { - } - "Shortcut" - { - "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_8033129B5D1D4BB0904586D539B32765" - { - "Name" = "8:Configure and Restart tgstation-server" - "Arguments" = "8:42069" - "Description" = "8:Runs the TGS setup wizard and optionally restarts the Windows service" - "ShowCmd" = "3:1" - "IconIndex" = "3:32512" - "Transitive" = "11:FALSE" - "Target" = "8:_E9F7402DCE77463F9B7319647D3C16F2" - "Folder" = "8:_758C42B61089428A950F84AD33260664" - "WorkingFolder" = "8:_B28C4FD80D0245E08AEDCFEECACB6493" - "Icon" = "8:_E9F7402DCE77463F9B7319647D3C16F2" - "Feature" = "8:" - } - "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_86C54A96871E40B6B517685DB09F223A" - { - "Name" = "8:Configure and Restart tgstation-server" - "Arguments" = "8:42069 " - "Description" = "8:Runs the TGS setup wizard and optionally restarts the Windows service" - "ShowCmd" = "3:1" - "IconIndex" = "3:32512" - "Transitive" = "11:FALSE" - "Target" = "8:_E9F7402DCE77463F9B7319647D3C16F2" - "Folder" = "8:_BD1E6451115645479FB57AD1F0BB6A8B" - "WorkingFolder" = "8:_B28C4FD80D0245E08AEDCFEECACB6493" - "Icon" = "8:_E9F7402DCE77463F9B7319647D3C16F2" - "Feature" = "8:" - } - } - "UserInterface" - { - "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_0E30589D83D5457EA1590BDA4DB93D03" - { - "UseDynamicProperties" = "11:FALSE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdBasicDialogs.wim" - } - "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_109A5A97F789460AB73CDF166664A916" - { - "Name" = "8:#1902" - "Sequence" = "3:2" - "Attributes" = "3:3" - "Dialogs" - { - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_76284EF5FA104F46A0644EE9513C0A4D" - { - "Sequence" = "3:100" - "DisplayName" = "8:Finished" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdAdminFinishedDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:2" - "Value" = "8:_F78AE830495A499099776F774CAB3D6D" - "UsePlugInResources" = "11:TRUE" - } - } - } - } - } - "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_278559DEB3E24BBCAA1C9B3F68673761" - { - "Name" = "8:#1900" - "Sequence" = "3:1" - "Attributes" = "3:1" - "Dialogs" - { - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_7CD912AA05C244CB8A903FBFD33E29A8" - { - "Sequence" = "3:300" - "DisplayName" = "8:Confirm Installation" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdConfirmDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:2" - "Value" = "8:_F78AE830495A499099776F774CAB3D6D" - "UsePlugInResources" = "11:TRUE" - } - } - } - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_B3748469032C440CA8C833C645EF67F9" - { - "Sequence" = "3:100" - "DisplayName" = "8:Welcome" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdWelcomeDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:2" - "Value" = "8:_F78AE830495A499099776F774CAB3D6D" - "UsePlugInResources" = "11:TRUE" - } - "CopyrightWarning" - { - "Name" = "8:CopyrightWarning" - "DisplayName" = "8:#1002" - "Description" = "8:#1102" - "Type" = "3:3" - "ContextData" = "8:" - "Attributes" = "3:0" - "Setting" = "3:1" - "Value" = "8:#1202" - "DefaultValue" = "8:#1202" - "UsePlugInResources" = "11:TRUE" - } - "Welcome" - { - "Name" = "8:Welcome" - "DisplayName" = "8:#1003" - "Description" = "8:#1103" - "Type" = "3:3" - "ContextData" = "8:" - "Attributes" = "3:0" - "Setting" = "3:1" - "Value" = "8:#1203" - "DefaultValue" = "8:#1203" - "UsePlugInResources" = "11:TRUE" - } - } - } - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_BE9B710186F946AC828F528A90F9B1CA" - { - "Sequence" = "3:200" - "DisplayName" = "8:Installation Folder" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdFolderDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:2" - "Value" = "8:_F78AE830495A499099776F774CAB3D6D" - "UsePlugInResources" = "11:TRUE" - } - "InstallAllUsersVisible" - { - "Name" = "8:InstallAllUsersVisible" - "DisplayName" = "8:#1059" - "Description" = "8:#1159" - "Type" = "3:5" - "ContextData" = "8:1;True=1;False=0" - "Attributes" = "3:0" - "Setting" = "3:0" - "Value" = "3:1" - "DefaultValue" = "3:1" - "UsePlugInResources" = "11:TRUE" - } - } - } - } - } - "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_2C7325D993884C978B1A4381E1143564" - { - "Name" = "8:#1901" - "Sequence" = "3:2" - "Attributes" = "3:2" - "Dialogs" - { - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_FB014E47DC3540A2AA6B4B1B109BDA09" - { - "Sequence" = "3:100" - "DisplayName" = "8:Progress" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdAdminProgressDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:2" - "Value" = "8:_F78AE830495A499099776F774CAB3D6D" - "UsePlugInResources" = "11:TRUE" - } - "ShowProgress" - { - "Name" = "8:ShowProgress" - "DisplayName" = "8:#1009" - "Description" = "8:#1109" - "Type" = "3:5" - "ContextData" = "8:1;True=1;False=0" - "Attributes" = "3:0" - "Setting" = "3:0" - "Value" = "3:1" - "DefaultValue" = "3:1" - "UsePlugInResources" = "11:TRUE" - } - } - } - } - } - "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_34AD1EE11A4C483C8F39A6F57C055D1C" - { - "Name" = "8:#1900" - "Sequence" = "3:2" - "Attributes" = "3:1" - "Dialogs" - { - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_0C069DDECE324687A9F07480971F4EA1" - { - "Sequence" = "3:200" - "DisplayName" = "8:Installation Folder" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdAdminFolderDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:2" - "Value" = "8:_F78AE830495A499099776F774CAB3D6D" - "UsePlugInResources" = "11:TRUE" - } - } - } - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_566942A0B14E44D2ABECDB1CCA6B4229" - { - "Sequence" = "3:300" - "DisplayName" = "8:Confirm Installation" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdAdminConfirmDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:2" - "Value" = "8:_F78AE830495A499099776F774CAB3D6D" - "UsePlugInResources" = "11:TRUE" - } - } - } - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_CDECB4E7DDE84A4DB72B528A15D01E47" - { - "Sequence" = "3:110" - "DisplayName" = "8:Welcome" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdAdminWelcomeDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:2" - "Value" = "8:_F78AE830495A499099776F774CAB3D6D" - "UsePlugInResources" = "11:TRUE" - } - "CopyrightWarning" - { - "Name" = "8:CopyrightWarning" - "DisplayName" = "8:#1002" - "Description" = "8:#1102" - "Type" = "3:3" - "ContextData" = "8:" - "Attributes" = "3:0" - "Setting" = "3:1" - "Value" = "8:#1202" - "DefaultValue" = "8:#1202" - "UsePlugInResources" = "11:TRUE" - } - "Welcome" - { - "Name" = "8:Welcome" - "DisplayName" = "8:#1003" - "Description" = "8:#1103" - "Type" = "3:3" - "ContextData" = "8:" - "Attributes" = "3:0" - "Setting" = "3:1" - "Value" = "8:#1203" - "DefaultValue" = "8:#1203" - "UsePlugInResources" = "11:TRUE" - } - } - } - } - } - "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_C1FAAD9180D249AE930209CFFDE47E92" - { - "Name" = "8:#1902" - "Sequence" = "3:1" - "Attributes" = "3:3" - "Dialogs" - { - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_F066076B6F3F439D9B70A2243DCC8D99" - { - "Sequence" = "3:100" - "DisplayName" = "8:Finished" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdFinishedDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:2" - "Value" = "8:_F78AE830495A499099776F774CAB3D6D" - "UsePlugInResources" = "11:TRUE" - } - "UpdateText" - { - "Name" = "8:UpdateText" - "DisplayName" = "8:#1058" - "Description" = "8:#1158" - "Type" = "3:15" - "ContextData" = "8:" - "Attributes" = "3:0" - "Setting" = "3:2" - "Value" = "8:You can now navigate to http://localhost: to manage your server." - "DefaultValue" = "8:#1258" - "UsePlugInResources" = "11:TRUE" - } - } - } - } - } - "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_CDC222C0F1734F22A35CE4BE55CD389D" - { - "UseDynamicProperties" = "11:FALSE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdUserInterface.wim" - } - "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_E2FF183010DC4AD5868B1B6BB4835C7F" - { - "Name" = "8:#1901" - "Sequence" = "3:1" - "Attributes" = "3:2" - "Dialogs" - { - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_9C81E7707FD24FA98CE1C7DAAB793AB6" - { - "Sequence" = "3:100" - "DisplayName" = "8:Progress" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdProgressDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:2" - "Value" = "8:_F78AE830495A499099776F774CAB3D6D" - "UsePlugInResources" = "11:TRUE" - } - "ShowProgress" - { - "Name" = "8:ShowProgress" - "DisplayName" = "8:#1009" - "Description" = "8:#1109" - "Type" = "3:5" - "ContextData" = "8:1;True=1;False=0" - "Attributes" = "3:0" - "Setting" = "3:0" - "Value" = "3:1" - "DefaultValue" = "3:1" - "UsePlugInResources" = "11:TRUE" - } - } - } - } - } - } - "MergeModule" - { - } - "ProjectOutput" - { - "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_11E0E9B45549402D92B039FCCD0783B8" - { - "SourcePath" = "8:" - "TargetName" = "8:" - "Tag" = "8:" - "Folder" = "8:_44E17B6EBB30432E9D4FBB976D7E029A" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - "ProjectOutputGroupRegister" = "3:1" - "OutputConfiguration" = "8:" - "OutputGroupCanonicalName" = "8:PublishItems" - "OutputProjectGuid" = "8:{2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}" - "ShowKeyOutput" = "11:TRUE" - "ExcludeFilters" - { - "ExcludeFilter" = "8:appsettings.yml" - } - } - "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_415514E8CEF94645B44E5665C5B9D8F5" - { - "SourcePath" = "8:..\\..\\..\\..\\src\\Tgstation.Server.Api\\bin\\Release\\netstandard2.0\\Tgstation.Server.Api.xml" - "TargetName" = "8:" - "Tag" = "8:" - "Folder" = "8:_44E17B6EBB30432E9D4FBB976D7E029A" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - "ProjectOutputGroupRegister" = "3:1" - "OutputConfiguration" = "8:" - "OutputGroupCanonicalName" = "8:Documentation" - "OutputProjectGuid" = "8:{8B4A208D-A48A-4A5D-8B94-E2661138865D}" - "ShowKeyOutput" = "11:TRUE" - "ExcludeFilters" - { - } - } - "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_5222E155071449818AC7AD899B0BD0EE" - { - "SourcePath" = "8:" - "TargetName" = "8:" - "Tag" = "8:" - "Folder" = "8:_44E17B6EBB30432E9D4FBB976D7E029A" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - "ProjectOutputGroupRegister" = "3:1" - "OutputConfiguration" = "8:" - "OutputGroupCanonicalName" = "8:ContentFiles" - "OutputProjectGuid" = "8:{2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}" - "ShowKeyOutput" = "11:TRUE" - "ExcludeFilters" - { - "ExcludeFilter" = "8:appsettings.yml" - } - } - "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_B2B80DADC2EA4646A8E8E8E54F2AE2EE" - { - "SourcePath" = "8:..\\..\\..\\..\\src\\Tgstation.Server.Host.Service\\obj\\Release\\net6.0-windows\\apphost.exe" - "TargetName" = "8:" - "Tag" = "8:" - "Folder" = "8:_B28C4FD80D0245E08AEDCFEECACB6493" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:TRUE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - "ProjectOutputGroupRegister" = "3:1" - "OutputConfiguration" = "8:" - "OutputGroupCanonicalName" = "8:PublishItems" - "OutputProjectGuid" = "8:{29927416-3B78-49A7-A560-5CCAA638B6B4}" - "ShowKeyOutput" = "11:TRUE" - "ExcludeFilters" - { - } - } - "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_E9F7402DCE77463F9B7319647D3C16F2" - { - "SourcePath" = "8:..\\Tgstation.Server.Host.Service.Configure\\obj\\Release\\net6.0-windows\\win-x86\\apphost.exe" - "TargetName" = "8:" - "Tag" = "8:" - "Folder" = "8:_0CFAD254CCC645209154DD4D85649AEA" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - "ProjectOutputGroupRegister" = "3:1" - "OutputConfiguration" = "8:" - "OutputGroupCanonicalName" = "8:PublishItems" - "OutputProjectGuid" = "8:{6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}" - "ShowKeyOutput" = "11:TRUE" - "ExcludeFilters" - { - } - } - } - } -} diff --git a/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Bundle.wxs b/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Bundle.wxs new file mode 100644 index 0000000000..a6d7135340 --- /dev/null +++ b/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Bundle.wxs @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Tgstation.Server.Host.Service.Wix.Bundle.wixproj b/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Tgstation.Server.Host.Service.Wix.Bundle.wixproj new file mode 100644 index 0000000000..209dd92a13 --- /dev/null +++ b/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Tgstation.Server.Host.Service.Wix.Bundle.wixproj @@ -0,0 +1,16 @@ + + + + ProductVersion=$(TgsCoreVersion);NetMajorVersion=$(TgsNetMajorVersion);AspNetRedistUrl=$(TgsRedistUrl) + Bundle + x86 + tgstation-server-installer + + + + + + + + + \ No newline at end of file diff --git a/build/package/winget/Tgstation.Server.Host.Service.Wix.Extensions/CustomAction.config b/build/package/winget/Tgstation.Server.Host.Service.Wix.Extensions/CustomAction.config new file mode 100644 index 0000000000..aa417a104d --- /dev/null +++ b/build/package/winget/Tgstation.Server.Host.Service.Wix.Extensions/CustomAction.config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/build/package/winget/Tgstation.Server.Host.Service.Wix.Extensions/InstallationExtensions.cs b/build/package/winget/Tgstation.Server.Host.Service.Wix.Extensions/InstallationExtensions.cs new file mode 100644 index 0000000000..02a90bdc43 --- /dev/null +++ b/build/package/winget/Tgstation.Server.Host.Service.Wix.Extensions/InstallationExtensions.cs @@ -0,0 +1,76 @@ +namespace Tgstation.Server.Host.Service.Wix.SafeShutdown +{ + using System; + using System.ServiceProcess; + + using Tgstation.Server.Host.Common; + + using WixToolset.Dtf.WindowsInstaller; + + /// + /// Extension methods for the .msi installer. + /// + public static class InstallationExtensions + { + /// + /// Attempts to detach stop the existing tgstation-server service if it exists. + /// + /// The installer . + /// The of the custom action. + [CustomAction] + public static ActionResult DetachStopTgsServiceIfRunning(Session session) + { + if (session == null) + throw new ArgumentNullException(nameof(session)); + + try + { + session.Log("Begin DetachStopTgsServiceIfRunning"); + ServiceController serviceController = null; + + session.Log($"Searching for {Constants.CanonicalPackageName} service..."); + foreach (var controller in ServiceController.GetServices()) + if (controller.ServiceName == Constants.CanonicalPackageName) + { + serviceController = controller; + break; + } + else + controller.Dispose(); + + using (serviceController) + { + if (serviceController == null || serviceController.Status != ServiceControllerStatus.Running) + { + session.Log($"{Constants.CanonicalPackageName} service not found. Continuing."); + return ActionResult.Success; + } + + var commandId = PipeCommands.GetCommandId( + PipeCommands.CommandDetachingShutdown) + .Value; + + session.Log($"{Constants.CanonicalPackageName} service found. Sending command \"{PipeCommands.CommandDetachingShutdown}\" ({commandId})..."); + + serviceController.ExecuteCommand(commandId); + + session.Log($"Command sent. Waiting for {Constants.CanonicalPackageName} service to stop..."); + + serviceController.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromMinutes(1)); + + var stopped = serviceController.Status == ServiceControllerStatus.Stopped; + session.Log($"{Constants.CanonicalPackageName} stopped {(stopped ? String.Empty : "un")}successfully."); + + return stopped + ? ActionResult.Success + : ActionResult.NotExecuted; + } + } + catch (Exception ex) + { + session.Log($"Exception in DetachStopTgsServiceIfRunning:{Environment.NewLine}{ex}"); + return ActionResult.Failure; + } + } + } +} diff --git a/build/package/winget/Tgstation.Server.Host.Service.Wix.Extensions/Tgstation.Server.Host.Service.Wix.Extensions.csproj b/build/package/winget/Tgstation.Server.Host.Service.Wix.Extensions/Tgstation.Server.Host.Service.Wix.Extensions.csproj new file mode 100644 index 0000000000..acadffcec1 --- /dev/null +++ b/build/package/winget/Tgstation.Server.Host.Service.Wix.Extensions/Tgstation.Server.Host.Service.Wix.Extensions.csproj @@ -0,0 +1,27 @@ + + + + + net2.0 + $(TgsCoreVersion) + + + + + + + + + True + + + + + + + + + + + + diff --git a/build/package/winget/Tgstation.Server.Host.Service.Wix/Package.en-us.wxl b/build/package/winget/Tgstation.Server.Host.Service.Wix/Package.en-us.wxl new file mode 100644 index 0000000000..b1675c9c30 --- /dev/null +++ b/build/package/winget/Tgstation.Server.Host.Service.Wix/Package.en-us.wxl @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/build/package/winget/Tgstation.Server.Host.Service.Wix/Package.wxs b/build/package/winget/Tgstation.Server.Host.Service.Wix/Package.wxs new file mode 100644 index 0000000000..773225386a --- /dev/null +++ b/build/package/winget/Tgstation.Server.Host.Service.Wix/Package.wxs @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/package/winget/Tgstation.Server.Host.Service.Wix/Tgstation.Server.Host.Service.Wix.wixproj b/build/package/winget/Tgstation.Server.Host.Service.Wix/Tgstation.Server.Host.Service.Wix.wixproj new file mode 100644 index 0000000000..a3aa164719 --- /dev/null +++ b/build/package/winget/Tgstation.Server.Host.Service.Wix/Tgstation.Server.Host.Service.Wix.wixproj @@ -0,0 +1,34 @@ + + + + ProductVersion=$(TgsCoreVersion) + 5150;5151 + x86 + tgstation-server + + + + + + + + InitialHostComponentGroup + DefaultLibDirectory + true + true + true + + + ServiceHostWatchdogComponentGroup + ApplicationDirectory + true + + + + + + + + + + \ No newline at end of file diff --git a/build/package/winget/build_msi.ps1 b/build/package/winget/build_msi.ps1 deleted file mode 100644 index a1da7c23a5..0000000000 --- a/build/package/winget/build_msi.ps1 +++ /dev/null @@ -1,29 +0,0 @@ -$currentCommit=git rev-parse HEAD - -Remove-Item -Recurse -Force -ErrorAction SilentlyContinue packaging - -git worktree remove -f packaging - -git worktree add -f packaging $currentCommit -cd packaging -Remove-Item -Recurse -Force .git - -dotnet restore - -[XML]$versionXML = Get-Content build/Version.props -ErrorAction Stop - -$tgsVersion = $versionXML.Project.PropertyGroup.TgsCoreVersion - -cd build/package/winget - -$devVersion = '0.22.475' - -(Get-Content Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj -ErrorAction Stop).Replace($devVersion, $tgsVersion) | Set-Content Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj -ErrorAction Stop - -# We make _some_ assumptions -DevEnv installer.sln /Project Tgstation.Server.Host.Service.Msi/Tgstation.Server.Host.Service.Msi.vdproj /build Release -if (-Not $?) { - exit $lastexitcode -} - -cd ../../../.. diff --git a/build/package/winget/installer.sln b/build/package/winget/installer.sln deleted file mode 100644 index 882fd39d42..0000000000 --- a/build/package/winget/installer.sln +++ /dev/null @@ -1,50 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.6.33801.468 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Service.Configure", "Tgstation.Server.Host.Service.Configure\Tgstation.Server.Host.Service.Configure.csproj", "{6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}" -EndProject -Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "Tgstation.Server.Host.Service.Msi", "Tgstation.Server.Host.Service.Msi\Tgstation.Server.Host.Service.Msi.vdproj", "{C7BE7AC6-D020-4497-84DE-282C24BA575D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Api", "..\..\..\src\Tgstation.Server.Api\Tgstation.Server.Api.csproj", "{8B4A208D-A48A-4A5D-8B94-E2661138865D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Common", "..\..\..\src\Tgstation.Server.Common\Tgstation.Server.Common.csproj", "{70CD9A98-D31A-44A4-81D1-D02764CEEEFD}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Common", "..\..\..\src\Tgstation.Server.Host.Common\Tgstation.Server.Host.Common.csproj", "{CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Service", "..\..\..\src\Tgstation.Server.Host.Service\Tgstation.Server.Host.Service.csproj", "{29927416-3B78-49A7-A560-5CCAA638B6B4}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Watchdog", "..\..\..\src\Tgstation.Server.Host.Watchdog\Tgstation.Server.Host.Watchdog.csproj", "{5D2D682C-6BF0-439C-850B-6AB945BBEAEA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host", "..\..\..\src\Tgstation.Server.Host\Tgstation.Server.Host.csproj", "{2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6CC73878-8C37-4ACC-ADAA-A60EBDBC2315}.Release|Any CPU.Build.0 = Release|Any CPU - {C7BE7AC6-D020-4497-84DE-282C24BA575D}.Release|Any CPU.ActiveCfg = Release - {C7BE7AC6-D020-4497-84DE-282C24BA575D}.Release|Any CPU.Build.0 = Release - {8B4A208D-A48A-4A5D-8B94-E2661138865D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8B4A208D-A48A-4A5D-8B94-E2661138865D}.Release|Any CPU.Build.0 = Release|Any CPU - {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Release|Any CPU.Build.0 = Release|Any CPU - {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Release|Any CPU.Build.0 = Release|Any CPU - {29927416-3B78-49A7-A560-5CCAA638B6B4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {29927416-3B78-49A7-A560-5CCAA638B6B4}.Release|Any CPU.Build.0 = Release|Any CPU - {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Release|Any CPU.Build.0 = Release|Any CPU - {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Release|Any CPU.ActiveCfg = Installer|Any CPU - {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Release|Any CPU.Build.0 = Installer|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {EBC981CA-0309-468F-984F-067BA2A6DF99} - EndGlobalSection -EndGlobal diff --git a/build/package/winget/manifest/Tgstation.Server.installer.yaml b/build/package/winget/manifest/Tgstation.Server.installer.yaml index 31f2517b77..3aced46d72 100644 --- a/build/package/winget/manifest/Tgstation.Server.installer.yaml +++ b/build/package/winget/manifest/Tgstation.Server.installer.yaml @@ -4,18 +4,20 @@ PackageIdentifier: Tgstation.Server PackageVersion: 0.22.475 # Set before publish by push_manifest.ps1 Installers: -- InstallerUrl: https://github.com/tgstation/tgstation-server/releases/download/tgstation-server-v0.22.475/tgstation-server.msi # Set before publish by push_manifest.ps1 +- InstallerUrl: https://github.com/tgstation/tgstation-server/releases/download/tgstation-server-v0.22.475/tgstation-server-installer.exe # Set before publish by push_manifest.ps1 InstallerLocale: en-US Architecture: x86 - InstallerType: msi + InstallerType: exe Scope: machine - InstallerSha256: F749672C1BDBAC8CD8AEF7352B97E54C21CF389D798D0ED245CA75EC72521460 # Set before publish by push_manifest.ps1 + InstallerSha256: CF0D4D2FD042098D826A226A05A9DAA5C792318CF48FD334F7FC06AF6A8A23B1 # Set before publish by push_manifest.ps1 InstallModes: - interactive - silent + InstallerSwitches: + Silent: /silent + SilentWithProgress: /passive + Log: /log ProductCode: '{D24887FA-3228-4509-B5F3-4E07E349F278}' - RequireExplicitUpgrade: true - UpgradeBehavior: uninstallPrevious UnsupportedOSArchitectures: - arm - arm64 diff --git a/build/package/winget/prepare_installer_input_artifacts.ps1 b/build/package/winget/prepare_installer_input_artifacts.ps1 new file mode 100644 index 0000000000..a7acbe1597 --- /dev/null +++ b/build/package/winget/prepare_installer_input_artifacts.ps1 @@ -0,0 +1,43 @@ +# Note: This script requires that Tgstation.Server.Host and Tgstation.Server.Host.Service be built in Release configuration beforehand + +$ErrorActionPreference="stop" + +$startDirectory=$pwd +try +{ + Remove-Item -Recurse -Force artifacts -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force build/package/winget/Tgstation.Server.Host.Service.Wix/bin -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force build/package/winget/Tgstation.Server.Host.Service.Wix/obj -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/obj -ErrorAction SilentlyContinue + + [XML]$versionXML = Get-Content build/Version.props -ErrorAction Stop + $redistUrl = $versionXML.Project.PropertyGroup.TgsRedistUrl + + mkdir artifacts + $previousProgressPreference = $ProgressPreference + $ProgressPreference = 'SilentlyContinue' + try + { + Invoke-WebRequest -Uri $redistUrl -OutFile artifacts/hosting-bundle.exe + } finally { + $ProgressPreference = $previousProgressPreference + } + + cd src/Tgstation.Server.Host + dotnet publish -c Release --no-build -o ../../artifacts/Tgstation.Server.Host + if (-Not $?) { + exit $lastexitcode + } + + cd ../Tgstation.Server.Host.Service + + dotnet publish -c Release --no-build -o ../../artifacts/Tgstation.Server.Host.Service + if (-Not $?) { + exit $lastexitcode + } + + mv ../../artifacts/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.exe ../../artifacts/ +} finally { + cd $startDirectory +} diff --git a/build/package/winget/push_manifest.ps1 b/build/package/winget/push_manifest.ps1 index f2a7154533..27cb64e46d 100644 --- a/build/package/winget/push_manifest.ps1 +++ b/build/package/winget/push_manifest.ps1 @@ -1,5 +1,5 @@ param( - [string]$MsiPath = 'packaging/build/package/winget/Tgstation.Server.Host.Service.Msi/Release/tgstation-server.msi' + [string]$MsiPath = 'packaging/build/package/winget/Tgstation.Server.Host.Service.Wix/Release/tgstation-server.msi' ) $ErrorActionPreference="Stop" diff --git a/build/tgstation-server.service b/build/tgstation-server.service index b09873cc99..4f6f9b81cd 100644 --- a/build/tgstation-server.service +++ b/build/tgstation-server.service @@ -10,7 +10,7 @@ After=mssql-server.service Type=notify-reload NotifyAccess=all WorkingDirectory=/opt/tgstation-server -ExecStart=/usr/bin/dotnet Tgstation.Server.Host.Console.dll --General:SetupWizardMode=Never --Internal:UsingSystemD=true +ExecStart=/usr/bin/dotnet Tgstation.Server.Host.Console.dll --appsettings-base-path=/etc/tgstation-server --General:SetupWizardMode=Never --Internal:UsingSystemD=true TimeoutStartSec=600 Restart=Always KillMode=process diff --git a/src/Tgstation.Server.Host.Common/Constants.cs b/src/Tgstation.Server.Host.Common/Constants.cs new file mode 100644 index 0000000000..9d0133bb0f --- /dev/null +++ b/src/Tgstation.Server.Host.Common/Constants.cs @@ -0,0 +1,13 @@ +namespace Tgstation.Server.Host.Common +{ + /// + /// Constant values. + /// + public static class Constants + { + /// + /// The name of the project. + /// + public const string CanonicalPackageName = "tgstation-server"; + } +} diff --git a/src/Tgstation.Server.Host.Common/PipeCommands.cs b/src/Tgstation.Server.Host.Common/PipeCommands.cs index 10390cbfbc..42a8525a46 100644 --- a/src/Tgstation.Server.Host.Common/PipeCommands.cs +++ b/src/Tgstation.Server.Host.Common/PipeCommands.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace Tgstation.Server.Host.Common +namespace Tgstation.Server.Host.Common { /// /// Values able to be passed via the update file path. @@ -22,14 +20,30 @@ namespace Tgstation.Server.Host.Common /// public const string CommandDetachingShutdown = "detach"; +#if NET6_0_OR_GREATER /// - /// All of the represented as a . + /// All of the represented as a . /// - public static IReadOnlyList AllCommands { get; } = new[] + public static System.Collections.Generic.IReadOnlyList AllCommands { get; } = new[] { CommandStop, CommandGracefulShutdown, CommandDetachingShutdown, }; +#endif + + /// + /// Gets the value of a given . + /// + /// The . + /// The value of the command or if it was unrecognized. + public static int? GetCommandId(string command) + => command switch + { + CommandStop => 128, // Windows only allows commands 128-256: https://stackoverflow.com/a/62858106 + CommandGracefulShutdown => 129, + CommandDetachingShutdown => 130, + _ => null, + }; } } diff --git a/src/Tgstation.Server.Host.Common/Tgstation.Server.Host.Common.csproj b/src/Tgstation.Server.Host.Common/Tgstation.Server.Host.Common.csproj index 92e7dae859..90389d89a6 100644 --- a/src/Tgstation.Server.Host.Common/Tgstation.Server.Host.Common.csproj +++ b/src/Tgstation.Server.Host.Common/Tgstation.Server.Host.Common.csproj @@ -2,7 +2,7 @@ - $(TgsNetVersion) + $(TgsFrameworkVersion);net2.0 $(TgsCoreVersion) false true diff --git a/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj b/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj index 71c3694644..0cdf6e82c5 100644 --- a/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj +++ b/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj @@ -3,7 +3,7 @@ Exe - $(TgsNetVersion) + $(TgsFrameworkVersion) $(TgsCoreVersion) false false diff --git a/src/Tgstation.Server.Host.Service/Program.cs b/src/Tgstation.Server.Host.Service/Program.cs index 7d365e7ad6..c0a9409ea1 100644 --- a/src/Tgstation.Server.Host.Service/Program.cs +++ b/src/Tgstation.Server.Host.Service/Program.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using McMaster.Extensions.CommandLineUtils; +using Microsoft.Extensions.Hosting.WindowsServices; using Microsoft.Extensions.Logging; using Tgstation.Server.Host.Common; @@ -30,56 +31,50 @@ namespace Tgstation.Server.Host.Service /// /// The --uninstall or -u option. /// - [Option(ShortName = "u")] + [Option(ShortName = "u", Description = "Uninstalls ANY installed tgstation-server service >=v4.0.0")] public bool Uninstall { get; } /// /// The --detach or -x option. Valid only with . /// - [Option(ShortName = "x")] + [Option(ShortName = "x", Description = "If the service has to stop, detach any running DreamDaemon processes beforehand. Only supported on versions >=5.13.0")] public bool Detach { get; } /// /// The --restart or -r option. /// - [Option(ShortName = "r")] + [Option(ShortName = "r", Description = "Stop and restart the tgstation-server service")] public bool Restart { get; } /// /// The --install or -i option. /// - [Option(ShortName = "i")] + [Option(ShortName = "i", Description = "Installs this executable as the tgstation-server Windows service")] public bool Install { get; set; } /// /// The --force or -f option. /// - [Option(ShortName = "f")] + [Option(ShortName = "f", Description = "Automatically agree to uninstall prompts")] public bool Force { get; set; } /// /// The --silent or -s option. /// - [Option(ShortName = "s")] + [Option(ShortName = "s", Description = "Suppresses console output from the host watchdog")] public bool Silent { get; set; } /// /// The --configure or -c option. /// - [Option(ShortName = "c")] + [Option(ShortName = "c", Description = "Runs the TGS setup wizard")] public bool Configure { get; set; } /// - /// The --trace or -t option. Enables trace logs. + /// The --passthroughargs or -p option. /// - [Option(ShortName = "t")] - public bool Trace { get; set; } - - /// - /// The --debug or -d option. Enables debug logs. - /// - [Option(ShortName = "d")] - public bool Debug { get; set; } + [Option(ShortName = "p", Description = "Arguments passed to main host process")] + public string PassthroughArgs { get; set; } /// /// Entrypoint for the application. @@ -108,6 +103,7 @@ namespace Tgstation.Server.Host.Service process.StartInfo.Arguments = serviceToUninstall == null ? $"create tgstation-server binPath=\"{exePath}\" start=auto depend=Tcpip/Dhcp/Dnscache" : $"delete {serviceToUninstall}"; + process.StartInfo.CreateNoWindow = false; process.Start(); @@ -121,35 +117,53 @@ namespace Tgstation.Server.Host.Service public async Task OnExecuteAsync() { var standardRun = !Install && !Uninstall && !Configure; + if (standardRun) + if (!Silent && !WindowsServiceHelpers.IsWindowsService()) + { +#if NET7_0_OR_GREATER +#error Deprecated functionality, remove +#endif + var result = NativeMethods.MessageBox( + default, + "You are running the TGS windows service executable directly. It should only be run by the service control manager. Would you like to install and configure the service in this location? (Note: This functionality is deprecated and will be removed in a future version)", + "TGS Service", + NativeMethods.MessageBoxButtons.YesNo); - if (Environment.UserInteractive && standardRun) - { - var result = NativeMethods.MessageBox( - default, - "You are running the TGS windows service executable directly. It should only be run by the service control manager. Would you like to install and configure the service in this location?", - "TGS Service", - NativeMethods.MessageBoxButtons.YesNo); + if (result != NativeMethods.DialogResult.Yes) + return; - if (result != NativeMethods.DialogResult.Yes) - return; - - Install = true; - Configure = true; - } + Install = true; + Configure = true; + } + else + using (var service = new ServerService(WatchdogFactory, GetPassthroughArgs(), LogLevel.Trace)) + { + service.Run(); + return; + } if (Configure) - await RunConfigure(CancellationToken.None); // DCT: None available + await RunConfigure(CancellationToken.None); // DCT: None available bool stopped = false; if (Uninstall) { foreach (ServiceController sc in ServiceController.GetServices()) - if (sc.ServiceName == ServerService.Name) + { + bool match; + using (sc) + { + match = sc.ServiceName == ServerService.Name; + if (match) + RestartService(sc); + } + + if (match) { - RestartService(sc); await InvokeSC(ServerService.Name); break; } + } stopped = true; } @@ -157,22 +171,17 @@ namespace Tgstation.Server.Host.Service if (Install) stopped |= await RunServiceInstall(); - if (standardRun) - { - using var service = new ServerService(WatchdogFactory, Trace ? LogLevel.Trace : Debug ? LogLevel.Debug : LogLevel.Information); - ServiceBase.Run(service); - } - if (Restart) foreach (ServiceController sc in ServiceController.GetServices()) - if (sc.ServiceName == ServerService.Name) - { - if (!stopped) - RestartService(sc); + using (sc) + if (sc.ServiceName == ServerService.Name) + { + if (!stopped) + RestartService(sc); - sc.Start(); - break; - } + sc.Start(); + break; + } } /// @@ -183,29 +192,30 @@ namespace Tgstation.Server.Host.Service { // First check if the service already exists bool serviceStopped = false; - if (Force || Environment.UserInteractive) + if (Force || !WindowsServiceHelpers.IsWindowsService()) foreach (ServiceController sc in ServiceController.GetServices()) - { - var serviceName = sc.ServiceName; - if (serviceName == ServerService.Name || serviceName == "tgstation-server-4") + using (sc) { - NativeMethods.DialogResult result = !Force - ? NativeMethods.MessageBox( - default, - $"You already have another TGS service installed ({sc.ServiceName}). Would you like to uninstall it now? Pressing \"No\" will cancel this install.", - "TGS Service", - NativeMethods.MessageBoxButtons.YesNo) - : NativeMethods.DialogResult.Yes; - if (result != NativeMethods.DialogResult.Yes) - return false; // is this needed after exit? + var serviceName = sc.ServiceName; + if (serviceName == ServerService.Name || serviceName == "tgstation-server-4") + { + NativeMethods.DialogResult result = !Force + ? NativeMethods.MessageBox( + default, + $"You already have another TGS service installed ({sc.ServiceName}). Would you like to uninstall it now? Pressing \"No\" will cancel this install.", + "TGS Service", + NativeMethods.MessageBoxButtons.YesNo) + : NativeMethods.DialogResult.Yes; + if (result != NativeMethods.DialogResult.Yes) + return false; // is this needed after exit? - // Stop it first to give it some cleanup time - RestartService(sc); + // Stop it first to give it some cleanup time + RestartService(sc); - // And remove it - await InvokeSC(sc.ServiceName); + // And remove it + await InvokeSC(sc.ServiceName); + } } - } await InvokeSC(null); @@ -225,7 +235,7 @@ namespace Tgstation.Server.Host.Service if (!stop) { serviceController.ExecuteCommand( - ServerService.GetCommand( + PipeCommands.GetCommandId( PipeCommands.CommandDetachingShutdown) .Value); serviceController.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30)); @@ -254,7 +264,13 @@ namespace Tgstation.Server.Host.Service }); var watchdog = WatchdogFactory.CreateWatchdog(new NoopSignalChecker(), loggerFactory); - await watchdog.RunAsync(true, Array.Empty(), cancellationToken); + await watchdog.RunAsync(true, GetPassthroughArgs(), cancellationToken); } + + /// + /// Format into an . + /// + /// formatted as a . + string[] GetPassthroughArgs() => PassthroughArgs?.Split(' ', StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty(); } } diff --git a/src/Tgstation.Server.Host.Service/ServerService.cs b/src/Tgstation.Server.Host.Service/ServerService.cs index c615bc592c..80b0fcfd79 100644 --- a/src/Tgstation.Server.Host.Service/ServerService.cs +++ b/src/Tgstation.Server.Host.Service/ServerService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Pipes; @@ -24,7 +25,7 @@ namespace Tgstation.Server.Host.Service /// /// The canonical windows service name. /// - public const string Name = "tgstation-server"; + public const string Name = Constants.CanonicalPackageName; /// /// The for the . @@ -32,7 +33,12 @@ namespace Tgstation.Server.Host.Service readonly IWatchdogFactory watchdogFactory; /// - /// The minimum for the . + /// The of command line arguments the service was invoked with. + /// + readonly string[] commandLineArguments; + + /// + /// The minimum for the . /// readonly LogLevel minimumLogLevel; @@ -61,28 +67,16 @@ namespace Tgstation.Server.Host.Service /// AnonymousPipeServerStream pipeServer; - /// - /// Gets the value of a given . - /// - /// The . - /// The value of the command or if it was unrecognized. - public static int? GetCommand(string command) - => command switch - { - PipeCommands.CommandStop => 128, // Windows only allows commands 128-256: https://stackoverflow.com/a/62858106 - PipeCommands.CommandGracefulShutdown => 129, - PipeCommands.CommandDetachingShutdown => 130, - _ => null, - }; - /// /// Initializes a new instance of the class. /// /// The value of . - /// The minimum to record in the event log. - public ServerService(IWatchdogFactory watchdogFactory, LogLevel minimumLogLevel) + /// The value of . + /// The minimum to record in the event log. + public ServerService(IWatchdogFactory watchdogFactory, string[] commandLineArguments, LogLevel minimumLogLevel) { this.watchdogFactory = watchdogFactory ?? throw new ArgumentNullException(nameof(watchdogFactory)); + this.commandLineArguments = commandLineArguments ?? throw new ArgumentNullException(nameof(commandLineArguments)); this.minimumLogLevel = minimumLogLevel; ServiceName = Name; } @@ -98,6 +92,11 @@ namespace Tgstation.Server.Host.Service } } + /// + /// Executes the . + /// + public void Run() => Run(this); + /// protected override void Dispose(bool disposing) { @@ -117,7 +116,7 @@ namespace Tgstation.Server.Host.Service var commandsToCheck = PipeCommands.AllCommands; foreach (var stringCommand in commandsToCheck) { - var commandId = GetCommand(stringCommand); + var commandId = PipeCommands.GetCommandId(stringCommand); if (command == commandId) { SendCommandToUpdatePath(stringCommand); @@ -149,7 +148,15 @@ namespace Tgstation.Server.Host.Service cancellationTokenSource?.Dispose(); cancellationTokenSource = new CancellationTokenSource(); - watchdogTask = RunWatchdog(watchdog, args, cancellationTokenSource.Token); + var newArgs = new List(commandLineArguments.Length + args.Length + 1) + { + "--General:SetupWizardMode=Never", + }; + + newArgs.AddRange(commandLineArguments); + newArgs.AddRange(args); + + watchdogTask = RunWatchdog(watchdog, newArgs.ToArray(), cancellationTokenSource.Token); } /// diff --git a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj index 8cbff0695e..0d5b8b429e 100644 --- a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj +++ b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj @@ -3,7 +3,7 @@ WinExe - $(TgsNetVersion)-windows + $(TgsFrameworkVersion)-windows $(TgsCoreVersion) true @@ -26,6 +26,7 @@ + @@ -48,5 +49,5 @@ - + diff --git a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj index 633515ec07..9a8d30a658 100644 --- a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj +++ b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj @@ -2,7 +2,7 @@ - $(TgsNetVersion) + $(TgsFrameworkVersion) Full false $(TgsHostWatchdogVersion) diff --git a/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs b/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs index a4cefdfde1..48b08b5b48 100644 --- a/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs @@ -75,7 +75,8 @@ namespace Tgstation.Server.Host.Configuration ? Directory : ioManager.ConcatPath( directoryToUse, - assemblyInformationProvider.VersionPrefix); + assemblyInformationProvider.VersionPrefix, + "logs"); } } } diff --git a/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs b/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs index d97c8a501c..0d54f24d73 100644 --- a/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs @@ -19,5 +19,10 @@ /// If the server is running under SystemD. /// public bool UsingSystemD { get; set; } + + /// + /// The base path for the app settings configuration files. + /// + public string AppSettingsBasePath { get; set; } } } diff --git a/src/Tgstation.Server.Host/ServerFactory.cs b/src/Tgstation.Server.Host/ServerFactory.cs index 9dddebff23..3e14cdb5a9 100644 --- a/src/Tgstation.Server.Host/ServerFactory.cs +++ b/src/Tgstation.Server.Host/ServerFactory.cs @@ -10,6 +10,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; +using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Core; using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.IO; @@ -59,14 +60,27 @@ namespace Tgstation.Server.Host args[oldArgs.Length] = "--hostBuilder:reloadConfigOnChange=false"; } - var basePath = IOManager.ResolvePath(); + const string AppSettings = "appsettings"; + const string AppSettingsRelocationKey = $"--{AppSettings}-base-path="; + + var appsettingsRelativeBasePathArgument = args.FirstOrDefault(arg => arg.StartsWith(AppSettingsRelocationKey, StringComparison.Ordinal)); + string basePath; + if (appsettingsRelativeBasePathArgument != null) + basePath = IOManager.ResolvePath(appsettingsRelativeBasePathArgument[AppSettingsRelocationKey.Length..]); + else + basePath = IOManager.ResolvePath(); + + // this is a massive bloody hack but I don't know a better way to do it + // It's needed for the setup wizard + Environment.SetEnvironmentVariable($"{InternalConfiguration.Section}__{nameof(InternalConfiguration.AppSettingsBasePath)}", basePath); + IHostBuilder CreateDefaultBuilder() => Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((context, builder) => { builder.SetBasePath(basePath); - builder.AddYamlFile("appsettings.yml", optional: true, reloadOnChange: false) - .AddYamlFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.yml", optional: true, reloadOnChange: false); + builder.AddYamlFile($"{AppSettings}.yml", optional: true, reloadOnChange: false) + .AddYamlFile($"{AppSettings}.{context.HostingEnvironment.EnvironmentName}.yml", optional: true, reloadOnChange: false); // reorganize the builder so our yaml configs don't override the env/cmdline configs // values obtained via debugger diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index c0fbbbb042..4b4654ca4b 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -27,6 +27,7 @@ using Tgstation.Server.Host.Extensions.Converters; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; + using YamlDotNet.Serialization; namespace Tgstation.Server.Host.Setup @@ -79,6 +80,11 @@ namespace Tgstation.Server.Host.Setup /// readonly GeneralConfiguration generalConfiguration; + /// + /// The for the . + /// + readonly InternalConfiguration internalConfiguration; + /// /// A that will complete when the is reloaded. /// @@ -97,6 +103,7 @@ namespace Tgstation.Server.Host.Setup /// The value of . /// The in use. /// The containing the value of . + /// The containing the value of . public SetupWizard( IIOManager ioManager, IConsole console, @@ -107,7 +114,8 @@ namespace Tgstation.Server.Host.Setup IAsyncDelayer asyncDelayer, IHostApplicationLifetime applicationLifetime, IConfiguration configuration, - IOptions generalConfigurationOptions) + IOptions generalConfigurationOptions, + IOptions internalConfigurationOptions) { this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.console = console ?? throw new ArgumentNullException(nameof(console)); @@ -120,6 +128,7 @@ namespace Tgstation.Server.Host.Setup ArgumentNullException.ThrowIfNull(configuration); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); + internalConfiguration = internalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(internalConfigurationOptions)); configuration .GetReloadToken() @@ -297,7 +306,13 @@ namespace Tgstation.Server.Host.Setup /// A resulting in the SQLite database path to store in the configuration. async Task ValidateNonExistantSqliteDBName(string databaseName, CancellationToken cancellationToken) { - var resolvedPath = ioManager.ResolvePath(databaseName); + var dbPathIsRooted = Path.IsPathRooted(databaseName); + var resolvedPath = ioManager.ResolvePath( + dbPathIsRooted + ? databaseName + : ioManager.ConcatPath( + internalConfiguration.AppSettingsBasePath, + databaseName)); try { var directoryName = ioManager.GetDirectoryName(resolvedPath); @@ -319,9 +334,9 @@ namespace Tgstation.Server.Host.Setup return null; } - if (!Path.IsPathRooted(databaseName)) + if (!dbPathIsRooted) { - await console.WriteAsync("Note, this relative path (currently) resolves to the following:", true, cancellationToken); + await console.WriteAsync("Note, this relative path currently resolves to the following:", true, cancellationToken); await console.WriteAsync(resolvedPath, true, cancellationToken); bool writeResolved = await PromptYesNo( "Would you like to save the relative path in the configuration? If not, the full path will be saved.", @@ -355,8 +370,6 @@ namespace Tgstation.Server.Host.Setup "It is, however, the easiest option to get started with and will pose few if any problems in a single user scenario.", true, cancellationToken); - - await asyncDelayer.Delay(TimeSpan.FromSeconds(3), cancellationToken); } await console.WriteAsync("What SQL database type will you be using?", true, cancellationToken); @@ -962,7 +975,10 @@ namespace Tgstation.Server.Host.Setup try { - await ioManager.WriteAllBytes(userConfigFileName, configBytes, cancellationToken); + await ioManager.WriteAllBytes( + userConfigFileName, + configBytes, + cancellationToken); // Ensure the reload if (generalConfiguration.SetupWizardMode != SetupWizardMode.Only) @@ -1046,7 +1062,9 @@ namespace Tgstation.Server.Host.Setup return; } - var userConfigFileName = String.Format(CultureInfo.InvariantCulture, "appsettings.{0}.yml", hostingEnvironment.EnvironmentName); + var userConfigFileName = ioManager.ConcatPath( + internalConfiguration.AppSettingsBasePath, + String.Format(CultureInfo.InvariantCulture, "appsettings.{0}.yml", hostingEnvironment.EnvironmentName)); async Task HandleSetupCancel() { diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index e7abd5846f..5673e4096d 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -2,7 +2,7 @@ - $(TgsNetVersion) + $(TgsFrameworkVersion) $(TgsCoreVersion) true true diff --git a/tests/Tgstation.Server.Api.Tests/Tgstation.Server.Api.Tests.csproj b/tests/Tgstation.Server.Api.Tests/Tgstation.Server.Api.Tests.csproj index 4cdf2fb2a0..8443db7356 100644 --- a/tests/Tgstation.Server.Api.Tests/Tgstation.Server.Api.Tests.csproj +++ b/tests/Tgstation.Server.Api.Tests/Tgstation.Server.Api.Tests.csproj @@ -2,7 +2,7 @@ - $(TgsNetVersion) + $(TgsFrameworkVersion) diff --git a/tests/Tgstation.Server.Client.Tests/Tgstation.Server.Client.Tests.csproj b/tests/Tgstation.Server.Client.Tests/Tgstation.Server.Client.Tests.csproj index 6b82ba7671..0d2d877fe1 100644 --- a/tests/Tgstation.Server.Client.Tests/Tgstation.Server.Client.Tests.csproj +++ b/tests/Tgstation.Server.Client.Tests/Tgstation.Server.Client.Tests.csproj @@ -2,7 +2,7 @@ - $(TgsNetVersion) + $(TgsFrameworkVersion) diff --git a/tests/Tgstation.Server.Host.Console.Tests/Tgstation.Server.Host.Console.Tests.csproj b/tests/Tgstation.Server.Host.Console.Tests/Tgstation.Server.Host.Console.Tests.csproj index 282b1742c7..e0d44a649e 100644 --- a/tests/Tgstation.Server.Host.Console.Tests/Tgstation.Server.Host.Console.Tests.csproj +++ b/tests/Tgstation.Server.Host.Console.Tests/Tgstation.Server.Host.Console.Tests.csproj @@ -2,7 +2,7 @@ - $(TgsNetVersion) + $(TgsFrameworkVersion) diff --git a/tests/Tgstation.Server.Host.Service.Tests/TestServerService.cs b/tests/Tgstation.Server.Host.Service.Tests/TestServerService.cs index 13fb19381e..19d2f60d69 100644 --- a/tests/Tgstation.Server.Host.Service.Tests/TestServerService.cs +++ b/tests/Tgstation.Server.Host.Service.Tests/TestServerService.cs @@ -19,9 +19,10 @@ namespace Tgstation.Server.Host.Service.Tests [TestMethod] public void TestConstructionAndDisposal() { - Assert.ThrowsException(() => new ServerService(null, default)); + Assert.ThrowsException(() => new ServerService(null, null, default)); var mockWatchdogFactory = new Mock(); - new ServerService(mockWatchdogFactory.Object, default).Dispose(); + Assert.ThrowsException(() => new ServerService(mockWatchdogFactory.Object, null, default)); + new ServerService(mockWatchdogFactory.Object, Array.Empty(), default).Dispose(); } [TestMethod] @@ -38,7 +39,7 @@ namespace Tgstation.Server.Host.Service.Tests var mockWatchdogFactory = new Mock(); mockWatchdogFactory.Setup(x => x.CreateWatchdog(It.IsNotNull(), It.IsNotNull())).Returns(mockWatchdog.Object).Verifiable(); - using (var service = new ServerService(mockWatchdogFactory.Object, default)) + using (var service = new ServerService(mockWatchdogFactory.Object, Array.Empty(), default)) { onStart.Invoke(service, new object[] { args }); onStop.Invoke(service, Array.Empty()); diff --git a/tests/Tgstation.Server.Host.Service.Tests/Tgstation.Server.Host.Service.Tests.csproj b/tests/Tgstation.Server.Host.Service.Tests/Tgstation.Server.Host.Service.Tests.csproj index ddd3745a96..54971a8c9f 100644 --- a/tests/Tgstation.Server.Host.Service.Tests/Tgstation.Server.Host.Service.Tests.csproj +++ b/tests/Tgstation.Server.Host.Service.Tests/Tgstation.Server.Host.Service.Tests.csproj @@ -2,7 +2,7 @@ - $(TgsNetVersion)-windows + $(TgsFrameworkVersion)-windows 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 ce86279440..c67edb6003 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 @@ -2,7 +2,7 @@ - $(TgsNetVersion) + $(TgsFrameworkVersion) Exe diff --git a/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs b/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs index 4ee9dfd632..76e2e26ee0 100644 --- a/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs +++ b/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs @@ -27,26 +27,28 @@ namespace Tgstation.Server.Host.Setup.Tests [TestMethod] public void TestConstructionThrows() { - Assert.ThrowsException(() => new SetupWizard(null, null, null, null, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(null, null, null, null, null, null, null, null, null, null, null)); var mockIOManager = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, null, null, null, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, null, null, null, null, null, null, null, null, null, null)); var mockConsole = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, null, null, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, null, null, null, null, null, null, null, null, null)); var mockHostingEnvironment = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, null, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, null, null, null, null, null, null, null, null)); var mockAssemblyInfoProvider = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, null, null, null, null, null, null, null)); var mockDBConnectionFactory = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, null, null, null, null, null, null)); var mockPlatformIdentifier = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, null, null, null, null, null)); var mockAsyncDelayer = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, null, null, null, null)); var mockLifetime = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, null, null, null)); var mockConfiguration = new Mock(); mockConfiguration.Setup(x => x.GetReloadToken()).Returns(Mock.Of()); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, mockConfiguration.Object, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, mockConfiguration.Object, null, null)); + var mockGeneralConfigurationOptions = Options.Create(new GeneralConfiguration()); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, mockConfiguration.Object, mockGeneralConfigurationOptions, null)); } [TestMethod] @@ -59,6 +61,7 @@ namespace Tgstation.Server.Host.Setup.Tests var mockDBConnectionFactory = new Mock(); var mockLifetime = new Mock(); var mockGeneralConfigurationOptions = new Mock>(); + var mockInternalConfigurationOptions = new Mock>(); var mockPlatformIdentifier = new Mock(); var mockAsyncDelayer = new Mock(); var mockConfiguration = new Mock(); @@ -85,8 +88,24 @@ namespace Tgstation.Server.Host.Setup.Tests }; mockGeneralConfigurationOptions.SetupGet(x => x.Value).Returns(testGeneralConfig).Verifiable(); - var wizard = new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, mockConfiguration.Object, mockGeneralConfigurationOptions.Object); + var testInternalConfig = new InternalConfiguration + { + AppSettingsBasePath = "asdfasdfasdf" + }; + mockInternalConfigurationOptions.SetupGet(x => x.Value).Returns(testInternalConfig).Verifiable(); + var wizard = new SetupWizard( + mockIOManager.Object, + mockConsole.Object, + mockHostingEnvironment.Object, + mockAssemblyInfoProvider.Object, + mockDBConnectionFactory.Object, + mockPlatformIdentifier.Object, + mockAsyncDelayer.Object, + mockLifetime.Object, + mockConfiguration.Object, + mockGeneralConfigurationOptions.Object, + mockInternalConfigurationOptions.Object); mockPlatformIdentifier.SetupGet(x => x.IsWindows).Returns(true).Verifiable(); mockAsyncDelayer.Setup(x => x.Delay(It.IsAny(), It.IsAny())).Returns(Task.CompletedTask).Verifiable(); @@ -100,6 +119,11 @@ namespace Tgstation.Server.Host.Setup.Tests await Assert.ThrowsExceptionAsync(() => RunWizard()); mockConsole.SetupGet(x => x.Available).Returns(true).Verifiable(); + mockIOManager.Setup(x => x.ConcatPath(testInternalConfig.AppSettingsBasePath, It.IsNotNull())).Returns(paths => + { + Assert.AreEqual(2, paths.Length); + return $"{paths[0]}/{paths[1]}"; + }).Verifiable(); mockIOManager.Setup(x => x.FileExists(It.IsNotNull(), It.IsAny())).Returns(Task.FromResult(true)).Verifiable(); mockIOManager.Setup(x => x.ReadAllBytes(It.IsNotNull(), It.IsAny())).Returns(Task.FromResult(Encoding.UTF8.GetBytes("less profane"))).Verifiable(); mockIOManager @@ -323,6 +347,7 @@ namespace Tgstation.Server.Host.Setup.Tests mockSuccessCommand.VerifyAll(); mockIOManager.VerifyAll(); mockGeneralConfigurationOptions.VerifyAll(); + mockInternalConfigurationOptions.VerifyAll(); mockConsole.VerifyAll(); mockGoodDbConnection.VerifyAll(); mockBadDbConnection.VerifyAll(); diff --git a/tests/Tgstation.Server.Host.Tests/Tgstation.Server.Host.Tests.csproj b/tests/Tgstation.Server.Host.Tests/Tgstation.Server.Host.Tests.csproj index b5449c75c4..5f0701e388 100644 --- a/tests/Tgstation.Server.Host.Tests/Tgstation.Server.Host.Tests.csproj +++ b/tests/Tgstation.Server.Host.Tests/Tgstation.Server.Host.Tests.csproj @@ -2,7 +2,7 @@ - $(TgsNetVersion) + $(TgsFrameworkVersion) diff --git a/tests/Tgstation.Server.Host.Watchdog.Tests/Tgstation.Server.Host.Watchdog.Tests.csproj b/tests/Tgstation.Server.Host.Watchdog.Tests/Tgstation.Server.Host.Watchdog.Tests.csproj index 21a8d65ba5..a3762c1162 100644 --- a/tests/Tgstation.Server.Host.Watchdog.Tests/Tgstation.Server.Host.Watchdog.Tests.csproj +++ b/tests/Tgstation.Server.Host.Watchdog.Tests/Tgstation.Server.Host.Watchdog.Tests.csproj @@ -2,7 +2,7 @@ - $(TgsNetVersion) + $(TgsFrameworkVersion) diff --git a/tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj b/tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj index 7f3dd2a0aa..925be86ff4 100644 --- a/tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj +++ b/tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj @@ -2,7 +2,7 @@ - $(TgsNetVersion) + $(TgsFrameworkVersion) diff --git a/tgstation-server.sln b/tgstation-server.sln index 00b15f676c..0eb2f3f898 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -222,7 +222,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "debian", "debian", "{08E7C6 build\package\deb\debian\control = build\package\deb\debian\control build\package\deb\debian\copyright = build\package\deb\debian\copyright build\package\deb\install_artifacts.sh = build\package\deb\install_artifacts.sh - build\package\deb\debian\links = build\package\deb\debian\links build\package\deb\debian\postinst = build\package\deb\debian\postinst build\package\deb\debian\prerm = build\package\deb\debian\prerm build\package\deb\debian\rules = build\package\deb\debian\rules @@ -235,9 +234,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "upstream", "upstream", "{B4 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "winget", "winget", "{506B9092-AF88-4DA2-84FD-C11646B695B0}" ProjectSection(SolutionItems) = preProject - build\package\winget\build_msi.ps1 = build\package\winget\build_msi.ps1 - build\package\winget\installer.sln = build\package\winget\installer.sln build\package\winget\install_banner.jpg = build\package\winget\install_banner.jpg + build\package\winget\prepare_installer_input_artifacts.ps1 = build\package\winget\prepare_installer_input_artifacts.ps1 build\package\winget\push_manifest.ps1 = build\package\winget\push_manifest.ps1 EndProjectSection EndProject @@ -248,174 +246,186 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "manifest", "manifest", "{3F build\package\winget\manifest\Tgstation.Server.yaml = build\package\winget\manifest\Tgstation.Server.yaml EndProjectSection EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tgstation.Server.Host.Service.Msi", "Tgstation.Server.Host.Service.Msi", "{F5B9D394-229B-44A1-AD12-D8C078F06814}" - ProjectSection(SolutionItems) = preProject - build\package\winget\Tgstation.Server.Host.Service.Msi\README.md = build\package\winget\Tgstation.Server.Host.Service.Msi\README.md - build\package\winget\Tgstation.Server.Host.Service.Msi\Tgstation.Server.Host.Service.Msi.vdproj = build\package\winget\Tgstation.Server.Host.Service.Msi\Tgstation.Server.Host.Service.Msi.vdproj - EndProjectSection +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tgstation.Server.Host.Service.Wix.Extensions", "build\package\winget\Tgstation.Server.Host.Service.Wix.Extensions\Tgstation.Server.Host.Service.Wix.Extensions.csproj", "{28669D98-E15D-4A62-B1D1-7C11D4CB1DE0}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tgstation.Server.Host.Service.Configure", "Tgstation.Server.Host.Service.Configure", "{5DDA72D5-DBFD-4FB2-9EAB-61D047145246}" - ProjectSection(SolutionItems) = preProject - build\package\winget\Tgstation.Server.Host.Service.Configure\Program.cs = build\package\winget\Tgstation.Server.Host.Service.Configure\Program.cs - build\package\winget\Tgstation.Server.Host.Service.Configure\Tgstation.Server.Host.Service.Configure.csproj = build\package\winget\Tgstation.Server.Host.Service.Configure\Tgstation.Server.Host.Service.Configure.csproj - EndProjectSection +Project("{B7DD6F7E-DEF8-4E67-B5B7-07EF123DB6F0}") = "Tgstation.Server.Host.Service.Wix", "build\package\winget\Tgstation.Server.Host.Service.Wix\Tgstation.Server.Host.Service.Wix.wixproj", "{82996E9D-5E63-4CC5-8179-612C71B4F56C}" +EndProject +Project("{B7DD6F7E-DEF8-4E67-B5B7-07EF123DB6F0}") = "Tgstation.Server.Host.Service.Wix.Bundle", "build\package\winget\Tgstation.Server.Host.Service.Wix.Bundle\Tgstation.Server.Host.Service.Wix.Bundle.wixproj", "{9E66C6F1-E235-4979-83B5-C2B3FDAD6E01}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU - DebugNoFramework|Any CPU = DebugNoFramework|Any CPU + DebugNoWindows|Any CPU = DebugNoWindows|Any CPU Release|Any CPU = Release|Any CPU - ReleaseNoFramework|Any CPU = ReleaseNoFramework|Any CPU + ReleaseNoWindows|Any CPU = ReleaseNoWindows|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU - {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU + {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Release|Any CPU.ActiveCfg = Release|Any CPU {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Release|Any CPU.Build.0 = Release|Any CPU - {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU - {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU + {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.Release|Any CPU.ActiveCfg = Release|Any CPU {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.Release|Any CPU.Build.0 = Release|Any CPU - {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU {D36B99C4-E771-42D6-A95F-1102B3E236DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D36B99C4-E771-42D6-A95F-1102B3E236DF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D36B99C4-E771-42D6-A95F-1102B3E236DF}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU - {D36B99C4-E771-42D6-A95F-1102B3E236DF}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU + {D36B99C4-E771-42D6-A95F-1102B3E236DF}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {D36B99C4-E771-42D6-A95F-1102B3E236DF}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU {D36B99C4-E771-42D6-A95F-1102B3E236DF}.Release|Any CPU.ActiveCfg = Release|Any CPU {D36B99C4-E771-42D6-A95F-1102B3E236DF}.Release|Any CPU.Build.0 = Release|Any CPU - {D36B99C4-E771-42D6-A95F-1102B3E236DF}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {D36B99C4-E771-42D6-A95F-1102B3E236DF}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {D36B99C4-E771-42D6-A95F-1102B3E236DF}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {D36B99C4-E771-42D6-A95F-1102B3E236DF}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU {8B4A208D-A48A-4A5D-8B94-E2661138865D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8B4A208D-A48A-4A5D-8B94-E2661138865D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8B4A208D-A48A-4A5D-8B94-E2661138865D}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU - {8B4A208D-A48A-4A5D-8B94-E2661138865D}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU + {8B4A208D-A48A-4A5D-8B94-E2661138865D}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {8B4A208D-A48A-4A5D-8B94-E2661138865D}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU {8B4A208D-A48A-4A5D-8B94-E2661138865D}.Release|Any CPU.ActiveCfg = Release|Any CPU {8B4A208D-A48A-4A5D-8B94-E2661138865D}.Release|Any CPU.Build.0 = Release|Any CPU - {8B4A208D-A48A-4A5D-8B94-E2661138865D}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {8B4A208D-A48A-4A5D-8B94-E2661138865D}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {8B4A208D-A48A-4A5D-8B94-E2661138865D}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {8B4A208D-A48A-4A5D-8B94-E2661138865D}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU {29927416-3B78-49A7-A560-5CCAA638B6B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {29927416-3B78-49A7-A560-5CCAA638B6B4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {29927416-3B78-49A7-A560-5CCAA638B6B4}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {29927416-3B78-49A7-A560-5CCAA638B6B4}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {29927416-3B78-49A7-A560-5CCAA638B6B4}.Release|Any CPU.ActiveCfg = Release|Any CPU {29927416-3B78-49A7-A560-5CCAA638B6B4}.Release|Any CPU.Build.0 = Release|Any CPU - {29927416-3B78-49A7-A560-5CCAA638B6B4}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {29927416-3B78-49A7-A560-5CCAA638B6B4}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU - {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU + {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.Release|Any CPU.ActiveCfg = Release|Any CPU {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.Release|Any CPU.Build.0 = Release|Any CPU - {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU - {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU + {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.Release|Any CPU.ActiveCfg = Release|Any CPU {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.Release|Any CPU.Build.0 = Release|Any CPU - {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU - {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU + {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.Release|Any CPU.ActiveCfg = Release|Any CPU {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.Release|Any CPU.Build.0 = Release|Any CPU - {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU - {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU + {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.Release|Any CPU.ActiveCfg = Release|Any CPU {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.Release|Any CPU.Build.0 = Release|Any CPU - {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU - {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU + {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Release|Any CPU.ActiveCfg = Release|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Release|Any CPU.Build.0 = Release|Any CPU - {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU {7500F776-4384-4B5F-A8D8-22461CAD108B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7500F776-4384-4B5F-A8D8-22461CAD108B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7500F776-4384-4B5F-A8D8-22461CAD108B}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU - {7500F776-4384-4B5F-A8D8-22461CAD108B}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU + {7500F776-4384-4B5F-A8D8-22461CAD108B}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {7500F776-4384-4B5F-A8D8-22461CAD108B}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU {7500F776-4384-4B5F-A8D8-22461CAD108B}.Release|Any CPU.ActiveCfg = Release|Any CPU {7500F776-4384-4B5F-A8D8-22461CAD108B}.Release|Any CPU.Build.0 = Release|Any CPU - {7500F776-4384-4B5F-A8D8-22461CAD108B}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {7500F776-4384-4B5F-A8D8-22461CAD108B}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {7500F776-4384-4B5F-A8D8-22461CAD108B}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {7500F776-4384-4B5F-A8D8-22461CAD108B}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU + {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.Release|Any CPU.ActiveCfg = Release|Any CPU {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.Release|Any CPU.Build.0 = Release|Any CPU - {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU + {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {09056964-1C74-445A-96EC-33F6DFC07916}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {09056964-1C74-445A-96EC-33F6DFC07916}.Debug|Any CPU.Build.0 = Debug|Any CPU - {09056964-1C74-445A-96EC-33F6DFC07916}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU - {09056964-1C74-445A-96EC-33F6DFC07916}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU + {09056964-1C74-445A-96EC-33F6DFC07916}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {09056964-1C74-445A-96EC-33F6DFC07916}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU {09056964-1C74-445A-96EC-33F6DFC07916}.Release|Any CPU.ActiveCfg = Release|Any CPU {09056964-1C74-445A-96EC-33F6DFC07916}.Release|Any CPU.Build.0 = Release|Any CPU - {09056964-1C74-445A-96EC-33F6DFC07916}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {09056964-1C74-445A-96EC-33F6DFC07916}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {09056964-1C74-445A-96EC-33F6DFC07916}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {09056964-1C74-445A-96EC-33F6DFC07916}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU - {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU + {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.Release|Any CPU.ActiveCfg = Release|Any CPU {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.Release|Any CPU.Build.0 = Release|Any CPU - {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU {5813CC33-B16C-485D-A74D-20204DDF6542}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5813CC33-B16C-485D-A74D-20204DDF6542}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5813CC33-B16C-485D-A74D-20204DDF6542}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU - {5813CC33-B16C-485D-A74D-20204DDF6542}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU + {5813CC33-B16C-485D-A74D-20204DDF6542}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {5813CC33-B16C-485D-A74D-20204DDF6542}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU {5813CC33-B16C-485D-A74D-20204DDF6542}.Release|Any CPU.ActiveCfg = Release|Any CPU {5813CC33-B16C-485D-A74D-20204DDF6542}.Release|Any CPU.Build.0 = Release|Any CPU - {5813CC33-B16C-485D-A74D-20204DDF6542}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {5813CC33-B16C-485D-A74D-20204DDF6542}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {5813CC33-B16C-485D-A74D-20204DDF6542}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {5813CC33-B16C-485D-A74D-20204DDF6542}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU {CE499888-B22B-457C-891E-0EA9DC317228}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CE499888-B22B-457C-891E-0EA9DC317228}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CE499888-B22B-457C-891E-0EA9DC317228}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU - {CE499888-B22B-457C-891E-0EA9DC317228}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU + {CE499888-B22B-457C-891E-0EA9DC317228}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {CE499888-B22B-457C-891E-0EA9DC317228}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU {CE499888-B22B-457C-891E-0EA9DC317228}.Release|Any CPU.ActiveCfg = Release|Any CPU {CE499888-B22B-457C-891E-0EA9DC317228}.Release|Any CPU.Build.0 = Release|Any CPU - {CE499888-B22B-457C-891E-0EA9DC317228}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {CE499888-B22B-457C-891E-0EA9DC317228}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {CE499888-B22B-457C-891E-0EA9DC317228}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {CE499888-B22B-457C-891E-0EA9DC317228}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU - {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU + {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.Release|Any CPU.ActiveCfg = Release|Any CPU {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.Release|Any CPU.Build.0 = Release|Any CPU - {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU - {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU + {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Release|Any CPU.ActiveCfg = Release|Any CPU {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Release|Any CPU.Build.0 = Release|Any CPU - {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.DebugNoFramework|Any CPU.ActiveCfg = Debug|Any CPU - {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.DebugNoFramework|Any CPU.Build.0 = Debug|Any CPU + {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Release|Any CPU.ActiveCfg = Release|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Release|Any CPU.Build.0 = Release|Any CPU - {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.ReleaseNoFramework|Any CPU.ActiveCfg = Release|Any CPU - {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.ReleaseNoFramework|Any CPU.Build.0 = Release|Any CPU + {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {28669D98-E15D-4A62-B1D1-7C11D4CB1DE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28669D98-E15D-4A62-B1D1-7C11D4CB1DE0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28669D98-E15D-4A62-B1D1-7C11D4CB1DE0}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {28669D98-E15D-4A62-B1D1-7C11D4CB1DE0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28669D98-E15D-4A62-B1D1-7C11D4CB1DE0}.Release|Any CPU.Build.0 = Release|Any CPU + {28669D98-E15D-4A62-B1D1-7C11D4CB1DE0}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {82996E9D-5E63-4CC5-8179-612C71B4F56C}.Debug|Any CPU.ActiveCfg = Debug|x86 + {82996E9D-5E63-4CC5-8179-612C71B4F56C}.Debug|Any CPU.Build.0 = Debug|x86 + {82996E9D-5E63-4CC5-8179-612C71B4F56C}.DebugNoWindows|Any CPU.ActiveCfg = Debug|x86 + {82996E9D-5E63-4CC5-8179-612C71B4F56C}.Release|Any CPU.ActiveCfg = Release|x86 + {82996E9D-5E63-4CC5-8179-612C71B4F56C}.Release|Any CPU.Build.0 = Release|x86 + {82996E9D-5E63-4CC5-8179-612C71B4F56C}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|x86 + {9E66C6F1-E235-4979-83B5-C2B3FDAD6E01}.Debug|Any CPU.ActiveCfg = Debug|x86 + {9E66C6F1-E235-4979-83B5-C2B3FDAD6E01}.Debug|Any CPU.Build.0 = Debug|x86 + {9E66C6F1-E235-4979-83B5-C2B3FDAD6E01}.DebugNoWindows|Any CPU.ActiveCfg = Debug|x86 + {9E66C6F1-E235-4979-83B5-C2B3FDAD6E01}.Release|Any CPU.ActiveCfg = Release|x86 + {9E66C6F1-E235-4979-83B5-C2B3FDAD6E01}.Release|Any CPU.Build.0 = Release|x86 + {9E66C6F1-E235-4979-83B5-C2B3FDAD6E01}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -450,8 +460,9 @@ Global {B4B5570C-8071-46DE-BB55-64C13480C606} = {08E7C650-A447-4DE2-974E-ED123B50F8D6} {506B9092-AF88-4DA2-84FD-C11646B695B0} = {2648A85F-61AE-428E-95E1-66D06C7A3768} {3F141E03-6ABB-46A8-AA24-1B4B6814E58F} = {506B9092-AF88-4DA2-84FD-C11646B695B0} - {F5B9D394-229B-44A1-AD12-D8C078F06814} = {506B9092-AF88-4DA2-84FD-C11646B695B0} - {5DDA72D5-DBFD-4FB2-9EAB-61D047145246} = {506B9092-AF88-4DA2-84FD-C11646B695B0} + {28669D98-E15D-4A62-B1D1-7C11D4CB1DE0} = {506B9092-AF88-4DA2-84FD-C11646B695B0} + {82996E9D-5E63-4CC5-8179-612C71B4F56C} = {506B9092-AF88-4DA2-84FD-C11646B695B0} + {9E66C6F1-E235-4979-83B5-C2B3FDAD6E01} = {506B9092-AF88-4DA2-84FD-C11646B695B0} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DFD36C95-3E49-41C7-ACDB-86BAF5B18A79} diff --git a/tools/ReleaseNotes/ReleaseNotes.csproj b/tools/ReleaseNotes/ReleaseNotes.csproj index d2a5370e27..2f2e6ab506 100644 --- a/tools/ReleaseNotes/ReleaseNotes.csproj +++ b/tools/ReleaseNotes/ReleaseNotes.csproj @@ -3,7 +3,7 @@ Exe - $(TgsNetVersion) + $(TgsFrameworkVersion) diff --git a/tools/Tgstation.Server.Migrator/Program.cs b/tools/Tgstation.Server.Migrator/Program.cs index e0760c9d77..046a6c7308 100644 --- a/tools/Tgstation.Server.Migrator/Program.cs +++ b/tools/Tgstation.Server.Migrator/Program.cs @@ -22,6 +22,7 @@ using Octokit; using Tgstation.Server.Api; using Tgstation.Server.Client; using Tgstation.Server.Common.Http; +using Tgstation.Server.Host.Common; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Setup; @@ -121,7 +122,7 @@ try Console.WriteLine("Checking for TGS3 service..."); const string OldServiceName = "TG Station Server"; - const string NewServiceName = "tgstation-server"; + const string NewServiceName = Constants.CanonicalPackageName; static ServiceController GetTgs3Service(bool checkNewOneIsntInstalled) { @@ -153,7 +154,7 @@ try return tgs3Service; } - var tgs3Service = GetTgs3Service(true); + using var tgs3Service = GetTgs3Service(true); if (tgs3Service.Status != ServiceControllerStatus.Running) { @@ -439,7 +440,7 @@ try installer.DisplayName = "/tg/station server"; installer.StartType = ServiceStartMode.Automatic; installer.ServicesDependedOn = new string[] { "Tcpip", "Dhcp", "Dnscache" }; - installer.ServiceName = "tgstation-server"; + installer.ServiceName = NewServiceName; installer.Parent = processInstaller; var state = new ListDictionary(); @@ -527,7 +528,6 @@ try managementObject.InvokeMethod("ChangeStartMode", new object[] { "Disabled" }); } - tgs3Service = GetTgs3Service(false); if(tgs3Service.StartType != ServiceStartMode.Disabled) Console.WriteLine("Failed to disable TGS3 service! This isn't critical, however."); diff --git a/tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj b/tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj index 550a5f0ac8..a74f718d7c 100644 --- a/tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj +++ b/tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj @@ -1,20 +1,20 @@  - + Exe - $(TgsNetVersion) + $(TgsFrameworkVersion) win-x86 $(TgsMigratorVersion) enable CA1416 false - + - + From 5a65b36ad6baea3e33a3d94869d20c17e85d031c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 03:55:04 -0400 Subject: [PATCH 105/160] Add README.mds for all Nuget packages --- build/NugetCommon.props | 2 ++ src/Tgstation.Server.Api/README.md | 8 ++------ src/Tgstation.Server.Client/README.md | 28 +++++++++++++++++++++++++++ src/Tgstation.Server.Common/README.md | 3 +++ 4 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 src/Tgstation.Server.Client/README.md create mode 100644 src/Tgstation.Server.Common/README.md diff --git a/build/NugetCommon.props b/build/NugetCommon.props index d844ff4b1a..886f98c028 100644 --- a/build/NugetCommon.props +++ b/build/NugetCommon.props @@ -7,6 +7,7 @@ /tg/station 13 https://tgstation.github.io/tgstation-server LICENSE + README.md tgs.png Git https://github.com/tgstation/tgstation-server @@ -17,6 +18,7 @@ + diff --git a/src/Tgstation.Server.Api/README.md b/src/Tgstation.Server.Api/README.md index bbfc100bcc..97a3631f44 100644 --- a/src/Tgstation.Server.Api/README.md +++ b/src/Tgstation.Server.Api/README.md @@ -1,7 +1,3 @@ -# TGS API Definitions +# tgstation-server API Definitions -This assembly defines models and routes for communicating with TGS. - -- Data models are stored in the [Models](./Models) directory. -- Rights enums are stored in the [Rights](./Rights) directory. -- API routes are defined in the [Routes.cs](./Routes.cs) file. +This assembly defines HTTP headers, default credentials, models, rights, and routes for communicating with the [tgstation-server](http://github.com/tgstation/tgstation-server) API. diff --git a/src/Tgstation.Server.Client/README.md b/src/Tgstation.Server.Client/README.md new file mode 100644 index 0000000000..e958404fd9 --- /dev/null +++ b/src/Tgstation.Server.Client/README.md @@ -0,0 +1,28 @@ +# tgstation-server Client Library + +This library is used for accessing [tgstation-server](https://github.com/tgstation/tgstation-server) instances via .NET code. + +## Examples + +### Connecting to a Server: + +```cs +using System.Threading; +using System.Threading.Tasks; + +using Tgstation.Server.Api; +using Tgstation.Server.Client; + +... + +async ValueTask CreateClientWithDefaultCredentials(CancellationToken cancellationToken) +{ + + + return await clientFactory.CreateFromLogin( + url, + DefaultCredentials.AdminUserName, + DefaultCredentials.DefaultAdminUserPassword, + cancellationToken: cancellationToken); +} +``` diff --git a/src/Tgstation.Server.Common/README.md b/src/Tgstation.Server.Common/README.md new file mode 100644 index 0000000000..b6a45d16fd --- /dev/null +++ b/src/Tgstation.Server.Common/README.md @@ -0,0 +1,3 @@ +# tgstation-server Common functionalty + +This library contains common functions used by both the [tgstation-server](https://github.com/tgstation/tgstation-server) host and client. From 2077394524612d870b08178d042fd0e395fbd3c9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 03:55:28 -0400 Subject: [PATCH 106/160] Remove unused using --- .../Deployment/Remote/GitLabRemoteDeploymentManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs index c1f90d5f12..2d554b2bef 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs @@ -11,7 +11,6 @@ using GitLabApiClient.Models.Notes.Requests; using Microsoft.Extensions.Logging; using Tgstation.Server.Host.Components.Repository; -using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.Models; namespace Tgstation.Server.Host.Components.Deployment.Remote From f216c534810c6543a55f7db3915213b43d01eef0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 03:56:34 -0400 Subject: [PATCH 107/160] Correct a documentation comment --- src/Tgstation.Server.Api/ApiHeaders.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Api/ApiHeaders.cs b/src/Tgstation.Server.Api/ApiHeaders.cs index 0ad8c7a487..062e521288 100644 --- a/src/Tgstation.Server.Api/ApiHeaders.cs +++ b/src/Tgstation.Server.Api/ApiHeaders.cs @@ -51,7 +51,7 @@ namespace Tgstation.Server.Api public const string OAuthAuthenticationScheme = "OAuth"; /// - /// Added to in netstandard2.1. Can't use because of Tgstation.Server.Migrator. + /// Added to in netstandard2.1. Can't use because of lack of .NET Framework support. /// public const string ApplicationJsonMime = "application/json"; From df50d5ce0ee6db187061743a7e17a3936ee51196 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 03:56:57 -0400 Subject: [PATCH 108/160] Improve base appsettings documentation --- src/Tgstation.Server.Host/appsettings.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Tgstation.Server.Host/appsettings.yml b/src/Tgstation.Server.Host/appsettings.yml index 10af3e04e7..2371468ca6 100644 --- a/src/Tgstation.Server.Host/appsettings.yml +++ b/src/Tgstation.Server.Host/appsettings.yml @@ -1,3 +1,5 @@ +# Base tgstation-server configuration file +# You SHOULD NOT edit this file. Instead, make changes in its override file: appsettings.Production.yml General: # ConfigVersion: # Basic semver. Differs from TGS version to version. See changelog for current version MinimumPasswordLength: 15 # Minimum TGS user password length From 2a360c119fd7f304a8159f212c78925ba7f2158c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 03:57:17 -0400 Subject: [PATCH 109/160] Fix useless IDE warning in `SessionController` --- .../Components/Session/SessionController.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index 8f7e4fa82a..a5793e38a1 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -21,7 +21,6 @@ using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Components.Interop.Bridge; using Tgstation.Server.Host.Components.Interop.Topic; -using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; @@ -82,17 +81,15 @@ namespace Tgstation.Server.Host.Components.Session get => rebootGate; set { - var tcs = new TaskCompletionSource(); - Task toAwait = null; + var tcs = new TaskCompletionSource(); async Task Wrap() { - await tcs.Task; + var toAwait = await tcs.Task; await toAwait; await value; } - toAwait = Interlocked.Exchange(ref rebootGate, Wrap()); - tcs.SetResult(); + tcs.SetResult(Interlocked.Exchange(ref rebootGate, Wrap())); } } From 2b16ca19d268a9b57ae116c1102f217306ca911e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 03:57:41 -0400 Subject: [PATCH 110/160] Fix default Elasticsearch configuration --- .../ElasticsearchConfiguration.cs | 21 +++---------------- src/Tgstation.Server.Host/Core/Application.cs | 16 +++++++++++--- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/Tgstation.Server.Host/Configuration/ElasticsearchConfiguration.cs b/src/Tgstation.Server.Host/Configuration/ElasticsearchConfiguration.cs index f3e9e92234..07a3afd8e0 100644 --- a/src/Tgstation.Server.Host/Configuration/ElasticsearchConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/ElasticsearchConfiguration.cs @@ -10,21 +10,6 @@ /// public const string Section = "Elasticsearch"; - /// - /// Default value of . - /// - const string DefaultHost = "http://127.0.0.1:9200"; // localhost - - /// - /// Default value of . - /// - const string DefaultUsername = "my_username"; - - /// - /// Default value of . - /// - const string DefaultPassword = "my_password"; - /// /// Do we want to enable elasticsearch or not?. /// @@ -33,16 +18,16 @@ /// /// The host of the elasticsearch endpoint. /// - public string Host { get; set; } = DefaultHost; + public string Host { get; set; } /// /// Username for elasticsearch. /// - public string Username { get; set; } = DefaultUsername; + public string Username { get; set; } /// /// Password for elasticsearch. /// - public string Password { get; set; } = DefaultPassword; + public string Password { get; set; } } } diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 213a55e02a..4a8bb4a152 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -196,11 +196,21 @@ namespace Tgstation.Server.Host.Core rollOnFileSizeLimit: true); }, elasticsearchConfiguration.Enable - ? new ElasticsearchSinkOptions(new Uri(elasticsearchConfiguration.Host ?? throw new InvalidOperationException())) + ? new ElasticsearchSinkOptions( + new Uri( + String.IsNullOrWhiteSpace(elasticsearchConfiguration.Host) + ? throw new InvalidOperationException($"Missing {ElasticsearchConfiguration.Section}:{nameof(elasticsearchConfiguration.Host)}!") + : elasticsearchConfiguration.Host)) { // Yes I know this means they cannot use a self signed cert unless they also have authentication, but lets be real here - // No one is going to be doing one of thsoe but not the other - ModifyConnectionSettings = connectionConfigration => (!string.IsNullOrEmpty(elasticsearchConfiguration.Username) && !string.IsNullOrEmpty(elasticsearchConfiguration.Password)) ? connectionConfigration.BasicAuthentication(elasticsearchConfiguration.Username, elasticsearchConfiguration.Password).ServerCertificateValidationCallback((o, certificate, arg3, arg4) => { return true; }) : null, + // No one is going to be doing one of those but not the other + ModifyConnectionSettings = connectionConfigration => (!String.IsNullOrWhiteSpace(elasticsearchConfiguration.Username) && !String.IsNullOrWhiteSpace(elasticsearchConfiguration.Password)) + ? connectionConfigration + .BasicAuthentication( + elasticsearchConfiguration.Username, + elasticsearchConfiguration.Password) + .ServerCertificateValidationCallback((o, certificate, chain, errors) => true) + : null, CustomFormatter = new EcsTextFormatter(), AutoRegisterTemplate = true, AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv7, From 648d3f5d27ccf345d5a04f4b7186edf10477bdb9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 03:58:26 -0400 Subject: [PATCH 111/160] Use ODR for AssemblyInformationProvider --- .../System/AssemblyInformationProvider.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs b/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs index b2462fc64a..f074d50c4e 100644 --- a/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs +++ b/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs @@ -3,6 +3,7 @@ using System.Net.Http.Headers; using System.Reflection; using Tgstation.Server.Api; +using Tgstation.Server.Host.Common; namespace Tgstation.Server.Host.System { @@ -10,7 +11,7 @@ namespace Tgstation.Server.Host.System sealed class AssemblyInformationProvider : IAssemblyInformationProvider { /// - public string VersionPrefix => "tgstation-server"; + public string VersionPrefix => Constants.CanonicalPackageName; /// public Version Version { get; } From f72bc1446fece4bed087d1d26213e4425e5b8f58 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 03:58:41 -0400 Subject: [PATCH 112/160] Log host watchdog launch arguments --- src/Tgstation.Server.Host.Watchdog/Watchdog.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs index f4fa2ab1b0..5cc8fb12cb 100644 --- a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs @@ -150,8 +150,6 @@ namespace Tgstation.Server.Host.Watchdog }; process.EnableRaisingEvents = true; - logger.LogInformation("Launching host..."); - var killedHostProcess = false; try { @@ -161,6 +159,8 @@ namespace Tgstation.Server.Host.Watchdog if (additionalArg != null) process.StartInfo.Arguments += $" {additionalArg}"; + logger.LogInformation("Launching host with arguments: {arguments}", process.StartInfo.Arguments); + process.Start(); return (process.Id, processTask); } From 5b5b0c019c62156e9d24b98afbab3a6bd2372b41 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 03:58:52 -0400 Subject: [PATCH 113/160] Remove unused using --- src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs b/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs index 7375db59b2..053510b759 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs @@ -9,7 +9,6 @@ using Microsoft.Extensions.Logging; using Octokit; using Tgstation.Server.Host.Configuration; -using Tgstation.Server.Host.Extensions; namespace Tgstation.Server.Host.Utils.GitHub { From 40eaa4900e9479263ba5e72d4e98919b689dc9bc Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 04:00:08 -0400 Subject: [PATCH 114/160] Documentation updates --- .github/CONTRIBUTING.md | 8 ++++++-- README.md | 19 +++++-------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 7f651ed937..d563d8c97c 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -34,9 +34,13 @@ You can of course, as always, ask for help at [#coderbus](irc://irc.rizon.net/co ### Development Environment -You need the Dotnet 6.0 SDK and npm>=v5.7 (in your PATH) to compile the server. In order to build the service version you need a to run on Windows. In order to build the .msi installer, you'll need [Visual Studio 2022](https://visualstudio.microsoft.com/vs/) or greater and the [Visual Studio Installer Projects Extension](https://marketplace.visualstudio.com/items?itemName=VisualStudioClient.MicrosoftVisualStudio2022InstallerProjects). +You need the .NET 6.0 SDK and npm>=v5.7 (in your PATH) to compile the server. -The recommended IDE is Visual Studio 2019 which has installation options for both of these. +The recommended IDE is Visual Studio 2022 or VSCode. + +In order to build the service version and/or the Windows installer you need a to run on Windows. + +In addition, the installer project uses the Wix v4 Toolset which will cause an error on loading the .sln in Visual Studio if the [HeatWave for VS2022 Extension](https://marketplace.visualstudio.com/items?itemName=FireGiant.FireGiantHeatWaveDev17) is not installed. In order to run the integration tests you must have the following environment variables set. To run them more accurately, include the optional ones. - `TGS_TEST_DATABASE_TYPE`: `MySql`, `MariaDB`, `PostgresSql`, or `SqlServer`. diff --git a/README.md b/README.md index cabcb02197..26e6c7460f 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Check if you have `winget` by running the following command. winget --version ``` -If it returns an error that means you don't have winget. You can easily install it by running the following Windows Powershell commands: +If it returns an error that means you don't have winget. You can easily install it by running the following commands in an administrative Windows Powershell instance: ``` Import-Module Appx Invoke-WebRequest -Uri https://www.nuget.org/api/v2/package/Microsoft.UI.Xaml/2.7.3 -OutFile .\microsoft.ui.xaml.2.7.3.zip @@ -68,31 +68,22 @@ Remove-Item .\microsoft.ui.xaml.2.7.3.zip Once winget is installed, simply run the following commands, accepting any prompts that may appear: ```ps -winget install Microsoft.DotNet.HostingBundle.6 winget install tgstation-server ``` -You won't be prompted to run the setup wizard. However, you can do so immediately after via the shortcut placed on your desktop. - -NOTE: - -`winget` should, theoretically, install the ASP .NET Core 6.0 Runtime as a pre-reqiusite. At the time of this writing, this functionality is untested (TODO). If the runtime isn't automatically installed for you, see below for steps on how to download and install it manually. - ##### Installer -If you don't have it installed already, download and install the [ASP .NET Core Runtime Hosting Bundle (>= v6.0)](https://dotnet.microsoft.com/download/dotnet/6.0). Ensure that the `dotnet` executable file is in your system's `PATH` variable (or that of the user's that will be running the server). You can test this by opening a command prompt and running `dotnet --list-runtimes`. - -[Download the latest release .msi](https://github.com/tgstation/tgstation-server/releases/latest). Executing it will take you through the process of installing and configuring your server. +[Download the latest release's tgstation-server-installer.exe](https://github.com/tgstation/tgstation-server/releases/latest). Executing it will take you through the process of installing and configuring your server. ##### Manual If you don't have it installed already, download and install the [ASP .NET Core Runtime Hosting Bundle (>= v6.0)](https://dotnet.microsoft.com/download/dotnet/6.0). Ensure that the `dotnet` executable file is in your system's `PATH` variable (or that of the user's that will be running the server). You can test this by opening a command prompt and running `dotnet --list-runtimes`. -[Download the latest release .zip](https://github.com/tgstation/tgstation-server/releases/latest). You probably want the `ServerService` package. Choose `ServerConsole` if you prefer not to use the Windows service. +[Download the latest release .zip](https://github.com/tgstation/tgstation-server/releases/latest). Typically, you want the `ServerService.zip` package in order to run TGS as a Windows service. Choose `ServerConsole.zip` if you prefer to use a command line daemon. -Extract the .zip file to where you want the server to run from. Note the account running the server must have write and delete access to the `lib` subdirectory. +Extract the .zip file to where you want the server to run from. Note the account running the server must have write, execute, and delete access to the `lib` subdirectory. -If you wish to install the TGS as a service, run `Tgstation.Server.Host.Service.exe`. It should prompt you to install it. Click `Yes` and accept a potential UAC elevation prompt and the setup wizard should run. +If you wish to install the TGS as a service, run `Tgstation.Server.Host.Service.exe`. It should prompt you to install it. Click `Yes` and the setup wizard should run. Should you want a clean start, be sure to first uninstall the service by running `Tgstation.Server.Host.Service.exe -u` from the command line. From 4d00c5c7c7974bd3f6f325190d116eed47491d92 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 16:41:16 -0400 Subject: [PATCH 115/160] Prevent autoapprove firing if there are open tasks --- .github/workflows/auto-approve-dominions-prs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/auto-approve-dominions-prs.yml b/.github/workflows/auto-approve-dominions-prs.yml index 971189179a..87d9a24677 100644 --- a/.github/workflows/auto-approve-dominions-prs.yml +++ b/.github/workflows/auto-approve-dominions-prs.yml @@ -16,7 +16,7 @@ concurrency: jobs: approve-pr-if-dominion-is-author: name: Approve PR if Dominion is Author - if: github.event.pull_request.user.login == 'Cyberboss' && !github.event.pull_request.draft && (github.event.pull_request.base.repo.owner.login == 'tgstation' || github.event.pull_request.base.repo.owner.login == 'Cyberboss') + if: github.event.pull_request.user.login == 'Cyberboss' && !(github.event.pull_request.draft || github.event.pull_request.body.contains('- [ ]')) && (github.event.pull_request.base.repo.owner.login == 'tgstation' || github.event.pull_request.base.repo.owner.login == 'Cyberboss') runs-on: ubuntu-latest steps: - name: GitHub API Call From 898570df29e1be68dcaa64a0896fa073cb9e3c7a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 26 Jun 2023 20:13:11 -0400 Subject: [PATCH 116/160] Fix auto-approve workflow --- .github/workflows/auto-approve-dominions-prs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/auto-approve-dominions-prs.yml b/.github/workflows/auto-approve-dominions-prs.yml index 87d9a24677..8f7cc8cba4 100644 --- a/.github/workflows/auto-approve-dominions-prs.yml +++ b/.github/workflows/auto-approve-dominions-prs.yml @@ -16,7 +16,7 @@ concurrency: jobs: approve-pr-if-dominion-is-author: name: Approve PR if Dominion is Author - if: github.event.pull_request.user.login == 'Cyberboss' && !(github.event.pull_request.draft || github.event.pull_request.body.contains('- [ ]')) && (github.event.pull_request.base.repo.owner.login == 'tgstation' || github.event.pull_request.base.repo.owner.login == 'Cyberboss') + if: github.event.pull_request.user.login == 'Cyberboss' && !github.event.pull_request.draft && !github.event.pull_request.body.contains('- [ ]') && (github.event.pull_request.base.repo.owner.login == 'tgstation' || github.event.pull_request.base.repo.owner.login == 'Cyberboss') runs-on: ubuntu-latest steps: - name: GitHub API Call From f67b0d2254b16aa284365b856862161263466e34 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 27 Jun 2023 18:47:45 -0400 Subject: [PATCH 117/160] Fix auto approve workflow for real this time --- .github/workflows/auto-approve-dominions-prs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/auto-approve-dominions-prs.yml b/.github/workflows/auto-approve-dominions-prs.yml index 8f7cc8cba4..cd499fffde 100644 --- a/.github/workflows/auto-approve-dominions-prs.yml +++ b/.github/workflows/auto-approve-dominions-prs.yml @@ -16,7 +16,7 @@ concurrency: jobs: approve-pr-if-dominion-is-author: name: Approve PR if Dominion is Author - if: github.event.pull_request.user.login == 'Cyberboss' && !github.event.pull_request.draft && !github.event.pull_request.body.contains('- [ ]') && (github.event.pull_request.base.repo.owner.login == 'tgstation' || github.event.pull_request.base.repo.owner.login == 'Cyberboss') + if: github.event.pull_request.user.login == 'Cyberboss' && !github.event.pull_request.draft && !contains(github.event.pull_request.body, '- [ ]') && (github.event.pull_request.base.repo.owner.login == 'tgstation' || github.event.pull_request.base.repo.owner.login == 'Cyberboss') runs-on: ubuntu-latest steps: - name: GitHub API Call From f434a281b46d4158b94b881ad386758edbdfb6ad Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 29 Jun 2023 14:47:55 -0400 Subject: [PATCH 118/160] Better error handling in RemoteDeploymentManagers --- .../Remote/GitHubRemoteDeploymentManager.cs | 31 ++++++++++++------- .../Remote/GitLabRemoteDeploymentManager.cs | 23 +++++++++----- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs index 16630a9f08..803895772a 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs @@ -127,9 +127,9 @@ namespace Tgstation.Server.Host.Components.Deployment.Remote Logger.LogTrace("In-progress deployment status created"); } - catch (ApiException ex) + catch (Exception ex) when (ex is not OperationCanceledException) { - Logger.LogWarning(ex, "Unable to create deployment!"); + Logger.LogWarning(ex, "Unable to create GitHub deployment!"); } } @@ -252,9 +252,9 @@ namespace Tgstation.Server.Host.Components.Deployment.Remote { await gitHubService.CommentOnIssue(remoteRepositoryOwner, remoteRepositoryName, comment, testMergeNumber, cancellationToken); } - catch (ApiException e) + catch (Exception ex) when (ex is not OperationCanceledException) { - Logger.LogWarning(e, "Error posting GitHub comment!"); + Logger.LogWarning(ex, "Error posting GitHub comment!"); } } @@ -336,14 +336,21 @@ namespace Tgstation.Server.Host.Components.Deployment.Remote var gitHubService = gitHubServiceFactory.CreateService(gitHubAccessToken); - await gitHubService.CreateDeploymentStatus( - new NewDeploymentStatus(deploymentState) - { - Description = description, - }, - compileJob.GitHubRepoId.Value, - compileJob.GitHubDeploymentId.Value, - cancellationToken); + try + { + await gitHubService.CreateDeploymentStatus( + new NewDeploymentStatus(deploymentState) + { + Description = description, + }, + compileJob.GitHubRepoId.Value, + compileJob.GitHubDeploymentId.Value, + cancellationToken); + } + catch (Exception ex) when (ex is not OperationCanceledException) + { + Logger.LogWarning(ex, "Error updating GitHub deployment!"); + } } } } diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs index 2d554b2bef..d9b8c99a08 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs @@ -119,7 +119,7 @@ namespace Tgstation.Server.Host.Components.Deployment.Remote CancellationToken cancellationToken) => Task.CompletedTask; /// - protected override Task CommentOnTestMergeSource( + protected override async Task CommentOnTestMergeSource( RepositorySettings repositorySettings, string remoteRepositoryOwner, string remoteRepositoryName, @@ -131,13 +131,20 @@ namespace Tgstation.Server.Host.Components.Deployment.Remote ? new GitLabClient(GitLabRemoteFeatures.GitLabUrl, repositorySettings.AccessToken) : new GitLabClient(GitLabRemoteFeatures.GitLabUrl); - return client - .MergeRequests - .CreateNoteAsync( - $"{remoteRepositoryOwner}/{remoteRepositoryName}", - testMergeNumber, - new CreateMergeRequestNoteRequest(comment)) - .WaitAsync(cancellationToken); + try + { + await client + .MergeRequests + .CreateNoteAsync( + $"{remoteRepositoryOwner}/{remoteRepositoryName}", + testMergeNumber, + new CreateMergeRequestNoteRequest(comment)) + .WaitAsync(cancellationToken); + } + catch (Exception ex) when (ex is not OperationCanceledException) + { + Logger.LogWarning(ex, "Error posting GitHub comment!"); + } } /// From c13f56470f2053228690c56e8b11e184438cfc73 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 29 Jun 2023 15:30:32 -0400 Subject: [PATCH 119/160] Version bump to 5.12.7 --- build/Version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Version.props b/build/Version.props index f8038e8242..be345f49cd 100644 --- a/build/Version.props +++ b/build/Version.props @@ -3,7 +3,7 @@ - 5.12.6 + 5.12.7 4.6.0 9.10.2 6.0.0 From 568b1f3f23b95d90bed5684ab61b91fbaed31efd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 29 Jun 2023 15:36:59 -0400 Subject: [PATCH 120/160] Clean up Exception handling when setting repo ID --- .../Deployment/Remote/GitHubRemoteDeploymentManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs index 803895772a..7365a58089 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs @@ -138,7 +138,7 @@ namespace Tgstation.Server.Host.Components.Deployment.Remote compileJob.GitHubRepoId = await repositoryIdTask; Logger.LogTrace("Set GitHub ID as {gitHubRepoId}", compileJob.GitHubRepoId); } - catch (RateLimitExceededException ex) when (!repositorySettings.CreateGitHubDeployments.Value) + catch (Exception ex) when (ex is not OperationCanceledException) { Logger.LogWarning(ex, "Unable to set compile job repository ID!"); } From 58cf3d77390127222328ded154227e8fca9514b5 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 04:15:40 -0400 Subject: [PATCH 121/160] Fix failing test --- tests/Tgstation.Server.Host.Service.Tests/TestServerService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Host.Service.Tests/TestServerService.cs b/tests/Tgstation.Server.Host.Service.Tests/TestServerService.cs index 19d2f60d69..54dc719a0b 100644 --- a/tests/Tgstation.Server.Host.Service.Tests/TestServerService.cs +++ b/tests/Tgstation.Server.Host.Service.Tests/TestServerService.cs @@ -35,7 +35,7 @@ namespace Tgstation.Server.Host.Service.Tests var mockWatchdog = new Mock(); var args = Array.Empty(); CancellationToken cancellationToken; - mockWatchdog.Setup(x => x.RunAsync(false, args, It.IsAny())).Callback((bool x, string[] _, CancellationToken token) => cancellationToken = token).Returns(Task.FromResult(true)).Verifiable(); + mockWatchdog.Setup(x => x.RunAsync(false, It.IsNotNull(), It.IsAny())).Callback((bool x, string[] _, CancellationToken token) => cancellationToken = token).Returns(Task.FromResult(true)).Verifiable(); var mockWatchdogFactory = new Mock(); mockWatchdogFactory.Setup(x => x.CreateWatchdog(It.IsNotNull(), It.IsNotNull())).Returns(mockWatchdog.Object).Verifiable(); From 352a65a1d1592915e56b4381122b1231e0cd056d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 07:28:38 -0400 Subject: [PATCH 122/160] libsystemd0 is not a hard dependency --- build/package/deb/debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package/deb/debian/control b/build/package/deb/debian/control index aa670a2e2c..a4e47829c7 100644 --- a/build/package/deb/debian/control +++ b/build/package/deb/debian/control @@ -21,8 +21,8 @@ Depends: libstdc++6:i386 [amd64], libstdc++6 [i386], gcc-multilib [amd64], - libsystemd0, Recommends: + libsystemd0, gdb, Description: A production scale tool for BYOND server management This is a toolset to manage production BYOND servers. It includes the ability to update the server without having to stop or shutdown the server (the update will take effect on a "reboot" of the server), the ability to start the server and restart it if it crashes, as well as systems for managing code and game files, and locally merging GitHub Pull Requests for test deployments. From 54c3a056ce496f0342df23d733b8f508e38c7b1b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 07:28:50 -0400 Subject: [PATCH 123/160] Add missing `dotnet restore` to CI --- .github/workflows/ci-pipeline.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index cc5b1d0156..6a53303a28 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -989,6 +989,9 @@ jobs: - name: Validate winget Manifest run: winget validate --manifest build/package/winget/manifest + + - name: Restore + run: dotnet restore - name: Build Service run: dotnet build -c Release src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj From cbd27fce585d765f8a3935e79aa98ff255cc884d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 07:32:06 -0400 Subject: [PATCH 124/160] Update Features list --- docs/Features.dox | 37 ++----------------------------------- 1 file changed, 2 insertions(+), 35 deletions(-) diff --git a/docs/Features.dox b/docs/Features.dox index 3c1430740f..6c1f42d3b3 100644 --- a/docs/Features.dox +++ b/docs/Features.dox @@ -3,41 +3,6 @@ @tableofcontents -@section new_features New since TGS3 (Rewrite) - -- Agnostic HTTP API: The replaces the WCF service calls used in TGS3. This helps avoid Windows vendor lock-in and get away from the SOAP API that literally no one understood (not even me). With it, it's much easier to expose TGS to the internet, all you need is a HTTPS reverse proxy in front of it. A rundown of the new API exists here: https://tgstation.github.io/tgstation-server/api.html. -- Granular Access Controls: Windows users are no longer (required to be) the basis for authentication to the server. We now have database-backed users as a login option. These use a combined Basic/JWT authentication scheme with industry standard password hashing and salting. Users are fully customizable and can be given granular access to every bit of the server via the new permissions system. From changing the BYOND version, to test merging a PR, to restarting the server, every action may now be granted or revoked on a per user basis. - - Limitation: Users can be disabled but not deleted. -- Proper Long Running Operation Support: Server actions take a long time, from a git pull to a DreamMaker compile. TGS now internally allows for them to be run in parallel with each other and provides an audit record via the database. This is an improvement over the old system where connections had to be held open for the duration of operations. -- Database Backend: TGS requires an SQL database to operate. This allows for much better concurrency and is just overall much cleaner than the old single json file storage blob per instance. - - Limitation: There is a one-to-one relationship with a TGS server and a database. **DO NOT SHARE TGS DATABASES OUTSIDE OF SWARM MODE**. -- Linux/Docker Support: TGS is Linux and docker compatible. (Note this does not mean that rust-g and BSQL work out of the box, they must be compiled using event scripts like PreCompile.sh). - - Limitation: TGS has a dependency on the native library libgit2 which is known to cause issues on Linux. The binaries distributed with TGS are kept up to date with the upstream repository, but out of the box Linux support can't be assured in every environment. Docker is guaranteed to always work, however. See the repository for the distributed binary here: https://github.com/libgit2/libgit2sharp.nativebinaries. - - Limitation: System based logins are not supported on Linux. https://github.com/tgstation/tgstation-server/issues/709 -- Incredibly Detailed Logging: Various log levels exist now (Trace/Debug/Info/Warning/Error/Critical) and are sanely output to a rolling file on the host. Significant improvement over having to use the Windows event viewer with TGS3. Until such a point where bugs stop copping up I'd recommend Trace logging for the main log level. -- Historical Deployment Data: Every time code is compiled the following data is logged and stored. - - The User that initiated it. - - When it was started. - - When it finished. - - All revision information including local/remote SHAs, test merged pull requests and their SHAs. - - The BYOND version used. - - The DMAPI version in the binary -- Multiple chat bots per instance: Up to 65535 as a matter of fact (who knows why I chose that number?)! -- Automatic Chat Bot Reconnection Intervals: Set in minutes. -- Better Error State Handling: The Server and Watchdog aren't your momma's boys anymore. Every error state will be automatically resolved or reported with recommended actions. -- Watchdog Health Checks: An interval in seconds can now be set at which TGS will send /world/Topic() packets to DreamDaemon. If four of these are missed, the server will be rebooted. No more endless @Key Holder pings in discord (and I can finally unmute the /tg/ guild)! This feature can be disabled. -- Better DMAPI: No longer requires injecting a .NET runtime .dll into the DreamDaemon process. DD -> TGS communication is now handled securely via BYOND's native /world/Export() API ("But Cyberboss, BYOND only supports GET requests." Who said anything about respecting HTTP standards when dealing with BYOND?). -- Safe/Ultrasafe Security Support: Thanks to the new DMAPI, the ultrasafe and safe security levels may be used without running into BYOND's limitations. But no one really cares... -- Private/Invisible visibility Support: Stored per instance. -- Self Upgrading: To upgrade TGS3 you needed to download and run the installer. This was pretty seamless, but it's now even better in versions >=4 as the command to upgrade can be given straight to the API. At that point the server will handle downloading the update, detaching running DreamDaemon instances, restarting with the new version, and reattaching to them. Easier than ever patch delivery. -- Multi-server co-operation: TGS installed on multiple machines can share the same database by using Swarm Mode. This mode keeps TGS and account details in sync on all machines. -- OAuth 2.0 Support: Integrate with your favorite 3rd party authentication providers -- *Gasp* TESTING: TGS currently has over 60% code coverage in automated unit and full stack integration tests. I aim to have that number ever increasing to prevent trivial mistakes. Big improvement over V3 which had... literally none... - -Along with these features, nearly every single V3 feature has been included and possibly improved in some fashion. This includes stuff like Windows accounts for logins, and using ACLs for static file handling. The following exceptions exist but are planned for future updates: -- Process memory/CPU diagnostic data is not generated: https://github.com/tgstation/tgstation-server/issues/611 -- Direct server announcements are no longer present but may be readded upon request. - @section features_list Comprehensive Feature List tgstation-server is a BYOND server managment suite. It includes all the following features @@ -58,6 +23,8 @@ tgstation-server is a BYOND server managment suite. It includes all the followin - Supports Elasticsearch ingesting - Able to self update with user input - Updates are sourced from our (or anyone else's if configured to do so) GitHub releases or uploaded directly by the user. + - Can also self update using official installation packages. +- Able to shutdown and restart without interrupting DreamDaemon processes. - Swarm system to coordinate servers across systems - Database backend supporting several providers - Microsoft SQL Server From b22f25ca616b27314a84b702c9337a7336d3701e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 07:33:10 -0400 Subject: [PATCH 125/160] Fix `cat` path in TestInstall step for `.deb` --- .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 6a53303a28..f582c68904 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -935,8 +935,8 @@ jobs: sudo apt-get install -y ./tgstation-server_${{ env.TGS_VERSION }}-1_amd64.deb sudo ls -al /etc/tgstation-server sudo cat /etc/tgstation-server/appsettings.Production.yml + sudo cat /etc/tgstation-server/appsettings.yml ls -al /opt/tgstation-server - cat /opt/tgstation-server/appsettings.yml cat /opt/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json cat /usr/bin/tgs-configure @@ -989,7 +989,7 @@ jobs: - name: Validate winget Manifest run: winget validate --manifest build/package/winget/manifest - + - name: Restore run: dotnet restore From 1aa18af161b2717beba9684f7c472a536e3090bd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 07:39:23 -0400 Subject: [PATCH 126/160] Add more missing `dotnet restore`s --- .github/workflows/ci-pipeline.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index f582c68904..cc142b4448 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -239,6 +239,9 @@ jobs: with: ref: "refs/pull/${{ github.event.number }}/merge" + - name: Restore + run: dotnet restore + - name: Build run: dotnet build -c ${{ matrix.configuration }}NoWindows @@ -279,6 +282,9 @@ jobs: with: ref: "refs/pull/${{ github.event.number }}/merge" + - name: Restore + run: dotnet restore + - name: Build run: dotnet build -c ${{ matrix.configuration }} @@ -399,6 +405,9 @@ jobs: with: ref: "refs/pull/${{ github.event.number }}/merge" + - name: Restore + run: dotnet restore + - name: Build run: dotnet build -c ${{ matrix.configuration }} tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj @@ -561,6 +570,9 @@ jobs: with: ref: "refs/pull/${{ github.event.number }}/merge" + - name: Restore + run: dotnet restore + - name: Build run: dotnet build -c ${{ matrix.configuration }}NoWindows tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj @@ -1093,6 +1105,9 @@ jobs: with: ref: "refs/pull/${{ github.event.number }}/merge" + - name: Restore + run: dotnet restore + - name: Build ReleaseNotes run: dotnet build -c Release tools/ReleaseNotes/ReleaseNotes.csproj @@ -1254,6 +1269,9 @@ jobs: - name: Checkout uses: actions/checkout@v3 + - name: Restore + run: dotnet restore + - name: Build ReleaseNotes run: dotnet build -c Release tools/ReleaseNotes/ReleaseNotes.csproj @@ -1274,6 +1292,9 @@ jobs: - name: Checkout uses: actions/checkout@v3 + - name: Restore + run: dotnet restore + - name: Build ReleaseNotes run: dotnet build -c Release tools/ReleaseNotes/ReleaseNotes.csproj From ef4ef59cf3978383a195012fded666d862aca113 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 07:45:11 -0400 Subject: [PATCH 127/160] Fix `push_manifest.ps1`'s parameter and default hash --- build/package/winget/push_manifest.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/package/winget/push_manifest.ps1 b/build/package/winget/push_manifest.ps1 index 27cb64e46d..b74367d302 100644 --- a/build/package/winget/push_manifest.ps1 +++ b/build/package/winget/push_manifest.ps1 @@ -1,5 +1,5 @@ param( - [string]$MsiPath = 'packaging/build/package/winget/Tgstation.Server.Host.Service.Wix/Release/tgstation-server.msi' + [string]$InstallerPath = 'build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/x86/Release/tgstation-server-installer.exe' ) $ErrorActionPreference="Stop" @@ -8,11 +8,11 @@ $ErrorActionPreference="Stop" $tgsVersion = $versionXML.Project.PropertyGroup.TgsCoreVersion -$installerHash = Get-FileHash -Path $MsiPath -ErrorAction Stop # SHA256 is the default +$installerHash = Get-FileHash -Path $InstallerPath -ErrorAction Stop # SHA256 is the default cd build/package/winget/manifest -$devHash = 'F749672C1BDBAC8CD8AEF7352B97E54C21CF389D798D0ED245CA75EC72521460' +$devHash = 'CF0D4D2FD042098D826A226A05A9DAA5C792318CF48FD334F7FC06AF6A8A23B1' $devVersion = '0.22.475' $devReleaseDate = '2023-06-24' $releaseDate = Get-Date -format "yyyy-MM-dd" From 04e9ff306f275b99b7e961931e12422a54a9f58a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 07:49:34 -0400 Subject: [PATCH 128/160] Add uninstall check to winget --- build/package/winget/push_manifest.ps1 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/build/package/winget/push_manifest.ps1 b/build/package/winget/push_manifest.ps1 index b74367d302..82de440ce9 100644 --- a/build/package/winget/push_manifest.ps1 +++ b/build/package/winget/push_manifest.ps1 @@ -26,12 +26,17 @@ if (-Not $?) { exit $lastexitcode } -# I know this is late, but we actually need the package online to install it +# I know these are late, but we actually need the package online to install it winget install -m . -h --disable-interactivity if (-Not $?) { exit $lastexitcode } +winget uninstall tgstation-server --disable-interactivity +if (-Not $?) { + exit $lastexitcode +} + wingetcreate submit -t $Env:WINGET_PUSH_TOKEN . if (-Not $?) { exit $lastexitcode From 1ced2e335e870f02984cdb1205546f87f2c90c02 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 07:51:42 -0400 Subject: [PATCH 129/160] Add missing `dotnet build` --- .github/workflows/ci-pipeline.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index cc142b4448..d340818dcf 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1005,6 +1005,9 @@ jobs: - name: Restore run: dotnet restore + - name: Build Host + run: dotnet build -c Release src/Tgstation.Server.Host/Tgstation.Server.Host.csproj + - name: Build Service run: dotnet build -c Release src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj From d7404abeb87e92716a9042ffb12cebd60923abda Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 07:57:34 -0400 Subject: [PATCH 130/160] Add `-NoWix` `.sln` configurations --- .github/workflows/ci-pipeline.yml | 4 +- tgstation-server.sln | 84 +++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index d340818dcf..b58ecfd626 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -286,10 +286,10 @@ jobs: run: dotnet restore - name: Build - run: dotnet build -c ${{ matrix.configuration }} + run: dotnet build -c ${{ matrix.configuration }}NoWix - name: Run Unit Tests - run: dotnet test --no-build --logger GitHubActions --filter FullyQualifiedName!~TestLiveServer -c ${{ matrix.configuration }} --collect:"XPlat Code Coverage" --settings build/coverlet.runsettings --results-directory ./TestResults tgstation-server.sln + run: dotnet test --no-build --logger GitHubActions --filter FullyQualifiedName!~TestLiveServer -c ${{ matrix.configuration }}NoWix --collect:"XPlat Code Coverage" --settings build/coverlet.runsettings --results-directory ./TestResults tgstation-server.sln - name: Store Code Coverage uses: actions/upload-artifact@v3 diff --git a/tgstation-server.sln b/tgstation-server.sln index 0eb2f3f898..7dd40adac4 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -256,176 +256,260 @@ Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU DebugNoWindows|Any CPU = DebugNoWindows|Any CPU + DebugNoWix|Any CPU = DebugNoWix|Any CPU Release|Any CPU = Release|Any CPU ReleaseNoWindows|Any CPU = ReleaseNoWindows|Any CPU + ReleaseNoWix|Any CPU = ReleaseNoWix|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Debug|Any CPU.Build.0 = Debug|Any CPU {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Release|Any CPU.ActiveCfg = Release|Any CPU {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.Release|Any CPU.Build.0 = Release|Any CPU {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {2B69AD6D-2B5A-4023-8EAD-0BD1B18E028A}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.Debug|Any CPU.Build.0 = Debug|Any CPU {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.Release|Any CPU.ActiveCfg = Release|Any CPU {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.Release|Any CPU.Build.0 = Release|Any CPU {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {A09C947F-4B9B-4AEE-AB50-47055EA05F18}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {D36B99C4-E771-42D6-A95F-1102B3E236DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D36B99C4-E771-42D6-A95F-1102B3E236DF}.Debug|Any CPU.Build.0 = Debug|Any CPU {D36B99C4-E771-42D6-A95F-1102B3E236DF}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {D36B99C4-E771-42D6-A95F-1102B3E236DF}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {D36B99C4-E771-42D6-A95F-1102B3E236DF}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {D36B99C4-E771-42D6-A95F-1102B3E236DF}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {D36B99C4-E771-42D6-A95F-1102B3E236DF}.Release|Any CPU.ActiveCfg = Release|Any CPU {D36B99C4-E771-42D6-A95F-1102B3E236DF}.Release|Any CPU.Build.0 = Release|Any CPU {D36B99C4-E771-42D6-A95F-1102B3E236DF}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {D36B99C4-E771-42D6-A95F-1102B3E236DF}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {D36B99C4-E771-42D6-A95F-1102B3E236DF}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {D36B99C4-E771-42D6-A95F-1102B3E236DF}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {8B4A208D-A48A-4A5D-8B94-E2661138865D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8B4A208D-A48A-4A5D-8B94-E2661138865D}.Debug|Any CPU.Build.0 = Debug|Any CPU {8B4A208D-A48A-4A5D-8B94-E2661138865D}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {8B4A208D-A48A-4A5D-8B94-E2661138865D}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {8B4A208D-A48A-4A5D-8B94-E2661138865D}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {8B4A208D-A48A-4A5D-8B94-E2661138865D}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {8B4A208D-A48A-4A5D-8B94-E2661138865D}.Release|Any CPU.ActiveCfg = Release|Any CPU {8B4A208D-A48A-4A5D-8B94-E2661138865D}.Release|Any CPU.Build.0 = Release|Any CPU {8B4A208D-A48A-4A5D-8B94-E2661138865D}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {8B4A208D-A48A-4A5D-8B94-E2661138865D}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {8B4A208D-A48A-4A5D-8B94-E2661138865D}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {8B4A208D-A48A-4A5D-8B94-E2661138865D}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {29927416-3B78-49A7-A560-5CCAA638B6B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {29927416-3B78-49A7-A560-5CCAA638B6B4}.Debug|Any CPU.Build.0 = Debug|Any CPU {29927416-3B78-49A7-A560-5CCAA638B6B4}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {29927416-3B78-49A7-A560-5CCAA638B6B4}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {29927416-3B78-49A7-A560-5CCAA638B6B4}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {29927416-3B78-49A7-A560-5CCAA638B6B4}.Release|Any CPU.ActiveCfg = Release|Any CPU {29927416-3B78-49A7-A560-5CCAA638B6B4}.Release|Any CPU.Build.0 = Release|Any CPU {29927416-3B78-49A7-A560-5CCAA638B6B4}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {29927416-3B78-49A7-A560-5CCAA638B6B4}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {29927416-3B78-49A7-A560-5CCAA638B6B4}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.Debug|Any CPU.Build.0 = Debug|Any CPU {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.Release|Any CPU.ActiveCfg = Release|Any CPU {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.Release|Any CPU.Build.0 = Release|Any CPU {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {E0AC911F-7675-4A91-9499-D8A2E2390AAD}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.Debug|Any CPU.Build.0 = Debug|Any CPU {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.Release|Any CPU.ActiveCfg = Release|Any CPU {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.Release|Any CPU.Build.0 = Release|Any CPU {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {BE0E8F49-334F-49D7-A04D-D82E9AB7AA36}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.Debug|Any CPU.Build.0 = Debug|Any CPU {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.Release|Any CPU.ActiveCfg = Release|Any CPU {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.Release|Any CPU.Build.0 = Release|Any CPU {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {E5301AF1-4F74-4982-BF24-95F23CC5D5B2}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.Debug|Any CPU.Build.0 = Debug|Any CPU {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.Release|Any CPU.ActiveCfg = Release|Any CPU {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.Release|Any CPU.Build.0 = Release|Any CPU {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {A3362FF6-550F-480F-859E-8EC1EB6EAB31}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Debug|Any CPU.Build.0 = Debug|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Release|Any CPU.ActiveCfg = Release|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.Release|Any CPU.Build.0 = Release|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {5D2D682C-6BF0-439C-850B-6AB945BBEAEA}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {7500F776-4384-4B5F-A8D8-22461CAD108B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7500F776-4384-4B5F-A8D8-22461CAD108B}.Debug|Any CPU.Build.0 = Debug|Any CPU {7500F776-4384-4B5F-A8D8-22461CAD108B}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {7500F776-4384-4B5F-A8D8-22461CAD108B}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {7500F776-4384-4B5F-A8D8-22461CAD108B}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {7500F776-4384-4B5F-A8D8-22461CAD108B}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {7500F776-4384-4B5F-A8D8-22461CAD108B}.Release|Any CPU.ActiveCfg = Release|Any CPU {7500F776-4384-4B5F-A8D8-22461CAD108B}.Release|Any CPU.Build.0 = Release|Any CPU {7500F776-4384-4B5F-A8D8-22461CAD108B}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {7500F776-4384-4B5F-A8D8-22461CAD108B}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {7500F776-4384-4B5F-A8D8-22461CAD108B}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {7500F776-4384-4B5F-A8D8-22461CAD108B}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.Debug|Any CPU.Build.0 = Debug|Any CPU {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.Release|Any CPU.ActiveCfg = Release|Any CPU {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.Release|Any CPU.Build.0 = Release|Any CPU {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {AA80A190-52E2-4BE3-BFEB-1F148D9E9007}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {09056964-1C74-445A-96EC-33F6DFC07916}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {09056964-1C74-445A-96EC-33F6DFC07916}.Debug|Any CPU.Build.0 = Debug|Any CPU {09056964-1C74-445A-96EC-33F6DFC07916}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {09056964-1C74-445A-96EC-33F6DFC07916}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {09056964-1C74-445A-96EC-33F6DFC07916}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {09056964-1C74-445A-96EC-33F6DFC07916}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {09056964-1C74-445A-96EC-33F6DFC07916}.Release|Any CPU.ActiveCfg = Release|Any CPU {09056964-1C74-445A-96EC-33F6DFC07916}.Release|Any CPU.Build.0 = Release|Any CPU {09056964-1C74-445A-96EC-33F6DFC07916}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {09056964-1C74-445A-96EC-33F6DFC07916}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {09056964-1C74-445A-96EC-33F6DFC07916}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {09056964-1C74-445A-96EC-33F6DFC07916}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.Debug|Any CPU.Build.0 = Debug|Any CPU {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.Release|Any CPU.ActiveCfg = Release|Any CPU {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.Release|Any CPU.Build.0 = Release|Any CPU {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {5CB51532-55F0-4255-B6E5-69ED5CCD14CD}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {5813CC33-B16C-485D-A74D-20204DDF6542}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5813CC33-B16C-485D-A74D-20204DDF6542}.Debug|Any CPU.Build.0 = Debug|Any CPU {5813CC33-B16C-485D-A74D-20204DDF6542}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {5813CC33-B16C-485D-A74D-20204DDF6542}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {5813CC33-B16C-485D-A74D-20204DDF6542}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {5813CC33-B16C-485D-A74D-20204DDF6542}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {5813CC33-B16C-485D-A74D-20204DDF6542}.Release|Any CPU.ActiveCfg = Release|Any CPU {5813CC33-B16C-485D-A74D-20204DDF6542}.Release|Any CPU.Build.0 = Release|Any CPU {5813CC33-B16C-485D-A74D-20204DDF6542}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {5813CC33-B16C-485D-A74D-20204DDF6542}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {5813CC33-B16C-485D-A74D-20204DDF6542}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {5813CC33-B16C-485D-A74D-20204DDF6542}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {CE499888-B22B-457C-891E-0EA9DC317228}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CE499888-B22B-457C-891E-0EA9DC317228}.Debug|Any CPU.Build.0 = Debug|Any CPU {CE499888-B22B-457C-891E-0EA9DC317228}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {CE499888-B22B-457C-891E-0EA9DC317228}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {CE499888-B22B-457C-891E-0EA9DC317228}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {CE499888-B22B-457C-891E-0EA9DC317228}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {CE499888-B22B-457C-891E-0EA9DC317228}.Release|Any CPU.ActiveCfg = Release|Any CPU {CE499888-B22B-457C-891E-0EA9DC317228}.Release|Any CPU.Build.0 = Release|Any CPU {CE499888-B22B-457C-891E-0EA9DC317228}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {CE499888-B22B-457C-891E-0EA9DC317228}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {CE499888-B22B-457C-891E-0EA9DC317228}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {CE499888-B22B-457C-891E-0EA9DC317228}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.Debug|Any CPU.Build.0 = Debug|Any CPU {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.Release|Any CPU.ActiveCfg = Release|Any CPU {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.Release|Any CPU.Build.0 = Release|Any CPU {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {07ED0FD5-E46B-4841-931D-BA2B673E16B2}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Debug|Any CPU.Build.0 = Debug|Any CPU {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Release|Any CPU.ActiveCfg = Release|Any CPU {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.Release|Any CPU.Build.0 = Release|Any CPU {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {CF3968A0-EA81-4464-B2D4-C7D40F6B5BCB}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Debug|Any CPU.Build.0 = Debug|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Release|Any CPU.ActiveCfg = Release|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.Release|Any CPU.Build.0 = Release|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {70CD9A98-D31A-44A4-81D1-D02764CEEEFD}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU {28669D98-E15D-4A62-B1D1-7C11D4CB1DE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {28669D98-E15D-4A62-B1D1-7C11D4CB1DE0}.Debug|Any CPU.Build.0 = Debug|Any CPU {28669D98-E15D-4A62-B1D1-7C11D4CB1DE0}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {28669D98-E15D-4A62-B1D1-7C11D4CB1DE0}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU {28669D98-E15D-4A62-B1D1-7C11D4CB1DE0}.Release|Any CPU.ActiveCfg = Release|Any CPU {28669D98-E15D-4A62-B1D1-7C11D4CB1DE0}.Release|Any CPU.Build.0 = Release|Any CPU {28669D98-E15D-4A62-B1D1-7C11D4CB1DE0}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {28669D98-E15D-4A62-B1D1-7C11D4CB1DE0}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU {82996E9D-5E63-4CC5-8179-612C71B4F56C}.Debug|Any CPU.ActiveCfg = Debug|x86 {82996E9D-5E63-4CC5-8179-612C71B4F56C}.Debug|Any CPU.Build.0 = Debug|x86 {82996E9D-5E63-4CC5-8179-612C71B4F56C}.DebugNoWindows|Any CPU.ActiveCfg = Debug|x86 + {82996E9D-5E63-4CC5-8179-612C71B4F56C}.DebugNoWix|Any CPU.ActiveCfg = Debug|x86 {82996E9D-5E63-4CC5-8179-612C71B4F56C}.Release|Any CPU.ActiveCfg = Release|x86 {82996E9D-5E63-4CC5-8179-612C71B4F56C}.Release|Any CPU.Build.0 = Release|x86 {82996E9D-5E63-4CC5-8179-612C71B4F56C}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|x86 + {82996E9D-5E63-4CC5-8179-612C71B4F56C}.ReleaseNoWix|Any CPU.ActiveCfg = Release|x86 {9E66C6F1-E235-4979-83B5-C2B3FDAD6E01}.Debug|Any CPU.ActiveCfg = Debug|x86 {9E66C6F1-E235-4979-83B5-C2B3FDAD6E01}.Debug|Any CPU.Build.0 = Debug|x86 {9E66C6F1-E235-4979-83B5-C2B3FDAD6E01}.DebugNoWindows|Any CPU.ActiveCfg = Debug|x86 + {9E66C6F1-E235-4979-83B5-C2B3FDAD6E01}.DebugNoWix|Any CPU.ActiveCfg = Debug|x86 {9E66C6F1-E235-4979-83B5-C2B3FDAD6E01}.Release|Any CPU.ActiveCfg = Release|x86 {9E66C6F1-E235-4979-83B5-C2B3FDAD6E01}.Release|Any CPU.Build.0 = Release|x86 {9E66C6F1-E235-4979-83B5-C2B3FDAD6E01}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|x86 + {9E66C6F1-E235-4979-83B5-C2B3FDAD6E01}.ReleaseNoWix|Any CPU.ActiveCfg = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 4b3440945fef9d73d62d85ca8bad4d4ce58f7518 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 08:12:42 -0400 Subject: [PATCH 131/160] Fix Wix CI build command --- .github/workflows/ci-pipeline.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index b58ecfd626..586a46e4a5 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1015,11 +1015,15 @@ jobs: shell: powershell run: build/package/winget/prepare_installer_input_artifacts.ps1 - - name: Build Installer + - name: Restore Wix dotnet Tool run: | cd build/package/winget dotnet tool restore - dotnet build -c Release Tgstation.Server.Service.Wix.Bundle + + - name: Build Installer .exe + run: | + cd build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle + dotnet build -c Release - name: Test Install # Sanity checks the .deps.json exists, which the installation is broken without shell: powershell # If it's missing, I found that in elements were the problem From b74a0d6e7964db446c9711d3dfca683b340e918a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 08:39:44 -0400 Subject: [PATCH 132/160] Do not deprecate service self-installing --- src/Tgstation.Server.Host.Service/Program.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host.Service/Program.cs b/src/Tgstation.Server.Host.Service/Program.cs index c0a9409ea1..fcd4cdb19e 100644 --- a/src/Tgstation.Server.Host.Service/Program.cs +++ b/src/Tgstation.Server.Host.Service/Program.cs @@ -120,12 +120,9 @@ namespace Tgstation.Server.Host.Service if (standardRun) if (!Silent && !WindowsServiceHelpers.IsWindowsService()) { -#if NET7_0_OR_GREATER -#error Deprecated functionality, remove -#endif var result = NativeMethods.MessageBox( default, - "You are running the TGS windows service executable directly. It should only be run by the service control manager. Would you like to install and configure the service in this location? (Note: This functionality is deprecated and will be removed in a future version)", + "You are running the TGS windows service executable directly. It should only be run by the service control manager. Would you like to install and configure the service in this location?", "TGS Service", NativeMethods.MessageBoxButtons.YesNo); From 609fea8fdea0ab1d2e5149bad5aed38c539e6498 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 08:45:02 -0400 Subject: [PATCH 133/160] Remove unused install banner --- build/package/winget/install_banner.jpg | Bin 11811 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 build/package/winget/install_banner.jpg diff --git a/build/package/winget/install_banner.jpg b/build/package/winget/install_banner.jpg deleted file mode 100644 index 4bbe3f134ca548b4e035f377bf55db0f2ef49414..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11811 zcmd6NXH-*Pzh>wiq(pjAs?t(^llKpGXexBbx)CuYw85ydU`qrCPpTvzmu7TjfI(+m6?f&m4lU)jU60J zESy{%?3{nE|9;8e$NxSBe%P6rnE&4K|2C*!A>7Q6_q5$~G^Zi7+%$CDG}Ly8I0Qn& z0Iv4$g8yUC(9+Q}FoH{BWdm=hIsq=9j*b>wECW3~cy|!^e+WG{1J9}Rx{SQ$_nA&V z<-71QF^5@Fue=3nF-VkBdEgbo!g`WlKu}0pMpo|3Syi=*>KdAt^sgEi8X22hv%F<> z+uG)it>eQ-PR=f_Zr;y)eEm@V0k1;C!XqN1qLY%}q@t0)Oki8U2~@UPkB#Yc*)GCmzY!D!Xl|+L4-c= z8e}~wr8+N7`fJ+1Ec^Ei3;F-D>^}|rUv^DF*y(7%;L&kIV31?-hiEy-KW&yF7x_D3 zY?J{U+b&KBHEdT-+zcaYJsuB;&qWAV}NJzsV|OF}8{>a=Kt5>%qlvX=}Z{B1SMS zjCntZdlgT-IRI!XFB)~>r@ZiY0j-4~@A-(A+VU#-5spl$PNRl~9zM(y+LkH=dcFC@ zxM1_Tn1(~9^$se8>1m(~;N`wfkpb($J}vCH(C`YhuwC`ccC zeGp-?E5xZCFTZ;0#WU zkOkwiU50N8?W;`f=G#}gA(@s`h${@xT-mb)IQLK1i`6ZNN7d(@dSftOs+#fWHC?4z zM@#gD&_zY=WXKY&q5MJkhdOlmsy70mUwrfcr&zfQvxB(~09u$u{&vZy&O}^`7!>e! zlsKD~wmvnR*BtvX^oddc!3810p84=#oXopO;e-RDME!8P^sDP=^RE3{cgydm6+$7JwXTYUXtzGRNT&U!Wa_$m3x9{Y<=^S2Dd z2J;`kr|_?4s}ddR92a10K=g$D+F@MAM)ZQp>wvjpdB)p@G>IuGFCIxe8zp}NqbrD> ztC;;8-MfM2l_V{L&S2oar0~FNBB4|?DoF^e=aUcxGw9zR00YJA{J6^lg zwx+jlo=rFnuMBZ=4ps0zNPM~Myd;&J$<>dGgAs32AybZfA;`pqggE>O55-NDl_?uH z_m7i3EZ>D@$9p1UcZ8p4S%(2sNS7_PgG=;}gUq<6%!tnbH)5dZH@{c8tCELIVqU7D zY|@>{D4qP~tm7ouT%>pPFpDo5c3bePHN!yYtRn`-_`iRbrUZl8`mZK!+jP%`mbu{d#s z3Yoyn1@3JHUO%pDge@>%xuc}mDENqetMI!ZU5oS@M+@Egm7M7*%y{8(8v5!a%)E3j zrODQ4IqR9j89;XdPY2i;jjLhVfEc4eZ3C_;)l$79v-H_<%NQxo5bK*?%B;d~CZ_15 z98Djwp<8Hh50t08+bAc293mJVZXGF>D%3+zzj3jc?b8Euyw*m*0RC!Dd=5B z%UX5uk{Sxjpbwk{eb3%i$i6e=o}FcWuUmr4{hPF1%iI+p$Ef}Kwe0L<<9&HUe6evuAZ&*gnon)~q2aVJ|Z6CA^Xr(vqMPvHMh&BO7w( zy@K&~f6Z+h+*}g=vpSilxWzYE21s$7ugf#?toV&SQ3WRm?w+)-GcI`|k(DNq2ra)S zEE}I9GMj8G8{FP2_bI#7u8#Z@Wj(JP-RLvl?`-pftg^u2XiQvZ{Bygxd^o?hdiWGQ zoz&Lpl&A|m>Y8*4mysCkS_24fuU^9*plMbkS`T$07P-76~gx&?2phMoCjYT8|*eho5X}p`I$Bwq zy#(mD|E>-wd7Xb@x>{e#-zg6IvC8-zp7B;oX>c6_DZlAC_AbCP}PgDbv=(ROK)-BYgSuC}l_e)TP^SW3kyB@AY zc+QRN92I6fP8~mC{KepOc8C3~SHI7UwGI{Ye;6-PeQM=u;br}Se)DhH;V z_kxJ<_RE5|FRORfOXpY6>)k(7&D;J(;7)|_qLbWDT0v$B?r1{sV!G=j#!*nFEF@Yk z@7zC$x?p<{z$N_N#85MTaK~*7)3YYGjz&9@@U7|~xLNeA=NaxYGtEC9`Y;7PFpVUn zm_Uq+&(Vk7x5W`{xd4rVHe9*Z9|U_dcU44;j^b6UYfxb-uWL4UhQ__c#HY_P6J)g{ z(Yv83E_Mf#z&nz9J4~?g`6pCvNBUUqf;czQyQ-g(i`FuG>T_zN&wuR&(-jCEgvMda zF0H%!c6OBeFH~LXeJH;VaPKMCtMLjQ@Ezw_balhxk#I{+*DGzKPSKuDQg(x$aN+ldgxXU&)Eg-*2 zORcFeF@4;m`selAslVIT!__qCiZq?1-@TB}iMYRZ>Zti)AacYexYSCJIvG|=6F#~El>JRrl=iWfy~&pRY8 zD4#?Qx+$Uy`=9%Zq%mH;vBB5Vb)m5R=?5ay%ArO}?97yt~px zj6yfxmqxFS29IU=+A_T_JOb!*%@RL0w9jJ^t~F81Gi&=ib~oOyAakMjF@XeVZP7(H@6cwh0x7u&;9nEs&>xT#p6-Q#2z64tGJh<>-mN~}9@ zoIa*$!>VgeSL^DAJcJ3fS1tU$N!BJU+q}5y_9NuVBj{ljq8$VJF|$IvuP&h7r*Ev|FNqL=kRFcl#!Yb#Vxymk3;&AFK9+{;3P{+PlMa|2XCcGaBsj}(`9joT;_CB*|yV7?%yjWUqA z7^t7&-G)g_kN$aIh4zZ`-Lg&6eAZLqCw*WH%`B*zy%-=P4^aO)D?X}iz7XeuINN*U zb7-$>J8j==boBcQtrLZx`r0AJ6tKqT!l@9VAq#BoErp?$#2*uA^t>$a8c8v#y1AmN z!7C6>} zv9ieYE$8qJ8?hO2y55>Q5({cyrFGr=)U8*;0>>N^-c09;^5FXp?>5i~NZZ=h)FjU1 ziI$iH!!80F74mSn9dn4R!!CZnm7{?(1LR!Cy)Y`|i|YdXSncOHY0%zZxkcGB`4X_W zioT8~y48?B#1Bw9n=B7H5P4Py4O9qYF}g=?oeEh;j>0mn4h*dn zdoPbMWXU7TK(TRcy2XCkBfnM$$+%M^k99`Xuv1VelUx3;>y2xlS#Et^i+=~*LX-9V zkNDApf>cOvjXf2zG<6gm-3k4qYs-Ti%(xM!+3@|$VQ$oM7R(vWNa@BgK0`#{xOUKh z5&6{oXv(uAuBri_y{8I8aM?{+zr+fuGQ5h2$JehA&Z+3LA{l;?*w)=f zXDa0W^yaZ#0A*Yr$OX2k5b54d^qy!l6*3fo^^}@LE02&=nsT;}xkd&63FY-&Z15q(M*)f8>TBpz0tOEUik)H)~AA0GYQ3F6`ES$qmh4C0VNP))6voqbJ1n;8v_>GEZ+U zkC5j5RbA}RZ{Vj-mcQ4&PA?t$KBq@l1iIx0dRbV!Qu#O;&Vybn`-O{-rgVVuDu8Xp zB~0;Cx(lLUJLBGnE`#TSf9t&Kd$Y!&_`l0(65=V^$8bjmGIM~$hiLgXzggw~Qn#m| zx6TGWJC4D5Y)0bQ$cpo@(D6g2P|pw56}6+!`t|I(tx9v=yc5!z_>ncly#=y~u|{#q z>D}XxuvKFKbase4sJT+rR@>yUaz*mUU;f+ua)vjQ4*kUkm17$1@&TsSfc%D%S>62A zL&dzB{c-P$6NGzFY~7M#J)iQDSLFc=5V3HJl-ADSZ4)P?vFon4Kr*i{Ofr1JHLSMV zMVJOR{*B`t&=c>)XzPgyQB|c}ZDO1wtim(AZ6_6-J<&DqQ%$5&{jQTcRg_wvT+1p> zICC6@n|p^4!p-H>Tq+=+#V}DJt-7u`rhK+p>r-*1DNQevwft0vPCd9H>&Ez)_NhZN z9ow!;kB{vLi8O&N={c8|9r4GHEcg|+@Pqt}3i;fbOoe>#Ku+N1*0IreVko*rWe3OA zb;l)0S4Jn5BGxbUGy?dXtHO<_8j)PW;)(hC#Ud;|19wq!rjh4d}>fEJ_ zz?|S=5p&M#)5QH2DFz)b;#fw`YhhoVex%6d=f~fxepbwM$3Hl!sVH?JyJ|l!(7??r%t+AFo3J_(yH;d`1o7dH zP#B;274YJ}ccRauiQdYDCRu_Nm^54?fszIG+MqJlNJ4pyo$Km#*MD*;w03>gEstr$ z_6&Ay2$zBblvc<*T{d7Mdj*fG+lIy9-S8ZgQ+MG-t3sLU+a{ipnyw`tQXmz-Fv)Im z!LVmi@fXAHmteU2rl&iXtj5Zo&c^r%;L(KK<2p`N#<^pr+2%J}dj(}`JO$iHQ!{t3 z=HyjWTzOQVb!+Z?{H$gkBr)slH>`9ioE|l84Imd4W!oLZN3g0v-ueyEpe$&vdfjz7 zlca%KG875F4SDrjeofl%WNzK|Q&$ts$LPlnY((EQ;%3VfJYvUG?%52#UPT1_b7klQ zEj!drBM~H}=R=`bYi02w7C5~^hUy!Gwq*zRojiwz-kw+F3C9^ootr*sHx|n^7F{eN>byDzGEBi|AIg02Ou;0ztEDV^|ZOPqPZ1> zND$Xr289D``Moip1Y2U`pU@h`JJC3Gu$kt0U?7S)jteN*j>Z`mcXgq~f(yz+DD;<4 zm>WQQe8l@A$S245n1MACg2I|XifGq42`H1C+tV3~KIuwl7kotN-)yXCFn9L&n47Bc zPK43oLf#fL0Rc*mwsM>+{7@Ym4+HevFysfg@&NgXg3KG-=F7J7VwbOH^Jb)}jQ*s^ zQ4|9iNdsRmyIltNdNz`C$gW^ofbE|tgU$?Z_Bi(R=*HG`Rtjw3&tdvCDW3EZ{7H~JkukSA? zN9d>zyKnBq`A!a-Q@Rq~Yz5z>+R;h`6_x4RZN0&E^%J^$wCS!K)b?ei}dy`k;I6QTnWf-Y9ZVA?*oJ1GR+EXJ5YlTJ#Xwx~F^GE}Zh#aX;2V zyKL*v+*oVvf~Zi?&gChMj|!JcEvpN*Wsgw7z3TXK7$JhhHt)WZd}EetOscA?Hbt-7 z&uPvSsU;_MCTZ6Ap#*On(2bQUg^Qr@HbC0qWxI9@bq@n(CqngK*#?a&Islod}j^OgD0Ozrm#FJLAMxEA#NG=db^vI37{b0Dw7!5J+@#( zJK>Jo9fK#uzrbT~_Xnob+i~nUQRIsX zr+;C1?K67`(_8C}eX^JeaT=aHKhS~@kiods=Uqz8$?Xp)r_ui0Xl^EQ9q2v##kePL z{(8Kj`b9J|a{Y155D zIY43cBMQo8^C32Q4zY~OJ_9qT!HBc+hqKs)u002mI{6f$64%z`>^rcI;a#g~z%?w- zTs;8K7m!Ccu)>$(3IzSdzMIO-%N=BcM20~VgsaEFKX7|y+90LRZ%C(Hl0V`HGbWP? z>A47VK^)0sOHm=i_Wfv4=wK3=XIFC@8?O_w)Bk@8D?|qFzv{2We|426TF|s&k#ZlR zmoI@$%lEYZp1kq?m%Jfv|4ZIX4*)7?iV1%g{D|EZb|~`;cMdmK4XcDlqg}9|F6?9> zn-vY9#Y45>g@C1TSp4bXbp?-KA#%A6(VSzxU9GqLM7UY**QBTNixnYHN+8eYl?z|B{kDZ}H z0F{jSe2jP-CeGn}kj`k;ohn6`VfgL`MpTY*Ub=A#DaFt^>YZ+zz>iGAU7tnydezLa z6&cQuQY+o{;CxCOqC6oKb`L&@X#?|+-=nx-wVc1936-Lx_PnbledB@7PW)^h!QiU+ zSvj#f11M=IIr&%W%0%Z``BW{Cq*&biCsZT22ATtqJ2RmG-^=~puOZzu3G{gC7Tj1N{X32Mus#g z5jl|Y;bop15z0=1&7LQVxBU$4?1~i19Mey_EQh_y<^1$@i5pRl`#eAvZCZpeRE0;8 zwp)FhRffm8dl%qb9is7{XdYZonj%+kpWr;t{~BW6CXx)y82F8~4VRRf-<{8iEHaqQ zC_lCj^gC{7<_n(15KVAX%Iydcee;3rvEKRo=9<0kdSQa%(ok8CVn@SEDZ6S7i{2`7 z^^^@Q^1uK)3Io+V*z2IMo&kFxgP;alU?rE7UFU#avn&uzMkG$gm;7$cGVvHD5B!^~ zW2GG5g(=z*P@dBt6c!3FpT7U0Ay~gxR+^oSfdVM09tcT`*PSUv1EC z@JY`F{u*%Gl)s(<2S z5k$gzy>ITLON68;RAz3DSRYq8)=@fr&nv?2CuzG-2Q~1q1Z@G5@HBEx?i}v;=_qbz zI|%XEnk1SJo`gCKK6b3C7~6er>QeDV&QmI0wY$6Z)yr;K5~$?oU4dLm_~qvy`tVR8 zBr7#9Kh3&rkLhU&^XdxgiJQxl(l|2RkrqHAt+b*m)LVm)owMrW3W2csCdSDPkFv6l zHZ4;hLtR*emjm66#}(G~UYOA0Vg|%fZ&Bl20b`%b1*~u5vUdz`1mZ3j20Bk`6slpN zZrRdXR7j!ciSJ%YJe)+}|vn)*wx+L?TV4f~(OjTsmq%#@=6Y ztwWi>@HEO6DJ3k3a++zZS@(NFzt+?-e-nQAX|VkGkl14g*GDAnTVHVa*{xbKWU9jN zd)X#A$t?JD@DB%$35^=ln(!6$08DiKtwO8g91^cvw!TuNwYvq`j!1(%R)- z;AwdF+y3`3Q~)`nxOK9}hu`|Z_26f$)uMo95dRAHfB|iYAiDTPI1Yo7GLv#~3&##t4=Eq#nzwowv{(AcjfdI&@%npYOibEkZpoW> z-X22C&=v@yN7s7OqWGj1g{2_ZMNFHxku#6r{+&Kb!CuS?4AFY)n35=YLB=cALQTt# zUE>>cAfx}RNYmu-8-sfCtkDeEr46jxnK$6ON%K#c4$?=D!0yMTU=9jC_#~wt$e9b0 zb*KyH<;X6J+6%I~A%0%WYy_2ZOXcKN_xTD(FZFACQ)hF}7|bg5y)!WJ>b4gjNFWfv zfMt+%f!m%{n=i#qB`nB9h^_JKj%I5qdeAS0nFQNCPl7B_mZLOoIU*A4t5ba5|E{^M zKDIqMJK6K&uI>ear4R$@JA&}DUqhI+L*$QMU{|^*oM3Av>!@lDk0ktgUaG^2g>k9NZ!q=(bBv(o{u`)g*CC{Y>3j_VIfn<- zBPc9So#&5WLS%Jdci|`j+UNdkhOWKbPQ}P8tgqu1T;^Njdw~?z>(T0G?q`Zmic>f@ zhzSW48By6q{KnprWTtHuD8K5OH0eG_DjmqI0Bb0w2onRzhFZ$g}CZ+M2h1 zG;dxDh_PluB|>QEtvk>}8&5!rYyHpBeHV2cuZ|Qd1V1kxS=sO~`cG$~y)KfYRgO() zHg6(6kp1)ti@Wq!maQznQklr0uu7A>DJ-PL0m4AIjzZJmVr?Sg=8%(2ko;{{X4-{` zta!atnog;kUC1+<1;Nt@qB%MSd}%5{gaf&Nj=}mwx-YpZs7A8X3{{qpA{F1PTgK9^ zTsTMPU9EEW+197Z-`je=_J>(1Dz-jnyuR}X)r-3$z$C55aQYPIr?sN1$G_V9nQDJ* zukkHEzxyqI%W7^ZXya-2C1&)3a1#?Ho(kDRgAc@_$pJW}Rjld67!`uSglOa4jVM7B zg<}H*pf22cTQkk#_)9ayX0ouiPkG)Qw?EpGFjkMF4O9UW4+Ps5nGJZ18Wj@7OBqA( zJ#)UWdZ-ik_?5oNI0s*Ud0x$d{gZyhzB&1D8^PB?o5Sh^W(84 z>0tZ7L8<&X+r&s%B2CL3#|O-JB%gedyhnIu`6`-FSRkmn5jy17N705M5rC|0hw`NI z-dhr)&0fE?ey`4dz5%BsOi(dP{e`!v_TkZeDtM)h$MD;<_Z#WN&plu7p^$rw0AW%6 z(IADDY&-hS+W%zmi4oaTD8YmK+FqLb*!BA8z1u!oc4?NK{tC*$?p%wNpzD=zu2+YZ zl%)VVQqt_ykW9KYre!Kri`&qo?J5_<7t5B;U;QpOQAktrK}pHE9;2H^rRXQ4Bm|ic zLt!=}!YQmOj?atjU7rG63s>>l!HR>5DNeP)=*2C_ZLRkvf=<)Q-*O&VebX}kZkh6_ zSXokNQpLPU-R~Fr%romzutpJpWLhT{kg2YbnmzYp+?Mz_>8vfP!T=PE`HK4%x6caA zIz0Vib@%l&Tj5XeWIn_f-69qY9(lD~s~SNwtRiy(oil<; Date: Sun, 2 Jul 2023 09:13:27 -0400 Subject: [PATCH 134/160] Add support for changing console title - Move `VersionExtensions` to `Tgstation.Server.Common`. - Fix Host watchdog API version specifying `Revision`. --- src/Tgstation.Server.Api/ApiHeaders.cs | 1 + .../Tgstation.Server.Api.csproj | 4 + .../Tgstation.Server.Client.csproj | 1 - .../Extensions}/VersionExtensions.cs | 2 +- src/Tgstation.Server.Host.Console/Program.cs | 5 +- .../Tgstation.Server.Host.Watchdog.csproj | 1 + .../Watchdog.cs | 4 +- .../Components/InstanceManager.cs | 87 ++++++++++++------- .../Components/Session/SessionController.cs | 2 +- .../Session/SessionControllerFactory.cs | 2 +- .../Controllers/ApiController.cs | 1 + .../Extensions/Converters/VersionConverter.cs | 2 +- src/Tgstation.Server.Host/IO/Console.cs | 21 ++++- src/Tgstation.Server.Host/IO/IConsole.cs | 5 ++ .../Setup/SetupWizard.cs | 17 +++- .../System/AssemblyInformationProvider.cs | 2 +- .../Tgstation.Server.Host.csproj | 1 - .../Utils/SwaggerConfiguration.cs | 1 + .../Converters/TestVersionConverter.cs | 4 +- .../IO/TestConsole.cs | 12 ++- .../Live/Instance/ByondTest.cs | 2 +- .../Live/Instance/WatchdogTest.cs | 1 + .../Live/RawRequestTests.cs | 1 + .../Live/TestLiveServer.cs | 1 + tests/Tgstation.Server.Tests/TestVersions.cs | 1 + .../Program.cs | 1 + tools/Tgstation.Server.Migrator/Program.cs | 1 + 27 files changed, 133 insertions(+), 50 deletions(-) rename src/{Tgstation.Server.Api => Tgstation.Server.Common/Extensions}/VersionExtensions.cs (94%) diff --git a/src/Tgstation.Server.Api/ApiHeaders.cs b/src/Tgstation.Server.Api/ApiHeaders.cs index 062e521288..c8a3093c78 100644 --- a/src/Tgstation.Server.Api/ApiHeaders.cs +++ b/src/Tgstation.Server.Api/ApiHeaders.cs @@ -12,6 +12,7 @@ using Microsoft.Net.Http.Headers; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Properties; +using Tgstation.Server.Common.Extensions; namespace Tgstation.Server.Api { diff --git a/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj b/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj index cb44534a9c..09a0d1bac7 100644 --- a/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj +++ b/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj @@ -48,4 +48,8 @@ + + + + diff --git a/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj b/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj index 07e99c9dd4..490a1c51dc 100644 --- a/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj +++ b/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj @@ -27,7 +27,6 @@ - diff --git a/src/Tgstation.Server.Api/VersionExtensions.cs b/src/Tgstation.Server.Common/Extensions/VersionExtensions.cs similarity index 94% rename from src/Tgstation.Server.Api/VersionExtensions.cs rename to src/Tgstation.Server.Common/Extensions/VersionExtensions.cs index 9a194f0abb..3e6b3102bd 100644 --- a/src/Tgstation.Server.Api/VersionExtensions.cs +++ b/src/Tgstation.Server.Common/Extensions/VersionExtensions.cs @@ -1,6 +1,6 @@ using System; -namespace Tgstation.Server.Api +namespace Tgstation.Server.Common.Extensions { /// /// Extensions for the class. diff --git a/src/Tgstation.Server.Host.Console/Program.cs b/src/Tgstation.Server.Host.Console/Program.cs index 1a3c02cd72..6ba3a851e9 100644 --- a/src/Tgstation.Server.Host.Console/Program.cs +++ b/src/Tgstation.Server.Host.Console/Program.cs @@ -1,10 +1,11 @@ using System; using System.Collections.Generic; +using System.Reflection; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; - +using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Watchdog; namespace Tgstation.Server.Host.Console @@ -34,6 +35,8 @@ namespace Tgstation.Server.Host.Console /// A representing the running operation. internal static async Task Main(string[] args) { + System.Console.Title = $"tgstation-server Host Watchdog v{Assembly.GetExecutingAssembly().GetName().Version.Semver()}"; + var arguments = new List(args); var trace = arguments.Remove("--trace-host-watchdog"); var debug = arguments.Remove("--debug-host-watchdog"); diff --git a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj index 9a8d30a658..2ee844505b 100644 --- a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj +++ b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj @@ -44,6 +44,7 @@ + diff --git a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs index 5cc8fb12cb..a2bd4e7420 100644 --- a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs @@ -10,7 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; - +using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Common; namespace Tgstation.Server.Host.Watchdog @@ -109,7 +109,7 @@ namespace Tgstation.Server.Host.Watchdog return false; } - var watchdogVersion = executingAssembly.GetName().Version.ToString(); + var watchdogVersion = executingAssembly.GetName().Version.Semver().ToString(); while (!cancellationToken.IsCancellationRequested) using (logger.BeginScope("Host invocation")) diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index 23172671dc..bd0c687e20 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -87,6 +87,11 @@ namespace Tgstation.Server.Host.Components /// readonly ISwarmServiceController swarmServiceController; + /// + /// The for the . + /// + readonly IConsole console; + /// /// The for the . /// @@ -132,6 +137,11 @@ namespace Tgstation.Server.Host.Components /// readonly CancellationTokenSource shutdownCancellationTokenSource; + /// + /// The original of . + /// + readonly string originalConsoleTitle; + /// /// The returned by . /// @@ -155,6 +165,7 @@ namespace Tgstation.Server.Host.Components /// The value of . /// The value of . /// The value of . + /// The value of . /// The containing the value of . /// The containing the value of . /// The value of . @@ -169,6 +180,7 @@ namespace Tgstation.Server.Host.Components IAsyncDelayer asyncDelayer, IServerPortProvider serverPortProvider, ISwarmServiceController swarmServiceController, + IConsole console, IOptions generalConfigurationOptions, IOptions swarmConfigurationOptions, ILogger logger) @@ -183,10 +195,13 @@ namespace Tgstation.Server.Host.Components this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.serverPortProvider = serverPortProvider ?? throw new ArgumentNullException(nameof(serverPortProvider)); this.swarmServiceController = swarmServiceController ?? throw new ArgumentNullException(nameof(swarmServiceController)); + this.console = console ?? throw new ArgumentNullException(nameof(console)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); swarmConfiguration = swarmConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(swarmConfigurationOptions)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); + originalConsoleTitle = console.Title; + instances = new Dictionary>(); bridgeHandlers = new Dictionary(); readyTcs = new TaskCompletionSource(); @@ -426,42 +441,49 @@ namespace Tgstation.Server.Host.Components /// public async Task StopAsync(CancellationToken cancellationToken) { - using (cancellationToken.Register(shutdownCancellationTokenSource.Cancel)) - try - { - logger.LogDebug("Stopping instance manager..."); - - if (!startupTask.IsCompleted) + try + { + using (cancellationToken.Register(shutdownCancellationTokenSource.Cancel)) + try { - logger.LogTrace("Interrupting startup task..."); - startupCancellationTokenSource.Cancel(); - await startupTask; + logger.LogDebug("Stopping instance manager..."); + + if (!startupTask.IsCompleted) + { + logger.LogTrace("Interrupting startup task..."); + startupCancellationTokenSource.Cancel(); + await startupTask; + } + + var instanceFactoryStopTask = instanceFactory.StopAsync(cancellationToken); + await jobService.StopAsync(cancellationToken); + + async Task OfflineInstanceImmediate(IInstance instance, CancellationToken cancellationToken) + { + try + { + await instance.StopAsync(cancellationToken); + } + catch (Exception ex) + { + logger.LogError(ex, "Instance shutdown exception!"); + } + } + + await Task.WhenAll(instances.Select(x => OfflineInstanceImmediate(x.Value.Instance, cancellationToken))); + await instanceFactoryStopTask; + + await swarmServiceController.Shutdown(cancellationToken); } - - var instanceFactoryStopTask = instanceFactory.StopAsync(cancellationToken); - await jobService.StopAsync(cancellationToken); - - async Task OfflineInstanceImmediate(IInstance instance, CancellationToken cancellationToken) + finally { - try - { - await instance.StopAsync(cancellationToken); - } - catch (Exception ex) - { - logger.LogError(ex, "Instance shutdown exception!"); - } + console.Title = originalConsoleTitle; } - - await Task.WhenAll(instances.Select(x => OfflineInstanceImmediate(x.Value.Instance, cancellationToken))); - await instanceFactoryStopTask; - - await swarmServiceController.Shutdown(cancellationToken); - } - catch (Exception ex) - { - logger.LogCritical(ex, "Instance manager stop exception!"); - } + } + catch (Exception ex) + { + logger.LogCritical(ex, "Instance manager stop exception!"); + } } /// @@ -535,6 +557,7 @@ namespace Tgstation.Server.Host.Components try { logger.LogInformation("{versionString}", assemblyInformationProvider.VersionString); + console.Title = assemblyInformationProvider.VersionString; CheckSystemCompatibility(); diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index a5793e38a1..70a76e6760 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -13,8 +13,8 @@ using Newtonsoft.Json; using Serilog.Context; -using Tgstation.Server.Api; using Tgstation.Server.Api.Models; +using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Components.Byond; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Deployment; diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 71756c841f..55439579db 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -10,9 +10,9 @@ using Byond.TopicSender; using Microsoft.Extensions.Logging; -using Tgstation.Server.Api; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Components.Byond; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Deployment; diff --git a/src/Tgstation.Server.Host/Controllers/ApiController.cs b/src/Tgstation.Server.Host/Controllers/ApiController.cs index f9e3868ada..b3d26b709f 100644 --- a/src/Tgstation.Server.Host/Controllers/ApiController.cs +++ b/src/Tgstation.Server.Host/Controllers/ApiController.cs @@ -22,6 +22,7 @@ using Serilog.Context; using Tgstation.Server.Api; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Response; +using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Database; using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.Models; diff --git a/src/Tgstation.Server.Host/Extensions/Converters/VersionConverter.cs b/src/Tgstation.Server.Host/Extensions/Converters/VersionConverter.cs index 83eee22114..ec08e5ae7b 100644 --- a/src/Tgstation.Server.Host/Extensions/Converters/VersionConverter.cs +++ b/src/Tgstation.Server.Host/Extensions/Converters/VersionConverter.cs @@ -2,7 +2,7 @@ using Newtonsoft.Json; -using Tgstation.Server.Api; +using Tgstation.Server.Common.Extensions; using YamlDotNet.Core; using YamlDotNet.Core.Events; diff --git a/src/Tgstation.Server.Host/IO/Console.cs b/src/Tgstation.Server.Host/IO/Console.cs index 1b9e5fc8f9..0643ac9cab 100644 --- a/src/Tgstation.Server.Host/IO/Console.cs +++ b/src/Tgstation.Server.Host/IO/Console.cs @@ -3,19 +3,33 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -using Tgstation.Server.Host.Extensions; +using Tgstation.Server.Host.System; namespace Tgstation.Server.Host.IO { /// sealed class Console : IConsole, IDisposable { + /// + public string Title + { + get => platformIdentifier.IsWindows + ? global::System.Console.Title + : null; + set => global::System.Console.Title = value; + } + /// public bool Available => Environment.UserInteractive; /// public CancellationToken CancelKeyPress => cancelKeyCts.Token; + /// + /// The for the . + /// + readonly IPlatformIdentifier platformIdentifier; + /// /// The for . /// @@ -29,8 +43,11 @@ namespace Tgstation.Server.Host.IO /// /// Initializes a new instance of the class. /// - public Console() + /// The value of . + public Console(IPlatformIdentifier platformIdentifier) { + this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); + cancelKeyCts = new CancellationTokenSource(); global::System.Console.CancelKeyPress += (sender, e) => { diff --git a/src/Tgstation.Server.Host/IO/IConsole.cs b/src/Tgstation.Server.Host/IO/IConsole.cs index 8fbe368f39..605f3e421d 100644 --- a/src/Tgstation.Server.Host/IO/IConsole.cs +++ b/src/Tgstation.Server.Host/IO/IConsole.cs @@ -8,6 +8,11 @@ namespace Tgstation.Server.Host.IO /// interface IConsole { + /// + /// Gets or sets the window's title. Can return if getting the console title is not supported. + /// + string Title { get; set; } + /// /// If the is visible to the user. /// diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index 4b4654ca4b..dde11140f8 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -1073,8 +1073,18 @@ namespace Tgstation.Server.Host.Setup await console.WriteAsync("Aborting setup!", true, default); } - // Link passed cancellationToken with cancel key press Task finalTask = Task.CompletedTask; + string originalConsoleTitle = null; + void SetConsoleTitle() + { + if (originalConsoleTitle != null) + return; + + originalConsoleTitle = console.Title; + console.Title = $"{assemblyInformationProvider.VersionString} Setup Wizard"; + } + + // Link passed cancellationToken with cancel key press using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, console.CancelKeyPress)) using ((cancellationToken = cts.Token).Register(() => finalTask = HandleSetupCancel())) try @@ -1106,6 +1116,7 @@ namespace Tgstation.Server.Host.Setup { if (forceRun) { + SetConsoleTitle(); await console.WriteAsync(String.Format(CultureInfo.InvariantCulture, "The configuration settings are requesting the setup wizard be run, but you already appear to have a configuration file ({0})!", userConfigFileName), true, cancellationToken); forceRun = await PromptYesNo("Continue running setup wizard?", false, cancellationToken); @@ -1115,6 +1126,8 @@ namespace Tgstation.Server.Host.Setup return; } + SetConsoleTitle(); + // flush the logs to prevent console conflicts await asyncDelayer.Delay(TimeSpan.FromSeconds(1), cancellationToken); @@ -1123,6 +1136,8 @@ namespace Tgstation.Server.Host.Setup finally { await finalTask; + if (originalConsoleTitle != null) + console.Title = originalConsoleTitle; } } } diff --git a/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs b/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs index f074d50c4e..aa035c772f 100644 --- a/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs +++ b/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs @@ -2,7 +2,7 @@ using System.Net.Http.Headers; using System.Reflection; -using Tgstation.Server.Api; +using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Common; namespace Tgstation.Server.Host.System diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 5673e4096d..1b58a03bdd 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -140,7 +140,6 @@ - diff --git a/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs b/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs index 367febec2f..3bd803b362 100644 --- a/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs +++ b/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs @@ -16,6 +16,7 @@ using Swashbuckle.AspNetCore.SwaggerGen; using Tgstation.Server.Api; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Response; +using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Controllers; namespace Tgstation.Server.Host.Utils diff --git a/tests/Tgstation.Server.Host.Tests/Extensions/Converters/TestVersionConverter.cs b/tests/Tgstation.Server.Host.Tests/Extensions/Converters/TestVersionConverter.cs index 8347ca19f7..deb2fc1760 100644 --- a/tests/Tgstation.Server.Host.Tests/Extensions/Converters/TestVersionConverter.cs +++ b/tests/Tgstation.Server.Host.Tests/Extensions/Converters/TestVersionConverter.cs @@ -1,7 +1,7 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using System; -using Tgstation.Server.Api; +using Tgstation.Server.Common.Extensions; using YamlDotNet.Serialization; diff --git a/tests/Tgstation.Server.Host.Tests/IO/TestConsole.cs b/tests/Tgstation.Server.Host.Tests/IO/TestConsole.cs index d093287c7a..f5878a7e2f 100644 --- a/tests/Tgstation.Server.Host.Tests/IO/TestConsole.cs +++ b/tests/Tgstation.Server.Host.Tests/IO/TestConsole.cs @@ -4,15 +4,23 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +using Tgstation.Server.Host.System; + namespace Tgstation.Server.Host.IO.Tests { [TestClass] public sealed class TestConsole { + [TestMethod] + public void TestContructionThrows() + { + Assert.ThrowsException(() => new Console(null)); + } + [TestMethod] public async Task TestWriteLine() { - var console = new Console(); + var console = new Console(new PlatformIdentifier()); await Assert.ThrowsExceptionAsync(() => console.WriteAsync(null, false, default)); try { @@ -28,7 +36,7 @@ namespace Tgstation.Server.Host.IO.Tests [TestMethod] public void TestUserInteractive() { - var console = new Console(); + var console = new Console(new PlatformIdentifier()); Assert.AreEqual(Environment.UserInteractive, console.Available); } } diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs index 68e89c0f9f..c4467ba34e 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs @@ -9,11 +9,11 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; -using Tgstation.Server.Api; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Request; using Tgstation.Server.Client; using Tgstation.Server.Client.Components; +using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Components.Byond; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.IO; diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 82d61d7b05..2dbb2ca193 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -24,6 +24,7 @@ using Tgstation.Server.Api.Models.Request; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Client; using Tgstation.Server.Client.Components; +using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Components; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Interop; diff --git a/tests/Tgstation.Server.Tests/Live/RawRequestTests.cs b/tests/Tgstation.Server.Tests/Live/RawRequestTests.cs index 02884dac07..a9023401ff 100644 --- a/tests/Tgstation.Server.Tests/Live/RawRequestTests.cs +++ b/tests/Tgstation.Server.Tests/Live/RawRequestTests.cs @@ -14,6 +14,7 @@ using Tgstation.Server.Api; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Client; +using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host; namespace Tgstation.Server.Tests.Live diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index d373e2916e..962b39c049 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -31,6 +31,7 @@ using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Api.Rights; using Tgstation.Server.Client; using Tgstation.Server.Client.Components; +using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Components; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Database; diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 8e206913ba..d5d0c6e881 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -9,6 +9,7 @@ using System.Xml.Linq; using Tgstation.Server.Api; using Tgstation.Server.Client; +using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Configuration; diff --git a/tools/Tgstation.Server.Migrator.Comms/Program.cs b/tools/Tgstation.Server.Migrator.Comms/Program.cs index cb8a68cfe3..8cebd477c7 100644 --- a/tools/Tgstation.Server.Migrator.Comms/Program.cs +++ b/tools/Tgstation.Server.Migrator.Comms/Program.cs @@ -15,6 +15,7 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Models.Request; using Tgstation.Server.Client; +using Tgstation.Server.Common.Extensions; static class Program { diff --git a/tools/Tgstation.Server.Migrator/Program.cs b/tools/Tgstation.Server.Migrator/Program.cs index 046a6c7308..3332b5b52e 100644 --- a/tools/Tgstation.Server.Migrator/Program.cs +++ b/tools/Tgstation.Server.Migrator/Program.cs @@ -21,6 +21,7 @@ using Octokit; using Tgstation.Server.Api; using Tgstation.Server.Client; +using Tgstation.Server.Common.Extensions; using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Common; using Tgstation.Server.Host.IO; From d177dafd24b6e439ceba1ec62b88fe55911b893a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 09:17:33 -0400 Subject: [PATCH 135/160] Fix test Windows install .exe path --- .github/workflows/ci-pipeline.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 586a46e4a5..75959c1595 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1030,9 +1030,9 @@ jobs: run: | mkdir C:/ProgramData/tgstation-server cp build/package/appsettings.GitHub.yml C:/ProgramData/tgstation-server/appsettings.Production.yml - $file = [System.IO.Path]::GetFullPath("build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin/x86/Release/tgstation-server-installer.exe") + $file = [System.IO.Path]::GetFullPath("build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin/Release/tgstation-server-installer.exe") $log = [System.IO.Path]::GetFullPath("install.log") - $procMain = Start-Process "$file" "/install /silent /log `"$log`"" -NoNewWindow -PassThru -Wait + $procMain = Start-Process -FilePath $file "/install /silent /log `"$log`"" -NoNewWindow -PassThru -Wait if (Test-Path -Path $log -PathType Leaf) { Get-Content $log } @@ -1062,9 +1062,9 @@ jobs: - name: Test Uninstall # Sanity checks the .deps.json exists, which the installation is broken without shell: powershell run: | - $file = [System.IO.Path]::GetFullPath("build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin/x86/Release/tgstation-server-installer.exe") + $file = [System.IO.Path]::GetFullPath("build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin/Release/tgstation-server-installer.exe") $log = [System.IO.Path]::GetFullPath("uninstall.log") - $procMain = Start-Process "$file" "/install /silent /log `"$log`"" -NoNewWindow -PassThru -Wait + $procMain = Start-Process -FilePath $file "/install /silent /log `"$log`"" -NoNewWindow -PassThru -Wait if (Test-Path -Path $log -PathType Leaf) { Get-Content $log } @@ -1083,7 +1083,7 @@ jobs: uses: actions/upload-artifact@v3 with: name: packaging-windows - path: build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin/x86/Release/tgstation-server-installer.exe + path: build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin/Release/tgstation-server-installer.exe check-winget-pr-template: name: Check winget-pkgs Pull Request Template is up to date From d308b302264cc8f9cab60c010a854f48b38c1f86 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 09:31:12 -0400 Subject: [PATCH 136/160] Add GitHub token for install-winget --- .github/workflows/ci-pipeline.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 75959c1595..4d6a07b664 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -983,6 +983,8 @@ jobs: steps: - name: Install winget uses: Cyberboss/install-winget@v1 + with: + GITHUB_TOKEN: ${{ env.WINGET_PUSH_TOKEN }} - name: Setup dotnet uses: actions/setup-dotnet@v2 @@ -1497,6 +1499,8 @@ jobs: - name: Install winget uses: Cyberboss/install-winget@v1 + with: + GITHUB_TOKEN: ${{ env.WINGET_PUSH_TOKEN }} - name: Install wingetcreate run: winget install wingetcreate --disable-interactivity --accept-source-agreements From 213c6906935e99c1047fdce578f6e59852267241 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 09:45:57 -0400 Subject: [PATCH 137/160] Fix bad Windows install path test --- .github/workflows/ci-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 4d6a07b664..2a629668b7 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1046,7 +1046,7 @@ jobs: if (-Not (Test-Path -Path "C:/Program Files (x86)/tgstation-server/lib/Default/Tgstation.Server.Host.deps.json" -PathType Leaf)) { exit 2 } - if (-Not (Test-Path -Path "C:/ProgramData/tgstation-server/appsettings.Production.json" -PathType Leaf)) { + if (-Not (Test-Path -Path "C:/ProgramData/tgstation-server/appsettings.yml" -PathType Leaf)) { exit 4 } From 5570659386c77a14256c11389e1ff75e38f2c1c3 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 09:58:42 -0400 Subject: [PATCH 138/160] Fix CI Windows test uninstall command --- .github/workflows/ci-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 2a629668b7..43a7355027 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1066,7 +1066,7 @@ jobs: run: | $file = [System.IO.Path]::GetFullPath("build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin/Release/tgstation-server-installer.exe") $log = [System.IO.Path]::GetFullPath("uninstall.log") - $procMain = Start-Process -FilePath $file "/install /silent /log `"$log`"" -NoNewWindow -PassThru -Wait + $procMain = Start-Process -FilePath $file "/uninstall /silent /log `"$log`"" -NoNewWindow -PassThru -Wait if (Test-Path -Path $log -PathType Leaf) { Get-Content $log } From e8603c450b01998e34ce2ba530f43975a59204cb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 10:15:48 -0400 Subject: [PATCH 139/160] Be persistent with winget arguments Also fix bracing in other .ps1 --- .../prepare_installer_input_artifacts.ps1 | 4 +- build/package/winget/push_manifest.ps1 | 58 ++++++++++--------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/build/package/winget/prepare_installer_input_artifacts.ps1 b/build/package/winget/prepare_installer_input_artifacts.ps1 index a7acbe1597..df88aca955 100644 --- a/build/package/winget/prepare_installer_input_artifacts.ps1 +++ b/build/package/winget/prepare_installer_input_artifacts.ps1 @@ -38,6 +38,8 @@ try } mv ../../artifacts/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.exe ../../artifacts/ -} finally { +} +finally +{ cd $startDirectory } diff --git a/build/package/winget/push_manifest.ps1 b/build/package/winget/push_manifest.ps1 index 82de440ce9..879e9d7a6c 100644 --- a/build/package/winget/push_manifest.ps1 +++ b/build/package/winget/push_manifest.ps1 @@ -11,35 +11,39 @@ $tgsVersion = $versionXML.Project.PropertyGroup.TgsCoreVersion $installerHash = Get-FileHash -Path $InstallerPath -ErrorAction Stop # SHA256 is the default cd build/package/winget/manifest +try +{ + $devHash = 'CF0D4D2FD042098D826A226A05A9DAA5C792318CF48FD334F7FC06AF6A8A23B1' + $devVersion = '0.22.475' + $devReleaseDate = '2023-06-24' + $releaseDate = Get-Date -format "yyyy-MM-dd" -$devHash = 'CF0D4D2FD042098D826A226A05A9DAA5C792318CF48FD334F7FC06AF6A8A23B1' -$devVersion = '0.22.475' -$devReleaseDate = '2023-06-24' -$releaseDate = Get-Date -format "yyyy-MM-dd" + (Get-Content Tgstation.Server.installer.yaml -ErrorAction Stop).Replace($devHash, $installerHash.Hash).Replace($devReleaseDate, $releaseDate).Replace($devVersion, $tgsVersion) | Set-Content Tgstation.Server.installer.yaml -ErrorAction Stop + (Get-Content Tgstation.Server.locale.en-US.yaml -ErrorAction Stop).Replace($devVersion, $tgsVersion) | Set-Content Tgstation.Server.locale.en-US.yaml -ErrorAction Stop + (Get-Content Tgstation.Server.yaml -ErrorAction Stop).Replace($devVersion, $tgsVersion) | Set-Content Tgstation.Server.yaml -ErrorAction Stop -(Get-Content Tgstation.Server.installer.yaml -ErrorAction Stop).Replace($devHash, $installerHash.Hash).Replace($devReleaseDate, $releaseDate).Replace($devVersion, $tgsVersion) | Set-Content Tgstation.Server.installer.yaml -ErrorAction Stop -(Get-Content Tgstation.Server.locale.en-US.yaml -ErrorAction Stop).Replace($devVersion, $tgsVersion) | Set-Content Tgstation.Server.locale.en-US.yaml -ErrorAction Stop -(Get-Content Tgstation.Server.yaml -ErrorAction Stop).Replace($devVersion, $tgsVersion) | Set-Content Tgstation.Server.yaml -ErrorAction Stop + winget validate --manifest . + if (-Not $?) { + exit $lastexitcode + } -winget validate --manifest . -if (-Not $?) { - exit $lastexitcode + # I know these are late, but we actually need the package online to install it + winget install -m . --accept-package-agreements --disable-interactivity + if (-Not $?) { + exit $lastexitcode + } + + winget uninstall tgstation-server --accept-source-agreements --disable-interactivity + if (-Not $?) { + exit $lastexitcode + } + + wingetcreate submit -t $Env:WINGET_PUSH_TOKEN . + if (-Not $?) { + exit $lastexitcode + } } - -# I know these are late, but we actually need the package online to install it -winget install -m . -h --disable-interactivity -if (-Not $?) { - exit $lastexitcode +finally +{ + cd ../../../.. } - -winget uninstall tgstation-server --disable-interactivity -if (-Not $?) { - exit $lastexitcode -} - -wingetcreate submit -t $Env:WINGET_PUSH_TOKEN . -if (-Not $?) { - exit $lastexitcode -} - -cd ../../../.. From 2607c6b8facab453a40f7345a0bc32d1e48b2935 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 16:44:53 -0400 Subject: [PATCH 140/160] Fix elevation requirement --- build/package/winget/manifest/Tgstation.Server.installer.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/build/package/winget/manifest/Tgstation.Server.installer.yaml b/build/package/winget/manifest/Tgstation.Server.installer.yaml index 3aced46d72..a9a6689538 100644 --- a/build/package/winget/manifest/Tgstation.Server.installer.yaml +++ b/build/package/winget/manifest/Tgstation.Server.installer.yaml @@ -21,6 +21,7 @@ Installers: UnsupportedOSArchitectures: - arm - arm64 + ElevationRequirement: elevatesSelf Dependencies: PackageDependencies: - PackageIdentifier: Microsoft.DotNet.AspNetCore.6 From ac9b1c8be1c97584a3aa7c2a00c48b4a367fc8db Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 18:22:45 -0400 Subject: [PATCH 141/160] Self sign installer .exe You know it's secure because this commit is signed! *taps head* --- .github/workflows/ci-pipeline.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 43a7355027..1cc32d0b2b 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1027,6 +1027,16 @@ jobs: cd build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle dotnet build -c Release + - name: Sign Installer .exe + shell: powershell + run: | + $pfxBytes = [convert]::FromBase64String("${{ secrets.CODE_SIGNING_BASE64 }}") + [IO.File]::WriteAllBytes("tg_codesigning.pfx", $pfxBytes) + $certPassword = ConvertTo-SecureString -String "${{ secrets.CODE_SIGNING_PASSWORD }}" -Force -AsPlainText + $cert=Import-PfxCertificate -FilePath tg_codesigning.pfx -Cert Cert:\CurrentUser\My -Password $certPassword + rm tg_codesigning.pfx + Set-AuthenticodeSignature build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin/Release/tgstation-server-installer.exe -Certificate $cert -TimestampServer "http://timestamp.digicert.com" + - name: Test Install # Sanity checks the .deps.json exists, which the installation is broken without shell: powershell # If it's missing, I found that in elements were the problem run: | From 6a25c2a115bc66d8dc11ce69579af03f37d5fe06 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 18:24:47 -0400 Subject: [PATCH 142/160] Disable Smart Screen during final winget test --- .github/workflows/ci-pipeline.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 1cc32d0b2b..e287ec98a9 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1502,6 +1502,15 @@ jobs: if: "!(cancelled() || failure()) && needs.deploy-tgs.result == 'success'" runs-on: windows-latest steps: + - name: Disable Smart Screen # https://superuser.com/a/1778345 + shell: powershell + run: | + Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" -Name "EnableSmartScreen" -Type DWord -Value 0 + if (!(Test-Path "HKLM:\SOFTWARE\Policies\Microsoft\MicrosoftEdge\PhishingFilter")) { + New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\MicrosoftEdge\PhishingFilter" -Force | Out-Null + } + Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\MicrosoftEdge\PhishingFilter" -Name "EnabledV9" -Type DWord -Value 0 + - name: Setup dotnet uses: actions/setup-dotnet@v2 with: From cf8f20fd1179c7f69bafbff835a153b8ad0db5b3 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 18:33:49 -0400 Subject: [PATCH 143/160] DO NOT CREATE SIGNED ARTIFACTS Delay Windows signing until TGS Deploy step --- .github/workflows/ci-pipeline.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index e287ec98a9..4b96da55be 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1027,16 +1027,6 @@ jobs: cd build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle dotnet build -c Release - - name: Sign Installer .exe - shell: powershell - run: | - $pfxBytes = [convert]::FromBase64String("${{ secrets.CODE_SIGNING_BASE64 }}") - [IO.File]::WriteAllBytes("tg_codesigning.pfx", $pfxBytes) - $certPassword = ConvertTo-SecureString -String "${{ secrets.CODE_SIGNING_PASSWORD }}" -Force -AsPlainText - $cert=Import-PfxCertificate -FilePath tg_codesigning.pfx -Cert Cert:\CurrentUser\My -Password $certPassword - rm tg_codesigning.pfx - Set-AuthenticodeSignature build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin/Release/tgstation-server-installer.exe -Certificate $cert -TimestampServer "http://timestamp.digicert.com" - - name: Test Install # Sanity checks the .deps.json exists, which the installation is broken without shell: powershell # If it's missing, I found that in elements were the problem run: | @@ -1360,6 +1350,17 @@ jobs: name: packaging-windows path: packaging-windows + - name: Sign Installer .exe + shell: powershell + run: | + $pfxBytes = [convert]::FromBase64String("${{ secrets.CODE_SIGNING_BASE64 }}") + [IO.File]::WriteAllBytes("tg_codesigning.pfx", $pfxBytes) + $certPassword = ConvertTo-SecureString -String "${{ secrets.CODE_SIGNING_PASSWORD }}" -Force -AsPlainText + $cert=Import-PfxCertificate -FilePath tg_codesigning.pfx -Cert Cert:\CurrentUser\My -Password $certPassword + Import-PfxCertificate -FilePath tg_codesigning.pfx -Cert Cert:\CurrentUser\Root -Password $certPassword + rm tg_codesigning.pfx + Set-AuthenticodeSignature packaging-windows/tgstation-server-installer.exe -Certificate $cert -TimestampServer "http://timestamp.digicert.com" + - name: Zip Artifacts shell: powershell run: | From 4ed133323a6ea4e3f98ed965d3396bf5da6cf34b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 18:37:05 -0400 Subject: [PATCH 144/160] Update notes about forks with code signing secrets --- .github/CONTRIBUTING.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index d563d8c97c..6f4a8cdab8 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -74,6 +74,8 @@ If you don't plan on deploying TGS, the following secrets can be omitted: - Secret `DOCKER_USERNAME`: Login username for Docker image push. - Secret `DOCKER_PASSWORD`: Login password for Docker image push. - Secret `NUGET_API_KEY`: Nuget.org API Key for client libraries push. +- Secret `CODE_SIGNING_BASE64`: Base64 string of a .pfx file containing a Windows code-signing certificate. +- Secret `CODE_SIGNING_PASSWORD`: Password for importing the above .pfx. ### Know your Code @@ -150,10 +152,13 @@ void Hello() { if (!thing1) return; + if (thing2) return; + if (thing3 != 30) return; + do stuff } ``` From 347e6b2f952ce51937772d6792e2d0190dfccf12 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 19:01:46 -0400 Subject: [PATCH 145/160] Sign test installer for CI purposes - Do not publish. - Also fix the CI deadlock by avoiding the root CA import --- .github/workflows/ci-pipeline.yml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 4b96da55be..1b5adbe419 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1027,12 +1027,25 @@ jobs: cd build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle dotnet build -c Release + - name: Create Test Installer .exe + run: cp build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin/Release/tgstation-server-installer.exe test-installer.exe + + - name: Sign Test Installer .exe + shell: powershell + run: | + $pfxBytes = [convert]::FromBase64String("${{ secrets.CODE_SIGNING_BASE64 }}") + [IO.File]::WriteAllBytes("tg_codesigning.pfx", $pfxBytes) + $certPassword = ConvertTo-SecureString -String "${{ secrets.CODE_SIGNING_PASSWORD }}" -Force -AsPlainText + $cert=Import-PfxCertificate -FilePath tg_codesigning.pfx -Cert Cert:\CurrentUser\My -Password $certPassword + rm tg_codesigning.pfx + Set-AuthenticodeSignature test-installer.exe -Certificate $cert -TimestampServer "http://timestamp.digicert.com" + - name: Test Install # Sanity checks the .deps.json exists, which the installation is broken without shell: powershell # If it's missing, I found that in elements were the problem run: | mkdir C:/ProgramData/tgstation-server cp build/package/appsettings.GitHub.yml C:/ProgramData/tgstation-server/appsettings.Production.yml - $file = [System.IO.Path]::GetFullPath("build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin/Release/tgstation-server-installer.exe") + $file = [System.IO.Path]::GetFullPath("test-installer.exe") $log = [System.IO.Path]::GetFullPath("install.log") $procMain = Start-Process -FilePath $file "/install /silent /log `"$log`"" -NoNewWindow -PassThru -Wait if (Test-Path -Path $log -PathType Leaf) { @@ -1064,7 +1077,7 @@ jobs: - name: Test Uninstall # Sanity checks the .deps.json exists, which the installation is broken without shell: powershell run: | - $file = [System.IO.Path]::GetFullPath("build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin/Release/tgstation-server-installer.exe") + $file = [System.IO.Path]::GetFullPath("test-installer.exe") $log = [System.IO.Path]::GetFullPath("uninstall.log") $procMain = Start-Process -FilePath $file "/uninstall /silent /log `"$log`"" -NoNewWindow -PassThru -Wait if (Test-Path -Path $log -PathType Leaf) { @@ -1081,7 +1094,7 @@ jobs: exit 2 } - - name: Upload Installer .exe + - name: Upload Unsigned Installer .exe uses: actions/upload-artifact@v3 with: name: packaging-windows @@ -1357,7 +1370,6 @@ jobs: [IO.File]::WriteAllBytes("tg_codesigning.pfx", $pfxBytes) $certPassword = ConvertTo-SecureString -String "${{ secrets.CODE_SIGNING_PASSWORD }}" -Force -AsPlainText $cert=Import-PfxCertificate -FilePath tg_codesigning.pfx -Cert Cert:\CurrentUser\My -Password $certPassword - Import-PfxCertificate -FilePath tg_codesigning.pfx -Cert Cert:\CurrentUser\Root -Password $certPassword rm tg_codesigning.pfx Set-AuthenticodeSignature packaging-windows/tgstation-server-installer.exe -Certificate $cert -TimestampServer "http://timestamp.digicert.com" From e60bf12f8714f4e36da4316a6106d7be62481372 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 19:13:28 -0400 Subject: [PATCH 146/160] Do not attempt winget (un)install validation Let's get it right the first time and then let MS do it for us --- .github/workflows/ci-pipeline.yml | 12 ------------ build/package/winget/push_manifest.ps1 | 11 ----------- 2 files changed, 23 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 1b5adbe419..4d869f8a0f 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1515,15 +1515,6 @@ jobs: if: "!(cancelled() || failure()) && needs.deploy-tgs.result == 'success'" runs-on: windows-latest steps: - - name: Disable Smart Screen # https://superuser.com/a/1778345 - shell: powershell - run: | - Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" -Name "EnableSmartScreen" -Type DWord -Value 0 - if (!(Test-Path "HKLM:\SOFTWARE\Policies\Microsoft\MicrosoftEdge\PhishingFilter")) { - New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\MicrosoftEdge\PhishingFilter" -Force | Out-Null - } - Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\MicrosoftEdge\PhishingFilter" -Name "EnabledV9" -Type DWord -Value 0 - - name: Setup dotnet uses: actions/setup-dotnet@v2 with: @@ -1537,9 +1528,6 @@ jobs: - name: Install wingetcreate run: winget install wingetcreate --disable-interactivity --accept-source-agreements - - name: Enable LocalManifestFiles - run: winget settings --enable LocalManifestFiles - - name: Checkout uses: actions/checkout@v3 diff --git a/build/package/winget/push_manifest.ps1 b/build/package/winget/push_manifest.ps1 index 879e9d7a6c..ff182010ff 100644 --- a/build/package/winget/push_manifest.ps1 +++ b/build/package/winget/push_manifest.ps1 @@ -27,17 +27,6 @@ try exit $lastexitcode } - # I know these are late, but we actually need the package online to install it - winget install -m . --accept-package-agreements --disable-interactivity - if (-Not $?) { - exit $lastexitcode - } - - winget uninstall tgstation-server --accept-source-agreements --disable-interactivity - if (-Not $?) { - exit $lastexitcode - } - wingetcreate submit -t $Env:WINGET_PUSH_TOKEN . if (-Not $?) { exit $lastexitcode From 3bb064be1e89a409e22be72b0b6e2fb23ad87f26 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 2 Jul 2023 20:14:57 -0400 Subject: [PATCH 147/160] We can't hash the unsigned installer for winget --- .github/workflows/ci-pipeline.yml | 8 +------- build/package/winget/push_manifest.ps1 | 16 +++++++++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 4d869f8a0f..0e8e3bfe0c 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1534,15 +1534,9 @@ jobs: - name: Build ReleaseNotes run: dotnet build -c Release tools/ReleaseNotes - - name: Retrieve Installer .exe - uses: actions/download-artifact@v3 - with: - name: packaging-windows - path: packaging-windows - - name: Execute Push Script shell: powershell - run: build/package/winget/push_manifest.ps1 -InstallerPath packaging-windows/tgstation-server-installer.exe + run: build/package/winget/push_manifest.ps1 - name: Run ReleaseNotes with --link-winget run: dotnet run -c Release --no-build --project tools/ReleaseNotes --link-winget ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/build/package/winget/push_manifest.ps1 b/build/package/winget/push_manifest.ps1 index ff182010ff..12b4135771 100644 --- a/build/package/winget/push_manifest.ps1 +++ b/build/package/winget/push_manifest.ps1 @@ -1,14 +1,20 @@ -param( - [string]$InstallerPath = 'build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/x86/Release/tgstation-server-installer.exe' -) - $ErrorActionPreference="Stop" [XML]$versionXML = Get-Content build/Version.props -ErrorAction Stop $tgsVersion = $versionXML.Project.PropertyGroup.TgsCoreVersion -$installerHash = Get-FileHash -Path $InstallerPath -ErrorAction Stop # SHA256 is the default +mkdir artifacts +$previousProgressPreference = $ProgressPreference +$ProgressPreference = 'SilentlyContinue' +try +{ + Invoke-WebRequest -Uri "https://github.com/tgstation/tgstation-server/releases/download/tgstation-server-v$tgsVersion/tgstation-server-installer.exe" -OutFile "artifacts/tgstation-server-installer.exe" +} finally { + $ProgressPreference = $previousProgressPreference +} + +$installerHash = Get-FileHash -Path "artifacts/tgstation-server-installer.exe" -ErrorAction Stop # SHA256 is the default cd build/package/winget/manifest try From 210b07e9d7221082c4f5c6dedc7ab6ee2f28e674 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 3 Jul 2023 12:34:25 -0400 Subject: [PATCH 148/160] Proper signing method for installer - Also sign published service `.exe`s --- .github/workflows/ci-pipeline.yml | 98 ++++++++++++++----- ...ion.Server.Host.Service.Wix.Bundle.wixproj | 13 +++ 2 files changed, 87 insertions(+), 24 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 0e8e3bfe0c..c08e4aa1ab 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -446,6 +446,21 @@ jobs: name: ServerService path: Artifacts/Service/ + - name: Install Code Signing Certificate + if: ${{ matrix.configuration == 'Release' && matrix.watchdog-type == 'Basic' }} + shell: powershell + run: | + $pfxBytes = [convert]::FromBase64String("${{ secrets.CODE_SIGNING_BASE64 }}") + [IO.File]::WriteAllBytes("tg_codesigning.pfx", $pfxBytes) + $certPassword = ConvertTo-SecureString -String "${{ secrets.CODE_SIGNING_PASSWORD }}" -Force -AsPlainText + Import-PfxCertificate -FilePath tg_codesigning.pfx -Cert Cert:\CurrentUser\My -Password $certPassword + rm tg_codesigning.pfx + + - name: Test Sign Service .exe + if: ${{ matrix.configuration == 'Release' && matrix.watchdog-type == 'Basic' }} + shell: powershell + run: Set-AuthenticodeSignature Artifacts/Service/Tgstation.Server.Host.Service.exe -Certificate (Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.Thumbprint -eq "${{ vars.CODE_SIGNING_THUMBPRINT }}" }) -TimestampServer "http://timestamp.digicert.com" + linux-integration-tests: name: Linux Live Tests needs: dmapi-build @@ -1001,6 +1016,11 @@ jobs: with: ref: "refs/pull/${{ github.event.number }}/merge" + - name: Restore Wix dotnet Tool + run: | + cd build/package/winget + dotnet tool restore + - name: Validate winget Manifest run: winget validate --manifest build/package/winget/manifest @@ -1017,35 +1037,35 @@ jobs: shell: powershell run: build/package/winget/prepare_installer_input_artifacts.ps1 - - name: Restore Wix dotnet Tool - run: | - cd build/package/winget - dotnet tool restore - - name: Build Installer .exe run: | cd build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle dotnet build -c Release - - name: Create Test Installer .exe - run: cp build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin/Release/tgstation-server-installer.exe test-installer.exe - - - name: Sign Test Installer .exe + - name: Install Code Signing Certificate shell: powershell run: | $pfxBytes = [convert]::FromBase64String("${{ secrets.CODE_SIGNING_BASE64 }}") [IO.File]::WriteAllBytes("tg_codesigning.pfx", $pfxBytes) $certPassword = ConvertTo-SecureString -String "${{ secrets.CODE_SIGNING_PASSWORD }}" -Force -AsPlainText - $cert=Import-PfxCertificate -FilePath tg_codesigning.pfx -Cert Cert:\CurrentUser\My -Password $certPassword + Import-PfxCertificate -FilePath tg_codesigning.pfx -Cert Cert:\CurrentUser\My -Password $certPassword rm tg_codesigning.pfx - Set-AuthenticodeSignature test-installer.exe -Certificate $cert -TimestampServer "http://timestamp.digicert.com" + + - name: Sign Installer .exe for Testing # https://wixtoolset.org/docs/tools/signing/ + shell: powershell + run: | + cd build/package/winget + dotnet wix burn detach Tgstation.Server.Host.Service.Wix.Bundle/bin/Release/tgstation-server-installer.exe -engine burnengine.exe + Set-AuthenticodeSignature burnengine.exe -Certificate (Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.Thumbprint -eq "${{ vars.CODE_SIGNING_THUMBPRINT }}" }) -TimestampServer "http://timestamp.digicert.com" + dotnet wix burn reattach Tgstation.Server.Host.Service.Wix.Bundle/bin/Release/tgstation-server-installer.exe -engine burnengine.exe -o test-installer.exe + Set-AuthenticodeSignature test-installer.exe -Certificate (Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.Thumbprint -eq "${{ vars.CODE_SIGNING_THUMBPRINT }}" }) -TimestampServer "http://timestamp.digicert.com" - name: Test Install # Sanity checks the .deps.json exists, which the installation is broken without shell: powershell # If it's missing, I found that in elements were the problem run: | mkdir C:/ProgramData/tgstation-server cp build/package/appsettings.GitHub.yml C:/ProgramData/tgstation-server/appsettings.Production.yml - $file = [System.IO.Path]::GetFullPath("test-installer.exe") + $file = [System.IO.Path]::GetFullPath("build/package/winget/test-installer.exe") $log = [System.IO.Path]::GetFullPath("install.log") $procMain = Start-Process -FilePath $file "/install /silent /log `"$log`"" -NoNewWindow -PassThru -Wait if (Test-Path -Path $log -PathType Leaf) { @@ -1077,7 +1097,7 @@ jobs: - name: Test Uninstall # Sanity checks the .deps.json exists, which the installation is broken without shell: powershell run: | - $file = [System.IO.Path]::GetFullPath("test-installer.exe") + $file = [System.IO.Path]::GetFullPath("build/package/winget/test-installer.exe") $log = [System.IO.Path]::GetFullPath("uninstall.log") $procMain = Start-Process -FilePath $file "/uninstall /silent /log `"$log`"" -NoNewWindow -PassThru -Wait if (Test-Path -Path $log -PathType Leaf) { @@ -1097,7 +1117,7 @@ jobs: - name: Upload Unsigned Installer .exe uses: actions/upload-artifact@v3 with: - name: packaging-windows + name: packaging-preview-windows path: build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/bin/Release/tgstation-server-installer.exe check-winget-pr-template: @@ -1317,9 +1337,33 @@ jobs: - name: Restore run: dotnet restore + - name: Restore Wix dotnet Tool + run: | + cd build/package/winget + dotnet tool restore + - name: Build ReleaseNotes run: dotnet build -c Release tools/ReleaseNotes/ReleaseNotes.csproj +# We need to rebuild the installer.exe so it can be properly signed + - name: Restore + run: dotnet restore + + - name: Build Host + run: dotnet build -c Release src/Tgstation.Server.Host/Tgstation.Server.Host.csproj + + - name: Build Service + run: dotnet build -c Release src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj + + - name: Prepare Artifacts + shell: powershell + run: build/package/winget/prepare_installer_input_artifacts.ps1 + + - name: Build Installer .exe + run: | + cd build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle + dotnet build -c Release + - name: Parse TGS version shell: powershell run: | @@ -1357,21 +1401,27 @@ jobs: name: packaging-debian path: packaging-debian - - name: Retrieve Installer .exe - uses: actions/download-artifact@v3 - with: - name: packaging-windows - path: packaging-windows - - - name: Sign Installer .exe + - name: Install Code Signing Certificate shell: powershell run: | $pfxBytes = [convert]::FromBase64String("${{ secrets.CODE_SIGNING_BASE64 }}") [IO.File]::WriteAllBytes("tg_codesigning.pfx", $pfxBytes) $certPassword = ConvertTo-SecureString -String "${{ secrets.CODE_SIGNING_PASSWORD }}" -Force -AsPlainText - $cert=Import-PfxCertificate -FilePath tg_codesigning.pfx -Cert Cert:\CurrentUser\My -Password $certPassword + Import-PfxCertificate -FilePath tg_codesigning.pfx -Cert Cert:\CurrentUser\My -Password $certPassword rm tg_codesigning.pfx - Set-AuthenticodeSignature packaging-windows/tgstation-server-installer.exe -Certificate $cert -TimestampServer "http://timestamp.digicert.com" + + - name: Sign Installer .exe # https://wixtoolset.org/docs/tools/signing/ + shell: powershell + run: | + cd build/package/winget + dotnet wix burn detach Tgstation.Server.Host.Service.Wix.Bundle/bin/Release/tgstation-server-installer.exe -engine burnengine.exe + Set-AuthenticodeSignature burnengine.exe -Certificate (Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.Thumbprint -eq "${{ vars.CODE_SIGNING_THUMBPRINT }}" }) -TimestampServer "http://timestamp.digicert.com" + dotnet wix burn reattach Tgstation.Server.Host.Service.Wix.Bundle/bin/Release/tgstation-server-installer.exe -engine burnengine.exe -o tgstation-server-installer.exe + Set-AuthenticodeSignature tgstation-server-installer.exe -Certificate (Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.Thumbprint -eq "${{ vars.CODE_SIGNING_THUMBPRINT }}" }) -TimestampServer "http://timestamp.digicert.com" + + - name: Sign Service .exe + shell: powershell + run: Set-AuthenticodeSignature ServerService/Tgstation.Server.Host.Service.exe -Certificate (Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.Thumbprint -eq "${{ vars.CODE_SIGNING_THUMBPRINT }}" }) -TimestampServer "http://timestamp.digicert.com" - name: Zip Artifacts shell: powershell @@ -1462,7 +1512,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./packaging-windows/tgstation-server-installer.exe + asset_path: ./build/package/winget/tgstation-server-installer.exe asset_name: tgstation-server-installer.exe asset_content_type: application/octet-stream diff --git a/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Tgstation.Server.Host.Service.Wix.Bundle.wixproj b/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Tgstation.Server.Host.Service.Wix.Bundle.wixproj index 209dd92a13..ab59841b93 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Tgstation.Server.Host.Service.Wix.Bundle.wixproj +++ b/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Tgstation.Server.Host.Service.Wix.Bundle.wixproj @@ -5,7 +5,20 @@ Bundle x86 tgstation-server-installer + + + + + + + + + + From cc06102a8b30ecf31250776866b555acdb549804 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 3 Jul 2023 13:26:05 -0400 Subject: [PATCH 149/160] Improve winget manifest installer info --- .../winget/manifest/Tgstation.Server.installer.yaml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/build/package/winget/manifest/Tgstation.Server.installer.yaml b/build/package/winget/manifest/Tgstation.Server.installer.yaml index a9a6689538..4afd9144f6 100644 --- a/build/package/winget/manifest/Tgstation.Server.installer.yaml +++ b/build/package/winget/manifest/Tgstation.Server.installer.yaml @@ -7,16 +7,13 @@ Installers: - InstallerUrl: https://github.com/tgstation/tgstation-server/releases/download/tgstation-server-v0.22.475/tgstation-server-installer.exe # Set before publish by push_manifest.ps1 InstallerLocale: en-US Architecture: x86 - InstallerType: exe + InstallerType: wix Scope: machine InstallerSha256: CF0D4D2FD042098D826A226A05A9DAA5C792318CF48FD334F7FC06AF6A8A23B1 # Set before publish by push_manifest.ps1 InstallModes: - interactive - silent - InstallerSwitches: - Silent: /silent - SilentWithProgress: /passive - Log: /log + - silentWithProgress ProductCode: '{D24887FA-3228-4509-B5F3-4E07E349F278}' UnsupportedOSArchitectures: - arm From 6202093be433eb4473c6b2c390d0efafa12b3d1e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 3 Jul 2023 14:11:03 -0400 Subject: [PATCH 150/160] We were hitting the GitHub API too fast here - Add a sleep to allow the PR to index --- .github/workflows/ci-pipeline.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index c08e4aa1ab..c60e85e07f 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1589,4 +1589,7 @@ jobs: run: build/package/winget/push_manifest.ps1 - name: Run ReleaseNotes with --link-winget - run: dotnet run -c Release --no-build --project tools/ReleaseNotes --link-winget ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + shell: powershell + run: | + Sleep 15 + dotnet run -c Release --no-build --project tools/ReleaseNotes --link-winget ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} From 65fee617bb35f04b87c1a9c1e05ac06155a9834d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 3 Jul 2023 14:17:02 -0400 Subject: [PATCH 151/160] Rename the CI gates a bit --- .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 c60e85e07f..07b19f07b5 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -70,7 +70,7 @@ jobs: run: exit 1 start-ci-run-gate: - name: Start CI Run Gate + name: CI Start Gate needs: security-checkpoint runs-on: ubuntu-latest if: "!(cancelled() || failure()) && (needs.security-checkpoint.result == 'success' || (needs.security-checkpoint.result == 'skipped' && (github.event_name == 'push' || github.event_name == 'schedule' || (github.event.pull_request.head.repo.id == github.event.pull_request.base.repo.id && github.event_name != 'pull_request_target'))))" @@ -1166,7 +1166,7 @@ jobs: run: exit 0 deployment-gate: - name: Deployment Gate + name: Deployment Start Gate needs: ci-completion-gate runs-on: ubuntu-latest if: "!(cancelled() || failure()) && needs.ci-completion-gate.result == 'success' && github.event_name == 'push'" From bc4321ac9d80299da158ef754884305e9c4c06f6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 3 Jul 2023 15:35:06 -0400 Subject: [PATCH 152/160] Fix Linux tests --- src/Tgstation.Server.Host/Components/InstanceManager.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index bd0c687e20..706950db1b 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -477,7 +477,8 @@ namespace Tgstation.Server.Host.Components } finally { - console.Title = originalConsoleTitle; + if (originalConsoleTitle != null) + console.Title = originalConsoleTitle; } } catch (Exception ex) From 2aada2892d9ecda0e3c326bd4010584818760deb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 3 Jul 2023 16:03:18 -0400 Subject: [PATCH 153/160] Cleanup winget manifests + Fix attempts - Specify `burn` for `InstallerType` rather than `wix`. - Check for .NET core runtime, since it is actually required. I think this is biting us in the ass for `winget` validation. --- .../Bundle.wxs | 5 ++++- .../winget/manifest/Tgstation.Server.installer.yaml | 10 +++++----- .../winget/manifest/Tgstation.Server.locale.en-US.yaml | 4 ++-- build/package/winget/manifest/Tgstation.Server.yaml | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Bundle.wxs b/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Bundle.wxs index a6d7135340..62a558e1f1 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Bundle.wxs +++ b/build/package/winget/Tgstation.Server.Host.Service.Wix.Bundle/Bundle.wxs @@ -6,8 +6,11 @@ + + + - + diff --git a/build/package/winget/manifest/Tgstation.Server.installer.yaml b/build/package/winget/manifest/Tgstation.Server.installer.yaml index 4afd9144f6..89c60fcab2 100644 --- a/build/package/winget/manifest/Tgstation.Server.installer.yaml +++ b/build/package/winget/manifest/Tgstation.Server.installer.yaml @@ -2,14 +2,14 @@ # yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.4.0.schema.json PackageIdentifier: Tgstation.Server -PackageVersion: 0.22.475 # Set before publish by push_manifest.ps1 +PackageVersion: 0.22.475 # Do not change. Set before publish by push_manifest.ps1 Installers: -- InstallerUrl: https://github.com/tgstation/tgstation-server/releases/download/tgstation-server-v0.22.475/tgstation-server-installer.exe # Set before publish by push_manifest.ps1 +- InstallerUrl: https://github.com/tgstation/tgstation-server/releases/download/tgstation-server-v0.22.475/tgstation-server-installer.exe # Do not change. Set before publish by push_manifest.ps1 InstallerLocale: en-US Architecture: x86 - InstallerType: wix + InstallerType: burn Scope: machine - InstallerSha256: CF0D4D2FD042098D826A226A05A9DAA5C792318CF48FD334F7FC06AF6A8A23B1 # Set before publish by push_manifest.ps1 + InstallerSha256: CF0D4D2FD042098D826A226A05A9DAA5C792318CF48FD334F7FC06AF6A8A23B1 # Do not change. Set before publish by push_manifest.ps1 InstallModes: - interactive - silent @@ -22,6 +22,6 @@ Installers: Dependencies: PackageDependencies: - PackageIdentifier: Microsoft.DotNet.AspNetCore.6 - ReleaseDate: 2023-06-24 + ReleaseDate: 2023-06-24 # Do not change. Set before publish by push_manifest.ps1 ManifestType: installer ManifestVersion: 1.4.0 diff --git a/build/package/winget/manifest/Tgstation.Server.locale.en-US.yaml b/build/package/winget/manifest/Tgstation.Server.locale.en-US.yaml index 67b00590d8..e4a446ca75 100644 --- a/build/package/winget/manifest/Tgstation.Server.locale.en-US.yaml +++ b/build/package/winget/manifest/Tgstation.Server.locale.en-US.yaml @@ -2,7 +2,7 @@ # yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.4.0.schema.json PackageIdentifier: Tgstation.Server -PackageVersion: 0.22.475 # Set before publish by push_manifest.ps1 +PackageVersion: 0.22.475 # Do not change. Set before publish by push_manifest.ps1 PackageLocale: en-US Publisher: /tg/station 13 PublisherUrl: https://github.com/tgstation/tgstation-server @@ -14,7 +14,7 @@ ShortDescription: A production scale tool for BYOND server management Moniker: tgstation-server Documentations: - DocumentLabel: README.md - DocumentUrl: https://github.com/tgstation/tgstation-server/blob/tgstation-server-v0.22.475/README.md + DocumentUrl: https://github.com/tgstation/tgstation-server/blob/tgstation-server-v0.22.475/README.md # Do not change. Set before publish by push_manifest.ps1 ReleaseNotesUrl: https://github.com/tgstation/tgstation-server/releases/tag/tgstation-server-v0.22.475 PurchaseUrl: https://github.com/sponsors/Cyberboss ManifestType: defaultLocale diff --git a/build/package/winget/manifest/Tgstation.Server.yaml b/build/package/winget/manifest/Tgstation.Server.yaml index c23541ad90..7b7d3b8eba 100644 --- a/build/package/winget/manifest/Tgstation.Server.yaml +++ b/build/package/winget/manifest/Tgstation.Server.yaml @@ -2,7 +2,7 @@ # yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.4.0.schema.json PackageIdentifier: Tgstation.Server -PackageVersion: 0.22.475 # Set before publish by push_manifest.ps1 +PackageVersion: 0.22.475 # Do not change. Set before publish by push_manifest.ps1 DefaultLocale: en-US ManifestType: version ManifestVersion: 1.4.0 From 0867219858729e67babfa1586e15991cb4277d23 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 3 Jul 2023 16:46:24 -0400 Subject: [PATCH 154/160] Improve `dotnet.exe` path searching on Windows --- src/Tgstation.Server.Host.Watchdog/Watchdog.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs index a2bd4e7420..8128ebeed5 100644 --- a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs @@ -369,7 +369,11 @@ namespace Tgstation.Server.Host.Watchdog if (isWindows) { exeName += ".exe"; - enumerator = paths; + enumerator = new List(paths) + { + "C:/Program Files/dotnet", + "C:/Program Files (x86)/dotnet", + }; } else enumerator = paths.Select(x => x.Split(':')).SelectMany(x => x); From e771a369afcedd3c9c9daabc4d2dd86b05bac648 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 3 Jul 2023 17:02:58 -0400 Subject: [PATCH 155/160] Do not StartServices if TGS is unconfigured - Cheeky workaround to pass winget validation --- README.md | 6 +++++- .../winget/Tgstation.Server.Host.Service.Wix/Package.wxs | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 26e6c7460f..d8ae528d61 100644 --- a/README.md +++ b/README.md @@ -71,9 +71,13 @@ Once winget is installed, simply run the following commands, accepting any promp winget install tgstation-server ``` +Note: If you use the `-h` or `--disable-interactivity` winget arguments, you will need to either pre-configure TGS or configure and start the `tgstation-server` service after installing. A shortcut will be placed on your desktop and in your start menu to assist with this. + ##### Installer -[Download the latest release's tgstation-server-installer.exe](https://github.com/tgstation/tgstation-server/releases/latest). Executing it will take you through the process of installing and configuring your server. +[Download the latest release's tgstation-server-installer.exe](https://github.com/tgstation/tgstation-server/releases/latest). Executing it will take you through the process of installing and configuring your server. The required dotnet runtime may be installed as a pre-requisite. + +Note: If you use the `/silent` or `/passive` arguments to the installer, you will need to either pre-configure TGS or configure and start the `tgstation-server` service after installing. A shortcut will be placed on your desktop and in your start menu to assist with this. ##### Manual diff --git a/build/package/winget/Tgstation.Server.Host.Service.Wix/Package.wxs b/build/package/winget/Tgstation.Server.Host.Service.Wix/Package.wxs index 773225386a..e136a27cd9 100644 --- a/build/package/winget/Tgstation.Server.Host.Service.Wix/Package.wxs +++ b/build/package/winget/Tgstation.Server.Host.Service.Wix/Package.wxs @@ -16,6 +16,7 @@ + From a1fde52d73c5b3e5e3115778cd907c30d5a9baa1 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 3 Jul 2023 17:14:21 -0400 Subject: [PATCH 156/160] Note about dotnet pre-requisite for `winget` --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d8ae528d61..4d4221493d 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,8 @@ Once winget is installed, simply run the following commands, accepting any promp winget install tgstation-server ``` +The required dotnet runtime may be installed as a pre-requisite. + Note: If you use the `-h` or `--disable-interactivity` winget arguments, you will need to either pre-configure TGS or configure and start the `tgstation-server` service after installing. A shortcut will be placed on your desktop and in your start menu to assist with this. ##### Installer From a6c773300b08eab91dd7a6dbf46459807a1d5427 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 3 Jul 2023 17:16:24 -0400 Subject: [PATCH 157/160] More dotnet search paths for Linux --- src/Tgstation.Server.Host.Watchdog/Watchdog.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs index 8128ebeed5..fc86f1f271 100644 --- a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs @@ -376,7 +376,15 @@ namespace Tgstation.Server.Host.Watchdog }; } else - enumerator = paths.Select(x => x.Split(':')).SelectMany(x => x); + enumerator = paths + .Select(x => x.Split(':')) + .SelectMany(x => x) + .Concat(new List(2) + { + "/usr/bin", + "/usr/share/bin", + "/usr/local/share/dotnet", + }); enumerator = enumerator.Select(x => Path.Combine(x, exeName)); From 7350fbfff28fee9caeae0f5146df87a62b55c058 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 3 Jul 2023 17:20:37 -0400 Subject: [PATCH 158/160] Add `AppsAndFeaturesEntries` to installer manifest --- build/package/winget/manifest/Tgstation.Server.installer.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/package/winget/manifest/Tgstation.Server.installer.yaml b/build/package/winget/manifest/Tgstation.Server.installer.yaml index 89c60fcab2..fc2aa030bb 100644 --- a/build/package/winget/manifest/Tgstation.Server.installer.yaml +++ b/build/package/winget/manifest/Tgstation.Server.installer.yaml @@ -19,6 +19,10 @@ Installers: - arm - arm64 ElevationRequirement: elevatesSelf + AppsAndFeaturesEntries: + - DisplayName: tgstation-server + DisplayVersion: 0.22.475 # Do not change. Set before publish by push_manifest.ps1 + Publisher: /tg/station 13 Dependencies: PackageDependencies: - PackageIdentifier: Microsoft.DotNet.AspNetCore.6 From f7bc1e490170f77b9fc7e5c4261973acb4f0f181 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 3 Jul 2023 17:39:43 -0400 Subject: [PATCH 159/160] Note about the root CA @Cyberboss runs --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 4d4221493d..b971d086e2 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,10 @@ Follow the instructions for your OS below. #### Windows +###### Note about Digital Signatures + +Note that the Windows Service and installer executables requires administrative privileges. These are digitally signed against the Root CA managed by [Jordan Dominion](https://github.com/Cyberboss). Consider installing the certificate into your `Trusted Root Authorities` store for cleaner UAC prompts. The certificate can be downloaded [here](https://file.house/zpFb.cer), please validate the thumbprint is `70176acf7ffa2898fa5b5cd6e38b43b38ea5d07f` before installing. + ##### winget (Windows 10 or later) [winget](https://github.com/microsoft/winget-cli) installed is the easiest way to install the latest version of tgstation-server (provided Microsoft has approved the most recent package manifest). From a00ef986556cfb91dfa91845cd829c1cfecff83d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 3 Jul 2023 17:58:32 -0400 Subject: [PATCH 160/160] Standardize AGPL-3.0 reference --- build/package/deb/debian/copyright | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package/deb/debian/copyright b/build/package/deb/debian/copyright index 31b11fc83b..5c4e3b7bcb 100644 --- a/build/package/deb/debian/copyright +++ b/build/package/deb/debian/copyright @@ -7,4 +7,4 @@ Files: * Copyright: 2023 Jordan Dominion -License: AGPL-3 +License: AGPL-3.0