From 18f0244d4bcbf7d00650ee46ad6ed6bf5b0a351d Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Thu, 9 Dec 2021 22:40:34 +0100 Subject: [PATCH 01/21] Started on a changelog --- .../Bake.Tests/ExplicitTests/GitHubTests.cs | 77 +++++++++++++++++++ Source/Bake.Tests/Helpers/BakeTest.cs | 16 ++++ .../Ingredients/Gathers/ChangelogGather.cs | 67 ++++++++++++++++ .../Extensions/ServiceCollectionExtensions.cs | 1 + Source/Bake/Services/GitHub.cs | 50 ++++++++++++ Source/Bake/Services/IGitHub.cs | 6 ++ Source/Bake/ValueObjects/Author.cs | 47 +++++++++++ Source/Bake/ValueObjects/Commit.cs | 59 ++++++++++++++ Source/Bake/ValueObjects/Ingredients.cs | 24 ++++++ 9 files changed, 347 insertions(+) create mode 100644 Source/Bake.Tests/ExplicitTests/GitHubTests.cs create mode 100644 Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs create mode 100644 Source/Bake/ValueObjects/Author.cs create mode 100644 Source/Bake/ValueObjects/Commit.cs diff --git a/Source/Bake.Tests/ExplicitTests/GitHubTests.cs b/Source/Bake.Tests/ExplicitTests/GitHubTests.cs new file mode 100644 index 00000000..4f611981 --- /dev/null +++ b/Source/Bake.Tests/ExplicitTests/GitHubTests.cs @@ -0,0 +1,77 @@ +// MIT License +// +// Copyright (c) 2021 Rasmus Mikkelsen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Bake.Cooking.Cooks.GitHub; +using Bake.Core; +using Bake.Services; +using Bake.Tests.Helpers; +using Bake.ValueObjects; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; + +namespace Bake.Tests.ExplicitTests +{ + [Explicit] + public class GitHubTests : ServiceTest + { + public GitHubTests() : base(null) { } + + [Test] + public async Task T() + { + await Sut.CompareAsync( + "c2dbe6e", + new GitHubInformation( + "rasmus", + "Bake", + new Uri("https://github.com/rasmus/Bake")), + CancellationToken.None); + } + + private static string GetToken() + { + return new ConfigurationBuilder() + .AddUserSecrets() + .Build()["github.token"]; + } + + protected override IServiceCollection Configure(IServiceCollection serviceCollection) + { + return base.Configure(serviceCollection) + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton(new TestEnvironmentVariables(new Dictionary + { + ["github_personal_token"] = GetToken(), + })); + } + } +} diff --git a/Source/Bake.Tests/Helpers/BakeTest.cs b/Source/Bake.Tests/Helpers/BakeTest.cs index 45a848ab..5465d758 100644 --- a/Source/Bake.Tests/Helpers/BakeTest.cs +++ b/Source/Bake.Tests/Helpers/BakeTest.cs @@ -32,6 +32,8 @@ using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; +// ReSharper disable StringLiteralTypo + namespace Bake.Tests.Helpers { public abstract class BakeTest : TestProject @@ -125,6 +127,20 @@ public Task CreateReleaseAsync( _releases.Add(release); return Task.CompletedTask; } + + public Task> CompareAsync( + string sha, + GitHubInformation gitHubInformation, + CancellationToken cancellationToken) + { + var commits = new List + { + new("Wrote some awesome tests", "c2dbe6e", DateTimeOffset.Now, new Author("Rasmus Mikkelsen", "r@smus.nu")), + new("Got it working", "4d79e4e", DateTimeOffset.Now, new Author("Rasmus Mikkelsen", "r@smus.nu")) + }; + + return Task.FromResult>(commits); + } } } } diff --git a/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs b/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs new file mode 100644 index 00000000..e43d006e --- /dev/null +++ b/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs @@ -0,0 +1,67 @@ +// MIT License +// +// Copyright (c) 2021 Rasmus Mikkelsen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Bake.Services; +using Bake.ValueObjects; + +namespace Bake.Cooking.Ingredients.Gathers +{ + public class ChangelogGather : IGather + { + private readonly IGitHub _gitHub; + + public ChangelogGather( + IGitHub gitHub) + { + _gitHub = gitHub; + } + + public async Task GatherAsync( + ValueObjects.Ingredients ingredients, + CancellationToken cancellationToken) + { + GitInformation gitInformation; + GitHubInformation gitHubInformation; + + try + { + gitInformation = await ingredients.GitTask; + gitHubInformation = await ingredients.GitHubTask; + } + catch (OperationCanceledException) + { + ingredients.FailChangelog(); + return; + } + + ingredients.Changelog = (await _gitHub.CompareAsync( + gitInformation.Sha, + gitHubInformation, + cancellationToken)) + .ToList(); + } + } +} diff --git a/Source/Bake/Extensions/ServiceCollectionExtensions.cs b/Source/Bake/Extensions/ServiceCollectionExtensions.cs index 8b1b46b1..878cdf3e 100644 --- a/Source/Bake/Extensions/ServiceCollectionExtensions.cs +++ b/Source/Bake/Extensions/ServiceCollectionExtensions.cs @@ -77,6 +77,7 @@ public static IServiceCollection AddBake( .AddTransient() .AddTransient() .AddTransient() + .AddTransient() // CLI wrappers .AddTransient() diff --git a/Source/Bake/Services/GitHub.cs b/Source/Bake/Services/GitHub.cs index f8b86bd1..4bb35f9b 100644 --- a/Source/Bake/Services/GitHub.cs +++ b/Source/Bake/Services/GitHub.cs @@ -20,6 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; @@ -28,12 +29,16 @@ using Bake.ValueObjects; using Microsoft.Extensions.Logging; using Octokit; +using Author = Bake.ValueObjects.Author; +using Commit = Bake.ValueObjects.Commit; using Release = Bake.ValueObjects.Release; namespace Bake.Services { public class GitHub : IGitHub { + private static readonly IReadOnlyCollection EmptyCommits = new Commit[] { }; + private readonly ILogger _logger; private readonly ICredentials _credentials; private readonly IGitHubClientFactory _gitHubClientFactory; @@ -91,6 +96,51 @@ await gitHubClient.Repository.Release.Edit( gitHubReleaseUpdate); } + public async Task> CompareAsync( + string sha, + GitHubInformation gitHubInformation, + CancellationToken cancellationToken) + { + var token = await _credentials.TryGetGitHubTokenAsync( + gitHubInformation.Url, + cancellationToken); + + var gitHubClient = await _gitHubClientFactory.CreateAsync( + token, + cancellationToken); + + var branches = await gitHubClient.Repository.Branch.GetAll( + gitHubInformation.Owner, + gitHubInformation.Repository); + + // TODO: Allow better selection + var releaseBranch = branches.SingleOrDefault(b => string.Equals(b.Name, "release")); + if (releaseBranch == null) + { + return EmptyCommits; + } + + var compareResult = await gitHubClient.Repository.Commit.Compare( + gitHubInformation.Owner, + gitHubInformation.Repository, + releaseBranch.Commit.Sha, + sha); + if (compareResult.AheadBy <= 0 || compareResult.BehindBy >= 0) + { + return EmptyCommits; + } + + return compareResult.Commits + .Select(c => new Commit( + c.Commit.Message, + c.Commit.Sha, + c.Commit.Author.Date, + new Author( + c.Commit.Author.Name, + c.Commit.Author.Email))) + .ToList(); + } + private async Task UploadFileAsync( ReleaseFile releaseFile, Octokit.Release gitHubRelease, diff --git a/Source/Bake/Services/IGitHub.cs b/Source/Bake/Services/IGitHub.cs index 4d8c41e8..2665d290 100644 --- a/Source/Bake/Services/IGitHub.cs +++ b/Source/Bake/Services/IGitHub.cs @@ -20,6 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Bake.ValueObjects; @@ -32,5 +33,10 @@ Task CreateReleaseAsync( Release release, GitHubInformation gitHubInformation, CancellationToken cancellationToken); + + Task> CompareAsync( + string sha, + GitHubInformation gitHubInformation, + CancellationToken cancellationToken); } } diff --git a/Source/Bake/ValueObjects/Author.cs b/Source/Bake/ValueObjects/Author.cs new file mode 100644 index 00000000..9e26c824 --- /dev/null +++ b/Source/Bake/ValueObjects/Author.cs @@ -0,0 +1,47 @@ +// MIT License +// +// Copyright (c) 2021 Rasmus Mikkelsen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +using System; +using YamlDotNet.Serialization; + +namespace Bake.ValueObjects +{ + public class Author + { + [YamlMember] + public string Name { get; [Obsolete] set; } + + [YamlMember] + public string Email { get; [Obsolete] set; } + + [Obsolete] + public Author() { } + + public Author( + string name, + string email) + { + Name = name; + Email = email; + } + } +} diff --git a/Source/Bake/ValueObjects/Commit.cs b/Source/Bake/ValueObjects/Commit.cs new file mode 100644 index 00000000..0d68ba54 --- /dev/null +++ b/Source/Bake/ValueObjects/Commit.cs @@ -0,0 +1,59 @@ +// MIT License +// +// Copyright (c) 2021 Rasmus Mikkelsen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +using System; +using YamlDotNet.Serialization; + +namespace Bake.ValueObjects +{ + public class Commit + { + [YamlMember] + public string Message { get; [Obsolete] set; } + + [YamlMember] + public string Sha { get; [Obsolete] set; } + + [YamlMember] + public Author Author { get; [Obsolete] set; } + + [YamlMember] + public DateTimeOffset Time { get; [Obsolete] set; } + + [Obsolete] + public Commit() { } + + public Commit( + string message, + string sha, + DateTimeOffset time, + Author author) + { +#pragma warning disable CS0612 // Type or member is obsolete + Message = message; + Sha = sha; + Author = author; + Time = time; +#pragma warning restore CS0612 // Type or member is obsolete + } + } +} diff --git a/Source/Bake/ValueObjects/Ingredients.cs b/Source/Bake/ValueObjects/Ingredients.cs index 06b76302..bfbc8b93 100644 --- a/Source/Bake/ValueObjects/Ingredients.cs +++ b/Source/Bake/ValueObjects/Ingredients.cs @@ -59,6 +59,20 @@ public static Ingredients New( [YamlMember] public List Destinations { get; [Obsolete] set; } = new(); + [YamlMember] + public List Changelog + { + get => _changelog.Task.IsCompletedSuccessfully ? _changelog.Task.Result : null; + set + { + if (value == null) + { + return; + } + _changelog.SetResult(value); + } + } + [YamlMember] public GitInformation Git { @@ -119,9 +133,13 @@ public ReleaseNotes ReleaseNotes [YamlIgnore] public Task GitHubTask => _gitHub.Task; + [YamlIgnore] + public Task> ChangelogTask => _changelog.Task; + private readonly TaskCompletionSource _git = new(); private readonly TaskCompletionSource _releaseNotes = new(); private readonly TaskCompletionSource _gitHub = new(); + private readonly TaskCompletionSource> _changelog = new(); [Obsolete] public Ingredients() { } @@ -142,6 +160,7 @@ public Ingredients( public void FailGit() => _git.SetCanceled(); public void FailGitHub() => _gitHub.SetCanceled(); + public void FailChangelog() => _changelog.SetCanceled(); public void FailOutstanding() { @@ -154,6 +173,11 @@ public void FailOutstanding() { _gitHub.SetCanceled(); } + + if (!_changelog.Task.IsCompleted) + { + _changelog.SetCanceled(); + } } } } From 8b0778a8e54d57fc32141fae0d9b0d78b8d7f619 Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Thu, 9 Dec 2021 22:43:20 +0100 Subject: [PATCH 02/21] Add token --- .github/workflows/pull-requests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pull-requests.yml b/.github/workflows/pull-requests.yml index f5ee3325..dec0d4d1 100644 --- a/.github/workflows/pull-requests.yml +++ b/.github/workflows/pull-requests.yml @@ -13,6 +13,7 @@ jobs: env: DOTNET_CLI_TELEMETRY_OPTOUT: true DOTNET_NOLOGO: true + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} services: baget: From bbdbc5b25ec4d5db8f13698c3dc63cb8fb4bec83 Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Thu, 9 Dec 2021 22:52:47 +0100 Subject: [PATCH 03/21] Add DateTimeOffset converter --- Source/Bake/Core/Yaml.cs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/Source/Bake/Core/Yaml.cs b/Source/Bake/Core/Yaml.cs index 26440a0f..4500baed 100644 --- a/Source/Bake/Core/Yaml.cs +++ b/Source/Bake/Core/Yaml.cs @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Reflection; using System.Threading; @@ -74,13 +75,14 @@ static Yaml() new DeserializerBuilder(), (b, a) => b.WithTagMapping(a.tag, a.type)) .WithNamingConvention(CamelCaseNamingConvention.Instance) - .WithTypeConverter(new SemVerYamlTypeConverter()) + .WithTypeConverter(new DateTimeOffsetTypeConverter()) .Build(); Serializer = recipeTypes.Aggregate( new SerializerBuilder(), (b, a) => b.WithTagMapping(a.tag, a.type)) .WithNamingConvention(CamelCaseNamingConvention.Instance) .WithTypeConverter(new SemVerYamlTypeConverter()) + .WithTypeConverter(new DateTimeOffsetTypeConverter()) .DisableAliases() .ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitDefaults) .Build(); @@ -124,6 +126,35 @@ public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter) } } + private class DateTimeOffsetTypeConverter : IYamlTypeConverter + { + private static readonly IValueDeserializer ValueDeserializer = new DeserializerBuilder() + .BuildValueDeserializer(); + + private static readonly IValueSerializer ValueSerializer = new SerializerBuilder() + .WithEventEmitter(n => new QuoteSurroundingEventEmitter(n)) + .BuildValueSerializer(); + + public bool Accepts(Type type) => typeof(DateTimeOffset) == type; + + public object? ReadYaml(IParser parser, Type type) + { + var value = (string)ValueDeserializer.DeserializeValue(parser, typeof(string), new SerializerState(), ValueDeserializer); + if (!DateTimeOffset.TryParseExact(value, "O", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var dateTimeOffset)) + { + throw new FormatException($"'{value}' is not a valid DateTimeOffset"); + } + + return dateTimeOffset; + } + + public void WriteYaml(IEmitter emitter, object? value, Type type) + { + var dateTimeOffset = (DateTimeOffset)value; + ValueSerializer.SerializeValue(emitter, dateTimeOffset.ToString("O"), typeof(string)); + } + } + private class SemVerYamlTypeConverter : IYamlTypeConverter { private static readonly IValueDeserializer ValueDeserializer = new DeserializerBuilder() From bda7ff4a50d8544351158ba63746db210c5f6c2b Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Thu, 9 Dec 2021 22:53:51 +0100 Subject: [PATCH 04/21] Handle null --- Source/Bake/Core/Yaml.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Source/Bake/Core/Yaml.cs b/Source/Bake/Core/Yaml.cs index 4500baed..f10da8b4 100644 --- a/Source/Bake/Core/Yaml.cs +++ b/Source/Bake/Core/Yaml.cs @@ -150,8 +150,15 @@ private class DateTimeOffsetTypeConverter : IYamlTypeConverter public void WriteYaml(IEmitter emitter, object? value, Type type) { - var dateTimeOffset = (DateTimeOffset)value; - ValueSerializer.SerializeValue(emitter, dateTimeOffset.ToString("O"), typeof(string)); + if (value == null) + { + ValueSerializer.SerializeValue(emitter, null, typeof(string)); + } + else + { + var dateTimeOffset = (DateTimeOffset)value; + ValueSerializer.SerializeValue(emitter, dateTimeOffset.ToString("O"), typeof(string)); + } } } From de2ecdbf5bb09bbfd11e8f95bf57aee567d665d3 Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Thu, 9 Dec 2021 23:01:13 +0100 Subject: [PATCH 05/21] Fix GitHub compare --- Source/Bake.Tests/ExplicitTests/GitHubTests.cs | 2 +- Source/Bake/Services/GitHub.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Bake.Tests/ExplicitTests/GitHubTests.cs b/Source/Bake.Tests/ExplicitTests/GitHubTests.cs index 4f611981..41382959 100644 --- a/Source/Bake.Tests/ExplicitTests/GitHubTests.cs +++ b/Source/Bake.Tests/ExplicitTests/GitHubTests.cs @@ -43,7 +43,7 @@ public GitHubTests() : base(null) { } [Test] public async Task T() { - await Sut.CompareAsync( + var commits = await Sut.CompareAsync( "c2dbe6e", new GitHubInformation( "rasmus", diff --git a/Source/Bake/Services/GitHub.cs b/Source/Bake/Services/GitHub.cs index 4bb35f9b..30d60249 100644 --- a/Source/Bake/Services/GitHub.cs +++ b/Source/Bake/Services/GitHub.cs @@ -125,7 +125,7 @@ public async Task> CompareAsync( gitHubInformation.Repository, releaseBranch.Commit.Sha, sha); - if (compareResult.AheadBy <= 0 || compareResult.BehindBy >= 0) + if (compareResult.AheadBy <= 0) { return EmptyCommits; } From a9001e0aea04977d8e2ce1e93487f868e44d868b Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Thu, 9 Dec 2021 23:05:05 +0100 Subject: [PATCH 06/21] Add changelog to release --- Source/Bake/Cooking/Cooks/GitHub/GitHubReleaseCook.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Source/Bake/Cooking/Cooks/GitHub/GitHubReleaseCook.cs b/Source/Bake/Cooking/Cooks/GitHub/GitHubReleaseCook.cs index ab2a1071..d3e54dec 100644 --- a/Source/Bake/Cooking/Cooks/GitHub/GitHubReleaseCook.cs +++ b/Source/Bake/Cooking/Cooks/GitHub/GitHubReleaseCook.cs @@ -93,6 +93,16 @@ protected override async Task CookAsync( .AppendLine(); } + if (context.Ingredients.Changelog != null && context.Ingredients.Changelog.Any()) + { + foreach (var commit in context.Ingredients.Changelog) + { + stringBuilder.AppendLine($"* {commit.Message}"); + } + + stringBuilder.AppendLine(); + } + var releaseFiles = (await CreateReleaseFilesAsync(additionalFiles, recipe, cancellationToken)).ToList(); var documentationSite = recipe.Artifacts From 2718a15fcc7ce25c4dac4132900b053a23f3f224 Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Tue, 12 Dec 2023 21:16:57 +0100 Subject: [PATCH 07/21] Work a bit --- .../Bake.Tests/ExplicitTests/GitHubTests.cs | 4 +- .../Cooking/Cooks/GitHub/GitHubReleaseCook.cs | 2 +- .../Ingredients/Gathers/ChangelogGather.cs | 20 +++++++-- Source/Bake/Services/GitHub.cs | 16 ++++--- Source/Bake/ValueObjects/Change.cs | 44 +++++++++++++++++++ Source/Bake/ValueObjects/Commit.cs | 9 +++- Source/Bake/ValueObjects/Ingredients.cs | 6 +-- 7 files changed, 84 insertions(+), 17 deletions(-) create mode 100644 Source/Bake/ValueObjects/Change.cs diff --git a/Source/Bake.Tests/ExplicitTests/GitHubTests.cs b/Source/Bake.Tests/ExplicitTests/GitHubTests.cs index d8ca5de5..7de8af8e 100644 --- a/Source/Bake.Tests/ExplicitTests/GitHubTests.cs +++ b/Source/Bake.Tests/ExplicitTests/GitHubTests.cs @@ -44,7 +44,7 @@ public GitHubTests() : base(null) { } public async Task T() { var commits = await Sut.CompareAsync( - "c2dbe6e", + "662965e", new GitHubInformation( "rasmus", "Bake", @@ -57,7 +57,7 @@ private static string GetToken() { return new ConfigurationBuilder() .AddUserSecrets() - .Build()["github.token"]; + .Build()["github:token"]; } protected override IServiceCollection Configure(IServiceCollection serviceCollection) diff --git a/Source/Bake/Cooking/Cooks/GitHub/GitHubReleaseCook.cs b/Source/Bake/Cooking/Cooks/GitHub/GitHubReleaseCook.cs index 57a5303c..1a6f47fe 100644 --- a/Source/Bake/Cooking/Cooks/GitHub/GitHubReleaseCook.cs +++ b/Source/Bake/Cooking/Cooks/GitHub/GitHubReleaseCook.cs @@ -97,7 +97,7 @@ protected override async Task CookAsync( { foreach (var commit in context.Ingredients.Changelog) { - stringBuilder.AppendLine($"* {commit.Message}"); + stringBuilder.AppendLine($"* {commit.Text}"); } stringBuilder.AppendLine(); diff --git a/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs b/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs index e43d006e..48b94023 100644 --- a/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs +++ b/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs @@ -22,6 +22,7 @@ using System; using System.Linq; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Bake.Services; @@ -31,6 +32,10 @@ namespace Bake.Cooking.Ingredients.Gathers { public class ChangelogGather : IGather { + private static readonly Regex IsMergeCommit = new( + @"^Merge\s+pull\s+request\s+\#(?[0-9]+)\s+.*", + RegexOptions.Compiled | RegexOptions.IgnoreCase); + private readonly IGitHub _gitHub; public ChangelogGather( @@ -57,11 +62,20 @@ public async Task GatherAsync( return; } - ingredients.Changelog = (await _gitHub.CompareAsync( + var commits = await _gitHub.CompareAsync( gitInformation.Sha, gitHubInformation, - cancellationToken)) - .ToList(); + cancellationToken); + + var pullRequestMerges = commits + .Select(c => new + { + match = IsMergeCommit.Match(c.Message), + commit = c + }) + .Where(a => a.match.Success); + + // TODO: } } } diff --git a/Source/Bake/Services/GitHub.cs b/Source/Bake/Services/GitHub.cs index 9c93117c..4fb1789e 100644 --- a/Source/Bake/Services/GitHub.cs +++ b/Source/Bake/Services/GitHub.cs @@ -20,6 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -38,8 +39,6 @@ namespace Bake.Services { public class GitHub : IGitHub { - private static readonly IReadOnlyCollection EmptyCommits = new Commit[] { }; - private readonly ILogger _logger; private readonly ICredentials _credentials; private readonly IGitHubClientFactory _gitHubClientFactory; @@ -169,6 +168,11 @@ public async Task> CompareAsync( gitHubInformation.Url, cancellationToken); + if (string.IsNullOrEmpty(token)) + { + return Array.Empty(); + } + var gitHubClient = await _gitHubClientFactory.CreateAsync( token, gitHubInformation.ApiUrl, @@ -178,11 +182,11 @@ public async Task> CompareAsync( gitHubInformation.Owner, gitHubInformation.Repository); - // TODO: Allow better selection + // TODO: Use tags instead and find best tag closest to current version var releaseBranch = branches.SingleOrDefault(b => string.Equals(b.Name, "release")); if (releaseBranch == null) { - return EmptyCommits; + return Array.Empty(); } var compareResult = await gitHubClient.Repository.Commit.Compare( @@ -192,13 +196,13 @@ public async Task> CompareAsync( sha); if (compareResult.AheadBy <= 0) { - return EmptyCommits; + return Array.Empty(); } return compareResult.Commits .Select(c => new Commit( c.Commit.Message, - c.Commit.Sha, + c.Sha, c.Commit.Author.Date, new Author( c.Commit.Author.Name, diff --git a/Source/Bake/ValueObjects/Change.cs b/Source/Bake/ValueObjects/Change.cs new file mode 100644 index 00000000..88566e13 --- /dev/null +++ b/Source/Bake/ValueObjects/Change.cs @@ -0,0 +1,44 @@ +// MIT License +// +// Copyright (c) 2021 Rasmus Mikkelsen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +using System; +using YamlDotNet.Serialization; + +namespace Bake.ValueObjects +{ + public class Change + { + [YamlMember] + public string Text { get; [Obsolete] set; } + + [Obsolete] + public Change() { } + + public Change( + string text) + { +#pragma warning disable CS0612 // Type or member is obsolete + Text = text; +#pragma warning restore CS0612 // Type or member is obsolete + } + } +} diff --git a/Source/Bake/ValueObjects/Commit.cs b/Source/Bake/ValueObjects/Commit.cs index 0d68ba54..40e5a427 100644 --- a/Source/Bake/ValueObjects/Commit.cs +++ b/Source/Bake/ValueObjects/Commit.cs @@ -49,11 +49,16 @@ public Commit( Author author) { #pragma warning disable CS0612 // Type or member is obsolete - Message = message; - Sha = sha; + Message = message ?? string.Empty; + Sha = sha ?? string.Empty; Author = author; Time = time; #pragma warning restore CS0612 // Type or member is obsolete } + + public override string ToString() + { + return $"{Sha[..5]}: {Message}"; + } } } diff --git a/Source/Bake/ValueObjects/Ingredients.cs b/Source/Bake/ValueObjects/Ingredients.cs index df387da3..4c8ef6a8 100644 --- a/Source/Bake/ValueObjects/Ingredients.cs +++ b/Source/Bake/ValueObjects/Ingredients.cs @@ -60,7 +60,7 @@ public static Ingredients New( public List Destinations { get; [Obsolete] set; } = new(); [YamlMember] - public List Changelog + public List Changelog { get => _changelog.Task.IsCompletedSuccessfully ? _changelog.Task.Result : null; set @@ -165,7 +165,7 @@ [Obsolete] set public Task GitHubTask => _gitHub.Task; [YamlIgnore] - public Task> ChangelogTask => _changelog.Task; + public Task> ChangelogTask => _changelog.Task; [YamlIgnore] public Task PullRequestTask => _pullRequest.Task; @@ -173,7 +173,7 @@ [Obsolete] set private readonly TaskCompletionSource _git = new(); private readonly TaskCompletionSource _releaseNotes = new(); private readonly TaskCompletionSource _gitHub = new(); - private readonly TaskCompletionSource> _changelog = new(); + private readonly TaskCompletionSource> _changelog = new(); private readonly TaskCompletionSource _description = new(); private readonly TaskCompletionSource _pullRequest = new(); From 22714e420dd850f8ba1d24819e568724409fb1cd Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Wed, 20 Dec 2023 16:23:26 +0100 Subject: [PATCH 08/21] Get pull requests --- .../Bake.Tests/ExplicitTests/GitHubTests.cs | 40 ++++++++++- Source/Bake.Tests/Helpers/BakeTest.cs | 21 +++++- .../Ingredients/Gathers/ChangelogGather.cs | 15 ---- Source/Bake/Services/GitHub.cs | 71 ++++++++++++++++++- Source/Bake/Services/IGitHub.cs | 12 +++- Source/Bake/ValueObjects/PullRequest.cs | 43 +++++++++++ 6 files changed, 180 insertions(+), 22 deletions(-) create mode 100644 Source/Bake/ValueObjects/PullRequest.cs diff --git a/Source/Bake.Tests/ExplicitTests/GitHubTests.cs b/Source/Bake.Tests/ExplicitTests/GitHubTests.cs index 7de8af8e..2792b2a2 100644 --- a/Source/Bake.Tests/ExplicitTests/GitHubTests.cs +++ b/Source/Bake.Tests/ExplicitTests/GitHubTests.cs @@ -29,6 +29,7 @@ using Bake.Services; using Bake.Tests.Helpers; using Bake.ValueObjects; +using FluentAssertions; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; @@ -41,9 +42,9 @@ public class GitHubTests : ServiceTest public GitHubTests() : base(null) { } [Test] - public async Task T() + public async Task GetCommits() { - var commits = await Sut.CompareAsync( + var commits = await Sut.GetCommitsAsync( "662965e", new GitHubInformation( "rasmus", @@ -53,6 +54,41 @@ public async Task T() CancellationToken.None); } + [Test] + public async Task GetPullRequests() + { + var pullRequests = await Sut.GetPullRequestsAsync( + "662965e", + new GitHubInformation( + "rasmus", + "Bake", + new Uri("https://github.com/rasmus/Bake"), + new Uri("https://api.github.com/")), + CancellationToken.None); + + foreach (var pullRequest in pullRequests) + { + Console.WriteLine($"{pullRequest.Title}"); + } + } + + [Test] + public async Task GetPullRequest_NonExisting() + { + // Act + var pullRequest = await Sut.GetPullRequestAsync( + new GitHubInformation( + "rasmus", + "Bake", + new Uri("https://github.com/rasmus/Bake"), + new Uri("https://api.github.com/")), + int.MaxValue, + CancellationToken.None); + + // Assert + pullRequest.Should().BeNull(); + } + private static string GetToken() { return new ConfigurationBuilder() diff --git a/Source/Bake.Tests/Helpers/BakeTest.cs b/Source/Bake.Tests/Helpers/BakeTest.cs index 55145fbd..56199c8f 100644 --- a/Source/Bake.Tests/Helpers/BakeTest.cs +++ b/Source/Bake.Tests/Helpers/BakeTest.cs @@ -127,8 +127,8 @@ public Task CreateReleaseAsync( _releases.Add(release); return Task.CompletedTask; } - - public Task GetPullRequestInformationAsync( + + public Task GetPullRequestInformationAsync( GitInformation gitInformation, GitHubInformation gitHubInformation, CancellationToken cancellationToken) @@ -136,7 +136,7 @@ public Task GetPullRequestInformationAsync( return Task.FromResult(null); } - public Task> CompareAsync( + public Task> GetCommitsAsync( string sha, GitHubInformation gitHubInformation, CancellationToken cancellationToken) @@ -150,6 +150,21 @@ public Task> CompareAsync( return Task.FromResult>(commits); } + public Task> GetPullRequestsAsync( + string sha, + GitHubInformation gitHubInformation, + CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetPullRequestAsync( + GitHubInformation gitHubInformation, + int number, + CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } } } diff --git a/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs b/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs index 48b94023..2796c0a9 100644 --- a/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs +++ b/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs @@ -32,10 +32,6 @@ namespace Bake.Cooking.Ingredients.Gathers { public class ChangelogGather : IGather { - private static readonly Regex IsMergeCommit = new( - @"^Merge\s+pull\s+request\s+\#(?[0-9]+)\s+.*", - RegexOptions.Compiled | RegexOptions.IgnoreCase); - private readonly IGitHub _gitHub; public ChangelogGather( @@ -62,18 +58,7 @@ public async Task GatherAsync( return; } - var commits = await _gitHub.CompareAsync( - gitInformation.Sha, - gitHubInformation, - cancellationToken); - var pullRequestMerges = commits - .Select(c => new - { - match = IsMergeCommit.Match(c.Message), - commit = c - }) - .Where(a => a.match.Success); // TODO: } diff --git a/Source/Bake/Services/GitHub.cs b/Source/Bake/Services/GitHub.cs index 4fb1789e..820aa38a 100644 --- a/Source/Bake/Services/GitHub.cs +++ b/Source/Bake/Services/GitHub.cs @@ -33,6 +33,7 @@ using Octokit; using Author = Bake.ValueObjects.Author; using Commit = Bake.ValueObjects.Commit; +using PullRequest = Bake.ValueObjects.PullRequest; using Release = Bake.ValueObjects.Release; namespace Bake.Services @@ -45,6 +46,9 @@ public class GitHub : IGitHub public static readonly Regex SpecialMergeCommitMessageParser = new( @"Merge\s+(?[a-f0-9]+)\s+into\s+(?[a-f0-9]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex IsMergeCommit = new( + @"^Merge\s+pull\s+request\s+\#(?[0-9]+)\s+.*", + RegexOptions.Compiled | RegexOptions.IgnoreCase); public GitHub( ILogger logger, @@ -159,7 +163,7 @@ private async Task CreateGitHubClientAsync( return gitHubClient; } - public async Task> CompareAsync( + public async Task> GetCommitsAsync( string sha, GitHubInformation gitHubInformation, CancellationToken cancellationToken) @@ -210,6 +214,71 @@ public async Task> CompareAsync( .ToList(); } + public async Task> GetPullRequestsAsync( + string sha, + GitHubInformation gitHubInformation, + CancellationToken cancellationToken) + { + var commits = await GetCommitsAsync( + sha, + gitHubInformation, + cancellationToken); + + var pullRequestTasks = commits + .Select(c => IsMergeCommit.Match(c.Message)) + .Where(m => m.Success) + .Select(m => GetPullRequestAsync(gitHubInformation, int.Parse(m.Groups["pr"].Value), cancellationToken)); + + var pullRequests = await Task.WhenAll(pullRequestTasks); + + return pullRequests + .Where(pr => pr != null) + .ToArray(); + } + + public async Task GetPullRequestAsync( + GitHubInformation gitHubInformation, + int number, + CancellationToken cancellationToken) + { + var token = await _credentials.TryGetGitHubTokenAsync( + gitHubInformation.Url, + cancellationToken); + + if (string.IsNullOrEmpty(token)) + { + return null; + } + + var gitHubClient = await _gitHubClientFactory.CreateAsync( + token, + gitHubInformation.ApiUrl, + cancellationToken); + + try + { + var pullRequest = await gitHubClient.PullRequest.Get( + gitHubInformation.Owner, + gitHubInformation.Repository, + number); + + return new PullRequest( + pullRequest.Number, + pullRequest.Title); + } + catch (NotFoundException e) + { + // Puke! (why throw exception for something that is likely to happen) + + _logger.LogDebug( + e, "Could not find pull request #{Number} in {Owner}/{Repository}", + number, + gitHubInformation.Owner, + gitHubInformation.Repository); + return null; + } + } + private async Task UploadFileAsync( ReleaseFile releaseFile, Octokit.Release gitHubRelease, diff --git a/Source/Bake/Services/IGitHub.cs b/Source/Bake/Services/IGitHub.cs index be5f5aad..255db1d3 100644 --- a/Source/Bake/Services/IGitHub.cs +++ b/Source/Bake/Services/IGitHub.cs @@ -39,9 +39,19 @@ Task GetPullRequestInformationAsync( GitHubInformation gitHubInformation, CancellationToken cancellationToken); - Task> CompareAsync( + Task> GetCommitsAsync( string sha, GitHubInformation gitHubInformation, CancellationToken cancellationToken); + + Task> GetPullRequestsAsync( + string sha, + GitHubInformation gitHubInformation, + CancellationToken cancellationToken); + + Task GetPullRequestAsync( + GitHubInformation gitHubInformation, + int number, + CancellationToken cancellationToken); } } diff --git a/Source/Bake/ValueObjects/PullRequest.cs b/Source/Bake/ValueObjects/PullRequest.cs new file mode 100644 index 00000000..d016c5f4 --- /dev/null +++ b/Source/Bake/ValueObjects/PullRequest.cs @@ -0,0 +1,43 @@ +// MIT License +// +// Copyright (c) 2023 Rasmus Mikkelsen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +namespace Bake.ValueObjects +{ + public class PullRequest + { + public int Number { get; } + public string Title { get; } + + public PullRequest( + int number, + string title) + { + Number = number; + Title = title; + } + + public override string ToString() + { + return $"#{Number}: {Title}"; + } + } +} From 462f8479ab7c76928d433403a116756144d2b953 Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Wed, 20 Dec 2023 16:34:34 +0100 Subject: [PATCH 09/21] Started on calculating the change log --- .../Bake.Tests/ExplicitTests/GitHubTests.cs | 6 +- .../Services/ChangeLogBuilderTests.cs | 106 ++++++++++++++++++ .../Ingredients/Gathers/ChangelogGather.cs | 4 +- .../Extensions/ServiceCollectionExtensions.cs | 1 + Source/Bake/IChangeLogBuilder.cs | 28 +++++ Source/Bake/Services/ChangeLogBuilder.cs | 41 +++++++ Source/Bake/ValueObjects/Author.cs | 4 +- Source/Bake/ValueObjects/Change.cs | 9 +- Source/Bake/ValueObjects/ChangeType.cs | 30 +++++ Source/Bake/ValueObjects/Commit.cs | 4 +- Source/Bake/ValueObjects/PullRequest.cs | 4 +- TestProjects/NetV8.Service/Source/Program.cs | 24 +++- 12 files changed, 247 insertions(+), 14 deletions(-) create mode 100644 Source/Bake.Tests/UnitTests/Services/ChangeLogBuilderTests.cs create mode 100644 Source/Bake/IChangeLogBuilder.cs create mode 100644 Source/Bake/Services/ChangeLogBuilder.cs create mode 100644 Source/Bake/ValueObjects/ChangeType.cs diff --git a/Source/Bake.Tests/ExplicitTests/GitHubTests.cs b/Source/Bake.Tests/ExplicitTests/GitHubTests.cs index 2792b2a2..747cb18b 100644 --- a/Source/Bake.Tests/ExplicitTests/GitHubTests.cs +++ b/Source/Bake.Tests/ExplicitTests/GitHubTests.cs @@ -1,6 +1,6 @@ -// MIT License +// MIT License // -// Copyright (c) 2021 Rasmus Mikkelsen +// Copyright (c) 2021-2023 Rasmus Mikkelsen // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -68,7 +68,7 @@ public async Task GetPullRequests() foreach (var pullRequest in pullRequests) { - Console.WriteLine($"{pullRequest.Title}"); + Console.WriteLine($"new ({pullRequest.Number}, \"{pullRequest.Title}\"),"); } } diff --git a/Source/Bake.Tests/UnitTests/Services/ChangeLogBuilderTests.cs b/Source/Bake.Tests/UnitTests/Services/ChangeLogBuilderTests.cs new file mode 100644 index 00000000..6336db33 --- /dev/null +++ b/Source/Bake.Tests/UnitTests/Services/ChangeLogBuilderTests.cs @@ -0,0 +1,106 @@ +// MIT License +// +// Copyright (c) 2021-2023 Rasmus Mikkelsen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +using System.Collections.Generic; +using Bake.Services; +using Bake.Tests.Helpers; +using Bake.ValueObjects; + +namespace Bake.Tests.UnitTests.Services +{ + public class ChangeLogBuilderTests : TestFor + { + private static IReadOnlyCollection Get() + { + return new PullRequest[] + { + new (236, "Bump NuGet.Packaging from 6.6.0 to 6.6.1"), + new (235, "Post release fixes"), + new (237, "Bump YamlDotNet from 13.1.0 to 13.1.1"), + new (240, "Bump WireMock.Net from 1.5.28 to 1.5.29"), + new (241, "Bump semver from 7.5.1 to 7.5.3 in /TestProjects/NodeJS.Service"), + new (239, "Bump Octokit from 6.0.0 to 6.1.0"), + new (242, "Bump WireMock.Net from 1.5.29 to 1.5.30"), + new (243, "Bump Microsoft.NET.Test.Sdk from 17.6.2 to 17.6.3"), + new (244, "Bump Octokit from 6.1.0 to 6.2.1"), + new (246, "Bump fastify from 4.18.0 to 4.19.1 in /TestProjects/NodeJS.Service"), + new (248, "Bump fastify from 4.19.1 to 4.19.2 in /TestProjects/NodeJS.Service"), + new (247, "Bump Octokit from 6.2.1 to 7.0.0"), + new (249, "Bump Octokit from 7.0.0 to 7.0.1"), + new (250, "Bump WireMock.Net from 1.5.30 to 1.5.31"), + new (252, "Bump github.com/labstack/echo/v4 from 4.10.2 to 4.11.1 in /TestProjects/GoLang.Service"), + new (254, "Bump fastify from 4.19.2 to 4.20.0 in /TestProjects/NodeJS.Service"), + new (255, "Bump Octokit from 7.0.1 to 7.1.0"), + new (253, "Bump WireMock.Net from 1.5.31 to 1.5.32"), + new (256, "Bump fastify from 4.20.0 to 4.21.0 in /TestProjects/NodeJS.Service"), + new (259, "Bump Microsoft.NET.Test.Sdk from 17.6.3 to 17.7.0"), + new (258, "Bump WireMock.Net from 1.5.32 to 1.5.34"), + new (260, "Remove moq"), + new (261, "Bump NuGet.Packaging from 6.6.1 to 6.7.0"), + new (262, "Bump YamlDotNet from 13.1.1 to 13.2.0"), + new (263, "Bump Microsoft.NET.Test.Sdk from 17.7.0 to 17.7.1"), + new (264, "Bump WireMock.Net from 1.5.34 to 1.5.35"), + new (265, "Bump flask from 2.3.2 to 2.3.3 in /TestProjects/Python3.Flask"), + new (266, "Bump FluentAssertions from 6.11.0 to 6.12.0"), + new (267, "Bump fastify from 4.21.0 to 4.22.0 in /TestProjects/NodeJS.Service"), + new (269, "Bump YamlDotNet from 13.2.0 to 13.3.1"), + new (268, "Bump McMaster.Extensions.CommandLineUtils from 4.0.2 to 4.1.0"), + new (270, "Bump Microsoft.NET.Test.Sdk from 17.7.1 to 17.7.2"), + new (271, "Bump fastify from 4.22.0 to 4.22.1 in /TestProjects/NodeJS.Service"), + new (272, "Bump fastify from 4.22.1 to 4.22.2 in /TestProjects/NodeJS.Service"), + new (275, "Bump fastify from 4.22.2 to 4.23.0 in /TestProjects/NodeJS.Service"), + new (276, "Bump fastify from 4.23.0 to 4.23.1 in /TestProjects/NodeJS.Service"), + new (277, "Bump fastify from 4.23.1 to 4.23.2 in /TestProjects/NodeJS.Service"), + new (278, "Bump YamlDotNet from 13.3.1 to 13.4.0"), + new (279, "Bump WireMock.Net from 1.5.35 to 1.5.36"), + new (281, "Bump WireMock.Net from 1.5.36 to 1.5.37"), + new (284, "Bump YamlDotNet from 13.4.0 to 13.5.1"), + new (285, "Bump YamlDotNet from 13.5.1 to 13.5.2"), + new (286, "Bump WireMock.Net from 1.5.37 to 1.5.39"), + new (287, "Bump YamlDotNet from 13.5.2 to 13.7.0"), + new (288, "Bump github.com/labstack/echo/v4 from 4.11.1 to 4.11.2 in /TestProjects/GoLang.Service"), + new (289, "Bump fastify from 4.23.2 to 4.24.0 in /TestProjects/NodeJS.Service"), + new (291, "Bump fastify from 4.24.0 to 4.24.2 in /TestProjects/NodeJS.Service"), + new (293, "Bump fastify from 4.24.2 to 4.24.3 in /TestProjects/NodeJS.Service"), + new (294, "Bump actions/setup-node from 3 to 4"), + new (292, "Bump YamlDotNet from 13.7.0 to 13.7.1"), + new (282, "Bump flask from 2.3.3 to 3.0.0 in /TestProjects/Python3.Flask"), + new (296, "Bump LibGit2Sharp from 0.27.2 to 0.28.0"), + new (297, "Bump NUnit from 3.13.3 to 3.14.0"), + new (273, "Bump actions/checkout from 3 to 4"), + new (298, "Bump github.com/labstack/echo/v4 from 4.11.2 to 4.11.3 in /TestProjects/GoLang.Service"), + new (299, "Bump WireMock.Net from 1.5.39 to 1.5.40"), + new (300, "Bump Microsoft.NET.Test.Sdk from 17.7.2 to 17.8.0"), + new (308, "Update and test .NET 8"), + new (309, "Bump NuGet.Packaging from 6.7.0 to 6.8.0"), + new (311, "Bump actions/setup-dotnet from 3 to 4"), + new (313, "Bump actions/setup-go from 4 to 5"), + new (314, "Bump WireMock.Net from 1.5.40 to 1.5.42"), + new (315, "Bump LibGit2Sharp from 0.28.0 to 0.29.0"), + new (316, "Bump AutoFixture.AutoNSubstitute from 4.18.0 to 4.18.1"), + new (318, "Bump WireMock.Net from 1.5.42 to 1.5.43"), + new (312, "Bump actions/setup-python from 4 to 5"), + new (319, "Don't print commands"), + }; + } + } +} diff --git a/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs b/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs index 2796c0a9..cd0e1451 100644 --- a/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs +++ b/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs @@ -1,6 +1,6 @@ -// MIT License +// MIT License // -// Copyright (c) 2021 Rasmus Mikkelsen +// Copyright (c) 2021-2023 Rasmus Mikkelsen // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Source/Bake/Extensions/ServiceCollectionExtensions.cs b/Source/Bake/Extensions/ServiceCollectionExtensions.cs index 1355ca82..05270710 100644 --- a/Source/Bake/Extensions/ServiceCollectionExtensions.cs +++ b/Source/Bake/Extensions/ServiceCollectionExtensions.cs @@ -57,6 +57,7 @@ public static IServiceCollection AddBake( .AddSingleton() .AddTransient() .AddTransient() + .AddSingleton() .AddSingleton() .AddSingleton() .AddTransient() diff --git a/Source/Bake/IChangeLogBuilder.cs b/Source/Bake/IChangeLogBuilder.cs new file mode 100644 index 00000000..7b738ef2 --- /dev/null +++ b/Source/Bake/IChangeLogBuilder.cs @@ -0,0 +1,28 @@ +// MIT License +// +// Copyright (c) 2021-2023 Rasmus Mikkelsen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +namespace Bake +{ + public interface IChangeLogBuilder + { + } +} diff --git a/Source/Bake/Services/ChangeLogBuilder.cs b/Source/Bake/Services/ChangeLogBuilder.cs new file mode 100644 index 00000000..eddeb35b --- /dev/null +++ b/Source/Bake/Services/ChangeLogBuilder.cs @@ -0,0 +1,41 @@ +// MIT License +// +// Copyright (c) 2021-2023 Rasmus Mikkelsen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using Bake.ValueObjects; + +namespace Bake.Services +{ + public class ChangeLogBuilder : IChangeLogBuilder + { + private static readonly Regex DependencyDetector = new( + @"Bump (?[^s]+) from (?[0-9\.\-a-z]+) to (?[0-9\.\-a-z]+)( (?[a-z\-\.0-9])){0,1}", + RegexOptions.Compiled | RegexOptions.IgnoreCase); + + public IReadOnlyCollection Build(IReadOnlyCollection pullRequests) + { + return ArraySegment.Empty; + } + } +} diff --git a/Source/Bake/ValueObjects/Author.cs b/Source/Bake/ValueObjects/Author.cs index 9e26c824..2fd02e40 100644 --- a/Source/Bake/ValueObjects/Author.cs +++ b/Source/Bake/ValueObjects/Author.cs @@ -1,6 +1,6 @@ -// MIT License +// MIT License // -// Copyright (c) 2021 Rasmus Mikkelsen +// Copyright (c) 2021-2023 Rasmus Mikkelsen // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Source/Bake/ValueObjects/Change.cs b/Source/Bake/ValueObjects/Change.cs index 88566e13..51a015d9 100644 --- a/Source/Bake/ValueObjects/Change.cs +++ b/Source/Bake/ValueObjects/Change.cs @@ -1,6 +1,6 @@ -// MIT License +// MIT License // -// Copyright (c) 2021 Rasmus Mikkelsen +// Copyright (c) 2021-2023 Rasmus Mikkelsen // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,6 +27,9 @@ namespace Bake.ValueObjects { public class Change { + [YamlMember] + public ChangeType Type { get; [Obsolete] set; } + [YamlMember] public string Text { get; [Obsolete] set; } @@ -34,9 +37,11 @@ public class Change public Change() { } public Change( + ChangeType type, string text) { #pragma warning disable CS0612 // Type or member is obsolete + Type = type; Text = text; #pragma warning restore CS0612 // Type or member is obsolete } diff --git a/Source/Bake/ValueObjects/ChangeType.cs b/Source/Bake/ValueObjects/ChangeType.cs new file mode 100644 index 00000000..6c26fb05 --- /dev/null +++ b/Source/Bake/ValueObjects/ChangeType.cs @@ -0,0 +1,30 @@ +// MIT License +// +// Copyright (c) 2021-2023 Rasmus Mikkelsen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +namespace Bake.ValueObjects +{ + public enum ChangeType + { + Other = 0, + Dependency = 1, + } +} diff --git a/Source/Bake/ValueObjects/Commit.cs b/Source/Bake/ValueObjects/Commit.cs index 40e5a427..5fe066d3 100644 --- a/Source/Bake/ValueObjects/Commit.cs +++ b/Source/Bake/ValueObjects/Commit.cs @@ -1,6 +1,6 @@ -// MIT License +// MIT License // -// Copyright (c) 2021 Rasmus Mikkelsen +// Copyright (c) 2021-2023 Rasmus Mikkelsen // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Source/Bake/ValueObjects/PullRequest.cs b/Source/Bake/ValueObjects/PullRequest.cs index d016c5f4..97338b37 100644 --- a/Source/Bake/ValueObjects/PullRequest.cs +++ b/Source/Bake/ValueObjects/PullRequest.cs @@ -1,6 +1,6 @@ -// MIT License +// MIT License // -// Copyright (c) 2023 Rasmus Mikkelsen +// Copyright (c) 2021-2023 Rasmus Mikkelsen // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/TestProjects/NetV8.Service/Source/Program.cs b/TestProjects/NetV8.Service/Source/Program.cs index 1785f550..2ba9b723 100644 --- a/TestProjects/NetV8.Service/Source/Program.cs +++ b/TestProjects/NetV8.Service/Source/Program.cs @@ -1,4 +1,26 @@ -var builder = WebApplication.CreateBuilder(args); +// MIT License +// +// Copyright (c) 2021-2023 Rasmus Mikkelsen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet("/ping", () => "Pong!"); From 5291f60892919e8170d1fb9b2bfdf159b9fd6ab0 Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Wed, 20 Dec 2023 17:20:37 +0100 Subject: [PATCH 10/21] More --- Source/Bake/Services/ChangeLogBuilder.cs | 29 ++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Source/Bake/Services/ChangeLogBuilder.cs b/Source/Bake/Services/ChangeLogBuilder.cs index eddeb35b..6850c0b1 100644 --- a/Source/Bake/Services/ChangeLogBuilder.cs +++ b/Source/Bake/Services/ChangeLogBuilder.cs @@ -22,7 +22,9 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text.RegularExpressions; +using Bake.Core; using Bake.ValueObjects; namespace Bake.Services @@ -35,6 +37,33 @@ public class ChangeLogBuilder : IChangeLogBuilder public IReadOnlyCollection Build(IReadOnlyCollection pullRequests) { + var dependencies = pullRequests + .Select(pr => new + { + match = DependencyDetector.Match(pr.Title), + pullRequest = pr, + }) + .Where(a => a.match.Success) + .Select(a => new + { + from = SemVer.Parse(a.match.Groups["from"].Value), + to = SemVer.Parse(a.match.Groups["to"].Value), + dependency = a.match.Groups["name"].Value, + project = a.match.Groups["project"].Value, + pullRequestNumber = a.pullRequest.Number, + }) + .GroupBy(a => new { a.dependency, a.project }) + .Select(g => new + { + from = g.Min(a => a.from), + to = g.Max(a => a.to), + g.Key.dependency, + g.Key.project, + pullRequestNumbers = g.Select(a => a.pullRequestNumber).ToArray(), + }) + .OrderBy(a => a.project) + .ThenBy(a => a.dependency); + return ArraySegment.Empty; } } From 7f8bca76922144907b8ec7b2b0ca13c3c00fbb78 Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Wed, 20 Dec 2023 23:53:47 +0100 Subject: [PATCH 11/21] Simpler changelog --- .../Services/ChangeLogBuilderTests.cs | 11 +++ Source/Bake/Services/ChangeLogBuilder.cs | 79 +++++++++++++------ Source/Bake/ValueObjects/Change.cs | 5 ++ 3 files changed, 70 insertions(+), 25 deletions(-) diff --git a/Source/Bake.Tests/UnitTests/Services/ChangeLogBuilderTests.cs b/Source/Bake.Tests/UnitTests/Services/ChangeLogBuilderTests.cs index 6336db33..75779e33 100644 --- a/Source/Bake.Tests/UnitTests/Services/ChangeLogBuilderTests.cs +++ b/Source/Bake.Tests/UnitTests/Services/ChangeLogBuilderTests.cs @@ -24,11 +24,22 @@ using Bake.Services; using Bake.Tests.Helpers; using Bake.ValueObjects; +using NUnit.Framework; namespace Bake.Tests.UnitTests.Services { public class ChangeLogBuilderTests : TestFor { + [Test] + public void T() + { + // Arrange + var pullRequests = Get(); + + // Act + var changes = Sut.Build(pullRequests); + } + private static IReadOnlyCollection Get() { return new PullRequest[] diff --git a/Source/Bake/Services/ChangeLogBuilder.cs b/Source/Bake/Services/ChangeLogBuilder.cs index 6850c0b1..f82129c6 100644 --- a/Source/Bake/Services/ChangeLogBuilder.cs +++ b/Source/Bake/Services/ChangeLogBuilder.cs @@ -32,39 +32,68 @@ namespace Bake.Services public class ChangeLogBuilder : IChangeLogBuilder { private static readonly Regex DependencyDetector = new( - @"Bump (?[^s]+) from (?[0-9\.\-a-z]+) to (?[0-9\.\-a-z]+)( (?[a-z\-\.0-9])){0,1}", + @"Bump (?[^s]+) from (?[0-9\.\-a-z]+) to (?[0-9\.\-a-z]+)( (?[a-z\-\.0-9/\\]+)){0,1}", RegexOptions.Compiled | RegexOptions.IgnoreCase); public IReadOnlyCollection Build(IReadOnlyCollection pullRequests) { - var dependencies = pullRequests - .Select(pr => new + var dependencyChanges = + from pr in pullRequests + let m = DependencyDetector.Match(pr.Title) + where m.Success + let p = m.Groups["project"] + let a = new { - match = DependencyDetector.Match(pr.Title), - pullRequest = pr, - }) - .Where(a => a.match.Success) - .Select(a => new - { - from = SemVer.Parse(a.match.Groups["from"].Value), - to = SemVer.Parse(a.match.Groups["to"].Value), - dependency = a.match.Groups["name"].Value, - project = a.match.Groups["project"].Value, - pullRequestNumber = a.pullRequest.Number, - }) - .GroupBy(a => new { a.dependency, a.project }) - .Select(g => new - { - from = g.Min(a => a.from), - to = g.Max(a => a.to), + fromVersion = SemVer.Parse(m.Groups["from"].Value), + to = SemVer.Parse(m.Groups["to"].Value), + dependency = m.Groups["name"].Value, + project = p.Success ? p.Value : string.Empty, + pr, + } + group a by new {a.dependency, a.project} + into g + orderby g.Key.project, g.Key.dependency + + select new DependencyChange( g.Key.dependency, g.Key.project, - pullRequestNumbers = g.Select(a => a.pullRequestNumber).ToArray(), - }) - .OrderBy(a => a.project) - .ThenBy(a => a.dependency); + g.Select(x => x.pr.Number).OrderBy(i => i).ToArray(), + g.Min(x => x.fromVersion), + g.Max(x => x.to)); + + return dependencyChanges + .Select(d => d.ToChange()) + .ToArray(); + } + + private class DependencyChange + { + public string Name { get; } + public string Project { get; } + public int[] PullRequests { get; } + public SemVer From { get; } + public SemVer To { get; } + + public DependencyChange( + string name, + string project, + int[] pullRequests, + SemVer from, + SemVer to) + { + Name = name; + Project = project; + PullRequests = pullRequests; + From = from; + To = to; + } - return ArraySegment.Empty; + public Change ToChange() + { + return new Change( + ChangeType.Dependency, + $"Bump {Name} {From} to {To} ({string.Join(", ", PullRequests.Select(pr => $"#{pr}"))})"); + } } } } diff --git a/Source/Bake/ValueObjects/Change.cs b/Source/Bake/ValueObjects/Change.cs index 51a015d9..c12145b5 100644 --- a/Source/Bake/ValueObjects/Change.cs +++ b/Source/Bake/ValueObjects/Change.cs @@ -45,5 +45,10 @@ public Change( Text = text; #pragma warning restore CS0612 // Type or member is obsolete } + + public override string ToString() + { + return $"{Type}: {Text}"; + } } } From be27274509e4fc0e55a388921284ad2dc3ce72a5 Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Thu, 21 Dec 2023 00:03:43 +0100 Subject: [PATCH 12/21] Minor --- Source/Bake/Services/ChangeLogBuilder.cs | 23 +++++++++++++++++------ Source/Bake/ValueObjects/PullRequest.cs | 5 +++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Source/Bake/Services/ChangeLogBuilder.cs b/Source/Bake/Services/ChangeLogBuilder.cs index f82129c6..03bd89e8 100644 --- a/Source/Bake/Services/ChangeLogBuilder.cs +++ b/Source/Bake/Services/ChangeLogBuilder.cs @@ -20,7 +20,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; @@ -32,12 +31,13 @@ namespace Bake.Services public class ChangeLogBuilder : IChangeLogBuilder { private static readonly Regex DependencyDetector = new( - @"Bump (?[^s]+) from (?[0-9\.\-a-z]+) to (?[0-9\.\-a-z]+)( (?[a-z\-\.0-9/\\]+)){0,1}", + @"Bump (?[^s]+) from (?[0-9\.\-a-z]+) to (?[0-9\.\-a-z]+)( in (?[a-z\-\.0-9\/\\]+)){0,1}", RegexOptions.Compiled | RegexOptions.IgnoreCase); public IReadOnlyCollection Build(IReadOnlyCollection pullRequests) { var dependencyChanges = + ( from pr in pullRequests let m = DependencyDetector.Match(pr.Title) where m.Success @@ -53,16 +53,27 @@ where m.Success group a by new {a.dependency, a.project} into g orderby g.Key.project, g.Key.dependency - select new DependencyChange( g.Key.dependency, g.Key.project, g.Select(x => x.pr.Number).OrderBy(i => i).ToArray(), g.Min(x => x.fromVersion), - g.Max(x => x.to)); + g.Max(x => x.to)) + ).ToArray(); + + var dependencyPRs = new HashSet(dependencyChanges.SelectMany(d => d.PullRequests)); + + var otherChanges = pullRequests + .Where(pr => !dependencyPRs.Contains(pr.Number)) + .OrderBy(pr => pr.Number) + .Select(pr => pr.ToChange()) + .ToArray(); + + // TODO: Use dictionary instead - return dependencyChanges - .Select(d => d.ToChange()) + return Enumerable.Empty() + .Concat(dependencyChanges.Select(d => d.ToChange())) + .Concat(otherChanges) .ToArray(); } diff --git a/Source/Bake/ValueObjects/PullRequest.cs b/Source/Bake/ValueObjects/PullRequest.cs index 97338b37..02c71c7c 100644 --- a/Source/Bake/ValueObjects/PullRequest.cs +++ b/Source/Bake/ValueObjects/PullRequest.cs @@ -35,6 +35,11 @@ public PullRequest( Title = title; } + public Change ToChange() + { + return new Change(ChangeType.Other, $"{Title} (#{Number})"); + } + public override string ToString() { return $"#{Number}: {Title}"; From 94f6fbbef331efd2d875de56c47beaaada850e8f Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Sat, 6 Jan 2024 21:14:28 +0100 Subject: [PATCH 13/21] All bumps parsed --- .../Bake.Tests/UnitTests/Core/SemVerTests.cs | 12 +++-- Source/Bake/Core/SemVer.cs | 43 +++++++++------ Source/Bake/Services/ChangeLogBuilder.cs | 54 ++++++++++--------- 3 files changed, 64 insertions(+), 45 deletions(-) diff --git a/Source/Bake.Tests/UnitTests/Core/SemVerTests.cs b/Source/Bake.Tests/UnitTests/Core/SemVerTests.cs index d5c36edb..bafc360e 100644 --- a/Source/Bake.Tests/UnitTests/Core/SemVerTests.cs +++ b/Source/Bake.Tests/UnitTests/Core/SemVerTests.cs @@ -35,6 +35,12 @@ public class SemVerTests 2, null, null)] + [TestCase( + "3", + 3, + null, + null, + null)] [TestCase( "1.2.3-meta", 1, @@ -62,12 +68,12 @@ public class SemVerTests public void ValidVersions( string str, int expectedMajor, - int expectedMinor, + int? expectedMinor, int? expectedPatch, string expectedMeta) { // Act - var version = SemVer.Parse(str); + var version = SemVer.Parse(str, true); // Assert version.Major.Should().Be(expectedMajor); @@ -117,7 +123,7 @@ public void Compare( { // Act var list = versions - .Select(SemVer.Parse) + .Select(s => SemVer.Parse(s)) .OrderBy(v => v); // Assert diff --git a/Source/Bake/Core/SemVer.cs b/Source/Bake/Core/SemVer.cs index efb0f4ac..7172fbdd 100644 --- a/Source/Bake/Core/SemVer.cs +++ b/Source/Bake/Core/SemVer.cs @@ -29,7 +29,7 @@ namespace Bake.Core public class SemVer : IComparable, IEquatable, IComparable { private static readonly Regex VersionParser = new( - @"^(v|version){0,1}\s*(?\d+)\.(?\d+)(\.(?\d+)){0,1}(\-(?[a-z0-9\-_]+)){0,1}$", + @"^(v|version){0,1}\s*(?\d+)(\.(?\d+)(\.(?\d+)){0,1}){0,1}(\-(?[a-z0-9\-_]+)){0,1}$", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Random R = new(); @@ -42,9 +42,9 @@ public class SemVer : IComparable, IEquatable, IComparable ? string.Empty : "meta"); - public static SemVer Parse(string str) + public static SemVer Parse(string str, bool allowNoMinor = false) { - var exception = InternalTryParse(str, out var version); + var exception = InternalTryParse(str, out var version, allowNoMinor); if (exception != null) { throw exception; @@ -53,14 +53,15 @@ public static SemVer Parse(string str) return version; } - public static bool TryParse(string str, out SemVer version) + public static bool TryParse(string str, out SemVer version, bool allowNoMinor = false) { - return InternalTryParse(str, out version) == null; + return InternalTryParse(str, out version, allowNoMinor) == null; } public static Exception InternalTryParse( string str, - out SemVer version) + out SemVer version, + bool allowNoMinor) { version = null; if (string.IsNullOrEmpty(str)) @@ -74,8 +75,16 @@ public static Exception InternalTryParse( return new ArgumentException($"'{str}' is not a valid version string"); } + var minorSuccess = match.Groups["minor"].Success; + if (!minorSuccess && !allowNoMinor) + { + return new ArgumentException($"'{str}' is not a valid version string"); + } + var major = int.Parse(match.Groups["major"].Value); - var minor = int.Parse(match.Groups["minor"].Value); + var minor = minorSuccess + ? int.Parse(match.Groups["minor"].Value) + : null as int?; var patch = match.Groups["patch"].Success ? int.Parse(match.Groups["patch"].Value) : null as int?; @@ -92,16 +101,17 @@ public static Exception InternalTryParse( return null; } - public static SemVer With(int major, - int minor = 0, - int patch = 0, + public static SemVer With( + int major, + int? minor = 0, + int? patch = 0, string meta = null) { return new SemVer(major, minor, patch, meta); } public int Major { get; } - public int Minor { get; } + public int? Minor { get; } public int? Patch { get; } public string Meta { get; } public Version LegacyVersion { get; } @@ -111,7 +121,7 @@ public static SemVer With(int major, private SemVer( int major, - int minor, + int? minor, int? patch , string meta) { @@ -120,12 +130,13 @@ private SemVer( Patch = patch; Meta = (meta ?? string.Empty).Trim('-'); LegacyVersion = patch.HasValue - ? new Version(major, minor, patch.Value) - : new Version(major, minor); + ? new Version(major, minor ?? 0, patch.Value) + : new Version(major, minor ?? 0); _lazyString = new Lazy(() => new StringBuilder() - .Append($"{Major}.{Minor}") + .Append($"{Major}") + .Append(Minor.HasValue ? $".{Minor}" : string.Empty) .Append(Patch.HasValue ? $".{Patch}" : string.Empty) .Append(!string.IsNullOrEmpty(Meta) ? $"-{Meta}" : string.Empty) .ToString()); @@ -169,7 +180,7 @@ public int CompareTo(SemVer other) if (ReferenceEquals(null, other)) return 1; var majorComparison = Major.CompareTo(other.Major); if (majorComparison != 0) return majorComparison; - var minorComparison = Minor.CompareTo(other.Minor); + var minorComparison = Minor.GetValueOrDefault().CompareTo(other.Patch.GetValueOrDefault()); if (minorComparison != 0) return minorComparison; var patchComparison = Patch.GetValueOrDefault().CompareTo(other.Patch.GetValueOrDefault()); if (patchComparison != 0) return patchComparison; diff --git a/Source/Bake/Services/ChangeLogBuilder.cs b/Source/Bake/Services/ChangeLogBuilder.cs index 03bd89e8..15745d4a 100644 --- a/Source/Bake/Services/ChangeLogBuilder.cs +++ b/Source/Bake/Services/ChangeLogBuilder.cs @@ -31,34 +31,34 @@ namespace Bake.Services public class ChangeLogBuilder : IChangeLogBuilder { private static readonly Regex DependencyDetector = new( - @"Bump (?[^s]+) from (?[0-9\.\-a-z]+) to (?[0-9\.\-a-z]+)( in (?[a-z\-\.0-9\/\\]+)){0,1}", + @"Bump (?[^\s]+) from (?[0-9\.\-a-z]+) to (?[0-9\.\-a-z]+)( in (?[^\s]+)){0,1}", RegexOptions.Compiled | RegexOptions.IgnoreCase); public IReadOnlyCollection Build(IReadOnlyCollection pullRequests) { var dependencyChanges = ( - from pr in pullRequests - let m = DependencyDetector.Match(pr.Title) - where m.Success - let p = m.Groups["project"] - let a = new - { - fromVersion = SemVer.Parse(m.Groups["from"].Value), - to = SemVer.Parse(m.Groups["to"].Value), - dependency = m.Groups["name"].Value, - project = p.Success ? p.Value : string.Empty, - pr, - } - group a by new {a.dependency, a.project} - into g - orderby g.Key.project, g.Key.dependency - select new DependencyChange( - g.Key.dependency, - g.Key.project, - g.Select(x => x.pr.Number).OrderBy(i => i).ToArray(), - g.Min(x => x.fromVersion), - g.Max(x => x.to)) + from pr in pullRequests + let m = DependencyDetector.Match(pr.Title) + where m.Success + let p = m.Groups["project"] + let a = new + { + fromVersion = SemVer.Parse(m.Groups["from"].Value, true), + to = SemVer.Parse(m.Groups["to"].Value, true), + dependency = m.Groups["name"].Value, + project = p.Success ? p.Value : string.Empty, + pr, + } + group a by new { a.dependency, a.project } + into g + orderby g.Key.project, g.Key.dependency + select new DependencyChange( + g.Key.dependency, + g.Key.project, + g.Select(x => x.pr.Number).OrderBy(i => i).ToArray(), + g.Min(x => x.fromVersion), + g.Max(x => x.to)) ).ToArray(); var dependencyPRs = new HashSet(dependencyChanges.SelectMany(d => d.PullRequests)); @@ -73,7 +73,7 @@ into g return Enumerable.Empty() .Concat(dependencyChanges.Select(d => d.ToChange())) - .Concat(otherChanges) + //.Concat(otherChanges) .ToArray(); } @@ -101,9 +101,11 @@ public DependencyChange( public Change ToChange() { - return new Change( - ChangeType.Dependency, - $"Bump {Name} {From} to {To} ({string.Join(", ", PullRequests.Select(pr => $"#{pr}"))})"); + var message = string.IsNullOrEmpty(Project) + ? $"Bump {Name} {From} to {To} ({string.Join(", ", PullRequests.Select(pr => $"#{pr}"))})" + : $"Bump {Name} {From} to {To} in {Project} ({string.Join(", ", PullRequests.Select(pr => $"#{pr}"))})"; + + return new Change(ChangeType.Dependency, message); } } } From 6252b3feb220da59cb175835d12ede62d8347aa0 Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Sat, 6 Jan 2024 21:22:12 +0100 Subject: [PATCH 14/21] Minor changes --- Source/Bake/Services/ChangeLogBuilder.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Source/Bake/Services/ChangeLogBuilder.cs b/Source/Bake/Services/ChangeLogBuilder.cs index 15745d4a..0afa6b8a 100644 --- a/Source/Bake/Services/ChangeLogBuilder.cs +++ b/Source/Bake/Services/ChangeLogBuilder.cs @@ -34,7 +34,7 @@ public class ChangeLogBuilder : IChangeLogBuilder @"Bump (?[^\s]+) from (?[0-9\.\-a-z]+) to (?[0-9\.\-a-z]+)( in (?[^\s]+)){0,1}", RegexOptions.Compiled | RegexOptions.IgnoreCase); - public IReadOnlyCollection Build(IReadOnlyCollection pullRequests) + public IReadOnlyDictionary> Build(IReadOnlyCollection pullRequests) { var dependencyChanges = ( @@ -59,7 +59,9 @@ into g g.Select(x => x.pr.Number).OrderBy(i => i).ToArray(), g.Min(x => x.fromVersion), g.Max(x => x.to)) - ).ToArray(); + ) + .OrderBy(c => c.Name) + .ToArray(); var dependencyPRs = new HashSet(dependencyChanges.SelectMany(d => d.PullRequests)); @@ -69,12 +71,11 @@ into g .Select(pr => pr.ToChange()) .ToArray(); - // TODO: Use dictionary instead - - return Enumerable.Empty() - .Concat(dependencyChanges.Select(d => d.ToChange())) - //.Concat(otherChanges) - .ToArray(); + return new Dictionary> + { + [ChangeType.Other] = otherChanges, + [ChangeType.Dependency] = dependencyChanges.Select(d => d.ToChange()).ToArray(), + }; } private class DependencyChange From b1d9d1fc55fd2e23fe77b4d594eecb2adde7f782 Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Sat, 6 Jan 2024 21:48:51 +0100 Subject: [PATCH 15/21] Build change log --- .../Bake.Tests/ExplicitTests/GitHubTests.cs | 6 ++- Source/Bake.Tests/Helpers/BakeTest.cs | 14 ++++-- .../Cooking/Cooks/GitHub/GitHubReleaseCook.cs | 17 ++++++- .../Ingredients/Gathers/ChangelogGather.cs | 25 +++++++++-- Source/Bake/IChangeLogBuilder.cs | 4 ++ Source/Bake/Services/GitHub.cs | 45 ++++++++++++------- Source/Bake/Services/IGitHub.cs | 11 +++-- Source/Bake/ValueObjects/Ingredients.cs | 6 +-- Source/Bake/ValueObjects/Release.cs | 7 +-- Source/Bake/ValueObjects/Tag.cs | 45 +++++++++++++++++++ 10 files changed, 141 insertions(+), 39 deletions(-) create mode 100644 Source/Bake/ValueObjects/Tag.cs diff --git a/Source/Bake.Tests/ExplicitTests/GitHubTests.cs b/Source/Bake.Tests/ExplicitTests/GitHubTests.cs index 747cb18b..052bf15c 100644 --- a/Source/Bake.Tests/ExplicitTests/GitHubTests.cs +++ b/Source/Bake.Tests/ExplicitTests/GitHubTests.cs @@ -45,7 +45,8 @@ public GitHubTests() : base(null) { } public async Task GetCommits() { var commits = await Sut.GetCommitsAsync( - "662965e", + "e1b486d", + "c54a03b", new GitHubInformation( "rasmus", "Bake", @@ -58,7 +59,8 @@ public async Task GetCommits() public async Task GetPullRequests() { var pullRequests = await Sut.GetPullRequestsAsync( - "662965e", + "e1b486d", + "c54a03b", new GitHubInformation( "rasmus", "Bake", diff --git a/Source/Bake.Tests/Helpers/BakeTest.cs b/Source/Bake.Tests/Helpers/BakeTest.cs index 56199c8f..3cf409a5 100644 --- a/Source/Bake.Tests/Helpers/BakeTest.cs +++ b/Source/Bake.Tests/Helpers/BakeTest.cs @@ -136,8 +136,7 @@ public Task GetPullRequestInformationAsync( return Task.FromResult(null); } - public Task> GetCommitsAsync( - string sha, + public Task> GetCommitsAsync(string baseSha, string headSha, GitHubInformation gitHubInformation, CancellationToken cancellationToken) { @@ -150,8 +149,8 @@ public Task> GetCommitsAsync( return Task.FromResult>(commits); } - public Task> GetPullRequestsAsync( - string sha, + public Task> GetPullRequestsAsync(string baseSha, + string headSha, GitHubInformation gitHubInformation, CancellationToken cancellationToken) { @@ -165,6 +164,13 @@ public Task GetPullRequestAsync( { throw new NotImplementedException(); } + + public Task> GetTagsAsync( + GitHubInformation gitHubInformation, + CancellationToken cancellationToken) + { + return Task.FromResult>(Array.Empty()); + } } } } diff --git a/Source/Bake/Cooking/Cooks/GitHub/GitHubReleaseCook.cs b/Source/Bake/Cooking/Cooks/GitHub/GitHubReleaseCook.cs index 1a6f47fe..a347d3f7 100644 --- a/Source/Bake/Cooking/Cooks/GitHub/GitHubReleaseCook.cs +++ b/Source/Bake/Cooking/Cooks/GitHub/GitHubReleaseCook.cs @@ -95,9 +95,22 @@ protected override async Task CookAsync( if (context.Ingredients.Changelog != null && context.Ingredients.Changelog.Any()) { - foreach (var commit in context.Ingredients.Changelog) + foreach (var (changeType, title) in new Dictionary + { + [ChangeType.Dependency] = "Updated dependencies", + [ChangeType.Other] = "Other changes", + }) { - stringBuilder.AppendLine($"* {commit.Text}"); + stringBuilder + .AppendLine($"#### {title}") + .AppendLine(); + + foreach (var change in context.Ingredients.Changelog[changeType]) + { + stringBuilder.AppendLine($"* {change.Text}"); + } + + stringBuilder.AppendLine(); } stringBuilder.AppendLine(); diff --git a/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs b/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs index cd0e1451..27bf5698 100644 --- a/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs +++ b/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs @@ -22,7 +22,6 @@ using System; using System.Linq; -using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Bake.Services; @@ -33,11 +32,14 @@ namespace Bake.Cooking.Ingredients.Gathers public class ChangelogGather : IGather { private readonly IGitHub _gitHub; + private readonly IChangeLogBuilder _changeLogBuilder; public ChangelogGather( - IGitHub gitHub) + IGitHub gitHub, + IChangeLogBuilder changeLogBuilder) { _gitHub = gitHub; + _changeLogBuilder = changeLogBuilder; } public async Task GatherAsync( @@ -58,9 +60,26 @@ public async Task GatherAsync( return; } + var tags = await _gitHub.GetTagsAsync( + gitHubInformation, + cancellationToken); + var tag = tags + .Where(t => t.Version.LegacyVersion < ingredients.Version.LegacyVersion) + .MaxBy(t => t.Version); - // TODO: + if (tag == null) + { + ingredients.FailChangelog(); + return; + } + + var pullRequests = await _gitHub.GetPullRequestsAsync( + tag.Sha, + gitInformation.Sha, + gitHubInformation, cancellationToken); + + ingredients.Changelog = _changeLogBuilder.Build(pullRequests); } } } diff --git a/Source/Bake/IChangeLogBuilder.cs b/Source/Bake/IChangeLogBuilder.cs index 7b738ef2..c600274e 100644 --- a/Source/Bake/IChangeLogBuilder.cs +++ b/Source/Bake/IChangeLogBuilder.cs @@ -20,9 +20,13 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +using System.Collections.Generic; +using Bake.ValueObjects; + namespace Bake { public interface IChangeLogBuilder { + IReadOnlyDictionary> Build(IReadOnlyCollection pullRequests); } } diff --git a/Source/Bake/Services/GitHub.cs b/Source/Bake/Services/GitHub.cs index 820aa38a..2b0335e8 100644 --- a/Source/Bake/Services/GitHub.cs +++ b/Source/Bake/Services/GitHub.cs @@ -97,6 +97,27 @@ await gitHubClient.Repository.Release.Edit( gitHubReleaseUpdate); } + public async Task> GetTagsAsync( + GitHubInformation gitHubInformation, + CancellationToken cancellationToken) + { + var gitHubClient = await CreateGitHubClientAsync(gitHubInformation, cancellationToken); + + var releases = await gitHubClient.Repository.GetAllTags( + gitHubInformation.Owner, + gitHubInformation.Repository); + + return releases + .Select(t => new + { + version = SemVer.TryParse(t.Name, out var v, true) ? v : null, + tag = t, + }) + .Where(a => a.version != null) + .Select(a => new Tag(a.version, a.tag.Commit.Sha)) + .ToArray(); + } + public async Task GetPullRequestInformationAsync( GitInformation gitInformation, GitHubInformation gitHubInformation, @@ -164,7 +185,8 @@ private async Task CreateGitHubClientAsync( } public async Task> GetCommitsAsync( - string sha, + string baseSha, + string headSha, GitHubInformation gitHubInformation, CancellationToken cancellationToken) { @@ -182,22 +204,11 @@ public async Task> GetCommitsAsync( gitHubInformation.ApiUrl, cancellationToken); - var branches = await gitHubClient.Repository.Branch.GetAll( - gitHubInformation.Owner, - gitHubInformation.Repository); - - // TODO: Use tags instead and find best tag closest to current version - var releaseBranch = branches.SingleOrDefault(b => string.Equals(b.Name, "release")); - if (releaseBranch == null) - { - return Array.Empty(); - } - var compareResult = await gitHubClient.Repository.Commit.Compare( gitHubInformation.Owner, gitHubInformation.Repository, - releaseBranch.Commit.Sha, - sha); + baseSha, + headSha); if (compareResult.AheadBy <= 0) { return Array.Empty(); @@ -215,12 +226,14 @@ public async Task> GetCommitsAsync( } public async Task> GetPullRequestsAsync( - string sha, + string baseSha, + string headSha, GitHubInformation gitHubInformation, CancellationToken cancellationToken) { var commits = await GetCommitsAsync( - sha, + baseSha, + headSha, gitHubInformation, cancellationToken); diff --git a/Source/Bake/Services/IGitHub.cs b/Source/Bake/Services/IGitHub.cs index 255db1d3..c1594430 100644 --- a/Source/Bake/Services/IGitHub.cs +++ b/Source/Bake/Services/IGitHub.cs @@ -39,13 +39,12 @@ Task GetPullRequestInformationAsync( GitHubInformation gitHubInformation, CancellationToken cancellationToken); - Task> GetCommitsAsync( - string sha, + Task> GetCommitsAsync(string baseSha, string headSha, GitHubInformation gitHubInformation, CancellationToken cancellationToken); - Task> GetPullRequestsAsync( - string sha, + Task> GetPullRequestsAsync(string baseSha, + string headSha, GitHubInformation gitHubInformation, CancellationToken cancellationToken); @@ -53,5 +52,9 @@ Task GetPullRequestAsync( GitHubInformation gitHubInformation, int number, CancellationToken cancellationToken); + + Task> GetTagsAsync( + GitHubInformation gitHubInformation, + CancellationToken cancellationToken); } } diff --git a/Source/Bake/ValueObjects/Ingredients.cs b/Source/Bake/ValueObjects/Ingredients.cs index 4c8ef6a8..7297450c 100644 --- a/Source/Bake/ValueObjects/Ingredients.cs +++ b/Source/Bake/ValueObjects/Ingredients.cs @@ -60,7 +60,7 @@ public static Ingredients New( public List Destinations { get; [Obsolete] set; } = new(); [YamlMember] - public List Changelog + public IReadOnlyDictionary> Changelog { get => _changelog.Task.IsCompletedSuccessfully ? _changelog.Task.Result : null; set @@ -165,7 +165,7 @@ [Obsolete] set public Task GitHubTask => _gitHub.Task; [YamlIgnore] - public Task> ChangelogTask => _changelog.Task; + public Task>> ChangelogTask => _changelog.Task; [YamlIgnore] public Task PullRequestTask => _pullRequest.Task; @@ -173,7 +173,7 @@ [Obsolete] set private readonly TaskCompletionSource _git = new(); private readonly TaskCompletionSource _releaseNotes = new(); private readonly TaskCompletionSource _gitHub = new(); - private readonly TaskCompletionSource> _changelog = new(); + private readonly TaskCompletionSource>> _changelog = new(); private readonly TaskCompletionSource _description = new(); private readonly TaskCompletionSource _pullRequest = new(); diff --git a/Source/Bake/ValueObjects/Release.cs b/Source/Bake/ValueObjects/Release.cs index 610ca82f..a7f0bf39 100644 --- a/Source/Bake/ValueObjects/Release.cs +++ b/Source/Bake/ValueObjects/Release.cs @@ -25,10 +25,8 @@ namespace Bake.ValueObjects { - public class Release + public class Release : Tag { - public SemVer Version { get; } - public string Sha { get; } public string Body { get; } public IReadOnlyCollection Files { get; } @@ -37,9 +35,8 @@ public Release( string sha, string body, IReadOnlyCollection files) + : base(version, sha) { - Version = version; - Sha = sha; Body = body; Files = files; } diff --git a/Source/Bake/ValueObjects/Tag.cs b/Source/Bake/ValueObjects/Tag.cs new file mode 100644 index 00000000..4832f30f --- /dev/null +++ b/Source/Bake/ValueObjects/Tag.cs @@ -0,0 +1,45 @@ +// MIT License +// +// Copyright (c) 2021-2023 Rasmus Mikkelsen +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +using Bake.Core; + +namespace Bake.ValueObjects +{ + public class Tag + { + public SemVer Version { get; } + public string Sha { get; } + + public Tag( + SemVer version, + string sha) + { + Version = version; + Sha = sha; + } + + public override string ToString() + { + return $"{Version}: {Sha}"; + } + } +} From b675b955fdddd7f4ca050993bb170be814a866ea Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Sat, 6 Jan 2024 21:53:22 +0100 Subject: [PATCH 16/21] A few SemVer fixes --- Source/Bake/Core/SemVer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Bake/Core/SemVer.cs b/Source/Bake/Core/SemVer.cs index 7172fbdd..45e491c3 100644 --- a/Source/Bake/Core/SemVer.cs +++ b/Source/Bake/Core/SemVer.cs @@ -180,7 +180,7 @@ public int CompareTo(SemVer other) if (ReferenceEquals(null, other)) return 1; var majorComparison = Major.CompareTo(other.Major); if (majorComparison != 0) return majorComparison; - var minorComparison = Minor.GetValueOrDefault().CompareTo(other.Patch.GetValueOrDefault()); + var minorComparison = Minor.GetValueOrDefault().CompareTo(other.Minor.GetValueOrDefault()); if (minorComparison != 0) return minorComparison; var patchComparison = Patch.GetValueOrDefault().CompareTo(other.Patch.GetValueOrDefault()); if (patchComparison != 0) return patchComparison; @@ -211,7 +211,7 @@ public override int GetHashCode() { return HashCode.Combine( Major, - Minor, + Minor.GetValueOrDefault(), Patch.GetValueOrDefault(), Meta); } From a4fa6f755f00b2b736d5bc0f66a02d3f7f3254c9 Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Mon, 8 Jan 2024 20:03:24 +0100 Subject: [PATCH 17/21] Updated release notes --- RELEASE_NOTES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 00ac926b..f51e14a1 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,7 @@ # 0.22-beta +* New: GitHub releases now have a description that contains the a summary + of all pull requests and issues that are part of the release * Fixed: Cleanup of the artifact post run report # 0.21-beta From 82988de664b1168e2e3c0143cdeda1018989db38 Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Mon, 8 Jan 2024 20:20:53 +0100 Subject: [PATCH 18/21] Print authors of PRs --- .../Bake.Tests/ExplicitTests/GitHubTests.cs | 3 +- .../Services/ChangeLogBuilderTests.cs | 144 ++++++++++-------- Source/Bake/Services/ChangeLogBuilder.cs | 22 ++- Source/Bake/Services/GitHub.cs | 10 +- Source/Bake/ValueObjects/PullRequest.cs | 12 +- 5 files changed, 114 insertions(+), 77 deletions(-) diff --git a/Source/Bake.Tests/ExplicitTests/GitHubTests.cs b/Source/Bake.Tests/ExplicitTests/GitHubTests.cs index 052bf15c..282ce765 100644 --- a/Source/Bake.Tests/ExplicitTests/GitHubTests.cs +++ b/Source/Bake.Tests/ExplicitTests/GitHubTests.cs @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Bake.Cooking.Cooks.GitHub; @@ -70,7 +71,7 @@ public async Task GetPullRequests() foreach (var pullRequest in pullRequests) { - Console.WriteLine($"new ({pullRequest.Number}, \"{pullRequest.Title}\"),"); + Console.WriteLine($"new ({pullRequest.Number}, \"{pullRequest.Title}\", new []{{\"{pullRequest.Authors.Single()}\"}}),"); } } diff --git a/Source/Bake.Tests/UnitTests/Services/ChangeLogBuilderTests.cs b/Source/Bake.Tests/UnitTests/Services/ChangeLogBuilderTests.cs index 75779e33..764f73b5 100644 --- a/Source/Bake.Tests/UnitTests/Services/ChangeLogBuilderTests.cs +++ b/Source/Bake.Tests/UnitTests/Services/ChangeLogBuilderTests.cs @@ -44,73 +44,83 @@ private static IReadOnlyCollection Get() { return new PullRequest[] { - new (236, "Bump NuGet.Packaging from 6.6.0 to 6.6.1"), - new (235, "Post release fixes"), - new (237, "Bump YamlDotNet from 13.1.0 to 13.1.1"), - new (240, "Bump WireMock.Net from 1.5.28 to 1.5.29"), - new (241, "Bump semver from 7.5.1 to 7.5.3 in /TestProjects/NodeJS.Service"), - new (239, "Bump Octokit from 6.0.0 to 6.1.0"), - new (242, "Bump WireMock.Net from 1.5.29 to 1.5.30"), - new (243, "Bump Microsoft.NET.Test.Sdk from 17.6.2 to 17.6.3"), - new (244, "Bump Octokit from 6.1.0 to 6.2.1"), - new (246, "Bump fastify from 4.18.0 to 4.19.1 in /TestProjects/NodeJS.Service"), - new (248, "Bump fastify from 4.19.1 to 4.19.2 in /TestProjects/NodeJS.Service"), - new (247, "Bump Octokit from 6.2.1 to 7.0.0"), - new (249, "Bump Octokit from 7.0.0 to 7.0.1"), - new (250, "Bump WireMock.Net from 1.5.30 to 1.5.31"), - new (252, "Bump github.com/labstack/echo/v4 from 4.10.2 to 4.11.1 in /TestProjects/GoLang.Service"), - new (254, "Bump fastify from 4.19.2 to 4.20.0 in /TestProjects/NodeJS.Service"), - new (255, "Bump Octokit from 7.0.1 to 7.1.0"), - new (253, "Bump WireMock.Net from 1.5.31 to 1.5.32"), - new (256, "Bump fastify from 4.20.0 to 4.21.0 in /TestProjects/NodeJS.Service"), - new (259, "Bump Microsoft.NET.Test.Sdk from 17.6.3 to 17.7.0"), - new (258, "Bump WireMock.Net from 1.5.32 to 1.5.34"), - new (260, "Remove moq"), - new (261, "Bump NuGet.Packaging from 6.6.1 to 6.7.0"), - new (262, "Bump YamlDotNet from 13.1.1 to 13.2.0"), - new (263, "Bump Microsoft.NET.Test.Sdk from 17.7.0 to 17.7.1"), - new (264, "Bump WireMock.Net from 1.5.34 to 1.5.35"), - new (265, "Bump flask from 2.3.2 to 2.3.3 in /TestProjects/Python3.Flask"), - new (266, "Bump FluentAssertions from 6.11.0 to 6.12.0"), - new (267, "Bump fastify from 4.21.0 to 4.22.0 in /TestProjects/NodeJS.Service"), - new (269, "Bump YamlDotNet from 13.2.0 to 13.3.1"), - new (268, "Bump McMaster.Extensions.CommandLineUtils from 4.0.2 to 4.1.0"), - new (270, "Bump Microsoft.NET.Test.Sdk from 17.7.1 to 17.7.2"), - new (271, "Bump fastify from 4.22.0 to 4.22.1 in /TestProjects/NodeJS.Service"), - new (272, "Bump fastify from 4.22.1 to 4.22.2 in /TestProjects/NodeJS.Service"), - new (275, "Bump fastify from 4.22.2 to 4.23.0 in /TestProjects/NodeJS.Service"), - new (276, "Bump fastify from 4.23.0 to 4.23.1 in /TestProjects/NodeJS.Service"), - new (277, "Bump fastify from 4.23.1 to 4.23.2 in /TestProjects/NodeJS.Service"), - new (278, "Bump YamlDotNet from 13.3.1 to 13.4.0"), - new (279, "Bump WireMock.Net from 1.5.35 to 1.5.36"), - new (281, "Bump WireMock.Net from 1.5.36 to 1.5.37"), - new (284, "Bump YamlDotNet from 13.4.0 to 13.5.1"), - new (285, "Bump YamlDotNet from 13.5.1 to 13.5.2"), - new (286, "Bump WireMock.Net from 1.5.37 to 1.5.39"), - new (287, "Bump YamlDotNet from 13.5.2 to 13.7.0"), - new (288, "Bump github.com/labstack/echo/v4 from 4.11.1 to 4.11.2 in /TestProjects/GoLang.Service"), - new (289, "Bump fastify from 4.23.2 to 4.24.0 in /TestProjects/NodeJS.Service"), - new (291, "Bump fastify from 4.24.0 to 4.24.2 in /TestProjects/NodeJS.Service"), - new (293, "Bump fastify from 4.24.2 to 4.24.3 in /TestProjects/NodeJS.Service"), - new (294, "Bump actions/setup-node from 3 to 4"), - new (292, "Bump YamlDotNet from 13.7.0 to 13.7.1"), - new (282, "Bump flask from 2.3.3 to 3.0.0 in /TestProjects/Python3.Flask"), - new (296, "Bump LibGit2Sharp from 0.27.2 to 0.28.0"), - new (297, "Bump NUnit from 3.13.3 to 3.14.0"), - new (273, "Bump actions/checkout from 3 to 4"), - new (298, "Bump github.com/labstack/echo/v4 from 4.11.2 to 4.11.3 in /TestProjects/GoLang.Service"), - new (299, "Bump WireMock.Net from 1.5.39 to 1.5.40"), - new (300, "Bump Microsoft.NET.Test.Sdk from 17.7.2 to 17.8.0"), - new (308, "Update and test .NET 8"), - new (309, "Bump NuGet.Packaging from 6.7.0 to 6.8.0"), - new (311, "Bump actions/setup-dotnet from 3 to 4"), - new (313, "Bump actions/setup-go from 4 to 5"), - new (314, "Bump WireMock.Net from 1.5.40 to 1.5.42"), - new (315, "Bump LibGit2Sharp from 0.28.0 to 0.29.0"), - new (316, "Bump AutoFixture.AutoNSubstitute from 4.18.0 to 4.18.1"), - new (318, "Bump WireMock.Net from 1.5.42 to 1.5.43"), - new (312, "Bump actions/setup-python from 4 to 5"), - new (319, "Don't print commands"), + new (236, "Bump NuGet.Packaging from 6.6.0 to 6.6.1", new []{"dependabot"}), + new (235, "Post release fixes", new []{"rasmus"}), + new (237, "Bump YamlDotNet from 13.1.0 to 13.1.1", new []{"dependabot"}), + new (240, "Bump WireMock.Net from 1.5.28 to 1.5.29", new []{"dependabot"}), + new (241, "Bump semver from 7.5.1 to 7.5.3 in /TestProjects/NodeJS.Service", new []{"dependabot"}), + new (239, "Bump Octokit from 6.0.0 to 6.1.0", new []{"dependabot"}), + new (242, "Bump WireMock.Net from 1.5.29 to 1.5.30", new []{"dependabot"}), + new (243, "Bump Microsoft.NET.Test.Sdk from 17.6.2 to 17.6.3", new []{"dependabot"}), + new (244, "Bump Octokit from 6.1.0 to 6.2.1", new []{"dependabot"}), + new (246, "Bump fastify from 4.18.0 to 4.19.1 in /TestProjects/NodeJS.Service", new []{"dependabot"}), + new (248, "Bump fastify from 4.19.1 to 4.19.2 in /TestProjects/NodeJS.Service", new []{"dependabot"}), + new (247, "Bump Octokit from 6.2.1 to 7.0.0", new []{"dependabot"}), + new (249, "Bump Octokit from 7.0.0 to 7.0.1", new []{"dependabot"}), + new (250, "Bump WireMock.Net from 1.5.30 to 1.5.31", new []{"dependabot"}), + new (252, "Bump github.com/labstack/echo/v4 from 4.10.2 to 4.11.1 in /TestProjects/GoLang.Service", new []{"dependabot"}), + new (254, "Bump fastify from 4.19.2 to 4.20.0 in /TestProjects/NodeJS.Service", new []{"dependabot"}), + new (255, "Bump Octokit from 7.0.1 to 7.1.0", new []{"dependabot"}), + new (253, "Bump WireMock.Net from 1.5.31 to 1.5.32", new []{"dependabot"}), + new (256, "Bump fastify from 4.20.0 to 4.21.0 in /TestProjects/NodeJS.Service", new []{"dependabot"}), + new (259, "Bump Microsoft.NET.Test.Sdk from 17.6.3 to 17.7.0", new []{"dependabot"}), + new (258, "Bump WireMock.Net from 1.5.32 to 1.5.34", new []{"dependabot"}), + new (260, "Remove moq", new []{"rasmus"}), + new (261, "Bump NuGet.Packaging from 6.6.1 to 6.7.0", new []{"dependabot"}), + new (262, "Bump YamlDotNet from 13.1.1 to 13.2.0", new []{"dependabot"}), + new (263, "Bump Microsoft.NET.Test.Sdk from 17.7.0 to 17.7.1", new []{"dependabot"}), + new (264, "Bump WireMock.Net from 1.5.34 to 1.5.35", new []{"dependabot"}), + new (265, "Bump flask from 2.3.2 to 2.3.3 in /TestProjects/Python3.Flask", new []{"dependabot"}), + new (266, "Bump FluentAssertions from 6.11.0 to 6.12.0", new []{"dependabot"}), + new (267, "Bump fastify from 4.21.0 to 4.22.0 in /TestProjects/NodeJS.Service", new []{"dependabot"}), + new (269, "Bump YamlDotNet from 13.2.0 to 13.3.1", new []{"dependabot"}), + new (268, "Bump McMaster.Extensions.CommandLineUtils from 4.0.2 to 4.1.0", new []{"dependabot"}), + new (270, "Bump Microsoft.NET.Test.Sdk from 17.7.1 to 17.7.2", new []{"dependabot"}), + new (271, "Bump fastify from 4.22.0 to 4.22.1 in /TestProjects/NodeJS.Service", new []{"dependabot"}), + new (272, "Bump fastify from 4.22.1 to 4.22.2 in /TestProjects/NodeJS.Service", new []{"dependabot"}), + new (275, "Bump fastify from 4.22.2 to 4.23.0 in /TestProjects/NodeJS.Service", new []{"dependabot"}), + new (276, "Bump fastify from 4.23.0 to 4.23.1 in /TestProjects/NodeJS.Service", new []{"dependabot"}), + new (277, "Bump fastify from 4.23.1 to 4.23.2 in /TestProjects/NodeJS.Service", new []{"dependabot"}), + new (278, "Bump YamlDotNet from 13.3.1 to 13.4.0", new []{"dependabot"}), + new (279, "Bump WireMock.Net from 1.5.35 to 1.5.36", new []{"dependabot"}), + new (281, "Bump WireMock.Net from 1.5.36 to 1.5.37", new []{"dependabot"}), + new (284, "Bump YamlDotNet from 13.4.0 to 13.5.1", new []{"dependabot"}), + new (285, "Bump YamlDotNet from 13.5.1 to 13.5.2", new []{"dependabot"}), + new (286, "Bump WireMock.Net from 1.5.37 to 1.5.39", new []{"dependabot"}), + new (287, "Bump YamlDotNet from 13.5.2 to 13.7.0", new []{"dependabot"}), + new (288, "Bump github.com/labstack/echo/v4 from 4.11.1 to 4.11.2 in /TestProjects/GoLang.Service", new []{"dependabot"}), + new (289, "Bump fastify from 4.23.2 to 4.24.0 in /TestProjects/NodeJS.Service", new []{"dependabot"}), + new (291, "Bump fastify from 4.24.0 to 4.24.2 in /TestProjects/NodeJS.Service", new []{"dependabot"}), + new (293, "Bump fastify from 4.24.2 to 4.24.3 in /TestProjects/NodeJS.Service", new []{"dependabot"}), + new (294, "Bump actions/setup-node from 3 to 4", new []{"dependabot"}), + new (292, "Bump YamlDotNet from 13.7.0 to 13.7.1", new []{"dependabot"}), + new (282, "Bump flask from 2.3.3 to 3.0.0 in /TestProjects/Python3.Flask", new []{"dependabot"}), + new (296, "Bump LibGit2Sharp from 0.27.2 to 0.28.0", new []{"dependabot"}), + new (297, "Bump NUnit from 3.13.3 to 3.14.0", new []{"dependabot"}), + new (273, "Bump actions/checkout from 3 to 4", new []{"dependabot"}), + new (298, "Bump github.com/labstack/echo/v4 from 4.11.2 to 4.11.3 in /TestProjects/GoLang.Service", new []{"dependabot"}), + new (299, "Bump WireMock.Net from 1.5.39 to 1.5.40", new []{"dependabot"}), + new (300, "Bump Microsoft.NET.Test.Sdk from 17.7.2 to 17.8.0", new []{"dependabot"}), + new (308, "Update and test .NET 8", new []{"rasmus"}), + new (309, "Bump NuGet.Packaging from 6.7.0 to 6.8.0", new []{"dependabot"}), + new (311, "Bump actions/setup-dotnet from 3 to 4", new []{"dependabot"}), + new (313, "Bump actions/setup-go from 4 to 5", new []{"dependabot"}), + new (314, "Bump WireMock.Net from 1.5.40 to 1.5.42", new []{"dependabot"}), + new (315, "Bump LibGit2Sharp from 0.28.0 to 0.29.0", new []{"dependabot"}), + new (316, "Bump AutoFixture.AutoNSubstitute from 4.18.0 to 4.18.1", new []{"dependabot"}), + new (318, "Bump WireMock.Net from 1.5.42 to 1.5.43", new []{"dependabot"}), + new (312, "Bump actions/setup-python from 4 to 5", new []{"dependabot"}), + new (319, "Don't print commands", new []{"rasmus"}), + new (321, "Bump fastify from 4.24.3 to 4.25.0 in /TestProjects/NodeJS.Service", new []{"dependabot"}), + new (323, "Bump WireMock.Net from 1.5.43 to 1.5.44", new []{"dependabot"}), + new (325, "Bump fastify from 4.25.0 to 4.25.1 in /TestProjects/NodeJS.Service", new []{"dependabot"}), + new (326, "Bump golang.org/x/crypto from 0.14.0 to 0.17.0 in /TestProjects/GoLang.Service", new []{"dependabot"}), + new (322, "Bump github/codeql-action from 2 to 3", new []{"dependabot"}), + new (317, "Bump NUnit from 3.14.0 to 4.0.1", new []{"dependabot"}), + new (327, "Bump github.com/labstack/echo/v4 from 4.11.3 to 4.11.4 in /TestProjects/GoLang.Service", new []{"dependabot"}), + new (328, "Bump WireMock.Net from 1.5.44 to 1.5.45", new []{"dependabot"}), + new (329, "Bump fastify from 4.25.1 to 4.25.2 in /TestProjects/NodeJS.Service", new []{"dependabot"}), + new (330, "Bump WireMock.Net from 1.5.45 to 1.5.46", new []{"dependabot"}), }; } } diff --git a/Source/Bake/Services/ChangeLogBuilder.cs b/Source/Bake/Services/ChangeLogBuilder.cs index 0afa6b8a..6291cd88 100644 --- a/Source/Bake/Services/ChangeLogBuilder.cs +++ b/Source/Bake/Services/ChangeLogBuilder.cs @@ -20,6 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; @@ -56,9 +57,17 @@ into g select new DependencyChange( g.Key.dependency, g.Key.project, - g.Select(x => x.pr.Number).OrderBy(i => i).ToArray(), + g + .Select(x => x.pr.Number) + .OrderBy(i => i) + .ToArray(), g.Min(x => x.fromVersion), - g.Max(x => x.to)) + g.Max(x => x.to), + g + .SelectMany(x => x.pr.Authors) + .Distinct(StringComparer.OrdinalIgnoreCase) + .OrderBy(x => x) + .ToArray()) ) .OrderBy(c => c.Name) .ToArray(); @@ -85,26 +94,29 @@ private class DependencyChange public int[] PullRequests { get; } public SemVer From { get; } public SemVer To { get; } + public IReadOnlyCollection Authors { get; } public DependencyChange( string name, string project, int[] pullRequests, SemVer from, - SemVer to) + SemVer to, + IReadOnlyCollection authors) { Name = name; Project = project; PullRequests = pullRequests; From = from; To = to; + Authors = authors; } public Change ToChange() { var message = string.IsNullOrEmpty(Project) - ? $"Bump {Name} {From} to {To} ({string.Join(", ", PullRequests.Select(pr => $"#{pr}"))})" - : $"Bump {Name} {From} to {To} in {Project} ({string.Join(", ", PullRequests.Select(pr => $"#{pr}"))})"; + ? $"Bump {Name} {From} to {To} ({string.Join(", ", PullRequests.Select(pr => $"#{pr}"))}, by {string.Join(", ", Authors.Select(a => $"@{a}"))})" + : $"Bump {Name} {From} to {To} in {Project} ({string.Join(", ", PullRequests.Select(pr => $"#{pr}"))}, by {string.Join(", ", Authors.Select(a => $"@{a}"))})"; return new Change(ChangeType.Dependency, message); } diff --git a/Source/Bake/Services/GitHub.cs b/Source/Bake/Services/GitHub.cs index 2b0335e8..815d7e66 100644 --- a/Source/Bake/Services/GitHub.cs +++ b/Source/Bake/Services/GitHub.cs @@ -275,9 +275,17 @@ public async Task> GetPullRequestsAsync( gitHubInformation.Repository, number); + var author = pullRequest.User.Login; + var i = author.IndexOf('['); + var length = i < 0 ? author.Length : i; + return new PullRequest( pullRequest.Number, - pullRequest.Title); + pullRequest.Title, + new [] + { + author[..length], + }); } catch (NotFoundException e) { diff --git a/Source/Bake/ValueObjects/PullRequest.cs b/Source/Bake/ValueObjects/PullRequest.cs index 02c71c7c..abc9d1f6 100644 --- a/Source/Bake/ValueObjects/PullRequest.cs +++ b/Source/Bake/ValueObjects/PullRequest.cs @@ -20,29 +20,35 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +using System.Collections.Generic; +using System.Linq; + namespace Bake.ValueObjects { public class PullRequest { public int Number { get; } public string Title { get; } + public IReadOnlyCollection Authors { get; } public PullRequest( int number, - string title) + string title, + string[] authors) { Number = number; Title = title; + Authors = authors; } public Change ToChange() { - return new Change(ChangeType.Other, $"{Title} (#{Number})"); + return new Change(ChangeType.Other, $"{Title} (#{Number}, by {string.Join(", ", Authors.Select(a => $"@{a}"))})"); } public override string ToString() { - return $"#{Number}: {Title}"; + return $"#{Number}: {Title} by {string.Join(", ", Authors)}"; } } } From 42d5de9d6f7d7b26367738049b2cde1874bd0e44 Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Tue, 9 Jan 2024 19:20:48 +0100 Subject: [PATCH 19/21] Actually verify --- .../UnitTests/Services/ChangeLogBuilderTests.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Source/Bake.Tests/UnitTests/Services/ChangeLogBuilderTests.cs b/Source/Bake.Tests/UnitTests/Services/ChangeLogBuilderTests.cs index 764f73b5..6f853f46 100644 --- a/Source/Bake.Tests/UnitTests/Services/ChangeLogBuilderTests.cs +++ b/Source/Bake.Tests/UnitTests/Services/ChangeLogBuilderTests.cs @@ -21,9 +21,11 @@ // SOFTWARE. using System.Collections.Generic; +using System.Linq; using Bake.Services; using Bake.Tests.Helpers; using Bake.ValueObjects; +using FluentAssertions; using NUnit.Framework; namespace Bake.Tests.UnitTests.Services @@ -31,13 +33,18 @@ namespace Bake.Tests.UnitTests.Services public class ChangeLogBuilderTests : TestFor { [Test] - public void T() + public void Build() { // Arrange var pullRequests = Get(); // Act var changes = Sut.Build(pullRequests); + + // Assert + changes.Should().HaveCount(2); + changes[ChangeType.Dependency].Should().HaveCount(21); + changes[ChangeType.Dependency].Select(d => d.Text).Should().Contain("Bump flask 2.3.2 to 3.0.0 in /TestProjects/Python3.Flask (#265, #282, by @dependabot)"); } private static IReadOnlyCollection Get() From ece929d971f16eddbf55ef07e55f059ad8550350 Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Tue, 9 Jan 2024 19:22:54 +0100 Subject: [PATCH 20/21] Update the readme --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a85dfb97..3055a9ee 100644 --- a/README.md +++ b/README.md @@ -78,9 +78,10 @@ regarding the environment its executed within. * **GitHub Action** - When Bake is executed from within a GitHub action, it automatically recognizes the token and uses that when publishing artifacts and releases -* **Release notes** - If the repository contains a `RELEASE_NOTES.md` file, - the content as well as the version information is used to further enrich - any release artifacts +* **Release notes** - Pull requests merged since latest release are summarized, + similar grouped together, used as release notes. In addition, if the repository + contains a `RELEASE_NOTES.md` file, the content as well as the version information + is used to further enrich any release artifacts After the initial environment information gathering is completed, Bake starts to scan the repository for files and structures it knows how to process. From 1b85fbbc8ee6d165dd3f0cd1cbaa7329825a8915 Mon Sep 17 00:00:00 2001 From: Rasmus Mikkelsen Date: Tue, 9 Jan 2024 19:36:15 +0100 Subject: [PATCH 21/21] Minor cleanups --- Source/Bake.Tests/Helpers/BakeTest.cs | 3 +- .../Ingredients/Gathers/ChangelogGather.cs | 12 ++++ Source/Bake/Services/GitHub.cs | 62 +++++++++++-------- Source/Bake/Services/IGitHub.cs | 3 +- Source/Bake/ValueObjects/Tag.cs | 14 ++++- 5 files changed, 61 insertions(+), 33 deletions(-) diff --git a/Source/Bake.Tests/Helpers/BakeTest.cs b/Source/Bake.Tests/Helpers/BakeTest.cs index 3cf409a5..0128dda5 100644 --- a/Source/Bake.Tests/Helpers/BakeTest.cs +++ b/Source/Bake.Tests/Helpers/BakeTest.cs @@ -128,8 +128,7 @@ public Task CreateReleaseAsync( return Task.CompletedTask; } - public Task GetPullRequestInformationAsync( - GitInformation gitInformation, + public Task GetPullRequestInformationAsync(GitInformation gitInformation, GitHubInformation gitHubInformation, CancellationToken cancellationToken) { diff --git a/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs b/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs index 27bf5698..ac04cdea 100644 --- a/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs +++ b/Source/Bake/Cooking/Ingredients/Gathers/ChangelogGather.cs @@ -26,18 +26,22 @@ using System.Threading.Tasks; using Bake.Services; using Bake.ValueObjects; +using Microsoft.Extensions.Logging; namespace Bake.Cooking.Ingredients.Gathers { public class ChangelogGather : IGather { + private readonly ILogger _logger; private readonly IGitHub _gitHub; private readonly IChangeLogBuilder _changeLogBuilder; public ChangelogGather( + ILogger logger, IGitHub gitHub, IChangeLogBuilder changeLogBuilder) { + _logger = logger; _gitHub = gitHub; _changeLogBuilder = changeLogBuilder; } @@ -64,12 +68,20 @@ public async Task GatherAsync( gitHubInformation, cancellationToken); + if (tags.Count == 0) + { + _logger.LogInformation("Did not find any release tags"); + ingredients.FailChangelog(); + return; + } + var tag = tags .Where(t => t.Version.LegacyVersion < ingredients.Version.LegacyVersion) .MaxBy(t => t.Version); if (tag == null) { + _logger.LogInformation("Could not find a su"); ingredients.FailChangelog(); return; } diff --git a/Source/Bake/Services/GitHub.cs b/Source/Bake/Services/GitHub.cs index 815d7e66..701c2f3a 100644 --- a/Source/Bake/Services/GitHub.cs +++ b/Source/Bake/Services/GitHub.cs @@ -102,6 +102,10 @@ public async Task> GetTagsAsync( CancellationToken cancellationToken) { var gitHubClient = await CreateGitHubClientAsync(gitHubInformation, cancellationToken); + if (gitHubClient == null) + { + return Array.Empty(); + } var releases = await gitHubClient.Repository.GetAllTags( gitHubInformation.Owner, @@ -124,25 +128,9 @@ public async Task GetPullRequestInformationAsync( CancellationToken cancellationToken) { var gitHubClient = await CreateGitHubClientAsync(gitHubInformation, cancellationToken); - - async Task SearchAsync(string c) + if (gitHubClient == null) { - var issues = await gitHubClient.Search.SearchIssues(new SearchIssuesRequest(c) - { - Type = IssueTypeQualifier.PullRequest, - Repos = new RepositoryCollection - { - {gitHubInformation.Owner, gitHubInformation.Repository}, - } - }); - if (issues.Items.Count != 1) - { - return null; - } - - var issue = issues.Items.Single(); - return new PullRequestInformation( - issue.Labels.Select(l => l.Name).ToArray()); + return null; } var pullRequestInformation = await SearchAsync(gitInformation.Sha); @@ -167,20 +155,45 @@ async Task SearchAsync(string c) match.Groups["pr"].Value, match.Groups["base"].Value); return await SearchAsync(match.Groups["pr"].Value); + + async Task SearchAsync(string c) + { + var issues = await gitHubClient.Search.SearchIssues(new SearchIssuesRequest(c) + { + Type = IssueTypeQualifier.PullRequest, + Repos = new RepositoryCollection + { + {gitHubInformation.Owner, gitHubInformation.Repository}, + } + }); + if (issues.Items.Count != 1) + { + return null; + } + + var issue = issues.Items.Single(); + return new PullRequestInformation( + issue.Labels.Select(l => l.Name).ToArray()); + } } - private async Task CreateGitHubClientAsync( + private async Task CreateGitHubClientAsync( GitHubInformation gitHubInformation, CancellationToken cancellationToken) { var token = await _credentials.TryGetGitHubTokenAsync( gitHubInformation.Url, cancellationToken); + if (string.IsNullOrEmpty(token)) + { + return null; + } var gitHubClient = await _gitHubClientFactory.CreateAsync( token, gitHubInformation.ApiUrl, cancellationToken); + return gitHubClient; } @@ -190,20 +203,15 @@ public async Task> GetCommitsAsync( GitHubInformation gitHubInformation, CancellationToken cancellationToken) { - var token = await _credentials.TryGetGitHubTokenAsync( - gitHubInformation.Url, + var gitHubClient = await CreateGitHubClientAsync( + gitHubInformation, cancellationToken); - if (string.IsNullOrEmpty(token)) + if (gitHubClient == null) { return Array.Empty(); } - var gitHubClient = await _gitHubClientFactory.CreateAsync( - token, - gitHubInformation.ApiUrl, - cancellationToken); - var compareResult = await gitHubClient.Repository.Commit.Compare( gitHubInformation.Owner, gitHubInformation.Repository, diff --git a/Source/Bake/Services/IGitHub.cs b/Source/Bake/Services/IGitHub.cs index c1594430..dff52405 100644 --- a/Source/Bake/Services/IGitHub.cs +++ b/Source/Bake/Services/IGitHub.cs @@ -34,8 +34,7 @@ Task CreateReleaseAsync( GitHubInformation gitHubInformation, CancellationToken cancellationToken); - Task GetPullRequestInformationAsync( - GitInformation gitInformation, + Task GetPullRequestInformationAsync(GitInformation gitInformation, GitHubInformation gitHubInformation, CancellationToken cancellationToken); diff --git a/Source/Bake/ValueObjects/Tag.cs b/Source/Bake/ValueObjects/Tag.cs index 4832f30f..aa8a95fb 100644 --- a/Source/Bake/ValueObjects/Tag.cs +++ b/Source/Bake/ValueObjects/Tag.cs @@ -20,21 +20,31 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +using System; using Bake.Core; +using YamlDotNet.Serialization; namespace Bake.ValueObjects { public class Tag { - public SemVer Version { get; } - public string Sha { get; } + [YamlMember] + public SemVer Version { get; [Obsolete] set; } + + [YamlMember] + public string Sha { get; [Obsolete] set; } + + [Obsolete] + public Tag(){} public Tag( SemVer version, string sha) { +#pragma warning disable CS0612 // Type or member is obsolete Version = version; Sha = sha; +#pragma warning restore CS0612 // Type or member is obsolete } public override string ToString()