Skip to content
Merged
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
4 changes: 2 additions & 2 deletions Sdk/Sdk.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ By integrating this SDK into your build process, you can easily generate install
<PackageReference Include="Nito.AsyncEx.Tasks" Version="5.1.2" />
<PackageReference Include="Skyline.DataMiner.CICD.DMApp.Common" Version="3.0.1" />
<PackageReference Include="Skyline.DataMiner.CICD.Assemblers.Automation" Version="1.1.5" />
<PackageReference Include="Skyline.DataMiner.Core.AppPackageCreator" Version="3.0.0" />
<PackageReference Include="Skyline.DataMiner.Core.ArtifactDownloader" Version="3.0.0" />
<PackageReference Include="Skyline.DataMiner.Core.AppPackageCreator" Version="3.0.2" />
<PackageReference Include="Skyline.DataMiner.Core.ArtifactDownloader" Version="3.0.2" />
<PackageReference Include="Skyline.DataMiner.CICD.FileSystem" Version="1.3.0" />
<PackageReference Include="Skyline.DataMiner.CICD.Parsers.Common" Version="1.1.3" />
</ItemGroup>
Expand Down
85 changes: 76 additions & 9 deletions Sdk/Tasks/CatalogInformation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,22 @@
namespace Skyline.DataMiner.Sdk.Tasks
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Compression;
using System.Linq;
using System.Threading;

using Microsoft.Build.Framework;
using Microsoft.CodeAnalysis;

using NuGet.Packaging;

using Skyline.DataMiner.CICD.FileSystem;
using Skyline.DataMiner.Sdk.Helpers;

using static NuGet.Packaging.PackagingConstants;

using Task = Microsoft.Build.Utilities.Task;

public class CatalogInformation : Task, ICancelableTask
Expand Down Expand Up @@ -61,20 +69,33 @@ public override bool Execute()
return true;
}

string outputDirectory = BuildOutputHandler.GetOutputPath(Output, ProjectDirectory);
string destinationFilePath = fs.Path.Combine(outputDirectory, $"{PackageId}.{PackageVersion}.CatalogInformation.zip");
// make a temporary directory to work in and make changes
string tempDirectory = FileSystem.Instance.Directory.CreateTemporaryDirectory();
try
{
FileSystem.Instance.Directory.CopyRecursive(catalogInformationFolder, tempDirectory);

fs.File.DeleteFile(destinationFilePath);
ZipFile.CreateFromDirectory(catalogInformationFolder, destinationFilePath, CompressionLevel.Optimal, includeBaseDirectory: false);
AddOfficialNotices(fs, tempDirectory);

Log.LogMessage(MessageImportance.High, $"Successfully created zip '{destinationFilePath}'.");
string outputDirectory = BuildOutputHandler.GetOutputPath(Output, ProjectDirectory);
string destinationFilePath = fs.Path.Combine(outputDirectory, $"{PackageId}.{PackageVersion}.CatalogInformation.zip");

if (cancel)
fs.File.DeleteFile(destinationFilePath);
ZipFile.CreateFromDirectory(tempDirectory, destinationFilePath, CompressionLevel.Optimal, includeBaseDirectory: false);

Log.LogMessage(MessageImportance.High, $"Successfully created zip '{destinationFilePath}'.");

if (cancel)
{
return false;
}

return !Log.HasLoggedErrors;
}
finally
{
return false;
FileSystem.Instance.Directory.DeleteDirectory(tempDirectory);
}

return !Log.HasLoggedErrors;
}
catch (Exception e)
{
Expand All @@ -87,5 +108,51 @@ public override bool Execute()
Log.LogMessage(MessageImportance.High, $"Catalog information creation for '{PackageId}' took {timer.ElapsedMilliseconds} ms.");
}
}

