Welcome to K2 Underground Sign In | Join | Help

Automatic Deployment of K2 Process and K2 SmartObject artefacts using theSourceCode Deployment Framework and MSBuild Assemblies

Introduction

Continuous Integration is a deployment concept that ensures changes to your code base results in an automatic build and deployment to their target environments. This article explains how to automatically deploy K2 Process and K2 SmartObject artefacts using the SourceCode Deployment Framework and the MSBuild Assemblies. The example code can be used to create a custom MSBuild task that can be included in a MSBuild file. CCNet, TFS and FinalBuilder are typically used to automatically build and deploy applications using MSBuild files as deployment directives.

K2 and MSBuild

The K2 Deployment Framework takes advantage of the MSBuild Libraries to build and deploy K2 Projects. This K2 deployment process is transparent to Developers using VS 2005 to compile and deploy K2 processes. The K2 Deployment API is used by VS 2005 under the covers to achieve this. This article will explain how to used this API and automate this build and deployment process.

Implementation Example

This example will create a Deployment Class called LibK2Deploy that will be referenced by a Console Application that calls a static method called Execute to deploy the K2 Processes or K2 SmartObjects. 

Let’s Start

Open VS 2005 and create a new Solution. Add a new Class Library project called LibK2Build to the solution. Add a new class to the project called LibK2Deploy. Add References to the following Assemblies

·         Microsoft.Build.Engine

·         Microsoft.Build.Framework

·         SourceCode.EnvironmentSettings.Client

·         SourceCode.Framework

·         SourceCode.Workflow.Design

Add the following code in your using directives

using SourceCode.EnvironmentSettings.Client;

using SourceCode.Framework.Deployment;

using SourceCode.ProjectSystem;

using SourceCode.Workflow.Design.EnvironmentSettings;

The class will contain a public Execute method and two helper methods GetEnvironmentManager and GetDeploymentPackage. Execute will use the EnvironmentSettingsManager and DeploymentPackage returned from the respective helper methods to build and deploy the K2 Project.

Add the following code into LibK2Deploy your class:

The method below is a standard way to return the Environment Manager.

private static EnvironmentSettingsManager GetEnvironmentManager()

        {

            EnvironmentSettingsManager environmentManager = new EnvironmentSettingsManager(false, false);

 

            // This is weird but the only way I could get it to work!

            environmentManager.ConnectToServer(GetConnectionString());

            environmentManager.InitializeSettingsManager();

            environmentManager.ConnectToServer(GetConnectionString());

 

            if (_environment != null)

                environmentManager.ChangeEnvironment(_environment);

            environmentManager.InitializeSettingsManager();

            environmentManager.GetEnvironmentFields(environmentManager.CurrentEnvironment);

 

            return environmentManager

}

 

The method below is particularly useful because you can intercept and change the Environment Field Values based on your configuration. You also specify your Deployment Label and Description in this method. These are the same Label and Description you would specify in VS 2005 when you deploy your K2 Artefacts. Note there are separate sections of code that deals with K2 Workflow and K2 SmartObject objects.

private static DeploymentPackage GetDeploymentPackage(Project project, EnvironmentSettingsManager environmentManager)

        {

            DeploymentPackage package;

 

            package = project.CreateDeploymentPackage();

 

            // Populate Environment Fields

            foreach (EnvironmentInstance env in environmentManager.CurrentTemplate.Environments)

            {

                DeploymentEnvironment depEnv = package.AddEnvironment(env.EnvironmentName);

                foreach (EnvironmentField field in env.EnvironmentFields)

                {

                    depEnv.Properties[field.FieldName] = field.Value;

                }

            }

 

            package.SelectedEnvironment = environmentManager.CurrentEnvironment.EnvironmentName;

            package.DeploymentLabelName = DateTime.Now.ToString();

            package.DeploymentLabelDescription = string.Empty;

            package.TestOnly = false;

 

            // Get the Default SmartObject Server in the Environment

            // The prefix "$Field=" is when the value of the SmartObject server is registered in the environment fields collection.

            // this will do a lookup in the environment with the display name of the field, and use the value.

            // If you set the value directly, no lookups will be performed.

            EnvironmentField smartObjectServerField =

                environmentManager.CurrentEnvironment.GetDefaultField(typeof(SmartObjectField));

            package.SmartObjectConnectionString = "$Field=" + smartObjectServerField.DisplayName;

 

            // Get the Default Workflow Management Server in the Environment

            EnvironmentField workflowServerField =

                environmentManager.CurrentEnvironment.GetDefaultField(typeof(WorkflowManagementServerField));

            package.WorkflowManagementConnectionString = "$Field=" + workflowServerField.DisplayName;

 

            return package;

}

 

