diff --git a/cmf-cli/Commands/upgrade/UpgradeBaseCommand.cs b/cmf-cli/Commands/upgrade/UpgradeBaseCommand.cs index 609ef8f43..ff78a12cf 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 index b5060f268..f5dd0eef2 100644 --- a/cmf-cli/Commands/upgrade/UpgradeCommand.cs +++ b/cmf-cli/Commands/upgrade/UpgradeCommand.cs @@ -1,38 +1,84 @@ -using Cmf.CLI.Core.Attributes; -using System.CommandLine; -using System.IO.Abstractions; - -namespace Cmf.CLI.Commands -{ - /// - /// Dummy upgrade command (only here to make "cmf upgrade base" work) - /// - /// - [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) - { - } - } -} +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); + } + } +} 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 a5472ae7f..8a9d33b65 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 d03390d92..13dd04e3c 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 693ac3c42..9bef8f746 100644 --- a/cmf-cli/Handlers/PackageType/IoTPackageTypeHandler.cs +++ b/cmf-cli/Handlers/PackageType/IoTPackageTypeHandler.cs @@ -241,13 +241,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 266167dd1..71fe3eaba 100644 --- a/cmf-cli/Handlers/PackageType/PackageTypeHandler.cs +++ b/cmf-cli/Handlers/PackageType/PackageTypeHandler.cs @@ -506,11 +506,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 421b571d6..d2c8adcb5 100644 --- a/cmf-cli/Utilities/UpgradeBaseUtilities.cs +++ b/cmf-cli/Utilities/UpgradeBaseUtilities.cs @@ -10,6 +10,8 @@ using Cmf.CLI.Core.Enums; using System.Runtime.CompilerServices; using NuGet.Versioning; +using Cmf.CLI.Builders; +using System; [assembly: InternalsVisibleTo("tests")] namespace Cmf.CLI.Utilities @@ -33,7 +35,7 @@ public static string UpdateJsonValue(string text, string key, string newValue) /// /// The original JSON content as a string. /// The JSON key to remove from the object. - /// The modified JSON string with the specified key removed. + /// The modified JSON string with the specified key removed. /// If the key does not exist, the original JSON string is returned unchanged. public static string RemoveJsonValue(string text, string key) { @@ -87,7 +89,7 @@ public static void UpdateNPMProject(IFileSystem fileSystem, CmfPackage cmfPackag public static void UpdateCSharpProject(IFileSystem fileSystem, CmfPackage cmfPackage, string version, bool strictMatching) { string[] filesToUpdate = fileSystem.Directory.GetFiles(cmfPackage.GetFileInfo().DirectoryName, "*.csproj", SearchOption.AllDirectories); - + string pattern; if (strictMatching) { @@ -113,232 +115,74 @@ 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) + /// Optional manifest file path for the migration tool. + public static void UpdateIoTMasterdataFiles(IFileSystem fileSystem, CmfPackage cmfPackage, string version, string manifest = null) { - /// 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(); + List args = []; + string workflowsFolder = null; + List masterdataFolders = []; foreach (ContentToPack contentToPack in cmfPackage.ContentToPack ?? []) { - if (contentToPack.Source?.Contains(@"$(version)") ?? false) + string contentToPackSource = contentToPack.Source; + + if (contentToPackSource?.Contains(@"$(version)") ?? false) { - Log.Warning("Source paths with \"$(version)\" in cmf packages will be ignored"); - continue; + contentToPackSource = contentToPackSource.Replace(@"$(version)", cmfPackage.Version); } if (contentToPack.ContentType == ContentType.MasterData) { - mdlFiles.AddRange(fileSystem.Directory.GetFiles( - cmfPackage.GetFileInfo().DirectoryName, - contentToPack.Source, - SearchOption.AllDirectories - )); - } - else if (contentToPack.ContentType == ContentType.AutomationWorkFlows) + masterdataFolders.Add(fileSystem.Path.GetFullPath(fileSystem.Path.Combine(cmfPackage.GetFileInfo().DirectoryName, contentToPackSource)).Replace("*", "")); + } else if (contentToPack.ContentType == ContentType.AutomationWorkFlows + && string.IsNullOrWhiteSpace(workflowsFolder)) { - workflowFiles.AddRange(fileSystem.Directory.GetFiles( - cmfPackage.GetFileInfo().DirectoryName, - contentToPack.Source, - SearchOption.AllDirectories - )); + workflowsFolder = fileSystem.Path.GetFullPath(fileSystem.Path.Combine(cmfPackage.GetFileInfo().DirectoryName, contentToPackSource)).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"))) + if (!string.IsNullOrEmpty(workflowsFolder)) { - UpdateIoTMasterdata(mdlPath, fileSystem, cmfPackage, version, ignorePackages); + args.AddRange(["--workflowsFolder", workflowsFolder]); } - 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" }) + if (!string.IsNullOrEmpty(manifest)) { - text = UpgradeBaseUtilities.UpdateJsonValue(text, key, version); + args.AddRange(["--manifest", manifest]); } - // Updating the versions in AutomationController requires special handling - JObject packageJsonObject = JsonConvert.DeserializeObject(text); + args.AddRange(["--registry", ExecutionContext.Instance.ProjectConfig.NPMRegistry.ToString()]); + args.AddRange(["--version", version]); - if (packageJsonObject.ContainsKey("AutomationController")) + try { - JObject automationControllers = packageJsonObject["AutomationController"] as JObject; - - foreach (JProperty prop in automationControllers.Properties()) + foreach(string masterdataFolder in masterdataFolders) { - UpdateTaskLibraryPackageJson(prop, version, ignorePackages); - } - } - - 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"]; + Log.Information($"Migration for materdatas inside ${masterdataFolder} started..."); - if (tasksLibraryPackagesToken == null || tasksLibraryPackagesToken.Type == JTokenType.Null) - { - return; - } + var npxCommand = new NPXCommand + { + Command = "@criticalmanufacturing/connect-iot-workflow-migration-tool", + Args = [masterdataFolder, ..args], + ForceColorOutput = true, + DisplayName = "Workflow Migration Tool", + WorkingDirectory = fileSystem.Directory.GetParent(cmfPackage.GetFileInfo().FullName) + }; - JArray tasksLibraryPackages = null; - bool wasStringFormat = false; + npxCommand.Exec(); - if (tasksLibraryPackagesToken.Type == JTokenType.String) - { - string rawString = tasksLibraryPackagesToken.ToString(); - if (!string.IsNullOrWhiteSpace(rawString)) - { - tasksLibraryPackages = JsonConvert.DeserializeObject(rawString); - wasStringFormat = true; + Log.Information("Migration completed."); } } - else if (tasksLibraryPackagesToken.Type == JTokenType.Array) + catch (Exception ex) { - tasksLibraryPackages = (JArray)tasksLibraryPackagesToken; + throw new CliException($"Workflow migration failed: {ex.Message}"); } - - 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)); - } - - foreach (var task in packageJsonObject?["tasks"]) - { - 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; - } - - foreach (var converter in packageJsonObject?["converters"]) - { - 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; - } - - SerializeWithOriginalIndentation(wflPath, packageJson, packageJsonObject, fileSystem); } /// @@ -385,4 +229,4 @@ internal static void SerializeWithOriginalIndentation(string jsonPath, string js fileSystem.File.WriteAllText(jsonPath, stringWriter.ToString()); } } -} \ No newline at end of file +} 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(