[New post] Exploration: Implement CI/CD in Dataverse
temmyraharjo posted: " In this blog post, I will share a bit of my experience in implementing CI/CD on the Dataverse Environment. Even now is not perfect and still got lots of room to improve, I hope you guys can learn something from it. Creating The Exe I currently not "
In this blog post, I will share a bit of my experience in implementing CI/CD on the Dataverse Environment. Even now is not perfect and still got lots of room to improve, I hope you guys can learn something from it.
Creating The Exe
I currently not using any features on official tools (Power Platform Build Tools) because it needs us to configure which solutions that we want to export. So that's why I create my own tools that I store in the repository.
Here is the sample of the code that I created (the Program.cs):
using CommandLine; using CrmDeployment.Business; using Microsoft.Crm.Sdk.Messages; using Microsoft.Xrm.Tooling.Connector; using System; namespace CrmDeployment { class Program { static void Main(string[] args) { Parser.Default.ParseArguments<CommandLineOptions>(args) .WithParsed(option => Run(option)); Console.Read(); } static void Run(CommandLineOptions option) { var client = new CrmServiceClient(option.ConnectionString); Console.WriteLine($"Connected to {client.ConnectedOrgFriendlyName}"); switch (option.Type) { case "Update-WebResource": { new UpsertWebResources(client, option.Directory).Execute(); var publishAll = new PublishAllXmlRequest(); client.Execute(publishAll); Console.WriteLine("Publish All finished"); break; } case "Update-Plugin": new UpdatePlugin(client, option.FilePath).Execute(); break; case "Update-Plugins": new UpdatePlugins(client, option.Directory).Execute(); break; case "Export-Solutions": { var publishAll = new PublishAllXmlRequest(); client.Execute(publishAll); Console.WriteLine("Publish All finished"); new SolutionsExporter(client, option.Directory, option.IsManaged.GetValueOrDefault()).Execute(); break; } case "Import-Solutions": { new SolutionsImporter(client, option.Directory, option.IsToday.GetValueOrDefault()).Execute(); break; } } } } }
On the above code, you can see that I'm using the CommandLineParser NuGet package that makes my code super tidy! You just need to define the model that you will use and define all the properties that will help users to understand more (CommandLineOptions.cs):
using CommandLine; namespace CrmDeployment { public class CommandLineOptions { [Value(index: 0, Required = true, HelpText = "CRM Connection string.")] public string ConnectionString { get; set; } [Value(index: 1, Required = true, HelpText = "Type of the execution console.")] public string Type { get; set; } [Option(shortName: 'f', longName: "filepath", Required = false, HelpText = "FilePath of plugin.")] public string FilePath { get; set; } [Option(shortName: 'd', longName: "directory", Required = false, HelpText = "Directory")] public string Directory { get; set; } [Option(shortName: 'm', longName: "managed", Required = false, HelpText = "Managed")] public bool? IsManaged { get; set; } [Option(shortName: 't', longName: "today", Required = false, HelpText = "Import Today Solution")] public bool? IsToday { get; set; } } }
In the Run method, you can see all the business logic that will be called based on the Type that we pass on the exe. The connection string will be passed on to the exe arguments. So we only need to configure when we call the exe later on. All the source code you can access on this GitHub repo.
Creating App Registration in Azure AD+Application User
Because we don't want to use user authentication (bypass the MFA), creating App Registration is the easiest + better solution.
You can go to portal.azure.com > Azure Active Directory > App registrations > New Registration
You just need to give a Name, and you can click the Register button:
After that you can go to API Permissions blade > Add a permission > select Dynamics CRM > check the user_impersonation > click Add permissions button.
Then you can go to the Certificates & secrets blade > Client secrets > New client secret:
Enter the description and click the Add button. Once you do that, you can copy the Secret Value (it will be gone after that, so you need to save it somewhere) and you also need to go Overview blade to get the Application (client) ID.
Once this is done, we need to register our Application Id in CRM. Go to your CRM environment > Settings > Security > Users > Change the view to Application Users > click New button (if the Form is not selected to Application User form, you can change manually). You just need to copy-paste the Application ID and click save. Once done, you need to assign a System administrator role to this user.
The only left is in this section is to create the connection string that will be consumed in the exe. You need to use this connection string format:
The source of the repository in this demonstration is in Azure Repos Git (not GitHub). So the steps that will be run for this sample will be seen as follow:
Like I said before, this flow is not yet perfect. But at least, I want to encourage you to try it and give your comment on it. This is the screenshot of my root repo folder:
CRMDeployment folder contains the exe that has been built in the first section (Creating The Exe). While in the src for currently only will contain Plugins folder (I already got samples of plugin code + unit tests there).
To create the Azure Pipeline (I will not show you how to set up the whole repo, just directly explain the Azure Pipeline only). To create the Azure Pipeline, go to dev.azure.com > Pipelines blade > New pipeline button > select Azure Repos Git > select your repository > select starter pipeline and change it as follows (YAML file):
The user.email and user.name in this demo are hardcoded. But you can change it using the Pipeline variable.
Once this is done, the next step is to set up our Project settings to enable self-commit inside the CI/CD process. Click the Project Settings > Repositories > click your repository > Security > select your Users (in my case DevOps Learning Build Service) > Set Contribute, Create tag, Create Branch, and Read as Allow.
Then the last thing is to create a Variable. Select Pipelines > your pipeline > select Edit > click Variables. Because in the YAML, we defined the variable for exe connection string as ConnectionString, then you need to name it ConnectionString and copy-paste the connection string that we define before:
Once all of this is done, you can test your pipeline:
Please wait for the next flow (deploying to another environment)!
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.