private void AddOfficialNotices(IFileSystem fs, string catalogInformationFolder)
{
// example D:\GITHUB\Skyline-QAOps\Skyline-QAOps-Package\PackageContent\CompanionFiles
var pathToPublicDirectoryOnSystem = fs.Path.Combine(@"C:\", "Skyline DataMiner", "Webpages", "Public");
var webpagesPublicDirectory = fs.Path.Combine(ProjectDirectory, "PackageContent", "CompanionFiles", "Skyline DataMiner", "Webpages", "Public");
Comment on lines +115 to +116
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var pathToPublicDirectoryOnSystem = fs.Path.Combine(@"C:\", "Skyline DataMiner", "Webpages", "Public");
var webpagesPublicDirectory = fs.Path.Combine(ProjectDirectory, "PackageContent", "CompanionFiles", "Skyline DataMiner", "Webpages", "Public");
var pathToPublicDirectoryOnSystem = fs.Path.Combine(@"C:\", "Skyline DataMiner", "WebPages", "Public");
var webpagesPublicDirectory = fs.Path.Combine(ProjectDirectory, "PackageContent", "CompanionFiles", "Skyline DataMiner", "WebPages", "Public");

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actual DataMiner folders use "Webpages". I would prefer to keep that matching skyline dataminer directory

if (fs.Directory.Exists(webpagesPublicDirectory))
{
// Get all files and folders directly under webpagesPublicDirectory
var entries = fs.Directory
.EnumerateDirectories(webpagesPublicDirectory)
.Select(path => fs.Path.Combine(pathToPublicDirectoryOnSystem, fs.Path.GetFileName(path)))
.OrderBy(name => name)
.ToList();

entries.AddRange(fs.Directory
.EnumerateFiles(webpagesPublicDirectory)
.Select(path => fs.Path.Combine(pathToPublicDirectoryOnSystem, fs.Path.GetFileName(path)))
.OrderBy(name => name)
.ToList());

if (entries.Count > 0)
{
var readmeFilePath = fs.Path.Combine(catalogInformationFolder, "README.md");
if (fs.File.Exists(readmeFilePath))
{
var noticeLines = new List<string>
{
"",
"",
"> [!IMPORTANT]",
">",
$"> - For DataMiner versions prior to 10.5.10, this package includes files located in `{pathToPublicDirectoryOnSystem}` that are **not automatically deployed** to all Agents in a DataMiner System.",
"> - To ensure proper functionality across the entire cluster, manually copy the following files and folders to the corresponding location on each Agent after installation:",
">",
};

noticeLines.AddRange(entries.Select(e => $"> - `{e}`"));
noticeLines.Add(""); // final newline for clean formatting

var noticeText = string.Join(Environment.NewLine, noticeLines);
fs.File.AppendAllText(readmeFilePath, noticeText);
}
}
}
}
}
}
4 changes: 2 additions & 2 deletions SdkTests/SdkTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
<PackageReference Include="Nito.AsyncEx.Tasks" Version="5.1.2" />
<PackageReference Include="Skyline.DataMiner.CICD.DMApp.Common" Version="3.0.1" />
<PackageReference Include="Skyline.DataMiner.CICD.Assemblers.Automation" Version="1.1.5" />
<PackageReference Include="Skyline.DataMiner.Core.AppPackageCreator" Version="3.0.0" />
<PackageReference Include="Skyline.DataMiner.Core.ArtifactDownloader" Version="3.0.0" />
<PackageReference Include="Skyline.DataMiner.Core.AppPackageCreator" Version="3.0.2" />
<PackageReference Include="Skyline.DataMiner.Core.ArtifactDownloader" Version="3.0.2" />
<PackageReference Include="Skyline.DataMiner.CICD.FileSystem" Version="1.3.0" />
<PackageReference Include="Skyline.DataMiner.CICD.Parsers.Common" Version="1.1.3" />
</ItemGroup>
Expand Down
123 changes: 123 additions & 0 deletions SdkTests/Tasks/DmappCreationTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
namespace SdkTests.Tasks
{
using System.IO.Compression;

using FluentAssertions;

using Microsoft.Build.Framework;
Expand Down Expand Up @@ -95,5 +97,126 @@ public void ExecuteTest_Package6()
FileSystem.Instance.Directory.DeleteDirectory(tempDirectory);
}
}

[TestMethod]
public void ExecuteCatalogInformation_NoNotice()
{
string tempDirectory = FileSystem.Instance.Directory.CreateTemporaryDirectory();
try
{
string projectDir = FileSystem.Instance.Path.Combine(TestHelper.GetTestFilesDirectory(), "Package 6", "My Package");

CatalogInformation info = new CatalogInformation()
{
ProjectDirectory = projectDir,
Output = tempDirectory,
PackageId = "My Package",
PackageVersion = "1.0.0",
BuildEngine = buildEngine.Object
};

string expectedDestinationFilePath = FileSystem.Instance.Path.Combine(
tempDirectory,
BuildOutputHandler.BuildDirectoryName,
$"{info.PackageId}.{info.PackageVersion}.CatalogInformation.zip");

// LOAD original README.md
string expectedReadmePath = FileSystem.Instance.Path.Combine(projectDir, "CatalogInformation", "README.md");
FileSystem.Instance.File.Exists(expectedReadmePath).Should().BeTrue("expected README.md must exist");
string expectedReadmeContent = FileSystem.Instance.File.ReadAllText(expectedReadmePath);

// Act
bool result = info.Execute();
errors.Should().BeEmpty();
result.Should().BeTrue();
FileSystem.Instance.File.Exists(expectedDestinationFilePath).Should().BeTrue();

// UNZIP to a temporary folder
string unzipDir = FileSystem.Instance.Path.Combine(tempDirectory, "unzipped");
ZipFile.ExtractToDirectory(expectedDestinationFilePath, unzipDir);

// FIND README.md inside the unzipped content
string[] readmeFiles = Directory.GetFiles(unzipDir, "README.md", SearchOption.AllDirectories);
readmeFiles.Length.Should().Be(1, "there should be exactly one README.md in the zipped output");
string actualReadmeContent = File.ReadAllText(readmeFiles[0]);

// COMPARE
actualReadmeContent.Should().Be(expectedReadmeContent, "README.md content in zip should match source");
}
finally
{
FileSystem.Instance.Directory.DeleteDirectory(tempDirectory);
}
}


