Skip to content

Commit

Permalink
Allow multiple active version of project and prefabs
Browse files Browse the repository at this point in the history
Automation project version will usually follow along the release version of target application being automated. It is possible that there can be a patch on top of an existing version of the application. This situation might require to patch the subsequent version of the automation project as well. To handle this scenario, it is now possible for projects and prefabs to have multiple active versions.
  • Loading branch information
Nfactor26 committed Oct 27, 2022
1 parent b0f9865 commit b2aaac5
Show file tree
Hide file tree
Showing 29 changed files with 342 additions and 251 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ public string GroupName
}
}

public IEnumerable<PrefabVersion> DeployedVersions
{
get => this.prefabProject.AvailableVersions.Where(a => a.IsDeployed).ToList();
public IEnumerable<PrefabVersion> PublishedVersion
{
get => this.prefabProject.PublishedVersions;
}

public PrefabProjectViewModel(PrefabProject prefabProject)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ public class PrefabVersionManagerViewModel : Screen , IVersionManager
private readonly PrefabProject prefabProject;
private readonly ApplicationSettings applicationSettings;

private bool wasDeployed = false;
private bool wasPublished = false;

public BindableCollection<PrefabVersionViewModel> AvailableVersions { get; set; } = new BindableCollection<PrefabVersionViewModel>();


public PrefabVersionManagerViewModel(PrefabProject prefabProject, IWorkspaceManagerFactory workspaceManagerFactory, IReferenceManagerFactory referenceManagerFactory,
ISerializer serializer, IApplicationDataManager applicationDataManager, ApplicationSettings applicationSettings)
{
this.DisplayName = "Manage & Deploy Versions";
this.DisplayName = "Manage Prefab Versions";
this.workspaceManagerFactory = Guard.Argument(workspaceManagerFactory, nameof(workspaceManagerFactory)).NotNull().Value;
this.referenceManagerFactory = Guard.Argument(referenceManagerFactory, nameof(referenceManagerFactory)).NotNull().Value;
this.serializer = Guard.Argument(serializer, nameof(serializer)).NotNull().Value;
Expand All @@ -45,36 +45,70 @@ public PrefabVersionManagerViewModel(PrefabProject prefabProject, IWorkspaceMana
}

/// <summary>
/// Create a copy of selected version and deploy the selected version.
/// Create a copy of selected version and mark the selected version as published.
/// </summary>
/// <returns></returns>
public async Task Deploy(PrefabVersionViewModel prefabVersionViewModel)
public async Task CloneAndPublishAsync(PrefabVersionViewModel prefabVersionViewModel)
{
try
{
if (prefabVersionViewModel?.IsActive == true)
logger.Information($"Trying to clone version {prefabVersionViewModel.Version} for Prefab : {this.prefabProject.PrefabName}");

//Create a new active version from selected version
PrefabVersion newVersion = prefabVersionViewModel.Clone();
IPrefabFileSystem fileSystem = new PrefabFileSystem(serializer, applicationSettings);
fileSystem.Initialize(this.prefabProject, newVersion);

//Publish the selected version
if(!prefabVersionViewModel.IsPublished)
{
//Create a new active version from selected version
PrefabVersion newVersion = prefabVersionViewModel.Clone();
prefabVersionViewModel.Publish(this.workspaceManagerFactory);
logger.Information($"Version {prefabVersionViewModel.Version} for Prefab : {this.prefabProject.PrefabName} is published now.");
}

IPrefabFileSystem fileSystem = new PrefabFileSystem(serializer, applicationSettings);
fileSystem.Initialize(this.prefabProject, newVersion);
int indexToInsert = 0;
foreach (var version in this.prefabProject.AvailableVersions.Select(s => s.Version))
{
if (version < newVersion.Version)
{
indexToInsert++;
continue;
}
break;
}

//Deploy the selected version
prefabVersionViewModel.Deploy(this.workspaceManagerFactory);
this.prefabProject.AvailableVersions.Insert(indexToInsert, newVersion);
serializer.Serialize<PrefabProject>(fileSystem.PrefabDescriptionFile, this.prefabProject);

this.prefabProject.AvailableVersions.Add(newVersion);
serializer.Serialize<PrefabProject>(fileSystem.PrefabDescriptionFile, this.prefabProject);
await this.applicationDataManager.AddOrUpdatePrefabAsync(this.prefabProject, new PrefabVersion(prefabVersionViewModel.Version) { IsActive = false });
await this.applicationDataManager.AddOrUpdatePrefabDataFilesAsync(this.prefabProject, new PrefabVersion(prefabVersionViewModel.Version) { IsActive = false });
await this.applicationDataManager.AddOrUpdatePrefabDataFilesAsync(this.prefabProject, newVersion);

await this.applicationDataManager.AddOrUpdatePrefabAsync(this.prefabProject, new PrefabVersion(prefabVersionViewModel.Version) { IsDeployed = true, IsActive = false });
await this.applicationDataManager.AddOrUpdatePrefabDataFilesAsync(this.prefabProject, new PrefabVersion(prefabVersionViewModel.Version) { IsDeployed = true, IsActive = false });
await this.applicationDataManager.AddOrUpdatePrefabDataFilesAsync(this.prefabProject, newVersion);

this.AvailableVersions.Add(new PrefabVersionViewModel(this.prefabProject, newVersion, fileSystem, referenceManagerFactory));
this.AvailableVersions.Insert(indexToInsert, new PrefabVersionViewModel(this.prefabProject, newVersion, fileSystem, referenceManagerFactory));
this.wasPublished = true;

this.wasDeployed = true;
}
}
catch (Exception ex)
{
logger.Error(ex, ex.Message);
}
}

/// <summary>
/// Create a copy of selected version and mark the selected version as published.
/// </summary>
/// <returns></returns>
public async Task PublishAsync(PrefabVersionViewModel prefabVersionViewModel)
{
try
{
if (prefabVersionViewModel.CanPublish)
{
prefabVersionViewModel.Publish(this.workspaceManagerFactory);
await this.applicationDataManager.AddOrUpdatePrefabAsync(this.prefabProject, new PrefabVersion(prefabVersionViewModel.Version) { IsActive = false });
await this.applicationDataManager.AddOrUpdatePrefabDataFilesAsync(this.prefabProject, new PrefabVersion(prefabVersionViewModel.Version) { IsActive = false });
logger.Information($"Version {prefabVersionViewModel.Version} for project : {this.prefabProject.PrefabName} is published now.");
}
}
catch (Exception ex)
{
Expand All @@ -84,7 +118,7 @@ public async Task Deploy(PrefabVersionViewModel prefabVersionViewModel)

public async Task CloseAsync()
{
await this.TryCloseAsync(this.wasDeployed);
await this.TryCloseAsync(this.wasPublished);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
using Pixel.Scripting.Editor.Core.Contracts;
using Pixel.Scripting.Reference.Manager;
using Pixel.Scripting.Reference.Manager.Contracts;
using Serilog;
using System.IO;
using System.Text.RegularExpressions;

namespace Pixel.Automation.AppExplorer.ViewModels.Prefab
{
public class PrefabVersionViewModel : PropertyChangedBase
{
private readonly ILogger logger = Log.ForContext<PrefabVersionViewModel>();

private readonly PrefabProject prefabProject;
private readonly PrefabVersion prefabVersion;
private readonly IPrefabFileSystem fileSystem;
Expand All @@ -23,18 +26,9 @@ public Version Version
set => prefabVersion.Version = value;
}

public bool IsDeployed
public bool IsPublished
{
get => prefabVersion.IsDeployed;
set
{
//can be only set to true when version is not already deployed
if (!prefabVersion.IsDeployed && value)
{
prefabVersion.IsDeployed = value;
}
NotifyOfPropertyChange(() => IsDeployed);
}
get => prefabVersion.IsPublished;
}

/// <summary>
Expand All @@ -51,16 +45,19 @@ public bool IsActive
prefabVersion.IsActive = value;
}
NotifyOfPropertyChange(() => IsActive);
NotifyOfPropertyChange(() => IsPublished);
}
}

public bool CanPublish { get; private set; }


public string PrefabAssembly
{
get => prefabVersion.DataModelAssembly;
private set
{
if (prefabVersion.IsDeployed && !string.IsNullOrEmpty(value))
if (prefabVersion.IsPublished && !string.IsNullOrEmpty(value))
{
prefabVersion.DataModelAssembly = value;
}
Expand All @@ -75,16 +72,28 @@ public PrefabVersionViewModel(PrefabProject prefabProject, PrefabVersion prefabV
this.prefabVersion = Guard.Argument(prefabVersion, nameof(prefabVersion)).NotNull();
this.fileSystem = Guard.Argument(fileSystem).NotNull().Value;
this.referenceManager = new Lazy<ReferenceManager>(() => { return referenceManagerFactory.CreateForPrefabProject(prefabProject, prefabVersion); });
this.CanPublish = !prefabVersion.IsPublished && !prefabVersion.Version.Equals(prefabProject.LatestActiveVersion.Version);
}

public PrefabVersion Clone()
{
////Increment active version for project
PrefabVersion newVersionInfo = new PrefabVersion(new Version(this.prefabVersion.Version.Major + 1, 0, 0, 0))
PrefabVersion newVersionInfo;
if (!this.prefabProject.AvailableVersions.Any(a => a.Version.Major.Equals(this.prefabVersion.Version.Major + 1)))
{
IsActive = true,
IsDeployed = false
};
newVersionInfo = new PrefabVersion(new Version(this.prefabVersion.Version.Major + 1, 0, 0, 0))
{
IsActive = true
};
}
else
{
var versionsWithSameMajor = this.prefabProject.AvailableVersions.Select(s => s.Version).Where(v => v.Major.Equals(this.prefabVersion.Version.Major));
int nextMinor = versionsWithSameMajor.Select(v => v.Minor).Max() + 1;
newVersionInfo = new PrefabVersion(new Version(this.prefabVersion.Version.Major, nextMinor, 0, 0))
{
IsActive = true
};
}

this.fileSystem.Initialize(this.prefabProject, this.prefabVersion);
var currentWorkingDirectory = new DirectoryInfo(this.fileSystem.WorkingDirectory);
Expand All @@ -109,7 +118,7 @@ void CopyAll(DirectoryInfo source, DirectoryInfo target)
CopyAll(diSourceSubDir, nextTargetSubDir);
}
}

logger.Information($"Completed cloning version : {this.prefabVersion} of Prefab: {this.prefabProject.PrefabName}. Cloned version is : {newVersionInfo}");
return newVersionInfo;
}

Expand All @@ -118,45 +127,53 @@ void CopyAll(DirectoryInfo source, DirectoryInfo target)
/// Copy last compiled dll from temp folder to References folder.
/// Set IsDeployed to true and set the assembly name
/// </summary>
public void Deploy(IWorkspaceManagerFactory workspaceFactory)
public void Publish(IWorkspaceManagerFactory workspaceFactory)
{

this.fileSystem.Initialize(this.prefabProject, this.prefabVersion);

string prefabProjectName = this.prefabProject.PrefabName;
ICodeWorkspaceManager workspaceManager = workspaceFactory.CreateCodeWorkspaceManager(this.fileSystem.DataModelDirectory);
workspaceManager.WithAssemblyReferences(this.referenceManager.Value.GetCodeEditorReferences());
workspaceManager.AddProject(prefabProjectName, this.prefabProject.Namespace, Array.Empty<string>());
string[] existingDataModelFiles = Directory.GetFiles(this.fileSystem.DataModelDirectory, "*.cs");
if (existingDataModelFiles.Any())
if(!this.IsPublished)
{
//This will add all the documents to workspace so that they are available during compilation
foreach (var dataModelFile in existingDataModelFiles)
this.fileSystem.Initialize(this.prefabProject, this.prefabVersion);
logger.Information($"Prefab file system has been initialized.");

string prefabProjectName = this.prefabProject.PrefabName;
ICodeWorkspaceManager workspaceManager = workspaceFactory.CreateCodeWorkspaceManager(this.fileSystem.DataModelDirectory);
workspaceManager.WithAssemblyReferences(this.referenceManager.Value.GetCodeEditorReferences());
workspaceManager.AddProject(prefabProjectName, this.prefabProject.Namespace, Array.Empty<string>());
string[] existingDataModelFiles = Directory.GetFiles(this.fileSystem.DataModelDirectory, "*.cs");
if (existingDataModelFiles.Any())
{
string documentName = Path.GetFileName(dataModelFile);
if (!workspaceManager.HasDocument(documentName, prefabProjectName))
//This will add all the documents to workspace so that they are available during compilation
foreach (var dataModelFile in existingDataModelFiles)
{
workspaceManager.AddDocument(documentName, prefabProjectName, File.ReadAllText(dataModelFile));
string documentName = Path.GetFileName(dataModelFile);
if (!workspaceManager.HasDocument(documentName, prefabProjectName))
{
workspaceManager.AddDocument(documentName, prefabProjectName, File.ReadAllText(dataModelFile));
}
}
}
}

string assemblyName = this.prefabProject.Namespace;
using (var compilationResult = workspaceManager.CompileProject(prefabProjectName, assemblyName))
{
compilationResult.SaveAssemblyToDisk(this.fileSystem.ReferencesDirectory);
}
this.IsDeployed = true;
this.IsActive = false;
this.PrefabAssembly = $"{assemblyName}.dll";
string assemblyName = this.prefabProject.Namespace;
using (var compilationResult = workspaceManager.CompileProject(prefabProjectName, assemblyName))
{
compilationResult.SaveAssemblyToDisk(this.fileSystem.ReferencesDirectory);
}
logger.Information($"Workspace prepared and compilation done.");

//Replace the assemly name in the process and template file
UpdateAssemblyReference(this.fileSystem.PrefabFile, assemblyName);
if(File.Exists(this.fileSystem.TemplateFile))
{
UpdateAssemblyReference(this.fileSystem.TemplateFile, assemblyName);
}
this.IsActive = false;
this.CanPublish = false;
this.PrefabAssembly = $"{assemblyName}.dll";

//Replace the assemly name in the process and template file
UpdateAssemblyReference(this.fileSystem.PrefabFile, assemblyName);
if (File.Exists(this.fileSystem.TemplateFile))
{
UpdateAssemblyReference(this.fileSystem.TemplateFile, assemblyName);
}

logger.Information($"Assembly references updated in process and template files.");

NotifyOfPropertyChange(() => CanPublish);
}
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public PrefabVersionSelectorViewModel(IProjectFileSystem projectFileSystem, IPre
{
this.prefabReferences = new PrefabReferences();
}
this.AvailableVersions = prefabProject.DeployedVersions;
this.AvailableVersions = prefabProject.PublishedVersions;
this.CanChangeVersion = !prefabReferences.HasReference(prefabProject);
if(!this.CanChangeVersion)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,28 @@
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Is Deployed">
<DataGridTemplateColumn Header="Is Published ?">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="Deployed" IsChecked="{Binding IsDeployed, Mode=OneWay}" IsEnabled="False" Margin="5,2,5,2" HorizontalAlignment="Center" />
<CheckBox x:Name="IsPublished" IsChecked="{Binding IsPublished, Mode=OneWay}" IsEnabled="False" Margin="5,2,5,2" HorizontalAlignment="Center" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Deploy">
<DataGridTemplateColumn Header="">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Visibility="{Binding IsActive, Converter={StaticResource boolToVisConverter}}">
<Button x:Name="Deploy" Content="DEPLOY" cal:Action.TargetWithoutContext="{Binding Path=DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}"
cal:Message.Attach="[Event Click] = [Action Deploy($dataContext)]" Margin="5,2,5,2" HorizontalAlignment="Center" ToolTip="Deploy this version and create an incremented cloned version" />
</StackPanel>
<Button x:Name="CloneAndPublish" Content="Clone and Publish" cal:Action.TargetWithoutContext="{Binding Path=DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}"
cal:Message.Attach="[Event Click] = [Action CloneAndPublishAsync($dataContext)]" Margin="5,2,5,2" HorizontalAlignment="Center" ToolTip="Create a copy with incremented version and mark this version published." />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="Publish" Content="Publish" IsEnabled="{Binding CanPublish}"
cal:Action.TargetWithoutContext="{Binding Path=DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}"
cal:Message.Attach="[Event Click] = [Action PublishAsync($dataContext)]" Margin="5,2,5,2" HorizontalAlignment="Center"
ToolTip="Mark the version as published. Published versions can be used in automation." />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Expand Down
Loading

0 comments on commit b2aaac5

Please sign in to comment.