Saturday 12 December 2020

Automate CRM Solution Deployment

 In this blog I am going to explain step by step guide to automate CRM solution (Unmanaged/Managed) deployment from DEV to SIT, UAT & Prod. I will use devops to demonstrate this use case.

Login to dev.azure.com-> Create new project

DevOps01

Once project created successfully, Navigate to Pipeline and create new pipeline. Select Use classic editor option.

DevOps02

Once you click on Use Class Editor link, it will open new dialog and select Agent. Azure devops will automatically populate for you. You can use custom built Agent as well.

DevOps3

Now we need to install Power Devops Tool by Wael Hamze. Once installed add this in your pipeline.

DevOps04

Next we have add Ping Environment task from Power Devops Tools to check if Dynamics CRM instance is up and running. We need to provide CRM Connectiong String in below format

AuthType=Office365;Username=username@name.onmicrosoft.com; Password=CRM Online Password;Url=https://CRMORG.crm8.dynamics.com

DevOps05

Then we have to add SetVersion task to set the CRM solution version number based on build number. Click on Options tab and set Build Number with as bewlo format. And use this in Set Version task in Version Number as $(Build.BuildNumber).

1.0.0.$(Rev:r) - Last digit of version number will be dynamically changed for each run.

Check this pagefor Azure Devops predefined variables

DevOps15

Now add Publish Customizations task to publish any changes before exporting the solution. It takes only connection string parameter.

DevOps16

Next add Export Solution Task from power devops tool and provide Connection string as mentioned in above steps and Solution Name which you want to take deploy.

Select whether you want to export managed or unmanaged solution. Also select additional General settings to be exported as part of the solution.

DevOps06

DevOps07

Next add Publish Build Artifact task to publish the solution zip file to Azure pipeling Artifact which will be used by Release to deploy to SIT, UAT & Prod. Select Path to publish as $(Build.ArtifactStagingDirectory) which we have used in export solution task. Publish Build Artifact will copy file from this location to Azure pipeline Artifact.

DevOps19

Pipeline is completed for exporting the solution and publishing the solution file to Artifact. Run this pipeline manually and verify Solution Zip file is published to Artifact.

DevOps14

Create Release to Deploy Solution to Target Environment

Click on Releases from left menu and create new release for UAT. And select Artifact where solution zip file is published.

DevOps13

Next go to Tasks and add below tasks in Releases.

  1. Add Power Devops Tools installer
  2. Add Ping Environemnt - Provide Connection string of Target Environment
  3. Add Import Solution - Provide Connection string of Target Environment and select Solution file as shown below

DevOps18

Once done, Click on Create Release to verify solution Deployment to Target Environment.

DevOps20

To downloag Solution Import Log file, Go to Release window and click on Download All Logs.

DevOps21

Hope this helps!

Thursday 24 September 2020

Color Console

 


In this post I'll discuss a small Console helper class I've been using to make it easier and more consistent to use colors with the .NET Console command. While colors are easy enough to access in the Console, to switch colors is a bit of a pain with the plain Console API. The simple class I present here makes it easier to write a line or string in a given color, write a line with multiple colors (using simple [color]text[/color] templating) and an easy way to create a header. The following is a very simple ColorConsole class that provides some useful color helpers:

  • WriteLine() and Write() methods with Color parameters
  • WriteError()WriteInfo()WriteSuccess() and WriteWarning() methods
  • A color template expansion WriteEmbeddedColorLine() function
  • A header generation routine

The Write methods let me quickly write output in a specific color without worrying about setting and resetting the color. The output is written with the specified color and the color is always reset to previously active color.

The high level wrappers like WriteError() and WriteSuccess() provide an alternative the raw Write methods and are more explicit about the intent of the message. It makes colors more consistent with color choices for common situations like error or informational statements.

I often find myself writing Console output that requires multiple more than a single color in a line of text when highlighting values over labels or displaying multiple values of difference importance. I can use multiple Write() statements with colors for this, but to make this easier to read I created a templated method that allows delimiting text with [color]text[/color] delimiters in a string.

csharp
ColorConsole.WriteEmbeddedColorLine($"Site Url: [darkcyan]{ServerConfig.GetHttpUrl()}[/darkcyan] [darkgray](binding: {HostUrl})[darkgray]");

Try it out

To use the class looks something like this:

csharp
static void Main(string[] args) { ColorConsole.WriteWrappedHeader("Color Console Examples"); Console.WriteLine("\nUsing a splash of color in your Console code more easily... (plain text)\n"); ColorConsole.WriteLine("Color me this - in Red", ConsoleColor.Red); ColorConsole.WriteWrappedHeader("Off with their green Heads!", headerColor: ConsoleColor.Green); ColorConsole.WriteWarning("\nWorking...\n"); Console.WriteLine("Writing some mixed colors: (plain text)"); ColorConsole.WriteEmbeddedColorLine( "Launch the site with [darkcyan]https://localhost:5200[/darkcyan] and press [yellow]Ctrl-c[/yellow] to exit.\n"); ColorConsole.WriteSuccess("The operation completed successfully."); }

which produces the following output:

Code

Here's the ColorConsole class:

