Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

* F# 10, C# 14, .NET 10, nullability checks enabled
* .NET SDK roll-forward policy in #file:'global.json'; the exact SDK version is pinned in the GitHub workflows and #file:'build/Program.fs'
* Never change the pinned .NET SDK version without moving `FSharpCoreVersion` in #file:'Packages.props' to the FSharp.Core version that SDK ships – the `FSharp.Core.<version>.nupkg` in `sdk/<SDK version>/FSharp/library-packs` of the installation (for example, SDK 10.0.401 ships FSharp.Core 10.1.401). A compiler older than the referenced FSharp.Core may not behave correctly (see the [FSharp.Core notes](https://github.com/dotnet/fsharp/blob/main/docs/fsharp-core-notes.md)), so the SDK and FSharp.Core versions always change together, in the same commit
* Common parameters specified in #file:'Directory.Build.props'
* Central NuGet package version management – versions go in #file:'Packages.props', not in `.fsproj` files
* Build: `dotnet build FSharp.Data.GraphQL.slnx`
Expand Down Expand Up @@ -267,9 +268,10 @@ During the implementation, if you need some types or members defined in the othe

## Testing

* Tests use xUnit.
* Tests use xUnit.net v3 on Microsoft.Testing.Platform (MTP): #file:'global.json' switches `dotnet test` to MTP mode.
* If you work with tests, then do not build the whole solution as it is large and the build happens very slow. Run the tests individually or the whole test project instead.
* Prefer running tests through the IDE's MCP test tools; fall back to the `--no-build` switch of `dotnet test` first to speed up execution when those tools are unavailable or fail to run the tests, and use the trx format for results so failures can be consumed and fixed.
* In MTP mode pass the project through `--project` and request TRX results with `--report-xunit-trx --report-xunit-trx-filename <name>.trx`. VSTest switches such as `--logger` are rejected, while `--filter` still takes the VSTest filter syntax.
* Use `Assert.Equal`, `Assert.Collection`, `Assert.Contains` / `Assert.DoesNotContain`, `Assert.Empty` / `Assert.NotEmpty` and `Assert.Single` for collection assertions – they work directly with F# lists, arrays and sequences.
* Every assertion should produce a self-explanatory failure output.
* Async tests must return `Task`, not `Async` or `Task<unit>` – always declare `) : Task = task {`.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
env:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
DOTNET_NOLOGO: true
DOTNET_SDK_VERSION: 10.0.303
DOTNET_SDK_VERSION: 10.0.401

jobs:
publish:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ env:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
DOTNET_NOLOGO: true
SLEEP_DURATION: 60
DOTNET_SDK_VERSION: 10.0.303
DOTNET_SDK_VERSION: 10.0.401

jobs:
publish:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-22.04, windows-latest, macOS-latest]
dotnet: [10.0.303]
dotnet: [10.0.401]
runs-on: ${{ matrix.os }}

