Use DOTNET_STARTUP_HOOK to have the target run the tests (#91)

This commit is contained in:
Patrick Stevens
2024-06-23 17:25:24 +01:00
committed by GitHub
parent 85cd116d52
commit fb945c04ac
17 changed files with 366 additions and 64 deletions

View File

@@ -38,7 +38,7 @@ jobs:
- name: Build
run: 'nix develop --command dotnet build --no-restore --configuration ${{matrix.config}}'
- name: Test
run: 'nix develop --command dotnet test --no-build --verbosity normal --configuration ${{matrix.config}}'
run: 'nix develop --command dotnet test --no-build --verbosity normal --configuration ${{matrix.config}} --framework net8.0'
selftest:
runs-on: ubuntu-latest
@@ -57,10 +57,6 @@ jobs:
security-events: none
statuses: read
strategy:
matrix:
framework: ["net6.0", "net8.0"]
steps:
- uses: actions/checkout@v4
with:
@@ -75,7 +71,49 @@ jobs:
- name: Build
run: 'nix develop --command dotnet build --no-restore --configuration Release'
- name: Test using self
run: 'nix develop --command dotnet exec ./WoofWare.NUnitTestRunner/bin/Release/net8.0/WoofWare.NUnitTestRunner.dll ./Consumer/bin/Release/${{matrix.framework}}/Consumer.dll --trx TrxOut/out.trx'
run: 'nix develop --command dotnet exec ./WoofWare.NUnitTestRunner/bin/Release/net6.0/WoofWare.NUnitTestRunner.dll ./Consumer/bin/Release/net8.0/Consumer.dll --trx TrxOut/out.trx'
- name: Parse Trx files
uses: NasAmin/trx-parser@v0.6.0
if: always()
id: trx-parser
with:
TRX_PATH: ${{ github.workspace }}/TrxOut
REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
selftest-net6:
runs-on: ubuntu-latest
permissions:
actions: none
checks: write
contents: read
deployments: none
id-token: none
issues: none
discussions: none
packages: none
pages: none
pull-requests: read
repository-projects: none
security-events: none
statuses: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
- name: Install Nix
uses: cachix/install-nix-action@V27
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Restore dependencies
run: nix develop --command dotnet restore
- name: Build runner
run: 'nix develop --command dotnet build WoofWare.NUnitTestRunner --configuration Release'
- name: Build target
run: 'nix develop --command dotnet build Consumer --configuration Release'
- name: Test using self
run: 'nix develop .#net6 --command ./WoofWare.NUnitTestRunner/bin/Release/net6.0/WoofWare.NUnitTestRunner ./Consumer/bin/Release/net6.0/Consumer.dll --trx TrxOut/out.trx'
- name: Parse Trx files
uses: NasAmin/trx-parser@v0.6.0
if: always()

View File

@@ -9,6 +9,7 @@
<ItemGroup>
<Compile Include="NoAttribute.fs" />
<Compile Include="Inconclusive.fs" />
<Compile Include="RunSubProcess.fs" />
<Compile Include="TestNonParallel.fs" />
<Compile Include="TestParallel.fs" />
<Compile Include="TestStdout.fs" />

45
Consumer/RunSubProcess.fs Normal file
View File

@@ -0,0 +1,45 @@
namespace Consumer
open System
open System.Diagnostics
open System.IO
open System.IO.Compression
open System.Text
open NUnit.Framework
open FsUnitTyped
[<TestFixture>]
module RunSubProcess =
[<Test>]
let ``Run a subprocess`` () =
let exe = "/bin/bash"
let args = [ "-c" ; "echo hi >&2 && echo bye" ]
let workingDir = None
let psi =
ProcessStartInfo (
exe,
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
WorkingDirectory = Option.toObj workingDir
)
for arg in args do
psi.ArgumentList.Add arg
psi.EnvironmentVariables.Add ("THING", Path.Combine (AppDomain.CurrentDomain.BaseDirectory, "hi"))
let stderr = StringBuilder ()
use proc = new Process (StartInfo = psi)
proc.OutputDataReceived.Add (fun e -> printfn $"%s{e.Data}")
proc.ErrorDataReceived.Add (fun e ->
eprintfn $"%s{e.Data}"
stderr.AppendLine e.Data |> ignore
)
proc.Start () |> shouldEqual true
proc.BeginOutputReadLine ()
proc.BeginErrorReadLine ()
proc.WaitForExit ()

View File

@@ -1,34 +0,0 @@
namespace WoofWare.NUnitTestRunner
open System
open System.IO
open System.Reflection
// Fix for https://github.com/Smaug123/unofficial-nunit-runner/issues/8
// (This tells the DLL loader to look next to the test DLL for dependencies.)
// TODO: do we actually need this when we move to the Hooks world?
/// Context manager to set the AppContext.BaseDirectory of the executing DLL.
type SetBaseDir (testDll : FileInfo) =
let oldBaseDir = AppContext.BaseDirectory
let setData =
let appContext = Type.GetType "System.AppContext"
if Object.ReferenceEquals (appContext, (null : obj)) then
ignore<string * string>
else
let setDataMethod =
appContext.GetMethod ("SetData", BindingFlags.Static ||| BindingFlags.Public)
if Object.ReferenceEquals (setDataMethod, (null : obj)) then
ignore<string * string>
else
fun (k, v) -> setDataMethod.Invoke ((null : obj), [| k ; v |]) |> unbox<unit>
do setData ("APP_CONTEXT_BASE_DIRECTORY", testDll.Directory.FullName)
interface IDisposable with
member _.Dispose () =
setData ("APP_CONTEXT_BASE_DIRECTORY", oldBaseDir)

View File

@@ -89,8 +89,13 @@ type TestContexts =
AsyncLocal = local
}
member internal this.Stdout : TextWriter = this.StdOutWriter
member internal this.Stderr : TextWriter = this.StdErrWriter
/// An output stream which will identify the ExecutionContext it's being written to from,
/// and will separate that output into its own stream internally.
member this.Stdout : TextWriter = this.StdOutWriter
/// An output stream which will identify the ExecutionContext it's being written to from,
/// and will separate that output into its own stream internally.
member this.Stderr : TextWriter = this.StdErrWriter
member internal this.DumpStdout (id : OutputStreamId) : string =
lock

