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 VersionAssemblyName to package manifest #14046

Merged
merged 10 commits into from
May 30, 2023
33 changes: 33 additions & 0 deletions src/Umbraco.Core/Extensions/AssemblyExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.

using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Umbraco.Cms.Core.Semver;

namespace Umbraco.Extensions;

Expand Down Expand Up @@ -104,4 +106,35 @@ public static bool IsGlobalAsaxAssembly(this Assembly assembly) =>

return null;
}

/// <summary>
/// Gets the assembly informational version for the specified <paramref name="assembly" />.
/// </summary>
/// <param name="assembly">The assembly.</param>
/// <param name="version">The assembly version.</param>
/// <returns>
/// <c>true</c> if the assembly information version is retrieved; otherwise, <c>false</c>.
/// </returns>
public static bool TryGetInformationalVersion(this Assembly assembly, [NotNullWhen(true)] out string? version)
{
AssemblyInformationalVersionAttribute? assemblyInformationalVersionAttribute = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
if (assemblyInformationalVersionAttribute is not null &&
SemVersion.TryParse(assemblyInformationalVersionAttribute.InformationalVersion, out SemVersion? semVersion))
{
version = semVersion.ToSemanticStringWithoutBuild();
return true;
}
else
{
AssemblyName assemblyName = assembly.GetName();
if (assemblyName.Version is not null)
{
version = assemblyName.Version.ToString(3);
return true;
}
}

version = null;
return false;
}
}
2 changes: 2 additions & 0 deletions src/Umbraco.Core/IO/IOHelperExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using Umbraco.Cms.Core.IO;