[TestMethod]
public void ExecuteCatalogInformation_WithNotice()
{
string tempDirectory = FileSystem.Instance.Directory.CreateTemporaryDirectory();
try
{
// Arrange
string projectDir = FileSystem.Instance.Path.Combine(TestHelper.GetTestFilesDirectory(), "Package 7", "My Package");

CatalogInformation info = new CatalogInformation()
{
ProjectDirectory = projectDir,
Output = tempDirectory,
PackageId = "My Package",
PackageVersion = "1.0.0",
BuildEngine = buildEngine.Object
};

string expectedDestinationFilePath = FileSystem.Instance.Path.Combine(
tempDirectory,
BuildOutputHandler.BuildDirectoryName,
$"{info.PackageId}.{info.PackageVersion}.CatalogInformation.zip");

// LOAD original README.md
string expectedReadmePath = FileSystem.Instance.Path.Combine(projectDir, "CatalogInformation", "README.md");
FileSystem.Instance.File.Exists(expectedReadmePath).Should().BeTrue("expected README.md must exist");
string expectedReadmeContent = FileSystem.Instance.File.ReadAllText(expectedReadmePath);

// Act
bool result = info.Execute();
errors.Should().BeEmpty();
result.Should().BeTrue();
FileSystem.Instance.File.Exists(expectedDestinationFilePath).Should().BeTrue();

// UNZIP to a temporary folder
string unzipDir = FileSystem.Instance.Path.Combine(tempDirectory, "unzipped");
ZipFile.ExtractToDirectory(expectedDestinationFilePath, unzipDir);

// FIND README.md inside the unzipped content
string[] readmeFiles = Directory.GetFiles(unzipDir, "README.md", SearchOption.AllDirectories);
readmeFiles.Length.Should().Be(1, "there should be exactly one README.md in the zipped output");
string actualReadmeContent = File.ReadAllText(readmeFiles[0]);
string expectedOriginalReadmeContent = FileSystem.Instance.File.ReadAllText(expectedReadmePath);

// Normalize line endings to \n and trim
string Normalize(string input) =>
input.Replace("\r\n", "\n").Replace("\r", "\n").TrimEnd();

string expectedWithNotice = expectedOriginalReadmeContent +
"\n\n" +
"> [!IMPORTANT]\n" +
">\n" +
"> - For DataMiner versions prior to 10.5.10, this package includes files located in `C:\\Skyline DataMiner\\Webpages\\Public` that are **not automatically deployed** to all Agents in a DataMiner System.\n" +
"> - To ensure proper functionality across the entire cluster, manually copy the following files and folders to the corresponding location on each Agent after installation:\n" +
">\n" +
"> - `C:\\Skyline DataMiner\\Webpages\\Public\\MyDirectory`\n" +
"> - `C:\\Skyline DataMiner\\Webpages\\Public\\MyFile1.txt`\n" +
"> - `C:\\Skyline DataMiner\\Webpages\\Public\\XMLFile1.xml`";


Normalize(actualReadmeContent)
.Should().Be(Normalize(expectedWithNotice), "README.md content in zip should match source with a notice appended to it.");
}
finally
{
FileSystem.Instance.Directory.DeleteDirectory(tempDirectory);
}
}
}
}
11 changes: 11 additions & 0 deletions SdkTests/Test Files/Package 7/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
root = true

[*]
indent_style = tab
indent_size = 4
tab_width = 4
end_of_line = crlf
trim_trailing_whitespace = true

[*.cs]
dotnet_sort_system_directives_first = true
24 changes: 24 additions & 0 deletions SdkTests/Test Files/Package 7/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType>
<CodeAnalysisRuleSet>..\Internal\Code Analysis\qaction-debug.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<CodeAnalysisRuleSet>..\Internal\Code Analysis\qaction-release.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="..\Internal\Code Analysis\stylecop.json">
<Link>Properties\stylecop.json</Link>
</AdditionalFiles>
<Content Include="..\.editorconfig">
<Link>Properties\.editorconfig</Link>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
Loading
Loading