diff --git a/cmf-cli/Commands/upgrade/UpgradeBaseCommand.cs b/cmf-cli/Commands/upgrade/UpgradeBaseCommand.cs index eff96cb4c..81f3e9925 100644 --- a/cmf-cli/Commands/upgrade/UpgradeBaseCommand.cs +++ b/cmf-cli/Commands/upgrade/UpgradeBaseCommand.cs @@ -57,28 +57,20 @@ public override void Configure(Command cmd) }; cmd.Add(baseVersionArgument); - var iotVersionOption = new Option("--iotVersion", "-iot") + var manifestOption = new Option("--manifest", "-m") { - Description = "New MES version for the IoT workflows & masterdatas." + Description = "The manifest file to use for the upgrade." }; - cmd.Add(iotVersionOption); - - var iotPackagesToIgnoreOption = new Option>("--iotPackagesToIgnore", "-ignore") - { - Description = "IoT packages to ignore when updating the MES version of the tasks in IoT workflows", - AllowMultipleArgumentsPerToken = true - }; - cmd.Add(iotPackagesToIgnoreOption); + cmd.Add(manifestOption); // Add the handler cmd.SetAction((parseResult, cancellationToken) => { var packagePath = parseResult.GetValue(packagePathArgument); var baseVersion = parseResult.GetValue(baseVersionArgument); - var iotVersion = parseResult.GetValue(iotVersionOption); - var iotPackagesToIgnore = parseResult.GetValue(iotPackagesToIgnoreOption); + var manifest = parseResult.GetValue(manifestOption); - Execute(packagePath, baseVersion, iotVersion, iotPackagesToIgnore); + Execute(packagePath, baseVersion, manifest); return Task.FromResult(0); }); } @@ -88,10 +80,8 @@ public override void Configure(Command cmd) /// /// The package path. /// The new Base version. - /// New MES version for the IoT workflows & masterdata - /// IoT packages to ignore when updating the MES version of the tasks in IoT workflows - /// - public void Execute(IDirectoryInfo packagePath, string baseVersion, string iotVersion, List iotPackagesToIgnore) + /// The manifest file to use for the upgrade. + public void Execute(IDirectoryInfo packagePath, string baseVersion, string manifest = null) { using var activity = ExecutionContext.ServiceProvider?.GetService()?.StartExtendedActivity(this.GetType().Name); @@ -100,29 +90,13 @@ public void Execute(IDirectoryInfo packagePath, string baseVersion, string iotVe foreach (IFileInfo path in cmfPackagePaths) { Log.Debug($"Processing {path.FullName}"); - Execute(CmfPackage.Load(path), baseVersion, iotVersion, iotPackagesToIgnore); + new UpgradeCommand(this.fileSystem).Execute(path.Directory, baseVersion, manifest); } UpdateProjectConfig(packagePath, baseVersion); Log.Warning("Don't forget to update pipeline files"); } - /// - /// Executes the specified CMF package. - /// - /// The CMF package. - /// The version. - /// New MES version for the IoT workflows & masterdata - /// IoT packages to ignore when updating the MES version of the tasks in IoT workflows - /// - public void Execute(CmfPackage cmfPackage, string version, string iotVersion, List iotPackagesToIgnore) - { - IDirectoryInfo packageDirectory = cmfPackage.GetFileInfo().Directory; - IPackageTypeHandler packageTypeHandler = PackageTypeFactory.GetPackageTypeHandler(cmfPackage); - - packageTypeHandler.UpgradeBase(version, iotVersion, iotPackagesToIgnore); - } - #region Utilities /// diff --git a/cmf-cli/Commands/upgrade/UpgradeCommand.cs b/cmf-cli/Commands/upgrade/UpgradeCommand.cs new file mode 100644 index 000000000..b2d754f5b --- /dev/null +++ b/cmf-cli/Commands/upgrade/UpgradeCommand.cs @@ -0,0 +1,84 @@ +using Cmf.CLI.Constants; +using Cmf.CLI.Core.Attributes; +using Cmf.CLI.Core.Interfaces; +using Cmf.CLI.Factories; +using System.CommandLine; +using System.IO.Abstractions; +using System.Threading.Tasks; + +namespace Cmf.CLI.Commands +{ + /// + /// Performs an upgrade of the current package + /// + /// + [CmfCommand("upgrade", Id = "upgrade", Description = "Project upgrade utilities")] + public class UpgradeCommand : BaseCommand + { + + /// + /// constructor for System.IO filesystem + /// + public UpgradeCommand() : base() + { + } + + /// + /// constructor + /// + /// + public UpgradeCommand(IFileSystem fileSystem) : base(fileSystem) + { + } + + /// + /// Configure command + /// + /// + public override void Configure(Command cmd) + { + var packagePathArgument = new Argument("packagePath") + { + Description = "Package path", + CustomParser = argResult => Parse(argResult, ".") + }; + cmd.Add(packagePathArgument); + + var baseVersionArgument = new Argument("BaseVersion") + { + Description = "New framework/MES Version" + }; + cmd.Add(baseVersionArgument); + + var manifestOption = new Option("--manifest", "-m") + { + Description = "The manifest file to use for the upgrade." + }; + cmd.Add(manifestOption); + + cmd.SetAction((parseResult) => + { + var packagePath = parseResult.GetValue(packagePathArgument); + var baseVersion = parseResult.GetValue(baseVersionArgument); + var manifest = parseResult.GetValue(manifestOption); + + Execute(packagePath, baseVersion, manifest); + return Task.FromResult(0); + }); + } + + /// + /// Executes the specified package path. + /// + /// The package path. + /// The new framework/MES version. + /// The manifest file to use for the upgrade. + public void Execute(IDirectoryInfo packagePath, string version, string manifest = null) + { + IFileInfo cmfpackageFile = this.fileSystem.FileInfo.New(this.fileSystem.Path.Combine(packagePath.FullName, CliConstants.CmfPackageFileName)); + + IPackageTypeHandler packageTypeHandler = PackageTypeFactory.GetPackageTypeHandler(cmfpackageFile); + packageTypeHandler.Upgrade(version, manifest); + } + } +} \ No newline at end of file diff --git a/cmf-cli/Handlers/PackageType/BusinessPackageTypeHandler.cs b/cmf-cli/Handlers/PackageType/BusinessPackageTypeHandler.cs index 25ab448c6..2b24612b2 100644 --- a/cmf-cli/Handlers/PackageType/BusinessPackageTypeHandler.cs +++ b/cmf-cli/Handlers/PackageType/BusinessPackageTypeHandler.cs @@ -116,13 +116,10 @@ public override void Bump(string version, string versionSuffix, Dictionary - /// Bumps the Base version of the package - /// - /// The new Base version. - public override void UpgradeBase(string version, string iotVersion, List iotPackagesToIgnore) + /// + public override void Upgrade(string version, string manifest = null) { - base.UpgradeBase(version, iotVersion, iotPackagesToIgnore); + base.Upgrade(version, manifest); UpgradeBaseUtilities.UpdateCSharpProject(this.fileSystem, this.CmfPackage, version, true); } } diff --git a/cmf-cli/Handlers/PackageType/DataPackageTypeHandlerV2.cs b/cmf-cli/Handlers/PackageType/DataPackageTypeHandlerV2.cs index e12b3ab93..3e649930b 100644 --- a/cmf-cli/Handlers/PackageType/DataPackageTypeHandlerV2.cs +++ b/cmf-cli/Handlers/PackageType/DataPackageTypeHandlerV2.cs @@ -17,7 +17,7 @@ namespace Cmf.CLI.Handlers public class DataPackageTypeHandlerV2 : PackageTypeHandler { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The CMF package. public DataPackageTypeHandlerV2(CmfPackage cmfPackage) : base(cmfPackage) @@ -52,8 +52,8 @@ public DataPackageTypeHandlerV2(CmfPackage cmfPackage) : base(cmfPackage) } }); - BuildSteps = new IBuildCommand[] - { + BuildSteps = + [ new JSONValidatorCommand() { DisplayName = "JSON Validator Command", @@ -64,7 +64,7 @@ public DataPackageTypeHandlerV2(CmfPackage cmfPackage) : base(cmfPackage) DisplayName = "DEE Validator Command", FilesToValidate = GetContentToPack(this.fileSystem.DirectoryInfo.New(".")) } - }; + ]; cmfPackage.DFPackageType = PackageType.Business; // necessary because we restart the host during installation @@ -91,21 +91,13 @@ public override void Pack(IDirectoryInfo packageOutputDir, IDirectoryInfo output base.Pack(packageOutputDir, outputDir, dryRun); } - /// - /// Bumps the Base version of the package - /// - /// The new Base version. - public override void UpgradeBase(string version, string iotVersion, List iotPackagesToIgnore) + /// + public override void Upgrade(string version, string manifest = null) { - base.UpgradeBase(version, iotVersion, iotPackagesToIgnore); + base.Upgrade(version, manifest); UpgradeBaseUtilities.UpdateCSharpProject(this.fileSystem, this.CmfPackage, version, true); - if (iotVersion == null) - { - return; - } - - UpgradeBaseUtilities.UpdateIoTMasterdatasAndWorkflows(this.fileSystem, this.CmfPackage, iotVersion, iotPackagesToIgnore); + UpgradeBaseUtilities.UpdateIoTMasterdataFiles(this.fileSystem, this.CmfPackage, version, manifest); } /// diff --git a/cmf-cli/Handlers/PackageType/HelpNgCliPackageTypeHandler.cs b/cmf-cli/Handlers/PackageType/HelpNgCliPackageTypeHandler.cs index 4063009d8..b372bd857 100644 --- a/cmf-cli/Handlers/PackageType/HelpNgCliPackageTypeHandler.cs +++ b/cmf-cli/Handlers/PackageType/HelpNgCliPackageTypeHandler.cs @@ -191,13 +191,10 @@ public override void Bump(string version, string versionSuffix, Dictionary - /// Bumps the Base version of the package - /// - /// The new Base version. - public override void UpgradeBase(string version, string iotVersion, List iotPackagesToIgnore) + /// + public override void Upgrade(string version, string manifest = null) { - base.UpgradeBase(version, iotVersion, iotPackagesToIgnore); + base.Upgrade(version, manifest); UpgradeBaseUtilities.UpdateNPMProject(this.fileSystem, this.CmfPackage, version); // Update the version in the config.json file diff --git a/cmf-cli/Handlers/PackageType/HtmlNgCliPackageTypeHandler.cs b/cmf-cli/Handlers/PackageType/HtmlNgCliPackageTypeHandler.cs index a2c79db43..65f256e43 100644 --- a/cmf-cli/Handlers/PackageType/HtmlNgCliPackageTypeHandler.cs +++ b/cmf-cli/Handlers/PackageType/HtmlNgCliPackageTypeHandler.cs @@ -180,13 +180,10 @@ public override void Bump(string version, string versionSuffix, Dictionary - /// Bumps the Base version of the package - /// - /// The new Base version. - public override void UpgradeBase(string version, string iotVersion, List iotPackagesToIgnore) + /// + public override void Upgrade(string version, string manifest = null) { - base.UpgradeBase(version, iotVersion, iotPackagesToIgnore); + base.Upgrade(version, manifest); UpgradeBaseUtilities.UpdateNPMProject(this.fileSystem, this.CmfPackage, version); IFileInfo projectConfig = this.fileSystem.FileInfo.New(Path.Join(this.CmfPackage.GetFileInfo().DirectoryName, "src", "assets", "config.json")); diff --git a/cmf-cli/Handlers/PackageType/IoTDataPackageTypeHandlerV2.cs b/cmf-cli/Handlers/PackageType/IoTDataPackageTypeHandlerV2.cs index 1998d95ff..ae210c36f 100644 --- a/cmf-cli/Handlers/PackageType/IoTDataPackageTypeHandlerV2.cs +++ b/cmf-cli/Handlers/PackageType/IoTDataPackageTypeHandlerV2.cs @@ -4,14 +4,11 @@ using Cmf.CLI.Core.Objects; using Cmf.CLI.Utilities; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.IO.Abstractions; using System.Linq; -using System.Text.RegularExpressions; namespace Cmf.CLI.Handlers { @@ -90,23 +87,6 @@ public override void Bump(string version, string versionSuffix, Dictionary - /// Bumps the Base version of the package - /// - /// The new Base version. - public override void UpgradeBase(string version, string iotVersion, List iotPackagesToIgnore) - { - base.UpgradeBase(version, iotVersion, iotPackagesToIgnore); - UpgradeBaseUtilities.UpdateCSharpProject(this.fileSystem, this.CmfPackage, version, true); - - if (iotVersion == null) - { - return; - } - - UpgradeBaseUtilities.UpdateIoTMasterdatasAndWorkflows(this.fileSystem, this.CmfPackage, iotVersion, iotPackagesToIgnore); - } - /// /// Retrieves all custom iot package names /// diff --git a/cmf-cli/Handlers/PackageType/IoTPackageTypeHandler.cs b/cmf-cli/Handlers/PackageType/IoTPackageTypeHandler.cs index 640ece42e..4bed2a8d9 100644 --- a/cmf-cli/Handlers/PackageType/IoTPackageTypeHandler.cs +++ b/cmf-cli/Handlers/PackageType/IoTPackageTypeHandler.cs @@ -239,13 +239,10 @@ public override void Bump(string version, string versionSuffix, Dictionary - /// Bumps the Base version of the package - /// - /// The new Base version. - public override void UpgradeBase(string version, string iotVersion, List iotPackagesToIgnore) + /// + public override void Upgrade(string version, string manifest = null) { - base.UpgradeBase(version, iotVersion, iotPackagesToIgnore); + base.Upgrade(version, manifest); UpgradeBaseUtilities.UpdateNPMProject(this.fileSystem, this.CmfPackage, version); } diff --git a/cmf-cli/Handlers/PackageType/PackageTypeHandler.cs b/cmf-cli/Handlers/PackageType/PackageTypeHandler.cs index 099a872dd..962a8f604 100644 --- a/cmf-cli/Handlers/PackageType/PackageTypeHandler.cs +++ b/cmf-cli/Handlers/PackageType/PackageTypeHandler.cs @@ -498,11 +498,9 @@ public virtual void Bump(string version, string versionSuffix, Dictionary - /// Bumps the Base version of the package - /// - /// The new Base version. - public virtual void UpgradeBase(string version, string iotVersion, List iotPackagesToIgnore) { + /// + public virtual void Upgrade(string version, string manifest = null) + { Log.Information($"Will bump {CmfPackage.PackageId}"); // Read and parse the JSON diff --git a/cmf-cli/Handlers/PackageType/TestPackageTypeHandler.cs b/cmf-cli/Handlers/PackageType/TestPackageTypeHandler.cs index a0ad3c524..cc21abcca 100644 --- a/cmf-cli/Handlers/PackageType/TestPackageTypeHandler.cs +++ b/cmf-cli/Handlers/PackageType/TestPackageTypeHandler.cs @@ -127,13 +127,10 @@ public override void Bump(string version, string versionSuffix, Dictionary - /// Bumps the Base version of the package - /// - /// The new Base version. - public override void UpgradeBase(string version, string iotVersion, List iotPackagesToIgnore) + /// + public override void Upgrade(string version, string manifest = null) { - base.UpgradeBase(version, iotVersion, iotPackagesToIgnore); + base.Upgrade(version, manifest); UpgradeBaseUtilities.UpdateCSharpProject(this.fileSystem, this.CmfPackage, version, false); } diff --git a/cmf-cli/Utilities/UpgradeBaseUtilities.cs b/cmf-cli/Utilities/UpgradeBaseUtilities.cs index 41838a2af..a5cb30bc5 100644 --- a/cmf-cli/Utilities/UpgradeBaseUtilities.cs +++ b/cmf-cli/Utilities/UpgradeBaseUtilities.cs @@ -2,15 +2,15 @@ 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 Cmf.CLI.Builders; +using System; [assembly: InternalsVisibleTo("tests")] namespace Cmf.CLI.Utilities @@ -112,38 +112,16 @@ public static void UpdateCSharpProject(IFileSystem fileSystem, CmfPackage cmfPac } /// - /// Updates version references in IoT master data and automation workflow files - /// within a given package, skipping specific packages if configured. + /// Updates IoT Masterdata and Automation Workflows files executing the appropriate migration scripts. /// /// The file system abstraction used to access files. /// The CMF package being processed. /// The new Base version. - /// List of package names to ignore during the update (e.g., custom tasks). - public static void UpdateIoTMasterdatasAndWorkflows(IFileSystem fileSystem, CmfPackage cmfPackage, string version, List iotPackagesToIgnore) - { - /// You might be wondering why the ignorePackages starts with these three packages by default: - /// - /// When I was testing this command on a bunch of projects, - /// I noticed that the version of these template packages were being inadvertently changed on a lot of projects. - /// - /// While one is able to use the --iotPackagesToIgnore flag to ignore these packages, - /// by adding these packages to the ignore list by default we make the usage of this command more ergonomic. - - List ignorePackages = new List() - { - "@criticalmanufacturing/connect-iot-controller-engine-custom-utilities-tasks", // SMT Template - "@criticalmanufacturing/connect-iot-controller-engine-custom-smt-utilities-tasks", // SMT Template - "@criticalmanufacturing/connect-iot-utilities-semi-tasks", // Semi Template - }; - ignorePackages.AddRange(iotPackagesToIgnore ?? []); - - // Useful debug info - Log.Debug("Packages that will be ignored:"); - ignorePackages.ForEach(pkg => Log.Debug($" - {pkg}")); - - List mdlFiles = new List(); - List workflowFiles = new List(); - + /// Optional manifest file path for the migration tool. + public static void UpdateIoTMasterdataFiles(IFileSystem fileSystem, CmfPackage cmfPackage, string version, string manifest = null) + { + List args = []; + string workflowsFolder = null; foreach (ContentToPack contentToPack in cmfPackage.ContentToPack ?? []) { if (contentToPack.Source?.Contains(@"$(version)") ?? false) @@ -154,190 +132,45 @@ public static void UpdateIoTMasterdatasAndWorkflows(IFileSystem fileSystem, CmfP if (contentToPack.ContentType == ContentType.MasterData) { - mdlFiles.AddRange(fileSystem.Directory.GetFiles( - cmfPackage.GetFileInfo().DirectoryName, - contentToPack.Source, - SearchOption.AllDirectories - )); - } - else if (contentToPack.ContentType == ContentType.AutomationWorkFlows) + var mdFilePath = fileSystem.Path.GetFullPath(fileSystem.Path.Combine(cmfPackage.GetFileInfo().DirectoryName, contentToPack.Source)).Replace("*", ""); + args.Add(mdFilePath); + } else if (contentToPack.ContentType == ContentType.AutomationWorkFlows) { - workflowFiles.AddRange(fileSystem.Directory.GetFiles( - cmfPackage.GetFileInfo().DirectoryName, - contentToPack.Source, - SearchOption.AllDirectories - )); + workflowsFolder = fileSystem.Path.GetFullPath(fileSystem.Path.Combine(cmfPackage.GetFileInfo().DirectoryName, contentToPack.Source)).Replace("*", ""); } } - if (mdlFiles.Where(mdl => !mdl.EndsWith(".json")).Any()) - { - Log.Warning("Only .json masterdata files will be updated"); - } - - // Update the MES references that might be present in the mdl files - foreach (string mdlPath in mdlFiles.Where(mdl => mdl.EndsWith(".json"))) - { - UpdateIoTMasterdata(mdlPath, fileSystem, cmfPackage, version, ignorePackages); - } - - Log.Debug("Processing workflows..."); - // Update the IoT workflows - foreach (string wflPath in workflowFiles.Where(path => path.EndsWith(".json"))) - { - UpdateIoTWorkflow(wflPath, fileSystem, cmfPackage, version, ignorePackages); - } - } - - /// - /// Updates version values in a given IoT master data (.json) file. - /// - /// Path to the master data file. - /// The file system abstraction used to access files. - /// The CMF package that owns the master data. - /// The new Base version. - /// List of task package names to ignore. - private static void UpdateIoTMasterdata(string mdlPath, IFileSystem fileSystem, CmfPackage cmfPackage, string version, List ignorePackages) - { - // Update some versions in several places in the masterdata - string text = fileSystem.File.ReadAllText(mdlPath); - foreach (string key in new string[] { "PackageVersion", "ControllerPackageVersion", "MonitorPackageVersion", "ManagerPackageVersion" }) - { - text = UpgradeBaseUtilities.UpdateJsonValue(text, key, version); - } - - // Updating the versions in AutomationController requires special handling - JObject packageJsonObject = JsonConvert.DeserializeObject(text); - - if (packageJsonObject.ContainsKey("AutomationController")) + if (!string.IsNullOrEmpty(workflowsFolder)) { - JObject automationControllers = packageJsonObject["AutomationController"] as JObject; - - foreach (JProperty prop in automationControllers.Properties()) - { - UpdateTaskLibraryPackageJson(prop, version, ignorePackages); - } + args.AddRange(["--workflowsFolder", workflowsFolder]); } - SerializeWithOriginalIndentation(mdlPath, text, packageJsonObject, fileSystem); - } - - /// - /// Updates the version of package strings listed in the "TasksLibraryPackages" field of a given AutomationController JSON property. - /// - /// The JSON property representing a controller entry within the "AutomationController" object. - /// The new version string to apply to all eligible package entries. - /// A list of package name substrings to exclude from version updates. - /// Any package string that contains a substring from this list will be skipped. - /// - /// - /// The "TasksLibraryPackages" field may be stored either as a JSON array or as a stringified JSON array. - /// This method detects the format and updates the version suffix (e.g., "@11.1.3") for each package string, - /// while preserving the original format of the field (string or array). I have no idea why are two different - /// formats are allowed in this field, but now we're stuck supporting them both - /// - private static void UpdateTaskLibraryPackageJson(JProperty prop, string version, List ignorePackages) - { - JObject controller = (JObject)prop.Value; - JToken tasksLibraryPackagesToken = controller["TasksLibraryPackages"]; - - if (tasksLibraryPackagesToken == null || tasksLibraryPackagesToken.Type == JTokenType.Null) + if (!string.IsNullOrEmpty(manifest)) { - return; + args.AddRange(["--manifest", manifest]); } - JArray tasksLibraryPackages = null; - bool wasStringFormat = false; + args.AddRange(["--registry", ExecutionContext.Instance.ProjectConfig.NPMRegistry.ToString()]); + args.AddRange(["--version", version]); - if (tasksLibraryPackagesToken.Type == JTokenType.String) + var npxCommand = new NPXCommand { - string rawString = tasksLibraryPackagesToken.ToString(); - if (!string.IsNullOrWhiteSpace(rawString)) - { - tasksLibraryPackages = JsonConvert.DeserializeObject(rawString); - wasStringFormat = true; - } - } - else if (tasksLibraryPackagesToken.Type == JTokenType.Array) - { - tasksLibraryPackages = (JArray)tasksLibraryPackagesToken; - } - - if (tasksLibraryPackages == null) - { - return; - } - - for (int i = 0; i < tasksLibraryPackages.Count; i++) - { - string packageStr = tasksLibraryPackages[i]?.ToString(); - - if (string.IsNullOrEmpty(packageStr) || ignorePackages.Any(ignore => packageStr.Contains(ignore))) - { - continue; - } - tasksLibraryPackages[i] = Regex.Replace(packageStr, @"@\d+.*$", $"@{version}"); - } - - if (wasStringFormat) - { - // Write back as a compact JSON string - controller["TasksLibraryPackages"] = JsonConvert.SerializeObject(tasksLibraryPackages, Formatting.None); - } - else - { - // Preserve original JArray structure - controller["TasksLibraryPackages"] = tasksLibraryPackages; - } - } - - /// - /// Updates the package version references in an IoT automation workflow file, - /// skipping any package names included in the ignore list. - /// - /// Path to the workflow .json file. - /// The file system abstraction used to access files. - /// The CMF package that owns the workflow. - /// The new Base version. - /// List of task package names to skip when applying the version update. - private static void UpdateIoTWorkflow(string wflPath, IFileSystem fileSystem, CmfPackage cmfPackage, string version, List ignorePackages) - { - Log.Debug($" - {wflPath}"); - string packageJson = fileSystem.File.ReadAllText(wflPath); - dynamic packageJsonObject = JsonConvert.DeserializeObject(packageJson); - - if (!packageJsonObject.ContainsKey("tasks")) - { - throw new CliException(string.Format(CoreMessages.MissingMandatoryPropertyInFile, "tasks", wflPath)); - } - if (!packageJsonObject.ContainsKey("converters")) - { - throw new CliException(string.Format(CoreMessages.MissingMandatoryPropertyInFile, "converters", wflPath)); - } + Command = "workflow-migration-tool", + Args = [.. args], + ForceColorOutput = true, + DisplayName = "Workflow Migration Tool", + WorkingDirectory = fileSystem.Directory.GetParent(cmfPackage.GetFileInfo().FullName) + }; - foreach (var task in packageJsonObject?["tasks"]) + try { - string name = (string)task["reference"]["package"]["name"]; - if (ignorePackages.Any(ignore => name.Contains(ignore))) - { - continue; // If there's a match with a package in the ignorePackages, skip the version bump - } - - task["reference"]["package"]["version"] = version; + npxCommand.Exec(); + Log.Information("Migration complete."); } - - foreach (var converter in packageJsonObject?["converters"]) + catch (Exception ex) { - string name = (string)converter["reference"]["package"]["name"]; - if (ignorePackages.Any(ignore => name.Contains(ignore))) - { - continue; // If there's a match with a package in the ignorePackages, skip the version bump - } - - converter["reference"]["package"]["version"] = version; + throw new CliException($"Workflow migration failed: {ex.Message}"); } - - SerializeWithOriginalIndentation(wflPath, packageJson, packageJsonObject, fileSystem); } /// diff --git a/core/Interfaces/IPackageTypeHandler.cs b/core/Interfaces/IPackageTypeHandler.cs index 583f4da3c..5be12657b 100644 --- a/core/Interfaces/IPackageTypeHandler.cs +++ b/core/Interfaces/IPackageTypeHandler.cs @@ -29,9 +29,8 @@ public interface IPackageTypeHandler /// Bumps the Base version of the package /// /// The new Base version. - /// New MES version for the IoT workflows & masterdata - /// IoT packages to ignore when updating the MES version of the tasks in IoT workflows - public abstract void UpgradeBase(string version, string iotVersion, List iotPackagesToIgnore); + /// The manifest file to use for the upgrade. + public abstract void Upgrade(string version, string manifest = null); /// /// Builds this instance. diff --git a/core/Utilities/IoTUtilities.cs b/core/Utilities/IoTUtilities.cs index 5848f8113..3ed5b781f 100644 --- a/core/Utilities/IoTUtilities.cs +++ b/core/Utilities/IoTUtilities.cs @@ -64,7 +64,7 @@ public static void BumpWorkflowFiles(string group, string version, string versio } /// - /// Bumps the io t master data. + /// Bumps the iot master data. /// /// The automation workflow file group. /// The version. @@ -142,7 +142,7 @@ public static void BumpIoTMasterData(string automationWorkflowFileGroup, string } string[] xmlMasterDatas = fileSystem.Directory.GetFiles(parentDirectory.FullName, "*.xml"); - string[] xlsxMasterDatas = fileSystem.Directory.GetFiles(parentDirectory.FullName, "*.xml"); + string[] xlsxMasterDatas = fileSystem.Directory.GetFiles(parentDirectory.FullName, "*.xlsx"); if (xmlMasterDatas == null || xmlMasterDatas.Length == 0) { diff --git a/tests/Specs/Upgrade.cs b/tests/Specs/Upgrade.cs new file mode 100644 index 000000000..b3dcbdb24 --- /dev/null +++ b/tests/Specs/Upgrade.cs @@ -0,0 +1,154 @@ +using System.Collections.Generic; +using System.IO.Abstractions.TestingHelpers; +using Cmf.CLI.Commands; +using FluentAssertions; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Xunit; + +namespace tests.Specs; + +public class Upgrade +{ + [Fact] + public void RootPackage() + { + string version = "11.1.6"; + + var fileSystem = new MockFileSystem(new Dictionary + { + { + "/cmfpackage.json", + new MockFileData( + @"{ + ""packageId"": ""Cmf.SMT.Package"", + ""version"": ""3.2.0"", + ""description"": ""Root package"", + ""packageType"": ""Root"", + ""isInstallable"": true, + ""isUniqueInstall"": false, + ""dependencies"": [ + { + ""id"": ""DS.ClickHouse.Workaround"", + ""version"": ""1.2.0"" + }, + { + ""id"": ""Cmf.Environment"", + ""version"": ""11.1.3"" + }, + { + ""id"": ""criticalmanufacturing.deploymentmetadata"", + ""version"": ""11.1.3"" + }, + { + ""id"": ""CriticalManufacturing.DeploymentMetadata"", + ""version"": ""11.1.3"" + } + ] + }" + ) + }, + }); + + var cmd = new UpgradeCommand(fileSystem); + cmd.Execute(fileSystem.DirectoryInfo.New("/"), version); + + string rootCmfpackageContents = fileSystem.File.ReadAllText("/cmfpackage.json"); + JObject rootCmfpackageObject = (JObject)JsonConvert.DeserializeObject(rootCmfpackageContents); + + rootCmfpackageObject["dependencies"][0]["version"].ToString().Should().Be("1.2.0"); + rootCmfpackageObject["dependencies"][1]["version"].ToString().Should().Be(version); + rootCmfpackageObject["dependencies"][2]["version"].ToString().Should().Be(version); + rootCmfpackageObject["dependencies"][3]["version"].ToString().Should().Be(version); + } + + [Fact] + public void BusinessPackage() + { + string version = "11.1.6"; + + var fileSystem = new MockFileSystem(new Dictionary + { + { + "/Business/cmfpackage.json", + new MockFileData( + @"{ + ""packageId"": ""Cmf.SMT.Business"", + ""version"": ""3.2.0"", + ""description"": ""Business Package"", + ""packageType"": ""Business"", + ""isInstallable"": true, + ""isUniqueInstall"": false + }" + ) + }, + { + "/Business/Common/a.b.c.csproj", + new MockFileData( + @" + + + + + + + + + " + ) + } + }); + + var cmd = new UpgradeCommand(fileSystem); + cmd.Execute(fileSystem.DirectoryInfo.New("/Business"), version); + + string csprojContents = fileSystem.File.ReadAllText("/Business/Common/a.b.c.csproj"); + csprojContents.Should().Contain($@""); + csprojContents.Should().Contain($@""); + csprojContents.Should().Contain($@""); + csprojContents.Should().Contain(@""); + } + + [Fact] + public void TestPackage() + { + string version = "11.1.6"; + + var fileSystem = new MockFileSystem(new Dictionary + { + { + "/cmfpackage.json", + new MockFileData( + @"{ + ""packageId"": ""Cmf.SMT.Tests"", + ""version"": ""3.2.0"", + ""description"": ""Tests Package"", + ""packageType"": ""Tests"", + ""isInstallable"": false, + ""isUniqueInstall"": false + }" + ) + }, + { + "/Common/a.b.c.csproj", + new MockFileData( + @" + + + + + + + + " + ) + } + }); + + var cmd = new UpgradeCommand(fileSystem); + cmd.Execute(fileSystem.DirectoryInfo.New("/"), version); + + string csprojContents = fileSystem.File.ReadAllText("/Common/a.b.c.csproj"); + csprojContents.Should().Contain($@""); + } +} \ No newline at end of file diff --git a/tests/Specs/UpgradeBase.cs b/tests/Specs/UpgradeBase.cs index 97f2caf80..ef6576899 100644 --- a/tests/Specs/UpgradeBase.cs +++ b/tests/Specs/UpgradeBase.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.IO.Abstractions.TestingHelpers; using System.Linq; @@ -53,7 +52,7 @@ public void ProjectConfig() }); UpgradeBaseCommand cmd = new UpgradeBaseCommand(fileSystem); - cmd.Execute(fileSystem.FileInfo.New(projectConfigPath).Directory, "11.1.6", "11.1.6", []); + cmd.Execute(fileSystem.FileInfo.New(projectConfigPath).Directory, "11.1.6", "11.1.6"); string projectConfigContents = fileSystem.File.ReadAllText(projectConfigPath); @@ -176,10 +175,8 @@ public void BusinessPackage() ) } }); - - UpgradeBaseCommand cmd = new UpgradeBaseCommand(fileSystem); - cmd.Execute(fileSystem.DirectoryInfo.New("/"), version, version, []); + cmd.Execute(fileSystem.DirectoryInfo.New("/"), version); string rootCmfpackageContents = fileSystem.File.ReadAllText("/cmfpackage.json"); @@ -207,13 +204,10 @@ public void BusinessPackage() } - [Theory] - [InlineData(true)] - [InlineData(false)] - public void DataPackage(bool iotShouldBeUpdated) + [Fact] + public void DataPackage() { string version = "11.1.6"; - string iotVersion = "11.1.6-123"; var fileSystem = new MockFileSystem(new Dictionary { @@ -508,50 +502,15 @@ public void DataPackage(bool iotShouldBeUpdated) } }); - UpgradeBaseCommand cmd = new UpgradeBaseCommand(fileSystem); - cmd.Execute(fileSystem.DirectoryInfo.New(@"/"), version, iotShouldBeUpdated ? iotVersion : null, ["ignore-this-package"]); + ExecutionContext.Initialize(fileSystem); + + UpgradeBaseUtilities.UpdateCSharpProject(fileSystem, new CmfPackage(fileSystem.FileInfo.New("/cmfpackage.json")), version, true); string csprojContents = fileSystem.File.ReadAllText(@"/DEEs/a.b.c.csproj"); csprojContents.Should().Contain( $@"" ); - if (iotShouldBeUpdated) - { - #region Masterdata validations - string mdlContents = fileSystem.File.ReadAllText(@"/MasterData/a.json"); - mdlContents.Should().ContainAll([ - $@"""PackageVersion"": ""{iotVersion}""", - $@"""MonitorPackageVersion"": ""{iotVersion}""", - $@"""ManagerPackageVersion"": ""{iotVersion}""", - $@"""ControllerPackageVersion"": ""{iotVersion}""", - $@"@criticalmanufacturing/connect-iot-controller-engine-core-tasks@{iotVersion}", - $@"@criticalmanufacturing/connect-iot-random@{iotVersion}", - $@"@criticalmanufacturing/connect-iot-controller-engine-custom-utilities-tasks@5.4.3", // The industry templates iot packages should remain unchanged - $@"@criticalmanufacturing/connect-iot-controller-engine-custom-smt-utilities-tasks@5.4.3", - $@"@criticalmanufacturing/connect-iot-utilities-semi-tasks@5.4.3", - ]); - Assert.Equal(7, Regex.Matches(mdlContents, iotVersion.Replace(".", "\\.")).Count); - #endregion IoT Masterdata validations - - #region Workflow validations - string wflContents = fileSystem.File.ReadAllText(@"/AutomationWorkFlows/workflow.json"); - JObject workflowJsonObject = (JObject)JsonConvert.DeserializeObject(wflContents); - - // Tasks - workflowJsonObject["tasks"][0]["reference"]["package"]["version"].ToString().Should().Be(iotVersion); - workflowJsonObject["tasks"][1]["reference"]["package"]["version"].ToString().Should().Be("11.1.5"); - workflowJsonObject["tasks"][2]["reference"]["package"]["version"].ToString().Should().Be(iotVersion); - - // Converters - workflowJsonObject["converters"][0]["reference"]["package"]["version"].ToString().Should().Be(iotVersion); - workflowJsonObject["converters"][1]["reference"]["package"]["version"].ToString().Should().Be("1.2.3"); - - Assert.Equal(3, Regex.Matches(wflContents, iotVersion.Replace(".", "\\.")).Count); - Assert.Single(Regex.Matches(wflContents, "11.1.5".Replace(".", "\\."))); // Ignored task - Assert.Single(Regex.Matches(wflContents, "1.2.3".Replace(".", "\\."))); // Ignored converter - #endregion IoT Workflow validations - } } [Theory] @@ -778,10 +737,8 @@ public void TestPackage() ) } }); - - UpgradeBaseCommand cmd = new UpgradeBaseCommand(fileSystem); - cmd.Execute(fileSystem.DirectoryInfo.New("/"), version, null, []); + cmd.Execute(fileSystem.DirectoryInfo.New("/"), version); string csprojContents = fileSystem.File.ReadAllText("/Common/a.b.c.csproj"); csprojContents.Should().Contain(