csharp
/// <summary> /// Console Color Helper class that provides coloring to individual commands /// </summary> public static class ColorConsole { /// <summary> /// WriteLine with color /// </summary> /// <param name="text"></param> /// <param name="color"></param> public static void WriteLine(string text, ConsoleColor? color = null) { if (color.HasValue) { var oldColor = System.Console.ForegroundColor; if (color == oldColor) Console.WriteLine(text); else { Console.ForegroundColor = color.Value; Console.WriteLine(text); Console.ForegroundColor = oldColor; } } else Console.WriteLine(text); } /// <summary> /// Writes out a line with a specific color as a string /// </summary> /// <param name="text">Text to write</param> /// <param name="color">A console color. Must match ConsoleColors collection names (case insensitive)</param> public static void WriteLine(string text, string color) { if (string.IsNullOrEmpty(color)) { WriteLine(text); return; } if (!Enum.TryParse(color, true, out ConsoleColor col)) { WriteLine(text); } else { WriteLine(text, col); } } /// <summary> /// Write with color /// </summary> /// <param name="text"></param> /// <param name="color"></param> public static void Write(string text, ConsoleColor? color = null) { if (color.HasValue) { var oldColor = System.Console.ForegroundColor; if (color == oldColor) Console.Write(text); else { Console.ForegroundColor = color.Value; Console.Write(text); Console.ForegroundColor = oldColor; } } else Console.Write(text); } /// <summary> /// Writes out a line with color specified as a string /// </summary> /// <param name="text">Text to write</param> /// <param name="color">A console color. Must match ConsoleColors collection names (case insensitive)</param> public static void Write(string text, string color) { if (string.IsNullOrEmpty(color)) { Write(text); return; } if (!ConsoleColor.TryParse(color, true, out ConsoleColor col)) { Write(text); } else { Write(text, col); } } #region Wrappers and Templates /// <summary> /// Writes a line of header text wrapped in a in a pair of lines of dashes: /// ----------- /// Header Text /// ----------- /// and allows you to specify a color for the header. The dashes are colored /// </summary> /// <param name="headerText">Header text to display</param> /// <param name="wrapperChar">wrapper character (-)</param> /// <param name="headerColor">Color for header text (yellow)</param> /// <param name="dashColor">Color for dashes (gray)</param> public static void WriteWrappedHeader(string headerText, char wrapperChar = '-', ConsoleColor headerColor = ConsoleColor.Yellow, ConsoleColor dashColor = ConsoleColor.DarkGray) { if (string.IsNullOrEmpty(headerText)) return; string line = new string(wrapperChar, headerText.Length); WriteLine(line,dashColor); WriteLine(headerText, headerColor); WriteLine(line,dashColor); } private static Lazy<Regex> colorBlockRegEx = new Lazy<Regex>( ()=> new Regex("\\[(?<color>.*?)\\](?<text>[^[]*)\\[/\\k<color>\\]", RegexOptions.IgnoreCase), isThreadSafe: true); /// <summary> /// Allows a string to be written with embedded color values using: /// This is [red]Red[/red] text and this is [cyan]Blue[/blue] text /// </summary> /// <param name="text">Text to display</param> /// <param name="baseTextColor">Base text color</param> public static void WriteEmbeddedColorLine(string text, ConsoleColor? baseTextColor = null) { if (baseTextColor == null) baseTextColor = Console.ForegroundColor; if (string.IsNullOrEmpty(text)) { WriteLine(string.Empty); return; } int at = text.IndexOf("["); int at2 = text.IndexOf("]"); if (at == -1 || at2 <= at) { WriteLine(text, baseTextColor); return; } while (true) { var match = colorBlockRegEx.Value.Match(text); if (match.Length < 1) { Write(text, baseTextColor); break; } // write up to expression Write(text.Substring(0, match.Index), baseTextColor); // strip out the expression string highlightText = match.Groups["text"].Value; string colorVal = match.Groups["color"].Value; Write(highlightText, colorVal); // remainder of string text = text.Substring(match.Index + match.Value.Length); } Console.WriteLine(); } #endregion #region Success, Error, Info, Warning Wrappers /// <summary> /// Write a Success Line - green /// </summary> /// <param name="text">Text to write out</param> public static void WriteSuccess(string text) { WriteLine(text, ConsoleColor.Green); } /// <summary> /// Write a Error Line - Red /// </summary> /// <param name="text">Text to write out</param> public static void WriteError(string text) { WriteLine(text, ConsoleColor.Red); } /// <summary> /// Write a Warning Line - Yellow /// </summary> /// <param name="text">Text to Write out</param> public static void WriteWarning(string text) { WriteLine(text, ConsoleColor.DarkYellow); } /// <summary> /// Write a Info Line - dark cyan /// </summary> /// <param name="text">Text to write out</param> public static void WriteInfo(string text) { WriteLine(text, ConsoleColor.DarkCyan); } #endregion }


Summary

Nothing fancy, and nothing you couldn't come up with in a few minutes yourself, but I find these super helpful and end up using this in just about any Console application now to make it easier to print help screens and provide basic status and progress information. Maybe some of you will find these useful as well...

Hide New... button on lookup controls in model-driven apps

  The 'New ...' button is shown upon opening the lookup search dialog whenever the logged in user has at least user create privileg...