steps:
Expand Down
28 changes: 11 additions & 17 deletions Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
<SystemVersion>10.0.*</SystemVersion>
<MicrosoftExtensionsVersion>10.0.*</MicrosoftExtensionsVersion>
<AspNetCoreVersion>10.0.*</AspNetCoreVersion>
<FSharpCoreVersion>10.1.202</FSharpCoreVersion>
<FsToolkitVersion>4.17.*</FsToolkitVersion>
<XUnitVersion>2.9.3</XUnitVersion>
<FSharpCoreVersion>10.1.401</FSharpCoreVersion>
<FsToolkitVersion>5.*</FsToolkitVersion>
<XUnitVersion>4.*</XUnitVersion>
<FAKEVersion>6.*</FAKEVersion>
</PropertyGroup>
<ItemGroup Label="Common">
Expand All @@ -19,7 +19,6 @@
<PackageReference Update="FSharp.Control.Reactive" Version="6.*" />
<PackageReference Update="FSharp.SystemTextJson" Version="1.*" />
<PackageReference Update="FsToolkit.ErrorHandling" Version="$(FsToolkitVersion)" />
<PackageReference Update="FsToolkit.ErrorHandling.TaskResult" Version="$(FsToolkitVersion)" />
<PackageReference Update="Giraffe" Version="7.*" />
<PackageReference Update="IcedTasks" Version="0.11.*" />
<PackageReference Update="Microsoft.Bcl.AsyncInterfaces" Version="$(SystemVersion)" />
Expand Down Expand Up @@ -55,18 +54,14 @@
<ItemGroup Label="Test platform">
<PackageReference Update="BenchmarkDotNet" Version="0.15.*" />
<PackageReference Update="BenchmarkDotNet.Annotations" Version="0.*" />
<PackageReference Update="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Update="Microsoft.TestPlatform.TestHost" Version="17.7.*" />
<PackageReference Update="Microsoft.TestPlatform.ObjectModel" Version="17.7.*" />
<PackageReference Update="xunit" Version="$(XUnitVersion)" />
<PackageReference Update="xunit.analyzers" Version="1.*" />
<PackageReference Update="xunit.assert" Version="$(XUnitVersion)" />
<PackageReference Update="xunit.core" Version="$(XUnitVersion)" />
<PackageReference Update="xunit.extensibility.core" Version="$(XUnitVersion)" />
<PackageReference Update="xunit.extensibility.execution" Version="$(XUnitVersion)" />
<PackageReference Update="xunit.runner.console" Version="$(XUnitVersion)" />
<PackageReference Update="xunit.runner.utility" Version="$(XUnitVersion)" />
<PackageReference Update="xunit.runner.visualstudio" Version="3.1.4" />
<PackageReference Update="Microsoft.Testing.Extensions.CodeCoverage" Version="18.*" />
<PackageReference Update="xunit.analyzers" Version="2.*" />
<PackageReference Update="xunit.v3" Version="$(XUnitVersion)" />
<PackageReference Update="xunit.v3.assert" Version="$(XUnitVersion)" />
<PackageReference Update="xunit.v3.core" Version="$(XUnitVersion)" />
<PackageReference Update="xunit.v3.extensibility.core" Version="$(XUnitVersion)" />
<PackageReference Update="xunit.v3.runner.console" Version="$(XUnitVersion)" />
<PackageReference Update="xunit.v3.runner.utility" Version="$(XUnitVersion)" />
</ItemGroup>
<ItemGroup Label="Tests and Samples">
<PackageReference Update="Azure.Core" Version="1.*" />
Expand All @@ -82,7 +77,6 @@
<PackageReference Update="Iced" Version="1.17.*" />
<PackageReference Update="Microsoft.AspNetCore.Mvc.Testing" Version="$(AspNetCoreVersion)" />
<PackageReference Update="Microsoft.Azure.Cosmos" Version="3.*" />
<PackageReference Update="Microsoft.CodeCoverage" Version="17.3.*" />
<PackageReference Update="Microsoft.Data.Sqlite" Version="$(MicrosoftExtensionsVersion)" />
<PackageReference Update="SQLitePCLRaw.lib.e_sqlite3" Version="3.53.3" />
<PackageReference Update="Microsoft.Diagnostics.NETCore.Client" Version="0.2.*" />
Expand Down
1 change: 1 addition & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@
* **Breaking Change** `BufferedStreamOptions.Interval` and `BufferedStreamOptions.PreferredBatchSize` are now `int voption`
* **Breaking Change** `ServerMessage.Error` and `ServerRawPayload.ErrorMessages` now carry `GQLProblemDetails list` instead of `NameValueLookup list`, so an `error` message's `payload` is a standard GraphQL error array as the `graphql-transport-ws` protocol requires
* **Breaking Change** A query or mutation whose non-null root field fails during execution now produces a `Direct` (execution) result with `null` data instead of a `RequestError`, which is now only ever produced for a request rejected before execution (validation, planning, variable or inline argument coercion, a middleware, or the executor itself failing); HTTP and `graphql-transport-ws` responses for such a failure now carry `data: null` as the spec requires, instead of omitting `data` entirely. This also changes the public `GQLResponse.Data`, `GQLResponseContent.Direct.Data`, `DeferredErrors.Data`, and `SubscriptionErrors.Data` signatures to use `voption`
* **Breaking Change** Updated `FsToolkit.ErrorHandling` to 5.x, which merged `FsToolkit.ErrorHandling.TaskResult` into the main package: a project referencing `FsToolkit.ErrorHandling.TaskResult` must remove that reference. See the [FsToolkit.ErrorHandling 5.0.0 release notes](https://github.com/demystifyfp/FsToolkit.ErrorHandling/blob/master/RELEASE_NOTES.md#500---june-02-2025) for its other breaking changes, such as `retn` renamed to `singleton`, `returnError` renamed to `error` and `and!` removed from `result { }`
* Added case-insensitive string comparison support to `ObjectListFilter`, including comparer-aware filter cases and GraphQL filter suffix handling
* Improved Relay XML documentation comments
* Changed query planning to throw `MalformedGQLQueryException` for invalid queries, `NotSupportedException` for unsupported type definition implementations and `InvalidOperationException` for internal planning errors instead of `System.Exception`, with messages naming the affected field, type and execution kind
Expand Down
64 changes: 35 additions & 29 deletions build/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ let ctx = Context.forceFakeContext ()
let embedAll = ctx.Arguments |> List.exists (fun arg -> arg = BuildArguments.EmbedAll)

module DotNetCli =
let setVersion (o : DotNet.Options) = { o with Version = Some "10.0.303" }
let setVersion (o : DotNet.Options) = { o with Version = Some "10.0.401" }
let setRestoreOptions (o : DotNet.RestoreOptions) = o.WithCommon setVersion

let configurationString = Environment.environVarOrDefault "CONFIGURATION" "Release"
Expand Down Expand Up @@ -114,36 +114,42 @@ let runTests (project : string) (resultsFileName : string) (filter : string vopt
if File.Exists resultsFilePath then
File.Delete resultsFilePath

DotNet.test
(fun options ->
{
options with
NoBuild = true
Logger = Some $"trx;LogFileName={resultsFileName}"
ResultsDirectory = Some TestResultsDirectory
Framework = Some DotNetMoniker
Configuration = configuration
Common = {
options.Common with
CustomParams = filter |> ValueOption.map (fun filter -> $"--filter {filter}") |> ValueOption.toOption
}
MSBuildParams = {
options.MSBuildParams with
DisableInternalBinLog = true
Verbosity = Some Normal
Properties = [
if embedAll then
("DebugType", "embedded")
("EmbedAllSources", "true")
]
}
}
|> _.WithRedirectOutput(true)
|> _.WithCommon(DotNetCli.setVersion))
// global.json runs `dotnet test` on Microsoft.Testing.Platform, which takes the project only through `--project`
// and leaves the TRX report to the xUnit.net test application. DotNet.test cannot produce that command line:
// it passes the project positionally after its other options and asks for the report through the VSTest `--logger`
let args = [
"--project"
project
"--no-build"
"--configuration"
configurationString
"--framework"
DotNetMoniker
"--results-directory"
TestResultsDirectory
"--verbosity"
"normal"
if embedAll then
"-p:DebugType=embedded"
"-p:EmbedAllSources=true"
"--report-xunit-trx"
"--report-xunit-trx-filename"
resultsFileName
match filter with
| ValueSome filter ->
"--filter"
filter
| ValueNone -> ()
]

let result =
DotNet.exec (fun options -> options.WithRedirectOutput true |> DotNetCli.setVersion) "test" (Args.toWindowsCommandLine args)

if not result.OK then
failwith $"'dotnet test {project}' failed with exit code %i{result.ExitCode}"

// `dotnet test --no-build` on a project that was never restored does not import the test SDK,
// so it runs nothing and still exits with 0. The missing results file is the only trace of that.
// `dotnet test --no-build` cannot tell that a project which was never restored is a test project,
// so it may run nothing and still exit with 0. The missing results file is the only trace of that.
if not (File.Exists resultsFilePath) then
failwith $"'dotnet test {project}' produced no test results at '{resultsFilePath}'. Was the project restored and built?"

Expand Down
3 changes: 3 additions & 0 deletions global.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@
"sdk": {
"rollForward": "latestMinor"
},
"test": {
"runner": "Microsoft.Testing.Platform"
},
"projects": [ "src", "tests" ]
}
2 changes: 1 addition & 1 deletion samples/chat-app/server/chat-app.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FsToolkit.ErrorHandling.TaskResult" />
<PackageReference Include="FsToolkit.ErrorHandling" />
<PackageReference Include="GraphQL.Server.Ui.Altair" />
<PackageReference Include="GraphQL.Server.Ui.GraphiQL" />
<PackageReference Include="GraphQL.Server.Ui.Voyager" />
Expand Down
2 changes: 1 addition & 1 deletion samples/star-wars-api/star-wars-api.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<ItemGroup Label="PackageReferences">
<PackageReference Include="FSharp.Control.TaskSeq" />
<PackageReference Include="FsToolkit.ErrorHandling.TaskResult" />
<PackageReference Include="FsToolkit.ErrorHandling" />
<PackageReference Include="GraphQL.Server.Ui.Altair" />
<PackageReference Include="GraphQL.Server.Ui.GraphiQL" />
<PackageReference Include="GraphQL.Server.Ui.Voyager" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<!-- This excludes FSharp.Core.xml and FSharp.Core.resources.dll while referencing the right FSharp.Core.dll version -->
<ExcludeAssets>contentFiles;runtime</ExcludeAssets>
</PackageReference>
<PackageReference Include="FSharp.TypeProviders.SDK" VersionOverride="8.10.0" />
<PackageReference Include="FSharp.TypeProviders.SDK" VersionOverride="8.11.0" />
<PackageReference Include="FsToolkit.ErrorHandling" />
<PackageReference Include="FParsec" />
<PackageReference Include="Microsoft.Extensions.Http">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
<ItemGroup>
<PackageReference Include="Collections.Pooled" />
<PackageReference Include="FsToolkit.ErrorHandling" />
<PackageReference Include="FsToolkit.ErrorHandling.TaskResult" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
<ItemGroup>
<PackageReference Include="Collections.Pooled" />
<PackageReference Include="FsToolkit.ErrorHandling" />
<PackageReference Include="FsToolkit.ErrorHandling.TaskResult" />
<PackageReference Include="Giraffe" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
<ItemGroup>
<PackageReference Include="Collections.Pooled" />
<PackageReference Include="FsToolkit.ErrorHandling" />
<PackageReference Include="FsToolkit.ErrorHandling.TaskResult" />
<PackageReference Include="Oxpecker" />
</ItemGroup>

Expand Down
2 changes: 1 addition & 1 deletion src/FSharp.Data.GraphQL.Server/Execution.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1218,7 +1218,7 @@ let internal coerceVariables
})
(variablesBuilder |> Ok)