View File

@@ -243,8 +243,6 @@ WoofWare.NUnitTestRunner.ParallelQueue.Run [method]: WoofWare.NUnitTestRunner.Te
WoofWare.NUnitTestRunner.ParallelQueue.RunTestSetup [method]: WoofWare.NUnitTestRunner.TestFixtureRunningToken -> (unit -> 'a) -> ('a * WoofWare.NUnitTestRunner.TestFixtureSetupToken) System.Threading.Tasks.Task
WoofWare.NUnitTestRunner.ParallelQueue.RunTestTearDown [method]: WoofWare.NUnitTestRunner.TestFixtureSetupToken -> (unit -> 'a) -> ('a * WoofWare.NUnitTestRunner.TestFixtureTearDownToken) System.Threading.Tasks.Task
WoofWare.NUnitTestRunner.ParallelQueue.StartTestFixture [method]: WoofWare.NUnitTestRunner.TestFixture -> WoofWare.NUnitTestRunner.TestFixtureRunningToken System.Threading.Tasks.Task
WoofWare.NUnitTestRunner.SetBaseDir inherit obj, implements IDisposable
WoofWare.NUnitTestRunner.SetBaseDir..ctor [constructor]: System.IO.FileInfo
WoofWare.NUnitTestRunner.SingleTestMethod inherit obj, implements WoofWare.NUnitTestRunner.SingleTestMethod System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.SingleTestMethod..ctor [constructor]: (System.Reflection.MethodInfo, WoofWare.NUnitTestRunner.TestKind, WoofWare.NUnitTestRunner.Modifier list, string list, int option, WoofWare.NUnitTestRunner.Combinatorial option, unit WoofWare.NUnitTestRunner.Parallelizable option)
WoofWare.NUnitTestRunner.SingleTestMethod.Categories [property]: [read-only] string list
@@ -267,6 +265,10 @@ WoofWare.NUnitTestRunner.SingleTestMethodModule inherit obj
WoofWare.NUnitTestRunner.SingleTestMethodModule.parse [static method]: string list -> System.Reflection.MethodInfo -> System.Reflection.CustomAttributeData list -> (WoofWare.NUnitTestRunner.SingleTestMethod option * System.Reflection.CustomAttributeData list)
WoofWare.NUnitTestRunner.TestContexts inherit obj, implements WoofWare.NUnitTestRunner.TestContexts System.IEquatable, System.Collections.IStructuralEquatable, IDisposable
WoofWare.NUnitTestRunner.TestContexts.Empty [static method]: unit -> WoofWare.NUnitTestRunner.TestContexts
WoofWare.NUnitTestRunner.TestContexts.get_Stderr [method]: unit -> System.IO.TextWriter
WoofWare.NUnitTestRunner.TestContexts.get_Stdout [method]: unit -> System.IO.TextWriter
WoofWare.NUnitTestRunner.TestContexts.Stderr [property]: [read-only] System.IO.TextWriter
WoofWare.NUnitTestRunner.TestContexts.Stdout [property]: [read-only] System.IO.TextWriter
WoofWare.NUnitTestRunner.TestFailure inherit obj, implements WoofWare.NUnitTestRunner.TestFailure System.IEquatable, System.Collections.IStructuralEquatable - union type with 3 cases
WoofWare.NUnitTestRunner.TestFailure+SetUpFailed inherit WoofWare.NUnitTestRunner.TestFailure
WoofWare.NUnitTestRunner.TestFailure+SetUpFailed.get_Item [method]: unit -> WoofWare.NUnitTestRunner.UserMethodFailure
@@ -397,6 +399,7 @@ WoofWare.NUnitTestRunner.TestMemberSuccess.Ok [static property]: [read-only] Woo
WoofWare.NUnitTestRunner.TestMemberSuccess.Tag [property]: [read-only] int
WoofWare.NUnitTestRunner.TestProgress inherit obj
WoofWare.NUnitTestRunner.TestProgress.toStderr [static method]: unit -> WoofWare.NUnitTestRunner.ITestProgress
WoofWare.NUnitTestRunner.TestProgress.toWriter [static method]: System.IO.TextWriter -> WoofWare.NUnitTestRunner.ITestProgress
WoofWare.NUnitTestRunner.TrxCounters inherit obj, implements WoofWare.NUnitTestRunner.TrxCounters System.IEquatable, System.Collections.IStructuralEquatable
WoofWare.NUnitTestRunner.TrxCounters..ctor [constructor]: (System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32, System.UInt32)
WoofWare.NUnitTestRunner.TrxCounters.Aborted [property]: [read-only] System.UInt32