This method creates a K2 Connection String that is used by the methods above.

 

private static string GetConnectionString()

{

            return string.Format("Integrated=True;IsPrimaryLogin=True;Authenticate=True;EncryptedPassword=False;Host={0};Port={1}", _server, _port);

}

The helper methods use the private variables below that are populated with the K2HostServer, Port and Environment Name. Add these to your class:

static string _server;

static int _port;

static string _environment;

 

Add the Execute method to the code. This public method’s signature accepts the K2 Host Server name (eg. “BLACKPEARL”), the Environment Name (typically “Development”, “Production”), the ProjectPath the location of the “.k2proj” that needs deploying and OuputPath the location of the MSBuild files that are consumed by MSBuild during deployment.

public static bool Execute(string K2HostServer, string EnvironmentName, string ProjectPath, string OutputPath)

        {

            _environment = EnvironmentName;

            _port = 5555;

            _server = K2HostServer;

 

            Project project;

            EnvironmentSettingsManager environmentManager;

            DeploymentResults results;

            DeploymentPackage package;

 

            bool success = false;

 

            try

            {

                project = new Project();

                project.Load(ProjectPath);

                // Compile the K2 Project

                results = project.Compile();

 

                environmentManager = GetEnvironmentManager();

                package = GetDeploymentPackage(project, environmentManager);

                package.Save(OutputPath, "K2 Deployment Package");

 

                results = package.Execute();

 

                success = results.Successful;

            }

            catch (Exception ex)

            {

                throw ex;

            }

 

            return success;

        }

Compile the project and add a new Console Application to the solution. Add a reference to the LibK2Build to your Console Application and add the following code:

using System;

using ArnIT.K2Lib.Build;

 

class Test

{

 static void Main(string[] args)

  {

LibK2Deploy.Execute("BLACKPEARL",

"Development",

@"C:\EmpSys\SlnEmp\EmpK2\ArnITK2EmpWF.k2proj",

@"C:\EmpSys\BUILD");          

  } 

}

 

The example above will deploy a K2 Workflow Project file called ArnITK2EmpWF.k2proj to a K2 Host Server called BLACKPEARL’s Development Environment.

 

Compile the project. Ensure you have the correct Deployment permissions before you run the application.  

  

Deployment

The following line of code in the Execute method will compile the .kproj file

results = project.Compile();

Notice the output Timestamp of the Assembly in the \bin\<%configuration%> folder changed after  this line of code executed.

 

The following line of code will create the deployment package, ready for deployment

package = GetDeploymentPackage(project, environmentManager);

 

The code below saves the all the files required by the MSBuild script. Note that you can execute MSBuild.exe against the “K2 Deployment Package.msbuild” file to deploy. You might create the MSBuild file, and decide to deploy at some other stage

package.Save(OutputPath, "K2 Deployment Package");

 

 

results = package.Execute(); deploys the package and the output of K2 Host Server will show the deployment cycle's output. This same output will be produced as a result of a VS 2005 deployment. 

Finally

You can subclass the MSBuild Task class and override the MSBuild Execute() method to convert the example into a custom MSBuild task. The following code extract shows part of the class:

using Microsoft.Build.Framework;

using Microsoft.Build.Utilities;

 

namespace ArnIT.K2Lib.Build

{

    public class LibK2Deploy : Task

{

public override bool Execute()...

This task can be called as part of the MSBuild process during execution.

The next post will show how to use this task as part of a Continuous Integration example using CCNet 3.0.

Happy Deploying...

 

 

Published Wednesday, April 30, 2008 2:02 AM by arno

Comments

# re: Automatic Deployment of K2 Process and K2 SmartObject artefacts using theSourceCode Deployment Framework and MSBuild Assemblies

Monday, July 28, 2008 2:19 PM by astevens

Hey,

I love the code above, it has been very helpful.  I wrapped it up into an exe so that I could include the generation of the K2 deployment packages with the rest of my build process.  Everything was working great for a couple of weeks and now I have run into a problem.  Any krpx that uses IPC.IPCEventItem can't compile using the above code.  The following error gets thrown:

Target "Build" in project "CSCode-cd35a11e99b4411eb62d8c8c7c1dbb6d.csproj"

Property accessor 'ProcessObject' on object 'SourceCode.Workflow.Design.IPC.IPCEventItem' threw the following exception:'Object reference not set to an instance of an object.'

  at System.ComponentModel.ReflectPropertyDescriptor.GetValue(Object component)

  at SourceCode.Framework.PersistableObject.Validate()

  at SourceCode.Framework.PersistableContainerObject.Validate()

....

The strange thing is that it compiles fine using the IDE.  Any ideas?

Thanks

astevens

Anonymous comments are disabled