Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to register dependent assemblies plugin packages #330

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

31,618 changes: 16,701 additions & 14,917 deletions MSDYNV9/Xrm.Framework.CI/Xrm.Framework.CI.Common/Entities/Entities.cs

Large diffs are not rendered by default.

15,565 changes: 7,970 additions & 7,595 deletions MSDYNV9/Xrm.Framework.CI/Xrm.Framework.CI.Common/Entities/OptionSets.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;

namespace Xrm.Framework.CI.Common.PluginRegistration
{
public class Package
{
public Guid? Id { get; set; }

public string Name { get; set; }

public List<Assembly> Assemblies { get; set; }

public Package()
{
Assemblies = new List<Assembly>();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Xml.Linq;

namespace Xrm.Framework.CI.Common.PluginRegistration
{
public class PackageInfo
{
public string PackageName { get; private set; }

public string PackageVersion { get; set; }

public string PackageDirectory { get; private set; }

public string Content { get; private set; }

private PackageInfo()
{ }

public static PackageInfo GetPackageInfo(string packagePath)
{
if (packagePath.EndsWith(".nupkg") == false)
throw new Exception("Invalid package file extension. Only .nupkg files are supported.");

var zip = ZipFile.OpenRead(packagePath);

var entry = zip.Entries.FirstOrDefault(x => x.Name.EndsWith("nuspec"));

if (entry == null)
throw new Exception("Package does not contain a nuspec file.");

var doc = XDocument.Load(entry.Open());
var ns = doc.Root.GetDefaultNamespace();

var id = doc.Descendants(ns + "id").First().Value;
var version = doc.Descendants(ns + "version").First().Value;

var info = new PackageInfo
{
PackageName = id,
PackageVersion = version,
PackageDirectory = packagePath,
Content = Convert.ToBase64String(File.ReadAllBytes(packagePath))
};

return info;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.Xml.XPath;

using Xrm.Framework.CI.Common;
using Xrm.Framework.CI.Common.PluginRegistration;

namespace Xrm.Framework.CI.Common
{
Expand Down Expand Up @@ -87,7 +88,7 @@ public void RemoveComponentsNotInMapping(Assembly assemblyMapping)
}
}

public void DeleteObjectWithDependencies(Guid objectId, ComponentType? componentType, HashSet<string> deletingHashSet = null)
public void DeleteObjectWithDependencies(Guid objectId, ComponentType? componentType, HashSet<string> deletingHashSet = null, int? componentTypeInt = null)
{
if (deletingHashSet == null)
{
Expand Down Expand Up @@ -137,6 +138,7 @@ public void DeleteObjectWithDependencies(Guid objectId, ComponentType? component
logVerbose?.Invoke($"Trying to delete {componentType} {workflow.Name}");
organizationService.Delete(Workflow.EntityLogicalName, objectId);
break;

case ComponentType.SDKMessageProcessingStep:
var step = pluginRepository.GetSdkMessageProcessingStepById(objectId);
if (step.IsHidden.Value == true)
Expand All @@ -147,19 +149,32 @@ public void DeleteObjectWithDependencies(Guid objectId, ComponentType? component
logVerbose?.Invoke($"Trying to delete {componentType} {step.Name} / {objectId}");
organizationService.Delete(SdkMessageProcessingStep.EntityLogicalName, objectId);
break;

case ComponentType.PluginType:
var type = pluginRepository.GetPluginTypeById(objectId);
logVerbose?.Invoke($"Trying to delete {componentType} {type.Name} / {objectId}");
organizationService.Delete(PluginType.EntityLogicalName, objectId);
break;

case ComponentType.PluginAssembly:
logVerbose?.Invoke($"Trying to delete {componentType} {objectId}");
organizationService.Delete(PluginAssembly.EntityLogicalName, objectId);
break;

case ComponentType.ServiceEndpoint:
logVerbose?.Invoke($"Trying to delete {componentType} {objectId}");
organizationService.Delete(ServiceEndpoint.EntityLogicalName, objectId);
break;

case null:
switch (componentTypeInt)
{
case 10031:
logVerbose?.Invoke($"Trying to delete {componentTypeInt} {objectId}");
organizationService.Delete(PluginPackage.EntityLogicalName, objectId);
break;
}
break;
}
}

Expand All @@ -183,6 +198,30 @@ private void RemoveAllWorkflowsFromBpf(Workflow bpf)
});
}

public Guid UpsertPluginPackage(PackageInfo packageInfo, string solutionName, string publisherPrefix, RegistrationTypeEnum registrationType)
{
var id = pluginRepository.GetPluginPackageId($"{publisherPrefix}_{packageInfo.PackageName}");
logWarning?.Invoke($"Extracted id using plugin package name {publisherPrefix}_{packageInfo.PackageName}");

var package = new PluginPackage()
{
Name = packageInfo.PackageName,
Content = packageInfo.Content,
};

if (!id.Equals(Guid.Empty) && registrationType == RegistrationTypeEnum.Reset)
{
DeleteObjectWithDependencies(id, null, null, 10031);
}

logVerbose?.Invoke($"Trying to upsert {packageInfo.PackageName} / {id}");
id = ExecuteRequest(registrationType, id, package);

AddComponentToSolution(id, null, solutionName, 10031);

return id;
}

public Guid UpsertPluginAssembly(Assembly pluginAssembly, AssemblyInfo assemblyInfo, string solutionName, RegistrationTypeEnum registrationType)
{
Guid Id = pluginAssembly?.Id ?? Guid.Empty;
Expand Down Expand Up @@ -220,7 +259,7 @@ public Guid UpsertPluginAssembly(Assembly pluginAssembly, AssemblyInfo assemblyI
return Id;
}

public void UpsertPluginTypeAndSteps(Guid parentId, Type pluginType, string solutionName, RegistrationTypeEnum registrationType)
public void UpsertPluginTypeAndSteps(Guid parentId, Type pluginType, string solutionName, RegistrationTypeEnum registrationType, bool isPluginPackage = false)
{
Guid Id = pluginType.Id ?? Guid.Empty;
if (Id == Guid.Empty)
Expand All @@ -229,19 +268,22 @@ public void UpsertPluginTypeAndSteps(Guid parentId, Type pluginType, string solu
logWarning?.Invoke($"Extracted id using plugin type name {pluginType.Name}");
}

var type = new PluginType()
if (!isPluginPackage)
{
Name = pluginType.Name,
Description = pluginType.Description,
FriendlyName = pluginType.FriendlyName,
TypeName = pluginType.TypeName,
WorkflowActivityGroupName = pluginType.WorkflowActivityGroupName,
PluginAssemblyId = new EntityReference(PluginAssembly.EntityLogicalName, parentId)
};

Id = ExecuteRequest(registrationType, Id, type);
// AddComponentToSolution(Id, ComponentType.PluginType, solutionName);
logVerbose?.Invoke($"UpsertPluginType {Id} completed");
var type = new PluginType()
{
Name = pluginType.Name,
Description = pluginType.Description,
FriendlyName = pluginType.FriendlyName,
TypeName = pluginType.TypeName,
WorkflowActivityGroupName = pluginType.WorkflowActivityGroupName,
PluginAssemblyId = new EntityReference(PluginAssembly.EntityLogicalName, parentId)
};

Id = ExecuteRequest(registrationType, Id, type);
// AddComponentToSolution(Id, ComponentType.PluginType, solutionName);
logVerbose?.Invoke($"UpsertPluginType {Id} completed");
}

var typeRef = new EntityReference(PluginType.EntityLogicalName, Id);

Expand All @@ -267,9 +309,11 @@ public void SerializerObjectToFile(string mappingFile, object obj)
case ".json":
Serializers.SaveJson(mappingFile, obj);
break;

case ".xml":
Serializers.SaveXml(mappingFile, obj);
break;

default:
throw new ArgumentException("Only .json and .xml mapping files are supported", nameof(mappingFile));
}
Expand Down Expand Up @@ -298,7 +342,6 @@ public void UpsertServiceEndpoints(List<ServiceEndpt> serviceEndptLst, string so
logVerbose?.Invoke($"UpsertSdkMessageProcessingStepImage {imageId} completed");
}
}

}
}

Expand Down Expand Up @@ -437,19 +480,24 @@ private Guid ExecuteRequest(RegistrationTypeEnum registrationType, Guid Id, Enti
return Id;
}

private void AddComponentToSolution(Guid componentId, ComponentType componentType, string solutionName)
private void AddComponentToSolution(Guid componentId, ComponentType? componentType, string solutionName, int? componentTypeInt = null)
{
if (string.IsNullOrEmpty(solutionName))
{
return;
}

if (!componentType.HasValue && !componentTypeInt.HasValue)
{
return;
}

logVerbose?.Invoke($"Adding {componentType} {componentId} to solution {solutionName}");
organizationService.Execute(new AddSolutionComponentRequest
{
AddRequiredComponents = false,
ComponentId = componentId,
ComponentType = (int)componentType,
ComponentType = componentType.HasValue ? (int)componentType : componentTypeInt.Value,
SolutionUniqueName = solutionName
});
}
Expand All @@ -476,14 +524,27 @@ public Assembly ReadMappingFile(string mappingFile)
var pluginAssembly = Serializers.ParseJson<Assembly>(mappingFile);
logVerbose("Deserialized mapping json file");
return pluginAssembly;

case ".xml":
logVerbose("Reading mapping xml file");
pluginAssembly = Serializers.ParseXml<Assembly>(mappingFile);
logVerbose("Deserialized mapping xml file");
return pluginAssembly;

default:
throw new ArgumentException("Only .json and .xml mapping files are supported", nameof(ReadMappingFile));
}
}

public void LoadPluginPackageAssemblies(Package pluginPackage)
{
var pluginAssemblies = pluginRepository.GetPluginPackageAssemblies(pluginPackage.Id.Value);

foreach (var pluginAssembly in pluginAssemblies)
{
var assembly = pluginRepository.GetAssemblyRegistration(pluginAssembly.Name, pluginAssembly.Version);
pluginPackage.Assemblies.Add(assembly);
}
}
}
}
Loading