Finally, I was able to develop a command line to deploy Infor Smart Office Mashups. This is important for me to save time when deploying many Mashups, on many environments, many times a day, so I can re-invest that time in the Mashups, instead of wasting time on their deployment in the various graphical user interfaces. Read #1, #2, and #3 for the backstory.
Disclaimer
I will use the internals of Smart Office and MangoServer which by definition are not public. Infor Product Development may change any of it at any time.
Project
I will create my C# Console Application project in the free (as in free beer) Microsoft Visual Studio 2015 Community Edition:
Add references to the Smart Office assemblies Mango.UI.dll and Mashup.Designer.dll which you can find in your Smart Office local storage (search for the path in your Log Viewer); you can also get them from the Smart Office product download, or in the Smart Office SDK:
When you Build the project, Visual Studio will automatically grab the additional assemblies Mango.Core.dll, log4net.dll, and DesignSystem.dll.
Web service client
Smart Office already has client code for its web services in the namespace Mango.UI.Services.WS, but it’s missing the method DeployMashup which is precisely the one I need:
It’s easy to generate the code in Visual Studio, select Add Service Reference, and enter the URL to the MangoServer /mangows/InstallationPointManager?wsdl:
In the App.config file, add the <transport clientCredentialType=”Basic” /> and add the name/address of the target M3 environments, e.g. DEV, TST, EDU, PRD:
Source code
Add the C# class Deploy.cs:
using System; using System.IO; using System.Reflection; using Mango.UI.Services.Mashup; using Mango.UI.Services.Mashup.Internal; using MangoServer.mangows; using Mashup.Designer; namespace Mashups { class Deploy { // Usage: deploy.exe Mashup1,Mashup2,Mashup3 DEV,TST static void Main(string[] args) { // get the M3 userid/password Console.Write("Userid: "); string userid = Console.ReadLine(); Console.Write("Password: "); string password = Console.ReadLine(); // for each directory string[] directories = args[0].Split(','); foreach (string directory in directories) { // for each Mashup string[] files = Directory.GetFiles(directory, "*.manifest", SearchOption.AllDirectories); foreach (string file in files) { Console.WriteLine("Opening {0}", file); ManifestDesigner manifest = new ManifestDesigner(new FileInfo(file)); string name = manifest.DeploymentName + Defines.ExtensionMashup; Console.WriteLine("Generating {0}", name); // generate the Mashup package if (SaveMashupFile(manifest)) { // get the resulting binary contents byte[] bytes = File.ReadAllBytes(manifest.File.Directory + "\\" + name); // for each M3 environment string[] environments = args[1].Split(','); foreach (string environment in environments) { // deploy Console.WriteLine("Deploying to {0}", environment); DeployMashup(name, bytes, environment, userid, password); } Console.WriteLine("DONE"); } } } } /* Create the Mashup package (*.mashup) from the specified Mashup Manifest. Inspired by Mashup.Designer.DeploymentHelper.SaveMashupFile */ static bool SaveMashupFile(ManifestDesigner manifest) { try { // validate Manifest typeof(DeploymentHelper).InvokeMember("ValidateManifest", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Static, null, null, new Object[] { manifest }); // create Mashup package string defaultFileName = manifest.DeploymentName + Defines.ExtensionMashup; FileInfo packageFile = new FileInfo(manifest.File.Directory + "\\" + defaultFileName); PackageHelper.CreatePackageFromManifest(manifest, manifest.File, packageFile, PackageHelper.DeployTarget_LSO); // check Mashup profile if (manifest.GetProfileNode() != null) { string message = "Please note that this Mashup contains a profile section and should be deployed using Life Cycle Manager. Warning - Using the Mashup File Administration tool will not result in a merge of profile information into the profile."; Console.WriteLine(message); } return true; } catch (Exception exception) { Console.Error.WriteLine(exception); return false; } } /* Deploy the specified Mashup name and file (*.mashup binary contents) to the specified M3 environment (see App.config) authenticating with the specified M3 userid and password. Inspired by /mangows/InstallationPointManager/DeployMashup */ static void DeployMashup(string Name, byte[] MashupFile, string environment, string userid, string password) { InstallationPointManagerClient client = new MangoServer.mangows.InstallationPointManagerClient(environment); client.ClientCredentials.UserName.UserName = userid; client.ClientCredentials.UserName.Password = password; client.DeployMashup(Name, MashupFile); } } }
Here is what the folder looks like:
Build the solution, the resulting command application will be Deploy.exe with the required assemblies and config file:
Usage
Suppose you have the following Mashups\ folder with Mashups inside, e.g. Mashup1, Mashup2, Mashup3, Mashup4, Mashup5, Mashup6:
And suppose you want to deploy only Mashup1, Mashup2, and Mashup3.
The usage is:
Mashups\> Deploy.exe Mashup1,Mashup2,Mashup3 DEV,TST
Where Mashup1,Mashup2,Mashup3 is the comma-separated list of Mashup folders, and where DEV,TST is the comma-separated list of target M3 environments as defined in Deploy.exe.config.
The program will recursively descend the specified folders. So you can also specify the parent folder – Mashups\ – and the program will deploy every Mashup that’s inside.
The program will ask for the M3 userid and password at the command prompt, as it’s more secure to not hard-code them in source code nor in a config file.
Result
Here is an example of deploying three Mashups on two environments:
Here is the result in the MangoServer database of one of the environments:
Here is the result in Smart Office:
Variations
- Instead of using Microsoft Visual Studio, you can use Xamarin’s MonoDevelop which is free software (as in freedom) and open source and recently acquired by Microsoft, or use Microsoft’s .NET SDK’s C# command line compiler csc.exe
- If you are more familiar with the JScript.NET programming language than C#, you can re-write the program in that language and compile it with Microsoft’s .NET SDK’s JScript.NET command line compiler jsc.exe (you could also run it as a script in Smart Office but that wouldn’t make sense)
- Instead of generating web service client code, you can use the Smart Office method Mango.Core.DynamicWs.WSDataService.CallAsync
Future work
- Remove the Mashups from LifeCycle Manager as Karin instructed
- Replace our generated web service client code with the built-in Smart Office code, if and when Infor Product Development will provide it
- Explore the Mango Admin tool
- Explore the FeatureServlet of the latest Smart Office hotfix
- Encrypt the password in the config file using a symmetric cipher as in the Grid applications, or use a YubiKey (hey, Sweden)
Conclusion
That was my solution to deploy Mashups at the command line. This is useful when deploying multiple Mashups, on multiple M3 environments, multiple times a day. It can potentially save hundreds of clicks and keystrokes per day compared to using the graphical user interfaces of Smart Office Mashup Designer and LifeCycle Manager. The time saved can be invested in the Mashups rather than on their deployment, aiming for continuous integration.
That’s it!
Please let me know what you think in the comments below, give me a thumbs up, click the Follow button to subscribe to this blog, share with your co-workers, and come write the next blog post with us. Pleeease, click something. Your support keeps this community going. Thank you for your support.
M3 Ideas, now 244 subscribers.
Related posts
- Continuous integration of Mashups #1 – HELP WANTED!!
- Continuous integration of Mashups #2 – Reverse engineering
- Continuous integration of Mashups #3 – HELP GOTTEN!!
- Continuous integration of Mashups #4 – Command line
UPDATE: Clarified usage
LikeLike
NOTE: Uninstall the Mashup from LCM prior to deploying it via the command line. i.e. un-install then deploy; the timestamps matter; if you do it in reverse, i.e deploy then un-install, then the Mashup will disappear from Smart Office.
LikeLike
NOTE: LCM does version control of Mashups: it won’t allow deploying a Mashup if that Mashup’s version number is already deployed. Now that we’re bypassing LCM, we must be the ones doing the version control. So let’s be careful with the version numbers.
LikeLike
NOTE: According to the message in SaveMashupFile, if the Mashup has a profile segment, this technique won’t work. FUTURE WORK
LikeLike
UPDATE: I updated the source code, and moved it to my GitHub at https://github.com/M3OpenSource/MashupDeployment
LikeLike