From 0f65522efd1738e3a70030e7d976ff089bb1ad7d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 20 Aug 2023 02:49:34 -0400 Subject: [PATCH] Setup autogenerated Nuget release notes --- .github/workflows/ci-pipeline.yml | 14 +++ .../Tgstation.Server.Api.csproj | 2 +- .../Tgstation.Server.Client.csproj | 2 +- .../Tgstation.Server.Common.csproj | 2 +- .../Tgstation.Server.ReleaseNotes/Program.cs | 93 ++++++++++++++++--- 5 files changed, 97 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 6e74f72fcf..714ea46c77 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -1393,6 +1393,20 @@ jobs: - name: Checkout uses: actions/checkout@v3 + - name: Restore + run: dotnet restore + + - name: Build ReleaseNotes + run: | + export TGS_HOST_NO_WEBPANEL=true + dotnet build -c Release tools/Tgstation.Server.ReleaseNotes/Tgstation.Server.ReleaseNotes.csproj + + - name: Grab Most Recent Changelog + run: curl -L https://raw.githubusercontent.com/tgstation/tgstation-server/gh-pages/changelog.yml -o changelog.yml + + - name: Generate Release Notes + run: dotnet run -c Release --no-build --project tools/Tgstation.Server.ReleaseNotes ${{ env.TGS_DM_VERSION }} --nuget + - name: Publish Tgstation.Server.Common to NuGet uses: alirezanet/publish-nuget@e276c40afeb2a154046f0997820f2a9ea74832d9 # v3.1.0 with: diff --git a/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj b/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj index 913f4db126..582c079b6e 100644 --- a/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj +++ b/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj @@ -6,7 +6,7 @@ $(TgsApiLibraryVersion) API definitions for tgstation-server. json web api tgstation-server tgstation ss13 byond http - Added support for -map-threads DreamDaemon parameter and UploadZip Administration update option. + $(TGS_NUGET_RELEASE_NOTES_API) CA1028 diff --git a/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj b/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj index 67bd6448a3..af89800112 100644 --- a/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj +++ b/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj @@ -6,7 +6,7 @@ $(TgsClientVersion) Client library for tgstation-server. json web api tgstation-server tgstation ss13 byond client http - Added support for .zip uploads for server updates. Added missing Dispose() call to the StringContents for requests with bodies and added missing ConfigureAwait(false) to async call. + $(TGS_NUGET_RELEASE_NOTES_CLIENT) diff --git a/src/Tgstation.Server.Common/Tgstation.Server.Common.csproj b/src/Tgstation.Server.Common/Tgstation.Server.Common.csproj index 29d40742bc..405226e89f 100644 --- a/src/Tgstation.Server.Common/Tgstation.Server.Common.csproj +++ b/src/Tgstation.Server.Common/Tgstation.Server.Common.csproj @@ -6,7 +6,7 @@ $(TgsCommonLibraryVersion) Common functions for tgstation-server. web tgstation-server tgstation ss13 byond client http - Added CachedResponseStream. + $(TGS_NUGET_RELEASE_NOTES_COMMON) diff --git a/tools/Tgstation.Server.ReleaseNotes/Program.cs b/tools/Tgstation.Server.ReleaseNotes/Program.cs index d336cd8367..c02128c7db 100644 --- a/tools/Tgstation.Server.ReleaseNotes/Program.cs +++ b/tools/Tgstation.Server.ReleaseNotes/Program.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Net; using System.Net.Http; using System.Net.Sockets; +using System.Security; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -50,12 +51,14 @@ namespace Tgstation.Server.ReleaseNotes var linkWinget = versionString.Equals("--link-winget", StringComparison.OrdinalIgnoreCase); var shaCheck = versionString.Equals("--winget-template-check", StringComparison.OrdinalIgnoreCase); var fullNotes = versionString.Equals("--generate-full-notes", StringComparison.OrdinalIgnoreCase); + var nuget = versionString.Equals("--nuget", StringComparison.OrdinalIgnoreCase); if ((!Version.TryParse(versionString, out var version) || version.Revision != -1) && !ensureRelease && !linkWinget && !shaCheck - && !fullNotes) + && !fullNotes + && !nuget) { Console.WriteLine("Invalid version: " + versionString); return 2; @@ -127,6 +130,9 @@ namespace Tgstation.Server.ReleaseNotes if (componentRelease.HasValue) return await ReleaseComponent(client, version, componentRelease.Value); + if (nuget) + return await ReleaseNuget(client); + var releasesTask = client.Repository.Release.GetAll(RepoOwner, RepoName); Console.WriteLine("Getting merged pull requests in milestone " + versionString + "..."); @@ -1033,7 +1039,7 @@ The user account that created this pull request is available to correct any issu static IReadOnlyDictionary> releasedNonCoreVersions; - static async Task GenerateNotes(IGitHubClient client, Tuple forceReleaseVersion = null) + static async Task GenerateNotes(IGitHubClient client, Dictionary forceReleaseVersions = null) { ReleaseNotes previousNotes = null; if (File.Exists("changelog.yml")) @@ -1081,11 +1087,13 @@ The user account that created this pull request is available to correct any issu { Component.NugetClient, await nugetClientVersions } }; - if (forceReleaseVersion != null && !newDic[forceReleaseVersion.Item1].Any(x => x == forceReleaseVersion.Item2)) - newDic[forceReleaseVersion.Item1] = newDic[forceReleaseVersion.Item1] - .Concat(new List { forceReleaseVersion.Item2 }) - .OrderBy(x => x) - .ToHashSet(); + if (forceReleaseVersions != null) + foreach (var kvp in forceReleaseVersions) + if (!newDic[kvp.Key].Any(x => x == kvp.Value)) + newDic[kvp.Key] = newDic[kvp.Key] + .Concat(new List { kvp.Value }) + .OrderBy(x => x) + .ToHashSet(); releasedNonCoreVersions = newDic; @@ -1230,17 +1238,76 @@ The user account that created this pull request is available to correct any issu } } - static async Task ReleaseComponent(IGitHubClient client, Version version, Component component) + static string GenerateComponentNotes(ReleaseNotes releaseNotes, Component component, Version version) { - var releaseNotes = await GenerateNotes(client, Tuple.Create(component, version)); - var relevantChangelog = releaseNotes.Components[component].First(x => x.Version == version); + var relevantChangelog = releaseNotes.Components[component].FirstOrDefault(x => x.Version == version); var newNotes = new StringBuilder("Full changelog can be found [here](https://raw.githubusercontent.com/tgstation/tgstation-server/gh-pages/changelog.yml)."); - newNotes.AppendLine(); - PrintChanges(newNotes, relevantChangelog); + if (relevantChangelog != null) + { + newNotes.AppendLine(); + PrintChanges(newNotes, relevantChangelog); + } var markdown = newNotes.ToString(); - await File.WriteAllTextAsync(OutputPath, markdown); + return markdown; + } + + static async Task ReleaseComponent(IGitHubClient client, Version version, Component component) + { + var releaseNotes = await GenerateNotes(client, new Dictionary { { component, version } }); + await File.WriteAllTextAsync(OutputPath, GenerateComponentNotes(releaseNotes, component, version)); + return 0; + } + + // must run from repo root + static async Task ReleaseNuget(IGitHubClient client) + { + const string PropsPath = "build/Version.props"; + + var doc = XDocument.Load(PropsPath); + var project = doc.Root; + var xmlNamespace = project.GetDefaultNamespace(); + var versionsPropertyGroup = project.Elements().First(x => x.Name == xmlNamespace + "PropertyGroup"); + + var commonVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsCommonLibraryVersion").Value); + var apiVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsApiLibraryVersion").Value); + var clientVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsClientVersion").Value); + + var componentVersions = new Dictionary + { + { Component.NugetCommon, commonVersion }, + { Component.NugetApi, apiVersion }, + { Component.NugetClient, clientVersion }, + }; + + var releaseNotes = await GenerateNotes( + client, + componentVersions); + + const string CsprojSubstitution = "src/Tgstation.Server.$PROJECT$/Tgstation.Server.$PROJECT$.csproj"; + var csprojNameMap = new Dictionary + { + { Component.NugetCommon, "Common" }, + { Component.NugetApi, "Api" }, + { Component.NugetClient, "Client" }, + }; + + foreach(var kvp in csprojNameMap) + { + var component = kvp.Key; + var csprojPath = CsprojSubstitution.Replace("$PROJECT$", kvp.Value); + + var markdown = GenerateComponentNotes(releaseNotes, component, componentVersions[component]); + + var escapedMarkdown = SecurityElement.Escape(markdown); + + var originalCsproj = await File.ReadAllTextAsync(csprojPath); + var substitutedCsproj = originalCsproj.Replace($"$(TGS_NUGET_RELEASE_NOTES_{kvp.Value.ToUpperInvariant()})", escapedMarkdown); + + await File.WriteAllTextAsync(csprojPath, substitutedCsproj); + } + return 0; } }