Incrementing Solution Version Number in Azure DevOps Pipeline Using PowerShell Cmdlet

Incrementing Solution Version Number in Azure DevOps Pipeline Using PowerShell Cmdlet


Managing version numbers for software solutions is a crucial aspect of maintaining orderly deployments and updates. Automating this process within your Azure DevOps pipeline can save time and reduce human error. In this article, we will explore how to create and use a PowerShell cmdlet to increment the version number of a solution within an Azure DevOps pipeline.

 

Overview

 The provided PowerShell cmdlet IncrementerCmdlet increments the version number of a specified solution. This cmdlet is integrated into an Azure DevOps pipeline to automate version management. Let's delve into the implementation and how it can be effectively utilized in your CI/CD pipeline.

 

Cmdlet Implementation

 Below is the implementation of the IncrementerCmdlet class, which includes the essential components for version increment:

 /// <summary>
/// Increment solution version
/// </summary>
/// <param name="serviceClient"></param>
/// <param name="solutionName"></param>
public static void IncSolutionVersion(this IOrganizationService serviceClient, string solutionName)
{
    // Query to retrieve solutions
    QueryExpression query = new QueryExpression("solution")
    {
        ColumnSet = new ColumnSet("solutionid", "uniquename", "version")
    };

    // Execute the query
    EntityCollection result = serviceClient.RetrieveMultiple(query);

    // Find the solution with the specified unique name
    var solution = result.Entities.FirstOrDefault(x => x.GetAttribute<string>("uniquename") == solutionName);
    if (solution != null)
    {
        var version = solution.GetAttribute<string>("version");

        solution.SetAttribute("version", version.NewVersion());

        // Update the solution
        serviceClient.Update(solution);
    }
}


using System;
using System.Management.Automation;
using Microsoft.Xrm.Tooling.Connector;

[Cmdlet("Inc", "Version")]
public class IncrementerCmdlet : Cmdlet
{
    
    public IncrementerCmdlet(){}

    #region Parameters

    /// <summary>
    /// <para type="description">The unique name of the target solution </para>
    /// </summary>
    [Parameter(Mandatory = true)]
    public string solution { get; set; } = "";

    [Parameter(Mandatory = true)]
   public string EnvironmentUrl { get; set; } = "";

   [Parameter(Mandatory = true)]
   Pubic string ClientId { get; set; } = "";

   [Parameter(Mandatory = true)]
   public string ClientSecret { get; set; } = "";

   [Parameter(Mandatory = false)]
   public int Timeout { get; set; }

   protected string getConnectionString()
   {
    return $"Url={EnvironmentUrl};AuthType=ClientSecret;ClientId={ClientId};ClientSecret={ClientSecret}";
   }
    #endregion

    #region Process Record

    protected override void ProcessRecord()
    {
        base.ProcessRecord();
        this.Run();
    }

   /// <summary>
   /// Method to log messages, either to console or using WriteObject
   /// </summary>
   /// <param name="str"></param>
   protected virtual void log(string str)
   {
           WriteObject(str);
   }

    /// <summary>
    /// Main logic to copy solution components from source solutions to target solution
    /// </summary>
    public void Run()
    {
        try
        {
            // Important to set the security protocol for ServicePointManager
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            // Create a new ServiceClient using the connection string
            using (var serviceClient = new CrmServiceClient(getConnectionString()))
            {
                Increment(serviceClient, solution);
            }
        }
        catch (Exception ex)
        {
            log(ex.Message);
            log(ex.StackTrace);
            throw;
        }
    }

    /// <summary>
    /// Increment solution version number
    /// </summary>
    /// <param name="serviceClient"></param>
    /// <param name="solution"></param>
    public void Increment(IOrganizationService serviceClient, string solution)
    {
        log(string.Format("Incrementing Solution version for {0} ", solution));
        serviceClient.IncSolutionVersion(solution);
        log("** Done **");
    }

    #endregion
}        

And here is the extension method to increment the version of the solution

/// <summary>
/// Increment solution version
/// </summary>
/// <param name="serviceClient"></param>
/// <param name="solutionName"></param>
public static void IncSolutionVersion(this IOrganizationService serviceClient, string solutionName)
{
    // Query to retrieve solutions
    QueryExpression query = new QueryExpression("solution")
    {
        ColumnSet = new ColumnSet("solutionid", "uniquename", "version")
    };

    // Execute the query
    EntityCollection result = serviceClient.RetrieveMultiple(query);

    // Find the solution with the specified unique name
    var solution = result.Entities.FirstOrDefault(x => x.GetAttribute<string>("uniquename") == solutionName);
    if (solution != null)
    {
        var version = solution.GetAttribute<string>("version");

        solution.SetAttribute("version", version.NewVersion());

        // Update the solution
        serviceClient.Update(solution);
    }
}        

Key Components

 1.     Parameters: The solution parameter is mandatory and is used to specify the unique name of the solution whose version number needs to be incremented.

2.     ProcessRecord Method: This method overrides the base method to execute the main logic encapsulated in the Run method.

3.     Run Method: Establishes a connection to the service and calls the Increment method to update the version number.

4.     Increment Method: Logs the version increment process and calls IncSolutionVersion to perform the version increment operation.

 

Integration with Azure DevOps Pipeline

 To utilize the IncrementerCmdlet in an Azure DevOps pipeline, follow these steps:

 1.     Add PowerShell Cmdlet to Repository: Ensure the cmdlet code and DLL assembly is part of your repository.

2.     Define Pipeline: Update your Azure DevOps pipeline YAML file to include a task for running the PowerShell cmdlet.

Example YAML pipeline configuration:

# manually trigger
trigger: none

pool:
  vmImage: 'windows-latest'

# Install Power Platform Tools
steps:
- task: PowerPlatformToolInstaller@2
  inputs:
    DefaultVersion: true

# Set connection variables
- task: PowerPlatformSetConnectionVariables@2
  inputs:
    authenticationType: 'PowerPlatformSPN'
    PowerPlatformSPN: 'Dev Connection'
    Environment: '$(environmentUrl)'

# Increment Solution Version
- task: PowerShell@2 
  inputs:
    targetType: 'inline'
    script: |
      $environmentUrl = '$(environmentUrl)'
      $clientId = '$(PowerPlatformSetConnectionVariables.BuildTools.ApplicationId)'
      $clientSecret = '$(PowerPlatformSetConnectionVariables.BuildTools.ClientSecret)'
      $solution = '$(SolutionName)'  
      Import-Module $(Build.SourcesDirectory)\ path\to\bin\IncrementVersion.dll" 
      Inc-Version -environmentUrl $environmentUrl -clientId $clientId -clientSecret $clientSecret -solution $solution        

We use PowerPlatformSetConnectionVariables to get access to Client Id and Client Secret of the target environment.

Conclusion

By implementing the IncrementerCmdlet and integrating it into your Azure DevOps pipeline, you can automate the process of incrementing solution version numbers, ensuring consistency and efficiency in your CI/CD workflows. This not only streamlines the deployment process but also helps maintain a clear version history for your solutions.

 

Very helpful!, Love this. Thanks for sharing.

To view or add a comment, sign in

Others also viewed

Explore content categories