diff --git a/src/Microsoft.DotNet.Build.Tasks.Feed/BuildManifest/PushOrchestratedBuildManifest.cs b/src/Microsoft.DotNet.Build.Tasks.Feed/BuildManifest/PushOrchestratedBuildManifest.cs
index 1813aabde9..639c31fd7e 100644
--- a/src/Microsoft.DotNet.Build.Tasks.Feed/BuildManifest/PushOrchestratedBuildManifest.cs
+++ b/src/Microsoft.DotNet.Build.Tasks.Feed/BuildManifest/PushOrchestratedBuildManifest.cs
@@ -8,6 +8,8 @@
using Microsoft.DotNet.VersionTools.Automation.GitHubApi;
using Microsoft.DotNet.VersionTools.BuildManifest;
using Microsoft.DotNet.VersionTools.BuildManifest.Model;
+using System.IO;
+using System.Linq;
using System.Xml.Linq;
namespace Microsoft.DotNet.Build.Tasks.Feed.BuildManifest
@@ -32,6 +34,12 @@ public class PushOrchestratedBuildManifest : Task
public string CommitMessage { get; set; }
+ ///
+ /// %(Identity): A file to upload to the versions repo.
+ /// %(RelativePath): Optional path to upload the file to, relative to VersionsRepoPath.
+ ///
+ public ITaskItem[] SupplementaryFiles { get; set; }
+
public override bool Execute()
{
string contents = System.IO.File.ReadAllText(ManifestFile);
@@ -47,12 +55,28 @@ public override bool Execute()
{
var client = new BuildManifestClient(gitHubClient);
+ SupplementaryUploadRequest[] supplementaryUploads = SupplementaryFiles
+ ?.Select(i =>
+ {
+ string path = i.GetMetadata("RelativePath");
+ if (string.IsNullOrEmpty(path))
+ {
+ path = Path.GetFileName(i.ItemSpec);
+ }
+ return new SupplementaryUploadRequest
+ {
+ Contents = File.ReadAllText(i.ItemSpec),
+ Path = path
+ };
+ })
+ .ToArray();
+
var pushTask = client.PushNewBuildAsync(
new GitHubProject(VersionsRepo, VersionsRepoOwner),
$"heads/{VersionsRepoBranch}",
VersionsRepoPath,
model,
- null,
+ supplementaryUploads,
CommitMessage);
pushTask.Wait();
diff --git a/src/Microsoft.DotNet.Build.Tasks.Feed/BuildManifest/WriteOrchestratedBuildManifestSummaryToFile.cs b/src/Microsoft.DotNet.Build.Tasks.Feed/BuildManifest/WriteOrchestratedBuildManifestSummaryToFile.cs
new file mode 100644
index 0000000000..6e99173f00
--- /dev/null
+++ b/src/Microsoft.DotNet.Build.Tasks.Feed/BuildManifest/WriteOrchestratedBuildManifestSummaryToFile.cs
@@ -0,0 +1,87 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using Microsoft.DotNet.VersionTools.BuildManifest.Model;
+using System.Linq;
+using System.Text;
+using System.Xml.Linq;
+
+namespace Microsoft.DotNet.Build.Tasks.Feed.BuildManifest
+{
+ public class WriteOrchestratedBuildManifestSummaryToFile : Task
+ {
+ [Required]
+ public string File { get; set; }
+
+ [Required]
+ public string ManifestFile { get; set; }
+
+ public string SdkTableTemplateFile { get; set; }
+
+ public string RuntimeTableTemplateFile { get; set; }
+
+ public override bool Execute()
+ {
+ string contents = System.IO.File.ReadAllText(ManifestFile);
+ OrchestratedBuildModel model = OrchestratedBuildModel.Parse(XElement.Parse(contents));
+ EndpointModel blobFeed = model.Endpoints.First(e => e.IsOrchestratedBlobFeed);
+
+ string feedAssetsRoot = blobFeed.Url.Replace("/index.json", "/assets");
+
+ string sdkProductVersion = model.Builds
+ .FirstOrDefault(b => b.Name == "cli")
+ ?.BuildId;
+ string runtimeProductVersion = blobFeed.Artifacts.Blobs
+ .FirstOrDefault(b => b.Id.StartsWith("Runtime/"))
+ ?.Id.Split('/')[1];
+
+ var builder = new StringBuilder();
+
+ builder.Append("## Product build: ");
+ builder.AppendLine(model.Identity.ToString());
+
+ if (!string.IsNullOrEmpty(SdkTableTemplateFile) && sdkProductVersion != null)
+ {
+ builder.AppendLine();
+ builder.AppendLine(FillTemplate(
+ SdkTableTemplateFile,
+ feedAssetsRoot,
+ sdkProductVersion));
+ }
+
+ if (!string.IsNullOrEmpty(RuntimeTableTemplateFile) && runtimeProductVersion != null)
+ {
+ builder.AppendLine();
+ builder.AppendLine(FillTemplate(
+ RuntimeTableTemplateFile,
+ feedAssetsRoot,
+ runtimeProductVersion));
+ }
+
+ builder.AppendLine();
+ builder.AppendLine("### Built Repositories");
+
+ foreach (BuildIdentity build in model.Builds
+ .Where(b => b.Name != "anonymous")
+ .OrderBy(b => b.Name))
+ {
+ builder.Append(" * ");
+ builder.AppendLine(build.ToString());
+ }
+
+ System.IO.File.WriteAllText(File, builder.ToString());
+
+ return !Log.HasLoggedErrors;
+ }
+
+ private static string FillTemplate(string templateFile, string feedAssetsRoot, string productVersion)
+ {
+ return System.IO.File.ReadAllText(templateFile)
+ .Replace("{{FeedAssetsRoot}}", feedAssetsRoot)
+ .Replace("{{ProductVersion}}", productVersion);
+ }
+ }
+}
diff --git a/src/Microsoft.DotNet.Build.Tasks.Feed/Microsoft.DotNet.Build.Tasks.Feed.csproj b/src/Microsoft.DotNet.Build.Tasks.Feed/Microsoft.DotNet.Build.Tasks.Feed.csproj
index e530dd169b..b499ac2d54 100644
--- a/src/Microsoft.DotNet.Build.Tasks.Feed/Microsoft.DotNet.Build.Tasks.Feed.csproj
+++ b/src/Microsoft.DotNet.Build.Tasks.Feed/Microsoft.DotNet.Build.Tasks.Feed.csproj
@@ -45,6 +45,7 @@
+
diff --git a/src/Microsoft.DotNet.Build.Tasks.Feed/PackageFiles/Microsoft.DotNet.Build.Tasks.Feed.targets b/src/Microsoft.DotNet.Build.Tasks.Feed/PackageFiles/Microsoft.DotNet.Build.Tasks.Feed.targets
index 42c60e0773..f03ec521e1 100644
--- a/src/Microsoft.DotNet.Build.Tasks.Feed/PackageFiles/Microsoft.DotNet.Build.Tasks.Feed.targets
+++ b/src/Microsoft.DotNet.Build.Tasks.Feed/PackageFiles/Microsoft.DotNet.Build.Tasks.Feed.targets
@@ -52,6 +52,7 @@
+
false
@@ -131,6 +132,7 @@
$(BaseIntermediateOutputPath)manifest-temp/
$(ManifestTempDir)downloads/
$(ManifestTempDir)build.xml
+ $(ManifestTempDir)README.md
@@ -154,6 +156,15 @@
BuildManifestFiles="@(BuildManifests)"
ManifestName="$(ManifestName)"
ManifestBuildId="$(ManifestBuildId)" />
+
+
+
+
+
+