From e821c015a27f2760fd20b72880a826feea3bf738 Mon Sep 17 00:00:00 2001 From: Aaron Pearson Date: Sun, 28 Jan 2024 21:57:33 +0000 Subject: [PATCH] Applier prep Also added Azure only testing logic & test area for using updater (to actually make) --- README.md | 5 +- TinyUpdate.sln | 20 +++++ .../TinyUpdate.Delta.BSDiff.csproj | 2 +- .../ExampleApplication.csproj | 17 ++++ src/ExampleApplication/Program.cs | 7 ++ .../TinyUpdate.TUUP/TinyUpdate.TUUP.csproj | 2 +- src/TinyUpdate.Core/Abstract/ReleaseEntry.cs | 4 +- src/TinyUpdate.Core/Testing.cs | 33 +++++++ .../TinyUpdate.Desktop/DesktopApplier.cs | 86 ++++++++++++------- .../TinyUpdate.Desktop.csproj | 4 + .../AzureClientTests.cs | 13 +++ .../TinyUpdate.Clients.Tests/GlobalUsings.cs | 1 + .../TinyUpdate.Clients.Tests.csproj | 23 +++++ .../Attributes/AzureTestAttribute.cs | 17 ++++ .../TinyUpdate.Core.Tests.csproj | 4 +- .../TinyUpdate.Delta.Tests.csproj | 5 -- .../TinyUpdate.Packages.Tests.csproj | 5 -- .../UpdatePackageTests.cs | 3 + .../TinyUpdate.Updaters.Tests/DesktopTests.cs | 6 ++ .../TinyUpdate.Updaters.Tests/GlobalUsings.cs | 1 + .../TinyUpdate.Updaters.Tests.csproj | 23 +++++ 21 files changed, 229 insertions(+), 52 deletions(-) create mode 100644 src/ExampleApplication/ExampleApplication.csproj create mode 100644 src/ExampleApplication/Program.cs create mode 100644 src/TinyUpdate.Core/Testing.cs create mode 100644 tests/TinyUpdate.Clients.Tests/AzureClientTests.cs create mode 100644 tests/TinyUpdate.Clients.Tests/GlobalUsings.cs create mode 100644 tests/TinyUpdate.Clients.Tests/TinyUpdate.Clients.Tests.csproj create mode 100644 tests/TinyUpdate.Core.Tests/Attributes/AzureTestAttribute.cs create mode 100644 tests/TinyUpdate.Updaters.Tests/DesktopTests.cs create mode 100644 tests/TinyUpdate.Updaters.Tests/GlobalUsings.cs create mode 100644 tests/TinyUpdate.Updaters.Tests/TinyUpdate.Updaters.Tests.csproj diff --git a/README.md b/README.md index c177582..227ad4b 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,9 @@ Tiny Update is an updater that focuses on being easy to use while being feature Because when I started this project, I was still in college and have learnt a lot since then and the .NET ecosystem is not the same as back then (Very much in a good way!) ### What is currently missing? -* Package Creation -* Applying updates -* Hard link support * Update package retrieval * Cli for making updates * Staging * RELEASE file creation/reading -*its likely that they is more missing but can't remeber at the time of creating the readme* \ No newline at end of file +*its likely that they is more missing but can't remember at the time of creating the readme* \ No newline at end of file diff --git a/TinyUpdate.sln b/TinyUpdate.sln index 93bc04e..9375eda 100644 --- a/TinyUpdate.sln +++ b/TinyUpdate.sln @@ -34,6 +34,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TinyUpdate.MicrosoftStore", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TinyUpdate.Azure", "src\Clients\TinyUpdate.Azure\TinyUpdate.Azure.csproj", "{35DBC016-62BB-41B4-B2F8-1153E1ACB5AA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TinyUpdate.Updaters.Tests", "tests\TinyUpdate.Updaters.Tests\TinyUpdate.Updaters.Tests.csproj", "{A770334A-238E-4150-9C1B-064DD9136073}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TinyUpdate.Clients.Tests", "tests\TinyUpdate.Clients.Tests\TinyUpdate.Clients.Tests.csproj", "{E101DF04-54F0-4A00-A3AF-03E92028A6AA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleApplication", "src\ExampleApplication\ExampleApplication.csproj", "{B24E6FD4-EA62-48DD-9146-72AA2D73D38F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -84,6 +90,18 @@ Global {35DBC016-62BB-41B4-B2F8-1153E1ACB5AA}.Debug|Any CPU.Build.0 = Debug|Any CPU {35DBC016-62BB-41B4-B2F8-1153E1ACB5AA}.Release|Any CPU.ActiveCfg = Release|Any CPU {35DBC016-62BB-41B4-B2F8-1153E1ACB5AA}.Release|Any CPU.Build.0 = Release|Any CPU + {A770334A-238E-4150-9C1B-064DD9136073}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A770334A-238E-4150-9C1B-064DD9136073}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A770334A-238E-4150-9C1B-064DD9136073}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A770334A-238E-4150-9C1B-064DD9136073}.Release|Any CPU.Build.0 = Release|Any CPU + {E101DF04-54F0-4A00-A3AF-03E92028A6AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E101DF04-54F0-4A00-A3AF-03E92028A6AA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E101DF04-54F0-4A00-A3AF-03E92028A6AA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E101DF04-54F0-4A00-A3AF-03E92028A6AA}.Release|Any CPU.Build.0 = Release|Any CPU + {B24E6FD4-EA62-48DD-9146-72AA2D73D38F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B24E6FD4-EA62-48DD-9146-72AA2D73D38F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B24E6FD4-EA62-48DD-9146-72AA2D73D38F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B24E6FD4-EA62-48DD-9146-72AA2D73D38F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {4B3D4412-9AF3-4D5A-B013-3462B46E815F} = {63F2556D-A89A-4552-84C7-D2BE30718485} @@ -101,5 +119,7 @@ Global {81B0A72E-04FA-4A4F-856F-68C22FF2D945} = {0BD356C4-B4F2-45D6-A94F-77ED1ECEEE11} {F364F894-0AF5-4A42-A6D3-9B6A8C10E45B} = {EE289D98-EE1C-4D17-9BB0-B4981E26A49D} {35DBC016-62BB-41B4-B2F8-1153E1ACB5AA} = {EE289D98-EE1C-4D17-9BB0-B4981E26A49D} + {A770334A-238E-4150-9C1B-064DD9136073} = {0BD356C4-B4F2-45D6-A94F-77ED1ECEEE11} + {E101DF04-54F0-4A00-A3AF-03E92028A6AA} = {0BD356C4-B4F2-45D6-A94F-77ED1ECEEE11} EndGlobalSection EndGlobal diff --git a/src/Deltas/TinyUpdate.Delta.BSDiff/TinyUpdate.Delta.BSDiff.csproj b/src/Deltas/TinyUpdate.Delta.BSDiff/TinyUpdate.Delta.BSDiff.csproj index 5a6719d..21e0c61 100644 --- a/src/Deltas/TinyUpdate.Delta.BSDiff/TinyUpdate.Delta.BSDiff.csproj +++ b/src/Deltas/TinyUpdate.Delta.BSDiff/TinyUpdate.Delta.BSDiff.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/ExampleApplication/ExampleApplication.csproj b/src/ExampleApplication/ExampleApplication.csproj new file mode 100644 index 0000000..6a70389 --- /dev/null +++ b/src/ExampleApplication/ExampleApplication.csproj @@ -0,0 +1,17 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + diff --git a/src/ExampleApplication/Program.cs b/src/ExampleApplication/Program.cs new file mode 100644 index 0000000..26b3a5c --- /dev/null +++ b/src/ExampleApplication/Program.cs @@ -0,0 +1,7 @@ +// See https://aka.ms/new-console-template for more information + +//TODO: When local client is made, add it to this for testing + +using TinyUpdate.Core; + +Console.WriteLine("Hello, World! In Test Runner?: " + Testing.InTestRunner); \ No newline at end of file diff --git a/src/Packages/TinyUpdate.TUUP/TinyUpdate.TUUP.csproj b/src/Packages/TinyUpdate.TUUP/TinyUpdate.TUUP.csproj index 4f9f84f..dafc56d 100644 --- a/src/Packages/TinyUpdate.TUUP/TinyUpdate.TUUP.csproj +++ b/src/Packages/TinyUpdate.TUUP/TinyUpdate.TUUP.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/TinyUpdate.Core/Abstract/ReleaseEntry.cs b/src/TinyUpdate.Core/Abstract/ReleaseEntry.cs index 3b64c8d..25d221a 100644 --- a/src/TinyUpdate.Core/Abstract/ReleaseEntry.cs +++ b/src/TinyUpdate.Core/Abstract/ReleaseEntry.cs @@ -24,8 +24,8 @@ protected ReleaseEntry(SemanticVersion? previousVersion, SemanticVersion newVers /// /// What version this update package was created against /// - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault), - JsonConverter(typeof(SemanticVersionConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + [JsonConverter(typeof(SemanticVersionConverter))] public SemanticVersion? PreviousVersion { get; } /// diff --git a/src/TinyUpdate.Core/Testing.cs b/src/TinyUpdate.Core/Testing.cs new file mode 100644 index 0000000..4a37fe4 --- /dev/null +++ b/src/TinyUpdate.Core/Testing.cs @@ -0,0 +1,33 @@ +using System.Reflection; + +namespace TinyUpdate.Core; + +public static class Testing +{ + public static bool InTestRunner + { + get + { + var nunitAssemblyName = Assembly.GetExecutingAssembly().GetReferencedAssemblies() + .FirstOrDefault(x => x.Name == "nunit.framework"); + if (nunitAssemblyName == null) + { + return false; + } + + var contextType = Assembly.Load(nunitAssemblyName).GetType("NUnit.Framework.Internal.TestExecutionContext"); + var currentContextProperty = contextType?.GetProperty("CurrentContext", BindingFlags.Public | BindingFlags.Static); + var currentContext = currentContextProperty?.GetValue(null); + + var startTicksProperty = currentContext?.GetType().GetProperty("StartTicks", BindingFlags.Public | BindingFlags.Instance); + var startTicksObj = startTicksProperty?.GetValue(currentContext); + + if (startTicksObj is long startTicks) + { + return startTicks > 0; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Updaters/TinyUpdate.Desktop/DesktopApplier.cs b/src/Updaters/TinyUpdate.Desktop/DesktopApplier.cs index 61a441e..61e9321 100644 --- a/src/Updaters/TinyUpdate.Desktop/DesktopApplier.cs +++ b/src/Updaters/TinyUpdate.Desktop/DesktopApplier.cs @@ -1,4 +1,6 @@ -using Microsoft.Extensions.Logging; +using System.Diagnostics; +using System.IO.Abstractions; +using Microsoft.Extensions.Logging; using TinyUpdate.Core.Abstract.Delta; using TinyUpdate.Core.Abstract.UpdatePackage; using TinyUpdate.Desktop.Abstract; @@ -11,12 +13,14 @@ public class DesktopApplier : IUpdateApplier private readonly ILogger _logger; private readonly IDeltaManager _deltaManager; private readonly INative? _native; - public DesktopApplier(ILogger logger, IHasher hasher, INative? native, IDeltaManager deltaManager) + private readonly IFileSystem _fileSystem; + public DesktopApplier(ILogger logger, IHasher hasher, INative? native, IDeltaManager deltaManager, IFileSystem fileSystem) { _logger = logger; _hasher = hasher; _native = native; _deltaManager = deltaManager; + _fileSystem = fileSystem; } public bool SupportedOS() => OperatingSystem.IsWindows() || OperatingSystem.IsLinux() || OperatingSystem.IsMacOS(); @@ -56,22 +60,59 @@ public Task Cleanup() public Task ApplyUpdate(IUpdatePackage updatePackage, string applicationLocation, IProgress? progress = null) { var newVersionLocation = Path.Combine(applicationLocation, updatePackage.ReleaseEntry.NewVersion.ToString()); - var previousVersionLocation = Path.Combine(applicationLocation, updatePackage.ReleaseEntry.PreviousVersion.ToString()); + string? previousVersionLocation = null; + if (updatePackage.ReleaseEntry.IsDelta) + { + previousVersionLocation = Path.Combine(applicationLocation, updatePackage.ReleaseEntry.PreviousVersion.ToString()); + } return ApplyUpdate(updatePackage, previousVersionLocation, newVersionLocation, progress); } - private async Task ApplyUpdate(IUpdatePackage updatePackage, string previousVersionLocation, + private async Task ApplyUpdate(IUpdatePackage updatePackage, string? previousVersionLocation, string newVersionLocation, IProgress? progress) { double progressTotal = 0; var ind = (double)1 / updatePackage.FileCount; - + + if (updatePackage.ReleaseEntry.IsDelta + && string.IsNullOrWhiteSpace(previousVersionLocation)) + { + _logger.LogError("We have not been given the previous version location"); + return false; + } //Create all the directories beforehand foreach (var directory in updatePackage.Directories) { - Directory.CreateDirectory(Path.Combine(newVersionLocation, directory)); + _fileSystem.Directory.CreateDirectory(Path.Combine(newVersionLocation, directory)); + } + + foreach (var newFile in updatePackage.NewFiles) + { + var newPath = Path.Combine(newVersionLocation, newFile.Location); + await using var newFileStream = _fileSystem.File.Open(newPath, new FileStreamOptions + { + PreallocationSize = newFile.Filesize, + Mode = FileMode.Create + }); + + await newFile.Stream.CopyToAsync(newFileStream); + await newFile.Stream.DisposeAsync(); + + newFileStream.Seek(0, SeekOrigin.Begin); + if (!CheckFile(newFileStream, newFile.Hash, newFile.Filesize, newPath)) + { + return false; + } + UpdateProgress(); + } + + //If this isn't a delta update then we'll only have new files + if (!updatePackage.ReleaseEntry.IsDelta) + { + Debug.Assert(updatePackage.FileCount != updatePackage.NewFiles.Count, "Non delta update isn't all new files"); + return true; } foreach (var movedFile in updatePackage.MovedFiles) @@ -99,34 +140,15 @@ private async Task ApplyUpdate(IUpdatePackage updatePackage, string previo } UpdateProgress(); } - - foreach (var newFile in updatePackage.NewFiles) - { - var newPath = Path.Combine(newVersionLocation, newFile.Location); - await using var newFileStream = File.Open(newPath, new FileStreamOptions - { - PreallocationSize = newFile.Filesize, - Mode = FileMode.Create - }); - - await newFile.Stream.CopyToAsync(newFileStream); - await newFile.Stream.DisposeAsync(); - - newFileStream.Seek(0, SeekOrigin.Begin); - if (!CheckFile(newFileStream, newFile.Hash, newFile.Filesize, newPath)) - { - return false; - } - UpdateProgress(); - } - + foreach (var deltaFile in updatePackage.DeltaFiles) { + Debug.Assert(previousVersionLocation != null, nameof(previousVersionLocation) + " != null"); var sourcePath = Path.Combine(previousVersionLocation, deltaFile.Location); var targetPath = Path.Combine(newVersionLocation, deltaFile.Location); - await using var sourceStream = File.OpenRead(sourcePath); - await using var targetStream = File.Open(targetPath, new FileStreamOptions + await using var sourceStream = _fileSystem.File.OpenRead(sourcePath); + await using var targetStream = _fileSystem.File.Open(targetPath, new FileStreamOptions { PreallocationSize = deltaFile.Filesize, Mode = FileMode.Create @@ -166,7 +188,7 @@ bool ProcessHardLinkableFile(string previousRelativePath, string newRelativePath //Attempt to create the file as a hard link if (_native?.CreateHardLink(previousPath, newPath) ?? false) { - using (fileStream = File.OpenRead(newPath)) + using (fileStream = _fileSystem.File.OpenRead(newPath)) { return CheckFile(fileStream, expectedHash, expectedFilesize, newPath); } @@ -174,8 +196,8 @@ bool ProcessHardLinkableFile(string previousRelativePath, string newRelativePath //We failed, we'll copy the file as a backup _logger.LogWarning("Was unable to hard link {PreviousPath} to {NewPath}, going to copy file", previousPath, newPath); - File.Copy(previousPath, newPath, true); - using (fileStream = File.OpenRead(newPath)) + _fileSystem.File.Copy(previousPath, newPath, true); + using (fileStream = _fileSystem.File.OpenRead(newPath)) { return CheckFile(fileStream, expectedHash, expectedFilesize, newPath); } diff --git a/src/Updaters/TinyUpdate.Desktop/TinyUpdate.Desktop.csproj b/src/Updaters/TinyUpdate.Desktop/TinyUpdate.Desktop.csproj index 97d3d97..82a72c9 100644 --- a/src/Updaters/TinyUpdate.Desktop/TinyUpdate.Desktop.csproj +++ b/src/Updaters/TinyUpdate.Desktop/TinyUpdate.Desktop.csproj @@ -11,4 +11,8 @@ + + + + diff --git a/tests/TinyUpdate.Clients.Tests/AzureClientTests.cs b/tests/TinyUpdate.Clients.Tests/AzureClientTests.cs new file mode 100644 index 0000000..b1d3200 --- /dev/null +++ b/tests/TinyUpdate.Clients.Tests/AzureClientTests.cs @@ -0,0 +1,13 @@ +using TinyUpdate.Core.Tests.Attributes; + +namespace TinyUpdate.Clients.Tests; + +[AzureTest] +public class AzureClientTests +{ + [Test] + public void Test() + { + Assert.Pass(); + } +} \ No newline at end of file diff --git a/tests/TinyUpdate.Clients.Tests/GlobalUsings.cs b/tests/TinyUpdate.Clients.Tests/GlobalUsings.cs new file mode 100644 index 0000000..cefced4 --- /dev/null +++ b/tests/TinyUpdate.Clients.Tests/GlobalUsings.cs @@ -0,0 +1 @@ +global using NUnit.Framework; \ No newline at end of file diff --git a/tests/TinyUpdate.Clients.Tests/TinyUpdate.Clients.Tests.csproj b/tests/TinyUpdate.Clients.Tests/TinyUpdate.Clients.Tests.csproj new file mode 100644 index 0000000..3bdae7d --- /dev/null +++ b/tests/TinyUpdate.Clients.Tests/TinyUpdate.Clients.Tests.csproj @@ -0,0 +1,23 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + diff --git a/tests/TinyUpdate.Core.Tests/Attributes/AzureTestAttribute.cs b/tests/TinyUpdate.Core.Tests/Attributes/AzureTestAttribute.cs new file mode 100644 index 0000000..770680f --- /dev/null +++ b/tests/TinyUpdate.Core.Tests/Attributes/AzureTestAttribute.cs @@ -0,0 +1,17 @@ +using NUnit.Framework.Interfaces; +using NUnit.Framework.Internal; + +namespace TinyUpdate.Core.Tests.Attributes; + +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] +public class AzureTestAttribute : Attribute, IApplyToTest +{ + public void ApplyToTest(Test test) + { + if (Environment.GetEnvironmentVariable("AZURE_DEVOPS_EXT_PAT") == null) + { + test.RunState = RunState.Skipped; + test.Properties.Set(PropertyNames.SkipReason, "Unable to run Azure Test without AZURE_DEVOPS_EXT_PAT set"); + } + } +} \ No newline at end of file diff --git a/tests/TinyUpdate.Core.Tests/TinyUpdate.Core.Tests.csproj b/tests/TinyUpdate.Core.Tests/TinyUpdate.Core.Tests.csproj index 02b8c42..deb6f4e 100644 --- a/tests/TinyUpdate.Core.Tests/TinyUpdate.Core.Tests.csproj +++ b/tests/TinyUpdate.Core.Tests/TinyUpdate.Core.Tests.csproj @@ -14,12 +14,12 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/tests/TinyUpdate.Delta.Tests/TinyUpdate.Delta.Tests.csproj b/tests/TinyUpdate.Delta.Tests/TinyUpdate.Delta.Tests.csproj index 3b66c16..263423d 100644 --- a/tests/TinyUpdate.Delta.Tests/TinyUpdate.Delta.Tests.csproj +++ b/tests/TinyUpdate.Delta.Tests/TinyUpdate.Delta.Tests.csproj @@ -12,12 +12,7 @@ - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/tests/TinyUpdate.Packages.Tests/TinyUpdate.Packages.Tests.csproj b/tests/TinyUpdate.Packages.Tests/TinyUpdate.Packages.Tests.csproj index 57cd1d7..b650ba3 100644 --- a/tests/TinyUpdate.Packages.Tests/TinyUpdate.Packages.Tests.csproj +++ b/tests/TinyUpdate.Packages.Tests/TinyUpdate.Packages.Tests.csproj @@ -11,12 +11,7 @@ - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/tests/TinyUpdate.Packages.Tests/UpdatePackageTests.cs b/tests/TinyUpdate.Packages.Tests/UpdatePackageTests.cs index fb8c1f8..4aa5b99 100644 --- a/tests/TinyUpdate.Packages.Tests/UpdatePackageTests.cs +++ b/tests/TinyUpdate.Packages.Tests/UpdatePackageTests.cs @@ -1,6 +1,8 @@ using System.IO.Compression; +using System.Reflection; using Microsoft.Extensions.Logging.Abstractions; using TinyUpdate.Core; +using TinyUpdate.Core.Tests; using TinyUpdate.Core.Tests.Attributes; using TinyUpdate.Packages.Tests.Abstract; using TinyUpdate.Packages.Tests.Model; @@ -18,6 +20,7 @@ public class TuupUpdatePackageTests : UpdatePackageCan [SetUp] public void Setup() { + var ta = Testing.InTestRunner; var mockApplier1 = CreateMockDeltaApplier(".bsdiff"); var mockApplier2 = CreateMockDeltaApplier(".diffing"); diff --git a/tests/TinyUpdate.Updaters.Tests/DesktopTests.cs b/tests/TinyUpdate.Updaters.Tests/DesktopTests.cs new file mode 100644 index 0000000..2a11606 --- /dev/null +++ b/tests/TinyUpdate.Updaters.Tests/DesktopTests.cs @@ -0,0 +1,6 @@ +namespace TinyUpdate.Updaters.Tests; + +public class DesktopTests +{ + +} \ No newline at end of file diff --git a/tests/TinyUpdate.Updaters.Tests/GlobalUsings.cs b/tests/TinyUpdate.Updaters.Tests/GlobalUsings.cs new file mode 100644 index 0000000..cefced4 --- /dev/null +++ b/tests/TinyUpdate.Updaters.Tests/GlobalUsings.cs @@ -0,0 +1 @@ +global using NUnit.Framework; \ No newline at end of file diff --git a/tests/TinyUpdate.Updaters.Tests/TinyUpdate.Updaters.Tests.csproj b/tests/TinyUpdate.Updaters.Tests/TinyUpdate.Updaters.Tests.csproj new file mode 100644 index 0000000..446841d --- /dev/null +++ b/tests/TinyUpdate.Updaters.Tests/TinyUpdate.Updaters.Tests.csproj @@ -0,0 +1,23 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + +