diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e1eca34032..f116b2259d 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -191,7 +191,7 @@ This prevents nesting levels from getting deeper then they need to be. - Some terminology to help understand the architecture: - An instance can be thought of as a separate server. It has a separate directory, repository, set of byond installations, etc... The only thing shared amongst instances is API surface, users, global configuration, the active tgstation-server version, and the host machine. - - API refers to the HTTP API unless otherwise specified. + - API refers to the REST API unless otherwise specified. - The entirety of server functionality resides in the host (Tgstation.Server.Host) project. - A Component is a service running in tgstation-server to help with instance functionality. These can only be communicated with via the HTTP or DM APIs. - There is a difference between Watchdog and Host Watchdog. The former monitors DreamDaemon uptime, the latter handles updating tgstation-server. @@ -247,7 +247,7 @@ Warning: You may need to temporarily set valid MySql credentials in [MySqlDesign OAuth providers are hardcoded but it is fairly easy to add new ones. The flow doesn't need to be strict OAuth either (r.e. /tg/ forums). Follow the following steps: -1. Add the name to the [Tgstation.Server.Api.Models.OAuthProviders](../src/Tgstation.Server.Api/Models/OAuthProviders.cs) enum (Also necessitates a minor HTTP API version bump). +1. Add the name to the [Tgstation.Server.Api.Models.OAuthProviders](../src/Tgstation.Server.Api/Models/OAuthProviders.cs) enum (Also necessitates a minor API version bump to the HTTP APIs (REST/GraphQL)). 1. Create an implementation of [IOAuthValidator](../src/Tgstation.Server.Host/Security/OAuth/IOAuthValidator.cs). - Most providers can simply override the [GenericOAuthValidator](../src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs). 1. Construct the implementation in the [OAuthProviders](../src/Tgstation.Server.Host/Security/OAuth/OAuthProviders.cs) class. @@ -275,7 +275,8 @@ Major changes should be committed to the `VX` branch created when the time for a We have several subcomponent APIs we ship with the core server that have their own versions. -- HTTP API +- REST API +- GraphQL API - DreamMaker API - Interop API - Configuration File @@ -308,7 +309,7 @@ Word commit names descriptively. Only submit work through pull requests (With th At the time of this writing, the repository is configured to automate much of the deployment/release process. -When the new API, client, or DMAPI is ready to be released, update the `Version.props` file appropriately and merge the pull request with the text `[APIDeploy]`, `[NuGetDeploy]`, or `[DMDeploy]` respectively in the commit message (or all three!). The release will be published automatically. +When the new API, client, or DMAPI is ready to be released, update the `Version.props` file appropriately and merge the pull request with the text `[RESTDeploy]`, `[GQLDeploy]`, `[NugetDeploy]`, or `[DMDeploy]` respectively in the commit message (or all three!). The release will be published automatically. That step should be taken for the latest API and client before releasing the core version that uses them if applicable. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a71922c1df..518a6e5b61 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -16,7 +16,7 @@ They will be amalgamated together in the end. Categories are used by [the release notes tool](../tools/Tgstation.Server.ReleaseNotes) to generate formatted changelists used in releases. The default category is Core. Only one category may be specified for a 🆑 block. -Valid categories are Core, DreamMaker API, HTTP API, Host Watchdog, Web Control Panel, Configuration, Nuget: Api, Nuget: Client, and Nuget: Common. +Valid categories are Core, DreamMaker API, REST API, GraphQL API, Host Watchdog, Web Control Panel, Configuration, Nuget: Api, Nuget: Client, and Nuget: Common. /🆑 [Why]: # (If this does not close or work on an existing GitHub issue, please add a short description [two lines down] of why you think these changes would benefit the server. If you can't justify it in words, it might not be worth adding.) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index afef6086dd..4c27487241 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -10,7 +10,8 @@ # - 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 HTTP API swagger.json [RESTDeploy] (dev/master) +# - Deploys GraphQL API schema.graphql [GQLDeploy] (dev/master) # - Deploys tgstation-server [TGSDeploy] (master) # - GitHub Releases: https://github.com/tgstation/tgstation-server/releases # - Docker: https://hub.docker.com/r/tgstation/server @@ -741,6 +742,13 @@ jobs: name: openapi-spec path: C:/tgs_api.json + - name: Store GraphQL Schema + if: ${{ matrix.configuration == 'Release' && matrix.watchdog-type == 'Advanced' && matrix.database-type == 'SqlServer' }} + uses: actions/upload-artifact@v4 + with: + name: graphql-schema + path: ./artifacts/tgs-api.graphql + - name: Package Server Service if: ${{ matrix.configuration == 'Release' && matrix.watchdog-type == 'Basic' && matrix.database-type == 'PostgresSql' }} run: | @@ -1611,11 +1619,11 @@ jobs: - name: GitHub Requires at Least One Step for a Job run: exit 0 - deploy-http: - name: Deploy HTTP API + deploy-rest: + name: Deploy REST API needs: deployment-gate runs-on: windows-latest - if: contains(github.event.head_commit.message, '[APIDeploy]') + if: contains(github.event.head_commit.message, '[RESTDeploy]') steps: - name: Setup dotnet uses: actions/setup-dotnet@v4 @@ -1630,7 +1638,7 @@ jobs: shell: powershell run: | [XML]$versionXML = Get-Content build/Version.props - $apiVersion = $versionXML.Project.PropertyGroup.TgsApiVersion + $apiVersion = $versionXML.Project.PropertyGroup.TgsRestVersion echo "TGS_API_VERSION=$apiVersion" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append - name: Retrieve OpenAPI Spec @@ -1661,7 +1669,7 @@ jobs: - name: Generate Release Notes env: TGS_RELEASE_NOTES_TOKEN: ${{ steps.app-token-generation.outputs.token }} - run: dotnet release_notes_bins/Tgstation.Server.ReleaseNotes.dll ${{ env.TGS_API_VERSION }} --httpapi + run: dotnet release_notes_bins/Tgstation.Server.ReleaseNotes.dll ${{ env.TGS_API_VERSION }} --restapi - name: Create GitHub Release uses: actions/create-release@v1 @@ -1670,7 +1678,7 @@ jobs: GITHUB_TOKEN: ${{ steps.app-token-generation.outputs.token }} with: tag_name: api-v${{ env.TGS_API_VERSION }} - release_name: tgstation-server API v${{ env.TGS_API_VERSION }} + release_name: tgstation-server REST API v${{ env.TGS_API_VERSION }} body_path: release_notes.md commitish: ${{ github.event.head_commit.id }} @@ -1684,6 +1692,86 @@ jobs: asset_name: swagger.json asset_content_type: application/json + deploy-gql: + name: Deploy GraphQL API + needs: deployment-gate + runs-on: windows-latest + if: contains(github.event.head_commit.message, '[GQLDeploy]') + steps: + - name: Setup dotnet + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.TGS_DOTNET_VERSION }}.0.x + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} + + - name: Checkout + uses: actions/checkout@v4 + + - name: Parse API version + shell: powershell + run: | + [XML]$versionXML = Get-Content build/Version.props + $apiVersion = $versionXML.Project.PropertyGroup.TgsGraphQLVersion + echo "TGS_API_VERSION=$apiVersion" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + [Version]$parsedVersion = $apiVersion + if ($parsedVersion.Major -eq 0) { + echo "TGS_GRAPHQL_PRERELEASE=true" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + } else { + echo "TGS_GRAPHQL_PRERELEASE=false" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + } + + - name: Retrieve GraphQL Schema + uses: actions/download-artifact@v4 + with: + name: graphql-schema + path: schema + + - name: Grab Most Recent Changelog + shell: powershell + run: | + $ProgressPreference = 'SilentlyContinue' + Invoke-WebRequest -Uri https://raw.githubusercontent.com/tgstation/tgstation-server/gh-pages/changelog.yml -OutFile changelog.yml + + - name: Retrieve ReleaseNotes Binaries + uses: actions/download-artifact@v4 + with: + name: release_notes_bins + path: release_notes_bins + + - name: Generate App Token + id: app-token-generation + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + + - name: Generate Release Notes + env: + TGS_RELEASE_NOTES_TOKEN: ${{ steps.app-token-generation.outputs.token }} + run: dotnet release_notes_bins/Tgstation.Server.ReleaseNotes.dll ${{ env.TGS_API_VERSION }} --graphqlapi + + - name: Create GitHub Release + uses: actions/create-release@v1 + id: create_release + env: + GITHUB_TOKEN: ${{ steps.app-token-generation.outputs.token }} + with: + tag_name: graphql-v${{ env.TGS_API_VERSION }} + release_name: tgstation-server GraphQL API v${{ env.TGS_API_VERSION }} + body_path: release_notes.md + commitish: ${{ github.event.head_commit.id }} + prerelease: ${{ env.TGS_GRAPHQL_PRERELEASE }} + + - name: Upload OpenApi Spec + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ steps.app-token-generation.outputs.token }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./schema/tgs-api.graphql + asset_name: tgs-api.graphql + asset_content_type: text/plain + deploy-dm: name: Deploy DreamMaker API needs: deployment-gate @@ -1818,7 +1906,7 @@ jobs: ensure-release: name: Ensure TGS Release is Latest GitHub Release - needs: [deploy-dm, deploy-http] + needs: [deploy-dm, deploy-rest, deploy-gql] runs-on: ubuntu-latest if: (!(cancelled() || failure())) && (!contains(github.event.head_commit.message, '[TGSDeploy]')) && (needs.deploy-dm.result == 'success' || needs.deploy-http.result == 'success') steps: @@ -1848,7 +1936,7 @@ jobs: deploy-tgs: name: Deploy TGS - needs: [deploy-dm, deploy-http, deployment-gate] + needs: [deploy-dm, deploy-rest, deploy-gql, deployment-gate] runs-on: windows-latest if: (!(cancelled() || failure())) && github.event.ref == 'refs/heads/master' && contains(github.event.head_commit.message, '[TGSDeploy]') && needs.deployment-gate.result == 'success' env: @@ -1940,6 +2028,12 @@ jobs: name: openapi-spec path: swagger + - name: Retrieve GraphQL Schema + uses: actions/download-artifact@v4 + with: + name: graphql-schema + path: schema + - name: Retrieve Debian Packaging Archive uses: actions/download-artifact@v4 with: @@ -2035,7 +2129,7 @@ jobs: asset_name: DMAPI.zip asset_content_type: application/zip - - name: Upload OpenApi Spec Artifact + - name: Upload REST API Artifact uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ steps.app-token-generation.outputs.token }} @@ -2045,6 +2139,16 @@ jobs: asset_name: swagger.json asset_content_type: application/json + - name: Upload GraphQL API Artifact + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ steps.app-token-generation.outputs.token }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./schema/tgs-api.graphql + asset_name: tgs-api.graphql + asset_content_type: text/plain + - name: Upload Server Update Package Artifact uses: actions/upload-release-asset@v1 env: diff --git a/build/Version.props b/build/Version.props index 9c784ed4d7..1e304d4fb6 100644 --- a/build/Version.props +++ b/build/Version.props @@ -5,7 +5,8 @@ 6.10.0 5.2.0 - 10.10.0 + 10.10.0 + 0.1.0 7.0.0 16.0.0 19.0.0 diff --git a/src/README.md b/src/README.md index 76cb6bdf5d..c05d859bf2 100644 --- a/src/README.md +++ b/src/README.md @@ -5,7 +5,7 @@ This is a series of README.md files aimed at directing people around the codebas - To explore the server code navigate to [Tgstation.Server.Host](./Tgstation.Server.Host). - To explore the DreamMaker public API navigate to [DMAPI/tgs.dm](./DMAPI/tgs.dm). - To explore the DMAPI internals, navigate to [DMAPI/tgs](./DMAPI/tgs). -- To explore the HTTP API definitions navigate to [Tgstation.Server.Api](./Tgstation.Server.Api). +- To explore the REST API definitions navigate to [Tgstation.Server.Api](./Tgstation.Server.Api). - To explore the C# client code navigate to [Tgstation.Server.Client](./Tgstation.Server.Client). [Tgstation.Server.Host.Watchdog](./Tgstation.Server.Host.Watchdog), [Tgstation.Server.Host.Service](./Tgstation.Server.Host.Service), and [Tgstation.Server.Host.Console](./Tgstation.Server.Host.Console) are related to the Service/Console runners which have the simple task of executing Tgstation.Server.Host and updating it when requested. diff --git a/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj b/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj index 2617a2a566..129035ad21 100644 --- a/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj +++ b/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj @@ -14,7 +14,7 @@ - <_Parameter1>$(TgsApiVersion) + <_Parameter1>$(TgsRestVersion) diff --git a/src/Tgstation.Server.Client.GraphQL/GQL/Queries/UnauthenticatedServerInformation.graphql b/src/Tgstation.Server.Client.GraphQL/GQL/Queries/UnauthenticatedServerInformation.graphql index 44bff278f0..d2a45ce425 100644 --- a/src/Tgstation.Server.Client.GraphQL/GQL/Queries/UnauthenticatedServerInformation.graphql +++ b/src/Tgstation.Server.Client.GraphQL/GQL/Queries/UnauthenticatedServerInformation.graphql @@ -3,7 +3,7 @@ query UnauthenticatedServerInformation { currentNode { gateway { information { - majorApiVersion + majorGraphQLApiVersion oAuthProviderInfos { key value { diff --git a/src/Tgstation.Server.Client.GraphQL/Tgstation.Server.Client.GraphQL.csproj b/src/Tgstation.Server.Client.GraphQL/Tgstation.Server.Client.GraphQL.csproj index 4c1e5d1557..f0fa5de21f 100644 --- a/src/Tgstation.Server.Client.GraphQL/Tgstation.Server.Client.GraphQL.csproj +++ b/src/Tgstation.Server.Client.GraphQL/Tgstation.Server.Client.GraphQL.csproj @@ -3,7 +3,7 @@ $(TgsFrameworkVersion) - $(TgsApiVersion) + enable diff --git a/src/Tgstation.Server.Host/GraphQL/Mutation.cs b/src/Tgstation.Server.Host/GraphQL/Mutation.cs index 4b68aa9b89..5e6fa1d10c 100644 --- a/src/Tgstation.Server.Host/GraphQL/Mutation.cs +++ b/src/Tgstation.Server.Host/GraphQL/Mutation.cs @@ -14,8 +14,14 @@ namespace Tgstation.Server.Host.GraphQL /// Root type for GraphQL mutations. /// /// Intentionally left mostly empty, use type extensions to properly scope operations to domains. + [GraphQLDescription(GraphQLDescription)] public sealed class Mutation { + /// + /// Description to show on the type. + /// + public const string GraphQLDescription = "Root Mutation type"; + /// /// Generate a JWT for authenticating with server. This is the only operation that accepts and required basic authentication. /// diff --git a/src/Tgstation.Server.Host/GraphQL/Mutations/UserGroupMutations.cs b/src/Tgstation.Server.Host/GraphQL/Mutations/UserGroupMutations.cs index 92ef77d288..7f27d8ea76 100644 --- a/src/Tgstation.Server.Host/GraphQL/Mutations/UserGroupMutations.cs +++ b/src/Tgstation.Server.Host/GraphQL/Mutations/UserGroupMutations.cs @@ -18,6 +18,7 @@ namespace Tgstation.Server.Host.GraphQL.Mutations /// related s. /// [ExtendObjectType(typeof(Mutation))] + [GraphQLDescription(Mutation.GraphQLDescription)] public sealed class UserGroupMutations { /// diff --git a/src/Tgstation.Server.Host/GraphQL/Mutations/UserMutations.cs b/src/Tgstation.Server.Host/GraphQL/Mutations/UserMutations.cs index 64c671a7cb..5c51fd8bc3 100644 --- a/src/Tgstation.Server.Host/GraphQL/Mutations/UserMutations.cs +++ b/src/Tgstation.Server.Host/GraphQL/Mutations/UserMutations.cs @@ -22,6 +22,7 @@ namespace Tgstation.Server.Host.GraphQL.Mutations /// related s. /// [ExtendObjectType(typeof(Mutation))] + [GraphQLDescription(Mutation.GraphQLDescription)] public sealed class UserMutations { /// diff --git a/src/Tgstation.Server.Host/GraphQL/Query.cs b/src/Tgstation.Server.Host/GraphQL/Query.cs index ca9fed764f..660040d41d 100644 --- a/src/Tgstation.Server.Host/GraphQL/Query.cs +++ b/src/Tgstation.Server.Host/GraphQL/Query.cs @@ -1,10 +1,13 @@ #pragma warning disable CA1724 // Dumb conflict with Microsoft.EntityFrameworkCore.Query +using HotChocolate; + namespace Tgstation.Server.Host.GraphQL { /// /// GraphQL query . /// + [GraphQLDescription("Root Query type")] public sealed class Query { /// diff --git a/src/Tgstation.Server.Host/GraphQL/Subscription.cs b/src/Tgstation.Server.Host/GraphQL/Subscription.cs index 114a7622ad..170dceb49a 100644 --- a/src/Tgstation.Server.Host/GraphQL/Subscription.cs +++ b/src/Tgstation.Server.Host/GraphQL/Subscription.cs @@ -16,8 +16,14 @@ namespace Tgstation.Server.Host.GraphQL /// Root type for GraphQL subscriptions. /// /// Intentionally left mostly empty, use type extensions to properly scope operations to domains. + [GraphQLDescription(GraphQLDescription)] public sealed class Subscription { + /// + /// Description to show on the type. + /// + public const string GraphQLDescription = "Root Subscription type. Note that subscriptions are performed over Server Sent events."; + /// /// Gets the topic name for the login session represented by a given . /// diff --git a/src/Tgstation.Server.Host/GraphQL/Subscriptions/UserSubscriptions.cs b/src/Tgstation.Server.Host/GraphQL/Subscriptions/UserSubscriptions.cs index 2369df8ab4..35be564c52 100644 --- a/src/Tgstation.Server.Host/GraphQL/Subscriptions/UserSubscriptions.cs +++ b/src/Tgstation.Server.Host/GraphQL/Subscriptions/UserSubscriptions.cs @@ -18,6 +18,7 @@ namespace Tgstation.Server.Host.GraphQL.Subscriptions /// Subscriptions for . /// [ExtendObjectType(typeof(Subscription))] + [GraphQLDescription(Subscription.GraphQLDescription)] public sealed class UserSubscriptions { /// diff --git a/src/Tgstation.Server.Host/GraphQL/Types/GatewayInformation.cs b/src/Tgstation.Server.Host/GraphQL/Types/GatewayInformation.cs index a4fc74bd1d..727e38c5f1 100644 --- a/src/Tgstation.Server.Host/GraphQL/Types/GatewayInformation.cs +++ b/src/Tgstation.Server.Host/GraphQL/Types/GatewayInformation.cs @@ -1,6 +1,5 @@ -using System; +using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using HotChocolate; @@ -123,12 +122,18 @@ namespace Tgstation.Server.Host.GraphQL.Types } /// - /// Gets the major HTTP API number of the . + /// Gets the major GraphQL API number of the . /// - public int MajorApiVersion => ApiHeaders.Version.Major; + public int MajorGraphQLApiVersion => GraphQLApiVersion.Major; /// - /// Gets the HTTP API of the . + /// Gets the GraphQL API of the . + /// + [TgsGraphQLAuthorize] + public Version GraphQLApiVersion => global::System.Version.Parse(MasterVersionsAttribute.Instance.RawGraphQLVersion); + + /// + /// Gets the REST API of the . /// [TgsGraphQLAuthorize] public Version ApiVersion => ApiHeaders.Version; diff --git a/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs b/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs index 8212c4ffee..efef0144bc 100644 --- a/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs +++ b/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs @@ -32,7 +32,7 @@ namespace Tgstation.Server.Host.Properties public string RawWebpanelVersion { get; } /// - /// The of the control panel version built. + /// The of the host watchdog that was built alongside this TGS version. /// public string RawHostWatchdogVersion { get; } @@ -42,10 +42,15 @@ namespace Tgstation.Server.Host.Properties public string RawMariaDBRedistVersion { get; } /// - /// The of the MariaDB server bundled with TGS installs. + /// The of the TGS swarm protocol. /// public string RawSwarmProtocolVersion { get; } + /// + /// The of the TGS GraphQL API. + /// + public string RawGraphQLVersion { get; } + /// /// Initializes a new instance of the class. /// @@ -55,13 +60,15 @@ namespace Tgstation.Server.Host.Properties /// The value of . /// The value of . /// The value of . + /// The value of . public MasterVersionsAttribute( string rawConfigurationVersion, string rawInteropVersion, string rawWebpanelVersion, string rawHostWatchdogVersion, string rawMariaDBRedistVersion, - string rawSwarmProtocolVersion) + string rawSwarmProtocolVersion, + string rawGraphQLVersion) { RawConfigurationVersion = rawConfigurationVersion ?? throw new ArgumentNullException(nameof(rawConfigurationVersion)); RawInteropVersion = rawInteropVersion ?? throw new ArgumentNullException(nameof(rawInteropVersion)); @@ -69,6 +76,7 @@ namespace Tgstation.Server.Host.Properties RawHostWatchdogVersion = rawHostWatchdogVersion ?? throw new ArgumentNullException(nameof(rawHostWatchdogVersion)); RawMariaDBRedistVersion = rawMariaDBRedistVersion ?? throw new ArgumentNullException(nameof(rawMariaDBRedistVersion)); RawSwarmProtocolVersion = rawSwarmProtocolVersion ?? throw new ArgumentNullException(nameof(rawSwarmProtocolVersion)); + RawGraphQLVersion = rawGraphQLVersion ?? throw new ArgumentNullException(nameof(rawGraphQLVersion)); } } } diff --git a/src/Tgstation.Server.Host/README.md b/src/Tgstation.Server.Host/README.md index 1f8df0feee..9dd86b2d63 100644 --- a/src/Tgstation.Server.Host/README.md +++ b/src/Tgstation.Server.Host/README.md @@ -23,13 +23,15 @@ Server startup can be a bit complicated so here's a walkthrough Here's a breakdown of things in this directory - [.config](./.config) contains the dotnet-tools.json. At the time of writing, this is only used to set the version of the [dotnet ef tools](https://docs.microsoft.com/en-us/ef/core/miscellaneous/cli/) used to create database migrations. +- [Authority](./Authority) is code that contains the buisiness logic that bridges the HTTP APIs with component code and the database. - [ClientApp](./ClientApp) contains scripts to build and deploy the web control panel with TGS. - [Components](./Components) is where the bulk of the TGS implementation lives. - [Configuration](./Configuration) contains classes that partly make up the configuration yaml files (i.e. [appsettings.yml](./appsettings.yml)). -- [Controllers](./Controllers) is where HTTP API code lives and bridges it with component code. +- [Controllers](./Controllers) is where REST API code lives. - [Core](./Core) contains [Application.cs](./Core/Application.cs) and other classes related to the overrarching server process. - [Database](./Database) contains all database related code. - [Extensions](./Extensions) contains helper functions implemented as C# extension methods. +- [GraphQL](./GraqhQL) is where GraphQL API code lives. - [IO](./IO) contains classes related to interacting with the filesystem. - [Jobs](./Jobs) contains the job manager code. - [Models](./Models) contains ORM models used to interact with the database. diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 22798e4f13..1a6ec0e2e7 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -57,6 +57,7 @@ <_Parameter4>$(TgsHostWatchdogVersion) <_Parameter5>$(TgsMariaDBRedistVersion) <_Parameter6>$(TgsSwarmProtocolVersion) + <_Parameter7>$(TgsGraphQLVersion) diff --git a/src/Tgstation.Server.Host/appsettings.yml b/src/Tgstation.Server.Host/appsettings.yml index 353104e6de..b965a326ed 100644 --- a/src/Tgstation.Server.Host/appsettings.yml +++ b/src/Tgstation.Server.Host/appsettings.yml @@ -13,7 +13,7 @@ General: UserGroupLimit: 25 # Maximum number of allowed groups InstanceLimit: 10 # Maximum number of allowed instances ValidInstancePaths: # An array of directories instances may be created in (either directly or as a subdirectory). null removes the restriction - HostApiDocumentation: false # Make HTTP API documentation available at /api/doc/tgs_api.json + HostApiDocumentation: false # Make HTTP API documentation available at /api/doc/tgs_api.json and /api/graphql SkipAddingByondFirewallException: false # Windows Only: Prevent running netsh.exe to add a firewall exception for installed engine binaries DeploymentDirectoryCopyTasksPerCore: 100 # Maximum number of concurrent file copy operations PER available CPU core OpenDreamGitUrl: https://github.com/OpenDreamProject/OpenDream # The repository to retrieve OpenDream from @@ -40,7 +40,7 @@ Logging: Microsoft: Warning # Level of stdout verbosity from Microsoft dependecies (i.e. webserver, database object relational mapper, etc...). Can be one of Trace, Debug, Information, Warning, Error, or Critical ControlPanel: Enable: false # If the web control panel is hosted alongside the server - Channel: https://tgstation.github.io/tgstation-server-webpanel/api/${Major}.${Minor}.${Patch} # Channel for live web control panel updates. The tokens ${Major}, ${Minor}, and ${Patch} are substituted for the version of the HTTP API TGS was built with + Channel: https://tgstation.github.io/tgstation-server-webpanel/api/${Major}.${Minor}.${Patch} # Channel for live web control panel updates. The tokens ${Major}, ${Minor}, and ${Patch} are substituted for the version of the REST API TGS was built with AllowAnyOrigin: false # Enable the `Access-Control-Allow-Origin: *` header for HTTP responses AllowedOrigins: [] # Explict list of origins for `Access-Control-Allow-Origin:` HTTP header. Ignored if AllowAnyOrigin is true PublicPath: # Used if TGS is not hosted at the website root. If TGS is hosted under `https://domain.com/tgs`, this should be `/tgs` diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index ea2bf9311f..dec3a1a96d 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1407,16 +1407,15 @@ namespace Tgstation.Server.Tests.Live gqlClient => gqlClient.UnauthenticatedServerInformation.ExecuteAsync(cancellationToken), (restServerInfo, gqlServerInfo) => { - var result = restServerInfo.ApiVersion.Major == gqlServerInfo.Swarm.CurrentNode.Gateway.Information.MajorApiVersion - && (restServerInfo.OAuthProviderInfos == gqlServerInfo.Swarm.CurrentNode.Gateway.Information.OAuthProviderInfos - || restServerInfo.OAuthProviderInfos.All(kvp => - { - var info = gqlServerInfo.Swarm.CurrentNode.Gateway.Information.OAuthProviderInfos.FirstOrDefault(x => (int)x.Key == (int)kvp.Key); - return info != null - && info.Value.ServerUrl == kvp.Value.ServerUrl - && info.Value.ClientId == kvp.Value.ClientId - && info.Value.RedirectUri == kvp.Value.RedirectUri; - })); + var result = restServerInfo.OAuthProviderInfos == gqlServerInfo.Swarm.CurrentNode.Gateway.Information.OAuthProviderInfos + || restServerInfo.OAuthProviderInfos.All(kvp => + { + var info = gqlServerInfo.Swarm.CurrentNode.Gateway.Information.OAuthProviderInfos.FirstOrDefault(x => (int)x.Key == (int)kvp.Key); + return info != null + && info.Value.ServerUrl == kvp.Value.ServerUrl + && info.Value.ClientId == kvp.Value.ClientId + && info.Value.RedirectUri == kvp.Value.RedirectUri; + }); return result; }, diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 6da26320aa..a0809b78f6 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -32,7 +32,7 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.System; using Tgstation.Server.Api.Models; using Tgstation.Server.Tests.Live; -using Tgstation.Server.Host.Utils; +using Tgstation.Server.Host.Properties; namespace Tgstation.Server.Tests { @@ -75,14 +75,23 @@ namespace Tgstation.Server.Tests } [TestMethod] - public void TestApiVersion() + public void TestRestVersion() { - var versionString = versionsPropertyGroup.Element(xmlNamespace + "TgsApiVersion").Value; + var versionString = versionsPropertyGroup.Element(xmlNamespace + "TgsRestVersion").Value; Assert.IsNotNull(versionString); Assert.IsTrue(Version.TryParse(versionString, out var expected)); Assert.AreEqual(expected, ApiHeaders.Version); } + [TestMethod] + public void TestGraphQLVersion() + { + var versionString = versionsPropertyGroup.Element(xmlNamespace + "TgsGraphQLVersion").Value; + Assert.IsNotNull(versionString); + Assert.IsTrue(Version.TryParse(versionString, out var expected)); + Assert.AreEqual(expected, Version.Parse(MasterVersionsAttribute.Instance.RawGraphQLVersion)); + } + [TestMethod] public void TestApiLibraryVersion() { diff --git a/tools/Tgstation.Server.ReleaseNotes/Component.cs b/tools/Tgstation.Server.ReleaseNotes/Component.cs index d1baa3fcda..b983aebc87 100644 --- a/tools/Tgstation.Server.ReleaseNotes/Component.cs +++ b/tools/Tgstation.Server.ReleaseNotes/Component.cs @@ -6,7 +6,8 @@ Core, HostWatchdog, WebControlPanel, - HttpApi, + RestApi, + GraphQLApi, DreamMakerApi, InteropApi, NugetCommon, diff --git a/tools/Tgstation.Server.ReleaseNotes/Program.cs b/tools/Tgstation.Server.ReleaseNotes/Program.cs index 801d10e779..3e64ff565b 100644 --- a/tools/Tgstation.Server.ReleaseNotes/Program.cs +++ b/tools/Tgstation.Server.ReleaseNotes/Program.cs @@ -91,8 +91,11 @@ namespace Tgstation.Server.ReleaseNotes case "--NO-CLOSE": doNotCloseMilestone = true; break; - case "--HTTPAPI": - componentRelease = Component.HttpApi; + case "--RESTAPI": + componentRelease = Component.RestApi; + break; + case "--GRAPHQLAPI": + componentRelease = Component.GraphQLApi; break; case "--INTEROPAPI": componentRelease = Component.InteropApi; @@ -245,7 +248,8 @@ namespace Tgstation.Server.ReleaseNotes return 10; } - var apiVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsApiVersion").Value); + var restVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsRestVersion").Value); + var graphQLVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsGraphQLVersion").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); @@ -255,7 +259,7 @@ namespace Tgstation.Server.ReleaseNotes if (webControlVersion.Major == 0) postControlPanelMessage = true; - prefix = $"Please refer to the [README](https://github.com/tgstation/tgstation-server#setup) for setup instructions. Full changelog can be found [here](https://raw.githubusercontent.com/tgstation/tgstation-server/gh-pages/changelog.yml).{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}"; + prefix = $"Please refer to the [README](https://github.com/tgstation/tgstation-server#setup) for setup instructions. Full changelog can be found [here](https://raw.githubusercontent.com/tgstation/tgstation-server/gh-pages/changelog.yml).{Environment.NewLine}{Environment.NewLine}#### Component Versions\nCore: {coreVersion}\nConfiguration: {configVersion}\nREST API: {restVersion}\nGraphQL API{(graphQLVersion.Major < 1 ? " (Pre-release)" : String.Empty)}: {graphQLVersion}\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) @@ -409,7 +413,7 @@ namespace Tgstation.Server.ReleaseNotes var componentVersionDict = new Dictionary { { Component.Configuration, configVersion }, - { Component.HttpApi, apiVersion }, + { Component.RestApi, restVersion }, { Component.DreamMakerApi, dmApiVersion }, { Component.InteropApi, interopVersion }, { Component.WebControlPanel, webControlVersion }, @@ -508,7 +512,7 @@ namespace Tgstation.Server.ReleaseNotes static string GetComponentDisplayName(Component component, bool debian) => component switch { - Component.HttpApi => debian ? "the HTTP API" : "HTTP API", + Component.RestApi => debian ? "the REST API" : "REST API", Component.InteropApi => debian ? "the Interop API" : "Interop API", Component.Configuration => debian ? "the TGS configuration" : "**Configuration**", Component.DreamMakerApi => debian ? "the DreamMaker API" : "DreamMaker API", @@ -607,7 +611,8 @@ namespace Tgstation.Server.ReleaseNotes var dict = new Dictionary { { Component.Core, Parse("TgsCoreVersion") }, - { Component.HttpApi, Parse("TgsApiVersion") }, + { Component.RestApi, Parse("TgsRestVersion") }, + { Component.GraphQLApi, Parse("TgsGraphQLVersion") }, { Component.DreamMakerApi, Parse("TgsDmapiVersion") }, }; @@ -720,7 +725,8 @@ namespace Tgstation.Server.ReleaseNotes component = targetComponent.ToUpperInvariant() switch { "**CONFIGURATION**" or "CONFIGURATION" or "CONFIG" => Component.Configuration, - "HTTP API" => Component.HttpApi, + "HTTP API" or "REST API" => Component.RestApi, + "GQL API" or "GRAPHQL API" or "GQL" or "GRAPHQL" => Component.GraphQLApi, "WEB CONTROL PANEL" => Component.WebControlPanel, "DMAPI" or "DREAMMAKER API" => Component.DreamMakerApi, "INTEROP API" => Component.InteropApi, @@ -1161,7 +1167,7 @@ Note: `` is the directory's name containing the manifest you're submitting var nugetClientVersions = EnumerateNugetVersions("Tgstation.Server.Client"); var newDic = new Dictionary> { - { Component.HttpApi, releases + { Component.RestApi, releases .Where(x => x.TagName.StartsWith("api-v")) .Select(x => Version.Parse(x.TagName[5..])) .OrderBy(x => x)