diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a096c248c4..b322d8425b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -39,14 +39,14 @@ You need the Dotnet 3.1 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. In order to run the integration tests you must have the following environment variables set: -- `TGS4_TEST_DATABASE_TYPE`: `MySql`, `MariaDB`, `PostgresSql`, or `SqlServer`. -- `TGS4_TEST_CONNECTION_STRING`: To a valid database connection string. You can use the setup wizard to create one. -- `TSG4_TEST_DISCORD_TOKEN`: To a valid discord bot token. -- `TGS4_TEST_DISCORD_CHANNEL`: To a valid discord channel ID that the above bot can access. -- `TGS4_TEST_IRC_CONNECTION_STRING`: To a valid TGS4 IRC connection string. See the code for [IrcConnectionStringBuilder](../src/Tgstation.Server.Api/Models/IrcConnectionStringBuilder.cs) for details. -- `TGS4_TEST_IRC_CHANNEL`: To a valid IRC channel accessible with the above connection. -- `TGS4_TEST_BRANCH`: Should be either `dev` or `master` depending on what you are working off of. Used for repository tests. -- (Optional) `TGS4_TEST_GITHUB_TOKEN`: A GitHub personal access token with no scopes used to bypass rate limits. +- `TGS_TEST_DATABASE_TYPE`: `MySql`, `MariaDB`, `PostgresSql`, or `SqlServer`. +- `TGS_TEST_CONNECTION_STRING`: To a valid database connection string. You can use the setup wizard to create one. +- `TSG_TEST_DISCORD_TOKEN`: To a valid discord bot token. +- `TGS_TEST_DISCORD_CHANNEL`: To a valid discord channel ID that the above bot can access. +- `TGS_TEST_IRC_CONNECTION_STRING`: To a valid IRC connection string. See the code for [IrcConnectionStringBuilder](../src/Tgstation.Server.Api/Models/IrcConnectionStringBuilder.cs) for details. +- `TGS_TEST_IRC_CHANNEL`: To a valid IRC channel accessible with the above connection. +- `TGS_TEST_BRANCH`: Should be either `dev` or `master` depending on what you are working off of. Used for repository tests. +- (Optional) `TGS_TEST_GITHUB_TOKEN`: A GitHub personal access token with no scopes used to bypass rate limits. ### Know your Code @@ -240,9 +240,9 @@ The NuGet package Tgstation.Server.Client is another part of the suite which sho _This section mainly applies to people with write access to the repository. Anyone is free to propose their work and maintainers will triage it appropriately._ -When issues affecting the server come in, they should be lebeled appropriately and either put into the `V4 Backlog` milestone or current patch milestone depending on if it's a feature request or bug. +When issues affecting the server come in, they should be lebeled appropriately and either put into the `Backlog` milestone or current patch milestone depending on if it's a feature request or bug. -After a minor release, the team should decide at that time what will go into it and setup the milestone accordingly. At this point the `Backlog` label should be removed and replaced with `Ready` and the milestone changed from `V4 Backlog` to `v4.X.0` with X being the minor release version. +After a minor release, the team should decide at that time what will go into it and setup the milestone accordingly. At this point the `Backlog` label should be removed and replaced with `Ready` and the milestone changed from `Backlog` to `vX.Y.0` with X/Y being the major/minor release versions respectively. Assign work before beginning on it. When work is started, replace the `Ready` label with the `Work In Progress` label. diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index 7d4dcaaf04..63a9677b57 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -1,4 +1,4 @@ -name: 'CI' +name: 'CI' on: push: @@ -11,13 +11,13 @@ on: - master env: - TGS4_DOTNET_VERSION: 3.1.x - TGS4_TEST_DISCORD_CHANNEL: ${{ secrets.DISCORD_CHANNEL_ID }} - TGS4_TEST_DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} - TGS4_TEST_IRC_CHANNEL: ${{ secrets.IRC_CHANNEL }} - TGS4_TEST_IRC_CONNECTION_STRING: ${{ secrets.IRC_CONNECTION_STRING }} - TGS4_TEST_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TGS4_RELEASE_NOTES_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} + TGS_DOTNET_VERSION: 3.1.x + TGS_TEST_DISCORD_CHANNEL: ${{ secrets.DISCORD_CHANNEL_ID }} + TGS_TEST_DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} + TGS_TEST_IRC_CHANNEL: ${{ secrets.IRC_CHANNEL }} + TGS_TEST_IRC_CONNECTION_STRING: ${{ secrets.IRC_CONNECTION_STRING }} + TGS_TEST_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TGS_RELEASE_NOTES_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} jobs: dmapi-build: @@ -134,7 +134,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v1 with: - dotnet-version: ${{ env.TGS4_DOTNET_VERSION }} + dotnet-version: ${{ env.TGS_DOTNET_VERSION }} - name: Checkout uses: actions/checkout@v1 @@ -161,7 +161,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v1 with: - dotnet-version: ${{ env.TGS4_DOTNET_VERSION }} + dotnet-version: ${{ env.TGS_DOTNET_VERSION }} - name: Checkout uses: actions/checkout@v1 @@ -185,8 +185,8 @@ jobs: name: Windows Integration Test needs: dmapi-build env: - TGS4_TEST_DATABASE_TYPE: SqlServer - TGS4_TEST_DUMP_API_SPEC: yes + TGS_TEST_DATABASE_TYPE: SqlServer + TGS_TEST_DUMP_API_SPEC: yes concurrency: integration-windows-${{ github.head_ref }} strategy: max-parallel: 2 @@ -198,35 +198,35 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v1 with: - dotnet-version: ${{ env.TGS4_DOTNET_VERSION }} + dotnet-version: ${{ env.TGS_DOTNET_VERSION }} - name: Set General__UseBasicWatchdog if: ${{ matrix.watchdog-type == 'Basic' }} run: echo "General__UseBasicWatchdog=true" >> $Env:GITHUB_ENV - - name: Set TGS4_TEST_CONNECTION_STRING + - name: Set TGS_TEST_CONNECTION_STRING shell: bash run: | - TGS4_CONNSTRING_VALUE="Server=(localdb)\MSSQLLocalDB;Integrated Security=true;Initial Catalog=TGS_${{ matrix.watchdog-type }}_${{ matrix.configuration }};Application Name=tgstation-server" - echo "TGS4_TEST_CONNECTION_STRING=$(echo $TGS4_CONNSTRING_VALUE)" >> $GITHUB_ENV + TGS_CONNSTRING_VALUE="Server=(localdb)\MSSQLLocalDB;Integrated Security=true;Initial Catalog=TGS_${{ matrix.watchdog-type }}_${{ matrix.configuration }};Application Name=tgstation-server" + echo "TGS_TEST_CONNECTION_STRING=$(echo $TGS_CONNSTRING_VALUE)" >> $GITHUB_ENV - name: Checkout uses: actions/checkout@v1 - - name: Set TGS4_TEST_PULL_REQUEST_NUMBER + - name: Set TGS_TEST_PULL_REQUEST_NUMBER if: ${{ github.event_name == 'pull_request' }} - run: echo "TGS4_TEST_PULL_REQUEST_NUMBER=${{ github.event.number }}" >> $Env:GITHUB_ENV + run: echo "TGS_TEST_PULL_REQUEST_NUMBER=${{ github.event.number }}" >> $Env:GITHUB_ENV - - name: Set TGS4_GITHUB_REF for PR + - name: Set TGS_GITHUB_REF for PR if: ${{ github.event_name == 'pull_request' }} - run: echo "TGS4_GITHUB_REF=${{ github.base_ref }}" >> $Env:GITHUB_ENV + run: echo "TGS_GITHUB_REF=${{ github.base_ref }}" >> $Env:GITHUB_ENV - - name: Set TGS4_GITHUB_REF for push + - name: Set TGS_GITHUB_REF for push if: ${{ github.event_name == 'push' }} shell: bash run: | TEMP_GITHUB_REF="${{ github.event.ref }}" - echo "TGS4_GITHUB_REF=${TEMP_GITHUB_REF##*/}" >> $GITHUB_ENV + echo "TGS_GITHUB_REF=${TEMP_GITHUB_REF##*/}" >> $GITHUB_ENV - name: Clean package cache as a temporary workaround for actions/setup-dotnet#155 run: dotnet clean && dotnet nuget locals all --clear @@ -329,31 +329,31 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v1 with: - dotnet-version: ${{ env.TGS4_DOTNET_VERSION }} + dotnet-version: ${{ env.TGS_DOTNET_VERSION }} - name: Set Sqlite Connection Info if: ${{ matrix.database-type == 'Sqlite' }} run: | - echo "TGS4_TEST_DATABASE_TYPE=Sqlite" >> $GITHUB_ENV - echo "TGS4_TEST_CONNECTION_STRING=Data Source=TGS_${{ matrix.watchdog-type }}_${{ matrix.configuration }}.sqlite3;Mode=ReadWriteCreate" >> $GITHUB_ENV + echo "TGS_TEST_DATABASE_TYPE=Sqlite" >> $GITHUB_ENV + echo "TGS_TEST_CONNECTION_STRING=Data Source=TGS_${{ matrix.watchdog-type }}_${{ matrix.configuration }}.sqlite3;Mode=ReadWriteCreate" >> $GITHUB_ENV - name: Set PostgresSql Connection Info if: ${{ matrix.database-type == 'PostgresSql' }} run: | - echo "TGS4_TEST_DATABASE_TYPE=PostgresSql" >> $GITHUB_ENV - echo "TGS4_TEST_CONNECTION_STRING=Application Name=tgstation-server;Host=127.0.0.1;Username=postgres;Password=postgres;Database=TGS__${{ matrix.watchdog-type }}_${{ matrix.configuration }}" >> $GITHUB_ENV + echo "TGS_TEST_DATABASE_TYPE=PostgresSql" >> $GITHUB_ENV + echo "TGS_TEST_CONNECTION_STRING=Application Name=tgstation-server;Host=127.0.0.1;Username=postgres;Password=postgres;Database=TGS__${{ matrix.watchdog-type }}_${{ matrix.configuration }}" >> $GITHUB_ENV - name: Set MariaDB Connection Info if: ${{ matrix.database-type == 'MariaDB' }} run: | - echo "TGS4_TEST_DATABASE_TYPE=MariaDB" >> $GITHUB_ENV - echo "TGS4_TEST_CONNECTION_STRING=Server=127.0.0.1;uid=root;pwd=mariadb;database=tgs__${{ matrix.watchdog-type }}_${{ matrix.configuration }}" >> $GITHUB_ENV + echo "TGS_TEST_DATABASE_TYPE=MariaDB" >> $GITHUB_ENV + echo "TGS_TEST_CONNECTION_STRING=Server=127.0.0.1;uid=root;pwd=mariadb;database=tgs__${{ matrix.watchdog-type }}_${{ matrix.configuration }}" >> $GITHUB_ENV - name: Set MySQL Connection Info if: ${{ matrix.database-type == 'MySql' }} run: | - echo "TGS4_TEST_DATABASE_TYPE=MySql" >> $GITHUB_ENV - echo "TGS4_TEST_CONNECTION_STRING=Server=127.0.0.1;Port=3307;uid=root;pwd=mysql;database=tgs__${{ matrix.watchdog-type }}_${{ matrix.configuration }}" >> $GITHUB_ENV + echo "TGS_TEST_DATABASE_TYPE=MySql" >> $GITHUB_ENV + echo "TGS_TEST_CONNECTION_STRING=Server=127.0.0.1;Port=3307;uid=root;pwd=mysql;database=tgs__${{ matrix.watchdog-type }}_${{ matrix.configuration }}" >> $GITHUB_ENV echo "Database__ServerVersion=5.7.31" >> $GITHUB_ENV - name: Set General__UseBasicWatchdog @@ -363,20 +363,20 @@ jobs: - name: Checkout uses: actions/checkout@v1 - - name: Set TGS4_TEST_PULL_REQUEST_NUMBER + - name: Set TGS_TEST_PULL_REQUEST_NUMBER if: ${{ github.event_name == 'pull_request' }} - run: echo "TGS4_TEST_PULL_REQUEST_NUMBER=${{ github.event.number }}" >> $GITHUB_ENV + run: echo "TGS_TEST_PULL_REQUEST_NUMBER=${{ github.event.number }}" >> $GITHUB_ENV - - name: Set TGS4_GITHUB_REF for PR + - name: Set TGS_GITHUB_REF for PR if: ${{ github.event_name == 'pull_request' }} - run: echo "TGS4_GITHUB_REF=${{ github.base_ref }}" >> $GITHUB_ENV + run: echo "TGS_GITHUB_REF=${{ github.base_ref }}" >> $GITHUB_ENV - - name: Set TGS4_GITHUB_REF for push + - name: Set TGS_GITHUB_REF for push if: ${{ github.event_name == 'push' }} shell: bash run: | TEMP_GITHUB_REF="${{ github.event.ref }}" - echo "TGS4_GITHUB_REF=${TEMP_GITHUB_REF##*/}" >> $GITHUB_ENV + echo "TGS_GITHUB_REF=${TEMP_GITHUB_REF##*/}" >> $GITHUB_ENV - name: Run Integration Test run: | @@ -658,7 +658,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v1 with: - dotnet-version: ${{ env.TGS4_DOTNET_VERSION }} + dotnet-version: ${{ env.TGS_DOTNET_VERSION }} - name: Checkout uses: actions/checkout@v1 diff --git a/.github/workflows/v5-merge.yml b/.github/workflows/v5-merge.yml new file mode 100644 index 0000000000..79227ffe94 --- /dev/null +++ b/.github/workflows/v5-merge.yml @@ -0,0 +1,28 @@ +name: 'V5 Merge' + +on: + push: + branches: + - dev + +jobs: + master-merge: + + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v1 + + - name: Merge dev into V5 + uses: robotology/gh-action-nightly-merge@v1.2.0 + with: + stable_branch: 'dev' + development_branch: 'V5' + allow_ff: true + user_name: tgstation-server + user_email: tgstation-server@users.noreply.github.com + push_token: DEV_PUSH_TOKEN + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DEV_PUSH_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} diff --git a/README.md b/README.md index 3d1d94fafe..91f5ec9a98 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# tgstation-server v4: +# tgstation-server: ![CI](https://github.com/tgstation/tgstation-server/workflows/CI/badge.svg) [![codecov](https://codecov.io/gh/tgstation/tgstation-server/branch/master/graph/badge.svg)](https://codecov.io/gh/tgstation/tgstation-server) @@ -12,7 +12,7 @@ This is a toolset to manage production BYOND servers. It includes the ability to ### Legacy Servers -Older server versions can be found in the V# branches of this repository. Note that V4 is nearly fully incompatible with existing installations. Only some static files may be copied over: https://github.com/tgstation/tgstation-server#static-files +Older server versions can be found in the V# branches of this repository. Note that the current server fully incompatible with installations before version 4. Only some static files may be copied over: https://github.com/tgstation/tgstation-server#static-files ## Setup @@ -23,7 +23,7 @@ Older server versions can be found in the V# branches of this repository. Note t ### Installation -1. [Download the latest V4 release .zip](https://github.com/tgstation/tgstation-server/releases/latest). The `ServerService` package will only work on Windows. Choose `ServerConsole` if that is not your target OS or you prefer not to use the Windows service. +1. [Download the latest release .zip](https://github.com/tgstation/tgstation-server/releases/latest). The `ServerService` package will only work on Windows. Choose `ServerConsole` if that is not your target OS or you prefer not to use the Windows service. 2. 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. #### Windows @@ -67,7 +67,7 @@ docker run \ -p 5000:5000 \ # Port bridge for accessing TGS, you can change this if you need -p 0.0.0.0:: \ # Port bridge for accessing DreamDaemon -v /path/to/your/configfile/directory:/config_data \ # Recommended, create a volume mapping for server configuration - -v /path/to/store/instances:/tgs4_instances \ # Recommended, create a volume mapping for server instances + -v /path/to/store/instances:/tgs_instances \ # Recommended, create a volume mapping for server instances -v /path/to/your/log/folder:/tgs_logs \ # Recommended, create a volume mapping for server logs tgstation/server[:] ``` @@ -79,7 +79,7 @@ Important note about port exposure: The internal port used by DreamDaemon _**MUS Note although `/app/lib` is specified as a volume mount point in the `Dockerfile`, unless you REALLY know what you're doing. Do not mount any volumes over this for fear of breaking your container. -The configuration option `General:ValidInstancePaths` will be preconfigured to point to `/tgs4_instances`. It is recommended you don't change this. +The configuration option `General:ValidInstancePaths` will be preconfigured to point to `/tgs_instances`. It is recommended you don't change this. Note that this container is meant to be long running. Updates are handled internally as opposed to at the container level. @@ -89,7 +89,7 @@ If using manual configuration, before starting your container make sure the afor ### Configuring -The first time you run TGS4 you should be prompted with a configuration wizard which will guide you through setting up your `appsettings.Production.yml` +The first time you run TGS you should be prompted with a configuration wizard which will guide you through setting up your `appsettings.Production.yml` This wizard will, generally, run whenever the server is launched without detecting the config yml. Follow the instructions below to perform this process manually. @@ -107,7 +107,7 @@ The latter two are not recommended as they cannot be dynamically changed at runt Create an `appsettings.Production.yml` file next to `appsettings.yml`. This will override the default settings in `appsettings.yml` with your production settings. There are a few keys meant to be changed by hosts. Modifying any config files while the server is running will trigger a safe restart (Keeps DreamDaemon instances running). Note these are all case-sensitive: -- `General:ConfigVersion`: Suppresses warnings about out of date config versions. You should change this after updating TGS to one with a new config version. The current version can be found on the releases page for your server version (This field did not exist before v4.4.0). +- `General:ConfigVersion`: Suppresses warnings about out of date config versions. You should change this after updating TGS to one with a new config version. The current version can be found on the releases page for your server version. - `General:MinimumPasswordLength`: Minimum password length requirement for database users @@ -137,7 +137,7 @@ Create an `appsettings.Production.yml` file next to `appsettings.yml`. This will - `ControlPanel:AllowedOrigins`: Set the Access-Control-Allow-Origin headers to this list of origins for all responses (also enables all headers and methods). This is overridden by `ControlPanel:AllowAnyOrigin` -- `Elasticsearch`: tgstation-server-v4 also supports automatically ingesting its logs to ElasticSearch. You can set this up in the setup wizard, or with the following configuration: +- `Elasticsearch`: tgstation-server also supports automatically ingesting its logs to ElasticSearch. You can set this up in the setup wizard, or with the following configuration: ```yml Elasticsearch: Enable: true @@ -204,6 +204,8 @@ For the console version press `Ctrl+C` or send a SIGQUIT to the ORIGINAL dotnet For the docker version run `docker stop ` +### Updating + ## Integrating tgstation-server 4 provides the DMAPI which can be be integrated into any BYOND codebase for heavily enhanced functionality. The integration process is a fairly simple set of code changes. @@ -260,7 +262,7 @@ var/global/client_count = 0 --global.client_count ``` -## Remote Access +### Remote Access tgstation-server is an [ASP.Net Core](https://docs.microsoft.com/en-us/aspnet/core/) app based on the Kestrel web server. This section is meant to serve as a general use case overview, but the entire Kestrel configuration can be modified to your liking with the configuration YAML. See [the official documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel) for details. @@ -270,7 +272,7 @@ System administrators will most likely have their own configuration plans, but h Once complete, test that your configuration worked by visiting your proxy site from a browser on a different computer. You should recieve a 401 Unauthorized response. -### IIS (Reccommended for Windows) +#### IIS (Reccommended for Windows) 1. Acquire an HTTPS certificate. The easiet free way for Windows is [win-acme](https://github.com/PKISharp/win-acme) (requires you to set up the website first) 2. Install the [Web Platform Installer](https://www.microsoft.com/web/downloads/platform.aspx) @@ -283,7 +285,7 @@ Once complete, test that your configuration worked by visiting your proxy site f 8. You may get a prompt about enabling proxy functionality. Click `OK` 9. In the window that appears set the `Inbound Rules` textbox to the URL of your tgstation-server i.e. `http://localhost:5000`. Ensure `Enable SSL Offloading` is checked, then click `OK` -### Caddy (Reccommended for Linux, or those unfamilar with configuring NGINX or Apache) +#### Caddy (Reccommended for Linux, or those unfamilar with configuring NGINX or Apache) 1. Setup a basic website configuration. Instructions on how to do so are out of scope. 2. In your Caddyfile, under a server entry, add the following (replace 8080 with the port TGS is hosted on): @@ -295,7 +297,7 @@ proxy /tgs localhost:8080 { See https://caddyserver.com/docs/proxy -### NGINX (Reccommended for Linux) +#### NGINX (Reccommended for Linux) 1. Setup a basic website configuration. Instructions on how to do so are out of scope. 2. Acquire an HTTPS certificate, likely via Let's Encrypt, and configure NGINX to use it. @@ -309,7 +311,7 @@ location /tgs { See https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/ -### Apache +#### Apache 1. Ensure the `mod_proxy` extension is installed. 2. Setup a basic website configuration. Instructions on how to do so are out of scope. @@ -338,13 +340,13 @@ Example VirtualHost Entry ``` -## Swarmed Servers +### Swarmed Servers Multiple tgstation-servers can be linked together in a swarm. The main benefit of this is allowing for users, groups, and permissions to be shared across the servers. Servers in a swarm must connect to the same database, use the same tgstation-server version, and have their own unique names. In a swarm, one server is designated the 'controller'. This is the server other 'node's in the swarm communicate with and coordinates group updates. Issuing an update command to one server in a swarm will update them all to the specified version. -### Swarm Server Instances +#### Swarm Server Instances Instances can be either part of a swarm or not. Once in the database they cannot switch between these states. In order to brin a non-swarmed instance into a swarmed server or vice-versa follow these steps. @@ -354,7 +356,17 @@ Instances can be either part of a swarm or not. Once in the database they cannot ## Usage -tgstation-server v4 is controlled via a RESTful HTTP json API. Documentation on this API can be found [here](https://tgstation.github.io/tgstation-server/api.html). This section serves to document the concepts of the server. The API is versioned separately from the release version. A specification for it can be found in the api-vX.X.X git releases/tags. +tgstation-server is controlled via a RESTful HTTP json API. Documentation on this API can be found [here](https://tgstation.github.io/tgstation-server/api.html). This section serves to document the concepts of the server. The API is versioned separately from the release version. A specification for it can be found in the api-vX.X.X git releases/tags. + +### Updating + +TGS can self update without stopping your DreamDaemon servers. Releases made to this repository are bound by a contract that allows changes of the runtime assemblies without stopping your servers. Database migrations are automatically applied as well. Because of this REVERTING TO LOWER VERSIONS IS NOT OFFICIALLY SUPPORTED, do so at your own risk (check changes made to `/src/Tgstation.Server.Host/Models/Migrations`). + +Major version updates may require additional action on the part of the user (apart from the configuration changes). + +#### Notifications + +If a server update is available, it will be indicated in the response from the GET /Administration endpoint. For more active notifications, you can subscribe to [this GitHub discussion](https://github.com/tgstation/tgstation-server/discussions/1322). ### Users @@ -434,13 +446,9 @@ This folder can contain anything. But, when certain events occur in the instance Any files and folders contained in this root level of this folder will be symbolically linked to all deployments at the time they are created. This allows persistent game data (BYOND `.sav`s or code configuration files for example) to persist across all deployments. This folder contains a .tgsignore file which can be used to prevent symlinks from being generated by entering the names of files and folders (1 per line) -### Updating - -TGS 4 can self update without stopping your DreamDaemon servers. Any V4 release made to this repository is bound by a contract that allows changes of the runtime assemblies without stopping your servers. Database migrations are automatically applied as well. Because of this REVERTING TO LOWER VERSIONS IS NOT OFFICIALLY SUPPORTED, do so at your own risk (check changes made to `/src/Tgstation.Server.Host/Models/Migrations`). - ### Clients -Here are tools for interacting with the TGS 4 web API +Here are tools for interacting with the TGS web API - [tgstation-server-webpanel](https://github.com/tgstation/tgstation-server-webpanel): Official client and included with the server (WIP). A react web app for using tgstation-server. - [Tgstation.Server.ControlPanel](https://github.com/tgstation/Tgstation.Server.ControlPanel): Official client. A cross platform GUI for using tgstation-server. Feature complete but lacks OAuth login options. diff --git a/SECURITY.md b/SECURITY.md index 7bf70fce52..c821acd452 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -13,6 +13,6 @@ Vulnerabilities should ideally be reported by directly messaging one of the main Here is a list of their discord IDs. -- Cyberboss#8246 +- Cyberboss#0016 Once reported, they will handle the processing of the security advisory. diff --git a/build/Dockerfile b/build/Dockerfile index 6a1d46b45d..507d8339c6 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -71,7 +71,7 @@ RUN apt-get update \ EXPOSE 5000 -ENV General__ValidInstancePaths__0 /tgs4_instances +ENV General__ValidInstancePaths__0 /tgs_instances ENV FileLogging__Directory /tgs_logs WORKDIR /app diff --git a/docs/API.dox b/docs/API.dox index 66f79a3174..bb0167c9d1 100644 --- a/docs/API.dox +++ b/docs/API.dox @@ -5,7 +5,7 @@ @section api_swag OpenAPI Spec -TGS4 has a, from code, generated OpenAPI 3.0 specification. It is much more authorative than these documents. +TGS has a, from code, generated OpenAPI 3.0 specification. It is much more authorative than these documents. The most up to date version should be found in the most recent appveyor build artifacts. It is also included in release artifacts. @@ -13,7 +13,7 @@ You can use the API explorer SwaggerUI to interact with it: https://petstore.swa @section api_intro Introduction -The TGS4 API is designed to be a fully realized RESTful service. Once hosted, follow the specified protocol for developing new clients or one off requests that provide full control over the server +The TGS API is designed to be a fully realized RESTful service. Once hosted, follow the specified protocol for developing new clients or one off requests that provide full control over the server Routes and their usages are defined as follows @@ -21,7 +21,7 @@ Routes and their usages are defined as follows @section api_lib Official Libraries -The TGS4 API's canonical definitions are provided as a .NET Standard library in the form of a nuget package located here: https://www.nuget.org/packages/Tgstation.Server.Api +The TGS API's canonical definitions are provided as a .NET Standard library in the form of a nuget package located here: https://www.nuget.org/packages/Tgstation.Server.Api An all inclusive TAP interface for using the API is also provided in this package: https://www.nuget.org/packages/Tgstation.Server.Client @@ -38,7 +38,7 @@ This document will reference the canonical C# models in the @ref Tgstation.Serve @section api_header Headers -TGS4 expects this set of headers. Failure to provide them will result in 400 error responses +TGS expects this set of headers. Failure to provide them will result in 400 error responses - User-Agent: The user agent product header value of the calling program - Api: Another product header value representing the version of the API to use. Currently this must be: Tgstation.Server.Api/4.0.0.0 @@ -124,7 +124,7 @@ Continue to use this token until you begin to recieve 401 responses from the API @subsection api_auth_o OAuth 2.0 -TGS4 supports OAuth 2.0 with select providers for authentication. +TGS supports OAuth 2.0 with select providers for authentication. The flow for this is as follows: diff --git a/docs/Architecture.dox b/docs/Architecture.dox index 6c5bdeea1d..136a3f27c2 100644 --- a/docs/Architecture.dox +++ b/docs/Architecture.dox @@ -7,7 +7,7 @@ @section arch_intro Introduction -This is meant to be a brief overview of the TGS4 architecture to give new coders direction on where to code and the curious some insight to their questions. Given that this document is seperate from the authorative code it may fall out of date. For clairity, please contact project maintainers. +This is meant to be a brief overview of the TGS architecture to give new coders direction on where to code and the curious some insight to their questions. Given that this document is seperate from the authorative code it may fall out of date. For clairity, please contact project maintainers. @section arch_hwatchdog Host Watchdog @@ -29,7 +29,7 @@ The @ref Tgstation.Server.Host.Core.Application class has two methods called by - Respond with 503 if the application is still starting or shutting down - Authenticate the JWT in Authentication header if present and run @ref Tgstation.Server.Host.Controllers.ApiController on success - Catch database exceptions and convert to 409 responses with the exception's @ref Tgstation.Server.Api.Models.ErrorMessage -- Check @ref Tgstation.Server.Host.Controllers for correct controller and run the action and use it's response. +- Check @ref Tgstation.Server.Host.Controllers for correct controller and run the action and use it's response. - If not properly authenticated beforehand and action has a @ref Tgstation.Server.Host.Controllers.TgsAuthorizeAttribute return 401 - If not properly authorized beforehand according to the parameters of the action's @ref Tgstation.Server.Host.Controllers.TgsAuthorizeAttribute (if present) return 403 - If requested action does not exist return 404 @@ -98,9 +98,9 @@ The compilation process is a distinct series of steps: 14. Symlink all `GameStaticFiles` to both the A and B directories 15. Commit the @ref Tgstation.Server.Host.Models.CompileJob to the database -If any of the above steps fail, the target directory is deleted and the deployment is considered a bust. If all went well, after the @ref Tgstation.Server.Host.Models.Job completes the new CompileJob is loaded into the instance's @ref Tgstation.Server.Host.Components.Deployment.IDmbFactory . +If any of the above steps fail, the target directory is deleted and the deployment is considered a bust. If all went well, after the @ref Tgstation.Server.Host.Models.Job completes the new CompileJob is loaded into the instance's @ref Tgstation.Server.Host.Components.Deployment.IDmbFactory . -The DmbFactory is where the @ref arch_watchdog gets the @ref Tgstation.Server.Host.Components.Deployment.IDmbProvider instances to run. Each CompileJob loaded into it is given a lock count. The latest CompileJob holds 1 lock and every DreamDaemon instance running that CompileJob holds another. Loading a new CompileJob releases the initial lock, and when all other locks are released the CompileJob's directory is deleted. Any directories in the `Game` folder not in use are also deleted when the Instance starts. +The DmbFactory is where the @ref arch_watchdog gets the @ref Tgstation.Server.Host.Components.Deployment.IDmbProvider instances to run. Each CompileJob loaded into it is given a lock count. The latest CompileJob holds 1 lock and every DreamDaemon instance running that CompileJob holds another. Loading a new CompileJob releases the initial lock, and when all other locks are released the CompileJob's directory is deleted. Any directories in the `Game` folder not in use are also deleted when the Instance starts. @section arch_chat Chat Bot System @@ -118,7 +118,7 @@ The @ref Tgstation.Server.Host.Components.StaticFiles.IConfiguration object is a @section arch_watchdog Watchdog -This is the core of tgstation-server, the component that starts, monitors, and updates DreamDaemon. +This is the core of tgstation-server, the component that starts, monitors, and updates DreamDaemon. At it's core, the watchdog operates using a hot/cold server setup. At any given moment there are two DreamDaemon instances running, only one of which players can see. If anything bad happens to that server, it is killed and the inactive server has its port changed to catch all the connections. If any changes need to be made to the configuration (port, security, compile job), the inactive server is killed and immediately relaunched with the new configuration. Whenever the active server reboots, the two servers change ports so as to minimize load times. @@ -128,9 +128,9 @@ That's a high level view of things, now let's get to the nitty gritty. @subsection arch_wd_launch Launch -First the most recent @ref Tgstation.Server.Host.Components.Deployment.IDmbProvider is retrieved from the @ref Tgstation.Server.Host.Components.Deployment.IDmbFactory twice, adding 2 locks. +First the most recent @ref Tgstation.Server.Host.Components.Deployment.IDmbProvider is retrieved from the @ref Tgstation.Server.Host.Components.Deployment.IDmbFactory twice, adding 2 locks. -This is used to launch a @ref Tgstation.Server.Host.Components.Watchdog.ISessionController via the watchdog's @ref Tgstation.Server.Host.Components.Watchdog.ISessionControllerFactory in the `A` directory of dmb providers @ref Tgstation.Server.Host.Models.CompileJob . This will be designated the `Alpha` server. +This is used to launch a @ref Tgstation.Server.Host.Components.Watchdog.ISessionController via the watchdog's @ref Tgstation.Server.Host.Components.Watchdog.ISessionControllerFactory in the `A` directory of dmb providers @ref Tgstation.Server.Host.Models.CompileJob . This will be designated the `Alpha` server. Whenever DreamDaemon is launched by any part of the watchdog, we try to elevate its process priority to the equivalent of Windows' `Above Normal` @@ -140,7 +140,7 @@ If the watchdog ever enters a failure state it can't recover from, it kills both @subsection arch_wd_monitor The Monitor -The monitor is responsible for handling every @ref Tgstation.Server.Host.Components.Watchdog.MonitorActivationReason . It sleeps until one of these things happen. If multiple things happen at once, they are processed in their order of declaration. +The monitor is responsible for handling every @ref Tgstation.Server.Host.Components.Watchdog.MonitorActivationReason . It sleeps until one of these things happen. If multiple things happen at once, they are processed in their order of declaration. The monitor maintains a @ref Tgstation.Server.Host.Components.Watchdog.MonitorState which helps it make descisions on how to handle activation reasons. The @ref Tgstation.Server.Host.Components.Watchdog.MonitorState.NextAction determines how multiple simultaneous events are handled in succession. diff --git a/docs/Features.dox b/docs/Features.dox index 02e37f1231..8958e28807 100644 --- a/docs/Features.dox +++ b/docs/Features.dox @@ -3,7 +3,7 @@ @tableofcontents -@section new_features New in V4 +@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. @@ -11,8 +11,8 @@ - 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**. -- Linux/Docker Support: TGS4 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: TGS4 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. +- 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. @@ -28,8 +28,9 @@ - Watchdog Heartbeats: 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... -- Self Upgrading: To upgrade TGS3 you needed to download and run the installer. This was pretty seamless, but it's now even better in V4 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. -- *Gasp* TESTING: TGS4 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... +- 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. +- *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 diff --git a/src/DMAPI/tgs/README.md b/src/DMAPI/tgs/README.md index 445cee41f5..6319028d81 100644 --- a/src/DMAPI/tgs/README.md +++ b/src/DMAPI/tgs/README.md @@ -7,7 +7,7 @@ This folder should be placed on it's own inside a codebase that wishes to use th - The other versioned folders contain code for the different DMAPI versions. - [v3210](./v3210) contains the final TGS3 API. - [v4](./v4) is the legacy DMAPI 4 (Used in TGS 4.0.X versions). - - [v5](./v5) is the current DMAPI version used by TGS4 >=4.1. + - [v5](./v5) is the current DMAPI version used by TGS >=4.1. - [LICENSE](./LICENSE) is the MIT license for the DMAPI. APIs communicate with TGS in two ways. All versions implement TGS -> DM communication using /world/Topic. DM -> TGS communication, called the bridge method, is different for each version. diff --git a/src/DMAPI/tgs/v5/api.dm b/src/DMAPI/tgs/v5/api.dm index 704ff873c0..572944ed40 100644 --- a/src/DMAPI/tgs/v5/api.dm +++ b/src/DMAPI/tgs/v5/api.dm @@ -269,7 +269,7 @@ if(!result) return - //okay so the standard TGS4 proceedure is: right before rebooting change the port to whatever was sent to us in the above json's data parameter + //okay so the standard TGS proceedure is: right before rebooting change the port to whatever was sent to us in the above json's data parameter var/port = result[DMAPI5_BRIDGE_RESPONSE_NEW_PORT] if(!isnum(port)) diff --git a/src/Tgstation.Server.Api/Models/ErrorCode.cs b/src/Tgstation.Server.Api/Models/ErrorCode.cs index 2b6b268cc5..f861b24cbb 100644 --- a/src/Tgstation.Server.Api/Models/ErrorCode.cs +++ b/src/Tgstation.Server.Api/Models/ErrorCode.cs @@ -48,7 +48,7 @@ namespace Tgstation.Server.Api.Models /// /// Generic database integrity failure. /// - [Description("The operation could not be performed as it would violate database integrity. Please retry the request, making sure to not duplicate field names with existing entities.")] + [Description("The operation could not be performed as it would violate database integrity. Please retry the request, making sure to not duplicate field names with existing entities!")] DatabaseIntegrityConflict, /// @@ -58,9 +58,9 @@ namespace Tgstation.Server.Api.Models MissingHostWatchdog, /// - /// Attempted to change to a suite other than TGS4. + /// Attempted to change to a major version less than 4. /// - [Description("Cannot update to a different tgstation-server suite version.")] + [Description("Cannot downgrade to tgstation-server major version <4!")] CannotChangeServerSuite, /// @@ -72,7 +72,7 @@ namespace Tgstation.Server.Api.Models /// /// A server update was requested while another was in progress. /// - [Description("A server update was requested while another was in progress")] + [Description("A server update was requested while another was in progress!")] ServerUpdateInProgress, /// diff --git a/src/Tgstation.Server.Host.Service/Program.cs b/src/Tgstation.Server.Host.Service/Program.cs index b21c71b5c5..15a0df1de3 100644 --- a/src/Tgstation.Server.Host.Service/Program.cs +++ b/src/Tgstation.Server.Host.Service/Program.cs @@ -124,8 +124,8 @@ namespace Tgstation.Server.Host.Service processInstaller.Account = ServiceAccount.LocalSystem; installer.Context = new InstallContext("tgs-4-install.log", new string[] { String.Format(CultureInfo.InvariantCulture, "/assemblypath={0}", Assembly.GetEntryAssembly().Location) }); - installer.Description = "/tg/station 13 server v4 running as a windows service"; - installer.DisplayName = "/tg/station server 4"; + installer.Description = "/tg/station 13 server running as a windows service"; + installer.DisplayName = "/tg/station server"; installer.DelayedAutoStart = true; installer.StartType = ServiceStartMode.Automatic; installer.ServicesDependedOn = new string[] { "Tcpip", "Dhcp", "Dnscache" }; diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs index 26b2386157..657fc57256 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs @@ -501,7 +501,10 @@ namespace Tgstation.Server.Host.Components.Chat : $"TGS: Updating to version {updateVersion}..."; List wdChannels; lock (mappedChannels) // so it doesn't change while we're using it - wdChannels = mappedChannels.Select(x => x.Key).ToList(); + wdChannels = mappedChannels + .Where(x => !x.Value.Channel.IsPrivateChannel) + .Select(x => x.Key) + .ToList(); return SendMessage(message, wdChannels, cancellationToken); } diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 160bdebd9c..e22aa9f605 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -374,9 +374,8 @@ namespace Tgstation.Server.Host.Components.Chat.Providers var fields = BuildUpdateEmbedFields(revisionInformation, byondVersion, gitHubOwner, gitHubRepo, localCommitPushed); var embed = new Embed { - Author = new EmbedAuthor + Author = new EmbedAuthor(assemblyInformationProvider.VersionPrefix) { - Name = assemblyInformationProvider.VersionPrefix, Url = "https://github.com/tgstation/tgstation-server", IconUrl = "https://avatars0.githubusercontent.com/u/1363778?s=280&v=4", }, diff --git a/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs b/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs index f5129d7a06..07fc17b243 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs @@ -39,8 +39,9 @@ namespace Tgstation.Server.Host.Components.Events if (watchdog == null) throw new InvalidOperationException("EventConsumer used without watchdog set!"); - await configuration.HandleEvent(eventType, parameters, cancellationToken).ConfigureAwait(false); + var scriptTask = configuration.HandleEvent(eventType, parameters, cancellationToken); await watchdog.HandleEvent(eventType, parameters, cancellationToken).ConfigureAwait(false); + await scriptTask.ConfigureAwait(false); } /// diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index 3e1f8eab93..5cd8306ceb 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -308,25 +308,33 @@ namespace Tgstation.Server.Host.Components cancellationToken) .ConfigureAwait(false); - Task LoadRevInfo() => databaseContext.RevisionInformations - .AsQueryable() - .Where(x => x.CommitSha == startSha && x.Instance.Id == metadata.Id) - .Include(x => x.ActiveTestMerges).ThenInclude(x => x.TestMerge) - .FirstOrDefaultAsync(cancellationToken); - - RevisionInformation currentRevInfo = null; var hasDbChanges = false; + RevisionInformation currentRevInfo = null; Models.Instance attachedInstance = null; async Task UpdateRevInfo(string currentHead, bool onOrigin, IEnumerable updatedTestMerges) { if (currentRevInfo == null) - currentRevInfo = await LoadRevInfo().ConfigureAwait(false); + { + logger.LogTrace("Loading revision info for commit {0}...", startSha.Substring(0, 7)); + currentRevInfo = await databaseContext + .RevisionInformations + .AsQueryable() + .Where(x => x.CommitSha == startSha && x.Instance.Id == metadata.Id) + .Include(x => x.ActiveTestMerges) + .ThenInclude(x => x.TestMerge) + .FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); + } if (currentRevInfo == default) { logger.LogInformation(Repository.Repository.OriginTrackingErrorTemplate, currentHead); onOrigin = true; } + else if (currentRevInfo.CommitSha == currentHead) + { + logger.LogTrace("Not updating rev-info, already in DB."); + return; + } if (attachedInstance == null) { @@ -347,6 +355,7 @@ namespace Tgstation.Server.Host.Components : await repo.GetOriginSha(cancellationToken).ConfigureAwait(false), Instance = attachedInstance, }; + if (!onOrigin) currentRevInfo.ActiveTestMerges = new List( updatedTestMerges ?? oldRevInfo.ActiveTestMerges); diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs index 9fcb712f26..ca75e5d396 100644 --- a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs +++ b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs @@ -631,7 +631,11 @@ namespace Tgstation.Server.Host.Components.StaticFiles await ioManager.WriteAllBytes(staticIgnorePath, Array.Empty(), cancellationToken).ConfigureAwait(false); } - await Task.WhenAll(ioManager.CreateDirectory(CodeModificationsSubdirectory, cancellationToken), ioManager.CreateDirectory(EventScriptsSubdirectory, cancellationToken), ValidateStaticFolder()).ConfigureAwait(false); + await Task.WhenAll( + ioManager.CreateDirectory(CodeModificationsSubdirectory, cancellationToken), + ioManager.CreateDirectory(EventScriptsSubdirectory, cancellationToken), + ValidateStaticFolder()) + .ConfigureAwait(false); } /// diff --git a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs index ec41aa29f4..f62bc2d2c8 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs @@ -111,7 +111,7 @@ namespace Tgstation.Server.Host.Components.Watchdog var eventType = Server.TerminationWasRequested ? EventType.WorldEndProcess : EventType.WatchdogCrash; - await EventConsumer.HandleEvent(eventType, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); + await HandleNonRelayedEvent(eventType, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); var exitWord = Server.TerminationWasRequested ? "exited" : "crashed"; if (Server.RebootState == Session.RebootState.Shutdown) @@ -146,7 +146,7 @@ namespace Tgstation.Server.Host.Components.Watchdog gracefulRebootRequired = false; Server.ResetRebootState(); - await EventConsumer.HandleEvent(EventType.WorldReboot, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); + await HandleNonRelayedEvent(EventType.WorldReboot, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); switch (rebootState) { @@ -173,7 +173,7 @@ namespace Tgstation.Server.Host.Components.Watchdog await HandleNewDmbAvailable(cancellationToken).ConfigureAwait(false); break; case MonitorActivationReason.ActiveServerPrimed: - await EventConsumer.HandleEvent(EventType.WorldPrime, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); + await HandleNonRelayedEvent(EventType.WorldPrime, Enumerable.Empty(), cancellationToken).ConfigureAwait(false); break; case MonitorActivationReason.Heartbeat: default: diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs index e053af0bcc..ebf67b6087 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs @@ -90,11 +90,6 @@ namespace Tgstation.Server.Host.Components.Watchdog /// protected IAsyncDelayer AsyncDelayer { get; } - /// - /// The that is not the . - /// - protected IEventConsumer EventConsumer { get; } - /// /// The for the . /// @@ -110,6 +105,11 @@ namespace Tgstation.Server.Host.Components.Watchdog /// readonly SemaphoreSlim controllerDisposeSemaphore; + /// + /// The that is not the . + /// + readonly IEventConsumer eventConsumer; + /// /// The for the . /// @@ -205,7 +205,7 @@ namespace Tgstation.Server.Host.Components.Watchdog this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager)); AsyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.diagnosticsIOManager = diagnosticsIOManager ?? throw new ArgumentNullException(nameof(diagnosticsIOManager)); - EventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer)); + this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer)); this.remoteDeploymentManagerFactory = remoteDeploymentManagerFactory ?? throw new ArgumentNullException(nameof(remoteDeploymentManagerFactory)); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); ActiveLaunchParameters = initialLaunchParameters ?? throw new ArgumentNullException(nameof(initialLaunchParameters)); @@ -505,7 +505,7 @@ namespace Tgstation.Server.Host.Components.Watchdog cancellationToken); // simple announce if (reattachInfo == null) announceTask = Task.WhenAll( - EventConsumer.HandleEvent(EventType.WatchdogLaunch, Enumerable.Empty(), cancellationToken), + HandleNonRelayedEvent(EventType.WatchdogLaunch, Enumerable.Empty(), cancellationToken), announceTask); } else @@ -676,6 +676,25 @@ namespace Tgstation.Server.Host.Components.Watchdog return remoteDeploymentManager.ApplyDeployment(newCompileJob, ActiveCompileJob, cancellationToken); } + /// + /// Handle a given without re-throwing errors. + /// + /// The . + /// An of parameters for . + /// The for the operation. + /// A representing the running operation. + protected async Task HandleNonRelayedEvent(EventType eventType, IEnumerable parameters, CancellationToken cancellationToken) + { + try + { + await eventConsumer.HandleEvent(eventType, parameters, cancellationToken); + } + catch (JobException ex) + { + Logger.LogError(ex, "Suppressing exception triggered by event!"); + } + } + /// /// Attempt to restart the monitor from scratch. /// @@ -954,7 +973,7 @@ namespace Tgstation.Server.Host.Components.Watchdog return; if (!graceful) { - var eventTask = EventConsumer.HandleEvent( + var eventTask = HandleNonRelayedEvent( releaseServers ? EventType.WatchdogDetach : EventType.WatchdogShutdown, diff --git a/src/Tgstation.Server.Host/Controllers/AdministrationController.cs b/src/Tgstation.Server.Host/Controllers/AdministrationController.cs index 6b653b2eed..a7dd4c41d8 100644 --- a/src/Tgstation.Server.Host/Controllers/AdministrationController.cs +++ b/src/Tgstation.Server.Host/Controllers/AdministrationController.cs @@ -166,7 +166,7 @@ namespace Tgstation.Server.Host.Controllers foreach (var release in releases) if (Version.TryParse(release.TagName.Replace(updatesConfiguration.GitTagPrefix, String.Empty, StringComparison.Ordinal), out var version) - && version.Major == assemblyInformationProvider.Version.Major + && version.Major > 3 // Forward/backward compatible but not before TGS4 && (greatestVersion == null || version > greatestVersion)) greatestVersion = version; repoUrl = new Uri((await repositoryTask.ConfigureAwait(false)).HtmlUrl); @@ -225,7 +225,7 @@ namespace Tgstation.Server.Host.Controllers AdditionalData = "newVersion is required!", }); - if (model.NewVersion.Major != assemblyInformationProvider.Version.Major) + if (model.NewVersion.Major < 3) return BadRequest(new ErrorMessageResponse(ErrorCode.CannotChangeServerSuite)); if (!serverControl.WatchdogPresent) diff --git a/src/Tgstation.Server.Host/Controllers/HomeController.cs b/src/Tgstation.Server.Host/Controllers/HomeController.cs index 205c20620d..93cbd26941 100644 --- a/src/Tgstation.Server.Host/Controllers/HomeController.cs +++ b/src/Tgstation.Server.Host/Controllers/HomeController.cs @@ -218,7 +218,7 @@ namespace Tgstation.Server.Host.Controllers { if (ApiHeaders == null) { - Response.Headers.Add(HeaderNames.WWWAuthenticate, new StringValues("basic realm=\"Create TGS4 bearer token\"")); + Response.Headers.Add(HeaderNames.WWWAuthenticate, new StringValues("basic realm=\"Create TGS bearer token\"")); return HeadersIssue(false); } diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 087cb51702..f79766ff24 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -430,7 +430,7 @@ namespace Tgstation.Server.Host.Core if (generalConfiguration.HostApiDocumentation) { applicationBuilder.UseSwagger(); - applicationBuilder.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "TGS API V4")); + applicationBuilder.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "TGS API")); logger.LogTrace("Swagger API generation enabled"); } diff --git a/src/Tgstation.Server.Host/Database/DatabaseContext.cs b/src/Tgstation.Server.Host/Database/DatabaseContext.cs index 3b9a4194bb..ae46944ec6 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseContext.cs @@ -409,7 +409,7 @@ namespace Tgstation.Server.Host.Database if (targetVersion == null) throw new ArgumentNullException(nameof(targetVersion)); if (targetVersion < new Version(4, 0)) - throw new ArgumentOutOfRangeException(nameof(targetVersion), targetVersion, "Not a valid V4 version!"); + throw new ArgumentOutOfRangeException(nameof(targetVersion), targetVersion, "Cannot migrate below version 4.0.0!"); if (currentDatabaseType == DatabaseType.PostgresSql && targetVersion < new Version(4, 3, 0)) throw new NotSupportedException("Cannot migrate below version 4.3.0 with PostgresSql!"); diff --git a/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs b/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs index bc6ed50c5a..1ae2809a75 100644 --- a/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs @@ -104,7 +104,7 @@ namespace Tgstation.Server.Host.Extensions CustomFormatter = new EcsTextFormatter(), AutoRegisterTemplate = true, AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv7, - IndexFormat = "tgs4-logs", + IndexFormat = "tgs-logs", }); } } diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index a697f8801f..0690e02050 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -346,7 +346,7 @@ namespace Tgstation.Server.Host.Setup cancellationToken) .ConfigureAwait(false); await console.WriteAsync( - "This means that you may not be able to update to the next minor version of TGS4 without a clean re-installation!", + "This means that you may not be able to update to the next minor version of TGS without a clean re-installation!", true, cancellationToken) .ConfigureAwait(false); diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 579b98fa6c..3424ea6dbc 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -1,4 +1,4 @@ - + @@ -87,7 +87,7 @@ - + diff --git a/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestDiscordProvider.cs b/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestDiscordProvider.cs index e2d527c43c..2a2f3d795b 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestDiscordProvider.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestDiscordProvider.cs @@ -22,7 +22,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers.Tests [TestInitialize] public void Initialize() { - var actualToken = Environment.GetEnvironmentVariable("TGS4_TEST_DISCORD_TOKEN"); + var actualToken = Environment.GetEnvironmentVariable("TGS_TEST_DISCORD_TOKEN"); if (!String.IsNullOrWhiteSpace(actualToken)) testToken1 = new ChatBot { @@ -45,7 +45,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers.Tests public async Task TestConstructionAndDisposal() { if (testToken1 == null) - Assert.Inconclusive("Required environment variable TGS4_TEST_DISCORD_TOKEN isn't set!"); + Assert.Inconclusive("Required environment variable TGS_TEST_DISCORD_TOKEN isn't set!"); Assert.ThrowsException(() => new DiscordProvider(null, null, null, null)); Assert.ThrowsException(() => new DiscordProvider(mockJobManager, null, null, null)); @@ -61,8 +61,6 @@ namespace Tgstation.Server.Host.Components.Chat.Providers.Tests [TestMethod] public async Task TestConnectWithFakeTokenFails() { - Assert.Inconclusive("Doesn't happen, see https://github.com/Nihlus/Remora.Discord/issues/99 for resolution"); - var mockLogger = new Mock>(); await using var provider = new DiscordProvider(mockJobManager, Mock.Of(), mockLogger.Object, new ChatBot { @@ -77,7 +75,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers.Tests public async Task TestConnectAndDisconnect() { if (testToken1 == null) - Assert.Inconclusive("Required environment variable TGS4_TEST_DISCORD_TOKEN isn't set!"); + Assert.Inconclusive("Required environment variable TGS_TEST_DISCORD_TOKEN isn't set!"); var mockLogger = new Mock>(); await using var provider = new DiscordProvider(mockJobManager, Mock.Of(), mockLogger.Object, testToken1); diff --git a/tests/Tgstation.Server.Tests/AdministrationTest.cs b/tests/Tgstation.Server.Tests/AdministrationTest.cs index 2ea67f7c8d..6b9581534a 100644 --- a/tests/Tgstation.Server.Tests/AdministrationTest.cs +++ b/tests/Tgstation.Server.Tests/AdministrationTest.cs @@ -1,4 +1,4 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Linq; using System.Threading; @@ -60,9 +60,9 @@ namespace Tgstation.Server.Tests } catch (RateLimitException) { - if (String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TGS4_TEST_GITHUB_TOKEN"))) + if (String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TGS_TEST_GITHUB_TOKEN"))) { - Assert.Inconclusive("GitHub rate limit hit while testing administration endpoint. Set environment variable TGS4_TEST_GITHUB_TOKEN to fix this!"); + Assert.Inconclusive("GitHub rate limit hit while testing administration endpoint. Set environment variable TGS_TEST_GITHUB_TOKEN to fix this!"); } // CI fails all the time b/c of this, ignore it @@ -70,7 +70,7 @@ namespace Tgstation.Server.Tests } //we've released a few 4.x versions now, check the release checker is at least somewhat functional - Assert.AreEqual(4, model.LatestVersion.Major); + Assert.IsTrue(4 <= model.LatestVersion.Major); } } } diff --git a/tests/Tgstation.Server.Tests/Instance/ChatTest.cs b/tests/Tgstation.Server.Tests/Instance/ChatTest.cs index 8c1baf40df..71a0f2ff03 100644 --- a/tests/Tgstation.Server.Tests/Instance/ChatTest.cs +++ b/tests/Tgstation.Server.Tests/Instance/ChatTest.cs @@ -37,9 +37,9 @@ namespace Tgstation.Server.Tests.Instance { var firstBotReq = new ChatBotCreateRequest { - ConnectionString = Environment.GetEnvironmentVariable("TGS4_TEST_IRC_CONNECTION_STRING"), + ConnectionString = Environment.GetEnvironmentVariable("TGS_TEST_IRC_CONNECTION_STRING"), Enabled = false, - Name = "tgs4_integration_test", + Name = "tgs_integration_test", Provider = ChatProvider.Irc, ReconnectionInterval = 1, ChannelLimit = 1 @@ -68,7 +68,7 @@ namespace Tgstation.Server.Tests.Instance Assert.AreEqual(true, updatedBot.Enabled); - var channelId = Environment.GetEnvironmentVariable("TGS4_TEST_IRC_CHANNEL"); ; + var channelId = Environment.GetEnvironmentVariable("TGS_TEST_IRC_CHANNEL"); ; updatedBot = await chatClient.Update(new ChatBotUpdateRequest { @@ -104,7 +104,7 @@ namespace Tgstation.Server.Tests.Instance ConnectionString = new DiscordConnectionStringBuilder { - BotToken = Environment.GetEnvironmentVariable("TGS4_TEST_DISCORD_TOKEN"), + BotToken = Environment.GetEnvironmentVariable("TGS_TEST_DISCORD_TOKEN"), DMOutputDisplay = DiscordDMOutputDisplayType.OnError }.ToString(), Enabled = false, @@ -137,7 +137,7 @@ namespace Tgstation.Server.Tests.Instance Assert.AreEqual(true, updatedBot.Enabled); - var channelId = UInt64.Parse(Environment.GetEnvironmentVariable("TGS4_TEST_DISCORD_CHANNEL")); + var channelId = UInt64.Parse(Environment.GetEnvironmentVariable("TGS_TEST_DISCORD_CHANNEL")); firstBot.Channels = new List { new ChatChannel diff --git a/tests/Tgstation.Server.Tests/Instance/RepositoryTest.cs b/tests/Tgstation.Server.Tests/Instance/RepositoryTest.cs index 0f9ebcadce..ff2e1d8dea 100644 --- a/tests/Tgstation.Server.Tests/Instance/RepositoryTest.cs +++ b/tests/Tgstation.Server.Tests/Instance/RepositoryTest.cs @@ -25,7 +25,7 @@ namespace Tgstation.Server.Tests.Instance public async Task RunPreWatchdog(CancellationToken cancellationToken) { - const string TestRefEnvVar = "TGS4_GITHUB_REF"; + const string TestRefEnvVar = "TGS_GITHUB_REF"; var envVar = Environment.GetEnvironmentVariable(TestRefEnvVar); string workingBranch = null; if (!String.IsNullOrWhiteSpace(envVar)) @@ -108,12 +108,12 @@ namespace Tgstation.Server.Tests.Instance updated = await Checkout(new RepositoryUpdateRequest { CheckoutSha = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }, true, false, cancellationToken); // Fake ref - updated = await Checkout(new RepositoryUpdateRequest { Reference = "Tgs4IntegrationTestFakeBranchNeverNameABranchThis" }, true, true, cancellationToken); + updated = await Checkout(new RepositoryUpdateRequest { Reference = "TgsIntegrationTestFakeBranchNeverNameABranchThis" }, true, true, cancellationToken); // Back updated = await Checkout(new RepositoryUpdateRequest { Reference = workingBranch }, false, true, cancellationToken); - var testPRString = Environment.GetEnvironmentVariable("TGS4_TEST_PULL_REQUEST_NUMBER"); + var testPRString = Environment.GetEnvironmentVariable("TGS_TEST_PULL_REQUEST_NUMBER"); if (String.IsNullOrWhiteSpace(testPRString)) testPRString = Environment.GetEnvironmentVariable("APPVEYOR_PULL_REQUEST_NUMBER"); if (String.IsNullOrWhiteSpace(testPRString)) diff --git a/tests/Tgstation.Server.Tests/IntegrationTest.cs b/tests/Tgstation.Server.Tests/IntegrationTest.cs index 3ac21f4037..a1b7b1a5c6 100644 --- a/tests/Tgstation.Server.Tests/IntegrationTest.cs +++ b/tests/Tgstation.Server.Tests/IntegrationTest.cs @@ -96,7 +96,7 @@ namespace Tgstation.Server.Tests } catch (RateLimitException ex) { - if (String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TGS4_TEST_GITHUB_TOKEN"))) + if (String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TGS_TEST_GITHUB_TOKEN"))) throw; Assert.Inconclusive("GitHub rate limit hit: {0}", ex); @@ -184,7 +184,7 @@ namespace Tgstation.Server.Tests } catch (RateLimitException ex) { - if (String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TGS4_TEST_GITHUB_TOKEN"))) + if (String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TGS_TEST_GITHUB_TOKEN"))) throw; Assert.Inconclusive("GitHub rate limit hit: {0}", ex); @@ -393,7 +393,7 @@ namespace Tgstation.Server.Tests } catch (RateLimitException ex) { - if (String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TGS4_TEST_GITHUB_TOKEN"))) + if (String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TGS_TEST_GITHUB_TOKEN"))) throw; Assert.Inconclusive("GitHub rate limit hit: {0}", ex); @@ -590,7 +590,7 @@ namespace Tgstation.Server.Tests } catch (RateLimitException ex) { - if (String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TGS4_TEST_GITHUB_TOKEN"))) + if (String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TGS_TEST_GITHUB_TOKEN"))) throw; Assert.Inconclusive("GitHub rate limit hit: {0}", ex); @@ -648,14 +648,14 @@ namespace Tgstation.Server.Tests [TestMethod] public async Task TestDownMigrations() { - var connectionString = Environment.GetEnvironmentVariable("TGS4_TEST_CONNECTION_STRING"); + var connectionString = Environment.GetEnvironmentVariable("TGS_TEST_CONNECTION_STRING"); if (String.IsNullOrEmpty(connectionString)) - Assert.Inconclusive("No connection string configured in env var TGS4_TEST_CONNECTION_STRING!"); + Assert.Inconclusive("No connection string configured in env var TGS_TEST_CONNECTION_STRING!"); - var databaseTypeString = Environment.GetEnvironmentVariable("TGS4_TEST_DATABASE_TYPE"); + var databaseTypeString = Environment.GetEnvironmentVariable("TGS_TEST_DATABASE_TYPE"); if (!Enum.TryParse(databaseTypeString, out var databaseType)) - Assert.Inconclusive("No/invalid database type configured in env var TGS4_TEST_DATABASE_TYPE!"); + Assert.Inconclusive("No/invalid database type configured in env var TGS_TEST_DATABASE_TYPE!"); string migrationName = null; DatabaseContext CreateContext() diff --git a/tests/Tgstation.Server.Tests/TestingServer.cs b/tests/Tgstation.Server.Tests/TestingServer.cs index 9fdbe31d62..878527bb15 100644 --- a/tests/Tgstation.Server.Tests/TestingServer.cs +++ b/tests/Tgstation.Server.Tests/TestingServer.cs @@ -35,10 +35,10 @@ namespace Tgstation.Server.Tests public TestingServer(SwarmConfiguration swarmConfiguration, bool enableOAuth, ushort port = 5010) { - Directory = Environment.GetEnvironmentVariable("TGS4_TEST_TEMP_DIRECTORY"); + Directory = Environment.GetEnvironmentVariable("TGS_TEST_TEMP_DIRECTORY"); if (String.IsNullOrWhiteSpace(Directory)) { - Directory = Path.Combine(Path.GetTempPath(), "TGS4_INTEGRATION_TEST"); + Directory = Path.Combine(Path.GetTempPath(), "TGS_INTEGRATION_TEST"); if (System.IO.Directory.Exists(Directory) && swarmConfiguration == null) try { @@ -55,16 +55,16 @@ namespace Tgstation.Server.Tests //so we need a db //we have to rely on env vars - DatabaseType = Environment.GetEnvironmentVariable("TGS4_TEST_DATABASE_TYPE"); - var connectionString = Environment.GetEnvironmentVariable("TGS4_TEST_CONNECTION_STRING"); - var gitHubAccessToken = Environment.GetEnvironmentVariable("TGS4_TEST_GITHUB_TOKEN"); - var dumpOpenAPISpecPathEnvVar = Environment.GetEnvironmentVariable("TGS4_TEST_DUMP_API_SPEC"); + DatabaseType = Environment.GetEnvironmentVariable("TGS_TEST_DATABASE_TYPE"); + var connectionString = Environment.GetEnvironmentVariable("TGS_TEST_CONNECTION_STRING"); + var gitHubAccessToken = Environment.GetEnvironmentVariable("TGS_TEST_GITHUB_TOKEN"); + var dumpOpenAPISpecPathEnvVar = Environment.GetEnvironmentVariable("TGS_TEST_DUMP_API_SPEC"); if (String.IsNullOrEmpty(DatabaseType)) - Assert.Inconclusive("No database type configured in env var TGS4_TEST_DATABASE_TYPE!"); + Assert.Inconclusive("No database type configured in env var TGS_TEST_DATABASE_TYPE!"); if (String.IsNullOrEmpty(connectionString)) - Assert.Inconclusive("No connection string configured in env var TGS4_TEST_CONNECTION_STRING!"); + Assert.Inconclusive("No connection string configured in env var TGS_TEST_CONNECTION_STRING!"); if (String.IsNullOrEmpty(gitHubAccessToken)) Console.WriteLine("WARNING: No GitHub access token configured, test may fail due to rate limits!"); diff --git a/tools/ReleaseNotes/Program.cs b/tools/ReleaseNotes/Program.cs index 9597fdf9df..7654e0bd5c 100644 --- a/tools/ReleaseNotes/Program.cs +++ b/tools/ReleaseNotes/Program.cs @@ -34,7 +34,7 @@ namespace ReleaseNotes var doNotCloseMilestone = args.Length > 1 && args[1].ToUpperInvariant() == "--NO-CLOSE"; - const string ReleaseNotesEnvVar = "TGS4_RELEASE_NOTES_TOKEN"; + const string ReleaseNotesEnvVar = "TGS_RELEASE_NOTES_TOKEN"; var githubToken = Environment.GetEnvironmentVariable(ReleaseNotesEnvVar); if (String.IsNullOrWhiteSpace(githubToken) && !doNotCloseMilestone) { @@ -201,8 +201,6 @@ namespace ReleaseNotes var releases = await releasesTask.ConfigureAwait(false); - var releasingSuite = version.Major; - Version highestReleaseVersion = null; Release highestRelease = null; foreach (var I in releases) @@ -213,7 +211,7 @@ namespace ReleaseNotes continue; } - if (currentReleaseVersion.Major == releasingSuite && (highestReleaseVersion == null || currentReleaseVersion > highestReleaseVersion) && version != currentReleaseVersion) + if (currentReleaseVersion.Major == version.Major && (highestReleaseVersion == null || currentReleaseVersion > highestReleaseVersion) && version != currentReleaseVersion) { highestReleaseVersion = currentReleaseVersion; highestRelease = I; @@ -222,7 +220,7 @@ namespace ReleaseNotes if (highestReleaseVersion == null) { - Console.WriteLine("Unable to determine highest release version for suite " + releasingSuite + "!"); + Console.WriteLine("Unable to determine highest release version for major version " + version.Major + "!"); return 6; } @@ -247,49 +245,38 @@ namespace ReleaseNotes oldNotes = String.Join('\n', splits); string prefix; - switch (releasingSuite) + const string PropsPath = "build/Version.props"; + const string ControlPanelPropsPath = "build/ControlPanelVersion.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 doc2 = XDocument.Load(ControlPanelPropsPath); + var project2 = doc2.Root; + var controlPanelXmlNamespace = project2.GetDefaultNamespace(); + var controlPanelVersionsPropertyGroup = project2.Elements().First(x => x.Name == controlPanelXmlNamespace + "PropertyGroup"); + + var coreVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsCoreVersion").Value); + if (coreVersion != version) { - case 4: - const string PropsPath = "build/Version.props"; - const string ControlPanelPropsPath = "build/ControlPanelVersion.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 doc2 = XDocument.Load(ControlPanelPropsPath); - var project2 = doc2.Root; - var controlPanelXmlNamespace = project2.GetDefaultNamespace(); - var controlPanelVersionsPropertyGroup = project2.Elements().First(x => x.Name == controlPanelXmlNamespace + "PropertyGroup"); - - var coreVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsCoreVersion").Value); - if (coreVersion != version) - { - Console.WriteLine("Received a different version on command line than in Version.props!"); - return 10; - } - - var apiVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsApiVersion").Value); - var configVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsConfigVersion").Value); - var dmApiVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsDmapiVersion").Value); - var interopVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsInteropVersion").Value); - var webControlVersion = Version.Parse(controlPanelVersionsPropertyGroup.Element(controlPanelXmlNamespace + "TgsControlPanelVersion").Value); - var hostWatchdogVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsHostWatchdogVersion").Value); - - if (webControlVersion.Major == 0) - postControlPanelMessage = true; - - prefix = $"Please refer to the [README](https://github.com/tgstation/tgstation-server#setup) for setup instructions.{Environment.NewLine}{Environment.NewLine}#### Component Versions\nCore: {coreVersion}\nConfiguration: {configVersion}\nHTTP API: {apiVersion}\nDreamMaker API: {dmApiVersion} (Interop: {interopVersion})\n[Web Control Panel](https://github.com/tgstation/tgstation-server-webpanel): {webControlVersion}\nHost Watchdog: {hostWatchdogVersion}"; - break; - case 3: - prefix = "The /tg/station server suite"; - break; - default: - prefix = "See https://tgstation.github.io/tgstation-server for installation instructions"; - break; + Console.WriteLine("Received a different version on command line than in Version.props!"); + return 10; } + var apiVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsApiVersion").Value); + var configVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsConfigVersion").Value); + var dmApiVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsDmapiVersion").Value); + var interopVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsInteropVersion").Value); + var webControlVersion = Version.Parse(controlPanelVersionsPropertyGroup.Element(controlPanelXmlNamespace + "TgsControlPanelVersion").Value); + var hostWatchdogVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsHostWatchdogVersion").Value); + + if (webControlVersion.Major == 0) + postControlPanelMessage = true; + + prefix = $"Please refer to the [README](https://github.com/tgstation/tgstation-server#setup) for setup instructions.{Environment.NewLine}{Environment.NewLine}#### Component Versions\nCore: {coreVersion}\nConfiguration: {configVersion}\nHTTP API: {apiVersion}\nDreamMaker API: {dmApiVersion} (Interop: {interopVersion})\n[Web Control Panel](https://github.com/tgstation/tgstation-server-webpanel): {webControlVersion}\nHost Watchdog: {hostWatchdogVersion}"; + var newNotes = new StringBuilder(prefix); if (postControlPanelMessage) { @@ -453,7 +440,7 @@ namespace ReleaseNotes newNotes.Append(Environment.NewLine); - if (version != new Version(4, 1, 0)) + if (version.Minor != 0 && version.Build != 0) newNotes.Append(oldNotes); const string OutputPath = "release_notes.md";