From 5e7562d6a0c3bcdcc13b8c445e9bacd1b53ea57a Mon Sep 17 00:00:00 2001 From: SzymonPobiega Date: Thu, 16 Oct 2014 15:48:29 +0200 Subject: [PATCH] Added a seam to enable isolated testing. Fixed #15 --- src/App/Program.cs | 2 +- src/Compiler/DefaultGitHubClient.cs | 63 +++++++++++++ src/Compiler/IGitHubClient.cs | 13 +++ src/Compiler/ReleaseNotesBuilder.cs | 74 +++++---------- src/Compiler/ReleaseNotesCompiler.csproj | 2 + src/Tests/FakeGitHubClient.cs | 35 +++++++ .../ReleaseNotesBuilderIntegrationTests.cs | 41 ++++++++ src/Tests/ReleaseNotesBuilderTests.cs | 94 +++++++++++++++---- src/Tests/ReleaseNotesCompiler.Tests.csproj | 4 +- 9 files changed, 257 insertions(+), 71 deletions(-) create mode 100644 src/Compiler/DefaultGitHubClient.cs create mode 100644 src/Compiler/IGitHubClient.cs create mode 100644 src/Tests/FakeGitHubClient.cs create mode 100644 src/Tests/ReleaseNotesBuilderIntegrationTests.cs diff --git a/src/App/Program.cs b/src/App/Program.cs index 58bde06..0aa4f2f 100644 --- a/src/App/Program.cs +++ b/src/App/Program.cs @@ -127,7 +127,7 @@ static async Task PublishReleaseAsync(PublishSubOptions options) private static async Task CreateRelease(GitHubClient github, string owner, string repository, string milestone, string asset) { - var releaseNotesBuilder = new ReleaseNotesBuilder(github, owner, repository, milestone); + var releaseNotesBuilder = new ReleaseNotesBuilder(new DefaultGitHubClient(github, owner, repository), owner, repository, milestone); var result = await releaseNotesBuilder.BuildReleaseNotes(); diff --git a/src/Compiler/DefaultGitHubClient.cs b/src/Compiler/DefaultGitHubClient.cs new file mode 100644 index 0000000..ac1cb1e --- /dev/null +++ b/src/Compiler/DefaultGitHubClient.cs @@ -0,0 +1,63 @@ +namespace ReleaseNotesCompiler +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Octokit; + + public class DefaultGitHubClient : IGitHubClient + { + GitHubClient gitHubClient; + string user; + string repository; + + public DefaultGitHubClient(GitHubClient gitHubClient, string user, string repository) + { + this.gitHubClient = gitHubClient; + this.user = user; + this.repository = repository; + } + + public async Task GetNumberOfCommitsBetween(Milestone previousMilestone, Milestone currentMilestone) + { + try + { + if (previousMilestone == null) + { + var gitHubClientRepositoryCommitsCompare = await gitHubClient.Repository.Commits.Compare(user, repository, "master", currentMilestone.Title); + return gitHubClientRepositoryCommitsCompare.AheadBy; + } + + var compareResult = await gitHubClient.Repository.Commits.Compare(user, repository, previousMilestone.Title, "master"); + return compareResult.AheadBy; + } + catch (NotFoundException) + { + //If there is not tag yet the Compare will return a NotFoundException + //we can safely ignore + return 0; + } + } + + public async Task> GetIssues(Milestone targetMilestone) + { + var allIssues = await gitHubClient.AllIssuesForMilestone(targetMilestone); + return allIssues.Where(x => x.State == ItemState.Closed).ToList(); + } + + public List GetMilestones() + { + var milestonesClient = gitHubClient.Issue.Milestone; + var closed = milestonesClient.GetForRepository(user, repository, new MilestoneRequest + { + State = ItemState.Closed + }).Result; + var open = milestonesClient.GetForRepository(user, repository, new MilestoneRequest + { + State = ItemState.Open + }).Result; + return closed.Concat(open).ToList(); + } + } +} \ No newline at end of file diff --git a/src/Compiler/IGitHubClient.cs b/src/Compiler/IGitHubClient.cs new file mode 100644 index 0000000..a6c63db --- /dev/null +++ b/src/Compiler/IGitHubClient.cs @@ -0,0 +1,13 @@ +namespace ReleaseNotesCompiler +{ + using System.Collections.Generic; + using System.Threading.Tasks; + using Octokit; + + public interface IGitHubClient + { + Task GetNumberOfCommitsBetween(Milestone previousMilestone, Milestone currentMilestone); + Task> GetIssues(Milestone targetMilestone); + List GetMilestones(); + } +} \ No newline at end of file diff --git a/src/Compiler/ReleaseNotesBuilder.cs b/src/Compiler/ReleaseNotesBuilder.cs index 1a04d41..2c97318 100644 --- a/src/Compiler/ReleaseNotesBuilder.cs +++ b/src/Compiler/ReleaseNotesBuilder.cs @@ -11,14 +11,14 @@ namespace ReleaseNotesCompiler public class ReleaseNotesBuilder { - GitHubClient gitHubClient; + IGitHubClient gitHubClient; string user; string repository; string milestoneTitle; List milestones; Milestone targetMilestone; - public ReleaseNotesBuilder(GitHubClient gitHubClient, string user, string repository, string milestoneTitle) + public ReleaseNotesBuilder(IGitHubClient gitHubClient, string user, string repository, string milestoneTitle) { this.gitHubClient = gitHubClient; this.user = user; @@ -28,27 +28,35 @@ public ReleaseNotesBuilder(GitHubClient gitHubClient, string user, string reposi public async Task BuildReleaseNotes() { - GetMilestones(); + LoadMilestones(); GetTargetMilestone(); var issues = await GetIssues(targetMilestone); var stringBuilder = new StringBuilder(); var previousMilestone = GetPreviousMilestone(); + var numberOfCommits = await gitHubClient.GetNumberOfCommitsBetween(previousMilestone, targetMilestone); - var issuesText = String.Format(issues.Count == 1 ? "{0} issue" : "{0} issues", issues.Count); - - var numberOfCommits = await GetNumberOfCommits(previousMilestone); - if (numberOfCommits > 0) + if (issues.Count > 0) { - var commitsLink = GetCommitsLink(previousMilestone); + var issuesText = String.Format(issues.Count == 1 ? "{0} issue" : "{0} issues", issues.Count); - var commitsText = String.Format(numberOfCommits == 1 ? "{0} commit" : "{0} commits", numberOfCommits); + if (numberOfCommits > 0) + { + var commitsLink = GetCommitsLink(previousMilestone); + var commitsText = String.Format(numberOfCommits == 1 ? "{0} commit" : "{0} commits", numberOfCommits); - stringBuilder.AppendFormat(@"As part of this release we had [{0}]({1}) which resulted in [{2}]({3}) being closed.", commitsText, commitsLink, issuesText, targetMilestone.HtmlUrl()); + stringBuilder.AppendFormat(@"As part of this release we had [{0}]({1}) which resulted in [{2}]({3}) being closed.", commitsText, commitsLink, issuesText, targetMilestone.HtmlUrl()); + } + else + { + stringBuilder.AppendFormat(@"As part of this release we had [{0}]({1}) closed.", issuesText, targetMilestone.HtmlUrl()); + } } - else + else if (numberOfCommits > 0) { - stringBuilder.AppendFormat(@"As part of this release we had [{0}]({1}) closed.", issuesText, targetMilestone.HtmlUrl()); + var commitsLink = GetCommitsLink(previousMilestone); + var commitsText = String.Format(numberOfCommits == 1 ? "{0} commit" : "{0} commits", numberOfCommits); + stringBuilder.AppendFormat(@"As part of this release we had [{0}]({1}).", commitsText, commitsLink); } stringBuilder.AppendLine(); @@ -62,27 +70,6 @@ public async Task BuildReleaseNotes() return stringBuilder.ToString(); } - async Task GetNumberOfCommits(Milestone previousMilestone) - { - try - { - if (previousMilestone == null) - { - var gitHubClientRepositoryCommitsCompare = await gitHubClient.Repository.Commits.Compare(user, repository, "master", targetMilestone.Title); - return gitHubClientRepositoryCommitsCompare.AheadBy; - } - - var compareResult = await gitHubClient.Repository.Commits.Compare(user, repository, previousMilestone.Title, "master"); - return compareResult.AheadBy; - } - catch (NotFoundException) - { - //If there is not tag yet the Compare will return a NotFoundException - //we can safely ignore - return 0; - } - } - Milestone GetPreviousMilestone() { var currentVersion = targetMilestone.Version(); @@ -131,33 +118,22 @@ static async Task AddFooter(StringBuilder stringBuilder) } } - void GetMilestones() + void LoadMilestones() { - var milestonesClient = gitHubClient.Issue.Milestone; - var closed = milestonesClient.GetForRepository(user, repository,new MilestoneRequest - { - State = ItemState.Closed - }).Result; - var open = milestonesClient.GetForRepository(user, repository,new MilestoneRequest - { - State = ItemState.Open - }).Result; - milestones = closed.Concat(open).ToList(); + milestones = gitHubClient.GetMilestones(); } async Task> GetIssues(Milestone milestone) { - var allIssues = await gitHubClient.AllIssuesForMilestone(milestone); - var issues = new List(); - foreach (var issue in allIssues.Where(x => x.State == ItemState.Closed)) + var issues = await gitHubClient.GetIssues(milestone); + foreach (var issue in issues) { CheckForValidLabels(issue); - issues.Add(issue); } return issues; } - void CheckForValidLabels(Issue issue) + static void CheckForValidLabels(Issue issue) { var count = issue.Labels.Count(l => l.Name == "Bug" || diff --git a/src/Compiler/ReleaseNotesCompiler.csproj b/src/Compiler/ReleaseNotesCompiler.csproj index 5ea23ab..41e1f76 100644 --- a/src/Compiler/ReleaseNotesCompiler.csproj +++ b/src/Compiler/ReleaseNotesCompiler.csproj @@ -48,6 +48,8 @@ + + diff --git a/src/Tests/FakeGitHubClient.cs b/src/Tests/FakeGitHubClient.cs new file mode 100644 index 0000000..eb583bf --- /dev/null +++ b/src/Tests/FakeGitHubClient.cs @@ -0,0 +1,35 @@ +namespace ReleaseNotesCompiler.Tests +{ + using System.Collections.Generic; + using System.Threading.Tasks; + using Octokit; + using IGitHubClient = ReleaseNotesCompiler.IGitHubClient; + + public class FakeGitHubClient : IGitHubClient + { + public List Milestones { get; set; } + public List Issues { get; set; } + public int NumberOfCommits { get; set; } + + public FakeGitHubClient() + { + Milestones = new List(); + Issues = new List(); + } + + public Task GetNumberOfCommitsBetween(Milestone previousMilestone, Milestone currentMilestone) + { + return Task.FromResult(NumberOfCommits); + } + + public Task> GetIssues(Milestone targetMilestone) + { + return Task.FromResult(Issues); + } + + public List GetMilestones() + { + return Milestones; + } + } +} \ No newline at end of file diff --git a/src/Tests/ReleaseNotesBuilderIntegrationTests.cs b/src/Tests/ReleaseNotesBuilderIntegrationTests.cs new file mode 100644 index 0000000..3f5f0dc --- /dev/null +++ b/src/Tests/ReleaseNotesBuilderIntegrationTests.cs @@ -0,0 +1,41 @@ +namespace ReleaseNotesCompiler.Tests +{ + using System.Diagnostics; + using NUnit.Framework; + using ReleaseNotesCompiler; + + [TestFixture] + public class ReleaseNotesBuilderIntegrationTests + { + [Test] + [Explicit] + public async void SingleMilestone() + { + var gitHubClient = ClientBuilder.Build(); + + var releaseNotesBuilder = new ReleaseNotesBuilder(new DefaultGitHubClient(gitHubClient, "Particular", "NServiceBus.Unity"), "Particular", "NServiceBus.Unity", "6.0.1"); + var result = await releaseNotesBuilder.BuildReleaseNotes(); + Debug.WriteLine(result); + ClipBoardHelper.SetClipboard(result); + } + + [Test] + [Explicit] + public async void SingleMilestone3() + { + var gitHubClient = ClientBuilder.Build(); + + var releaseNotesBuilder = new ReleaseNotesBuilder(new DefaultGitHubClient(gitHubClient, "Particular", "ServiceControl"), "Particular", "ServiceControl", "1.0.0-Beta4"); + var result = await releaseNotesBuilder.BuildReleaseNotes(); + Debug.WriteLine(result); + ClipBoardHelper.SetClipboard(result); + } + + [Test] + [Explicit] + public void OctokitTests() + { + ClientBuilder.Build(); + } + } +} diff --git a/src/Tests/ReleaseNotesBuilderTests.cs b/src/Tests/ReleaseNotesBuilderTests.cs index ed7ebae..57bbc4c 100644 --- a/src/Tests/ReleaseNotesBuilderTests.cs +++ b/src/Tests/ReleaseNotesBuilderTests.cs @@ -1,41 +1,95 @@ namespace ReleaseNotesCompiler.Tests { - using System.Diagnostics; + using System; + using System.Linq; using NUnit.Framework; - using ReleaseNotesCompiler; + using Octokit; [TestFixture] public class ReleaseNotesBuilderTests { [Test] - [Explicit] - public async void SingleMilestone() + public void It_prints_number_of_isses_closed() { - var gitHubClient = ClientBuilder.Build(); + var fakeClient = new FakeGitHubClient(); + fakeClient.Issues.Add(CreateIssue(1, "Bug")); + fakeClient.Issues.Add(CreateIssue(2, "Feature")); + fakeClient.Issues.Add(CreateIssue(3, "Improvement")); - var releaseNotesBuilder = new ReleaseNotesBuilder(gitHubClient, "Particular", "NServiceBus", "4.6.5"); - var result = await releaseNotesBuilder.BuildReleaseNotes(); - Debug.WriteLine(result); - ClipBoardHelper.SetClipboard(result); + fakeClient.Milestones.Add(CreateMilestone("1.2.3")); + + var builder = new ReleaseNotesBuilder(fakeClient, "SzymonPobiega", "FakeRepo", "1.2.3"); + + var notes = builder.BuildReleaseNotes().Result; + + Assert.IsTrue(notes.Contains("3 issues")); } + + [Test] + public void It_prints_number_of_commits_if_anything_has_been_committed() + { + var fakeClient = new FakeGitHubClient(); + fakeClient.Issues.Add(CreateIssue(1, "Bug")); + fakeClient.Issues.Add(CreateIssue(2, "Feature")); + fakeClient.Issues.Add(CreateIssue(3, "Improvement")); + fakeClient.NumberOfCommits = 5; + + fakeClient.Milestones.Add(CreateMilestone("1.2.3")); + var builder = new ReleaseNotesBuilder(fakeClient, "SzymonPobiega", "FakeRepo", "1.2.3"); + + var notes = builder.BuildReleaseNotes().Result; + + Assert.IsTrue(notes.Contains("5 commits")); + } + [Test] - [Explicit] - public async void SingleMilestone3() + public void It_does_not_print_number_of_issues_if_nothing_has_been_closed() { - var gitHubClient = ClientBuilder.Build(); + var fakeClient = new FakeGitHubClient(); + + fakeClient.Milestones.Add(CreateMilestone("1.2.3")); + + var builder = new ReleaseNotesBuilder(fakeClient, "SzymonPobiega", "FakeRepo", "1.2.3"); - var releaseNotesBuilder = new ReleaseNotesBuilder(gitHubClient, "Particular", "ServiceControl", "1.0.0-Beta4"); - var result = await releaseNotesBuilder.BuildReleaseNotes(); - Debug.WriteLine(result); - ClipBoardHelper.SetClipboard(result); + var notes = builder.BuildReleaseNotes().Result; + + Assert.IsFalse(notes.Contains("0 issues")); } [Test] - [Explicit] - public void OctokitTests() + public void It_does_not_print_number_of_commits_if_nothing_has_been_committed() + { + var fakeClient = new FakeGitHubClient(); + + fakeClient.Milestones.Add(CreateMilestone("1.2.3")); + + var builder = new ReleaseNotesBuilder(fakeClient, "SzymonPobiega", "FakeRepo", "1.2.3"); + + var notes = builder.BuildReleaseNotes().Result; + + Assert.IsFalse(notes.Contains("0 commits")); + } + + static Milestone CreateMilestone(string version) + { + return new Milestone() + { + Title = version, + Url = new Uri("https://github.com/Particular/FakeRepo/issues?q=milestone%3A" + version) + }; + } + + static Issue CreateIssue(int number, params string[] labels) { - ClientBuilder.Build(); + return new Issue() + { + Number = number, + Title = "Issue "+number, + HtmlUrl = new Uri("http://example.com/"+number), + Body = "Some issue", + Labels = labels.Select(x => new Label {Name = x}).ToArray(), + }; } } -} +} \ No newline at end of file diff --git a/src/Tests/ReleaseNotesCompiler.Tests.csproj b/src/Tests/ReleaseNotesCompiler.Tests.csproj index d533ffb..58ab896 100644 --- a/src/Tests/ReleaseNotesCompiler.Tests.csproj +++ b/src/Tests/ReleaseNotesCompiler.Tests.csproj @@ -51,10 +51,12 @@ + - + +