and! nulls = nulls |> splitSeqErrorsList
let! nulls = nulls |> splitSeqErrorsList

nulls |> Array.iter variablesBuilder.Add

Expand Down
4 changes: 2 additions & 2 deletions src/FSharp.Data.GraphQL.Server/Planning.fs
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,13 @@ let private getIncluder (directives: Directive list) parentIncluder : Includer =
| "skip" ->
fun vars -> result {
let! accValue = acc vars
and! skipValue = directiveIncluder directive vars
let! skipValue = directiveIncluder directive vars
return accValue && not(skipValue)
}
| "include" ->
fun vars -> result {
let! accValue = acc vars
and! includeValue = directiveIncluder directive vars
let! includeValue = directiveIncluder directive vars
return accValue && includeValue
}
| _ -> acc) parentIncluder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FsToolkit.ErrorHandling.TaskResult" />
<PackageReference Include="Giraffe" />
<PackageReference Include="GraphQL.Server.Ui.Voyager" />
<PackageReference Include="HotChocolate.AspNetCore" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" />
<PackageReference Include="Microsoft.Extensions.Http" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio" />
<PackageReference Include="Microsoft.Testing.Extensions.CodeCoverage" />
<PackageReference Include="xunit.v3" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
"appDomain": "denied",
"maxParallelThreads": -1,
"parallelizeAssembly": true
}
7 changes: 7 additions & 0 deletions tests/FSharp.Data.GraphQL.Tests/AssemblyInfo.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace FSharp.Data.GraphQL.Tests

