From 22dbe857bf5b77a333551cfaf8d549e65965c3aa Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 6 May 2026 11:31:49 -0500 Subject: [PATCH 1/4] Replace generated CGManifest.json with a static one The Component Governance (CG) Azure DevOps build task auto-detects NuGet packages by scanning `.csproj` files on the build machine, making the 287-line `Step_GenerateCGManifest` in xaprepare redundant. Only git submodules need manual registration via `CGManifest.json`, since CG cannot auto-detect them. This commit replaces the dynamic generation with a static `CGManifest.json` at the repo root containing only `type: git` entries for each submodule. Reference: - https://docs.opensource.microsoft.com/tools/cg/component-detection/cgmanifest.md - https://docs.opensource.microsoft.com/tools/cg/component-detection/build-task.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CGManifest.json | 87 +++++ .../xaprepare/Scenarios/Scenario_Standard.cs | 1 - .../Steps/Step_GenerateCGManifest.cs | 336 ------------------ 3 files changed, 87 insertions(+), 337 deletions(-) create mode 100644 CGManifest.json delete mode 100644 build-tools/xaprepare/xaprepare/Steps/Step_GenerateCGManifest.cs diff --git a/CGManifest.json b/CGManifest.json new file mode 100644 index 00000000000..21385334e4a --- /dev/null +++ b/CGManifest.json @@ -0,0 +1,87 @@ +{ + "$schema": "https://json.schemastore.org/component-detection-manifest.json", + "version": 1, + "registrations": [ + { + "component": { + "type": "git", + "git": { + "repositoryUrl": "https://github.com/dotnet/android-api-docs", + "commitHash": "d382c5bd406432083901e51a4e87cd677b8759d8" + } + } + }, + { + "component": { + "type": "git", + "git": { + "repositoryUrl": "https://github.com/chys87/constexpr-xxh3", + "commitHash": "aebcee75c8b6c2458fa8ae151754a8ba833bd697" + } + } + }, + { + "component": { + "type": "git", + "git": { + "repositoryUrl": "https://github.com/Cyan4973/xxHash", + "commitHash": "bbb27a5efb85b92a0486cf361a8635715a53f6ba" + } + } + }, + { + "component": { + "type": "git", + "git": { + "repositoryUrl": "https://github.com/dotnet/android-tools", + "commitHash": "2b9c8c2f03e18d481da8586586783cd1a92a6a3e" + } + } + }, + { + "component": { + "type": "git", + "git": { + "repositoryUrl": "https://github.com/dotnet/java-interop", + "commitHash": "4abc52e338643b747d59cf3880669917989d1b5e" + } + } + }, + { + "component": { + "type": "git", + "git": { + "repositoryUrl": "https://github.com/dotnet/lz4", + "commitHash": "ebb370ca83af193212df4dcbadcc5d87bc0de2f0" + } + } + }, + { + "component": { + "type": "git", + "git": { + "repositoryUrl": "https://github.com/libunwind/libunwind", + "commitHash": "e97c9ef82f8b48d0c7f713be4fa7b15e634d76b8" + } + } + }, + { + "component": { + "type": "git", + "git": { + "repositoryUrl": "https://github.com/mono/debugger-libs", + "commitHash": "e7fbb713d156d11193ed404783ad6fe9c4042a6d" + } + } + }, + { + "component": { + "type": "git", + "git": { + "repositoryUrl": "https://github.com/xamarin/robin-map", + "commitHash": "d37a41003bfbc7e12e34601f93c18ca2ff6d7c07" + } + } + } + ] +} diff --git a/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs b/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs index 35946068248..247b2981b31 100644 --- a/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs +++ b/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs @@ -24,7 +24,6 @@ protected override void AddSteps (Context context) Steps.Add (new Step_GenerateFiles (atBuildStart: true)); Steps.Add (new Step_PrepareProps ()); Steps.Add (new Step_InstallGNUBinutils ()); - Steps.Add (new Step_GenerateCGManifest ()); Steps.Add (new Step_Get_Android_BuildTools ()); } diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateCGManifest.cs b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateCGManifest.cs deleted file mode 100644 index 3074c672f22..00000000000 --- a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateCGManifest.cs +++ /dev/null @@ -1,336 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using System.Xml.Linq; - -namespace Xamarin.Android.Prepare -{ - partial class Step_GenerateCGManifest : Step - { - static readonly HashSet DevelopmentDependencies = new HashSet (StringComparer.OrdinalIgnoreCase) { - "7-Zip.CommandLine", - "Kajabity.Tools.Java", - "Mono.Linq.Expressions", - "mono/debugger-libs", - "Newtonsoft.Json", - "System.CommandLine", - "Xamarin.Forms", - "xunit", - "xunit.abstractions", - "xunit.analyzers", - "xunit.assert", - "xunit.core", - "xunit.extensibility.core", - "xunit.extensibility.execution", - "xunit.runner.utility", - - // ??? - "Microsoft.Build", - "Microsoft.Build.Framework", - "Microsoft.Build.Tasks.Core", - "Microsoft.Build.Utilities.Core", - "Microsoft.VisualStudio.CoreUtility", - "Microsoft.VisualStudio.Imaging", - "Microsoft.VisualStudio.OLE.Interop", - "Microsoft.VisualStudio.Shell.15.0", - "Microsoft.VisualStudio.Shell.Framework", - "Microsoft.VisualStudio.Shell.Interop", - "Microsoft.VisualStudio.Shell.Interop.8.0", - "Microsoft.VisualStudio.Shell.Interop.9.0", - "Microsoft.VisualStudio.TextManager.Interop", - "Microsoft.VisualStudio.TextManager.Interop.8.0", - "Microsoft.VisualStudio.Threading", - "Microsoft.VisualStudio.Utilities", - "Microsoft.VisualStudio.Validation", - "Microsoft.VSSDK.BuildTools", - }; - - public Step_GenerateCGManifest () - : base ("Generate CGManifest.json") - {} - - protected override async Task Execute (Context context) - { - var nugets = MSBuildPackageReferenceInfo.GetPackageReferences (); - var git = new GitRunner (context); - var gitSubmoduleInfo = await git.ConfigList (new[]{"--blob", "HEAD:.gitmodules"}); - var gitSubmoduleStatus = await git.SubmoduleStatus (); - var gitSubmodules = GitSubmoduleInfo.GetGitSubmodules (gitSubmoduleInfo, gitSubmoduleStatus); - - var cgManifestEntries = ((IEnumerable) nugets).Concat (gitSubmodules) - .OrderBy (e => e.Name); - - var jsonPath = Path.Combine (Configurables.Paths.BuildBinDir, "CGManifest.json"); - using var json = File.CreateText (jsonPath); - - json.WriteLine ("{"); - json.WriteLine (" \"$schema\": \"https://json.schemastore.org/component-detection-manifest.json\","); - json.WriteLine (" \"version\": 1,"); - json.WriteLine (" \"registrations\": ["); - - var properties = new Dictionary (); - - bool first = true; - - foreach (var entry in cgManifestEntries) { - if (first) { - first = false; - } else { - json.WriteLine (","); - } - - WriteComponent (json, entry, properties); - } - - json.WriteLine (); - json.WriteLine (" ]"); - json.WriteLine ("}"); - - return true; - } - - void WriteComponent (TextWriter json, CGManifestEntry entry, Dictionary properties) - { - string dev = DevelopmentDependencies.Contains (entry.Name) - ? "true" - : "false"; - - properties.Clear (); - entry.FillComponentProperties (properties); - - json.WriteLine ($" {{"); - json.WriteLine ($" \"component\": {{"); - json.WriteLine ($" \"type\": \"{entry.Type.ToLowerInvariant ()}\","); - json.WriteLine ($" \"{entry.Type}\": {{"); - bool firstProp = true; - foreach (var key in properties.Keys.OrderBy (p => p, StringComparer.OrdinalIgnoreCase)) { - var value = properties [key]; - if (firstProp) { - firstProp = false; - } else { - json.WriteLine (","); - } - json.Write ($" \"{key}\": \"{value}\""); - } - json.WriteLine (); - json.WriteLine ($" }}"); - json.WriteLine ($" }},"); - json.WriteLine ($" \"developmentDependency\":{dev}"); - json.Write ($" }}"); - } - } - - abstract class CGManifestEntry { - - public abstract string Name {get;} - public abstract string Type {get;} - - public abstract void FillComponentProperties (Dictionary properties); - - protected CGManifestEntry () - { - } - } - - sealed class GitSubmoduleInfo : CGManifestEntry { - - public override string Name { - get { - const string github = "github.com/"; - int i = RepositoryUrl.IndexOf (github, StringComparison.OrdinalIgnoreCase); - if (i >= 0) - return RepositoryUrl.Substring (i + github.Length); - return RepositoryUrl; - } - } - - public override string Type => "git"; - - public string RepositoryUrl {get; private set;} = String.Empty; - public string CommitHash {get; private set;} = String.Empty; - public string LocalPath {get; private set;} = String.Empty; - - GitSubmoduleInfo () - { - } - - public override void FillComponentProperties (Dictionary properties) - { - properties ["repositoryUrl"] = RepositoryUrl; - properties ["commitHash"] = CommitHash; - } - - const string Submodule = "submodule.external/"; - - public static IEnumerable GetGitSubmodules (List? config, List? submoduleStatus) - { - if (config == null) { - yield return CreateEmptySubmoduleInfo (); - } - - string? entryId = null; - string? path = null; - string? url = null; - - foreach (var line in config!) { - if (!line.StartsWith (Submodule, StringComparison.Ordinal)) - continue; - - string? id = GetSubmoduleId (line); - if (id != entryId) { - if (url != null && path != null) - yield return CreateSubmoduleInfo (url, path); - - entryId = id; - path = null; - url = null; - } - - const string Path = ".path="; - const string Url = ".url="; - const string Git = ".git"; - - int pathIndex = line.IndexOf (Path, StringComparison.Ordinal); - if (pathIndex > 0) { - path = line.Substring (pathIndex + Path.Length); - continue; - } - - int urlIndex = line.IndexOf (Url, StringComparison.Ordinal); - if (urlIndex > 0) { - int start = urlIndex + Url.Length; - int count = line.Length - start; - if (line.EndsWith (Git, StringComparison.Ordinal)) - count -= Git.Length; - url = line.Substring (start, count); - continue; - } - } - - if (url != null && path != null) - yield return CreateSubmoduleInfo (url, path); - - GitSubmoduleInfo CreateSubmoduleInfo (string url, string path) - { - if (submoduleStatus == null) { - return CreateEmptySubmoduleInfo (); - } - - string? hash = null; - foreach (var e in submoduleStatus) { - int pi = e.IndexOf (path, StringComparison.OrdinalIgnoreCase); - if (pi < 1 || e [pi - 1] != ' ') - continue; - hash = e.Substring (1, pi - 2); - break; - } - return new GitSubmoduleInfo () { - LocalPath = path, - RepositoryUrl = url, - CommitHash = hash ?? String.Empty, - }; - } - - GitSubmoduleInfo CreateEmptySubmoduleInfo () - { - return new GitSubmoduleInfo { - RepositoryUrl = String.Empty, - CommitHash = String.Empty, - }; - } - } - - static string? GetSubmoduleId (string line) - { - int eq = line.IndexOf ('='); - if (eq < 0) - return null; - int lastDot = line.LastIndexOf ('.', eq); - return line.Substring (Submodule.Length, lastDot - Submodule.Length); - } - } - - sealed class MSBuildPackageReferenceInfo : CGManifestEntry { - - string name; - - public override string Name => name; - public override string Type => "nuget"; - - public string Version {get; private set;} - - MSBuildPackageReferenceInfo (string name, string version) - { - this.name = name; - Version = version; - } - - public override void FillComponentProperties (Dictionary properties) - { - properties ["name"] = Name; - properties ["version"] = Version; - } - - static readonly XNamespace MSBuildXmlns = XNamespace.Get ("http://schemas.microsoft.com/developer/msbuild/2003"); - - public static IEnumerable GetPackageReferences () - { - var files = Directory.EnumerateFiles (BuildPaths.XamarinAndroidSourceRoot, "*.csproj", SearchOption.AllDirectories) - .Concat (Directory.EnumerateFiles (BuildPaths.XamarinAndroidSourceRoot, "*.targets", SearchOption.AllDirectories)) - .Concat (Directory.EnumerateFiles (BuildPaths.XamarinAndroidSourceRoot, "*.projitems", SearchOption.AllDirectories)) - ; - var packages = new Dictionary> (); - var versions = new Dictionary> (); - foreach (var file in files) { - var contents = File.ReadAllText (file); - if (contents.IndexOf ("PackageReference", StringComparison.Ordinal) < 0 || - contents.IndexOf ("PropertyGroup", StringComparison.Ordinal) < 0) - continue; - var proj = XDocument.Parse (contents); - var packageReferences = proj.Elements (MSBuildXmlns + "Project") - .Elements (MSBuildXmlns + "ItemGroup") - .Elements (MSBuildXmlns + "PackageReference"); - foreach (var packageReference in packageReferences) { - var name = (string?) packageReference.Attribute ("Include"); - var version = (string?) packageReference.Attribute ("Version") ?? - packageReference.Element (MSBuildXmlns+"Version")?.Value; - if (name == null || version == null) - continue; - if (!packages.TryGetValue (name, out var v)) { - packages.Add (name, v = new HashSet ()); - } - v.Add (version); - } - var properties = proj.Elements (MSBuildXmlns + "Project") - .Elements (MSBuildXmlns + "PropertyGroup") - .Elements (); - foreach (var property in properties) { - var name = $"$({property.Name.LocalName})"; - if (!property.Name.LocalName.EndsWith ("Version", StringComparison.Ordinal)) - continue; - if (!versions.TryGetValue (name, out var v)) { - versions.Add (name, v = new HashSet ()); - } - v.Add (property.Value.Trim ()); - } - } - - foreach (var package in packages) { - string name = package.Key; - foreach (var version in package.Value) { - if (version.Length > 0 && version [0] != '$') { - yield return new MSBuildPackageReferenceInfo (name, version); - continue; - } - if (!versions.TryGetValue (version, out var propertyVersions)) - continue; - foreach (var propertyVersion in propertyVersions) { - yield return new MSBuildPackageReferenceInfo (name, propertyVersion); - } - } - } - } - } -} From dbe86213259a92d60808df8503bcfaa52ce2a7d1 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 6 May 2026 11:34:04 -0500 Subject: [PATCH 2/4] Rename CGManifest.json to cgmanifest.json Match the canonical lowercase filename used by the CG docs and other dotnet repos (machinelearning, android-libraries, test-templates). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CGManifest.json => cgmanifest.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename CGManifest.json => cgmanifest.json (100%) diff --git a/CGManifest.json b/cgmanifest.json similarity index 100% rename from CGManifest.json rename to cgmanifest.json From b234d68869227ab2f260856ef77332ee1894f16f Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 6 May 2026 11:37:46 -0500 Subject: [PATCH 3/4] Remove NuGet scanning from Step_GenerateCGManifest The Component Governance (CG) Azure DevOps build task auto-detects NuGet packages by scanning `.csproj` files on the build machine, making the NuGet scanning in `Step_GenerateCGManifest` redundant. Strip the step down to only generate `cgmanifest.json` entries for git submodules, which CG cannot auto-detect. This removes the `MSBuildPackageReferenceInfo` class, `CGManifestEntry` abstraction, `DevelopmentDependencies` list, and all NuGet/MSBuild XML scanning code (-231 lines). The file continues to be generated at build time (not checked in) so that commit hashes stay current when dependabot bumps submodules. Reference: - https://docs.opensource.microsoft.com/tools/cg/component-detection/cgmanifest.md - https://docs.opensource.microsoft.com/tools/cg/component-detection/build-task.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../xaprepare/Scenarios/Scenario_Standard.cs | 1 + .../Steps/Step_GenerateCGManifest.cs | 148 ++++++++++++++++++ cgmanifest.json | 87 ---------- 3 files changed, 149 insertions(+), 87 deletions(-) create mode 100644 build-tools/xaprepare/xaprepare/Steps/Step_GenerateCGManifest.cs delete mode 100644 cgmanifest.json diff --git a/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs b/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs index 247b2981b31..35946068248 100644 --- a/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs +++ b/build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs @@ -24,6 +24,7 @@ protected override void AddSteps (Context context) Steps.Add (new Step_GenerateFiles (atBuildStart: true)); Steps.Add (new Step_PrepareProps ()); Steps.Add (new Step_InstallGNUBinutils ()); + Steps.Add (new Step_GenerateCGManifest ()); Steps.Add (new Step_Get_Android_BuildTools ()); } diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateCGManifest.cs b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateCGManifest.cs new file mode 100644 index 00000000000..7ee187863e5 --- /dev/null +++ b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateCGManifest.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace Xamarin.Android.Prepare +{ + partial class Step_GenerateCGManifest : Step + { + public Step_GenerateCGManifest () + : base ("Generate cgmanifest.json") + {} + + protected override async Task Execute (Context context) + { + var git = new GitRunner (context); + var gitSubmoduleInfo = await git.ConfigList (new[]{"--blob", "HEAD:.gitmodules"}); + var gitSubmoduleStatus = await git.SubmoduleStatus (); + var gitSubmodules = GitSubmoduleInfo.GetGitSubmodules (gitSubmoduleInfo, gitSubmoduleStatus) + .OrderBy (e => e.RepositoryUrl, StringComparer.OrdinalIgnoreCase); + + var jsonPath = Path.Combine (Configurables.Paths.BuildBinDir, "cgmanifest.json"); + using var json = File.CreateText (jsonPath); + + json.WriteLine ("{"); + json.WriteLine (" \"$schema\": \"https://json.schemastore.org/component-detection-manifest.json\","); + json.WriteLine (" \"version\": 1,"); + json.WriteLine (" \"registrations\": ["); + + bool first = true; + + foreach (var entry in gitSubmodules) { + if (first) { + first = false; + } else { + json.WriteLine (","); + } + + json.WriteLine ($" {{"); + json.WriteLine ($" \"component\": {{"); + json.WriteLine ($" \"type\": \"git\","); + json.WriteLine ($" \"git\": {{"); + json.WriteLine ($" \"commitHash\": \"{entry.CommitHash}\","); + json.WriteLine ($" \"repositoryUrl\": \"{entry.RepositoryUrl}\""); + json.WriteLine ($" }}"); + json.WriteLine ($" }}"); + json.Write ($" }}"); + } + + json.WriteLine (); + json.WriteLine (" ]"); + json.WriteLine ("}"); + + return true; + } + } + + sealed class GitSubmoduleInfo + { + public string RepositoryUrl { get; private set; } = String.Empty; + public string CommitHash { get; private set; } = String.Empty; + + GitSubmoduleInfo () + { + } + + const string Submodule = "submodule.external/"; + + public static IEnumerable GetGitSubmodules (List? config, List? submoduleStatus) + { + if (config == null) { + yield break; + } + + string? entryId = null; + string? path = null; + string? url = null; + + foreach (var line in config) { + if (!line.StartsWith (Submodule, StringComparison.Ordinal)) + continue; + + string? id = GetSubmoduleId (line); + if (id != entryId) { + if (url != null && path != null) + yield return CreateSubmoduleInfo (url, path, submoduleStatus); + + entryId = id; + path = null; + url = null; + } + + const string Path = ".path="; + const string Url = ".url="; + const string Git = ".git"; + + int pathIndex = line.IndexOf (Path, StringComparison.Ordinal); + if (pathIndex > 0) { + path = line.Substring (pathIndex + Path.Length); + continue; + } + + int urlIndex = line.IndexOf (Url, StringComparison.Ordinal); + if (urlIndex > 0) { + int start = urlIndex + Url.Length; + int count = line.Length - start; + if (line.EndsWith (Git, StringComparison.Ordinal)) + count -= Git.Length; + url = line.Substring (start, count); + continue; + } + } + + if (url != null && path != null) + yield return CreateSubmoduleInfo (url, path, submoduleStatus); + } + + static GitSubmoduleInfo CreateSubmoduleInfo (string url, string path, List? submoduleStatus) + { + string commitHash = String.Empty; + + if (submoduleStatus != null) { + foreach (var e in submoduleStatus) { + int pi = e.IndexOf (path, StringComparison.OrdinalIgnoreCase); + if (pi < 1 || e [pi - 1] != ' ') + continue; + commitHash = e.Substring (1, pi - 2); + break; + } + } + + return new GitSubmoduleInfo { + RepositoryUrl = url, + CommitHash = commitHash, + }; + } + + static string? GetSubmoduleId (string line) + { + int eq = line.IndexOf ('='); + if (eq < 0) + return null; + int lastDot = line.LastIndexOf ('.', eq); + return line.Substring (Submodule.Length, lastDot - Submodule.Length); + } + } +} diff --git a/cgmanifest.json b/cgmanifest.json deleted file mode 100644 index 21385334e4a..00000000000 --- a/cgmanifest.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/component-detection-manifest.json", - "version": 1, - "registrations": [ - { - "component": { - "type": "git", - "git": { - "repositoryUrl": "https://github.com/dotnet/android-api-docs", - "commitHash": "d382c5bd406432083901e51a4e87cd677b8759d8" - } - } - }, - { - "component": { - "type": "git", - "git": { - "repositoryUrl": "https://github.com/chys87/constexpr-xxh3", - "commitHash": "aebcee75c8b6c2458fa8ae151754a8ba833bd697" - } - } - }, - { - "component": { - "type": "git", - "git": { - "repositoryUrl": "https://github.com/Cyan4973/xxHash", - "commitHash": "bbb27a5efb85b92a0486cf361a8635715a53f6ba" - } - } - }, - { - "component": { - "type": "git", - "git": { - "repositoryUrl": "https://github.com/dotnet/android-tools", - "commitHash": "2b9c8c2f03e18d481da8586586783cd1a92a6a3e" - } - } - }, - { - "component": { - "type": "git", - "git": { - "repositoryUrl": "https://github.com/dotnet/java-interop", - "commitHash": "4abc52e338643b747d59cf3880669917989d1b5e" - } - } - }, - { - "component": { - "type": "git", - "git": { - "repositoryUrl": "https://github.com/dotnet/lz4", - "commitHash": "ebb370ca83af193212df4dcbadcc5d87bc0de2f0" - } - } - }, - { - "component": { - "type": "git", - "git": { - "repositoryUrl": "https://github.com/libunwind/libunwind", - "commitHash": "e97c9ef82f8b48d0c7f713be4fa7b15e634d76b8" - } - } - }, - { - "component": { - "type": "git", - "git": { - "repositoryUrl": "https://github.com/mono/debugger-libs", - "commitHash": "e7fbb713d156d11193ed404783ad6fe9c4042a6d" - } - } - }, - { - "component": { - "type": "git", - "git": { - "repositoryUrl": "https://github.com/xamarin/robin-map", - "commitHash": "d37a41003bfbc7e12e34601f93c18ca2ff6d7c07" - } - } - } - ] -} From 8a5f37a2ec78c8bbde2916359d4b7ac4db084742 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 6 May 2026 12:35:23 -0500 Subject: [PATCH 4/4] Fix build: restore Name and LocalPath on GitSubmoduleInfo GeneratedSourceLinkJsonFile and Step_GenerateFiles use these properties. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../xaprepare/Steps/Step_GenerateCGManifest.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateCGManifest.cs b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateCGManifest.cs index 7ee187863e5..53dd72a13e6 100644 --- a/build-tools/xaprepare/xaprepare/Steps/Step_GenerateCGManifest.cs +++ b/build-tools/xaprepare/xaprepare/Steps/Step_GenerateCGManifest.cs @@ -58,8 +58,19 @@ protected override async Task Execute (Context context) sealed class GitSubmoduleInfo { + public string Name { + get { + const string github = "github.com/"; + int i = RepositoryUrl.IndexOf (github, StringComparison.OrdinalIgnoreCase); + if (i >= 0) + return RepositoryUrl.Substring (i + github.Length); + return RepositoryUrl; + } + } + public string RepositoryUrl { get; private set; } = String.Empty; public string CommitHash { get; private set; } = String.Empty; + public string LocalPath { get; private set; } = String.Empty; GitSubmoduleInfo () { @@ -131,6 +142,7 @@ static GitSubmoduleInfo CreateSubmoduleInfo (string url, string path, List