namespace Umbraco.Extensions;
Expand All @@ -11,6 +12,7 @@ public static class IOHelperExtensions
/// <param name="ioHelper"></param>
/// <param name="path"></param>
/// <returns></returns>
[return: NotNullIfNotNull("path")]
public static string? ResolveRelativeOrVirtualUrl(this IIOHelper ioHelper, string? path)
{
if (string.IsNullOrWhiteSpace(path))
Expand Down
88 changes: 71 additions & 17 deletions src/Umbraco.Core/Manifest/PackageManifest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@
namespace Umbraco.Cms.Core.Manifest;

/// <summary>
/// Represents the content of a package manifest.
/// Represents the content of a package manifest.
/// </summary>
[DataContract]
public class PackageManifest
{
private string? _packageName;

/// <summary>
/// An optional package name. If not specified then the directory name is used.
/// Gets or sets the name of the package. If not specified, uses the directory name instead.
/// </summary>
/// <value>
/// The name of the package.
/// </value>
[DataMember(Name = "name")]
public string? PackageName
{
Expand All @@ -35,81 +38,132 @@ public string? PackageName
set => _packageName = value;
}

/// <summary>
/// Gets or sets the package view.
/// </summary>
/// <value>
/// The package view.
/// </value>
[DataMember(Name = "packageView")]
public string? PackageView { get; set; }

/// <summary>
/// Gets the source path of the manifest.
/// Gets or sets the source path of the manifest.
/// </summary>
/// <value>
/// The source path.
/// </value>
/// <remarks>
/// <para>
/// Gets the full absolute file path of the manifest,
/// using system directory separators.
/// </para>
/// Gets the full/absolute file path of the manifest, using system directory separators.
/// </remarks>
[IgnoreDataMember]
public string Source { get; set; } = null!;

/// <summary>
/// Gets or sets the version of the package
/// Gets or sets the version of the package.
/// </summary>
/// <value>
/// The version of the package.
/// </value>
[DataMember(Name = "version")]
public string Version { get; set; } = string.Empty;

/// <summary>
/// Gets or sets a value indicating whether telemetry is allowed
/// Gets or sets the assembly name to get the package version from.
/// </summary>
/// <value>
/// The assembly name to get the package version from.
/// </value>
[DataMember(Name = "versionAssemblyName")]
public string? VersionAssemblyName { get; set; }

/// <summary>
/// Gets or sets a value indicating whether telemetry is allowed.
/// </summary>
/// <value>
/// <c>true</c> if package telemetry is allowed; otherwise, <c>false</c>.
/// </value>
[DataMember(Name = "allowPackageTelemetry")]
public bool AllowPackageTelemetry { get; set; } = true;

/// <summary>
/// Gets or sets the bundle options.
/// </summary>
/// <value>
/// The bundle options.
/// </value>
[DataMember(Name = "bundleOptions")]
public BundleOptions BundleOptions { get; set; }

/// <summary>
/// Gets or sets the scripts listed in the manifest.
/// Gets or sets the scripts listed in the manifest.
/// </summary>
/// <value>
/// The scripts.
/// </value>
[DataMember(Name = "javascript")]
public string[] Scripts { get; set; } = Array.Empty<string>();

/// <summary>
/// Gets or sets the stylesheets listed in the manifest.
/// Gets or sets the stylesheets listed in the manifest.
/// </summary>
/// <value>
/// The stylesheets.
/// </value>
[DataMember(Name = "css")]
public string[] Stylesheets { get; set; } = Array.Empty<string>();

/// <summary>
/// Gets or sets the property editors listed in the manifest.
/// Gets or sets the property editors listed in the manifest.
/// </summary>
/// <value>
/// The property editors.
/// </value>
[DataMember(Name = "propertyEditors")]
public IDataEditor[] PropertyEditors { get; set; } = Array.Empty<IDataEditor>();

/// <summary>
/// Gets or sets the parameter editors listed in the manifest.
/// Gets or sets the parameter editors listed in the manifest.
/// </summary>
/// <value>
/// The parameter editors.
/// </value>
[DataMember(Name = "parameterEditors")]
public IDataEditor[] ParameterEditors { get; set; } = Array.Empty<IDataEditor>();

/// <summary>
/// Gets or sets the grid editors listed in the manifest.
/// Gets or sets the grid editors listed in the manifest.
/// </summary>
/// <value>
/// The grid editors.
/// </value>
[DataMember(Name = "gridEditors")]
public GridEditor[] GridEditors { get; set; } = Array.Empty<GridEditor>();

/// <summary>
/// Gets or sets the content apps listed in the manifest.
/// Gets or sets the content apps listed in the manifest.
/// </summary>
/// <value>
/// The content apps.
/// </value>
[DataMember(Name = "contentApps")]
public ManifestContentAppDefinition[] ContentApps { get; set; } = Array.Empty<ManifestContentAppDefinition>();

/// <summary>
/// Gets or sets the dashboards listed in the manifest.
/// Gets or sets the dashboards listed in the manifest.
/// </summary>
/// <value>
/// The dashboards.
/// </value>
[DataMember(Name = "dashboards")]
public ManifestDashboard[] Dashboards { get; set; } = Array.Empty<ManifestDashboard>();

/// <summary>
/// Gets or sets the sections listed in the manifest.
/// Gets or sets the sections listed in the manifest.
/// </summary>
/// <value>
/// The sections.
/// </value>
[DataMember(Name = "sections")]
public ManifestSection[] Sections { get; set; } = Array.Empty<ManifestSection>();
}
5 changes: 3 additions & 2 deletions src/Umbraco.Core/Semver/Semver.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Text.RegularExpressions;
using System.Text.RegularExpressions;
using System.Diagnostics.CodeAnalysis;
#if !NETSTANDARD
using System.Globalization;
using System.Runtime.Serialization;
Expand Down Expand Up @@ -195,7 +196,7 @@ public static SemVersion Parse(string version, bool strict = false)
/// </param>
/// <param name="strict">If set to <c>true</c> minor and patch version are required, else they default to 0.</param>
/// <returns><c>False</c> when a invalid version string is passed, otherwise <c>true</c>.</returns>
public static bool TryParse(string version, out SemVersion? semver, bool strict = false)
public static bool TryParse(string version, [NotNullWhen(true)] out SemVersion? semver, bool strict = false)
{
try
{
Expand Down
47 changes: 35 additions & 12 deletions src/Umbraco.Infrastructure/Manifest/ManifestParser.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
Expand All @@ -17,7 +20,7 @@
namespace Umbraco.Cms.Core.Manifest;

/// <summary>
/// Parses the Main.js file and replaces all tokens accordingly.
/// Parses the Main.js file and replaces all tokens accordingly.
/// </summary>
public class ManifestParser : IManifestParser
{
Expand All @@ -39,7 +42,7 @@ public class ManifestParser : IManifestParser
private string _path = null!;

/// <summary>
/// Initializes a new instance of the <see cref="ManifestParser" /> class.
/// Initializes a new instance of the <see cref="ManifestParser" /> class.
/// </summary>
public ManifestParser(
AppCaches appCaches,
Expand Down Expand Up @@ -163,31 +166,35 @@ public IEnumerable<PackageManifest> GetManifests()
/// </summary>
public PackageManifest ParseManifest(string text)
{
if (text == null)
{
throw new ArgumentNullException(nameof(text));
}
ArgumentNullException.ThrowIfNull(text);

if (string.IsNullOrWhiteSpace(text))
{
throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(text));
}

PackageManifest? manifest = JsonConvert.DeserializeObject<PackageManifest>(
PackageManifest manifest = JsonConvert.DeserializeObject<PackageManifest>(
text,
new DataEditorConverter(_dataValueEditorFactory, _ioHelper, _localizedTextService, _shortStringHelper, _jsonSerializer),
new ValueValidatorConverter(_validators),
new DashboardAccessRuleConverter());
new DashboardAccessRuleConverter())!;

if (string.IsNullOrEmpty(manifest.Version) &&
!string.IsNullOrEmpty(manifest.VersionAssemblyName) &&
TryGetAssemblyInformationalVersion(manifest.VersionAssemblyName, out string? version))
{
manifest.Version = version;
}

// scripts and stylesheets are raw string, must process here
for (var i = 0; i < manifest!.Scripts.Length; i++)
for (var i = 0; i < manifest.Scripts.Length; i++)
{
manifest.Scripts[i] = _ioHelper.ResolveRelativeOrVirtualUrl(manifest.Scripts[i])!;
manifest.Scripts[i] = _ioHelper.ResolveRelativeOrVirtualUrl(manifest.Scripts[i]);
}

for (var i = 0; i < manifest.Stylesheets.Length; i++)
{
manifest.Stylesheets[i] = _ioHelper.ResolveRelativeOrVirtualUrl(manifest.Stylesheets[i])!;
manifest.Stylesheets[i] = _ioHelper.ResolveRelativeOrVirtualUrl(manifest.Stylesheets[i]);
}

foreach (ManifestContentAppDefinition contentApp in manifest.ContentApps)
Expand All @@ -197,7 +204,7 @@ public PackageManifest ParseManifest(string text)

foreach (ManifestDashboard dashboard in manifest.Dashboards)
{
dashboard.View = _ioHelper.ResolveRelativeOrVirtualUrl(dashboard.View)!;
dashboard.View = _ioHelper.ResolveRelativeOrVirtualUrl(dashboard.View);
}

foreach (GridEditor gridEditor in manifest.GridEditors)
Expand All @@ -217,6 +224,22 @@ public PackageManifest ParseManifest(string text)
return manifest;
}

private bool TryGetAssemblyInformationalVersion(string name, [NotNullWhen(true)] out string? version)
{
foreach (Assembly assembly in AssemblyLoadContext.Default.Assemblies)
{
AssemblyName assemblyName = assembly.GetName();
if (string.Equals(assemblyName.Name, name, StringComparison.OrdinalIgnoreCase) &&
assembly.TryGetInformationalVersion(out version))
{
return true;
}
}

version = null;
return false;
}

/// <summary>
/// Merges all manifests into one.
/// </summary>
Expand Down
Loading