diff --git a/CHANGES.md b/CHANGES.md
index cc4c1dd64..88afa89aa 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -2,6 +2,25 @@
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
+## [6.0.0-3](https://github.com/criticalmanufacturing/cli/compare/6.0.0-2...6.0.0-3) (2026-08-21)
+
+
+### Features
+
+* add dependency version for v12 (dotnet, node, ng22) ([3c3019a](https://github.com/criticalmanufacturing/cli/commit/3c3019af1202e790770c25240493335c35deb89e))
+* add support for pre-releases ([2d89954](https://github.com/criticalmanufacturing/cli/commit/2d89954ae20f980209508aea1a702f3f634dca49))
+
+
+### Bug Fixes
+
+* update SharpCompress package version and improve TAR.GZ handling in CmfPackageController ([c3f654b](https://github.com/criticalmanufacturing/cli/commit/c3f654bb62b8b4032f924e17c8332f30281b0a8a))
+
+
+### Under the hood
+
+* remove outdated NPX version handling logic from NPXCommand ([5a75a86](https://github.com/criticalmanufacturing/cli/commit/5a75a86b21231a7582d9ccd64ba9b8a0605e511d))
+* replace Version with MesVersion for improved semantic version handling across the CLI ([7893e74](https://github.com/criticalmanufacturing/cli/commit/7893e749d07c83a60498c513ce9bf91aa8d3aabf))
+
## [6.0.0-2](https://github.com/criticalmanufacturing/cli/compare/6.0.0-1...6.0.0-2) (2026-07-22)
diff --git a/cmf-cli/Builders/NPXCommand.cs b/cmf-cli/Builders/NPXCommand.cs
index 15bd956b8..8e7640b61 100644
--- a/cmf-cli/Builders/NPXCommand.cs
+++ b/cmf-cli/Builders/NPXCommand.cs
@@ -1,8 +1,7 @@
-using System;
using System.Collections.Generic;
-using System.Linq;
using System.Runtime.InteropServices;
using Cmf.CLI.Core.Objects;
+using NuGet.Versioning;
namespace Cmf.CLI.Builders
{
@@ -40,18 +39,6 @@ public override ProcessBuildStep[] GetSteps()
// Bypass any interactive confirmation prompts that might appear
"-y"
};
-
- // The initial versions of NPX (<= 6) that are used by MES v8 and v9 must be called like this:
- // npx -y true
- // Later versions of NPX (>= 7) that are used by MES v10 and greater, must be called only like this:
- // npx -y
- // So we get the MES version of the project, and we assume that the user must be running the supported
- // node version for that MES project
- var mesVersion = ExecutionContext.Instance?.ProjectConfig?.MESVersion;
- if (mesVersion != null && mesVersion < new Version(10, 0))
- {
- args.Add("true");
- }
args.Add(this.Command);
if (this.Args != null)
diff --git a/cmf-cli/Commands/UILayerTemplateCommand.cs b/cmf-cli/Commands/UILayerTemplateCommand.cs
index d8fd0f22e..be70ce980 100644
--- a/cmf-cli/Commands/UILayerTemplateCommand.cs
+++ b/cmf-cli/Commands/UILayerTemplateCommand.cs
@@ -41,13 +41,13 @@ protected void CloneHTMLStarter(Version versionTag, IDirectoryInfo target)
target.GetFiles(".gitkeep").FirstOrDefault()?.Delete();
Log.Verbose("cloning html starter");
// git init
- (new GitCommand() { Command = "init", WorkingDirectory = target }).Exec();
+ new GitCommand() { Command = "init", WorkingDirectory = target }.Exec();
// git remote add origin https://github.com/criticalmanufacturing/html-starter
- (new GitCommand() { Command = "remote", WorkingDirectory = target, Args = new[] { "add", "origin", "https://github.com/criticalmanufacturing/html-starter" } }).Exec();
+ new GitCommand() { Command = "remote", WorkingDirectory = target, Args = ["add", "origin", "https://github.com/criticalmanufacturing/html-starter"] }.Exec();
// git fetch
- (new GitCommand() { Command = "fetch", WorkingDirectory = target }).Exec();
+ new GitCommand() { Command = "fetch", WorkingDirectory = target }.Exec();
// git pull origin $vars['HTMLStarterVersion']
- (new GitCommand() { Command = "pull", WorkingDirectory = target, Args = new[] { "origin", versionTag.ToString() } }).Exec();
+ new GitCommand() { Command = "pull", WorkingDirectory = target, Args = ["origin", versionTag.ToString()] }.Exec();
Log.Debug("delete .git folder");
this.DeleteFolderWithReadOnlyFiles(target.GetDirectories(".git").FirstOrDefault());
// delete apps/.gitkeep
diff --git a/cmf-cli/Commands/build/html/ExtractI18nCommand.cs b/cmf-cli/Commands/build/html/ExtractI18nCommand.cs
index c678e5cb2..898d4d2a8 100644
--- a/cmf-cli/Commands/build/html/ExtractI18nCommand.cs
+++ b/cmf-cli/Commands/build/html/ExtractI18nCommand.cs
@@ -10,10 +10,10 @@
using Cmf.CLI.Utilities;
using System.Xml.Linq;
using System.Linq;
-using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
+using NuGet.Versioning;
namespace Cmf.CLI.Commands.html;
@@ -26,7 +26,7 @@ public class ExtractI18nCommand : BaseCommand
///
/// The minimum MES Version that supports this command
///
- private readonly Version MIN_MES_VERSION = new Version(11, 2, 0);
+ private readonly NuGetVersion MIN_MES_VERSION = new NuGetVersion(11, 2, 0);
///
/// constructor
diff --git a/cmf-cli/Commands/build/html/LocalizeCommand.cs b/cmf-cli/Commands/build/html/LocalizeCommand.cs
index f69e9c010..086d65fda 100644
--- a/cmf-cli/Commands/build/html/LocalizeCommand.cs
+++ b/cmf-cli/Commands/build/html/LocalizeCommand.cs
@@ -8,7 +8,7 @@
using Cmf.CLI.Core.Objects;
using Cmf.CLI.Utilities;
using System.Linq;
-using System;
+using NuGet.Versioning;
namespace Cmf.CLI.Commands.html;
@@ -21,7 +21,7 @@ public class LocalizeCommand : BaseCommand
///
/// The minimum MES Version that supports this command
///
- private readonly Version MIN_MES_VERSION = new Version(11, 2, 0);
+ private readonly NuGetVersion MIN_MES_VERSION = new NuGetVersion(11, 2, 0);
public override void Configure(Command cmd)
{
diff --git a/cmf-cli/Commands/init/InitCommand.cs b/cmf-cli/Commands/init/InitCommand.cs
index d1c082452..a6343d97d 100644
--- a/cmf-cli/Commands/init/InitCommand.cs
+++ b/cmf-cli/Commands/init/InitCommand.cs
@@ -17,6 +17,7 @@
using Cmf.CLI.Utilities;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
+using NuGet.Versioning;
namespace Cmf.CLI.Commands
{
@@ -514,8 +515,8 @@ internal void Execute(InitArguments x)
if (string.IsNullOrWhiteSpace(x.ngxSchematicsVersion))
{
- var mesVer = Version.Parse(x.BaseVersion);
- x.ngxSchematicsVersion = $"release-{mesVer.Major}{mesVer.Minor}{mesVer.Build}";
+ var mesVer = NuGetVersion.Parse(x.BaseVersion);
+ x.ngxSchematicsVersion = GenericUtilities.GetNpmDistTag(mesVer);
}
Log.Information($"Using ngx-schematics version: {x.ngxSchematicsVersion}");
@@ -578,10 +579,10 @@ internal void Execute(InitArguments x)
#region version-specific bits
- var version = Version.Parse(x.BaseVersion);
+ var version = new NuGetVersion(x.BaseVersion);
args.AddRange(new []{ "--dotnetSDKVersion", ExecutionContext.ServiceProvider.GetService().DotNetSdk(version) });
- if(version < new Version(10,0))
+ if(version < new NuGetVersion(10, 0, 0))
{
throw new CliException("MES Versions under 10 are no longer supported with the newest version of the CLI. Please use cmf-cli 5.8.0 or lower.");
}
diff --git a/cmf-cli/Commands/new/DataCommand.cs b/cmf-cli/Commands/new/DataCommand.cs
index 4118184a3..591b2616e 100644
--- a/cmf-cli/Commands/new/DataCommand.cs
+++ b/cmf-cli/Commands/new/DataCommand.cs
@@ -58,7 +58,7 @@ public override void Configure(Command cmd)
protected override List GenerateArgs(IDirectoryInfo projectRoot, IDirectoryInfo workingDir, List args)
{
var repoType = ExecutionContext.Instance.ProjectConfig.RepositoryType ?? CliConstants.DefaultRepositoryType;
- Version version = ExecutionContext.Instance.ProjectConfig.MESVersion;
+ var version = ExecutionContext.Instance.ProjectConfig.MESVersion;
var relativePathToRoot =
this.fileSystem.Path.Join("..", //always one level deeper
diff --git a/cmf-cli/Commands/new/HTMLCommand.cs b/cmf-cli/Commands/new/HTMLCommand.cs
index 4760fd856..be6ac9895 100644
--- a/cmf-cli/Commands/new/HTMLCommand.cs
+++ b/cmf-cli/Commands/new/HTMLCommand.cs
@@ -104,7 +104,7 @@ public void ExecuteV10(IDirectoryInfo workingDir, string version)
var packageName = base.GeneratePackageName(workingDir)!.Value.Item1;
var packageDir = workingDir.GetDirectories(packageName).First();
- var schematicsVersion = !string.IsNullOrEmpty(ngxSchematicsVersion) ? ngxSchematicsVersion : $"release-{mesVersion.Major}{mesVersion.Minor}{mesVersion.Build}";
+ var schematicsVersion = !string.IsNullOrEmpty(ngxSchematicsVersion?.ToString()) ? ngxSchematicsVersion.ToString() : GenericUtilities.GetNpmDistTag(mesVersion);
//After v11 we use Angular default routing
var routing = mesVersion.Major >= 11 ? "true" : "false";
@@ -143,7 +143,7 @@ public void ExecuteV10(IDirectoryInfo workingDir, string version)
"add", "--registry", ExecutionContext.Instance.ProjectConfig.NPMRegistry.OriginalString,
"--skip-confirmation", $"@criticalmanufacturing/ngx-schematics@{schematicsVersion}",
"--eslint", "--application", baseLayer.ToString(),
- "--version", $"release-{mesVersion.Major}{mesVersion.Minor}{mesVersion.Build}"
+ "--version", GenericUtilities.GetNpmDistTag(mesVersion)
],
WorkingDirectory = packageDir,
ForceColorOutput = false
@@ -170,7 +170,15 @@ public void ExecuteV10(IDirectoryInfo workingDir, string version)
rootPkgJson.devDependencies["cross-env"] = "^10.1.0";
}
- rootPkgJson.scripts["serve"] = "cross-env NODE_OPTIONS=--max-old-space-size=8192 npm run start -- --host 0.0.0.0 --disable-host-check --port 7000";
+
+ if (mesVersion.Major < 12)
+ {
+ rootPkgJson.scripts["serve"] = "cross-env NODE_OPTIONS=--max-old-space-size=8192 npm run start -- --host 0.0.0.0 --disable-host-check --port 7000";
+ }
+ else
+ {
+ rootPkgJson.scripts["serve"] = "cross-env NODE_OPTIONS=--max-old-space-size=8192 npm run start -- --host 0.0.0.0 --port 7000";
+ }
if (ExecutionContext.Instance.ProjectConfig.RepositoryType == RepositoryType.App)
{
diff --git a/cmf-cli/Commands/new/HelpCommand.cs b/cmf-cli/Commands/new/HelpCommand.cs
index f461ecb5d..896575c9a 100644
--- a/cmf-cli/Commands/new/HelpCommand.cs
+++ b/cmf-cli/Commands/new/HelpCommand.cs
@@ -1,4 +1,3 @@
-using System;
using System.Collections.Generic;
using System.CommandLine;
using System.IO.Abstractions;
@@ -16,6 +15,7 @@
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
+using NuGet.Versioning;
namespace Cmf.CLI.Commands.New
{
@@ -64,9 +64,10 @@ protected override List GenerateArgs(IDirectoryInfo projectRoot, IDirect
projectRoot.FullName)
).Replace("\\", "/");
+ var mesVersion = ExecutionContext.Instance.ProjectConfig.MESVersion;
var requireModuleSES =
- ExecutionContext.Instance.ProjectConfig.MESVersion >= new Version(11, 0, 0) &&
- ExecutionContext.Instance.ProjectConfig.MESVersion < new Version(11, 2, 0);
+ mesVersion >= new NuGetVersion(11, 0, 0) &&
+ mesVersion < new NuGetVersion(11, 2, 0);
var angularDeps = ExecutionContext.ServiceProvider.GetService().Angular(ExecutionContext.Instance.ProjectConfig.MESVersion);
@@ -102,7 +103,7 @@ public void Execute(IDirectoryInfo workingDir, string version)
var mesVersion = ExecutionContext.Instance.ProjectConfig.MESVersion;
- this.schematicsVersion = ngxSchematicsVersion ?? $"release-{mesVersion.Major}{mesVersion.Minor}{mesVersion.Build}";
+ this.schematicsVersion = !string.IsNullOrEmpty(ngxSchematicsVersion?.ToString()) ? ngxSchematicsVersion.ToString() : GenericUtilities.GetNpmDistTag(mesVersion);
//Switch between v10 and v11 template
switch (majorVersion)
diff --git a/cmf-cli/Commands/new/IoTCommand.cs b/cmf-cli/Commands/new/IoTCommand.cs
index a7d189f96..8922d24f9 100644
--- a/cmf-cli/Commands/new/IoTCommand.cs
+++ b/cmf-cli/Commands/new/IoTCommand.cs
@@ -7,7 +7,7 @@
using Cmf.CLI.Services;
using Cmf.CLI.Utilities;
using Microsoft.Extensions.DependencyInjection;
-using System;
+using NuGet.Versioning;
using System.Collections.Generic;
using System.CommandLine;
using System.IO.Abstractions;
@@ -114,10 +114,10 @@ public void Execute(IDirectoryInfo workingDir, string version, string htmlPackag
var mesVersion = ExecutionContext.Instance.ProjectConfig.MESVersion;
// (ATL) Automation Task Library Package
// only introduced in v10.2.7
- var executeV10ATL = !isAngularPackage && mesVersion >= new Version(10, 2, 7) && mesVersion < new Version(11, 0, 0);
+ var executeV10ATL = !isAngularPackage && mesVersion >= new NuGetVersion(10, 2, 7) && mesVersion < new NuGetVersion(11, 0, 0);
// only introduced in v11
- var executeV11ATL = !isAngularPackage && mesVersion >= new Version(11, 0, 0);
+ var executeV11ATL = !isAngularPackage && mesVersion >= new NuGetVersion(11, 0, 0);
if (executeV10ATL)
{
@@ -160,7 +160,6 @@ public void ExecuteV10ATL(IDirectoryInfo workingDir, string version)
}
var iotCustomPackageWorkDir = iotCustomPackage.GetFileInfo().Directory;
- var iotCustomPackageName = base.GeneratePackageName(iotCustomPackageWorkDir)!.Value.Item1;
var mesVersion = ExecutionContext.Instance.ProjectConfig.MESVersion;
@@ -175,8 +174,10 @@ public void ExecuteV10AngularPackage(IDirectoryInfo workingDir, string version,
{
throw new CliException(CliMessages.IoTV10HTMLPackageMustBeProvided);
}
-
+
+ var mesVersion = ExecutionContext.Instance.ProjectConfig.MESVersion;
var ngxSchematicsVersion = ExecutionContext.Instance.ProjectConfig.NGXSchematicsVersion;
+ var schematicsVersion = !string.IsNullOrEmpty(ngxSchematicsVersion?.ToString()) ? ngxSchematicsVersion.ToString() : GenericUtilities.GetNpmDistTag(mesVersion);
IDirectoryInfo htmlPackageDir = fileSystem.DirectoryInfo.New(htmlPackageLocation);
@@ -208,11 +209,6 @@ public void ExecuteV10AngularPackage(IDirectoryInfo workingDir, string version,
}
var iotCustomPackageWorkDir = iotCustomPackage.GetFileInfo().Directory;
- var iotCustomPackageName = base.GeneratePackageName(iotCustomPackageWorkDir)!.Value.Item1;
-
- var mesVersion = ExecutionContext.Instance.ProjectConfig.MESVersion;
-
- var schematicsVersion = ngxSchematicsVersion ?? $"release-{mesVersion.Major}{mesVersion.Minor}{mesVersion.Build}";
Log.Debug($"Creating new IoT Workspace {packageName}");
@@ -256,7 +252,7 @@ public void ExecuteV10AngularPackage(IDirectoryInfo workingDir, string version,
"--skip-confirmation", $"@criticalmanufacturing/ngx-iot-schematics@{schematicsVersion}",
"--lint",
"--base-app", baseLayer.ToString(),
- "--version", $"release-{mesVersion.Major}{mesVersion.Minor}{mesVersion.Build}" },
+ "--version", GenericUtilities.GetNpmDistTag(mesVersion) },
WorkingDirectory = iotCustomPackageWorkDir,
ForceColorOutput = false
}.Exec();
@@ -276,7 +272,7 @@ public void ExecuteV10AngularPackage(IDirectoryInfo workingDir, string version,
#endregion Link To HTML Package
}
- private static void InstallYoeman(IDirectoryInfo iotCustomPackageWorkDir, Version mesVersion)
+ private static void InstallYoeman(IDirectoryInfo iotCustomPackageWorkDir, NuGetVersion mesVersion)
{
Log.Debug($"Installing Yeoman");
diff --git a/cmf-cli/Commands/new/TestCommand.cs b/cmf-cli/Commands/new/TestCommand.cs
index 49a8fbc01..f19c37929 100644
--- a/cmf-cli/Commands/new/TestCommand.cs
+++ b/cmf-cli/Commands/new/TestCommand.cs
@@ -6,10 +6,10 @@
using System.Collections.Generic;
using System.CommandLine;
using System.IO.Abstractions;
-using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Cmf.CLI.Services;
+using NuGet.Versioning;
namespace Cmf.CLI.Commands.New
{
@@ -108,7 +108,7 @@ public void Execute(string version)
#region version-specific bits
args.AddRange(new []{ "--targetFramework", ExecutionContext.ServiceProvider.GetService().DotNetTargetFramework(mesVersion) });
- if (mesVersion >= new Version(11, 2, 3))
+ if (mesVersion >= new NuGetVersion(11, 2, 3))
{
args.Add("--hostPerformanceTests");
}
diff --git a/cmf-cli/Commands/new/iot/GenerateDotnetDriverCommand.cs b/cmf-cli/Commands/new/iot/GenerateDotnetDriverCommand.cs
index 83cf0791f..faebe19a2 100644
--- a/cmf-cli/Commands/new/iot/GenerateDotnetDriverCommand.cs
+++ b/cmf-cli/Commands/new/iot/GenerateDotnetDriverCommand.cs
@@ -128,7 +128,7 @@ private List GenerateArgs(
var args = new List();
args.AddRange(new[]
{
- "--targetSystemVersionProcessed", $"release-{mesVersion.Major}{mesVersion.Minor}{mesVersion.Build}",
+ "--targetSystemVersionProcessed", GenericUtilities.GetNpmDistTag(mesVersion),
"--directoryName", directoryName,
"--identifier", identifier,
"--identifierCamel", identifierCamel,
diff --git a/cmf-cli/Commands/new/iot/GenerateDotnetFrameworkDriverCommand.cs b/cmf-cli/Commands/new/iot/GenerateDotnetFrameworkDriverCommand.cs
index 4570a9f68..7bd9ce561 100644
--- a/cmf-cli/Commands/new/iot/GenerateDotnetFrameworkDriverCommand.cs
+++ b/cmf-cli/Commands/new/iot/GenerateDotnetFrameworkDriverCommand.cs
@@ -123,7 +123,7 @@ private List GenerateArgs(
var args = new List();
args.AddRange(new[]
{
- "--targetSystemVersionProcessed", $"release-{mesVersion.Major}{mesVersion.Minor}{mesVersion.Build}",
+ "--targetSystemVersionProcessed", GenericUtilities.GetNpmDistTag(mesVersion),
"--directoryName", directoryName,
"--identifier", identifier,
"--identifierCamel", identifierCamel,
diff --git a/cmf-cli/Commands/new/iot/GenerateDriverCommand.cs b/cmf-cli/Commands/new/iot/GenerateDriverCommand.cs
index 085fa75cc..b2504fd25 100644
--- a/cmf-cli/Commands/new/iot/GenerateDriverCommand.cs
+++ b/cmf-cli/Commands/new/iot/GenerateDriverCommand.cs
@@ -143,7 +143,7 @@ private List GenerateArgs(
var args = new List();
args.AddRange(new[]
{
- "--targetSystemVersionProcessed", $"release-{mesVersion.Major}{mesVersion.Minor}{mesVersion.Build}",
+ "--targetSystemVersionProcessed", GenericUtilities.GetNpmDistTag(mesVersion),
"--directoryName", directoryName,
"--identifier", identifier,
"--identifierCamel", identifierCamel,
diff --git a/cmf-cli/Commands/new/iot/GenerateTaskLibraryCommand.cs b/cmf-cli/Commands/new/iot/GenerateTaskLibraryCommand.cs
index 6dff59428..09a45ce45 100644
--- a/cmf-cli/Commands/new/iot/GenerateTaskLibraryCommand.cs
+++ b/cmf-cli/Commands/new/iot/GenerateTaskLibraryCommand.cs
@@ -130,7 +130,7 @@ private List GenerateArgs(
"--identifierLower", identifier.Replace(" ", "").ToLower().Trim(),
"--packageName", fullPackageName,
"--packageVersion", packageVersion,
- "--targetSystemVersionProcessed", $"release-{mesVersion.Major}{mesVersion.Minor}{mesVersion.Build}",
+ "--targetSystemVersionProcessed", GenericUtilities.GetNpmDistTag(mesVersion),
"--dependsOnScope", JsonConvert.SerializeObject(dependsOnScope),
"--mandatoryForScope", JsonConvert.SerializeObject(mandatoryForScope),
"--dependsOnProtocol", JsonConvert.SerializeObject(dependsOnProtocol),
diff --git a/cmf-cli/Commands/upgrade/UpgradeBaseCommand.cs b/cmf-cli/Commands/upgrade/UpgradeBaseCommand.cs
index eff96cb4c..609ef8f43 100644
--- a/cmf-cli/Commands/upgrade/UpgradeBaseCommand.cs
+++ b/cmf-cli/Commands/upgrade/UpgradeBaseCommand.cs
@@ -6,7 +6,7 @@
using Cmf.CLI.Factories;
using Cmf.CLI.Utilities;
using Microsoft.Extensions.DependencyInjection;
-using System;
+using NuGet.Versioning;
using System.Collections.Generic;
using System.CommandLine;
using System.IO;
@@ -144,7 +144,7 @@ private void UpdateProjectConfig(IDirectoryInfo packagePath, string baseVersion)
text = UpgradeBaseUtilities.UpdateJsonValue(text, key, baseVersion);
}
- if (new Version(baseVersion).Major >= 11)
+ if (NuGetVersion.Parse(baseVersion).Major >= 11)
{
// TODO: find a more elegant way to apply these changes to files/packages when this command is executed.
// For the moment, sneaking this if-statement in will do the job but long-term we'll need an approach that
diff --git a/cmf-cli/Handlers/PackageType/IoTPackageTypeHandler.cs b/cmf-cli/Handlers/PackageType/IoTPackageTypeHandler.cs
index 640ece42e..b29874a9a 100644
--- a/cmf-cli/Handlers/PackageType/IoTPackageTypeHandler.cs
+++ b/cmf-cli/Handlers/PackageType/IoTPackageTypeHandler.cs
@@ -9,6 +9,7 @@
using Cmf.CLI.Utilities;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
+using NuGet.Versioning;
using System;
using System.Collections.Generic;
using System.IO;
@@ -479,12 +480,12 @@ private bool IsAngularProject(string path)
"angular.json"));
}
- private List AddAutomationTaskLibrariesStep(Version targetVersion, CmfPackage cmfPackage, List defaultSteps, string packageLocation = "src")
+ private List AddAutomationTaskLibrariesStep(NuGetVersion targetVersion, CmfPackage cmfPackage, List defaultSteps, string packageLocation = "src")
{
// Introduced in version 10.2.x
if ((targetVersion.Major > 10 || (targetVersion.Major == 10 &&
targetVersion.Minor >= 2 &&
- targetVersion.Build >= 7)) && !this.IsAngularProject(cmfPackage.GetFileInfo().Directory.FullName))
+ targetVersion.Patch >= 7)) && !this.IsAngularProject(cmfPackage.GetFileInfo().Directory.FullName))
{
var packages = string.Join(",", this.GetPackagesWithTaskLibraries(this.GetPackageJsons(cmfPackage, packageLocation)));
@@ -499,10 +500,10 @@ private List AddAutomationTaskLibrariesStep(Version targetVersion, CmfPack
return defaultSteps;
}
- private List AddAutomationBusinessScenarioStep(Version targetVersion, CmfPackage cmfPackage, List defaultSteps, string packageLocation = "src")
+ private List AddAutomationBusinessScenarioStep(NuGetVersion targetVersion, CmfPackage cmfPackage, List defaultSteps, string packageLocation = "src")
{
// Introduced in version 11.1.x
- if ((targetVersion.Major > 11 || (targetVersion.Major == 11 && targetVersion.Minor >= 1)))
+ if (targetVersion.Major > 11 || (targetVersion.Major == 11 && targetVersion.Minor >= 1))
{
var packages = string.Join(",", this.GetPackagesWithBusinessScenarios(this.GetPackageJsons(cmfPackage, packageLocation)));
diff --git a/cmf-cli/Program.cs b/cmf-cli/Program.cs
index 9cc94fd72..fdfbe36a0 100644
--- a/cmf-cli/Program.cs
+++ b/cmf-cli/Program.cs
@@ -78,7 +78,7 @@ public static async Task Main(string[] args)
.InitializeClientsForRepositories(ExecutionContext.Instance.FileSystem);
// Global validation for all CLI core commands
- ValidateMesVersion(ExecutionContext.Instance.ProjectConfig?.MESVersion?.Major);
+ ValidateMesVersion(ExecutionContext.Instance.ProjectConfig?.MESVersion.Major);
// Parse and invoke using beta5 pattern
var parseResult = rootCommand.Parse(args);
diff --git a/cmf-cli/Utilities/NodeVersionUtilities.cs b/cmf-cli/Utilities/NodeVersionUtilities.cs
index c9808cd6e..10b8760f7 100644
--- a/cmf-cli/Utilities/NodeVersionUtilities.cs
+++ b/cmf-cli/Utilities/NodeVersionUtilities.cs
@@ -1,4 +1,5 @@
using Cmf.CLI.Core;
+using NuGet.Versioning;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
@@ -15,7 +16,7 @@ public static class NodeVersionUtilities
/// Gets the installed Node.js version
///
/// The installed Node.js version, or null if Node.js is not installed
- public static Version GetInstalledNodeVersion()
+ public static NuGetVersion GetInstalledNodeVersion()
{
try
{
@@ -51,7 +52,7 @@ public static Version GetInstalledNodeVersion()
int major = int.Parse(match.Groups[1].Value);
int minor = int.Parse(match.Groups[2].Value);
int patch = int.Parse(match.Groups[3].Value);
- return new Version(major, minor, patch);
+ return new NuGetVersion(major, minor, patch);
}
return null;
@@ -69,7 +70,7 @@ public static Version GetInstalledNodeVersion()
/// The target MES version
/// The required Node.js major version
/// Thrown when Node.js is not installed or the version is incompatible
- public static void ValidateNodeVersion(Version mesVersion, string requiredNodeMajorVersion)
+ public static void ValidateNodeVersion(SemanticVersion mesVersion, string requiredNodeMajorVersion)
{
var installedVersion = GetInstalledNodeVersion();
diff --git a/cmf-cli/Utilities/UpgradeBaseUtilities.cs b/cmf-cli/Utilities/UpgradeBaseUtilities.cs
index 41838a2af..421b571d6 100644
--- a/cmf-cli/Utilities/UpgradeBaseUtilities.cs
+++ b/cmf-cli/Utilities/UpgradeBaseUtilities.cs
@@ -2,15 +2,14 @@
using System.IO;
using System.IO.Abstractions;
using System.Linq;
-using System.Reflection;
using System.Text.RegularExpressions;
using Cmf.CLI.Core;
using Cmf.CLI.Core.Objects;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using Cmf.CLI.Core.Enums;
-using System.Text.Json.Nodes;
using System.Runtime.CompilerServices;
+using NuGet.Versioning;
[assembly: InternalsVisibleTo("tests")]
namespace Cmf.CLI.Utilities
@@ -54,12 +53,14 @@ public static void UpdateNPMProject(IFileSystem fileSystem, CmfPackage cmfPackag
{
// package.json files
string[] filesToUpdate = fileSystem.Directory.GetFiles(cmfPackage.GetFileInfo().DirectoryName, "package.json", SearchOption.AllDirectories);
- string pattern = @"release-\d+";
+ // matches any npm dist-tag in the "{label}-{version}" convention (e.g. "release-1200", "alpha-1200", "next-1200")
+ string pattern = @"(?:release|alpha|beta|rc|next|canary|preview)-\d+";
+ string newDistTag = GenericUtilities.GetNpmDistTag(NuGetVersion.Parse(version));
foreach (string filePath in filesToUpdate.Where(path => !path.Contains("node_modules") && !path.Contains("dist")))
{
string text = fileSystem.File.ReadAllText(filePath);
- text = Regex.Replace(text, pattern, $"release-{version.Replace(".", "")}", RegexOptions.IgnoreCase);
+ text = Regex.Replace(text, pattern, newDistTag, RegexOptions.IgnoreCase);
fileSystem.File.WriteAllText(filePath, text);
}
diff --git a/cmf-cli/cmf.csproj b/cmf-cli/cmf.csproj
index 51c4bb68b..a32392f5b 100644
--- a/cmf-cli/cmf.csproj
+++ b/cmf-cli/cmf.csproj
@@ -15,7 +15,7 @@
Name
Namespace
Namespaces
- 6.0.0-2
+ 6.0.0-3
diff --git a/cmf-cli/resources/template_feed/init/.template.config/template.json b/cmf-cli/resources/template_feed/init/.template.config/template.json
index af8ebda82..f6b0cd991 100644
--- a/cmf-cli/resources/template_feed/init/.template.config/template.json
+++ b/cmf-cli/resources/template_feed/init/.template.config/template.json
@@ -608,17 +608,17 @@
"forms": {
"versionToMajor": {
"identifier": "replace",
- "pattern": "(\\d+)\\.(\\d+)\\.(\\d+)",
+ "pattern": "^(\\d+)\\.\\d+\\.\\d+\\.?\\d*(?:[-+].*)?$",
"replacement": "$1"
},
"versionToMajorRange": {
"identifier": "replace",
- "pattern": "(\\d+)\\.(\\d+)\\.(\\d+).*",
+ "pattern": "^(\\d+)\\.\\d+\\.\\d+\\.?\\d*(?:[-+].*)?$",
"replacement": "$1.x.x"
},
"versionToFeature": {
"identifier": "replace",
- "pattern": "(\\d+)\\.(\\d+)\\.(\\d+)",
+ "pattern": "^(\\d+)\\.(\\d+)\\.\\d+\\.?\\d*(?:[-+].*)?$",
"replacement": "$1.$2.x"
},
"stripQuotes": {
diff --git a/cmf-cli/services/DependencyVersionService.cs b/cmf-cli/services/DependencyVersionService.cs
index bf408f460..d8f64281a 100644
--- a/cmf-cli/services/DependencyVersionService.cs
+++ b/cmf-cli/services/DependencyVersionService.cs
@@ -1,4 +1,5 @@
using System;
+using NuGet.Versioning;
namespace Cmf.CLI.Services;
@@ -21,35 +22,35 @@ public interface IDependencyVersionService
///
/// The product version to use
/// String representing the .NET SDK version
- string DotNetSdk(Version productVersion);
+ string DotNetSdk(NuGetVersion productVersion);
///
/// Returns the expected .NET Target Framework for the given product version
///
///
/// String representing the .NET Target Framework
- string DotNetTargetFramework(Version productVersion);
+ string DotNetTargetFramework(NuGetVersion productVersion);
///
/// Returns the expected Node.js version for the given product version
///
/// The product version to use
/// String representing the Node.js version
- string Node(Version productVersion);
+ string Node(SemanticVersion productVersion);
///
/// Returns the expected Angular CLI major version for the given product version
///
/// The product version to use
/// String representing the Angular CLI major version
- string AngularCLI(Version productVersion);
+ string AngularCLI(SemanticVersion productVersion);
///
/// Returns the expected Angular dependencies for the given product version
///
/// The product version to use
/// AngularDeps representing the Angular dependencies
- AngularDeps Angular(Version productVersion);
+ AngularDeps Angular(SemanticVersion productVersion);
}
///
@@ -59,31 +60,56 @@ public class DependencyVersionService : IDependencyVersionService
{
public const string NET6TARGETFRAMEWORK = "net6.0";
public const string NET8TARGETFRAMEWORK = "net8.0";
+ public const string NET10TARGETFRAMEWORK = "net10.0";
public const string NET6SDK = "6.0.201"; // avoid >2xx as it requires HTTPS for nuget pulls
public const string NET8SDK = "8.0.301";
+ public const string NET10SDK = "10.0.301";
+ public const string NODE24 = "24";
public const string NODE20 = "20";
public const string NODE18 = "18";
public const string NG15 = "15.2.1";
public const string NG17 = "17.2.1";
public const string NG21 = "21.1.0";
+ public const string NG22 = "22.1.2";
public const string NG15_ZONE = "0.12.0";
public const string NG17_ZONE = "0.14.3";
public const string NG21_ZONE = "0.16.0";
+ public const string NG22_ZONE = "0.16.2";
public const string NG15_TSESLINT = "5.44.0";
public const string NG17_TSESLINT = "6.10.0";
public const string NG21_TSESLINT = "8.52.0";
+ public const string NG22_TSESLINT = "8.67.0";
public const string NG15_ESLINT = "8.28.0";
public const string NG17_ESLINT = "8.53.0";
public const string NG21_ESLINT = "9.39.2";
+ public const string NG22_ESLINT = "10.8.1";
public const string NG15_TS = "4.8.4";
public const string NG17_TS = "5.3.3";
public const string NG21_TS = "5.9.3";
+ public const string NG22_TS = "6.0.3";
- public string DotNetSdk(Version productVersion) => productVersion.Major >= 11 ? NET8SDK : NET6SDK;
- public string DotNetTargetFramework(Version productVersion) => productVersion.Major >= 11 ? NET8TARGETFRAMEWORK : NET6TARGETFRAMEWORK;
- public string Node(Version productVersion) => productVersion.Major >= 11 ? NODE20 : NODE18;
+ public string DotNetSdk(NuGetVersion productVersion) =>
+ productVersion.Major >= 12
+ ? NET10SDK
+ : productVersion.Major >= 11
+ ? NET8SDK
+ : NET6SDK;
- public AngularDeps Angular(Version productVersion) =>
+ public string DotNetTargetFramework(NuGetVersion productVersion) =>
+ productVersion.Major >= 12
+ ? NET10TARGETFRAMEWORK
+ : productVersion.Major >= 11
+ ? NET8TARGETFRAMEWORK
+ : NET6TARGETFRAMEWORK;
+
+ public string Node(SemanticVersion productVersion) =>
+ productVersion.Major >= 12
+ ? NODE24
+ : productVersion.Major >= 11
+ ? NODE20
+ : NODE18;
+
+ public AngularDeps Angular(SemanticVersion productVersion) =>
productVersion.Major switch
{
<= 10 => new AngularDeps()
@@ -104,14 +130,14 @@ public AngularDeps Angular(Version productVersion) =>
},
12 => new AngularDeps()
{
- CLI = Version.Parse(NG21),
- Zone = NG21_ZONE,
- Typescript = NG21_TS,
- ESLint = NG21_ESLINT,
- TSESLint = NG21_TSESLINT
+ CLI = Version.Parse(NG22),
+ Zone = NG22_ZONE,
+ Typescript = NG22_TS,
+ ESLint = NG22_ESLINT,
+ TSESLint = NG22_TSESLINT
},
_ => throw new NotSupportedException($"No Angular dependencies defined for MES version {productVersion}")
};
- public string AngularCLI(Version productVersion) => this.Angular(productVersion).CLI.Major.ToString();
+ public string AngularCLI(SemanticVersion productVersion) => this.Angular(productVersion).CLI.Major.ToString();
}
\ No newline at end of file
diff --git a/core/Objects/MESVersionValidationService.cs b/core/Objects/MESVersionValidationService.cs
index e00c5505c..5bc140725 100644
--- a/core/Objects/MESVersionValidationService.cs
+++ b/core/Objects/MESVersionValidationService.cs
@@ -1,4 +1,6 @@
using System;
+using Cmf.CLI.Utilities;
+using NuGet.Versioning;
namespace Cmf.CLI.Core.Objects
{
@@ -43,9 +45,9 @@ public void ValidateMinimumVersion(string minimumVersion)
return; // No validation needed if no minimum version is specified
}
- if (!Version.TryParse(minimumVersion, out Version minVersion))
+ if (!NuGetVersion.TryParse(minimumVersion, out NuGetVersion minVersion))
{
- throw new ArgumentException($"Invalid minimum version format: {minimumVersion}. Expected format: 'Major.Minor.Build' (e.g., '11.0.0')");
+ throw new ArgumentException($"Invalid minimum version format: {minimumVersion}.");
}
var currentVersion = ExecutionContext.Instance?.ProjectConfig?.MESVersion;
@@ -68,7 +70,7 @@ public bool IsVersionCompatible(string minimumVersion)
return true; // No minimum version requirement
}
- if (!Version.TryParse(minimumVersion, out Version minVersion))
+ if (!NuGetVersion.TryParse(minimumVersion, out var minVersion))
{
return false;
}
diff --git a/core/Objects/ProjectConfig/ProjectConfigV1.cs b/core/Objects/ProjectConfig/ProjectConfigV1.cs
index 7e0ec5892..7fe45cd8f 100644
--- a/core/Objects/ProjectConfig/ProjectConfigV1.cs
+++ b/core/Objects/ProjectConfig/ProjectConfigV1.cs
@@ -1,6 +1,7 @@
using System;
using System.Text.Json.Serialization;
using Cmf.CLI.Core.Enums;
+using Cmf.CLI.Utilities;
using Newtonsoft.Json;
using NuGet.Versioning;
@@ -26,13 +27,20 @@ public class ProjectConfigV1
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
public int? RESTPort { get; set; }
public string Tenant { get; set; }
- public Version MESVersion { get; set; }
+ [Newtonsoft.Json.JsonConverter(typeof(VersionStringConverter))]
+ public NuGetVersion MESVersion { get; set; }
+ [Newtonsoft.Json.JsonConverter(typeof(VersionStringConverter))]
public SemanticVersion DevTasksVersion { get; set; }
- public Version HTMLStarterVersion { get; set; }
+ [Newtonsoft.Json.JsonConverter(typeof(VersionStringConverter))]
+ public SemanticVersion HTMLStarterVersion { get; set; }
+ [Newtonsoft.Json.JsonConverter(typeof(VersionStringConverter))]
public SemanticVersion YoGeneratorVersion { get; set; }
- public string NGXSchematicsVersion { get; set; }
- public Version NugetVersion { get; set; }
- public Version TestScenariosNugetVersion { get; set; }
+ [Newtonsoft.Json.JsonConverter(typeof(VersionStringConverter))]
+ public SemanticVersion NGXSchematicsVersion { get; set; }
+ [Newtonsoft.Json.JsonConverter(typeof(VersionStringConverter))]
+ public NuGetVersion NugetVersion { get; set; }
+ [Newtonsoft.Json.JsonConverter(typeof(VersionStringConverter))]
+ public NuGetVersion TestScenariosNugetVersion { get; set; }
[Newtonsoft.Json.JsonConverter(typeof(BooleanJsonConverter))]
public bool IsSslEnabled { get; set; }
public string vmHostname { get; set; }
@@ -69,6 +77,48 @@ public class ProjectConfigV1
public string Product { get; set; }
}
+/***
+ * Converts project-config version strings into the concrete CLR types expected by the model.
+ * This is required because .project-config.json stores values as strings while fields such as
+ * MESVersion and NugetVersion are typed as NuGetVersion/SemanticVersion instances.
+ * Without this conversion, Json.NET can try to assign a SemanticVersion to a NuGetVersion and throw
+ * an invalid cast when prerelease values such as "12.0.0-beta.1" are deserialized.
+ */
+public class VersionStringConverter : Newtonsoft.Json.JsonConverter
+ where T : class
+{
+ public override T ReadJson(JsonReader reader, Type objectType, T existingValue, bool hasExistingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null || reader.Value is null)
+ {
+ return null;
+ }
+
+ var value = reader.Value?.ToString();
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return null;
+ }
+
+ if (typeof(T) == typeof(NuGetVersion))
+ {
+ return (T)(object)NuGetVersion.Parse(value);
+ }
+
+ if (typeof(T) == typeof(SemanticVersion))
+ {
+ return (T)(object)SemanticVersion.Parse(value);
+ }
+
+ throw new NotSupportedException($"Unsupported version type: {typeof(T).FullName}");
+ }
+
+ public override void WriteJson(JsonWriter writer, T value, JsonSerializer serializer)
+ {
+ writer.WriteValue(value?.ToString());
+ }
+}
+
public class BooleanJsonConverter : Newtonsoft.Json.JsonConverter
{
public override bool CanRead => true;
diff --git a/core/Services/CmfPackageController.cs b/core/Services/CmfPackageController.cs
index 67b148d96..d6493c771 100644
--- a/core/Services/CmfPackageController.cs
+++ b/core/Services/CmfPackageController.cs
@@ -158,9 +158,12 @@ public CmfPackageController(IFileInfo file, IFileSystem fileSystem = null, bool
Log.Debug("File is a DF package in TAR.GZ format");
using Stream zipToOpen = file.OpenRead();
using GZipStream gzipStream = new GZipStream(zipToOpen, CompressionMode.Decompress);
+ using var decompressedStream = new MemoryStream();
+ gzipStream.CopyTo(decompressedStream);
+ decompressedStream.Position = 0;
var foundManifest = false;
- using var tarReader = SharpCompress.Readers.Tar.TarReader.Open(gzipStream, new SharpCompress.Readers.ReaderOptions { });
+ using var tarReader = SharpCompress.Readers.Tar.TarReader.OpenReader(decompressedStream, new SharpCompress.Readers.ReaderOptions { });
while (tarReader.MoveToNextEntry())
{
var entry = tarReader.Entry;
@@ -183,7 +186,10 @@ public CmfPackageController(IFileInfo file, IFileSystem fileSystem = null, bool
{
using Stream zipToOpen2 = file.OpenRead();
using GZipStream gzipStream2 = new GZipStream(zipToOpen2, CompressionMode.Decompress);
- using var tarReader2 = SharpCompress.Readers.Tar.TarReader.Open(gzipStream2, new SharpCompress.Readers.ReaderOptions { });
+ using var decompressedStream2 = new MemoryStream();
+ gzipStream2.CopyTo(decompressedStream2);
+ decompressedStream2.Position = 0;
+ using var tarReader2 = SharpCompress.Readers.Tar.TarReader.OpenReader(decompressedStream2, new SharpCompress.Readers.ReaderOptions { });
while (tarReader2.MoveToNextEntry())
{
@@ -782,9 +788,9 @@ public static CmfPackageV1 FromJson(JObject json)
var auxArr = (JObject)rootNode.Value;
var steps = new List();
- if (auxArr.Property("steps").Value.Type == JTokenType.Array)
+ var stepsProperty = auxArr.Property("steps");
+ if (stepsProperty?.Value is JArray stepsEl)
{
- var stepsEl = (JArray)auxArr.Property("steps").Value;
if (stepsEl != null)
{
diff --git a/core/Utilities/GenericUtilities.cs b/core/Utilities/GenericUtilities.cs
index ba9f162b0..785a39cf3 100644
--- a/core/Utilities/GenericUtilities.cs
+++ b/core/Utilities/GenericUtilities.cs
@@ -7,6 +7,7 @@
using Cmf.CLI.Core.Enums;
using Cmf.CLI.Core.Objects;
using Cmf.CLI.Core.Repository.Credentials;
+using NuGet.Versioning;
using Spectre.Console;
namespace Cmf.CLI.Utilities
@@ -183,6 +184,7 @@ public static IEnumerable Flatten(
{
return string.IsNullOrEmpty(value?.Value) ? null : new Uri(value!.Value);
}
+#nullable disable
///
/// Builds a tree representation of a CmfPackage dependency tree
@@ -281,6 +283,19 @@ public static string BuildEnvVarPrefix(RepositoryCredentialsType repositoryType,
return repositoryType.ToString().ToLower() + "__" + new string(baseUri.Select(ch => strip.Contains(ch) ? '_' : ch).ToArray());
}
+ ///
+ /// Computes the npm dist-tag for a full SemVer value, preserving the prerelease label when present.
+ ///
+ /// the parsed NuGet version to convert
+ /// the npm dist-tag for
+ public static string GetNpmDistTag(NuGetVersion version)
+ {
+ // ReleaseLabels are dot separated values from the pre-release part of the version, e.g. "alpha.1" or "beta.2".
+ // We only want the first label (e.g. "alpha" or "beta") for the dist-tag.
+ var label = version.IsPrerelease ? version.ReleaseLabels.FirstOrDefault() : null;
+ return $"{(string.IsNullOrWhiteSpace(label) ? "release" : label)}-{version.Major}{version.Minor}{version.Patch}";
+ }
+
#endregion Public Methods
#region Private Methods
diff --git a/core/core.csproj b/core/core.csproj
index 6875b304e..e6ff0d219 100644
--- a/core/core.csproj
+++ b/core/core.csproj
@@ -4,7 +4,7 @@
net10.0
CriticalManufacturing.CLI.Core
Cmf.CLI.Core
- 6.0.0-2
+ 6.0.0-3
CriticalManufacturing
CriticalManufacturing
BSD-3-Clause
@@ -25,7 +25,7 @@
-
+
diff --git a/npm/package-lock.json b/npm/package-lock.json
index c36e4fa2d..93bf2d647 100644
--- a/npm/package-lock.json
+++ b/npm/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@criticalmanufacturing/cli",
- "version": "6.0.0-2",
+ "version": "6.0.0-3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@criticalmanufacturing/cli",
- "version": "6.0.0-2",
+ "version": "6.0.0-3",
"hasInstallScript": true,
"license": "BSD-3-Clause",
"dependencies": {
diff --git a/npm/package.json b/npm/package.json
index 9e07a082b..2bb7b7789 100644
--- a/npm/package.json
+++ b/npm/package.json
@@ -1,6 +1,6 @@
{
"name": "@criticalmanufacturing/cli",
- "version": "6.0.0-2",
+ "version": "6.0.0-3",
"description": "Critical Manufacturing command line client",
"bin": {
"cmf": "run.js"
diff --git a/tests/Objects/DFTGZPackageBuilder.cs b/tests/Objects/DFTGZPackageBuilder.cs
index b00d9a20c..e8393c639 100644
--- a/tests/Objects/DFTGZPackageBuilder.cs
+++ b/tests/Objects/DFTGZPackageBuilder.cs
@@ -83,8 +83,7 @@ public DFTGZPackageBuilder CreateManifest(string id, string version, Dictionary<
///
public byte[] ToByteArray()
{
- // Flush ZipArchive
- // gzArchive.Flush();
+ tarArchive.Dispose();
gzArchive.Dispose();
byte[] result = memoryStream.ToArray();
diff --git a/tests/Specs/CmfPackageController_FromTgz.cs b/tests/Specs/CmfPackageController_FromTgz.cs
new file mode 100644
index 000000000..c77378501
--- /dev/null
+++ b/tests/Specs/CmfPackageController_FromTgz.cs
@@ -0,0 +1,149 @@
+using System.IO.Abstractions.TestingHelpers;
+using Cmf.CLI.Core.Constants;
+using Cmf.CLI.Core.Services;
+using FluentAssertions;
+using tests.Objects;
+using Xunit;
+
+namespace tests.Specs;
+
+public class CmfPackageController_FromTgz
+{
+ [Fact]
+ public void Constructor_ShouldReadXmlManifest_FromPackageFolderInTgz()
+ {
+ var fileSystem = new MockFileSystem();
+ fileSystem.Directory.CreateDirectory("/repo");
+ var packageFile = fileSystem.FileInfo.New("/repo/package.tgz");
+ var manifestXml = $"""
+
+
+ Cmf.Custom.Data
+ 1.2.3
+
+ """;
+
+ var archiveBytes = new DFTGZPackageBuilder()
+ .CreateEntry($"package/{CoreConstants.DeploymentFrameworkManifestFileName}", manifestXml)
+ .ToByteArray();
+
+ using (var stream = packageFile.Create())
+ {
+ stream.Write(archiveBytes, 0, archiveBytes.Length);
+ stream.Flush();
+ }
+
+ var controller = new CmfPackageController(packageFile, fileSystem);
+
+ controller.CmfPackage.Should().NotBeNull();
+ controller.CmfPackage.PackageId.Should().Be("Cmf.Custom.Data");
+ controller.CmfPackage.Version.Should().Be("1.2.3");
+ }
+
+ [Fact]
+ public void Constructor_ShouldReadJsonManifest_FromPackageFolderInTgz()
+ {
+ var fileSystem = new MockFileSystem();
+ fileSystem.Directory.CreateDirectory("/repo");
+ var packageFile = fileSystem.FileInfo.New("/repo/package.tgz");
+ var manifestJson = """
+ {
+ "name": "Cmf.Custom.Data",
+ "version": "1.2.3",
+ "packageName": "Cmf.Custom.Data",
+ "description": "Sample package",
+ "packageType": "Generic",
+ "keywords": ["cmf-deployment-package"],
+ "deployment": {
+ "packageId": "Cmf.Custom.Data",
+ "version": "1.2.3"
+ }
+ }
+ """;
+
+ var archiveBytes = new DFTGZPackageBuilder()
+ .CreateEntry($"package/{CoreConstants.PackageJson}", manifestJson)
+ .ToByteArray();
+
+ using (var stream = packageFile.Create())
+ {
+ stream.Write(archiveBytes, 0, archiveBytes.Length);
+ stream.Flush();
+ }
+
+ var controller = new CmfPackageController(packageFile, fileSystem);
+
+ controller.CmfPackage.Should().NotBeNull();
+ controller.CmfPackage.PackageId.Should().Be("Cmf.Custom.Data");
+ controller.CmfPackage.Version.Should().Be("1.2.3");
+ }
+
+ [Fact]
+ public void Constructor_ShouldReadXmlManifest_FromRootOfTgz()
+ {
+ var fileSystem = new MockFileSystem();
+ fileSystem.Directory.CreateDirectory("/repo");
+ var packageFile = fileSystem.FileInfo.New("/repo/package.tgz");
+ var manifestXml = $"""
+
+
+ Cmf.Custom.Root
+ 2.0.0
+
+ """;
+
+ var archiveBytes = new DFTGZPackageBuilder()
+ .CreateEntry(CoreConstants.DeploymentFrameworkManifestFileName, manifestXml)
+ .ToByteArray();
+
+ using (var stream = packageFile.Create())
+ {
+ stream.Write(archiveBytes, 0, archiveBytes.Length);
+ stream.Flush();
+ }
+
+ var controller = new CmfPackageController(packageFile, fileSystem);
+
+ controller.CmfPackage.Should().NotBeNull();
+ controller.CmfPackage.PackageId.Should().Be("Cmf.Custom.Root");
+ controller.CmfPackage.Version.Should().Be("2.0.0");
+ }
+
+ [Fact]
+ public void Constructor_ShouldReadJsonManifest_WithoutSteps_FromRootOfTgz()
+ {
+ var fileSystem = new MockFileSystem();
+ fileSystem.Directory.CreateDirectory("/repo");
+ var packageFile = fileSystem.FileInfo.New("/repo/package.tgz");
+ var manifestJson = """
+ {
+ "name": "Cmf.Custom.Root",
+ "version": "2.0.0",
+ "packageName": "Cmf.Custom.Root",
+ "description": "Sample package without steps",
+ "keywords": ["cmf-deployment-package"],
+ "deployment": {
+ "packageType": "Generic",
+ "packageId": "Cmf.Custom.Root",
+ "version": "2.0.0"
+ }
+ }
+ """;
+
+ var archiveBytes = new DFTGZPackageBuilder()
+ .CreateEntry(CoreConstants.PackageJson, manifestJson)
+ .ToByteArray();
+
+ using (var stream = packageFile.Create())
+ {
+ stream.Write(archiveBytes, 0, archiveBytes.Length);
+ stream.Flush();
+ }
+
+ var controller = new CmfPackageController(packageFile, fileSystem);
+
+ controller.CmfPackage.Should().NotBeNull();
+ controller.CmfPackage.PackageId.Should().Be("Cmf.Custom.Root");
+ controller.CmfPackage.Version.Should().Be("2.0.0");
+ }
+}
diff --git a/tests/Specs/GenericUtilitiesTests.cs b/tests/Specs/GenericUtilitiesTests.cs
new file mode 100644
index 000000000..3f6de739a
--- /dev/null
+++ b/tests/Specs/GenericUtilitiesTests.cs
@@ -0,0 +1,148 @@
+using System;
+using Cmf.CLI.Core.Objects;
+using Cmf.CLI.Utilities;
+using FluentAssertions;
+using NuGet.Versioning;
+using Xunit;
+
+namespace tests.Specs
+{
+ public class GenericUtilitiesTests
+ {
+ [Theory]
+ [InlineData("12.0.0", 12, 0, 0)]
+ [InlineData("11.1.5", 11, 1, 5)]
+ [InlineData("10.0.0.0", 10, 0, 0)]
+ public void ParseVersion_PlainVersion_ParsesCorrectly(string version, int major, int minor, int patch)
+ {
+ var result = NuGetVersion.Parse(version);
+
+ result.Major.Should().Be(major);
+ result.Minor.Should().Be(minor);
+ result.Patch.Should().Be(patch);
+ result.IsPrerelease.Should().BeFalse();
+ }
+
+ [Theory]
+ [InlineData("12.0.0-alpha.1", 12, 0, 0, "alpha.1")]
+ [InlineData("12.0.0-beta", 12, 0, 0, "beta")]
+ [InlineData("11.1.5-rc.2+build.123", 11, 1, 5, "rc.2")]
+ public void ParseVersion_PreReleaseVersion_PreservesPreReleaseLabel(string version, int major, int minor, int patch, string expectedRelease)
+ {
+ var result = NuGetVersion.Parse(version);
+
+ result.Major.Should().Be(major);
+ result.Minor.Should().Be(minor);
+ result.Patch.Should().Be(patch);
+ result.IsPrerelease.Should().BeTrue();
+ result.Release.Should().Be(expectedRelease);
+ }
+
+ [Fact]
+ public void ParseVersion_NullOrEmpty_Throws()
+ {
+ ((Action)(() => NuGetVersion.Parse(null))).Should().Throw();
+ ((Action)(() => NuGetVersion.Parse(""))).Should().Throw();
+ ((Action)(() => NuGetVersion.Parse(" "))).Should().Throw();
+ }
+
+ [Fact]
+ public void ParseVersion_Invalid_Throws()
+ {
+ ((Action)(() => NuGetVersion.Parse("not-a-version"))).Should().Throw();
+ }
+
+ [Theory]
+ [InlineData("12.0.0-alpha.1")]
+ [InlineData("12.0.0")]
+ public void TryParseVersion_ValidVersions_ReturnsTrue(string version)
+ {
+ var success = NuGetVersion.TryParse(version, out var result);
+
+ success.Should().BeTrue();
+ result.Major.Should().Be(12);
+ result.Minor.Should().Be(0);
+ result.Patch.Should().Be(0);
+ }
+
+ [Fact]
+ public void TryParseVersion_Invalid_ReturnsFalse()
+ {
+ var success = NuGetVersion.TryParse("not-a-version", out var result);
+
+ success.Should().BeFalse();
+ result.Should().BeNull();
+ }
+
+ [Fact]
+ public void ParseVersion_PreReleaseAndPlainVersions_AreComparableAndOrdered()
+ {
+ // this mirrors how MESVersion is used across the CLI: comparisons must keep working
+ // regardless of a pre-release label being present in the original string
+ var preRelease = NuGetVersion.Parse("12.0.0-alpha.1");
+ var release = NuGetVersion.Parse("12.0.0");
+ var older = NuGetVersion.Parse("11.0.0");
+
+ // a pre-release version sorts before its associated release version, per semver rules
+ (preRelease < release).Should().BeTrue();
+ (preRelease > older).Should().BeTrue();
+ }
+
+ [Theory]
+ [InlineData("12.0.0", "release-1200")]
+ [InlineData("11.1.5", "release-1115")]
+ [InlineData("12.0.0-alpha.1", "alpha-1200")]
+ [InlineData("12.0.0-next.2", "next-1200")]
+ [InlineData("11.1.5-beta.2", "beta-1115")]
+ public void GetNpmDistTag_NuGetVersion_ComputesExpectedDistTag(string version, string expectedDistTag)
+ {
+ var nuGetVersion = NuGetVersion.Parse(version);
+
+ var result = GenericUtilities.GetNpmDistTag(nuGetVersion);
+
+ result.Should().Be(expectedDistTag);
+ }
+
+ [Fact]
+ public void GetNpmDistTag_PlainVersion_AlwaysUsesReleaseTag()
+ {
+ var result = GenericUtilities.GetNpmDistTag(new NuGetVersion(12, 0, 0));
+
+ result.Should().Be("release-1200");
+ }
+
+ [Fact]
+ public void GetNpmDistTag_PreReleaseVersion_ShouldUsePrereleaseDistTag()
+ {
+ // Prerelease MES versions should map to the corresponding prerelease npm dist-tag rather than the release tag.
+ var result = GenericUtilities.GetNpmDistTag(NuGetVersion.Parse("12.0.0-beta.2"));
+
+ result.Should().Be("beta-1200");
+ }
+
+ [Theory]
+ [InlineData("12.0.0", "release-1200")]
+ [InlineData("12.0.0-beta.2", "beta-1200")]
+ public void GetNpmDistTag_NuGetVersion_UsesSemVerAwareDistTag(string version, string expectedDistTag)
+ {
+ var mesVersion = NuGetVersion.Parse(version);
+
+ var result = GenericUtilities.GetNpmDistTag(mesVersion);
+
+ result.Should().Be(expectedDistTag);
+ }
+
+ [Theory]
+ [InlineData("12.0.0", "12.0.0", false)]
+ [InlineData("12.0.0-beta.1", "12.0.0-beta.2", true)]
+ [InlineData("12.0.0-beta.2", "12.0.0", true)]
+ [InlineData("12.0.0", "12.0.0-beta.1", false)]
+ public void NuGetVersion_Comparison_RespectsSemVerOrdering(string left, string right, bool leftIsLessThanRight)
+ {
+ var leftVersion = new NuGetVersion(left);
+ var rightVersion = new NuGetVersion(right);
+
+ (leftVersion < rightVersion).Should().Be(leftIsLessThanRight);
+ }
+ }
+}
diff --git a/tests/Specs/Init.cs b/tests/Specs/Init.cs
index 2faf685bb..e109b0659 100644
--- a/tests/Specs/Init.cs
+++ b/tests/Specs/Init.cs
@@ -13,7 +13,10 @@
using Cmf.CLI.Services;
using Xunit;
using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System.Text.RegularExpressions;
using Assert = tests.AssertWithMessage;
+using NuGet.Versioning;
namespace tests.Specs
{
@@ -37,6 +40,25 @@ public Init()
parseResult.Invoke(console);
}
+ [Theory]
+ [InlineData("10.2.0", "10", "10.x.x", "10.2.x")]
+ [InlineData("11.1.5", "11", "11.x.x", "11.1.x")]
+ [InlineData("12.0.0-beta.2", "12", "12.x.x", "12.0.x")]
+ public void Template_VersionTransforms_MatchTheConfiguredRegexes(string version, string expectedMajor, string expectedMajorRange, string expectedFeature)
+ {
+ var templatePath = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "cmf-cli", "resources", "template_feed", "init", ".template.config", "template.json"));
+ var template = JObject.Parse(File.ReadAllText(templatePath));
+ var forms = (JObject)template["forms"]!;
+
+ var major = Transform(forms["versionToMajor"]!, version);
+ var majorRange = Transform(forms["versionToMajorRange"]!, version);
+ var feature = Transform(forms["versionToFeature"]!, version);
+
+ major.Should().Be(expectedMajor, $"versionToMajor should reduce '{version}' to its major segment");
+ majorRange.Should().Be(expectedMajorRange, $"versionToMajorRange should produce a major-only range from '{version}'");
+ feature.Should().Be(expectedFeature, $"versionToFeature should produce the feature segment from '{version}'");
+ }
+
[Theory]
[InlineData("10.2.0", DependencyVersionService.NET6SDK)]
[InlineData("11.0.0", DependencyVersionService.NET8SDK)]
@@ -82,9 +104,9 @@ public void Init_(string baseVersionStr, string dotnetSDKVersion)
var extractFileName = new Func(s => s.Split(Path.DirectorySeparatorChar).LastOrDefault());
// For v10 and above, the devcontainer should be created
- var baseVersion = new Version(baseVersionStr);
+ var baseVersion = new NuGetVersion(baseVersionStr);
- if (baseVersion >= new Version(10, 0))
+ if (baseVersion >= new NuGetVersion(10, 0, 0))
{
var devContainerFile = File.ReadAllText(Path.Join(tmp, ".devcontainer/devcontainer.json"));
@@ -133,6 +155,13 @@ public void Init_(string baseVersionStr, string dotnetSDKVersion)
}
}
+ private static string Transform(JToken form, string value)
+ {
+ var pattern = (string)form["pattern"]!;
+ var replacement = (string)form["replacement"]!;
+ return Regex.Replace(value, pattern, replacement);
+ }
+
[Fact]
public void Init_Fail_InvalidProjectName_WithDot()
{
@@ -250,6 +279,51 @@ public void Init_NgxSchematicsVersionUsesProvidedValueOverDefault()
}
}
+ [Theory]
+ [InlineData("12.0.0-alpha.1", "alpha-1200")]
+ [InlineData("11.1.5-beta.2", "beta-1115")]
+ public void Init_PreReleaseMESVersion_Succeeds(string mesVersion, string expectedNgxSchematicsVersion)
+ {
+ var tmp = TestUtilities.GetTmpDirectory();
+ var projectName = Convert.ToHexString(Guid.NewGuid().ToByteArray()).Substring(0, 8);
+ var deploymentDir = "\\\\share\\deployment_dir";
+
+ var cur = Directory.GetCurrentDirectory();
+ try
+ {
+ var console = new TestConsole();
+ Directory.SetCurrentDirectory(tmp);
+
+ var initCommand = new InitCommand();
+ var cmd = new Command("x");
+ initCommand.Configure(cmd);
+
+ TestUtilities.GetParser(cmd).Invoke(new[]
+ {
+ projectName,
+ "--infra", TestUtilities.GetFixturePath("init", "infrastructure.json"),
+ "-c", TestUtilities.GetFixturePath("init", "config.json"),
+ "--MESVersion", mesVersion,
+ // --nugetVersion, --testScenariosNugetVersion and --ngxSchematicsVersion are intentionally omitted
+ "--deploymentDir", deploymentDir,
+ }, console);
+
+ console.Error.ToString().Should().BeEmpty("command should succeed with a pre-release MES version");
+ Assert.True(File.Exists("cmfpackage.json"), "root cmfpackage is missing");
+
+ var projectConfig = File.ReadAllText(Path.Join(tmp, ".project-config.json"));
+ projectConfig.Should().Contain($@"""MESVersion"": ""{mesVersion}""", "MESVersion should retain the original pre-release string");
+ projectConfig.Should().Contain($@"""NugetVersion"": ""{mesVersion}""", "NugetVersion should default to the MES version");
+ projectConfig.Should().Contain($@"""TestScenariosNugetVersion"": ""{mesVersion}""", "TestScenariosNugetVersion should default to the MES version");
+ projectConfig.Should().Contain($@"""NGXSchematicsVersion"": ""{expectedNgxSchematicsVersion}""", "NGXSchematicsVersion should be derived from the MES version's pre-release label and numeric components");
+ }
+ finally
+ {
+ Directory.SetCurrentDirectory(cur);
+ Directory.Delete(tmp, true);
+ }
+ }
+
[Fact]
public void Init_Fail_ForLTv10()
{
@@ -291,6 +365,48 @@ public void Init_Fail_ForLTv10()
}
}
+ [Fact]
+ public void Init_Fail_ForLTv10_WithPreReleaseVersion()
+ {
+ var console = new TestConsole();
+ var tmp = TestUtilities.GetTmpDirectory();
+
+ var projectName = Convert.ToHexString(Guid.NewGuid().ToByteArray()).Substring(0, 8);
+ var deploymentDir = "\\\\share\\deployment_dir";
+
+ var cur = Directory.GetCurrentDirectory();
+ try
+ {
+ Directory.SetCurrentDirectory(tmp);
+
+ var initCommand = new InitCommand();
+ var cmd = new Command("x"); // this is the command name used in help text
+ initCommand.Configure(cmd);
+
+ TestUtilities.GetParser(cmd).Invoke(new[]
+ {
+ projectName,
+ "-c", TestUtilities.GetFixturePath("init", "config.json"),
+ "--MESVersion", "8.2.0-alpha.1",
+ "--nugetVersion", "8.2.0-alpha.1",
+ "--testScenariosNugetVersion", "8.2.0-alpha.1",
+ "--nugetRegistry", "http://nuget.example/feed",
+ "--npmRegistry", "http://npm.example/feed",
+ "--ISOLocation", "dummy",
+ "--ngxSchematicsVersion", "1.3.7",
+ "--deploymentDir", deploymentDir,
+ }, console);
+
+ // the pre-release label should not stop the numeric comparison from being evaluated correctly
+ console.Error.ToString().Should().Contain("MES Versions under 10 are no longer supported with the newest version of the CLI. Please use cmf-cli 5.8.0 or lower.");
+ }
+ finally
+ {
+ Directory.SetCurrentDirectory(cur);
+ Directory.Delete(tmp, true);
+ }
+ }
+
[Fact]
public void Init_Fail_MissingOptionsForGTv10()
{
diff --git a/tests/Specs/MESVersionValidation.cs b/tests/Specs/MESVersionValidation.cs
index 0281f03cc..6184fa89f 100644
--- a/tests/Specs/MESVersionValidation.cs
+++ b/tests/Specs/MESVersionValidation.cs
@@ -1,9 +1,10 @@
using System;
-using System.Collections.Generic;
using System.IO.Abstractions.TestingHelpers;
using Cmf.CLI.Core.Objects;
+using Cmf.CLI.Utilities;
using FluentAssertions;
using Microsoft.Extensions.DependencyInjection;
+using NuGet.Versioning;
using Xunit;
namespace tests.Specs;
@@ -164,6 +165,69 @@ public void IsVersionCompatible_NoExecutionContext_ShouldReturnFalse()
result.Should().BeFalse();
}
+ [Theory]
+ [InlineData("12.0.0-alpha.1", "11.0.0", true)] // pre-release, current version higher
+ [InlineData("12.0.0-alpha.1", "12.0.0", false)] // pre-release is still below the release build
+ [InlineData("12.0.0-alpha.1", "13.0.0", false)] // pre-release, current version lower
+ public void ProjectConfig_WithPreReleaseMESVersion_LoadsAndComparesCorrectly(string currentVersion, string minimumVersion, bool expectedResult)
+ {
+ // Arrange - this exercises loading a .project-config.json (as produced by `cmf init`) whose
+ // MESVersion contains a semantic versioning pre-release label (e.g. "12.0.0-alpha.1")
+ SetupExecutionContext(currentVersion);
+ var service = new MESVersionValidationService();
+
+ // Act
+ var result = service.IsVersionCompatible(minimumVersion);
+
+ // Assert
+ result.Should().Be(expectedResult);
+ ExecutionContext.Instance.ProjectConfig.MESVersion.ToString().Should().Be(currentVersion);
+ }
+
+ [Fact]
+ public void IsVersionCompatible_PreReleaseCurrentVersion_BelowReleaseMinimum_ShouldReturnFalse()
+ {
+ // SemVer rule: 12.0.0-alpha.1 is lower than 12.0.0.
+ SetupExecutionContext("12.0.0-alpha.1");
+ var service = new MESVersionValidationService();
+
+ service.IsVersionCompatible("12.0.0").Should().BeFalse();
+ }
+
+ [Fact]
+ public void ValidateMinimumVersion_PrereleaseMinimumVersion_ShouldAcceptSemVerMinimum()
+ {
+ // The API should accept prerelease minimums like 12.0.0-beta.1 instead of rejecting them as invalid.
+ SetupExecutionContext("12.0.0-beta.2");
+ var service = new MESVersionValidationService();
+
+ service.Invoking(x => x.ValidateMinimumVersion("12.0.0-beta.1"))
+ .Should().NotThrow();
+ }
+
+ [Fact]
+ public void IsVersionCompatible_PrereleaseMinimumVersion_ShouldCompareUsingSemVerRules()
+ {
+ // A minimum of 12.0.0-beta.1 should be considered lower than the current 12.0.0-beta.2 version.
+ SetupExecutionContext("12.0.0-beta.2");
+ var service = new MESVersionValidationService();
+
+ service.IsVersionCompatible("12.0.0-beta.1").Should().BeTrue();
+ }
+
+ [Theory]
+ [InlineData("12.0.0")]
+ [InlineData("12.0.0-beta.1")]
+ public void ProjectConfig_WithReleaseOrPrereleaseMESVersion_ShouldRoundTripWithoutLosingSemVer(string mesVersion)
+ {
+ // The config must preserve the original SemVer identity, including prerelease labels,
+ // while still exposing the normalized form used for comparisons.
+ SetupExecutionContext(mesVersion);
+
+ ExecutionContext.Instance.ProjectConfig.MESVersion.ToString().Should().Be(mesVersion);
+ ExecutionContext.Instance.ProjectConfig.MESVersion.ToNormalizedString().Should().Be(NuGetVersion.Parse(mesVersion).ToNormalizedString());
+ }
+
private void SetupExecutionContext(string mesVersion)
{
var projConfig = projCfgTemplate.Replace("{MES_VERSION}", mesVersion);
diff --git a/tests/Specs/New.cs b/tests/Specs/New.cs
index 729826b5a..39fd6f9a0 100644
--- a/tests/Specs/New.cs
+++ b/tests/Specs/New.cs
@@ -29,6 +29,7 @@
using Cmf.CLI.Commands.New.IoT;
using TestingConsole = Spectre.Console.Testing;
using Xunit.Sdk;
+using NuGet.Versioning;
namespace tests.Specs
{
@@ -304,7 +305,7 @@ private void UI_internal(string scaffoldingDir, BaseLayer layer, string mesVersi
Assert.True(File.Exists($"Cmf.Custom.HTML/src/index.html"), "Index file is missing or has wrong name");
Assert.True(File.ReadAllText("Cmf.Custom.HTML/src/index.html").Contains("MES"), "Index content is not expected");
Assert.True(File.ReadAllText("Cmf.Custom.HTML/src/index.html").Contains(""), "Index base path was not changed correctly");
- if(new Version(mesVersion) < new Version(11,0,0))
+ if(new NuGetVersion(mesVersion) < new NuGetVersion(11,0,0))
{
if (layer == BaseLayer.Core)
{
@@ -374,7 +375,7 @@ public void IoT(string mesVersion, bool htmlPackageLocationFullPath = false, boo
string packageFolderData = packageIdData;
// Before v10.2.7, all packages were Angular packages, even if the flag was not passed explicitly
- bool isAngularPackage = isAngularPackageFlag || Version.Parse(mesVersion) < new Version(10, 2, 7);
+ bool isAngularPackage = isAngularPackageFlag || NuGetVersion.Parse(mesVersion) < new NuGetVersion(10, 2, 7);
CopyNewFixture(dir, mesVersion: mesVersion);
if (isAngularPackage)
@@ -451,7 +452,7 @@ public void IoTDriverDefaultValues(string mesVersion)
string packageFolderPackages = "Cmf.Custom.IoT.Packages";
- bool isGreaterOrEqualThan1120 = Version.Parse(mesVersion) >= new Version(11, 2, 0);
+ bool isGreaterOrEqualThan1120 = NuGetVersion.Parse(mesVersion) >= new NuGetVersion(11, 2, 0);
var cur = Directory.GetCurrentDirectory();
try
diff --git a/tests/Specs/NodeVersionUtilities.cs b/tests/Specs/NodeVersionUtilities.cs
index 494b43975..ff98e1fc7 100644
--- a/tests/Specs/NodeVersionUtilities.cs
+++ b/tests/Specs/NodeVersionUtilities.cs
@@ -1,7 +1,6 @@
using Cmf.CLI.Utilities;
-using Cmf.CLI.Core;
-using System;
using Xunit;
+using NuGet.Versioning;
namespace tests.Specs
{
@@ -28,7 +27,7 @@ public void GetInstalledNodeVersion_ReturnsVersion_WhenNodeIsInstalled()
public void ValidateNodeVersion_ThrowsException_WhenNodeNotInstalled(string mesVersionString, string requiredNodeVersion)
{
// Arrange
- var mesVersion = new Version(mesVersionString);
+ var mesVersion = new NuGetVersion(mesVersionString);
// Act & Assert
// This test assumes Node.js is either not installed or the version doesn't match
@@ -62,20 +61,20 @@ public void ValidateNodeVersion_DoesNotThrow_WhenNodeVersionMatches()
if (installedVersion != null)
{
// Determine the MES version based on the installed Node.js version
- Version mesVersion;
+ NuGetVersion mesVersion;
string requiredNodeVersion = installedVersion.Major.ToString();
switch (installedVersion.Major)
{
case 12:
- mesVersion = new Version("8.0.0");
+ mesVersion = new NuGetVersion(8, 0, 0);
break;
case 18:
- mesVersion = new Version("10.0.0");
+ mesVersion = new NuGetVersion(10, 0, 0);
break;
case 20:
default:
- mesVersion = new Version("11.0.0");
+ mesVersion = new NuGetVersion(11, 0, 0);
break;
}