open Xunit.Sdk
open Xunit.v3

[<assembly: Parallelization(Mode = ParallelMode.None)>]
do ()
11 changes: 5 additions & 6 deletions tests/FSharp.Data.GraphQL.Tests/FSharp.Data.GraphQL.Tests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<PropertyGroup>
<TargetFramework>$(DotNetVersion)</TargetFramework>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateProgramFile>false</GenerateProgramFile>
<OutputType>Exe</OutputType>

<Description>FSharp implementation of Facebook GraphQL query language (Server)</Description>
Expand All @@ -17,14 +16,14 @@
<ItemGroup>
<PackageReference Include="Azure.Core" />
<PackageReference Include="Microsoft.Azure.Cosmos" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<!-- Microsoft.Azure.Cosmos needs Newtonsoft.Json at run time but leaves the reference to the consuming project -->
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="BenchmarkDotNet" />
<PackageReference Include="FSharp.Control.TaskSeq" />
<PackageReference Include="IcedTasks" />
<PackageReference Include="Validus" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.utility" />
<PackageReference Include="xunit.runner.visualstudio" />
<PackageReference Include="Microsoft.Testing.Extensions.CodeCoverage" />
<PackageReference Include="xunit.v3" />
</ItemGroup>

<ItemGroup>
Expand Down Expand Up @@ -105,7 +104,7 @@
<Compile Include="AspNetCore/SubscriptionWorkerTests.fs" />
<Compile Include="AspNetCore/WebSocketConnectionTests.fs" />
<Compile Include="TaskSeqFieldTests.fs" />
<Compile Include="Program.fs" />
<Compile Include="AssemblyInfo.fs" />
</ItemGroup>

<ItemGroup>
Expand Down
21 changes: 0 additions & 21 deletions tests/FSharp.Data.GraphQL.Tests/Program.fs

This file was deleted.

6 changes: 3 additions & 3 deletions tests/FSharp.Data.GraphQL.Tests/TestAttributes.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@ namespace FSharp.Data.GraphQL.Tests

open System
open System.Globalization
open Xunit.Sdk
open Xunit.v3

type UseInvariantCultureAttribute() =
inherit BeforeAfterTestAttribute()

let mutable _originalUICulture: CultureInfo = null
let mutable _originalCulture: CultureInfo = null

override _.Before (methodUnderTest) =
override _.Before (methodUnderTest, test) =
_originalUICulture <- CultureInfo.CurrentUICulture
_originalCulture <- CultureInfo.CurrentCulture

CultureInfo.CurrentUICulture <- CultureInfo.InvariantCulture
CultureInfo.CurrentCulture <- CultureInfo.InvariantCulture

override _.After (methodUnderTest) =
override _.After (methodUnderTest, test) =
CultureInfo.CurrentUICulture <- _originalUICulture
CultureInfo.CurrentCulture <- _originalCulture

Expand Down
Loading
Loading