View File

@@ -1,6 +1,7 @@
namespace WoofWare.NUnitTestRunner
open System
open System.IO
/// Represents something which knows how to report progress through a test suite.
/// Note that we don't guarantee anything about parallelism; you must make sure
@@ -24,22 +25,25 @@ type ITestProgress =
/// Methods for constructing specific ITestProgress objects.
[<RequireQualifiedAccess>]
module TestProgress =
/// An ITestProgress which logs to stderr.
let toStderr () : ITestProgress =
/// An ITestProgress which logs to the given writer.
let toWriter (writer : TextWriter) : ITestProgress =
{ new ITestProgress with
member _.OnTestFixtureStart name testCount =
let plural = if testCount = 1 then "" else "s"
Console.Error.WriteLine $"Running test fixture: %s{name} (%i{testCount} test%s{plural} to run)"
writer.WriteLine $"Running test fixture: %s{name} (%i{testCount} test%s{plural} to run)"
member _.OnTestMemberStart name =
Console.Error.WriteLine $"Running test: %s{name}"
writer.WriteLine $"Running test: %s{name}"
member _.OnTestFailed name failure =
Console.Error.WriteLine $"Test failed: %O{failure}"
writer.WriteLine $"Test failed: %O{failure}"
member _.OnTestMemberFinished name =
Console.Error.WriteLine $"Finished test %s{name}"
writer.WriteLine $"Finished test %s{name}"
member _.OnTestMemberSkipped name =
Console.Error.WriteLine $"Skipping test due to filter: %s{name}"
writer.WriteLine $"Skipping test due to filter: %s{name}"
}
/// An ITestProgress which logs to stderr.
let toStderr () : ITestProgress = toWriter Console.Error

