Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(#93) recognize single number versions #95

Merged
merged 2 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ bin/
obj/
/tools/
/BuildArtifacts/
*.DotSettings.user
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0"/>
<PackageReference Include="Shouldly" Version="4.2.1" />
<PackageReference Include="xunit" Version="2.4.2"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\GitHubMilestoneCleaner\GitHubMilestoneCleaner.csproj" />
</ItemGroup>

</Project>
1 change: 1 addition & 0 deletions src/GitHubMilestoneCleaner.Tests/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
global using Xunit;

Check warning on line 1 in src/GitHubMilestoneCleaner.Tests/GlobalUsings.cs

View workflow job for this annotation

GitHub Actions / build (windows-2022)

C# 10.0 language feature
59 changes: 59 additions & 0 deletions src/GitHubMilestoneCleaner.Tests/IssueGroupEngineTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System.Collections.Immutable;
using System.Runtime.InteropServices.ComTypes;
using GitHubMilestoneCleaner.Engines;

Check warning on line 3 in src/GitHubMilestoneCleaner.Tests/IssueGroupEngineTests.cs

View workflow job for this annotation

GitHub Actions / build (windows-2022)

Namespace 'GitHubMilestoneCleaner.Engines' contains no declarations
using Octokit;
using Shouldly;

namespace GitHubMilestoneCleaner.Tests;

Check warning on line 7 in src/GitHubMilestoneCleaner.Tests/IssueGroupEngineTests.cs

View workflow job for this annotation

GitHub Actions / build (windows-2022)

Namespace body block expected

public class IssueGroupEngineTests
{
public class MockIssueWrapper(string title, int number) : IssueGroupEngine.IIssueWrapper

Check warning on line 11 in src/GitHubMilestoneCleaner.Tests/IssueGroupEngineTests.cs

View workflow job for this annotation

GitHub Actions / build (windows-2022)

Class cannot have primary constructor
{
public string Title { get; } = title;

Check warning on line 13 in src/GitHubMilestoneCleaner.Tests/IssueGroupEngineTests.cs

View workflow job for this annotation

GitHub Actions / build (windows-2022)

Cannot resolve symbol 'title'
public int Number { get; } = number;

Check warning on line 14 in src/GitHubMilestoneCleaner.Tests/IssueGroupEngineTests.cs

View workflow job for this annotation

GitHub Actions / build (windows-2022)

Cannot resolve symbol 'number'
public Issue BackingIssue { get; } = new();
}

[Theory]
[InlineData("Bump coverlet.msbuild from 3.1.1 to 3.1.2", "Bump coverlet.msbuild from 3.1.0 to 3.1.1")]
[InlineData("Update github/codeql-action digest to 6a28655", "Update github/codeql-action digest to ddccb87")]
[InlineData("Bump coverlet.msbuild from 3.1.1 to 3.1.2", "Bump coverlet.msbuild digest to ddccb87")]
[InlineData("Bump actions/setup-dotnet from 1.9.0 to 1.9.1", "Bump actions/setup-dotnet from 1.9.1 to 2")]
[InlineData("Bump github/codeql-action from 1 to 2", "Bump github/codeql-action from 2 to 3")]
public void Should_group_two_bumps_of_the_same_package_into_one(string lhs, string rhs)
{
// given
var sut = new IssueGroupEngine();
var issues = new[] { lhs, rhs }
.Select(x =>

Check warning on line 29 in src/GitHubMilestoneCleaner.Tests/IssueGroupEngineTests.cs

View workflow job for this annotation

GitHub Actions / build (windows-2022)

Cannot resolve symbol 'Select'
new MockIssueWrapper(x, 1));

Check warning on line 30 in src/GitHubMilestoneCleaner.Tests/IssueGroupEngineTests.cs

View workflow job for this annotation

GitHub Actions / build (windows-2022)

Constructor 'MockIssueWrapper' has 0 parameter(s) but is invoked with 2 argument(s)

// when
var f = sut.GroupIssues(issues).ToList();

Check warning on line 33 in src/GitHubMilestoneCleaner.Tests/IssueGroupEngineTests.cs

View workflow job for this annotation

GitHub Actions / build (windows-2022)

Cannot resolve symbol 'ToList'

// then
f.Count.ShouldBe(1);
f[0].SubIssues.Count().ShouldBe(1);
}

[Theory]
[InlineData("Bump coverlet.msbuild from 3.1.1 to 3.1.2", "Bump coverlet.msbuild to nothing at all")]
[InlineData("Bump coverlet.msbuild from 3.1.1 to 3.1.2", "Update coverlet.msbuild from 3.1.1 to 3.1.2")]
public void Should_NOT_group_two_bumps_of_different_packages_into_one(string lhs, string rhs)
{
// given
var sut = new IssueGroupEngine();
var issues = new[] { lhs, rhs }
.Select(x =>

Check warning on line 48 in src/GitHubMilestoneCleaner.Tests/IssueGroupEngineTests.cs

View workflow job for this annotation

GitHub Actions / build (windows-2022)

Cannot resolve symbol 'Select'
new MockIssueWrapper(x, 1));

// when
var f = sut.GroupIssues(issues).ToList();

// then
f.Count.ShouldBe(2);
f[0].SubIssues.Count().ShouldBe(0);
f[1].SubIssues.Count().ShouldBe(0);
}
}
14 changes: 14 additions & 0 deletions src/GitHubMilestoneCleaner.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHubMilestoneCleaner", "GitHubMilestoneCleaner\GitHubMilestoneCleaner.csproj", "{26124460-67B8-4A9D-B5E3-ABC422405C7A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHubMilestoneCleaner.Tests", "GitHubMilestoneCleaner.Tests\GitHubMilestoneCleaner.Tests.csproj", "{1A4464F8-9042-4B67-A7B4-026D3794E8F3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -30,5 +32,17 @@ Global
{26124460-67B8-4A9D-B5E3-ABC422405C7A}.Release|x64.Build.0 = Release|Any CPU
{26124460-67B8-4A9D-B5E3-ABC422405C7A}.Release|x86.ActiveCfg = Release|Any CPU
{26124460-67B8-4A9D-B5E3-ABC422405C7A}.Release|x86.Build.0 = Release|Any CPU
{1A4464F8-9042-4B67-A7B4-026D3794E8F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1A4464F8-9042-4B67-A7B4-026D3794E8F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A4464F8-9042-4B67-A7B4-026D3794E8F3}.Debug|x64.ActiveCfg = Debug|Any CPU
{1A4464F8-9042-4B67-A7B4-026D3794E8F3}.Debug|x64.Build.0 = Debug|Any CPU
{1A4464F8-9042-4B67-A7B4-026D3794E8F3}.Debug|x86.ActiveCfg = Debug|Any CPU
{1A4464F8-9042-4B67-A7B4-026D3794E8F3}.Debug|x86.Build.0 = Debug|Any CPU
{1A4464F8-9042-4B67-A7B4-026D3794E8F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A4464F8-9042-4B67-A7B4-026D3794E8F3}.Release|Any CPU.Build.0 = Release|Any CPU
{1A4464F8-9042-4B67-A7B4-026D3794E8F3}.Release|x64.ActiveCfg = Release|Any CPU
{1A4464F8-9042-4B67-A7B4-026D3794E8F3}.Release|x64.Build.0 = Release|Any CPU
{1A4464F8-9042-4B67-A7B4-026D3794E8F3}.Release|x86.ActiveCfg = Release|Any CPU
{1A4464F8-9042-4B67-A7B4-026D3794E8F3}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
2 changes: 0 additions & 2 deletions src/GitHubMilestoneCleaner.sln.DotSettings.user

This file was deleted.

26 changes: 20 additions & 6 deletions src/GitHubMilestoneCleaner/Commands/AutoCleanupCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ public override async Task<int> ExecuteAsync(CommandContext context, Settings se
}

var groupEngine = new IssueGroupEngine();
var grouped = groupEngine.GroupIssues(issues).ToList();
var toRemove = new List<Issue>();
var grouped = groupEngine.GroupIssues(issues.Select(x => new IssueWrapper(x))).ToList();
var toRemove = new List<IssueGroupEngine.IIssueWrapper>();

if (!settings.NonInteractive)
{
var prompt = new MultiSelectionPrompt<Issue>
var prompt = new MultiSelectionPrompt<IssueGroupEngine.IIssueWrapper>
{
Converter = IssueExtensions.ToMarkup,
PageSize = 25,
Expand Down Expand Up @@ -118,14 +118,16 @@ async Task DoRemove(Action? callback = null)
{
foreach (var issue in toRemove)
{
var group = grouped.First(g => g.MainIssue.Id == issue.Id || g.SubIssues.Any(i => i.Id == issue.Id));
var group = grouped.First(g =>
g.MainIssue.BackingIssue.Id == issue.BackingIssue.Id
|| g.SubIssues.Any(i => i.BackingIssue.Id == issue.BackingIssue.Id));
var comment = issue == group.MainIssue ? settings.TopIssueComment : settings.SubIssueComment;
if (!string.IsNullOrEmpty(comment))
{
comment = string.Format(comment, group.MainIssue.HtmlUrl);
comment = string.Format(comment, group.MainIssue.BackingIssue.HtmlUrl);
}

await adapter.RemoveMilestone(repo, issue, comment);
await adapter.RemoveMilestone(repo, issue.BackingIssue, comment);
callback?.Invoke();
}
}
Expand Down Expand Up @@ -153,4 +155,16 @@ await DoRemove(() =>

return 0;
}

private class IssueWrapper : IssueGroupEngine.IIssueWrapper
{
public IssueWrapper(Issue issue)
{
BackingIssue = issue;
}

public string Title => BackingIssue.Title;
public int Number => BackingIssue.Number;
public Issue BackingIssue { get; }
}
}
30 changes: 22 additions & 8 deletions src/GitHubMilestoneCleaner/Engines/IssueGroupEngine.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.VisualBasic;
using Octokit;

namespace GitHubMilestoneCleaner.Engines;
Expand All @@ -9,11 +10,11 @@ public class IssueGroupEngine
{
private readonly Regex _versionMatcher =
new(
@"\s*(from|to) v?(0|[1-9]\d*)(\.(0|[1-9]\d*))+(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?");
@"\s*(from|to) v?(0|[1-9]\d*)(\.(0|[1-9]\d*))*(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?");
private readonly Regex _digestMatcher = new(@"\s*digest to [0-9a-fA-F]+$");


public IEnumerable<IssueGroup> GroupIssues(IEnumerable<Issue> issues)
public IEnumerable<IssueGroup> GroupIssues(IEnumerable<IIssueWrapper> issues)
{
var matchers = new[]
{
Expand All @@ -26,9 +27,15 @@ public IEnumerable<IssueGroup> GroupIssues(IEnumerable<Issue> issues)
{
Issue = x,
VersionAgnosticName = (matchers
.FirstOrDefault(m => m.IsMatch(x.Title))?
.Replace(x.Title, string.Empty) ?? x.Title)
.TrimEnd(),
.Select(m => new
{
Matcher = m,
Matches = m.Matches(x.Title)
})
.Where(y => y.Matches.Count > 0)
.MaxBy(m => m.Matches[0].Length)? // Really, the longest match is always the best??
.Matcher.Replace(x.Title, string.Empty) ?? x.Title)
.Trim(),
})
.GroupBy(x => x.VersionAgnosticName)
.Select(x =>
Expand All @@ -52,7 +59,14 @@ public IEnumerable<IssueGroup> GroupIssues(IEnumerable<Issue> issues)
public record IssueGroup
{
public string MatchKey { get; init; } = default!;
public Issue MainIssue { get; init; } = default!;
public IEnumerable<Issue> SubIssues { get; init; } = default!;
public IIssueWrapper MainIssue { get; init; } = default!;
public IEnumerable<IIssueWrapper> SubIssues { get; init; } = default!;
}
}

public interface IIssueWrapper
{
string Title { get; }
int Number { get; }
Issue BackingIssue { get; }
}
}
11 changes: 6 additions & 5 deletions src/GitHubMilestoneCleaner/Extension/IssueExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using GitHubMilestoneCleaner.Engines;
using Octokit;

namespace GitHubMilestoneCleaner.Extension;
Expand All @@ -15,17 +16,17 @@ private static string GetWebUrl(this Issue issue)
return url;
}

internal static string ToMarkup(this Issue issue)
internal static string ToMarkup(this IssueGroupEngine.IIssueWrapper issue)
{
return $"[link={issue.GetWebUrl()}][green](#{issue.Number})[/] [yellow]{issue.Title}[/][/]";
return $"[link={issue.BackingIssue.GetWebUrl()}][green](#{issue.Number})[/] [yellow]{issue.Title}[/][/]";
}

internal static string ToShortMarkup(this Issue issue)
internal static string ToShortMarkup(this IssueGroupEngine.IIssueWrapper issue)
{
return $"[link={issue.GetWebUrl()}]#{issue.Number}[/]";
return $"[link={issue.BackingIssue.GetWebUrl()}]#{issue.Number}[/]";
}

internal static string ToShortMarkup(this IEnumerable<Issue> issues)
internal static string ToShortMarkup(this IEnumerable<IssueGroupEngine.IIssueWrapper> issues)
{
return string.Join(
", ",
Expand Down
Loading