View File

@@ -19,7 +19,6 @@
<ItemGroup>
<Compile Include="AssemblyInfo.fs" />
<Compile Include="AppContext.fs" />
<Compile Include="RuntimeConfig.fs" />
<Compile Include="GeneratedRuntimeConfig.fs">
<MyriadFile>RuntimeConfig.fs</MyriadFile>

View File

@@ -1,5 +1,5 @@
{
"version": "0.15",
"version": "0.16",
"publicReleaseRefSpec": [
"^refs/heads/main$"
],

View File

@@ -0,0 +1,35 @@
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using WoofWare.NUnitTestRunner.StartupHook;
namespace WoofWare.NUnitTestRunner.StartupHook
{
internal class StartupAssemblyLoadContext : AssemblyLoadContext
{
private readonly AssemblyDependencyResolver _resolver;
public StartupAssemblyLoadContext()
{
_resolver = new AssemblyDependencyResolver(Assembly.GetExecutingAssembly().Location);
}
protected override Assembly Load(AssemblyName assemblyName)
{
var assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
return assemblyPath != null ? LoadFromAssemblyPath(assemblyPath) : null;
}
}
}
// Must be internal and called `StartupHook`
internal class StartupHook
{
public static void Initialize()
{
var loadContext = new StartupAssemblyLoadContext();
var assembly = loadContext.LoadFromAssemblyName(new AssemblyName("WoofWare.NUnitTestRunner.StartupHookLogic"));
assembly.DefinedTypes.First(x => x.Name == "StartupHookLogic").GetDeclaredMethod("DoIt")!.Invoke(null, null);
}
}

View File

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\WoofWare.NUnitTestRunner.StartupHookLogic\WoofWare.NUnitTestRunner.StartupHookLogic.csproj" />
<ProjectReference Include="..\WoofWare.NUnitTestRunner.Lib\WoofWare.NUnitTestRunner.Lib.fsproj"/>
</ItemGroup>
<ItemGroup>
<Compile Include="StartupHook.cs"/>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,102 @@
using System.Reflection;
using Microsoft.FSharp.Collections;
using Microsoft.FSharp.Core;
namespace WoofWare.NUnitTestRunner.StartupHookLogic;
public class StartupHookLogic
{
private static void DoIt()
{
// Load test runner lib
var nunitLib = Environment.GetEnvironmentVariable("WOOFWARE_NUNIT_LIB");
if (string.IsNullOrEmpty(nunitLib))
{
throw new ArgumentException("WoofWare.NUnitTestRunner hook expects to run with WOOFWARE_NUNIT_LIB set to WoofWare.NUnitTestRunner.Lib.dll");
}
Assembly.LoadFrom(nunitLib);
var startTime = DateTimeOffset.Now;
// Arg parsing
var filterVar = Environment.GetEnvironmentVariable("WOOFWARE_NUNIT_FILTER");
static bool NoFilter(TestFixture f, SingleTestMethod g)
{
return true;
}
FSharpFunc<TestFixture, FSharpFunc<SingleTestMethod, bool>> filter;
if (string.IsNullOrEmpty(filterVar))
{
filter = FuncConvert.FromFunc<TestFixture, SingleTestMethod, bool>(NoFilter);
}
else
{
filter = FilterModule.shouldRun(FilterModule.parse(filterVar));
}
var assy = Assembly.GetEntryAssembly()!;
var attrs = AssemblyLevelAttributesModule.get(assy);
FSharpOption<int> levelOfParallelism;
var parallelismVar = Environment.GetEnvironmentVariable("WOOFWARE_NUNIT_PARALLELISM_LEVEL");
if (string.IsNullOrEmpty(parallelismVar))
{
levelOfParallelism = attrs.Parallelism;
}
else
{
levelOfParallelism = FSharpOption<int>.Some(Int32.Parse(parallelismVar));
}
var testFixtures = assy.ExportedTypes.Select(TestFixtureModule.parse);
using var par =
new ParallelQueue(levelOfParallelism, attrs.Parallelizable, FSharpOption<CancellationToken>.None);
var creationTime = DateTimeOffset.Now;
var timeoutVar = Environment.GetEnvironmentVariable("WOOFWARE_NUNIT_TIMEOUT_SECS");
TimeSpan timeout;
if (string.IsNullOrEmpty(timeoutVar))
{
timeout = TimeSpan.FromHours(2.0);
}
else
{
timeout = TimeSpan.FromSeconds(Int32.Parse(timeoutVar));
}
var normalErr = Console.Error;
using var contexts = TestContexts.Empty();
Console.SetOut(contexts.Stdout);
Console.SetError(contexts.Stderr);
var results =
Task.WhenAll(testFixtures.Select(x =>
TestFixtureModule.run(contexts, par, TestProgress.toWriter(normalErr), filter, x)));
if (!results.Wait(timeout))
{
throw new Exception($"Tests failed to terminate within timeout of {timeout}");
}
var sorted =
results.Result.SelectMany(x => x);
var report = BuildTrxReport.build(assy, creationTime, startTime, ListModule.OfSeq(sorted));
var trxFile = Environment.GetEnvironmentVariable("WOOFWARE_NUNIT_GENERATE_TRX");
if (!string.IsNullOrEmpty(trxFile))
{
var contents = TrxReportModule.toXml(report).OuterXml;
var trxPath = new FileInfo(trxFile);
trxPath.Directory!.Create();
File.WriteAllText(trxPath.FullName, contents);
normalErr.WriteLine($"Written TRX file: {trxPath.FullName}");
}
if (report.ResultsSummary.Outcome.Equals(TrxOutcome.Completed))
Environment.Exit(0);
else
Environment.Exit(1);
}
}

View File

@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\WoofWare.NUnitTestRunner.Lib\WoofWare.NUnitTestRunner.Lib.fsproj"/>
</ItemGroup>
<ItemGroup>
<Compile Include="StartupHookLogic.cs"/>
</ItemGroup>
</Project>

View File

@@ -8,6 +8,10 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.NUnitTestRunner.Li
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.NUnitTestRunner.Test", "WoofWare.NUnitTestRunner\WoofWare.NUnitTestRunner.Test\WoofWare.NUnitTestRunner.Test.fsproj", "{443B01B3-2A8C-45CF-96D6-1D890EEA0533}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WoofWare.NUnitTestRunner.StartupHook", "WoofWare.NUnitTestRunner.StartupHook\WoofWare.NUnitTestRunner.StartupHook.csproj", "{E2C73D96-570C-4E3C-B997-707AF8BB0E6A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WoofWare.NUnitTestRunner.StartupHookLogic", "WoofWare.NUnitTestRunner.StartupHookLogic\WoofWare.NUnitTestRunner.StartupHookLogic.csproj", "{A70627C8-9D19-42C2-AFEB-CFBDDDCE045D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -30,5 +34,13 @@ Global
{443B01B3-2A8C-45CF-96D6-1D890EEA0533}.Debug|Any CPU.Build.0 = Debug|Any CPU
{443B01B3-2A8C-45CF-96D6-1D890EEA0533}.Release|Any CPU.ActiveCfg = Release|Any CPU
{443B01B3-2A8C-45CF-96D6-1D890EEA0533}.Release|Any CPU.Build.0 = Release|Any CPU
{E2C73D96-570C-4E3C-B997-707AF8BB0E6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E2C73D96-570C-4E3C-B997-707AF8BB0E6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2C73D96-570C-4E3C-B997-707AF8BB0E6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E2C73D96-570C-4E3C-B997-707AF8BB0E6A}.Release|Any CPU.Build.0 = Release|Any CPU
{A70627C8-9D19-42C2-AFEB-CFBDDDCE045D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A70627C8-9D19-42C2-AFEB-CFBDDDCE045D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A70627C8-9D19-42C2-AFEB-CFBDDDCE045D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A70627C8-9D19-42C2-AFEB-CFBDDDCE045D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -1,12 +1,15 @@
namespace WoofWare.NUnitTestRunner
open System
open System.Diagnostics
open System.IO
open System.Reflection
open System.Threading.Tasks
open Spectre.Console
module Program =
let main argv =
// This is actually transcribed into C# in WoofWare.NUnitTestRunner.StartupHookLogic.
let execute argv =
let startTime = DateTimeOffset.Now
let args = argv |> List.ofArray |> Args.Parse
@@ -31,8 +34,6 @@ module Program =
for d in runtime do
stderr.WriteLine $".NET runtime directory: %s{d.FullName}"
use _ = new SetBaseDir (args.Dll)
use contexts = TestContexts.Empty ()
let ctx = LoadContext (args.Dll, runtime, contexts)
@@ -89,6 +90,52 @@ module Program =
| TrxOutcome.Completed -> 0
| _ -> 1
let main argv =
let args = argv |> List.ofArray |> Args.Parse
let psi = ProcessStartInfo "dotnet"
match args.Trx with
| None -> ()
| Some trx -> psi.EnvironmentVariables.Add ("WOOFWARE_NUNIT_GENERATE_TRX", trx.FullName)
match args.LevelOfParallelism with
| None -> ()
| Some par -> psi.EnvironmentVariables.Add ("WOOFWARE_NUNIT_PARALLELISM_LEVEL", string<int> par)
match args.Filter with
| None -> ()
| Some (filter, _) -> psi.EnvironmentVariables.Add ("WOOFWARE_NUNIT_FILTER", filter)
match args.Timeout with
| None -> ()
| Some timeout ->
psi.EnvironmentVariables.Add ("WOOFWARE_NUNIT_TIMEOUT_SECS", string<int> (int<float> timeout.TotalSeconds))
psi.ArgumentList.Add "exec"
psi.ArgumentList.Add args.Dll.FullName
let us = Assembly.GetExecutingAssembly().Location |> FileInfo
let startupHook =
Path.Combine (us.Directory.FullName, "WoofWare.NUnitTestRunner.StartupHook.dll")
psi.EnvironmentVariables.Add ("DOTNET_STARTUP_HOOKS", startupHook)
psi.EnvironmentVariables.Add (
"WOOFWARE_NUNIT_LIB",
Path.Combine (us.Directory.FullName, "WoofWare.NUnitTestRunner.Lib.dll")
)
use proc = new Process ()
proc.StartInfo <- psi
if not (proc.Start ()) then
failwith "Failed to start dotnet"
proc.WaitForExit ()
proc.ExitCode
[<EntryPoint>]
let reallyMain argv =
// Hack to make sure `finally`s get run.

View File

@@ -2,7 +2,8 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<RollForward>Major</RollForward>
<PackAsTool>true</PackAsTool>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Authors>Patrick Stevens</Authors>
@@ -29,6 +30,8 @@
<ItemGroup>
<ProjectReference Include="..\WoofWare.NUnitTestRunner.Lib\WoofWare.NUnitTestRunner.Lib.fsproj" />
<ProjectReference Include="..\WoofWare.NUnitTestRunner.StartupHookLogic\WoofWare.NUnitTestRunner.StartupHookLogic.csproj" />
<ProjectReference Include="..\WoofWare.NUnitTestRunner.StartupHook\WoofWare.NUnitTestRunner.StartupHook.csproj" />
</ItemGroup>
<ItemGroup>

View File

@@ -56,13 +56,20 @@
doCheck = true;
};
};
devShell = pkgs.mkShell {
packages = [
(pkgs.dotnetCorePackages.combinePackages [dotnet-sdk pkgs.dotnetCorePackages.runtime_6_0])
pkgs.alejandra
pkgs.nodePackages.markdown-link-check
pkgs.shellcheck
];
devShells = {
default = pkgs.mkShell {
packages = [
dotnet-sdk
pkgs.alejandra
pkgs.nodePackages.markdown-link-check
pkgs.shellcheck
];
};
net6 = pkgs.mkShell {
packages = [
pkgs.dotnetCorePackages.runtime_6_0
];
};
};
});
}