From 1ae21ba5d4a9cdda3e37f2533c10fa1926ca2269 Mon Sep 17 00:00:00 2001 From: Gary Ewan Park Date: Fri, 17 Apr 2020 20:28:48 +0100 Subject: [PATCH 001/181] (build) Update to latest Cake.Recipe --- recipe.cake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/recipe.cake b/recipe.cake index 0c1de526..df0c665b 100644 --- a/recipe.cake +++ b/recipe.cake @@ -1,4 +1,4 @@ -#load nuget:https://www.myget.org/F/cake-contrib/api/v2?package=Cake.Recipe&version=2.0.0-unstable0023&prerelease +#load nuget:https://www.myget.org/F/cake-contrib/api/v2?package=Cake.Recipe&version=2.0.0-unstable0029&prerelease Environment.SetVariableNames(githubUserNameVariable: "GITTOOLS_GITHUB_USERNAME", githubPasswordVariable: "GITTOOLS_GITHUB_PASSWORD", @@ -49,4 +49,4 @@ BuildParameters.Tasks.CreateReleaseNotesTask BuildParameters.Tasks.PublishPreReleasePackagesTask.IsDependentOn(BuildParameters.Tasks.PublishGitHubReleaseTask); BuildParameters.Tasks.PublishReleasePackagesTask.IsDependentOn(BuildParameters.Tasks.PublishGitHubReleaseTask); -Build.RunDotNetCore(); \ No newline at end of file +Build.RunDotNetCore(); From 6f8724d9e72bc88c2c27b2d1a5e635469b839c9f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2020 19:31:16 +0000 Subject: [PATCH 002/181] Bump Octokit from 0.44.0 to 0.47.0 in /Source Bumps [Octokit](https://github.com/octokit/octokit.net) from 0.44.0 to 0.47.0. - [Release notes](https://github.com/octokit/octokit.net/releases) - [Changelog](https://github.com/octokit/octokit.net/blob/master/ReleaseNotes.md) - [Commits](https://github.com/octokit/octokit.net/compare/v0.44.0...v0.47.0) Signed-off-by: dependabot-preview[bot] --- Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj | 2 +- Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj | 2 +- Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj | 2 +- Source/GitReleaseManager/GitReleaseManager.Core.csproj | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj index 25a08ca4..bc045686 100644 --- a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj +++ b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj @@ -17,7 +17,7 @@ - + \ No newline at end of file diff --git a/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj b/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj index 06ba2bb6..a3f6ead6 100644 --- a/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj +++ b/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj @@ -32,7 +32,7 @@ - + diff --git a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj index 93c85167..ec899a6d 100644 --- a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj +++ b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj @@ -18,6 +18,6 @@ - + \ No newline at end of file diff --git a/Source/GitReleaseManager/GitReleaseManager.Core.csproj b/Source/GitReleaseManager/GitReleaseManager.Core.csproj index 91b3dad0..c09addc6 100644 --- a/Source/GitReleaseManager/GitReleaseManager.Core.csproj +++ b/Source/GitReleaseManager/GitReleaseManager.Core.csproj @@ -11,7 +11,7 @@ - + From 46ea9871d8087f54dbec97fe3dafa85d5b0a0f62 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2020 19:39:57 +0000 Subject: [PATCH 003/181] Bump ApprovalTests from 4.5.1 to 5.0.4 in /Source Bumps [ApprovalTests](https://github.com/approvals/ApprovalTests.Net) from 4.5.1 to 5.0.4. - [Release notes](https://github.com/approvals/ApprovalTests.Net/releases) - [Commits](https://github.com/approvals/ApprovalTests.Net/commits) Signed-off-by: dependabot-preview[bot] --- Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj index ec899a6d..fa64c104 100644 --- a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj +++ b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj @@ -15,7 +15,7 @@ - + From 6e7e5e448197c00140b4ad37244deee7a0c15693 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2020 20:00:46 +0000 Subject: [PATCH 004/181] Bump TextCopy from 3.0.1 to 3.0.2 in /Source Bumps [TextCopy](https://github.com/SimonCropp/TextCopy) from 3.0.1 to 3.0.2. - [Release notes](https://github.com/SimonCropp/TextCopy/releases) - [Commits](https://github.com/SimonCropp/TextCopy/commits) Signed-off-by: dependabot-preview[bot] --- .../GitReleaseManager.IntegrationTests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj index 8b066ec1..1027bb4e 100644 --- a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj +++ b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj @@ -18,6 +18,6 @@ - + \ No newline at end of file From 08bc4ef79fb550af68cf7dc817ca43553e771c07 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2020 07:29:30 +0000 Subject: [PATCH 005/181] Bump Microsoft.NET.Test.Sdk from 16.5.0 to 16.6.0 in /Source Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.5.0 to 16.6.0. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v16.5.0...v16.6.0) Signed-off-by: dependabot-preview[bot] --- .../GitReleaseManager.IntegrationTests.csproj | 2 +- Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj index 1027bb4e..733bd4b1 100644 --- a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj +++ b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj @@ -16,7 +16,7 @@ - + diff --git a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj index fa64c104..49c3265b 100644 --- a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj +++ b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj @@ -14,7 +14,7 @@ - + From fc81c5d5b420e457ece9e5c5cd0e1e46be016376 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2020 20:17:25 +0000 Subject: [PATCH 006/181] Bump YamlDotNet from 8.1.0 to 8.1.1 in /Source Bumps [YamlDotNet](https://github.com/aaubry/YamlDotNet) from 8.1.0 to 8.1.1. - [Release notes](https://github.com/aaubry/YamlDotNet/releases) - [Changelog](https://github.com/aaubry/YamlDotNet/blob/master/RELEASE_NOTES.md) - [Commits](https://github.com/aaubry/YamlDotNet/compare/v8.1.0...v8.1.1) Signed-off-by: dependabot-preview[bot] --- Source/GitReleaseManager/GitReleaseManager.Core.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GitReleaseManager/GitReleaseManager.Core.csproj b/Source/GitReleaseManager/GitReleaseManager.Core.csproj index c09addc6..b4f77adf 100644 --- a/Source/GitReleaseManager/GitReleaseManager.Core.csproj +++ b/Source/GitReleaseManager/GitReleaseManager.Core.csproj @@ -13,7 +13,7 @@ - + \ No newline at end of file From a96cf3ee785249afbaec253c9b9ba197c29226f1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2020 07:48:05 +0000 Subject: [PATCH 007/181] Bump Microsoft.NET.Test.Sdk from 16.6.0 to 16.6.1 in /Source Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.6.0 to 16.6.1. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v16.6.0...v16.6.1) Signed-off-by: dependabot-preview[bot] --- .../GitReleaseManager.IntegrationTests.csproj | 2 +- Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj index 733bd4b1..b8223b81 100644 --- a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj +++ b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj @@ -16,7 +16,7 @@ - + diff --git a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj index 49c3265b..8ef2299c 100644 --- a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj +++ b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj @@ -14,7 +14,7 @@ - + From 1c2ccb504f46a6e3ec508453edd8e9a0b4efcc1f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2020 12:58:41 +0000 Subject: [PATCH 008/181] Bump ApprovalTests from 5.0.4 to 5.1.0 in /Source Bumps [ApprovalTests](https://github.com/approvals/ApprovalTests.Net) from 5.0.4 to 5.1.0. - [Release notes](https://github.com/approvals/ApprovalTests.Net/releases) - [Commits](https://github.com/approvals/ApprovalTests.Net/commits) Signed-off-by: dependabot-preview[bot] --- Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj index 8ef2299c..ac2162c4 100644 --- a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj +++ b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj @@ -15,7 +15,7 @@ - + From a0c0dab416db31e9af993689764eb21a4d860d3e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2020 13:07:40 +0000 Subject: [PATCH 009/181] Bump Microsoft.CodeAnalysis.FxCopAnalyzers in /Source Bumps [Microsoft.CodeAnalysis.FxCopAnalyzers](https://github.com/dotnet/roslyn-analyzers) from 2.9.8 to 3.0.0. - [Release notes](https://github.com/dotnet/roslyn-analyzers/releases) - [Changelog](https://github.com/dotnet/roslyn-analyzers/blob/master/PostReleaseActivities.md) - [Commits](https://github.com/dotnet/roslyn-analyzers/compare/v2.9.8...v3.0.0) Signed-off-by: dependabot-preview[bot] --- Source/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Directory.Build.props b/Source/Directory.Build.props index f927b7cd..75bbda4a 100644 --- a/Source/Directory.Build.props +++ b/Source/Directory.Build.props @@ -14,7 +14,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all From 7b5d7d7186c1935942faed80753845b3546c133c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 8 May 2020 07:07:55 +0000 Subject: [PATCH 010/181] Bump ApprovalTests from 5.1.0 to 5.1.1 in /Source Bumps [ApprovalTests](https://github.com/approvals/ApprovalTests.Net) from 5.1.0 to 5.1.1. - [Release notes](https://github.com/approvals/ApprovalTests.Net/releases) - [Commits](https://github.com/approvals/ApprovalTests.Net/commits) Signed-off-by: dependabot-preview[bot] --- Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj index ac2162c4..a2e33399 100644 --- a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj +++ b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj @@ -15,7 +15,7 @@ - + From 920664f61b993ca0d63fe19f580e45b562fc7c45 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 12 May 2020 07:19:10 +0000 Subject: [PATCH 011/181] Bump ApprovalTests from 5.1.1 to 5.2.1 in /Source Bumps [ApprovalTests](https://github.com/approvals/ApprovalTests.Net) from 5.1.1 to 5.2.1. - [Release notes](https://github.com/approvals/ApprovalTests.Net/releases) - [Commits](https://github.com/approvals/ApprovalTests.Net/commits) Signed-off-by: dependabot-preview[bot] --- Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj index a2e33399..eda2d4e0 100644 --- a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj +++ b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj @@ -15,7 +15,7 @@ - + From 79b275a866622f88a3e3211878123232789d3805 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 20:19:12 +0000 Subject: [PATCH 012/181] Bump TextCopy from 3.0.2 to 3.3.0 in /Source Bumps [TextCopy](https://github.com/CopyText/TextCopy) from 3.0.2 to 3.3.0. - [Release notes](https://github.com/CopyText/TextCopy/releases) - [Commits](https://github.com/CopyText/TextCopy/compare/3.0.2...3.3.0) Signed-off-by: dependabot-preview[bot] --- .../GitReleaseManager.IntegrationTests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj index b8223b81..cc91c59f 100644 --- a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj +++ b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj @@ -18,6 +18,6 @@ - + \ No newline at end of file From a3916ec2531f0e81089b48d9c2cea058e8acbc1c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 14 May 2020 20:27:13 +0000 Subject: [PATCH 013/181] Bump CommandLineParser from 2.7.82 to 2.8.0 in /Source Bumps [CommandLineParser](https://github.com/commandlineparser/commandline) from 2.7.82 to 2.8.0. - [Release notes](https://github.com/commandlineparser/commandline/releases) - [Changelog](https://github.com/commandlineparser/commandline/blob/master/CHANGELOG.md) - [Commits](https://github.com/commandlineparser/commandline/commits/2.8.0) Signed-off-by: dependabot-preview[bot] --- Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj | 2 +- Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj index bc045686..e105bf53 100644 --- a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj +++ b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj @@ -16,7 +16,7 @@ - + diff --git a/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj b/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj index a3f6ead6..bcb74085 100644 --- a/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj +++ b/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj @@ -31,7 +31,7 @@ - + From eff28a80480f9b4819072e84ef0da7e381da35a5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 29 May 2020 07:11:21 +0000 Subject: [PATCH 014/181] Bump YamlDotNet from 8.1.1 to 8.1.2 in /Source Bumps [YamlDotNet](https://github.com/aaubry/YamlDotNet) from 8.1.1 to 8.1.2. - [Release notes](https://github.com/aaubry/YamlDotNet/releases) - [Changelog](https://github.com/aaubry/YamlDotNet/blob/master/RELEASE_NOTES.md) - [Commits](https://github.com/aaubry/YamlDotNet/compare/v8.1.1...v8.1.2) Signed-off-by: dependabot-preview[bot] --- Source/GitReleaseManager/GitReleaseManager.Core.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GitReleaseManager/GitReleaseManager.Core.csproj b/Source/GitReleaseManager/GitReleaseManager.Core.csproj index b4f77adf..0371816f 100644 --- a/Source/GitReleaseManager/GitReleaseManager.Core.csproj +++ b/Source/GitReleaseManager/GitReleaseManager.Core.csproj @@ -13,7 +13,7 @@ - + \ No newline at end of file From cef7956883cd1034a6e8e4fe2b40b7edac8178a1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 30 May 2020 00:25:11 +0200 Subject: [PATCH 015/181] (maint) Bump ApprovalTests from 5.2.1 to 5.2.5 in /Source (#244) Bumps [ApprovalTests](https://github.com/approvals/ApprovalTests.Net) from 5.2.1 to 5.2.5. - [Release notes](https://github.com/approvals/ApprovalTests.Net/releases) - [Commits](https://github.com/approvals/ApprovalTests.Net/commits) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj index eda2d4e0..146142ce 100644 --- a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj +++ b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj @@ -15,7 +15,7 @@ - + From 7286f3b90a6ff30fa191d73ab29c9ec788489a37 Mon Sep 17 00:00:00 2001 From: Gary Ewan Park Date: Fri, 24 Jul 2020 20:29:00 +0100 Subject: [PATCH 016/181] (build) Fix build Switch to Azure DevOps feed, rather than MyGet --- .appveyor.yml | 2 +- build.ps1 | 7 ++++++- build.sh | 2 +- recipe.cake | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index c38995ae..abb7e0b1 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -8,7 +8,7 @@ image: Visual Studio 2019 # Build Script # #---------------------------------# build_script: - - ps: .\build.ps1 -Target ContinuousIntegration + - ps: .\build.ps1 -Target CI #---------------------------------# # Tests diff --git a/build.ps1 b/build.ps1 index f8deb004..b5c276d7 100644 --- a/build.ps1 +++ b/build.ps1 @@ -250,5 +250,10 @@ $cakeArguments += $ScriptArgs # Start Cake Write-Host "Running build script..." -Invoke-Expression "& $CAKE_EXE_INVOCATION $($cakeArguments -join " ")" + +Invoke-Expression "& $CAKE_EXE_INVOCATION ./recipe.cake --bootstrap" +if ($LASTEXITCODE -eq 0) +{ + Invoke-Expression "& $CAKE_EXE_INVOCATION $($cakeArguments -join " ")" +} exit $LASTEXITCODE \ No newline at end of file diff --git a/build.sh b/build.sh index 73b9719f..924cdb3d 100755 --- a/build.sh +++ b/build.sh @@ -121,4 +121,4 @@ if [ ! -f "$CAKE_EXE" ]; then fi # Start Cake -exec mono "$CAKE_EXE" $SCRIPT "${CAKE_ARGUMENTS[@]}" \ No newline at end of file +(exec mono "$CAKE_EXE" recipe.cake --bootstrap) && (exec mono "$CAKE_EXE" recipe.cake "$@") \ No newline at end of file diff --git a/recipe.cake b/recipe.cake index df0c665b..0296cb28 100644 --- a/recipe.cake +++ b/recipe.cake @@ -1,4 +1,4 @@ -#load nuget:https://www.myget.org/F/cake-contrib/api/v2?package=Cake.Recipe&version=2.0.0-unstable0029&prerelease +#load nuget:https://pkgs.dev.azure.com/cake-contrib/Home/_packaging/addins/nuget/v3/index.json?package=Cake.Recipe&version=2.0.0-alpha0319&prerelease Environment.SetVariableNames(githubUserNameVariable: "GITTOOLS_GITHUB_USERNAME", githubPasswordVariable: "GITTOOLS_GITHUB_PASSWORD", From ee230ef351ab068cae0dcdd60086f0283faaf24f Mon Sep 17 00:00:00 2001 From: Gary Ewan Park Date: Fri, 24 Jul 2020 20:41:25 +0100 Subject: [PATCH 017/181] (build) Update to latest build.sh So that arguments are passed through correctly --- build.sh | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/build.sh b/build.sh index 924cdb3d..b0ab5d37 100755 --- a/build.sh +++ b/build.sh @@ -7,7 +7,7 @@ ########################################################################## # Define directories. -SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) TOOLS_DIR=$SCRIPT_DIR/tools ADDINS_DIR=$TOOLS_DIR/Addins MODULES_DIR=$TOOLS_DIR/Modules @@ -33,23 +33,16 @@ CAKE_ARGUMENTS=() # Parse arguments. for i in "$@"; do case $1 in - -s | --script) - SCRIPT="$2" - shift - ;; - --) - shift - CAKE_ARGUMENTS+=("$@") - break - ;; - *) CAKE_ARGUMENTS+=("$1") ;; + -s|--script) SCRIPT="$2"; shift ;; + --) shift; CAKE_ARGUMENTS+=("$@"); break ;; + *) CAKE_ARGUMENTS+=("$1") ;; esac shift done # Make sure the tools folder exist. if [ ! -d "$TOOLS_DIR" ]; then - mkdir "$TOOLS_DIR" + mkdir "$TOOLS_DIR" fi # Make sure that packages.config exist. @@ -74,7 +67,7 @@ fi # Restore tools from NuGet. pushd "$TOOLS_DIR" >/dev/null -if [ ! -f "$PACKAGES_CONFIG_MD5" ] || [ "$(cat "$PACKAGES_CONFIG_MD5" | sed 's/\r$//')" != "$($MD5_EXE "$PACKAGES_CONFIG" | awk '{ print $1 }')" ]; then +if [ ! -f "$PACKAGES_CONFIG_MD5" ] || [ "$( cat "$PACKAGES_CONFIG_MD5" | sed 's/\r$//' )" != "$( $MD5_EXE "$PACKAGES_CONFIG" | awk '{ print $1 }' )" ]; then find . -type d ! -name . ! -name 'Cake.Bakery' | xargs rm -rf fi @@ -84,7 +77,7 @@ if [ $? -ne 0 ]; then exit 1 fi -$MD5_EXE "$PACKAGES_CONFIG" | awk '{ print $1 }' >|"$PACKAGES_CONFIG_MD5" +$MD5_EXE "$PACKAGES_CONFIG" | awk '{ print $1 }' >| "$PACKAGES_CONFIG_MD5" popd >/dev/null @@ -121,4 +114,4 @@ if [ ! -f "$CAKE_EXE" ]; then fi # Start Cake -(exec mono "$CAKE_EXE" recipe.cake --bootstrap) && (exec mono "$CAKE_EXE" recipe.cake "$@") \ No newline at end of file +(exec mono "$CAKE_EXE" $SCRIPT --bootstrap) && (exec mono "$CAKE_EXE" recipe.cake "${CAKE_ARGUMENTS[@]}") \ No newline at end of file From ac7040cafa470a43d7584245c69b3da77baf3b4b Mon Sep 17 00:00:00 2001 From: Gary Ewan Park Date: Fri, 24 Jul 2020 20:41:53 +0100 Subject: [PATCH 018/181] (build) Enable deterministic build --- Source/Directory.Build.targets | 28 +++++++++++++++++++ .../GitReleaseManager.Cli.csproj | 4 +++ .../GitReleaseManager.Tool.csproj | 4 +++ .../GitReleaseManager.IntegrationTests.csproj | 8 ++++++ .../GitReleaseManager.Tests.csproj | 8 ++++++ .../GitReleaseManager.Core.csproj | 4 +++ 6 files changed, 56 insertions(+) create mode 100644 Source/Directory.Build.targets diff --git a/Source/Directory.Build.targets b/Source/Directory.Build.targets new file mode 100644 index 00000000..690ab261 --- /dev/null +++ b/Source/Directory.Build.targets @@ -0,0 +1,28 @@ + + + + + + + + true + true + $([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)')) + + + + + + + + + + + <_LocalTopLevelSourceRoot Include="@(SourceRoot)" Condition="'%(SourceRoot.NestedRoot)' == ''"/> + + + diff --git a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj index e105bf53..dd3b7574 100644 --- a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj +++ b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj @@ -17,6 +17,10 @@ + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj b/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj index bcb74085..31852f76 100644 --- a/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj +++ b/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj @@ -32,6 +32,10 @@ + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj index cc91c59f..1478274f 100644 --- a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj +++ b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj @@ -14,6 +14,14 @@ + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj index 146142ce..a75bf9d4 100644 --- a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj +++ b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj @@ -14,8 +14,16 @@ + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/Source/GitReleaseManager/GitReleaseManager.Core.csproj b/Source/GitReleaseManager/GitReleaseManager.Core.csproj index 0371816f..e2832bac 100644 --- a/Source/GitReleaseManager/GitReleaseManager.Core.csproj +++ b/Source/GitReleaseManager/GitReleaseManager.Core.csproj @@ -11,6 +11,10 @@ + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + From bd1271c02e0253efc3854987c1c64808818a8889 Mon Sep 17 00:00:00 2001 From: Gary Ewan Park Date: Fri, 24 Jul 2020 21:11:53 +0100 Subject: [PATCH 019/181] (build) Remove usage of SolutionInfo.cs --- .../GitReleaseManager.Cli.csproj | 4 ---- .../GitReleaseManager.Tool.csproj | 3 --- .../GitReleaseManager.IntegrationTests.csproj | 4 ---- .../GitReleaseManager.Tests.csproj | 4 ---- .../GitReleaseManager.Core.csproj | 4 ---- Source/SolutionInfo.cs | 20 ------------------- 6 files changed, 39 deletions(-) delete mode 100644 Source/SolutionInfo.cs diff --git a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj index dd3b7574..767c1515 100644 --- a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj +++ b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj @@ -7,11 +7,7 @@ GitReleaseManager.Cli Create release notes in markdown given a milestone false - false - - - diff --git a/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj b/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj index 31852f76..a5249113 100644 --- a/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj +++ b/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj @@ -24,9 +24,6 @@ git https://github.com/GitTools/GitReleaseManager.git - - - diff --git a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj index 1478274f..2ca23145 100644 --- a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj +++ b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj @@ -4,12 +4,8 @@ net472;netcoreapp2.2 GitReleaseManager.IntegrationTests Integration Test Project for GitReleaseManager - false $(NoWarn);CA1707 - - - diff --git a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj index a75bf9d4..43a94947 100644 --- a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj +++ b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj @@ -4,12 +4,8 @@ net472;netcoreapp2.2 GitReleaseManager.Tests Test Project for GitReleaseManager - false $(NoWarn);CA1707 - - - diff --git a/Source/GitReleaseManager/GitReleaseManager.Core.csproj b/Source/GitReleaseManager/GitReleaseManager.Core.csproj index e2832bac..9166aa50 100644 --- a/Source/GitReleaseManager/GitReleaseManager.Core.csproj +++ b/Source/GitReleaseManager/GitReleaseManager.Core.csproj @@ -4,12 +4,8 @@ netstandard2.0;net461 GitReleaseManager.Core Create release notes in markdown given a milestone - false false - - - runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Source/SolutionInfo.cs b/Source/SolutionInfo.cs deleted file mode 100644 index ea60d85f..00000000 --- a/Source/SolutionInfo.cs +++ /dev/null @@ -1,20 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by Cake. -// -//------------------------------------------------------------------------------ - -using System; -using System.Reflection; -using System.Resources; -using System.Runtime.InteropServices; - -[assembly: AssemblyCompany("GitTools Contributors")] -[assembly: AssemblyProduct("GitReleaseManager")] -[assembly: AssemblyVersion("0.1.0")] -[assembly: AssemblyFileVersion("0.1.0")] -[assembly: AssemblyInformationalVersion("0.1.0")] -[assembly: AssemblyCopyright("Copyright 2015 - Present - GitTools Contributors")] -[assembly: NeutralResourcesLanguage("en-GB")] -[assembly: CLSCompliant(false)] -[assembly: ComVisible(false)] \ No newline at end of file From 8a1eef464bf2f56948e04faf37bb67b6a8cbfc1e Mon Sep 17 00:00:00 2001 From: Gary Ewan Park Date: Fri, 24 Jul 2020 21:15:04 +0100 Subject: [PATCH 020/181] (build) Remove additional attribute Should have really been in the last commit. --- Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj b/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj index a5249113..f46296cc 100644 --- a/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj +++ b/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj @@ -20,7 +20,6 @@ MIT package_icon.png https://github.com/GitTools/GitReleaseManager/releases - false git https://github.com/GitTools/GitReleaseManager.git From bd128aff2ec6d6b08c9454ff1aa0d2be3188f51b Mon Sep 17 00:00:00 2001 From: AdmiringWorm Date: Sat, 25 Jul 2020 00:38:26 +0200 Subject: [PATCH 021/181] (maint) Split Tools project to its own project directory Due to most likely a change in .NET Core, compile erros now happen because of the override of 'BaseIntermediateOutputPath' that resulted in duplicate AssemblyVersion files being included when running multiple builds. This commit splits out all of the projects to their own respective directory instead of re-using the same directory for the CLI and the Tools project --- .../Directory.Build.props | 12 ------------ .../GitReleaseManager.Cli.csproj | 8 ++++++-- .../GitReleaseManager.Tool.csproj | 12 ++++++++++-- Source/GitReleaseManager.sln | 18 ++++++------------ 4 files changed, 22 insertions(+), 28 deletions(-) delete mode 100644 Source/GitReleaseManager.Cli/Directory.Build.props rename Source/{GitReleaseManager.Cli => GitReleaseManager.Tool}/GitReleaseManager.Tool.csproj (72%) diff --git a/Source/GitReleaseManager.Cli/Directory.Build.props b/Source/GitReleaseManager.Cli/Directory.Build.props deleted file mode 100644 index 94650e73..00000000 --- a/Source/GitReleaseManager.Cli/Directory.Build.props +++ /dev/null @@ -1,12 +0,0 @@ - - - $(MSBuildThisFileDirectory)obj\$(MSBuildProjectName)\ - - - - - - - - - \ No newline at end of file diff --git a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj index 767c1515..6ab2e3b3 100644 --- a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj +++ b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj @@ -13,11 +13,15 @@ + - runtime; build; native; contentfiles; analyzers; buildtransitive - all + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + \ No newline at end of file diff --git a/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj b/Source/GitReleaseManager.Tool/GitReleaseManager.Tool.csproj similarity index 72% rename from Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj rename to Source/GitReleaseManager.Tool/GitReleaseManager.Tool.csproj index f46296cc..928c2151 100644 --- a/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj +++ b/Source/GitReleaseManager.Tool/GitReleaseManager.Tool.csproj @@ -23,16 +23,24 @@ git https://github.com/GitTools/GitReleaseManager.git + + + + - runtime; build; native; contentfiles; analyzers; buildtransitive - all + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + diff --git a/Source/GitReleaseManager.sln b/Source/GitReleaseManager.sln index b0952036..5bdbb63e 100644 --- a/Source/GitReleaseManager.sln +++ b/Source/GitReleaseManager.sln @@ -2,16 +2,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29519.181 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuSpecs", "NuSpecs", "{87E2E61F-5F5D-45F1-8C4A-98E0BF8CA01D}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GitReleaseManager.Tests", "GitReleaseManager.Tests\GitReleaseManager.Tests.csproj", "{FAD045A3-CF63-48CA-BA49-8F4D79E3EF4F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GitReleaseManager.Cli", "GitReleaseManager.Cli\GitReleaseManager.Cli.csproj", "{F1163F09-3D4E-4F95-AF46-24C15AB297FB}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GitReleaseManager.Core", "GitReleaseManager\GitReleaseManager.Core.csproj", "{B02A026E-CA3A-48F4-BBA9-EB337B0A2035}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GitReleaseManager.Tool", "GitReleaseManager.Cli\GitReleaseManager.Tool.csproj", "{56F96DA7-E286-46C7-88DB-068F4BE96538}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C87778A7-B100-4D05-A050-BA37BD59058C}" ProjectSection(SolutionItems) = preProject Directory.Build.props = Directory.Build.props @@ -33,6 +29,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Chocolatey", "Chocolatey", ..\nuspec\chocolatey\VERIFICATION.TXT = ..\nuspec\chocolatey\VERIFICATION.TXT EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitReleaseManager.Tool", "GitReleaseManager.Tool\GitReleaseManager.Tool.csproj", "{E60129C7-706A-4B24-9D8D-6D5F23543280}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -51,22 +49,18 @@ Global {B02A026E-CA3A-48F4-BBA9-EB337B0A2035}.Debug|Any CPU.Build.0 = Debug|Any CPU {B02A026E-CA3A-48F4-BBA9-EB337B0A2035}.Release|Any CPU.ActiveCfg = Release|Any CPU {B02A026E-CA3A-48F4-BBA9-EB337B0A2035}.Release|Any CPU.Build.0 = Release|Any CPU - {56F96DA7-E286-46C7-88DB-068F4BE96538}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {56F96DA7-E286-46C7-88DB-068F4BE96538}.Debug|Any CPU.Build.0 = Debug|Any CPU - {56F96DA7-E286-46C7-88DB-068F4BE96538}.Release|Any CPU.ActiveCfg = Release|Any CPU - {56F96DA7-E286-46C7-88DB-068F4BE96538}.Release|Any CPU.Build.0 = Release|Any CPU {53D8DA02-2BF8-454A-997C-B6BE62F90F9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {53D8DA02-2BF8-454A-997C-B6BE62F90F9E}.Debug|Any CPU.Build.0 = Debug|Any CPU {53D8DA02-2BF8-454A-997C-B6BE62F90F9E}.Release|Any CPU.ActiveCfg = Release|Any CPU {53D8DA02-2BF8-454A-997C-B6BE62F90F9E}.Release|Any CPU.Build.0 = Release|Any CPU + {E60129C7-706A-4B24-9D8D-6D5F23543280}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E60129C7-706A-4B24-9D8D-6D5F23543280}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E60129C7-706A-4B24-9D8D-6D5F23543280}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E60129C7-706A-4B24-9D8D-6D5F23543280}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {29340E98-B35A-4738-9784-580D48C6AD3D} = {87E2E61F-5F5D-45F1-8C4A-98E0BF8CA01D} - {2EB7AC4C-8600-4F99-9029-E9F36B83D1C2} = {87E2E61F-5F5D-45F1-8C4A-98E0BF8CA01D} - EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DBDED135-9696-4CB2-9D4D-EACFF30B4A99} EndGlobalSection From e656f06018c4631fb5ccb3cfa7d5a4e83cb7ca74 Mon Sep 17 00:00:00 2001 From: AdmiringWorm Date: Sat, 25 Jul 2020 00:41:01 +0200 Subject: [PATCH 022/181] (maint) Add generated assembly info files to dupfinder ignore list --- recipe.cake | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/recipe.cake b/recipe.cake index 0296cb28..63a49a9c 100644 --- a/recipe.cake +++ b/recipe.cake @@ -26,7 +26,8 @@ ToolSettings.SetToolSettings(context: Context, dupFinderExcludePattern: new string[] { BuildParameters.RootDirectoryPath + "/Source/GitReleaseManager.Tests/*.cs", BuildParameters.RootDirectoryPath + "/Source/GitReleaseManager.IntegrationTests/*.cs", - BuildParameters.RootDirectoryPath + "/Source/GitReleaseManager/AutoMapperConfiguration.cs" }, + BuildParameters.RootDirectoryPath + "/Source/GitReleaseManager/AutoMapperConfiguration.cs", + "**/*.AssemblyInfo.cs" }, testCoverageFilter: "+[GitReleaseManager*]* -[GitReleaseManager.Tests*]*", testCoverageExcludeByAttribute: "*.ExcludeFromCodeCoverage*", testCoverageExcludeByFile: "*/*Designer.cs;*/*.g.cs;*/*.g.i.cs"); @@ -49,4 +50,4 @@ BuildParameters.Tasks.CreateReleaseNotesTask BuildParameters.Tasks.PublishPreReleasePackagesTask.IsDependentOn(BuildParameters.Tasks.PublishGitHubReleaseTask); BuildParameters.Tasks.PublishReleasePackagesTask.IsDependentOn(BuildParameters.Tasks.PublishGitHubReleaseTask); -Build.RunDotNetCore(); +Build.RunDotNetCore(); \ No newline at end of file From 8b518c5e430b38f97e0b0e9527780601a4f54f9a Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 23 Jul 2020 18:35:09 +0200 Subject: [PATCH 023/181] Fix docs markdown format --- docs/input/docs/advanced.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/input/docs/advanced.md b/docs/input/docs/advanced.md index 687596cd..eaefb70f 100644 --- a/docs/input/docs/advanced.md +++ b/docs/input/docs/advanced.md @@ -48,20 +48,20 @@ Every build of Chocolatey GUI generates a number of Build Artifacts, these inclu - Chocolatey GUI uses [AppVeyor](http://www.appveyor.com/) as it's Continuous Integration Server. - Any time a **Pull Request** is created, an AppVeyor build is triggered, but no deployment of the build artifacts takes place -- Any time a commit is made into the **develop **branch, an AppVeyor build is +- Any time a commit is made into the **develop** branch, an AppVeyor build is triggered, and the build artifacts are deployed to the [MyGet Develop Feed](https://www.myget.org/feed/Packages/ghrm_develop) -- Any time a commit is made into the **master **branch, an AppVeyor build is +- Any time a commit is made into the **master** branch, an AppVeyor build is triggered, and the build artifacts are deployed to the [MyGet Master Feed](https://www.myget.org/feed/Packages/ghrm_master) -- Any time a **tag **is applied to the repository, an AppVeyor build is +- Any time a **tag** is applied to the repository, an AppVeyor build is triggered, and the build artifacts are deployed to [Chocolatey.org](https://chocolatey.org/) for public consumption. ### Ok, so where does GitReleaseManager come into play? The role of GitReleaseManager really comes into play when moving between a -**release** or **hotfix** branch and the **master **branch. +**release** or **hotfix** branch and the **master** branch. Let's say you have done a bunch of work on the develop branch, you want to move all of that work into the master branch, via a release branch. When you do @@ -71,7 +71,7 @@ the issues list, everything that is being included in the release, and now would seem like a great time to create some release notes. And this is exactly what the build process for Chocolatey GUI does. Let's break this down further... -- A **release **branch is created from **develop **branch +- A **release** branch is created from **develop** branch - The release branch is merged into master branch, triggering a build (with deployment to MyGet Master Feed). - During this build, GitReleaseManager is executed, using the **create** From 5341670709015ca12100d1f0e94b08aea5e1ae82 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 26 Jul 2020 18:35:34 +0000 Subject: [PATCH 024/181] Bump AutoMapper from 9.0.0 to 10.0.0 in /Source Bumps [AutoMapper](https://github.com/AutoMapper/AutoMapper) from 9.0.0 to 10.0.0. - [Release notes](https://github.com/AutoMapper/AutoMapper/releases) - [Changelog](https://github.com/AutoMapper/AutoMapper/blob/master/docs/API-Changes.md) - [Commits](https://github.com/AutoMapper/AutoMapper/compare/v9.0.0...v10.0.0) Signed-off-by: dependabot-preview[bot] --- Source/GitReleaseManager/GitReleaseManager.Core.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GitReleaseManager/GitReleaseManager.Core.csproj b/Source/GitReleaseManager/GitReleaseManager.Core.csproj index 9166aa50..ef15069c 100644 --- a/Source/GitReleaseManager/GitReleaseManager.Core.csproj +++ b/Source/GitReleaseManager/GitReleaseManager.Core.csproj @@ -14,6 +14,6 @@ - + \ No newline at end of file From 32a161af9881a93a694dcb02bbf60f557d530100 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 26 Jul 2020 18:42:31 +0000 Subject: [PATCH 025/181] Bump Octokit from 0.47.0 to 0.48.0 in /Source Bumps [Octokit](https://github.com/octokit/octokit.net) from 0.47.0 to 0.48.0. - [Release notes](https://github.com/octokit/octokit.net/releases) - [Changelog](https://github.com/octokit/octokit.net/blob/master/ReleaseNotes.md) - [Commits](https://github.com/octokit/octokit.net/compare/v0.47.0...v0.48.0) Signed-off-by: dependabot-preview[bot] --- Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj | 2 +- Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj | 2 +- Source/GitReleaseManager.Tool/GitReleaseManager.Tool.csproj | 2 +- Source/GitReleaseManager/GitReleaseManager.Core.csproj | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj index 6ab2e3b3..c073531f 100644 --- a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj +++ b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj @@ -18,7 +18,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj index 43a94947..4de13cd2 100644 --- a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj +++ b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj @@ -22,6 +22,6 @@ - + \ No newline at end of file diff --git a/Source/GitReleaseManager.Tool/GitReleaseManager.Tool.csproj b/Source/GitReleaseManager.Tool/GitReleaseManager.Tool.csproj index 928c2151..3e7ed613 100644 --- a/Source/GitReleaseManager.Tool/GitReleaseManager.Tool.csproj +++ b/Source/GitReleaseManager.Tool/GitReleaseManager.Tool.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/Source/GitReleaseManager/GitReleaseManager.Core.csproj b/Source/GitReleaseManager/GitReleaseManager.Core.csproj index ef15069c..5fff5ce6 100644 --- a/Source/GitReleaseManager/GitReleaseManager.Core.csproj +++ b/Source/GitReleaseManager/GitReleaseManager.Core.csproj @@ -11,7 +11,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + From eeac27dd4a51a3f38f2fb2a34b07712916b79235 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 26 Jul 2020 18:53:06 +0000 Subject: [PATCH 026/181] Bump NUnit3TestAdapter from 3.16.1 to 3.17.0 in /Source Bumps [NUnit3TestAdapter](https://github.com/nunit/nunit3-vs-adapter) from 3.16.1 to 3.17.0. - [Release notes](https://github.com/nunit/nunit3-vs-adapter/releases) - [Commits](https://github.com/nunit/nunit3-vs-adapter/compare/V3.16.1...V3.17) Signed-off-by: dependabot-preview[bot] --- .../GitReleaseManager.IntegrationTests.csproj | 2 +- Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj index 2ca23145..15ff7751 100644 --- a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj +++ b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj @@ -19,7 +19,7 @@ all - + diff --git a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj index 4de13cd2..427e7734 100644 --- a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj +++ b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj @@ -21,7 +21,7 @@ all - + \ No newline at end of file From ae6a1d4b087a18b8e2334ffac3580fedb4c972dc Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 26 Jul 2020 19:03:08 +0000 Subject: [PATCH 027/181] Bump TextCopy from 3.3.0 to 4.2.0 in /Source Bumps [TextCopy](https://github.com/CopyText/TextCopy) from 3.3.0 to 4.2.0. - [Release notes](https://github.com/CopyText/TextCopy/releases) - [Commits](https://github.com/CopyText/TextCopy/compare/3.3.0...4.2.0) Signed-off-by: dependabot-preview[bot] --- .../GitReleaseManager.IntegrationTests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj index 15ff7751..8c1389b2 100644 --- a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj +++ b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj @@ -22,6 +22,6 @@ - + \ No newline at end of file From 09533aa49cfed737920bc9305208912437ebcb9d Mon Sep 17 00:00:00 2001 From: Gary Ewan Park Date: Sun, 26 Jul 2020 20:13:48 +0100 Subject: [PATCH 028/181] (build) Fix usage of TextCopy There was a breaking change in the latest release, which needed to be addressed. --- Source/GitReleaseManager.IntegrationTests/ClipBoardHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GitReleaseManager.IntegrationTests/ClipBoardHelper.cs b/Source/GitReleaseManager.IntegrationTests/ClipBoardHelper.cs index eec9afd4..023d7944 100644 --- a/Source/GitReleaseManager.IntegrationTests/ClipBoardHelper.cs +++ b/Source/GitReleaseManager.IntegrationTests/ClipBoardHelper.cs @@ -13,7 +13,7 @@ public static class ClipBoardHelper { public static void SetClipboard(string result) { - var thread = new Thread(() => Clipboard.SetText(result)); + var thread = new Thread(() => new Clipboard().SetText(result)); thread.SetApartmentState(ApartmentState.STA); thread.Start(); thread.Join(); From d5092dabbd0eff042ecd17672c1a0f1dd1023952 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Sun, 26 Jul 2020 16:46:48 +0200 Subject: [PATCH 029/181] (GH-188) Add LabelConfig --- Source/GitReleaseManager/Configuration/Config.cs | 6 ++++++ .../Configuration/LabelConfig.cs | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 Source/GitReleaseManager/Configuration/LabelConfig.cs diff --git a/Source/GitReleaseManager/Configuration/Config.cs b/Source/GitReleaseManager/Configuration/Config.cs index b9f53fc1..eed43a46 100644 --- a/Source/GitReleaseManager/Configuration/Config.cs +++ b/Source/GitReleaseManager/Configuration/Config.cs @@ -50,6 +50,8 @@ public Config() IssueCommentFormat = IssueCommentFormat, }; + Label = new List(); + IssueLabelsInclude = new List { "Bug", @@ -86,6 +88,10 @@ public Config() [YamlMember(Alias = "close")] public CloseConfig Close { get; set; } + [Description("Configuration values used when creating labels")] + [YamlMember(Alias = "label")] + public IList Label { get; } + [Description("The labels that will be used to include issues in release notes.")] [YamlMember(Alias = "issue-labels-include")] public IList IssueLabelsInclude { get; private set; } diff --git a/Source/GitReleaseManager/Configuration/LabelConfig.cs b/Source/GitReleaseManager/Configuration/LabelConfig.cs new file mode 100644 index 00000000..0e389878 --- /dev/null +++ b/Source/GitReleaseManager/Configuration/LabelConfig.cs @@ -0,0 +1,16 @@ +namespace GitReleaseManager.Core.Configuration +{ + using YamlDotNet.Serialization; + + public class LabelConfig + { + [YamlMember(Alias = "name")] + public string Name { get; set; } + + [YamlMember(Alias = "description")] + public string Description { get; set; } + + [YamlMember(Alias = "color")] + public string Color { get; set; } + } +} \ No newline at end of file From 28840b79421f02017a73cdc2834fc9cee25a3b30 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Sun, 26 Jul 2020 18:45:32 +0200 Subject: [PATCH 030/181] (GH-188) Add default labels --- .../GitReleaseManager/Configuration/Config.cs | 70 ++++++++++++++++++- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/Source/GitReleaseManager/Configuration/Config.cs b/Source/GitReleaseManager/Configuration/Config.cs index eed43a46..97d9537e 100644 --- a/Source/GitReleaseManager/Configuration/Config.cs +++ b/Source/GitReleaseManager/Configuration/Config.cs @@ -50,7 +50,71 @@ public Config() IssueCommentFormat = IssueCommentFormat, }; - Label = new List(); + Labels = new List + { + new LabelConfig + { + Name = "Breaking Change", + Description = "Functionality breaking changes", + Color = "b60205", + }, + + new LabelConfig + { + Name = "Bug", + Description = "Something isn't working", + Color = "ee0701", + }, + + new LabelConfig + { + Name = "Build", + Description = "Build pipeline", + Color = "009800", + }, + + new LabelConfig + { + Name = "Documentation", + Description = "Improvements or additions to documentation", + Color = "d4c5f9", + }, + + new LabelConfig + { + Name = "Feature", + Description = "Request for a new feature", + Color = "84b6eb", + }, + + new LabelConfig + { + Name = "Good First Issue", + Description = "Good for newcomers", + Color = "7057ff", + }, + + new LabelConfig + { + Name = "Help Wanted", + Description = "Extra attention is needed", + Color = "33aa3f", + }, + + new LabelConfig + { + Name = "Improvement", + Description = "Improvement of an existing feature", + Color = "207de5", + }, + + new LabelConfig + { + Name = "Question", + Description = "Further information is requested", + Color = "cc317c", + }, + }; IssueLabelsInclude = new List { @@ -89,8 +153,8 @@ public Config() public CloseConfig Close { get; set; } [Description("Configuration values used when creating labels")] - [YamlMember(Alias = "label")] - public IList Label { get; } + [YamlMember(Alias = "labels")] + public IList Labels { get; } [Description("The labels that will be used to include issues in release notes.")] [YamlMember(Alias = "issue-labels-include")] From e5c3204fd647923f342350e7f6b77871df88100f Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Sun, 26 Jul 2020 18:59:04 +0200 Subject: [PATCH 031/181] (GH-188) GitHubProvider uses configured labels --- Source/GitReleaseManager/GitHubProvider.cs | 46 ++++++++++++---------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/Source/GitReleaseManager/GitHubProvider.cs b/Source/GitReleaseManager/GitHubProvider.cs index ed93ebeb..23a1890c 100644 --- a/Source/GitReleaseManager/GitHubProvider.cs +++ b/Source/GitReleaseManager/GitHubProvider.cs @@ -343,31 +343,35 @@ public async Task PublishRelease(string owner, string repository, string tagName public async Task CreateLabels(string owner, string repository) { - var newLabels = new List + if (_configuration.Labels.Any()) { - new NewLabel("Breaking change", "b60205"), - new NewLabel("Bug", "ee0701"), - new NewLabel("Build", "009800"), - new NewLabel("Documentation", "d4c5f9"), - new NewLabel("Feature", "84b6eb"), - new NewLabel("Improvement", "207de5"), - new NewLabel("Question", "cc317c"), - new NewLabel("good first issue", "7057ff"), - new NewLabel("help wanted", "33aa3f"), - }; + var newLabels = new List(); + + foreach (var label in _configuration.Labels) + { + newLabels.Add(new NewLabel(label.Name, label.Color) + { + Description = label.Description, + }); + } - _logger.Verbose("Grabbing all existing labels on '{Owner}/{Repository}'", owner, repository); - var labels = await _gitHubClient.Issue.Labels.GetAllForRepository(owner, repository).ConfigureAwait(false); + _logger.Verbose("Grabbing all existing labels on '{Owner}/{Repository}'", owner, repository); + var labels = await _gitHubClient.Issue.Labels.GetAllForRepository(owner, repository).ConfigureAwait(false); - _logger.Verbose("Removing existing labels"); - _logger.Debug("{@Labels}", labels); - var deleteLabelsTasks = labels.Select(label => _gitHubClient.Issue.Labels.Delete(owner, repository, label.Name)); - await Task.WhenAll(deleteLabelsTasks).ConfigureAwait(false); + _logger.Verbose("Removing existing labels"); + _logger.Debug("{@Labels}", labels); + var deleteLabelsTasks = labels.Select(label => _gitHubClient.Issue.Labels.Delete(owner, repository, label.Name)); + await Task.WhenAll(deleteLabelsTasks).ConfigureAwait(false); - _logger.Verbose("Creating new standard labels"); - _logger.Debug("{@Labels}", newLabels); - var createLabelsTasks = newLabels.Select(label => _gitHubClient.Issue.Labels.Create(owner, repository, label)); - await Task.WhenAll(createLabelsTasks).ConfigureAwait(false); + _logger.Verbose("Creating new standard labels"); + _logger.Debug("{@Labels}", newLabels); + var createLabelsTasks = newLabels.Select(label => _gitHubClient.Issue.Labels.Create(owner, repository, label)); + await Task.WhenAll(createLabelsTasks).ConfigureAwait(false); + } + else + { + _logger.Warning("No labels defined"); + } } private static NewRelease CreateNewRelease(string name, string tagName, string body, bool prerelease, string targetCommitish) From 7d61711bc36ba748daa104d1ca53690c8eb767b4 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Sun, 26 Jul 2020 19:39:05 +0200 Subject: [PATCH 032/181] (GH-188) Update docs for 'Default Configuration' --- .../configuration/default-configuration.md | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/input/docs/configuration/default-configuration.md b/docs/input/docs/configuration/default-configuration.md index 53ba4c38..9f0ffe85 100644 --- a/docs/input/docs/configuration/default-configuration.md +++ b/docs/input/docs/configuration/default-configuration.md @@ -37,6 +37,34 @@ close: - [GitHub release](https://github.com/{owner}/{repository}/releases/tag/{milestone}) Your **[GitReleaseManager](https://github.com/GitTools/GitReleaseManager)** bot :package::rocket: +labels: + - name: Breaking Change + description: Functionality breaking changes + color: b60205 + - name: Bug + description: Something isn't working + color: ee0701 + - name: Build + description: Build pipeline + color: 009800 + - name: Documentation + description: Improvements or additions to documentation + color: d4c5f9 + - name: Feature + description: Request for a new feature + color: 84b6eb + - name: Good First Issue + description: Good for newcomers + color: 7057ff + - name: Help Wanted + description: Extra attention is needed + color: 33aa3f + - name: Improvement + description: Improvement of an existing feature + color: 207de5 + - name: Question + description: Further information is requested + color: cc317c issue-labels-include: - Bug - Duplicate @@ -154,6 +182,10 @@ tokenized values, such as milestone, owner, repository, with the actual values. this comment template, it is possible to replace information for example, the milestone name, the owner/repository information, etc. +## Labels + +Pre-defined issue labels. + ## Issues to include See the [Issues to include](include-issues) section. From 1dff1966eefa15d1192dcd0804fd38242881f1ec Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 30 Jul 2020 20:44:46 +0200 Subject: [PATCH 033/181] (GH-259) Make the default configuration consistent Including updating documentation where required. --- .../ReleaseNotesBuilderTests.cs | 2 +- .../GitReleaseManager/Configuration/Config.cs | 34 ++++++++----------- .../configuration/default-configuration.md | 11 +++--- .../docs/configuration/exclude-issues.md | 2 +- 4 files changed, 22 insertions(+), 27 deletions(-) diff --git a/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs b/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs index 51b5e8e0..3375b70a 100644 --- a/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs +++ b/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs @@ -133,7 +133,7 @@ public void SomeCommitsWrongIssueLabel() [Test] public void CorrectlyExcludeIssues() { - AcceptTest(5, CreateIssue(1, "Internal Refactoring"), CreateIssue(2, "Bug")); + AcceptTest(5, CreateIssue(1, "Build"), CreateIssue(2, "Bug")); Assert.True(true); // Just to make sonarlint happy } diff --git a/Source/GitReleaseManager/Configuration/Config.cs b/Source/GitReleaseManager/Configuration/Config.cs index 97d9537e..892e8d82 100644 --- a/Source/GitReleaseManager/Configuration/Config.cs +++ b/Source/GitReleaseManager/Configuration/Config.cs @@ -117,22 +117,21 @@ public Config() }; IssueLabelsInclude = new List - { - "Bug", - "Duplicate", - "Enhancement", - "Feature", - "Help Wanted", - "Improvement", - "Invalid", - "Question", - "WontFix", - }; + { + "Breaking Change", + "Bug", + "Documentation", + "Feature", + "Good First Issue", + "Help Wanted", + "Improvement", + "Question", + }; IssueLabelsExclude = new List - { - "Internal Refactoring", - }; + { + "Build", + }; LabelAliases = new List(); } @@ -145,16 +144,13 @@ public Config() [YamlMember(Alias = "export")] public ExportConfig Export { get; private set; } - /// - /// Gets or sets the close configuration values. - /// [Description("Configuration values used when closing a milestone")] [YamlMember(Alias = "close")] - public CloseConfig Close { get; set; } + public CloseConfig Close { get; private set; } [Description("Configuration values used when creating labels")] [YamlMember(Alias = "labels")] - public IList Labels { get; } + public IList Labels { get; private set; } [Description("The labels that will be used to include issues in release notes.")] [YamlMember(Alias = "issue-labels-include")] diff --git a/docs/input/docs/configuration/default-configuration.md b/docs/input/docs/configuration/default-configuration.md index 9f0ffe85..845fe284 100644 --- a/docs/input/docs/configuration/default-configuration.md +++ b/docs/input/docs/configuration/default-configuration.md @@ -66,17 +66,16 @@ labels: description: Further information is requested color: cc317c issue-labels-include: - - Bug - - Duplicate - - Enhancement + - Breaking Change + - Bug + - Documentation - Feature + - Good First Issue - Help Wanted - Improvement - - Invalid - Question - - Wontfix issue-labels-exclude: - - Internal Refactoring + - Build issue-labels-alias: [] ``` diff --git a/docs/input/docs/configuration/exclude-issues.md b/docs/input/docs/configuration/exclude-issues.md index 4598ce64..c909801b 100644 --- a/docs/input/docs/configuration/exclude-issues.md +++ b/docs/input/docs/configuration/exclude-issues.md @@ -16,7 +16,7 @@ tagged with the following labels: ```yaml issue-labels-exclude: - - Internal Refactoring + - Build ``` :::{.alert .alert-info} From cf10db08ed94f0457d45439f2e3c64fb4c3f5bd1 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 30 Jul 2020 21:51:19 +0200 Subject: [PATCH 034/181] (GH-249) Add default branch property to configuration --- Source/GitReleaseManager/Configuration/Config.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/GitReleaseManager/Configuration/Config.cs b/Source/GitReleaseManager/Configuration/Config.cs index 892e8d82..e8333c10 100644 --- a/Source/GitReleaseManager/Configuration/Config.cs +++ b/Source/GitReleaseManager/Configuration/Config.cs @@ -50,6 +50,8 @@ public Config() IssueCommentFormat = IssueCommentFormat, }; + DefaultBranch = "master"; + Labels = new List { new LabelConfig @@ -148,6 +150,10 @@ public Config() [YamlMember(Alias = "close")] public CloseConfig Close { get; private set; } + [Description("The name of the default branch.")] + [YamlMember(Alias = "default-branch")] + public string DefaultBranch { get; private set; } + [Description("Configuration values used when creating labels")] [YamlMember(Alias = "labels")] public IList Labels { get; private set; } From 4cdbd7b7f6bd0aa0025515698244a0c8f1259d0b Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 30 Jul 2020 21:52:05 +0200 Subject: [PATCH 035/181] (GH-249) Replace hardcoded default branch value with configuration value --- Source/GitReleaseManager/GitHubProvider.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/GitReleaseManager/GitHubProvider.cs b/Source/GitReleaseManager/GitHubProvider.cs index 23a1890c..c12fd034 100644 --- a/Source/GitReleaseManager/GitHubProvider.cs +++ b/Source/GitReleaseManager/GitHubProvider.cs @@ -492,13 +492,13 @@ private async Task GetNumberOfCommitsBetweenInternal(Milestone previousMile { if (previousMilestone == null) { - _logger.Verbose("Getting commit count between base '{Base}' and head '{Head}'", "master", currentMilestone.Title); - var gitHubClientRepositoryCommitsCompare = await _gitHubClient.Repository.Commit.Compare(user, repository, "master", currentMilestone.Title).ConfigureAwait(false); + _logger.Verbose("Getting commit count between base '{Base}' and head '{Head}'", _configuration.DefaultBranch, currentMilestone.Title); + var gitHubClientRepositoryCommitsCompare = await _gitHubClient.Repository.Commit.Compare(user, repository, _configuration.DefaultBranch, currentMilestone.Title).ConfigureAwait(false); return gitHubClientRepositoryCommitsCompare.AheadBy; } - _logger.Verbose("Getting commit count between base '{Base}' and head '{Head}'", previousMilestone.Title, "master"); - var compareResult = await _gitHubClient.Repository.Commit.Compare(user, repository, previousMilestone.Title, "master").ConfigureAwait(false); + _logger.Verbose("Getting commit count between base '{Base}' and head '{Head}'", previousMilestone.Title, _configuration.DefaultBranch); + var compareResult = await _gitHubClient.Repository.Commit.Compare(user, repository, previousMilestone.Title, _configuration.DefaultBranch).ConfigureAwait(false); return compareResult.AheadBy; } catch (NotFoundException) From 3bf455931eb0b486054780ab21b51d89250e49cc Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 30 Jul 2020 21:53:33 +0200 Subject: [PATCH 036/181] (GH-249) Update configuration unit test --- .../ConfigurationTests.cs | 1 + Source/GitReleaseManager.Tests/Resources.resx | 178 +++++++++--------- 2 files changed, 90 insertions(+), 89 deletions(-) diff --git a/Source/GitReleaseManager.Tests/ConfigurationTests.cs b/Source/GitReleaseManager.Tests/ConfigurationTests.cs index 2da7c393..d8ad033f 100644 --- a/Source/GitReleaseManager.Tests/ConfigurationTests.cs +++ b/Source/GitReleaseManager.Tests/ConfigurationTests.cs @@ -107,6 +107,7 @@ public void Should_WriteSample_String_Values() // Then Assert.That(text, Contains.Substring("# footer-heading: Where to get it")); + Assert.That(text, Contains.Substring("#default-branch: master")); } [Test] diff --git a/Source/GitReleaseManager.Tests/Resources.resx b/Source/GitReleaseManager.Tests/Resources.resx index 59590530..3b6b2574 100644 --- a/Source/GitReleaseManager.Tests/Resources.resx +++ b/Source/GitReleaseManager.Tests/Resources.resx @@ -1,17 +1,17 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - # Configuration values used when creating new releases + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + # Configuration values used when creating new releases create: include-footer: false footer-heading: @@ -137,6 +134,9 @@ export: regex-text: multiline-regex: false +# The name of the default branch. +default-branch: master + # The labels that will be used to include issues in release notes. issue-labels-include: - Bug @@ -156,5 +156,5 @@ issue-labels-alias: - name: Improvement header: Baz plural: Qux - + \ No newline at end of file From 0ea110e57ca86983a68b1ac7fc5be2d794801aa3 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 30 Jul 2020 21:55:18 +0200 Subject: [PATCH 037/181] (GH-249) Update documentation --- docs/input/docs/configuration/default-configuration.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/input/docs/configuration/default-configuration.md b/docs/input/docs/configuration/default-configuration.md index 845fe284..18237107 100644 --- a/docs/input/docs/configuration/default-configuration.md +++ b/docs/input/docs/configuration/default-configuration.md @@ -37,6 +37,7 @@ close: - [GitHub release](https://github.com/{owner}/{repository}/releases/tag/{milestone}) Your **[GitReleaseManager](https://github.com/GitTools/GitReleaseManager)** bot :package::rocket: +default-branch: master labels: - name: Breaking Change description: Functionality breaking changes @@ -181,6 +182,10 @@ tokenized values, such as milestone, owner, repository, with the actual values. this comment template, it is possible to replace information for example, the milestone name, the owner/repository information, etc. +## Default branch + +The name of the default branch. + ## Labels Pre-defined issue labels. From 845ea8268fd27d9eaf6f50ccf0ad7d010a7501dd Mon Sep 17 00:00:00 2001 From: Gary Ewan Park Date: Mon, 3 Aug 2020 13:05:32 -0700 Subject: [PATCH 038/181] (build) Make target frameworks consistent --- Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj | 2 +- .../GitReleaseManager.IntegrationTests.csproj | 2 +- Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj index c073531f..ce295098 100644 --- a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj +++ b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj @@ -3,7 +3,7 @@ 8.0 Exe GitReleaseManager - netcoreapp2.0;net461 + netcoreapp2.1;net461 GitReleaseManager.Cli Create release notes in markdown given a milestone false diff --git a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj index 8c1389b2..54e5480f 100644 --- a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj +++ b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj @@ -1,7 +1,7 @@ 8.0 - net472;netcoreapp2.2 + net472;netcoreapp2.1 GitReleaseManager.IntegrationTests Integration Test Project for GitReleaseManager $(NoWarn);CA1707 diff --git a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj index 427e7734..e71fb69a 100644 --- a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj +++ b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj @@ -1,7 +1,7 @@ 8.0 - net472;netcoreapp2.2 + net472;netcoreapp2.1 GitReleaseManager.Tests Test Project for GitReleaseManager $(NoWarn);CA1707 From 3d5356634074a70d56df12964ec1b403dbbb5920 Mon Sep 17 00:00:00 2001 From: Gary Ewan Park Date: Mon, 3 Aug 2020 13:06:24 -0700 Subject: [PATCH 039/181] (build) Use latest version of Cake.Recipe This brings in support for running using .Net Global Tool, but requires running with 0.38.4 as a minimum. --- recipe.cake | 2 +- tools/packages.config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/recipe.cake b/recipe.cake index 63a49a9c..1984cdf4 100644 --- a/recipe.cake +++ b/recipe.cake @@ -1,4 +1,4 @@ -#load nuget:https://pkgs.dev.azure.com/cake-contrib/Home/_packaging/addins/nuget/v3/index.json?package=Cake.Recipe&version=2.0.0-alpha0319&prerelease +#load nuget:https://pkgs.dev.azure.com/cake-contrib/Home/_packaging/addins/nuget/v3/index.json?package=Cake.Recipe&version=2.0.0-alpha0338&prerelease Environment.SetVariableNames(githubUserNameVariable: "GITTOOLS_GITHUB_USERNAME", githubPasswordVariable: "GITTOOLS_GITHUB_PASSWORD", diff --git a/tools/packages.config b/tools/packages.config index 7740eb4a..2f8b02b8 100644 --- a/tools/packages.config +++ b/tools/packages.config @@ -1,4 +1,4 @@ - + \ No newline at end of file From 33f4d905118b75b9bbf9c00208b90dd9e31ad2d7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 21 Aug 2020 06:10:23 +0000 Subject: [PATCH 040/181] Bump Microsoft.NET.Test.Sdk from 16.6.1 to 16.7.1 in /Source Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.6.1 to 16.7.1. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v16.6.1...v16.7.1) Signed-off-by: dependabot-preview[bot] --- .../GitReleaseManager.IntegrationTests.csproj | 2 +- Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj index 54e5480f..dd5b17e9 100644 --- a/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj +++ b/Source/GitReleaseManager.IntegrationTests/GitReleaseManager.IntegrationTests.csproj @@ -20,7 +20,7 @@ - + diff --git a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj index e71fb69a..7bcf9e75 100644 --- a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj +++ b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj @@ -14,7 +14,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive From 9076320f3bd9715d5d0ecbe8a4dadf3b8475ee3e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2020 18:16:27 +0000 Subject: [PATCH 041/181] Bump Microsoft.CodeAnalysis.FxCopAnalyzers in /Source Bumps [Microsoft.CodeAnalysis.FxCopAnalyzers](https://github.com/dotnet/roslyn-analyzers) from 3.0.0 to 3.3.0. - [Release notes](https://github.com/dotnet/roslyn-analyzers/releases) - [Changelog](https://github.com/dotnet/roslyn-analyzers/blob/master/PostReleaseActivities.md) - [Commits](https://github.com/dotnet/roslyn-analyzers/compare/v3.0.0...v3.3.0) Signed-off-by: dependabot-preview[bot] --- Source/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Directory.Build.props b/Source/Directory.Build.props index 75bbda4a..d22699b8 100644 --- a/Source/Directory.Build.props +++ b/Source/Directory.Build.props @@ -14,7 +14,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all From 30359b5ecb307aabe025d32b4b7b7b8382514776 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 30 Jul 2020 23:16:59 +0200 Subject: [PATCH 042/181] (GH-181) Update OctokitExtensions to use IGitHubClient interface --- Source/GitReleaseManager/OctokitExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/GitReleaseManager/OctokitExtensions.cs b/Source/GitReleaseManager/OctokitExtensions.cs index d3d5451b..b8669e5b 100644 --- a/Source/GitReleaseManager/OctokitExtensions.cs +++ b/Source/GitReleaseManager/OctokitExtensions.cs @@ -28,7 +28,7 @@ public static bool IsPullRequest(this Issue issue) return !(issue.PullRequest is null); } - public static Task> AllIssuesForMilestone(this GitHubClient gitHubClient, Milestone milestone) + public static Task> AllIssuesForMilestone(this IGitHubClient gitHubClient, Milestone milestone) { if (gitHubClient is null) { @@ -57,7 +57,7 @@ public static Uri HtmlUrl(this Milestone milestone) return new Uri(string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/issues?milestone={2}&state=closed", user, repository, milestone.Number)); } - private static async Task> AllIssuesForMilestoneInternal(GitHubClient gitHubClient, Milestone milestone) + private static async Task> AllIssuesForMilestoneInternal(IGitHubClient gitHubClient, Milestone milestone) { var closedIssueRequest = new RepositoryIssueRequest { From 816267850f4561650e53f30a4014a5e5b615d087 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 30 Jul 2020 23:41:59 +0200 Subject: [PATCH 043/181] (GH-181) Update GitHubProvider to use IGitHubClient and ILogger interface --- Source/GitReleaseManager.Cli/Program.cs | 12 ++++++- Source/GitReleaseManager/GitHubProvider.cs | 37 ++++------------------ 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/Source/GitReleaseManager.Cli/Program.cs b/Source/GitReleaseManager.Cli/Program.cs index fb6de33f..9a473137 100644 --- a/Source/GitReleaseManager.Cli/Program.cs +++ b/Source/GitReleaseManager.Cli/Program.cs @@ -4,6 +4,8 @@ // //----------------------------------------------------------------------- +using Octokit; + namespace GitReleaseManager.Cli { using System; @@ -267,7 +269,15 @@ private static IVcsProvider GetVcsProvider(BaseVcsOptions subOptions) var configuration = ConfigurationProvider.Provide(subOptions.TargetDirectory ?? Environment.CurrentDirectory, _fileSystem); Log.Information("Using {Provider} as VCS Provider", "GitHub"); - return new GitHubProvider(_mapper, configuration, subOptions.UserName, subOptions.Password, subOptions.Token); + var credentials = string.IsNullOrWhiteSpace(subOptions.Token) + ? new Credentials(subOptions.UserName, subOptions.Password) + : new Credentials(subOptions.Token); + + var gitHubClient = new GitHubClient(new ProductHeaderValue("GitReleaseManager")) { Credentials = credentials }; + + var logger = Log.ForContext(); + + return new GitHubProvider(gitHubClient, logger, _mapper, configuration); } private static void LogOptions(BaseSubOptions options) diff --git a/Source/GitReleaseManager/GitHubProvider.cs b/Source/GitReleaseManager/GitHubProvider.cs index c12fd034..13e6c050 100644 --- a/Source/GitReleaseManager/GitHubProvider.cs +++ b/Source/GitReleaseManager/GitHubProvider.cs @@ -28,24 +28,17 @@ namespace GitReleaseManager.Core public class GitHubProvider : IVcsProvider { - private readonly Config _configuration; - private readonly ILogger _logger = Log.ForContext(); + private readonly IGitHubClient _gitHubClient; + private readonly ILogger _logger; private readonly IMapper _mapper; - private GitHubClient _gitHubClient; - - [Obsolete("Use overload with token only instead")] - public GitHubProvider(IMapper mapper, Config configuration, string userName, string password, string token) - { - _mapper = mapper; - _configuration = configuration; - CreateClient(userName, password, token); - } + private readonly Config _configuration; - public GitHubProvider(IMapper mapper, Config configuration, string token) + public GitHubProvider(IGitHubClient gitHubClient, ILogger logger, IMapper mapper, Config configuration) { + _gitHubClient = gitHubClient; + _logger = logger; _mapper = mapper; _configuration = configuration; - CreateClient(token); } public Task GetNumberOfCommitsBetween(Milestone previousMilestone, Milestone currentMilestone, string user, string repository) @@ -103,24 +96,6 @@ public async Task> GetReadOnlyMilestonesAsync(stri return new ReadOnlyCollection(_mapper.Map>(closed.Concat(open).ToList())); } - [Obsolete("Use overload with token only instead")] - public void CreateClient(string userName, string password, string token) - { - var credentials = string.IsNullOrWhiteSpace(token) - ? new Credentials(userName, password) - : new Credentials(token); - - var github = new GitHubClient(new ProductHeaderValue("GitReleaseManager")) { Credentials = credentials }; - _gitHubClient = github; - } - - public void CreateClient(string token) - { - var credentials = new Credentials(token); - var github = new GitHubClient(new ProductHeaderValue("GitReleaseManager")) { Credentials = credentials }; - _gitHubClient = github; - } - public string GetCommitsLink(string user, string repository, Milestone milestone, Milestone previousMilestone) { if (milestone is null) From 083233309eb1e8d41fb8a683bc4f4dadda1515e9 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 30 Jul 2020 23:46:55 +0200 Subject: [PATCH 044/181] (GH-181) Update ReleaseNotesBuilder to use ILogger interface --- Source/GitReleaseManager/GitHubProvider.cs | 2 +- Source/GitReleaseManager/ReleaseNotesBuilder.cs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Source/GitReleaseManager/GitHubProvider.cs b/Source/GitReleaseManager/GitHubProvider.cs index 13e6c050..52857737 100644 --- a/Source/GitReleaseManager/GitHubProvider.cs +++ b/Source/GitReleaseManager/GitHubProvider.cs @@ -114,7 +114,7 @@ public string GetCommitsLink(string user, string repository, Milestone milestone public async Task CreateReleaseFromMilestone(string owner, string repository, string milestone, string releaseName, string targetCommitish, IList assets, bool prerelease) { var release = await GetReleaseFromTagNameAsync(owner, repository, milestone).ConfigureAwait(false); - var releaseNotesBuilder = new ReleaseNotesBuilder(this, owner, repository, milestone, _configuration); + var releaseNotesBuilder = new ReleaseNotesBuilder(this, _logger, owner, repository, milestone, _configuration); var result = await releaseNotesBuilder.BuildReleaseNotes().ConfigureAwait(false); if (release == null) diff --git a/Source/GitReleaseManager/ReleaseNotesBuilder.cs b/Source/GitReleaseManager/ReleaseNotesBuilder.cs index 552fa7b7..ff6a4bd8 100644 --- a/Source/GitReleaseManager/ReleaseNotesBuilder.cs +++ b/Source/GitReleaseManager/ReleaseNotesBuilder.cs @@ -20,8 +20,8 @@ namespace GitReleaseManager.Core public class ReleaseNotesBuilder { - private readonly ILogger _logger = Log.ForContext(); private readonly IVcsProvider _vcsProvider; + private readonly ILogger _logger; private readonly string _user; private readonly string _repository; private readonly string _milestoneTitle; @@ -29,9 +29,10 @@ public class ReleaseNotesBuilder private ReadOnlyCollection _milestones; private Milestone _targetMilestone; - public ReleaseNotesBuilder(IVcsProvider vcsProvider, string user, string repository, string milestoneTitle, Config configuration) + public ReleaseNotesBuilder(IVcsProvider vcsProvider, ILogger logger, string user, string repository, string milestoneTitle, Config configuration) { _vcsProvider = vcsProvider; + _logger = logger; _user = user; _repository = repository; _milestoneTitle = milestoneTitle; From dca3a8f8c32305687094823e549014f4f8ac5945 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 30 Jul 2020 23:48:25 +0200 Subject: [PATCH 045/181] (GH-181) Update ReleaseNotesExporter to use ILogger interface --- Source/GitReleaseManager/GitHubProvider.cs | 2 +- Source/GitReleaseManager/ReleaseNotesExporter.cs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Source/GitReleaseManager/GitHubProvider.cs b/Source/GitReleaseManager/GitHubProvider.cs index 52857737..e4af67f5 100644 --- a/Source/GitReleaseManager/GitHubProvider.cs +++ b/Source/GitReleaseManager/GitHubProvider.cs @@ -254,7 +254,7 @@ public async Task AddAssets(string owner, string repository, string tagName, ILi public Task ExportReleases(string owner, string repository, string tagName) { - var releaseNotesExporter = new ReleaseNotesExporter(this, _configuration, owner, repository); + var releaseNotesExporter = new ReleaseNotesExporter(this, _logger, _configuration, owner, repository); return releaseNotesExporter.ExportReleaseNotes(tagName); } diff --git a/Source/GitReleaseManager/ReleaseNotesExporter.cs b/Source/GitReleaseManager/ReleaseNotesExporter.cs index e693ec6f..08c07fc5 100644 --- a/Source/GitReleaseManager/ReleaseNotesExporter.cs +++ b/Source/GitReleaseManager/ReleaseNotesExporter.cs @@ -17,15 +17,16 @@ namespace GitReleaseManager.Core public class ReleaseNotesExporter { - private readonly ILogger _logger = Log.ForContext(); private readonly IVcsProvider _vcsProvider; + private readonly ILogger _logger; private readonly Config _configuration; private readonly string _user; private readonly string _repository; - public ReleaseNotesExporter(IVcsProvider vcsProvider, Config configuration, string user, string repository) + public ReleaseNotesExporter(IVcsProvider vcsProvider, ILogger logger, Config configuration, string user, string repository) { _vcsProvider = vcsProvider; + _logger = logger; _configuration = configuration; _user = user; _repository = repository; From 41bd9c4e122bcd5a34dc7d56210bb36d1bbc8510 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Fri, 31 Jul 2020 00:07:45 +0200 Subject: [PATCH 046/181] (GH-181) Fix unit tests --- .../ReleaseNotesBuilderIntegrationTests.cs | 21 ++++++++++++++----- .../GitReleaseManager.Tests.csproj | 1 + .../ReleaseNotesBuilderTests.cs | 6 +++++- .../ReleaseNotesExporterTests.cs | 6 +++++- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs b/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs index 1b9842be..34acc4c3 100644 --- a/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs +++ b/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs @@ -4,6 +4,8 @@ // //----------------------------------------------------------------------- +using Octokit; + namespace GitReleaseManager.IntegrationTests { using System; @@ -19,6 +21,8 @@ namespace GitReleaseManager.IntegrationTests [TestFixture] public class ReleaseNotesBuilderIntegrationTests { + private IGitHubClient _gitHubClient; + private ILogger _logger; private IMapper _mapper; private string _username; private string _password; @@ -30,11 +34,18 @@ public class ReleaseNotesBuilderIntegrationTests public void Configure() { _mapper = AutoMapperConfiguration.Configure(); - Log.Logger = new LoggerConfiguration().WriteTo.Console().CreateLogger(); + _logger = new LoggerConfiguration().WriteTo.Console().CreateLogger(); + Log.Logger = _logger; _username = Environment.GetEnvironmentVariable("GITTOOLS_GITHUB_USERNAME"); _password = Environment.GetEnvironmentVariable("GITTOOLS_GITHUB_PASSWORD"); _token = Environment.GetEnvironmentVariable("GITTOOLS_GITHUB_TOKEN"); + + var credentials = string.IsNullOrWhiteSpace(_token) + ? new Credentials(_username, _password) + : new Credentials(_token); + + _gitHubClient = new GitHubClient(new ProductHeaderValue("GitReleaseManager")) { Credentials = credentials }; } [OneTimeTearDown] @@ -57,8 +68,8 @@ public async Task SingleMilestone() var currentDirectory = Environment.CurrentDirectory; var configuration = ConfigurationProvider.Provide(currentDirectory, fileSystem); - var vcsProvider = new GitHubProvider(_mapper, configuration, _username, _password, _token); - var releaseNotesBuilder = new ReleaseNotesBuilder(vcsProvider, "Chocolatey", "ChocolateyGUI", "0.12.4", configuration); + var vcsProvider = new GitHubProvider(_gitHubClient, _logger, _mapper, configuration); + var releaseNotesBuilder = new ReleaseNotesBuilder(vcsProvider, _logger, "Chocolatey", "ChocolateyGUI", "0.12.4", configuration); var result = await releaseNotesBuilder.BuildReleaseNotes().ConfigureAwait(false); Debug.WriteLine(result); ClipBoardHelper.SetClipboard(result); @@ -79,8 +90,8 @@ public async Task SingleMilestone3() var currentDirectory = Environment.CurrentDirectory; var configuration = ConfigurationProvider.Provide(currentDirectory, fileSystem); - var vcsProvider = new GitHubProvider(_mapper, configuration, _username, _password, _token); - var releaseNotesBuilder = new ReleaseNotesBuilder(vcsProvider, "Chocolatey", "ChocolateyGUI", "0.13.0", configuration); + var vcsProvider = new GitHubProvider(_gitHubClient, _logger, _mapper, configuration); + var releaseNotesBuilder = new ReleaseNotesBuilder(vcsProvider, _logger, "Chocolatey", "ChocolateyGUI", "0.13.0", configuration); var result = await releaseNotesBuilder.BuildReleaseNotes().ConfigureAwait(false); Debug.WriteLine(result); ClipBoardHelper.SetClipboard(result); diff --git a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj index e71fb69a..89fb9fef 100644 --- a/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj +++ b/Source/GitReleaseManager.Tests/GitReleaseManager.Tests.csproj @@ -20,6 +20,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all + diff --git a/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs b/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs index 3375b70a..db199e18 100644 --- a/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs +++ b/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs @@ -4,6 +4,9 @@ // //----------------------------------------------------------------------- +using NSubstitute; +using Serilog; + namespace GitReleaseManager.Tests { using System; @@ -146,6 +149,7 @@ private static void AcceptTest(int commits, params Issue[] issues) private static void AcceptTest(int commits, Config config, params Issue[] issues) { var fakeClient = new FakeGitHubClient(); + var logger = Substitute.For(); var fileSystem = new FileSystem(); var currentDirectory = Environment.CurrentDirectory; var configuration = config ?? ConfigurationProvider.Provide(currentDirectory, fileSystem); @@ -159,7 +163,7 @@ private static void AcceptTest(int commits, Config config, params Issue[] issues fakeClient.Issues.Add(issue); } - var builder = new ReleaseNotesBuilder(fakeClient, "TestUser", "FakeRepository", "1.2.3", configuration); + var builder = new ReleaseNotesBuilder(fakeClient, logger, "TestUser", "FakeRepository", "1.2.3", configuration); var notes = builder.BuildReleaseNotes().Result; Approvals.Verify(notes); diff --git a/Source/GitReleaseManager.Tests/ReleaseNotesExporterTests.cs b/Source/GitReleaseManager.Tests/ReleaseNotesExporterTests.cs index f608f113..5c05c427 100644 --- a/Source/GitReleaseManager.Tests/ReleaseNotesExporterTests.cs +++ b/Source/GitReleaseManager.Tests/ReleaseNotesExporterTests.cs @@ -4,6 +4,9 @@ // //----------------------------------------------------------------------- +using NSubstitute; +using Serilog; + namespace GitReleaseManager.Tests { using System; @@ -60,13 +63,14 @@ public void SingleReleaseExcludeRegexRemoval() private static void AcceptTest(Config configuration, params Release[] releases) { var fakeClient = new FakeGitHubClient(); + var logger = Substitute.For(); foreach (var release in releases) { fakeClient.Releases.Add(release); } - var builder = new ReleaseNotesExporter(fakeClient, configuration, "bob", "repo"); + var builder = new ReleaseNotesExporter(fakeClient, logger, configuration, "bob", "repo"); var notes = builder.ExportReleaseNotes(null).Result; Approvals.Verify(notes); From 6bfcb050b92b5ac17c2c141eb6e45d6e494845d7 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Fri, 31 Jul 2020 20:07:24 +0200 Subject: [PATCH 047/181] (GH-181) Add ConfigureAwait --- Source/GitReleaseManager.Cli/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GitReleaseManager.Cli/Program.cs b/Source/GitReleaseManager.Cli/Program.cs index 9a473137..aa42e18b 100644 --- a/Source/GitReleaseManager.Cli/Program.cs +++ b/Source/GitReleaseManager.Cli/Program.cs @@ -181,7 +181,7 @@ private static async Task DiscardReleaseAsync(DiscardSubOptions subOptions) Log.Information("Discarding release {Milestone}", subOptions.Milestone); _vcsProvider = GetVcsProvider(subOptions); - await _vcsProvider.DiscardRelease(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone); + await _vcsProvider.DiscardRelease(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false); return 0; } From b238e10e1bbf216f7b4370d96f66d76dd0e2c22b Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Fri, 31 Jul 2020 20:58:17 +0200 Subject: [PATCH 048/181] (GH-181) Add Dependency Injection --- .../GitReleaseManager.Cli.csproj | 3 +- Source/GitReleaseManager.Cli/Program.cs | 74 ++++++++++++------- .../GitReleaseManager.Tool.csproj | 3 +- 3 files changed, 50 insertions(+), 30 deletions(-) diff --git a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj index ce295098..22897588 100644 --- a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj +++ b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj @@ -14,13 +14,14 @@ + runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/Source/GitReleaseManager.Cli/Program.cs b/Source/GitReleaseManager.Cli/Program.cs index aa42e18b..e3518846 100644 --- a/Source/GitReleaseManager.Cli/Program.cs +++ b/Source/GitReleaseManager.Cli/Program.cs @@ -4,8 +4,6 @@ // //----------------------------------------------------------------------- -using Octokit; - namespace GitReleaseManager.Cli { using System; @@ -13,20 +11,21 @@ namespace GitReleaseManager.Cli using System.Net; using System.Reflection; using System.Threading.Tasks; - using AutoMapper; using CommandLine; using GitReleaseManager.Cli.Logging; using GitReleaseManager.Cli.Options; using GitReleaseManager.Core; using GitReleaseManager.Core.Configuration; using GitReleaseManager.Core.Helpers; + using Microsoft.Extensions.DependencyInjection; + using Octokit; using Serilog; public static class Program { private static FileSystem _fileSystem; - private static IMapper _mapper; private static IVcsProvider _vcsProvider; + private static IServiceProvider _serviceProvider; private static async Task Main(string[] args) { @@ -36,8 +35,6 @@ private static async Task Main(string[] args) _fileSystem = new FileSystem(); - _mapper = AutoMapperConfiguration.Configure(); - try { return await Parser.Default.ParseArguments(args) @@ -45,6 +42,7 @@ private static async Task Main(string[] args) .WithParsed(CreateFiglet) .WithParsed(LogOptions) .WithParsed(ReportUsernamePasswordDeprecation) + .WithParsed(RegisterServices) .MapResult( (CreateSubOptions opts) => CreateReleaseAsync(opts), (DiscardSubOptions opts) => DiscardReleaseAsync(opts), @@ -76,6 +74,37 @@ private static async Task Main(string[] args) finally { Log.CloseAndFlush(); + DisposeServices(); + } + } + + private static void RegisterServices(BaseVcsOptions options) + { + var logger = Log.ForContext(); + var mapper = AutoMapperConfiguration.Configure(); + var configuration = ConfigurationProvider.Provide(options.TargetDirectory ?? Environment.CurrentDirectory, _fileSystem); + + var credentials = string.IsNullOrWhiteSpace(options.Token) + ? new Credentials(options.UserName, options.Password) + : new Credentials(options.Token); + + var gitHubClient = new GitHubClient(new ProductHeaderValue("GitReleaseManager")) { Credentials = credentials }; + + var serviceCollection = new ServiceCollection() + .AddSingleton(logger) + .AddSingleton(mapper) + .AddSingleton(configuration) + .AddSingleton(gitHubClient) + .AddSingleton(); + + _serviceProvider = serviceCollection.BuildServiceProvider(); + } + + private static void DisposeServices() + { + if (_serviceProvider is IDisposable serviceProvider) + { + serviceProvider.Dispose(); } } @@ -150,7 +179,7 @@ private static int GetConsoleWidth() private static async Task CreateReleaseAsync(CreateSubOptions subOptions) { Log.Information("Creating release..."); - _vcsProvider = GetVcsProvider(subOptions); + _vcsProvider = GetVcsProvider(); Core.Model.Release release; if (!string.IsNullOrEmpty(subOptions.Milestone)) @@ -179,7 +208,7 @@ private static async Task CreateReleaseAsync(CreateSubOptions subOptions) private static async Task DiscardReleaseAsync(DiscardSubOptions subOptions) { Log.Information("Discarding release {Milestone}", subOptions.Milestone); - _vcsProvider = GetVcsProvider(subOptions); + _vcsProvider = GetVcsProvider(); await _vcsProvider.DiscardRelease(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false); @@ -189,7 +218,7 @@ private static async Task DiscardReleaseAsync(DiscardSubOptions subOptions) private static async Task AddAssetsAsync(AddAssetSubOptions subOptions) { Log.Information("Uploading assets"); - _vcsProvider = GetVcsProvider(subOptions); + _vcsProvider = GetVcsProvider(); await _vcsProvider.AddAssets(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName, subOptions.AssetPaths).ConfigureAwait(false); @@ -199,7 +228,7 @@ private static async Task AddAssetsAsync(AddAssetSubOptions subOptions) private static async Task CloseMilestoneAsync(CloseSubOptions subOptions) { Log.Information("Closing milestone {Milestone}", subOptions.Milestone); - _vcsProvider = GetVcsProvider(subOptions); + _vcsProvider = GetVcsProvider(); await _vcsProvider.CloseMilestone(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false); @@ -209,7 +238,7 @@ private static async Task CloseMilestoneAsync(CloseSubOptions subOptions) private static async Task OpenMilestoneAsync(OpenSubOptions subOptions) { Log.Information("Opening milestone {Milestone}", subOptions.Milestone); - _vcsProvider = GetVcsProvider(subOptions); + _vcsProvider = GetVcsProvider(); await _vcsProvider.OpenMilestone(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false); @@ -218,7 +247,7 @@ private static async Task OpenMilestoneAsync(OpenSubOptions subOptions) private static async Task PublishReleaseAsync(PublishSubOptions subOptions) { - _vcsProvider = GetVcsProvider(subOptions); + _vcsProvider = GetVcsProvider(); await _vcsProvider.PublishRelease(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName).ConfigureAwait(false); return 0; @@ -227,11 +256,11 @@ private static async Task PublishReleaseAsync(PublishSubOptions subOptions) private static async Task ExportReleasesAsync(ExportSubOptions subOptions) { Log.Information("Exporting release {TagName}", subOptions.TagName); - _vcsProvider = GetVcsProvider(subOptions); + _vcsProvider = GetVcsProvider(); var releasesMarkdown = await _vcsProvider.ExportReleases(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName).ConfigureAwait(false); - using (var sw = new StreamWriter(File.Open(subOptions.FileOutputPath, FileMode.OpenOrCreate))) + using (var sw = new StreamWriter(File.Open(subOptions.FileOutputPath, System.IO.FileMode.OpenOrCreate))) { sw.Write(releasesMarkdown); } @@ -258,26 +287,15 @@ private static Task ShowConfigAsync(ShowConfigSubOptions subOptions) private static async Task CreateLabelsAsync(LabelSubOptions subOptions) { Log.Information("Creating standard labels"); - _vcsProvider = GetVcsProvider(subOptions); + _vcsProvider = GetVcsProvider(); await _vcsProvider.CreateLabels(subOptions.RepositoryOwner, subOptions.RepositoryName).ConfigureAwait(false); return 0; } - private static IVcsProvider GetVcsProvider(BaseVcsOptions subOptions) + private static IVcsProvider GetVcsProvider() { - var configuration = ConfigurationProvider.Provide(subOptions.TargetDirectory ?? Environment.CurrentDirectory, _fileSystem); - - Log.Information("Using {Provider} as VCS Provider", "GitHub"); - var credentials = string.IsNullOrWhiteSpace(subOptions.Token) - ? new Credentials(subOptions.UserName, subOptions.Password) - : new Credentials(subOptions.Token); - - var gitHubClient = new GitHubClient(new ProductHeaderValue("GitReleaseManager")) { Credentials = credentials }; - - var logger = Log.ForContext(); - - return new GitHubProvider(gitHubClient, logger, _mapper, configuration); + return _serviceProvider.GetService(); } private static void LogOptions(BaseSubOptions options) diff --git a/Source/GitReleaseManager.Tool/GitReleaseManager.Tool.csproj b/Source/GitReleaseManager.Tool/GitReleaseManager.Tool.csproj index 3e7ed613..229da8d8 100644 --- a/Source/GitReleaseManager.Tool/GitReleaseManager.Tool.csproj +++ b/Source/GitReleaseManager.Tool/GitReleaseManager.Tool.csproj @@ -32,13 +32,14 @@ + runtime; build; native; contentfiles; analyzers; buildtransitive all - + From ffab1597e4f35e6c3070c30d8a1d09bdcd24f92d Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Wed, 5 Aug 2020 13:14:43 +0200 Subject: [PATCH 049/181] (GH-181) Rename GithHubProvider to VcsService --- Source/GitReleaseManager.Cli/Program.cs | 44 +++++++++---------- .../ReleaseNotesBuilderIntegrationTests.cs | 8 ++-- .../FakeGitHubClient.cs | 4 +- .../{IVcsProvider.cs => IVcsService.cs} | 4 +- .../GitReleaseManager/ReleaseNotesBuilder.cs | 16 +++---- .../GitReleaseManager/ReleaseNotesExporter.cs | 10 ++--- .../{GitHubProvider.cs => VcsService.cs} | 6 +-- 7 files changed, 46 insertions(+), 46 deletions(-) rename Source/GitReleaseManager/{IVcsProvider.cs => IVcsService.cs} (94%) rename Source/GitReleaseManager/{GitHubProvider.cs => VcsService.cs} (99%) diff --git a/Source/GitReleaseManager.Cli/Program.cs b/Source/GitReleaseManager.Cli/Program.cs index e3518846..fbd8887a 100644 --- a/Source/GitReleaseManager.Cli/Program.cs +++ b/Source/GitReleaseManager.Cli/Program.cs @@ -24,7 +24,7 @@ namespace GitReleaseManager.Cli public static class Program { private static FileSystem _fileSystem; - private static IVcsProvider _vcsProvider; + private static IVcsService _vcsService; private static IServiceProvider _serviceProvider; private static async Task Main(string[] args) @@ -80,7 +80,7 @@ private static async Task Main(string[] args) private static void RegisterServices(BaseVcsOptions options) { - var logger = Log.ForContext(); + var logger = Log.ForContext(); var mapper = AutoMapperConfiguration.Configure(); var configuration = ConfigurationProvider.Provide(options.TargetDirectory ?? Environment.CurrentDirectory, _fileSystem); @@ -95,7 +95,7 @@ private static void RegisterServices(BaseVcsOptions options) .AddSingleton(mapper) .AddSingleton(configuration) .AddSingleton(gitHubClient) - .AddSingleton(); + .AddSingleton(); _serviceProvider = serviceCollection.BuildServiceProvider(); } @@ -179,7 +179,7 @@ private static int GetConsoleWidth() private static async Task CreateReleaseAsync(CreateSubOptions subOptions) { Log.Information("Creating release..."); - _vcsProvider = GetVcsProvider(); + _vcsService = GetVcsService(); Core.Model.Release release; if (!string.IsNullOrEmpty(subOptions.Milestone)) @@ -192,12 +192,12 @@ private static async Task CreateReleaseAsync(CreateSubOptions subOptions) releaseName = subOptions.Milestone; } - release = await _vcsProvider.CreateReleaseFromMilestone(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone, releaseName, subOptions.TargetCommitish, subOptions.AssetPaths, subOptions.Prerelease).ConfigureAwait(false); + release = await _vcsService.CreateReleaseFromMilestone(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone, releaseName, subOptions.TargetCommitish, subOptions.AssetPaths, subOptions.Prerelease).ConfigureAwait(false); } else { Log.Verbose("No milestone was specified, switching to release creating from input file"); - release = await _vcsProvider.CreateReleaseFromInputFile(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Name, subOptions.InputFilePath, subOptions.TargetCommitish, subOptions.AssetPaths, subOptions.Prerelease).ConfigureAwait(false); + release = await _vcsService.CreateReleaseFromInputFile(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Name, subOptions.InputFilePath, subOptions.TargetCommitish, subOptions.AssetPaths, subOptions.Prerelease).ConfigureAwait(false); } Log.Information("Drafted release is available at:\n{HtmlUrl}", release.HtmlUrl); @@ -208,9 +208,9 @@ private static async Task CreateReleaseAsync(CreateSubOptions subOptions) private static async Task DiscardReleaseAsync(DiscardSubOptions subOptions) { Log.Information("Discarding release {Milestone}", subOptions.Milestone); - _vcsProvider = GetVcsProvider(); + _vcsService = GetVcsService(); - await _vcsProvider.DiscardRelease(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false); + await _vcsService.DiscardRelease(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false); return 0; } @@ -218,9 +218,9 @@ private static async Task DiscardReleaseAsync(DiscardSubOptions subOptions) private static async Task AddAssetsAsync(AddAssetSubOptions subOptions) { Log.Information("Uploading assets"); - _vcsProvider = GetVcsProvider(); + _vcsService = GetVcsService(); - await _vcsProvider.AddAssets(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName, subOptions.AssetPaths).ConfigureAwait(false); + await _vcsService.AddAssets(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName, subOptions.AssetPaths).ConfigureAwait(false); return 0; } @@ -228,9 +228,9 @@ private static async Task AddAssetsAsync(AddAssetSubOptions subOptions) private static async Task CloseMilestoneAsync(CloseSubOptions subOptions) { Log.Information("Closing milestone {Milestone}", subOptions.Milestone); - _vcsProvider = GetVcsProvider(); + _vcsService = GetVcsService(); - await _vcsProvider.CloseMilestone(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false); + await _vcsService.CloseMilestone(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false); return 0; } @@ -238,27 +238,27 @@ private static async Task CloseMilestoneAsync(CloseSubOptions subOptions) private static async Task OpenMilestoneAsync(OpenSubOptions subOptions) { Log.Information("Opening milestone {Milestone}", subOptions.Milestone); - _vcsProvider = GetVcsProvider(); + _vcsService = GetVcsService(); - await _vcsProvider.OpenMilestone(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false); + await _vcsService.OpenMilestone(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false); return 0; } private static async Task PublishReleaseAsync(PublishSubOptions subOptions) { - _vcsProvider = GetVcsProvider(); + _vcsService = GetVcsService(); - await _vcsProvider.PublishRelease(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName).ConfigureAwait(false); + await _vcsService.PublishRelease(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName).ConfigureAwait(false); return 0; } private static async Task ExportReleasesAsync(ExportSubOptions subOptions) { Log.Information("Exporting release {TagName}", subOptions.TagName); - _vcsProvider = GetVcsProvider(); + _vcsService = GetVcsService(); - var releasesMarkdown = await _vcsProvider.ExportReleases(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName).ConfigureAwait(false); + var releasesMarkdown = await _vcsService.ExportReleases(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName).ConfigureAwait(false); using (var sw = new StreamWriter(File.Open(subOptions.FileOutputPath, System.IO.FileMode.OpenOrCreate))) { @@ -287,15 +287,15 @@ private static Task ShowConfigAsync(ShowConfigSubOptions subOptions) private static async Task CreateLabelsAsync(LabelSubOptions subOptions) { Log.Information("Creating standard labels"); - _vcsProvider = GetVcsProvider(); + _vcsService = GetVcsService(); - await _vcsProvider.CreateLabels(subOptions.RepositoryOwner, subOptions.RepositoryName).ConfigureAwait(false); + await _vcsService.CreateLabels(subOptions.RepositoryOwner, subOptions.RepositoryName).ConfigureAwait(false); return 0; } - private static IVcsProvider GetVcsProvider() + private static IVcsService GetVcsService() { - return _serviceProvider.GetService(); + return _serviceProvider.GetService(); } private static void LogOptions(BaseSubOptions options) diff --git a/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs b/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs index 34acc4c3..dc7490ac 100644 --- a/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs +++ b/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs @@ -68,8 +68,8 @@ public async Task SingleMilestone() var currentDirectory = Environment.CurrentDirectory; var configuration = ConfigurationProvider.Provide(currentDirectory, fileSystem); - var vcsProvider = new GitHubProvider(_gitHubClient, _logger, _mapper, configuration); - var releaseNotesBuilder = new ReleaseNotesBuilder(vcsProvider, _logger, "Chocolatey", "ChocolateyGUI", "0.12.4", configuration); + var vcsService = new VcsService(_gitHubClient, _logger, _mapper, configuration); + var releaseNotesBuilder = new ReleaseNotesBuilder(vcsService, _logger, "Chocolatey", "ChocolateyGUI", "0.12.4", configuration); var result = await releaseNotesBuilder.BuildReleaseNotes().ConfigureAwait(false); Debug.WriteLine(result); ClipBoardHelper.SetClipboard(result); @@ -90,8 +90,8 @@ public async Task SingleMilestone3() var currentDirectory = Environment.CurrentDirectory; var configuration = ConfigurationProvider.Provide(currentDirectory, fileSystem); - var vcsProvider = new GitHubProvider(_gitHubClient, _logger, _mapper, configuration); - var releaseNotesBuilder = new ReleaseNotesBuilder(vcsProvider, _logger, "Chocolatey", "ChocolateyGUI", "0.13.0", configuration); + var vcsService = new VcsService(_gitHubClient, _logger, _mapper, configuration); + var releaseNotesBuilder = new ReleaseNotesBuilder(vcsService, _logger, "Chocolatey", "ChocolateyGUI", "0.13.0", configuration); var result = await releaseNotesBuilder.BuildReleaseNotes().ConfigureAwait(false); Debug.WriteLine(result); ClipBoardHelper.SetClipboard(result); diff --git a/Source/GitReleaseManager.Tests/FakeGitHubClient.cs b/Source/GitReleaseManager.Tests/FakeGitHubClient.cs index bc30f93d..00987980 100644 --- a/Source/GitReleaseManager.Tests/FakeGitHubClient.cs +++ b/Source/GitReleaseManager.Tests/FakeGitHubClient.cs @@ -11,9 +11,9 @@ namespace GitReleaseManager.Tests using System.Globalization; using System.Threading.Tasks; using GitReleaseManager.Core.Model; - using IVcsProvider = GitReleaseManager.Core.IVcsProvider; + using IVcsService = GitReleaseManager.Core.IVcsService; - public class FakeGitHubClient : IVcsProvider + public class FakeGitHubClient : IVcsService { public FakeGitHubClient() { diff --git a/Source/GitReleaseManager/IVcsProvider.cs b/Source/GitReleaseManager/IVcsService.cs similarity index 94% rename from Source/GitReleaseManager/IVcsProvider.cs rename to Source/GitReleaseManager/IVcsService.cs index 995c05eb..d691b705 100644 --- a/Source/GitReleaseManager/IVcsProvider.cs +++ b/Source/GitReleaseManager/IVcsService.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// +// // Copyright (c) 2015 - Present - GitTools Contributors // //----------------------------------------------------------------------- @@ -11,7 +11,7 @@ namespace GitReleaseManager.Core using System.Threading.Tasks; using GitReleaseManager.Core.Model; - public interface IVcsProvider + public interface IVcsService { Task GetNumberOfCommitsBetween(Milestone previousMilestone, Milestone currentMilestone, string user, string repository); diff --git a/Source/GitReleaseManager/ReleaseNotesBuilder.cs b/Source/GitReleaseManager/ReleaseNotesBuilder.cs index ff6a4bd8..a5622619 100644 --- a/Source/GitReleaseManager/ReleaseNotesBuilder.cs +++ b/Source/GitReleaseManager/ReleaseNotesBuilder.cs @@ -20,7 +20,7 @@ namespace GitReleaseManager.Core public class ReleaseNotesBuilder { - private readonly IVcsProvider _vcsProvider; + private readonly IVcsService _vcsService; private readonly ILogger _logger; private readonly string _user; private readonly string _repository; @@ -29,9 +29,9 @@ public class ReleaseNotesBuilder private ReadOnlyCollection _milestones; private Milestone _targetMilestone; - public ReleaseNotesBuilder(IVcsProvider vcsProvider, ILogger logger, string user, string repository, string milestoneTitle, Config configuration) + public ReleaseNotesBuilder(IVcsService vcsService, ILogger logger, string user, string repository, string milestoneTitle, Config configuration) { - _vcsProvider = vcsProvider; + _vcsService = vcsService; _logger = logger; _user = user; _repository = repository; @@ -48,7 +48,7 @@ public async Task BuildReleaseNotes() var issues = await GetIssues(_targetMilestone).ConfigureAwait(false); var stringBuilder = new StringBuilder(); var previousMilestone = GetPreviousMilestone(); - var numberOfCommits = await _vcsProvider.GetNumberOfCommitsBetween(previousMilestone, _targetMilestone, _user, _repository).ConfigureAwait(false); + var numberOfCommits = await _vcsService.GetNumberOfCommitsBetween(previousMilestone, _targetMilestone, _user, _repository).ConfigureAwait(false); if (issues.Count == 0) { @@ -62,7 +62,7 @@ public async Task BuildReleaseNotes() if (numberOfCommits > 0) { - var commitsLink = _vcsProvider.GetCommitsLink(_user, _repository, _targetMilestone, previousMilestone); + var commitsLink = _vcsService.GetCommitsLink(_user, _repository, _targetMilestone, 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 + "?closed=1"); @@ -74,7 +74,7 @@ public async Task BuildReleaseNotes() } else if (numberOfCommits > 0) { - var commitsLink = _vcsProvider.GetCommitsLink(_user, _repository, _targetMilestone, previousMilestone); + var commitsLink = _vcsService.GetCommitsLink(_user, _repository, _targetMilestone, 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); } @@ -193,12 +193,12 @@ private void AddFooter(StringBuilder stringBuilder) private async Task LoadMilestones() { - _milestones = await _vcsProvider.GetReadOnlyMilestonesAsync(_user, _repository).ConfigureAwait(false); + _milestones = await _vcsService.GetReadOnlyMilestonesAsync(_user, _repository).ConfigureAwait(false); } private async Task> GetIssues(Milestone milestone) { - var issues = await _vcsProvider.GetIssuesAsync(milestone).ConfigureAwait(false); + var issues = await _vcsService.GetIssuesAsync(milestone).ConfigureAwait(false); var hasIncludedIssues = false; diff --git a/Source/GitReleaseManager/ReleaseNotesExporter.cs b/Source/GitReleaseManager/ReleaseNotesExporter.cs index 08c07fc5..7bbb4f36 100644 --- a/Source/GitReleaseManager/ReleaseNotesExporter.cs +++ b/Source/GitReleaseManager/ReleaseNotesExporter.cs @@ -17,15 +17,15 @@ namespace GitReleaseManager.Core public class ReleaseNotesExporter { - private readonly IVcsProvider _vcsProvider; + private readonly IVcsService _vcsService; private readonly ILogger _logger; private readonly Config _configuration; private readonly string _user; private readonly string _repository; - public ReleaseNotesExporter(IVcsProvider vcsProvider, ILogger logger, Config configuration, string user, string repository) + public ReleaseNotesExporter(IVcsService vcsService, ILogger logger, Config configuration, string user, string repository) { - _vcsProvider = vcsProvider; + _vcsService = vcsService; _logger = logger; _configuration = configuration; _user = user; @@ -40,7 +40,7 @@ public async Task ExportReleaseNotes(string tagName) if (string.IsNullOrEmpty(tagName)) { - var releases = await _vcsProvider.GetReleasesAsync(_user, _repository).ConfigureAwait(false); + var releases = await _vcsService.GetReleasesAsync(_user, _repository).ConfigureAwait(false); if (releases.Count > 0) { @@ -56,7 +56,7 @@ public async Task ExportReleaseNotes(string tagName) } else { - var release = await _vcsProvider.GetSpecificRelease(tagName, _user, _repository).ConfigureAwait(false); + var release = await _vcsService.GetSpecificRelease(tagName, _user, _repository).ConfigureAwait(false); AppendVersionReleaseNotes(stringBuilder, release); } diff --git a/Source/GitReleaseManager/GitHubProvider.cs b/Source/GitReleaseManager/VcsService.cs similarity index 99% rename from Source/GitReleaseManager/GitHubProvider.cs rename to Source/GitReleaseManager/VcsService.cs index e4af67f5..3a896548 100644 --- a/Source/GitReleaseManager/GitHubProvider.cs +++ b/Source/GitReleaseManager/VcsService.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// +// // Copyright (c) 2015 - Present - GitTools Contributors // //----------------------------------------------------------------------- @@ -26,14 +26,14 @@ namespace GitReleaseManager.Core using Milestone = GitReleaseManager.Core.Model.Milestone; using Release = GitReleaseManager.Core.Model.Release; - public class GitHubProvider : IVcsProvider + public class VcsService : IVcsService { private readonly IGitHubClient _gitHubClient; private readonly ILogger _logger; private readonly IMapper _mapper; private readonly Config _configuration; - public GitHubProvider(IGitHubClient gitHubClient, ILogger logger, IMapper mapper, Config configuration) + public VcsService(IGitHubClient gitHubClient, ILogger logger, IMapper mapper, Config configuration) { _gitHubClient = gitHubClient; _logger = logger; From 9b7103ff01650e82d8316b77447ef7eeaa178031 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Wed, 5 Aug 2020 14:21:48 +0200 Subject: [PATCH 050/181] (GH-181) Extract method from VcsService to VcsProvider --- Source/GitReleaseManager.Cli/Program.cs | 2 ++ Source/GitReleaseManager/Ensure.cs | 33 +++++++++++++++++++ Source/GitReleaseManager/IVcsService.cs | 2 -- .../Provider/GitHubProvider.cs | 25 ++++++++++++++ .../Provider/IVcsProvider.cs | 7 ++++ .../GitReleaseManager/ReleaseNotesBuilder.cs | 9 +++-- Source/GitReleaseManager/VcsService.cs | 23 +++---------- 7 files changed, 78 insertions(+), 23 deletions(-) create mode 100644 Source/GitReleaseManager/Ensure.cs create mode 100644 Source/GitReleaseManager/Provider/GitHubProvider.cs create mode 100644 Source/GitReleaseManager/Provider/IVcsProvider.cs diff --git a/Source/GitReleaseManager.Cli/Program.cs b/Source/GitReleaseManager.Cli/Program.cs index fbd8887a..debe6c0c 100644 --- a/Source/GitReleaseManager.Cli/Program.cs +++ b/Source/GitReleaseManager.Cli/Program.cs @@ -17,6 +17,7 @@ namespace GitReleaseManager.Cli using GitReleaseManager.Core; using GitReleaseManager.Core.Configuration; using GitReleaseManager.Core.Helpers; + using GitReleaseManager.Core.Provider; using Microsoft.Extensions.DependencyInjection; using Octokit; using Serilog; @@ -95,6 +96,7 @@ private static void RegisterServices(BaseVcsOptions options) .AddSingleton(mapper) .AddSingleton(configuration) .AddSingleton(gitHubClient) + .AddSingleton() .AddSingleton(); _serviceProvider = serviceCollection.BuildServiceProvider(); diff --git a/Source/GitReleaseManager/Ensure.cs b/Source/GitReleaseManager/Ensure.cs new file mode 100644 index 00000000..52350a08 --- /dev/null +++ b/Source/GitReleaseManager/Ensure.cs @@ -0,0 +1,33 @@ +using System; + +namespace GitReleaseManager.Core +{ + /// + /// Provides static methods that help a constructor or method to verify correct arguments and + /// state. + /// + public static class Ensure + { + /// + /// Checks whether a specified string is not null, empty, or consists only + /// of white-space characters. + /// + /// The string to test. + /// The name of the parameter that caused the exception. + /// str is + /// null. + /// str is + /// whitespace. + public static void IsNotNullOrWhiteSpace(string str, string paramName) + { + if (str == null) + { + throw new ArgumentNullException(paramName); + } + else if (string.IsNullOrWhiteSpace(str)) + { + throw new ArgumentException($"Value cannot be empty or white-space. (Parameter '{paramName}')", paramName); + } + } + } +} \ No newline at end of file diff --git a/Source/GitReleaseManager/IVcsService.cs b/Source/GitReleaseManager/IVcsService.cs index d691b705..b7e2870c 100644 --- a/Source/GitReleaseManager/IVcsService.cs +++ b/Source/GitReleaseManager/IVcsService.cs @@ -15,8 +15,6 @@ public interface IVcsService { Task GetNumberOfCommitsBetween(Milestone previousMilestone, Milestone currentMilestone, string user, string repository); - string GetCommitsLink(string user, string repository, Milestone milestone, Milestone previousMilestone); - Task> GetIssuesAsync(Milestone targetMilestone); Task> GetReleasesAsync(string user, string repository); diff --git a/Source/GitReleaseManager/Provider/GitHubProvider.cs b/Source/GitReleaseManager/Provider/GitHubProvider.cs new file mode 100644 index 00000000..95c15da6 --- /dev/null +++ b/Source/GitReleaseManager/Provider/GitHubProvider.cs @@ -0,0 +1,25 @@ +using System.Globalization; + +namespace GitReleaseManager.Core.Provider +{ + public class GitHubProvider : IVcsProvider + { + public string GetCommitsUrl(string owner, string repository, string baseMilestoneTitle, string compareMilestoneTitle = null) + { + Ensure.IsNotNullOrWhiteSpace(baseMilestoneTitle, nameof(baseMilestoneTitle)); + + string url; + + if (string.IsNullOrWhiteSpace(compareMilestoneTitle)) + { + url = string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/commits/{2}", owner, repository, baseMilestoneTitle); + } + else + { + url = string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/compare/{2}...{3}", owner, repository, compareMilestoneTitle, baseMilestoneTitle); + } + + return url; + } + } +} \ No newline at end of file diff --git a/Source/GitReleaseManager/Provider/IVcsProvider.cs b/Source/GitReleaseManager/Provider/IVcsProvider.cs new file mode 100644 index 00000000..d01a3a6f --- /dev/null +++ b/Source/GitReleaseManager/Provider/IVcsProvider.cs @@ -0,0 +1,7 @@ +namespace GitReleaseManager.Core.Provider +{ + public interface IVcsProvider + { + string GetCommitsUrl(string owner, string repository, string baseMilestoneTitle, string compareMilestoneTitle = null); + } +} \ No newline at end of file diff --git a/Source/GitReleaseManager/ReleaseNotesBuilder.cs b/Source/GitReleaseManager/ReleaseNotesBuilder.cs index a5622619..bcad2017 100644 --- a/Source/GitReleaseManager/ReleaseNotesBuilder.cs +++ b/Source/GitReleaseManager/ReleaseNotesBuilder.cs @@ -16,11 +16,13 @@ namespace GitReleaseManager.Core using GitReleaseManager.Core.Configuration; using GitReleaseManager.Core.Extensions; using GitReleaseManager.Core.Model; + using GitReleaseManager.Core.Provider; using Serilog; public class ReleaseNotesBuilder { private readonly IVcsService _vcsService; + private readonly IVcsProvider _vcsProvider; private readonly ILogger _logger; private readonly string _user; private readonly string _repository; @@ -29,9 +31,10 @@ public class ReleaseNotesBuilder private ReadOnlyCollection _milestones; private Milestone _targetMilestone; - public ReleaseNotesBuilder(IVcsService vcsService, ILogger logger, string user, string repository, string milestoneTitle, Config configuration) + public ReleaseNotesBuilder(IVcsService vcsService, IVcsProvider vcsProvider, ILogger logger, string user, string repository, string milestoneTitle, Config configuration) { _vcsService = vcsService; + _vcsProvider = vcsProvider; _logger = logger; _user = user; _repository = repository; @@ -62,7 +65,7 @@ public async Task BuildReleaseNotes() if (numberOfCommits > 0) { - var commitsLink = _vcsService.GetCommitsLink(_user, _repository, _targetMilestone, previousMilestone); + var commitsLink = _vcsProvider.GetCommitsUrl(_user, _repository, _targetMilestone?.Title, previousMilestone?.Title); 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 + "?closed=1"); @@ -74,7 +77,7 @@ public async Task BuildReleaseNotes() } else if (numberOfCommits > 0) { - var commitsLink = _vcsService.GetCommitsLink(_user, _repository, _targetMilestone, previousMilestone); + var commitsLink = _vcsProvider.GetCommitsUrl(_user, _repository, _targetMilestone?.Title, previousMilestone?.Title); var commitsText = string.Format(numberOfCommits == 1 ? "{0} commit" : "{0} commits", numberOfCommits); stringBuilder.AppendFormat(@"As part of this release we had [{0}]({1}).", commitsText, commitsLink); } diff --git a/Source/GitReleaseManager/VcsService.cs b/Source/GitReleaseManager/VcsService.cs index 3a896548..7dca72a4 100644 --- a/Source/GitReleaseManager/VcsService.cs +++ b/Source/GitReleaseManager/VcsService.cs @@ -9,7 +9,6 @@ namespace GitReleaseManager.Core using System; using System.Collections.Generic; using System.Collections.ObjectModel; - using System.Globalization; using System.IO; using System.Linq; using System.Security.Cryptography; @@ -20,6 +19,7 @@ namespace GitReleaseManager.Core using GitReleaseManager.Core.Configuration; using GitReleaseManager.Core.Exceptions; using GitReleaseManager.Core.Extensions; + using GitReleaseManager.Core.Provider; using Octokit; using Serilog; using Issue = GitReleaseManager.Core.Model.Issue; @@ -28,13 +28,15 @@ namespace GitReleaseManager.Core public class VcsService : IVcsService { + private readonly IVcsProvider _vcsProvider; private readonly IGitHubClient _gitHubClient; private readonly ILogger _logger; private readonly IMapper _mapper; private readonly Config _configuration; - public VcsService(IGitHubClient gitHubClient, ILogger logger, IMapper mapper, Config configuration) + public VcsService(IVcsProvider vcsProvider, IGitHubClient gitHubClient, ILogger logger, IMapper mapper, Config configuration) { + _vcsProvider = vcsProvider; _gitHubClient = gitHubClient; _logger = logger; _mapper = mapper; @@ -96,25 +98,10 @@ public async Task> GetReadOnlyMilestonesAsync(stri return new ReadOnlyCollection(_mapper.Map>(closed.Concat(open).ToList())); } - public string GetCommitsLink(string user, string repository, Milestone milestone, Milestone previousMilestone) - { - if (milestone is null) - { - throw new ArgumentNullException(nameof(milestone)); - } - - if (previousMilestone is null) - { - return string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/commits/{2}", user, repository, milestone.Title); - } - - return string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/compare/{2}...{3}", user, repository, previousMilestone.Title, milestone.Title); - } - public async Task CreateReleaseFromMilestone(string owner, string repository, string milestone, string releaseName, string targetCommitish, IList assets, bool prerelease) { var release = await GetReleaseFromTagNameAsync(owner, repository, milestone).ConfigureAwait(false); - var releaseNotesBuilder = new ReleaseNotesBuilder(this, _logger, owner, repository, milestone, _configuration); + var releaseNotesBuilder = new ReleaseNotesBuilder(this, _vcsProvider, _logger, owner, repository, milestone, _configuration); var result = await releaseNotesBuilder.BuildReleaseNotes().ConfigureAwait(false); if (release == null) From f496f505dc1725c4970d824c5cb6d6787085e26d Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Wed, 5 Aug 2020 14:24:08 +0200 Subject: [PATCH 051/181] (GH-181) Update unit tests --- .../ReleaseNotesBuilderIntegrationTests.cs | 14 ++++++++------ .../ReleaseNotesBuilderTests.cs | 9 +++++---- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs b/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs index dc7490ac..369cb122 100644 --- a/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs +++ b/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs @@ -4,8 +4,6 @@ // //----------------------------------------------------------------------- -using Octokit; - namespace GitReleaseManager.IntegrationTests { using System; @@ -15,7 +13,9 @@ namespace GitReleaseManager.IntegrationTests using GitReleaseManager.Core; using GitReleaseManager.Core.Configuration; using GitReleaseManager.Core.Helpers; + using GitReleaseManager.Core.Provider; using NUnit.Framework; + using Octokit; using Serilog; [TestFixture] @@ -68,8 +68,9 @@ public async Task SingleMilestone() var currentDirectory = Environment.CurrentDirectory; var configuration = ConfigurationProvider.Provide(currentDirectory, fileSystem); - var vcsService = new VcsService(_gitHubClient, _logger, _mapper, configuration); - var releaseNotesBuilder = new ReleaseNotesBuilder(vcsService, _logger, "Chocolatey", "ChocolateyGUI", "0.12.4", configuration); + var vcsProvider = new GitHubProvider(); + var vcsService = new VcsService(vcsProvider, _gitHubClient, _logger, _mapper, configuration); + var releaseNotesBuilder = new ReleaseNotesBuilder(vcsService, vcsProvider, _logger, "Chocolatey", "ChocolateyGUI", "0.12.4", configuration); var result = await releaseNotesBuilder.BuildReleaseNotes().ConfigureAwait(false); Debug.WriteLine(result); ClipBoardHelper.SetClipboard(result); @@ -90,8 +91,9 @@ public async Task SingleMilestone3() var currentDirectory = Environment.CurrentDirectory; var configuration = ConfigurationProvider.Provide(currentDirectory, fileSystem); - var vcsService = new VcsService(_gitHubClient, _logger, _mapper, configuration); - var releaseNotesBuilder = new ReleaseNotesBuilder(vcsService, _logger, "Chocolatey", "ChocolateyGUI", "0.13.0", configuration); + var vcsProvider = new GitHubProvider(); + var vcsService = new VcsService(vcsProvider, _gitHubClient, _logger, _mapper, configuration); + var releaseNotesBuilder = new ReleaseNotesBuilder(vcsService, vcsProvider, _logger, "Chocolatey", "ChocolateyGUI", "0.13.0", configuration); var result = await releaseNotesBuilder.BuildReleaseNotes().ConfigureAwait(false); Debug.WriteLine(result); ClipBoardHelper.SetClipboard(result); diff --git a/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs b/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs index db199e18..66774ea7 100644 --- a/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs +++ b/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs @@ -4,9 +4,6 @@ // //----------------------------------------------------------------------- -using NSubstitute; -using Serilog; - namespace GitReleaseManager.Tests { using System; @@ -16,7 +13,10 @@ namespace GitReleaseManager.Tests using GitReleaseManager.Core.Configuration; using GitReleaseManager.Core.Helpers; using GitReleaseManager.Core.Model; + using GitReleaseManager.Core.Provider; + using NSubstitute; using NUnit.Framework; + using Serilog; [TestFixture] public class ReleaseNotesBuilderTests @@ -163,7 +163,8 @@ private static void AcceptTest(int commits, Config config, params Issue[] issues fakeClient.Issues.Add(issue); } - var builder = new ReleaseNotesBuilder(fakeClient, logger, "TestUser", "FakeRepository", "1.2.3", configuration); + var vcsProvider = new GitHubProvider(); + var builder = new ReleaseNotesBuilder(fakeClient, vcsProvider, logger, "TestUser", "FakeRepository", "1.2.3", configuration); var notes = builder.BuildReleaseNotes().Result; Approvals.Verify(notes); From 5510d77516042ba0e1c43d182b56d6471d46ccc2 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Wed, 5 Aug 2020 16:01:11 +0200 Subject: [PATCH 052/181] (GH-181) Update classes, add unit tests --- .../EnsureTests.cs | 29 ++++++++++++ .../GitReleaseManager.Core.Tests.csproj | 29 ++++++++++++ .../Provider/GitHubProviderTests.cs | 46 +++++++++++++++++++ Source/GitReleaseManager.sln | 8 +++- Source/GitReleaseManager/Ensure.cs | 2 +- .../Provider/GitHubProvider.cs | 10 ++-- .../Provider/IVcsProvider.cs | 2 +- 7 files changed, 119 insertions(+), 7 deletions(-) create mode 100644 Source/GitReleaseManager.Core.Tests/EnsureTests.cs create mode 100644 Source/GitReleaseManager.Core.Tests/GitReleaseManager.Core.Tests.csproj create mode 100644 Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs diff --git a/Source/GitReleaseManager.Core.Tests/EnsureTests.cs b/Source/GitReleaseManager.Core.Tests/EnsureTests.cs new file mode 100644 index 00000000..83ddeeb3 --- /dev/null +++ b/Source/GitReleaseManager.Core.Tests/EnsureTests.cs @@ -0,0 +1,29 @@ +using System; +using NUnit.Framework; +using Shouldly; + +namespace GitReleaseManager.Core.Tests +{ + [TestFixture] + public class EnsureTests + { + [Test] + public void Should_Throw_Exception_When_String_Is_Null() + { + var paramName = "str"; + + var ex = Should.Throw(() => Ensure.IsNotNullOrWhiteSpace(null, paramName)); + ex.ParamName.ShouldBe(paramName); + } + + [Test] + public void Should_Throw_Exception_When_String_Is_Whitespace([Values("", " ")] string str) + { + var paramName = nameof(str); + + var ex = Should.Throw(() => Ensure.IsNotNullOrWhiteSpace(str, paramName)); + ex.Message.ShouldContain("Value cannot be empty or white-space."); + ex.ParamName.ShouldBe(paramName); + } + } +} \ No newline at end of file diff --git a/Source/GitReleaseManager.Core.Tests/GitReleaseManager.Core.Tests.csproj b/Source/GitReleaseManager.Core.Tests/GitReleaseManager.Core.Tests.csproj new file mode 100644 index 00000000..6e29a42c --- /dev/null +++ b/Source/GitReleaseManager.Core.Tests/GitReleaseManager.Core.Tests.csproj @@ -0,0 +1,29 @@ + + + 8.0 + net472;netcoreapp2.2 + GitReleaseManager.Core.Tests + Test Project for GitReleaseManager.Core + $(NoWarn);CA1707 + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + \ No newline at end of file diff --git a/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs b/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs new file mode 100644 index 00000000..7e73fb75 --- /dev/null +++ b/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections; +using GitReleaseManager.Core.Provider; +using NUnit.Framework; +using Shouldly; + +namespace GitReleaseManager.Core.Tests.Provider +{ + [TestFixture] + public class GitHubProviderTests + { + [TestCase("0.1.0", null, "https://github.com/owner/repo/commits/0.1.0")] + [TestCase("0.5.0", "0.1.0", "https://github.com/owner/repo/compare/0.1.0...0.5.0")] + public void Should_Get_A_Commits_Url(string milestoneTitle, string compareMilestoneTitle, string expectedResult) + { + var gitHubProvider = new GitHubProvider(); + + var result = gitHubProvider.GetCommitsUrl("owner", "repo", milestoneTitle, compareMilestoneTitle); + result.ShouldBe(expectedResult); + } + + [TestCaseSource(nameof(GetCommitsUrl_TestCases))] + public void Should_Throw_An_Exception_If_Parameter_Is_Invalid(string owner, string repository, string milestoneTitle, string paramName, Type expectedException) + { + var gitHubProvider = new GitHubProvider(); + + var ex = Should.Throw(() => gitHubProvider.GetCommitsUrl(owner, repository, milestoneTitle), expectedException); + ex.Message.ShouldContain(paramName); + } + + public static IEnumerable GetCommitsUrl_TestCases() + { + yield return new TestCaseData(null, null, null, "owner", typeof(ArgumentNullException)); + yield return new TestCaseData("", null, null, "owner", typeof(ArgumentException)); + yield return new TestCaseData(" ", null, null, "owner", typeof(ArgumentException)); + + yield return new TestCaseData("owner", null, null, "repository", typeof(ArgumentNullException)); + yield return new TestCaseData("owner", "", null, "repository", typeof(ArgumentException)); + yield return new TestCaseData("owner", " ", null, "repository", typeof(ArgumentException)); + + yield return new TestCaseData("owner", "repository", null, "milestoneTitle", typeof(ArgumentNullException)); + yield return new TestCaseData("owner", "repository", "", "milestoneTitle", typeof(ArgumentException)); + yield return new TestCaseData("owner", "repository", " ", "milestoneTitle", typeof(ArgumentException)); + } + } +} \ No newline at end of file diff --git a/Source/GitReleaseManager.sln b/Source/GitReleaseManager.sln index 5bdbb63e..26694af9 100644 --- a/Source/GitReleaseManager.sln +++ b/Source/GitReleaseManager.sln @@ -29,7 +29,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Chocolatey", "Chocolatey", ..\nuspec\chocolatey\VERIFICATION.TXT = ..\nuspec\chocolatey\VERIFICATION.TXT EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitReleaseManager.Tool", "GitReleaseManager.Tool\GitReleaseManager.Tool.csproj", "{E60129C7-706A-4B24-9D8D-6D5F23543280}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GitReleaseManager.Tool", "GitReleaseManager.Tool\GitReleaseManager.Tool.csproj", "{E60129C7-706A-4B24-9D8D-6D5F23543280}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GitReleaseManager.Core.Tests", "GitReleaseManager.Core.Tests\GitReleaseManager.Core.Tests.csproj", "{DB77C071-63A0-4B48-863F-5F78485AA09A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -57,6 +59,10 @@ Global {E60129C7-706A-4B24-9D8D-6D5F23543280}.Debug|Any CPU.Build.0 = Debug|Any CPU {E60129C7-706A-4B24-9D8D-6D5F23543280}.Release|Any CPU.ActiveCfg = Release|Any CPU {E60129C7-706A-4B24-9D8D-6D5F23543280}.Release|Any CPU.Build.0 = Release|Any CPU + {DB77C071-63A0-4B48-863F-5F78485AA09A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB77C071-63A0-4B48-863F-5F78485AA09A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB77C071-63A0-4B48-863F-5F78485AA09A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB77C071-63A0-4B48-863F-5F78485AA09A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Source/GitReleaseManager/Ensure.cs b/Source/GitReleaseManager/Ensure.cs index 52350a08..4e2e22a2 100644 --- a/Source/GitReleaseManager/Ensure.cs +++ b/Source/GitReleaseManager/Ensure.cs @@ -26,7 +26,7 @@ public static void IsNotNullOrWhiteSpace(string str, string paramName) } else if (string.IsNullOrWhiteSpace(str)) { - throw new ArgumentException($"Value cannot be empty or white-space. (Parameter '{paramName}')", paramName); + throw new ArgumentException("Value cannot be empty or white-space.", paramName); } } } diff --git a/Source/GitReleaseManager/Provider/GitHubProvider.cs b/Source/GitReleaseManager/Provider/GitHubProvider.cs index 95c15da6..e8ecbdd7 100644 --- a/Source/GitReleaseManager/Provider/GitHubProvider.cs +++ b/Source/GitReleaseManager/Provider/GitHubProvider.cs @@ -4,19 +4,21 @@ namespace GitReleaseManager.Core.Provider { public class GitHubProvider : IVcsProvider { - public string GetCommitsUrl(string owner, string repository, string baseMilestoneTitle, string compareMilestoneTitle = null) + public string GetCommitsUrl(string owner, string repository, string milestoneTitle, string compareMilestoneTitle = null) { - Ensure.IsNotNullOrWhiteSpace(baseMilestoneTitle, nameof(baseMilestoneTitle)); + Ensure.IsNotNullOrWhiteSpace(owner, nameof(owner)); + Ensure.IsNotNullOrWhiteSpace(repository, nameof(repository)); + Ensure.IsNotNullOrWhiteSpace(milestoneTitle, nameof(milestoneTitle)); string url; if (string.IsNullOrWhiteSpace(compareMilestoneTitle)) { - url = string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/commits/{2}", owner, repository, baseMilestoneTitle); + url = string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/commits/{2}", owner, repository, milestoneTitle); } else { - url = string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/compare/{2}...{3}", owner, repository, compareMilestoneTitle, baseMilestoneTitle); + url = string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/compare/{2}...{3}", owner, repository, compareMilestoneTitle, milestoneTitle); } return url; diff --git a/Source/GitReleaseManager/Provider/IVcsProvider.cs b/Source/GitReleaseManager/Provider/IVcsProvider.cs index d01a3a6f..e6f0ff13 100644 --- a/Source/GitReleaseManager/Provider/IVcsProvider.cs +++ b/Source/GitReleaseManager/Provider/IVcsProvider.cs @@ -2,6 +2,6 @@ namespace GitReleaseManager.Core.Provider { public interface IVcsProvider { - string GetCommitsUrl(string owner, string repository, string baseMilestoneTitle, string compareMilestoneTitle = null); + string GetCommitsUrl(string owner, string repository, string milestoneTitle, string compareMilestoneTitle = null); } } \ No newline at end of file From a8c4f5a6fed14f8bc49ba04dee2068aa088a5815 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 6 Aug 2020 11:21:13 +0200 Subject: [PATCH 053/181] (GH-181) Extract method from VcsService to VcsProvider --- ...{FakeGitHubClient.cs => VcsServiceMock.cs} | 11 ++---- .../Exceptions/ApiException.cs | 28 +++++++++++++++ Source/GitReleaseManager/IVcsService.cs | 2 -- .../Model/ItemStateFilter.cs | 20 +++++++++++ Source/GitReleaseManager/Model/Milestone.cs | 2 +- .../Provider/GitHubProvider.cs | 35 +++++++++++++++++++ .../Provider/IVcsProvider.cs | 6 ++++ .../GitReleaseManager/ReleaseNotesBuilder.cs | 4 +-- Source/GitReleaseManager/VcsService.cs | 9 ----- 9 files changed, 95 insertions(+), 22 deletions(-) rename Source/GitReleaseManager.Tests/{FakeGitHubClient.cs => VcsServiceMock.cs} (93%) create mode 100644 Source/GitReleaseManager/Exceptions/ApiException.cs create mode 100644 Source/GitReleaseManager/Model/ItemStateFilter.cs diff --git a/Source/GitReleaseManager.Tests/FakeGitHubClient.cs b/Source/GitReleaseManager.Tests/VcsServiceMock.cs similarity index 93% rename from Source/GitReleaseManager.Tests/FakeGitHubClient.cs rename to Source/GitReleaseManager.Tests/VcsServiceMock.cs index 00987980..b00f36fb 100644 --- a/Source/GitReleaseManager.Tests/FakeGitHubClient.cs +++ b/Source/GitReleaseManager.Tests/VcsServiceMock.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// +// // Copyright (c) 2015 - Present - GitTools Contributors // //----------------------------------------------------------------------- @@ -13,9 +13,9 @@ namespace GitReleaseManager.Tests using GitReleaseManager.Core.Model; using IVcsService = GitReleaseManager.Core.IVcsService; - public class FakeGitHubClient : IVcsService + public class VcsServiceMock : IVcsService { - public FakeGitHubClient() + public VcsServiceMock() { Milestones = new List(); Issues = new List(); @@ -38,11 +38,6 @@ public Task GetNumberOfCommitsBetween(Milestone previousMilestone, Mileston return Task.FromResult(NumberOfCommits); } - public Task> GetIssuesAsync(Milestone targetMilestone) - { - return Task.FromResult(Issues); - } - public Task> GetReleasesAsync(string user, string repository) { return Task.FromResult(Releases); diff --git a/Source/GitReleaseManager/Exceptions/ApiException.cs b/Source/GitReleaseManager/Exceptions/ApiException.cs new file mode 100644 index 00000000..6bf81139 --- /dev/null +++ b/Source/GitReleaseManager/Exceptions/ApiException.cs @@ -0,0 +1,28 @@ +using System; +using System.Runtime.Serialization; + +namespace GitReleaseManager.Core.Exceptions +{ + [Serializable] + public class ApiException : Exception + { + public ApiException() + { + } + + public ApiException(string message) + : base(message) + { + } + + public ApiException(string message, Exception inner) + : base(message, inner) + { + } + + protected ApiException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/Source/GitReleaseManager/IVcsService.cs b/Source/GitReleaseManager/IVcsService.cs index b7e2870c..736c59c5 100644 --- a/Source/GitReleaseManager/IVcsService.cs +++ b/Source/GitReleaseManager/IVcsService.cs @@ -15,8 +15,6 @@ public interface IVcsService { Task GetNumberOfCommitsBetween(Milestone previousMilestone, Milestone currentMilestone, string user, string repository); - Task> GetIssuesAsync(Milestone targetMilestone); - Task> GetReleasesAsync(string user, string repository); Task GetSpecificRelease(string tagName, string user, string repository); diff --git a/Source/GitReleaseManager/Model/ItemStateFilter.cs b/Source/GitReleaseManager/Model/ItemStateFilter.cs new file mode 100644 index 00000000..10eded25 --- /dev/null +++ b/Source/GitReleaseManager/Model/ItemStateFilter.cs @@ -0,0 +1,20 @@ +namespace GitReleaseManager.Core.Model +{ + public enum ItemStateFilter + { + /// + /// Items that are open. + /// + Open = 0, + + /// + /// Items that are closed. + /// + Closed = 1, + + /// + /// All the items. + /// + All = 2 + } +} \ No newline at end of file diff --git a/Source/GitReleaseManager/Model/Milestone.cs b/Source/GitReleaseManager/Model/Milestone.cs index 567b9e35..20d187aa 100644 --- a/Source/GitReleaseManager/Model/Milestone.cs +++ b/Source/GitReleaseManager/Model/Milestone.cs @@ -14,7 +14,7 @@ public sealed class Milestone public string Description { get; set; } - public string Number { get; set; } + public int Number { get; set; } public string HtmlUrl { get; set; } diff --git a/Source/GitReleaseManager/Provider/GitHubProvider.cs b/Source/GitReleaseManager/Provider/GitHubProvider.cs index e8ecbdd7..51830991 100644 --- a/Source/GitReleaseManager/Provider/GitHubProvider.cs +++ b/Source/GitReleaseManager/Provider/GitHubProvider.cs @@ -1,9 +1,24 @@ +using System.Collections.Generic; using System.Globalization; +using System.Threading.Tasks; +using AutoMapper; +using Octokit; +using Issue = GitReleaseManager.Core.Model.Issue; +using ItemStateFilter = GitReleaseManager.Core.Model.ItemStateFilter; namespace GitReleaseManager.Core.Provider { public class GitHubProvider : IVcsProvider { + private readonly IGitHubClient _gitHubClient; + private readonly IMapper _mapper; + + public GitHubProvider(IGitHubClient gitHubClient, IMapper mapper) + { + _gitHubClient = gitHubClient; + _mapper = mapper; + } + public string GetCommitsUrl(string owner, string repository, string milestoneTitle, string compareMilestoneTitle = null) { Ensure.IsNotNullOrWhiteSpace(owner, nameof(owner)); @@ -23,5 +38,25 @@ public string GetCommitsUrl(string owner, string repository, string milestoneTit return url; } + + public async Task> GetIssuesAsync(string owner, string repository, int milestoneNumber, ItemStateFilter itemStateFilter = ItemStateFilter.All) + { + try + { + var openIssueRequest = new RepositoryIssueRequest + { + Milestone = milestoneNumber.ToString(CultureInfo.InvariantCulture), + State = (Octokit.ItemStateFilter)itemStateFilter, + }; + + var issues = await _gitHubClient.Issue.GetAllForRepository(owner, repository, openIssueRequest).ConfigureAwait(false); + + return _mapper.Map>(issues); + } + catch (ApiValidationException ex) + { + throw new ApiException(ex.Message, ex); + } + } } } \ No newline at end of file diff --git a/Source/GitReleaseManager/Provider/IVcsProvider.cs b/Source/GitReleaseManager/Provider/IVcsProvider.cs index e6f0ff13..7ad5c2a7 100644 --- a/Source/GitReleaseManager/Provider/IVcsProvider.cs +++ b/Source/GitReleaseManager/Provider/IVcsProvider.cs @@ -1,7 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using GitReleaseManager.Core.Model; + namespace GitReleaseManager.Core.Provider { public interface IVcsProvider { string GetCommitsUrl(string owner, string repository, string milestoneTitle, string compareMilestoneTitle = null); + + Task> GetIssuesAsync(string owner, string repository, int milestoneNumber, ItemStateFilter itemStateFilter = ItemStateFilter.All); } } \ No newline at end of file diff --git a/Source/GitReleaseManager/ReleaseNotesBuilder.cs b/Source/GitReleaseManager/ReleaseNotesBuilder.cs index bcad2017..a87516df 100644 --- a/Source/GitReleaseManager/ReleaseNotesBuilder.cs +++ b/Source/GitReleaseManager/ReleaseNotesBuilder.cs @@ -201,7 +201,7 @@ private async Task LoadMilestones() private async Task> GetIssues(Milestone milestone) { - var issues = await _vcsService.GetIssuesAsync(milestone).ConfigureAwait(false); + var issues = await _vcsProvider.GetIssuesAsync(_user, _repository, milestone.Number, ItemStateFilter.Closed).ConfigureAwait(false); var hasIncludedIssues = false; @@ -222,7 +222,7 @@ private async Task> GetIssues(Milestone milestone) return new List(); } - return issues; + return issues.ToList(); } private void GetTargetMilestone() diff --git a/Source/GitReleaseManager/VcsService.cs b/Source/GitReleaseManager/VcsService.cs index 7dca72a4..23bd1cf4 100644 --- a/Source/GitReleaseManager/VcsService.cs +++ b/Source/GitReleaseManager/VcsService.cs @@ -22,7 +22,6 @@ namespace GitReleaseManager.Core using GitReleaseManager.Core.Provider; using Octokit; using Serilog; - using Issue = GitReleaseManager.Core.Model.Issue; using Milestone = GitReleaseManager.Core.Model.Milestone; using Release = GitReleaseManager.Core.Model.Release; @@ -53,14 +52,6 @@ public Task GetNumberOfCommitsBetween(Milestone previousMilestone, Mileston return GetNumberOfCommitsBetweenInternal(previousMilestone, currentMilestone, user, repository); } - public async Task> GetIssuesAsync(Milestone targetMilestone) - { - var githubMilestone = _mapper.Map(targetMilestone); - _logger.Verbose("Finding issues on milestone: {@Milestone}", githubMilestone); - var allIssues = await _gitHubClient.AllIssuesForMilestone(githubMilestone).ConfigureAwait(false); - return _mapper.Map>(allIssues.Where(x => x.State == ItemState.Closed).ToList()); - } - public async Task> GetReleasesAsync(string user, string repository) { _logger.Verbose("Finding all releases on '{User}/{Repository}'", user, repository); From c1ba1a0f265ff2863b642aa349b34dd492043a0a Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 6 Aug 2020 11:23:15 +0200 Subject: [PATCH 054/181] (GH-181) Update and add unit tests --- .../Provider/GitHubProviderTests.cs | 74 +++++++++++++++++-- .../ReleaseNotesBuilderIntegrationTests.cs | 4 +- .../ReleaseNotesBuilderTests.cs | 27 +++++-- .../ReleaseNotesExporterTests.cs | 11 ++- 4 files changed, 94 insertions(+), 22 deletions(-) diff --git a/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs b/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs index 7e73fb75..d858059a 100644 --- a/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs +++ b/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs @@ -1,30 +1,53 @@ using System; using System.Collections; +using System.Collections.Generic; +using System.Threading.Tasks; +using AutoMapper; using GitReleaseManager.Core.Provider; +using NSubstitute; using NUnit.Framework; +using Octokit; using Shouldly; +using Issue = GitReleaseManager.Core.Model.Issue; +using ItemStateFilter = GitReleaseManager.Core.Model.ItemStateFilter; namespace GitReleaseManager.Core.Tests.Provider { [TestFixture] public class GitHubProviderTests { - [TestCase("0.1.0", null, "https://github.com/owner/repo/commits/0.1.0")] - [TestCase("0.5.0", "0.1.0", "https://github.com/owner/repo/compare/0.1.0...0.5.0")] - public void Should_Get_A_Commits_Url(string milestoneTitle, string compareMilestoneTitle, string expectedResult) + private readonly string _owner = "owner"; + private readonly string _repository = "repository"; + private readonly int _milestoneNumber = 1; + private readonly string _milestoneNumberString = "1"; + private readonly Octokit.ApiValidationException _apiValidationException = new Octokit.ApiValidationException(); + + + private IMapper _mapper; + private IGitHubClient _gitHubClient; + private GitHubProvider _gitHubProvider; + + [SetUp] + public void Setup() { - var gitHubProvider = new GitHubProvider(); + _mapper = Substitute.For(); + _gitHubClient = Substitute.For(); + _gitHubProvider = new GitHubProvider(_gitHubClient, _mapper); + } - var result = gitHubProvider.GetCommitsUrl("owner", "repo", milestoneTitle, compareMilestoneTitle); + // Commits + [TestCase("0.1.0", null, "https://github.com/owner/repository/commits/0.1.0")] + [TestCase("0.5.0", "0.1.0", "https://github.com/owner/repository/compare/0.1.0...0.5.0")] + public void Should_Get_A_Commits_Url(string milestoneTitle, string compareMilestoneTitle, string expectedResult) + { + var result = _gitHubProvider.GetCommitsUrl(_owner, _repository, milestoneTitle, compareMilestoneTitle); result.ShouldBe(expectedResult); } [TestCaseSource(nameof(GetCommitsUrl_TestCases))] public void Should_Throw_An_Exception_If_Parameter_Is_Invalid(string owner, string repository, string milestoneTitle, string paramName, Type expectedException) { - var gitHubProvider = new GitHubProvider(); - - var ex = Should.Throw(() => gitHubProvider.GetCommitsUrl(owner, repository, milestoneTitle), expectedException); + var ex = Should.Throw(() => _gitHubProvider.GetCommitsUrl(owner, repository, milestoneTitle), expectedException); ex.Message.ShouldContain(paramName); } @@ -42,5 +65,40 @@ public static IEnumerable GetCommitsUrl_TestCases() yield return new TestCaseData("owner", "repository", "", "milestoneTitle", typeof(ArgumentException)); yield return new TestCaseData("owner", "repository", " ", "milestoneTitle", typeof(ArgumentException)); } + + // Issues + [TestCase(ItemStateFilter.Open)] + [TestCase(ItemStateFilter.Closed)] + [TestCase(ItemStateFilter.All)] + public async Task Should_Get_Issues_For_A_Milestone(ItemStateFilter itemStateFilter) + { + var issues = new List(); + + _gitHubClient.Issue.GetAllForRepository(_owner, _repository, Arg.Any()) + .Returns(Task.FromResult((IReadOnlyList)new List())); + + _mapper.Map>(Arg.Any()) + .Returns(issues); + + var result = await _gitHubProvider.GetIssuesAsync(_owner, _repository, _milestoneNumber, itemStateFilter).ConfigureAwait(false); + result.ShouldBeSameAs(issues); + + await _gitHubClient.Issue.Received(1).GetAllForRepository(_owner, _repository, Arg.Is(o => + o.Milestone == _milestoneNumberString && + o.State == (Octokit.ItemStateFilter)itemStateFilter)).ConfigureAwait(false); + + _mapper.ReceivedWithAnyArgs(1).Map>(default); + } + + [Test] + public async Task Should_Throw_An_Exception_On_Getting_Issues_For_Non_Existing_Milestone() + { + _gitHubClient.Issue.GetAllForRepository(_owner, _repository, Arg.Any()) + .Returns(Task.FromException>(_apiValidationException)); + + var ex = await Should.ThrowAsync(() => _gitHubProvider.GetIssuesAsync(_owner, _repository, 1)).ConfigureAwait(false); + ex.Message.ShouldBe(_apiValidationException.Message); + ex.InnerException.ShouldBe(_apiValidationException); + } } } \ No newline at end of file diff --git a/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs b/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs index 369cb122..d26244c2 100644 --- a/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs +++ b/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs @@ -68,7 +68,7 @@ public async Task SingleMilestone() var currentDirectory = Environment.CurrentDirectory; var configuration = ConfigurationProvider.Provide(currentDirectory, fileSystem); - var vcsProvider = new GitHubProvider(); + var vcsProvider = new GitHubProvider(_gitHubClient, _mapper); var vcsService = new VcsService(vcsProvider, _gitHubClient, _logger, _mapper, configuration); var releaseNotesBuilder = new ReleaseNotesBuilder(vcsService, vcsProvider, _logger, "Chocolatey", "ChocolateyGUI", "0.12.4", configuration); var result = await releaseNotesBuilder.BuildReleaseNotes().ConfigureAwait(false); @@ -91,7 +91,7 @@ public async Task SingleMilestone3() var currentDirectory = Environment.CurrentDirectory; var configuration = ConfigurationProvider.Provide(currentDirectory, fileSystem); - var vcsProvider = new GitHubProvider(); + var vcsProvider = new GitHubProvider(_gitHubClient, _mapper); var vcsService = new VcsService(vcsProvider, _gitHubClient, _logger, _mapper, configuration); var releaseNotesBuilder = new ReleaseNotesBuilder(vcsService, vcsProvider, _logger, "Chocolatey", "ChocolateyGUI", "0.13.0", configuration); var result = await releaseNotesBuilder.BuildReleaseNotes().ConfigureAwait(false); diff --git a/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs b/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs index 66774ea7..15e47aa0 100644 --- a/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs +++ b/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs @@ -4,6 +4,9 @@ // //----------------------------------------------------------------------- +using System.Collections.Generic; +using System.Threading.Tasks; + namespace GitReleaseManager.Tests { using System; @@ -148,23 +151,34 @@ private static void AcceptTest(int commits, params Issue[] issues) private static void AcceptTest(int commits, Config config, params Issue[] issues) { - var fakeClient = new FakeGitHubClient(); + var owner = "TestUser"; + var repository = "FakeRepository"; + var milestoneNumber = 1; + var milestoneTitle = "1.2.3"; + + var vcsService = new VcsServiceMock(); var logger = Substitute.For(); var fileSystem = new FileSystem(); var currentDirectory = Environment.CurrentDirectory; var configuration = config ?? ConfigurationProvider.Provide(currentDirectory, fileSystem); - fakeClient.Milestones.Add(CreateMilestone("1.2.3")); + vcsService.Milestones.Add(CreateMilestone(milestoneTitle)); - fakeClient.NumberOfCommits = commits; + vcsService.NumberOfCommits = commits; foreach (var issue in issues) { - fakeClient.Issues.Add(issue); + vcsService.Issues.Add(issue); } - var vcsProvider = new GitHubProvider(); - var builder = new ReleaseNotesBuilder(fakeClient, vcsProvider, logger, "TestUser", "FakeRepository", "1.2.3", configuration); + var vcsProvider = Substitute.For(); + vcsProvider.GetCommitsUrl(owner, repository, Arg.Any(), Arg.Any()) + .Returns(o => new GitHubProvider(null, null).GetCommitsUrl((string)o[0], (string)o[1], (string)o[2], (string)o[3])); + + vcsProvider.GetIssuesAsync(owner, repository, milestoneNumber, ItemStateFilter.Closed) + .Returns(Task.FromResult((IEnumerable)issues)); + + var builder = new ReleaseNotesBuilder(vcsService, vcsProvider, logger, owner, repository, milestoneTitle, configuration); var notes = builder.BuildReleaseNotes().Result; Approvals.Verify(notes); @@ -175,6 +189,7 @@ private static Milestone CreateMilestone(string version) return new Milestone { Title = version, + Number = 1, HtmlUrl = "https://github.com/gep13/FakeRepository/issues?q=milestone%3A" + version, Version = new Version(version), }; diff --git a/Source/GitReleaseManager.Tests/ReleaseNotesExporterTests.cs b/Source/GitReleaseManager.Tests/ReleaseNotesExporterTests.cs index 5c05c427..017366ff 100644 --- a/Source/GitReleaseManager.Tests/ReleaseNotesExporterTests.cs +++ b/Source/GitReleaseManager.Tests/ReleaseNotesExporterTests.cs @@ -4,9 +4,6 @@ // //----------------------------------------------------------------------- -using NSubstitute; -using Serilog; - namespace GitReleaseManager.Tests { using System; @@ -16,7 +13,9 @@ namespace GitReleaseManager.Tests using GitReleaseManager.Core.Configuration; using GitReleaseManager.Core.Helpers; using GitReleaseManager.Core.Model; + using NSubstitute; using NUnit.Framework; + using Serilog; [TestFixture] public class ReleaseNotesExporterTests @@ -62,15 +61,15 @@ public void SingleReleaseExcludeRegexRemoval() private static void AcceptTest(Config configuration, params Release[] releases) { - var fakeClient = new FakeGitHubClient(); + var vcsService = new VcsServiceMock(); var logger = Substitute.For(); foreach (var release in releases) { - fakeClient.Releases.Add(release); + vcsService.Releases.Add(release); } - var builder = new ReleaseNotesExporter(fakeClient, logger, configuration, "bob", "repo"); + var builder = new ReleaseNotesExporter(vcsService, logger, configuration, "bob", "repo"); var notes = builder.ExportReleaseNotes(null).Result; Approvals.Verify(notes); From 03a5b8a9ae5572b0842d90b7bda7d97a7b4c7196 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 6 Aug 2020 16:42:35 +0200 Subject: [PATCH 055/181] (GH-181) Extract method from VcsService to VcsProvider --- .../GitReleaseManager.Tests/VcsServiceMock.cs | 27 -------- Source/GitReleaseManager/IVcsService.cs | 5 -- .../Provider/GitHubProvider.cs | 48 ++++++++++++-- .../Provider/IVcsProvider.cs | 6 +- .../GitReleaseManager/ReleaseNotesBuilder.cs | 20 ++++-- Source/GitReleaseManager/VcsService.cs | 64 +------------------ 6 files changed, 61 insertions(+), 109 deletions(-) diff --git a/Source/GitReleaseManager.Tests/VcsServiceMock.cs b/Source/GitReleaseManager.Tests/VcsServiceMock.cs index b00f36fb..a71a02ba 100644 --- a/Source/GitReleaseManager.Tests/VcsServiceMock.cs +++ b/Source/GitReleaseManager.Tests/VcsServiceMock.cs @@ -7,8 +7,6 @@ namespace GitReleaseManager.Tests { using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Globalization; using System.Threading.Tasks; using GitReleaseManager.Core.Model; using IVcsService = GitReleaseManager.Core.IVcsService; @@ -33,11 +31,6 @@ public VcsServiceMock() public int NumberOfCommits { get; set; } - public Task GetNumberOfCommitsBetween(Milestone previousMilestone, Milestone currentMilestone, string user, string repository) - { - return Task.FromResult(NumberOfCommits); - } - public Task> GetReleasesAsync(string user, string repository) { return Task.FromResult(Releases); @@ -48,26 +41,6 @@ public Task GetSpecificRelease(string tagName, string user, string repo return Task.FromResult(Release); } - public Task> GetReadOnlyMilestonesAsync(string user, string repository) - { - return Task.FromResult(new ReadOnlyCollection(Milestones)); - } - - public string GetCommitsLink(string user, string repository, Milestone milestone, Milestone previousMilestone) - { - if (milestone is null) - { - throw new System.ArgumentNullException(nameof(milestone)); - } - - if (previousMilestone is null) - { - return string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/commits/{2}", user, repository, milestone.Title); - } - - return string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/compare/{2}...{3}", user, repository, previousMilestone.Title, milestone.Title); - } - public Task CreateReleaseFromMilestone(string owner, string repository, string milestone, string releaseName, string targetCommitish, IList assets, bool prerelease) { throw new System.NotImplementedException(); diff --git a/Source/GitReleaseManager/IVcsService.cs b/Source/GitReleaseManager/IVcsService.cs index 736c59c5..16986cc2 100644 --- a/Source/GitReleaseManager/IVcsService.cs +++ b/Source/GitReleaseManager/IVcsService.cs @@ -7,20 +7,15 @@ namespace GitReleaseManager.Core { using System.Collections.Generic; - using System.Collections.ObjectModel; using System.Threading.Tasks; using GitReleaseManager.Core.Model; public interface IVcsService { - Task GetNumberOfCommitsBetween(Milestone previousMilestone, Milestone currentMilestone, string user, string repository); - Task> GetReleasesAsync(string user, string repository); Task GetSpecificRelease(string tagName, string user, string repository); - Task> GetReadOnlyMilestonesAsync(string user, string repository); - Task CreateReleaseFromMilestone(string owner, string repository, string milestone, string releaseName, string targetCommitish, IList assets, bool prerelease); Task CreateReleaseFromInputFile(string owner, string repository, string name, string inputFilePath, string targetCommitish, IList assets, bool prerelease); diff --git a/Source/GitReleaseManager/Provider/GitHubProvider.cs b/Source/GitReleaseManager/Provider/GitHubProvider.cs index 51830991..9f023e51 100644 --- a/Source/GitReleaseManager/Provider/GitHubProvider.cs +++ b/Source/GitReleaseManager/Provider/GitHubProvider.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Globalization; using System.Threading.Tasks; @@ -5,6 +6,7 @@ using Octokit; using Issue = GitReleaseManager.Core.Model.Issue; using ItemStateFilter = GitReleaseManager.Core.Model.ItemStateFilter; +using Milestone = GitReleaseManager.Core.Model.Milestone; namespace GitReleaseManager.Core.Provider { @@ -19,21 +21,40 @@ public GitHubProvider(IGitHubClient gitHubClient, IMapper mapper) _mapper = mapper; } - public string GetCommitsUrl(string owner, string repository, string milestoneTitle, string compareMilestoneTitle = null) + public async Task GetCommitsCount(string owner, string repository, string @base, string head) + { + try + { + var result = await _gitHubClient.Repository.Commit.Compare(owner, repository, @base, head).ConfigureAwait(false); + return result.AheadBy; + } + catch (NotFoundException) + { + // If there is no tag yet the Compare will return a NotFoundException + // we can safely ignore + return 0; + } + catch (Exception ex) + { + throw new ApiException(ex.Message, ex); + } + } + + public string GetCommitsUrl(string owner, string repository, string head, string @base = null) { Ensure.IsNotNullOrWhiteSpace(owner, nameof(owner)); Ensure.IsNotNullOrWhiteSpace(repository, nameof(repository)); - Ensure.IsNotNullOrWhiteSpace(milestoneTitle, nameof(milestoneTitle)); + Ensure.IsNotNullOrWhiteSpace(head, nameof(head)); string url; - if (string.IsNullOrWhiteSpace(compareMilestoneTitle)) + if (string.IsNullOrWhiteSpace(@base)) { - url = string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/commits/{2}", owner, repository, milestoneTitle); + url = string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/commits/{2}", owner, repository, head); } else { - url = string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/compare/{2}...{3}", owner, repository, compareMilestoneTitle, milestoneTitle); + url = string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/compare/{2}...{3}", owner, repository, @base, head); } return url; @@ -53,7 +74,22 @@ public async Task> GetIssuesAsync(string owner, string reposi return _mapper.Map>(issues); } - catch (ApiValidationException ex) + catch (Exception ex) + { + throw new ApiException(ex.Message, ex); + } + } + + public async Task> GetMilestonesAsync(string owner, string repository, ItemStateFilter itemStateFilter = ItemStateFilter.All) + { + try + { + var request = new MilestoneRequest { State = (Octokit.ItemStateFilter)itemStateFilter }; + var milestones = await _gitHubClient.Issue.Milestone.GetAllForRepository(owner, repository, request).ConfigureAwait(false); + + return _mapper.Map>(milestones); + } + catch (Exception ex) { throw new ApiException(ex.Message, ex); } diff --git a/Source/GitReleaseManager/Provider/IVcsProvider.cs b/Source/GitReleaseManager/Provider/IVcsProvider.cs index 7ad5c2a7..19bb30ed 100644 --- a/Source/GitReleaseManager/Provider/IVcsProvider.cs +++ b/Source/GitReleaseManager/Provider/IVcsProvider.cs @@ -6,8 +6,12 @@ namespace GitReleaseManager.Core.Provider { public interface IVcsProvider { - string GetCommitsUrl(string owner, string repository, string milestoneTitle, string compareMilestoneTitle = null); + Task GetCommitsCount(string owner, string repository, string @base, string head); + + string GetCommitsUrl(string owner, string repository, string head, string @base = null); Task> GetIssuesAsync(string owner, string repository, int milestoneNumber, ItemStateFilter itemStateFilter = ItemStateFilter.All); + + Task> GetMilestonesAsync(string owner, string repository, ItemStateFilter itemStateFilter = ItemStateFilter.All); } } \ No newline at end of file diff --git a/Source/GitReleaseManager/ReleaseNotesBuilder.cs b/Source/GitReleaseManager/ReleaseNotesBuilder.cs index a87516df..4a8b5fe2 100644 --- a/Source/GitReleaseManager/ReleaseNotesBuilder.cs +++ b/Source/GitReleaseManager/ReleaseNotesBuilder.cs @@ -8,7 +8,6 @@ namespace GitReleaseManager.Core { using System; using System.Collections.Generic; - using System.Collections.ObjectModel; using System.Globalization; using System.Linq; using System.Text; @@ -21,19 +20,17 @@ namespace GitReleaseManager.Core public class ReleaseNotesBuilder { - private readonly IVcsService _vcsService; private readonly IVcsProvider _vcsProvider; private readonly ILogger _logger; private readonly string _user; private readonly string _repository; private readonly string _milestoneTitle; private readonly Config _configuration; - private ReadOnlyCollection _milestones; + private IEnumerable _milestones; private Milestone _targetMilestone; - public ReleaseNotesBuilder(IVcsService vcsService, IVcsProvider vcsProvider, ILogger logger, string user, string repository, string milestoneTitle, Config configuration) + public ReleaseNotesBuilder(IVcsProvider vcsProvider, ILogger logger, string user, string repository, string milestoneTitle, Config configuration) { - _vcsService = vcsService; _vcsProvider = vcsProvider; _logger = logger; _user = user; @@ -51,7 +48,16 @@ public async Task BuildReleaseNotes() var issues = await GetIssues(_targetMilestone).ConfigureAwait(false); var stringBuilder = new StringBuilder(); var previousMilestone = GetPreviousMilestone(); - var numberOfCommits = await _vcsService.GetNumberOfCommitsBetween(previousMilestone, _targetMilestone, _user, _repository).ConfigureAwait(false); + + var @base = previousMilestone != null + ? previousMilestone.Title + : _configuration.DefaultBranch; + + var head = _targetMilestone.Title; + + _logger.Verbose("Getting commit count between base '{Base}' and head '{Head}'", @base, head); + + var numberOfCommits = await _vcsProvider.GetCommitsCount(_user, _repository, @base, head).ConfigureAwait(false); if (issues.Count == 0) { @@ -196,7 +202,7 @@ private void AddFooter(StringBuilder stringBuilder) private async Task LoadMilestones() { - _milestones = await _vcsService.GetReadOnlyMilestonesAsync(_user, _repository).ConfigureAwait(false); + _milestones = await _vcsProvider.GetMilestonesAsync(_user, _repository).ConfigureAwait(false); } private async Task> GetIssues(Milestone milestone) diff --git a/Source/GitReleaseManager/VcsService.cs b/Source/GitReleaseManager/VcsService.cs index 23bd1cf4..97fe1bb0 100644 --- a/Source/GitReleaseManager/VcsService.cs +++ b/Source/GitReleaseManager/VcsService.cs @@ -8,7 +8,6 @@ namespace GitReleaseManager.Core { using System; using System.Collections.Generic; - using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Security.Cryptography; @@ -22,7 +21,6 @@ namespace GitReleaseManager.Core using GitReleaseManager.Core.Provider; using Octokit; using Serilog; - using Milestone = GitReleaseManager.Core.Model.Milestone; using Release = GitReleaseManager.Core.Model.Release; public class VcsService : IVcsService @@ -42,16 +40,6 @@ public VcsService(IVcsProvider vcsProvider, IGitHubClient gitHubClient, ILogger _configuration = configuration; } - public Task GetNumberOfCommitsBetween(Milestone previousMilestone, Milestone currentMilestone, string user, string repository) - { - if (currentMilestone is null) - { - throw new ArgumentNullException(nameof(currentMilestone)); - } - - return GetNumberOfCommitsBetweenInternal(previousMilestone, currentMilestone, user, repository); - } - public async Task> GetReleasesAsync(string user, string repository) { _logger.Verbose("Finding all releases on '{User}/{Repository}'", user, repository); @@ -64,35 +52,10 @@ public async Task GetSpecificRelease(string tagName, string user, strin return _mapper.Map(await GetReleaseFromTagNameAsync(user, repository, tagName).ConfigureAwait(false)); } - public async Task> GetReadOnlyMilestonesAsync(string user, string repository) - { - var milestonesClient = _gitHubClient.Issue.Milestone; - - _logger.Verbose("Finding all closed milestones on '{User}/{Repository}'", user, repository); - var closed = await milestonesClient.GetAllForRepository( - user, - repository, - new MilestoneRequest - { - State = ItemStateFilter.Closed, - }).ConfigureAwait(false); - - _logger.Verbose("Finding all open milestones on '{User}/{Repository}'", user, repository); - var open = await milestonesClient.GetAllForRepository( - user, - repository, - new MilestoneRequest - { - State = ItemStateFilter.Open, - }).ConfigureAwait(false); - - return new ReadOnlyCollection(_mapper.Map>(closed.Concat(open).ToList())); - } - public async Task CreateReleaseFromMilestone(string owner, string repository, string milestone, string releaseName, string targetCommitish, IList assets, bool prerelease) { var release = await GetReleaseFromTagNameAsync(owner, repository, milestone).ConfigureAwait(false); - var releaseNotesBuilder = new ReleaseNotesBuilder(this, _vcsProvider, _logger, owner, repository, milestone, _configuration); + var releaseNotesBuilder = new ReleaseNotesBuilder(_vcsProvider, _logger, owner, repository, milestone, _configuration); var result = await releaseNotesBuilder.BuildReleaseNotes().ConfigureAwait(false); if (release == null) @@ -439,31 +402,6 @@ private async Task CreateReleaseFromInputFileInternal(string owner, str }); } - private async Task GetNumberOfCommitsBetweenInternal(Milestone previousMilestone, Milestone currentMilestone, string user, string repository) - { - try - { - if (previousMilestone == null) - { - _logger.Verbose("Getting commit count between base '{Base}' and head '{Head}'", _configuration.DefaultBranch, currentMilestone.Title); - var gitHubClientRepositoryCommitsCompare = await _gitHubClient.Repository.Commit.Compare(user, repository, _configuration.DefaultBranch, currentMilestone.Title).ConfigureAwait(false); - return gitHubClientRepositoryCommitsCompare.AheadBy; - } - - _logger.Verbose("Getting commit count between base '{Base}' and head '{Head}'", previousMilestone.Title, _configuration.DefaultBranch); - var compareResult = await _gitHubClient.Repository.Commit.Compare(user, repository, previousMilestone.Title, _configuration.DefaultBranch).ConfigureAwait(false); - return compareResult.AheadBy; - } - catch (NotFoundException) - { - _logger.Warning("Unable to find tag for milestone, so commit count will be returned as zero"); - - // If there is no tag yet the Compare will return a NotFoundException - // we can safely ignore - return 0; - } - } - private async Task GetReleaseFromTagNameAsync(string owner, string repository, string tagName) { _logger.Verbose("Finding release with tag name: '{TagName}'", tagName); From 27b04318bb6a010486252808d569a54435bcbaf7 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 6 Aug 2020 16:43:44 +0200 Subject: [PATCH 056/181] (GH-181) Update and add unit tests --- .../Provider/GitHubProviderTests.cs | 114 +++++++++++++++--- .../ReleaseNotesBuilderIntegrationTests.cs | 6 +- .../ReleaseNotesBuilderTests.cs | 10 +- 3 files changed, 106 insertions(+), 24 deletions(-) diff --git a/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs b/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs index d858059a..a4d984a1 100644 --- a/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs +++ b/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Net; using System.Threading.Tasks; using AutoMapper; using GitReleaseManager.Core.Provider; @@ -10,6 +11,7 @@ using Shouldly; using Issue = GitReleaseManager.Core.Model.Issue; using ItemStateFilter = GitReleaseManager.Core.Model.ItemStateFilter; +using Milestone = GitReleaseManager.Core.Model.Milestone; namespace GitReleaseManager.Core.Tests.Provider { @@ -18,10 +20,12 @@ public class GitHubProviderTests { private readonly string _owner = "owner"; private readonly string _repository = "repository"; + private readonly string _base = "0.1.0"; + private readonly string _head = "0.5.0"; private readonly int _milestoneNumber = 1; private readonly string _milestoneNumberString = "1"; - private readonly Octokit.ApiValidationException _apiValidationException = new Octokit.ApiValidationException(); - + private readonly Exception _exception = new Exception("API Error"); + private readonly Octokit.NotFoundException _notFoundException = new Octokit.NotFoundException("NotFound", HttpStatusCode.NotFound); private IMapper _mapper; private IGitHubClient _gitHubClient; @@ -36,34 +40,74 @@ public void Setup() } // Commits + [Test] + public async Task Should_Get_Commits_Count() + { + var commitsCount = 12; + + _gitHubClient.Repository.Commit.Compare(_owner, _repository, _base, _head) + .Returns(Task.FromResult(new CompareResult(null, null, null, null, null, null, null, null, commitsCount, 0, 0, null, null))); + + var result = await _gitHubProvider.GetCommitsCount(_owner, _repository, _base, _head).ConfigureAwait(false); + result.ShouldBe(commitsCount); + + await _gitHubClient.Repository.Commit.Received(1).Compare(_owner, _repository, _base, _head).ConfigureAwait(false); + } + + [Test] + public async Task Should_Get_Commits_Count_Zero_If_No_Commits_Found() + { + _gitHubClient.Repository.Commit.Compare(_owner, _repository, _base, _head) + .Returns(Task.FromException(_notFoundException)); + + var result = await _gitHubProvider.GetCommitsCount(_owner, _repository, _base, _head).ConfigureAwait(false); + result.ShouldBe(0); + + await _gitHubClient.Repository.Commit.Received(1).Compare(_owner, _repository, _base, _head).ConfigureAwait(false); + } + + [Test] + public async Task Should_Throw_An_Exception_On_Getting_Commits_Count() + { + _gitHubClient.Repository.Commit.Compare(_owner, _repository, _base, _head) + .Returns(Task.FromException(_exception)); + + var ex = await Should.ThrowAsync(() => _gitHubProvider.GetCommitsCount(_owner, _repository, _base, _head)).ConfigureAwait(false); + ex.Message.ShouldContain(_exception.Message); + ex.InnerException.ShouldBeSameAs(_exception); + } + [TestCase("0.1.0", null, "https://github.com/owner/repository/commits/0.1.0")] [TestCase("0.5.0", "0.1.0", "https://github.com/owner/repository/compare/0.1.0...0.5.0")] - public void Should_Get_A_Commits_Url(string milestoneTitle, string compareMilestoneTitle, string expectedResult) + public void Should_Get_A_Commits_Url(string head, string @base, string expectedResult) { - var result = _gitHubProvider.GetCommitsUrl(_owner, _repository, milestoneTitle, compareMilestoneTitle); + var result = _gitHubProvider.GetCommitsUrl(_owner, _repository, head, @base); result.ShouldBe(expectedResult); } [TestCaseSource(nameof(GetCommitsUrl_TestCases))] - public void Should_Throw_An_Exception_If_Parameter_Is_Invalid(string owner, string repository, string milestoneTitle, string paramName, Type expectedException) + public void Should_Throw_An_Exception_If_Parameter_Is_Invalid(string owner, string repository, string head, string paramName, Type expectedException) { - var ex = Should.Throw(() => _gitHubProvider.GetCommitsUrl(owner, repository, milestoneTitle), expectedException); + var ex = Should.Throw(() => _gitHubProvider.GetCommitsUrl(owner, repository, head), expectedException); ex.Message.ShouldContain(paramName); } public static IEnumerable GetCommitsUrl_TestCases() { - yield return new TestCaseData(null, null, null, "owner", typeof(ArgumentNullException)); - yield return new TestCaseData("", null, null, "owner", typeof(ArgumentException)); - yield return new TestCaseData(" ", null, null, "owner", typeof(ArgumentException)); + var typeArgumentException = typeof(ArgumentException); + var typeArgumentNullException = typeof(ArgumentNullException); + + yield return new TestCaseData(null, null, null, "owner", typeArgumentNullException); + yield return new TestCaseData("", null, null, "owner", typeArgumentException); + yield return new TestCaseData(" ", null, null, "owner", typeArgumentException); - yield return new TestCaseData("owner", null, null, "repository", typeof(ArgumentNullException)); - yield return new TestCaseData("owner", "", null, "repository", typeof(ArgumentException)); - yield return new TestCaseData("owner", " ", null, "repository", typeof(ArgumentException)); + yield return new TestCaseData("owner", null, null, "repository", typeArgumentNullException); + yield return new TestCaseData("owner", "", null, "repository", typeArgumentException); + yield return new TestCaseData("owner", " ", null, "repository", typeArgumentException); - yield return new TestCaseData("owner", "repository", null, "milestoneTitle", typeof(ArgumentNullException)); - yield return new TestCaseData("owner", "repository", "", "milestoneTitle", typeof(ArgumentException)); - yield return new TestCaseData("owner", "repository", " ", "milestoneTitle", typeof(ArgumentException)); + yield return new TestCaseData("owner", "repository", null, "head", typeArgumentNullException); + yield return new TestCaseData("owner", "repository", "", "head", typeArgumentException); + yield return new TestCaseData("owner", "repository", " ", "head", typeArgumentException); } // Issues @@ -94,11 +138,45 @@ await _gitHubClient.Issue.Received(1).GetAllForRepository(_owner, _repository, A public async Task Should_Throw_An_Exception_On_Getting_Issues_For_Non_Existing_Milestone() { _gitHubClient.Issue.GetAllForRepository(_owner, _repository, Arg.Any()) - .Returns(Task.FromException>(_apiValidationException)); + .Returns(Task.FromException>(_exception)); var ex = await Should.ThrowAsync(() => _gitHubProvider.GetIssuesAsync(_owner, _repository, 1)).ConfigureAwait(false); - ex.Message.ShouldBe(_apiValidationException.Message); - ex.InnerException.ShouldBe(_apiValidationException); + ex.Message.ShouldBe(_exception.Message); + ex.InnerException.ShouldBe(_exception); + } + + // Milestones + [TestCase(ItemStateFilter.Open)] + [TestCase(ItemStateFilter.Closed)] + [TestCase(ItemStateFilter.All)] + public async Task Should_Get_Milestone(ItemStateFilter itemStateFilter) + { + var milestones = new List(); + + _gitHubClient.Issue.Milestone.GetAllForRepository(_owner, _repository, Arg.Any()) + .Returns(Task.FromResult((IReadOnlyList)new List())); + + _mapper.Map>(Arg.Any()) + .Returns(milestones); + + var result = await _gitHubProvider.GetMilestonesAsync(_owner, _repository, itemStateFilter).ConfigureAwait(false); + result.ShouldBeSameAs(milestones); + + await _gitHubClient.Issue.Milestone.Received(1).GetAllForRepository(_owner, _repository, Arg.Is(o => + o.State == (Octokit.ItemStateFilter)itemStateFilter)).ConfigureAwait(false); + + _mapper.ReceivedWithAnyArgs(1).Map>(default); + } + + [Test] + public async Task Should_Throw_An_Exception_On_Getting_Milestone() + { + _gitHubClient.Issue.Milestone.GetAllForRepository(_owner, _repository, Arg.Any()) + .Returns(Task.FromException>(_exception)); + + var ex = await Should.ThrowAsync(() => _gitHubProvider.GetMilestonesAsync(_owner, _repository)).ConfigureAwait(false); + ex.Message.ShouldBe(_exception.Message); + ex.InnerException.ShouldBe(_exception); } } } \ No newline at end of file diff --git a/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs b/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs index d26244c2..c39e7a66 100644 --- a/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs +++ b/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs @@ -69,8 +69,7 @@ public async Task SingleMilestone() var configuration = ConfigurationProvider.Provide(currentDirectory, fileSystem); var vcsProvider = new GitHubProvider(_gitHubClient, _mapper); - var vcsService = new VcsService(vcsProvider, _gitHubClient, _logger, _mapper, configuration); - var releaseNotesBuilder = new ReleaseNotesBuilder(vcsService, vcsProvider, _logger, "Chocolatey", "ChocolateyGUI", "0.12.4", configuration); + var releaseNotesBuilder = new ReleaseNotesBuilder(vcsProvider, _logger, "Chocolatey", "ChocolateyGUI", "0.12.4", configuration); var result = await releaseNotesBuilder.BuildReleaseNotes().ConfigureAwait(false); Debug.WriteLine(result); ClipBoardHelper.SetClipboard(result); @@ -92,8 +91,7 @@ public async Task SingleMilestone3() var configuration = ConfigurationProvider.Provide(currentDirectory, fileSystem); var vcsProvider = new GitHubProvider(_gitHubClient, _mapper); - var vcsService = new VcsService(vcsProvider, _gitHubClient, _logger, _mapper, configuration); - var releaseNotesBuilder = new ReleaseNotesBuilder(vcsService, vcsProvider, _logger, "Chocolatey", "ChocolateyGUI", "0.13.0", configuration); + var releaseNotesBuilder = new ReleaseNotesBuilder(vcsProvider, _logger, "Chocolatey", "ChocolateyGUI", "0.13.0", configuration); var result = await releaseNotesBuilder.BuildReleaseNotes().ConfigureAwait(false); Debug.WriteLine(result); ClipBoardHelper.SetClipboard(result); diff --git a/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs b/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs index 15e47aa0..10977d33 100644 --- a/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs +++ b/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs @@ -172,13 +172,19 @@ private static void AcceptTest(int commits, Config config, params Issue[] issues } var vcsProvider = Substitute.For(); + vcsProvider.GetCommitsCount(owner, repository, Arg.Any(), Arg.Any()) + .Returns(Task.FromResult(vcsService.NumberOfCommits)); + vcsProvider.GetCommitsUrl(owner, repository, Arg.Any(), Arg.Any()) .Returns(o => new GitHubProvider(null, null).GetCommitsUrl((string)o[0], (string)o[1], (string)o[2], (string)o[3])); vcsProvider.GetIssuesAsync(owner, repository, milestoneNumber, ItemStateFilter.Closed) - .Returns(Task.FromResult((IEnumerable)issues)); + .Returns(Task.FromResult((IEnumerable)vcsService.Issues)); + + vcsProvider.GetMilestonesAsync(owner, repository, Arg.Any()) + .Returns(Task.FromResult((IEnumerable)vcsService.Milestones)); - var builder = new ReleaseNotesBuilder(vcsService, vcsProvider, logger, owner, repository, milestoneTitle, configuration); + var builder = new ReleaseNotesBuilder(vcsProvider, logger, owner, repository, milestoneTitle, configuration); var notes = builder.BuildReleaseNotes().Result; Approvals.Verify(notes); From fe67d2787b53c4ace56df3b67e5cf0b50a20f585 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 6 Aug 2020 18:06:35 +0200 Subject: [PATCH 057/181] (GH-181) Update ReleaseNotesBuilderIntegrationTests --- .../ReleaseNotesBuilderIntegrationTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs b/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs index c39e7a66..880d4ab6 100644 --- a/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs +++ b/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs @@ -19,6 +19,7 @@ namespace GitReleaseManager.IntegrationTests using Serilog; [TestFixture] + [Explicit] public class ReleaseNotesBuilderIntegrationTests { private IGitHubClient _gitHubClient; From cd2d8f36b2d07b8cc6a6466f745d914531705f30 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 6 Aug 2020 18:14:29 +0200 Subject: [PATCH 058/181] (GH-181) Remove duplication in ReleaseNotesBuilder --- Source/GitReleaseManager/ReleaseNotesBuilder.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Source/GitReleaseManager/ReleaseNotesBuilder.cs b/Source/GitReleaseManager/ReleaseNotesBuilder.cs index 4a8b5fe2..28596493 100644 --- a/Source/GitReleaseManager/ReleaseNotesBuilder.cs +++ b/Source/GitReleaseManager/ReleaseNotesBuilder.cs @@ -65,15 +65,15 @@ public async Task BuildReleaseNotes() throw new InvalidOperationException(logMessage); } + var commitsLink = _vcsProvider.GetCommitsUrl(_user, _repository, _targetMilestone?.Title, previousMilestone?.Title); + var commitsText = string.Format(numberOfCommits == 1 ? "{0} commit" : "{0} commits", numberOfCommits); + if (issues.Count > 0) { var issuesText = string.Format(issues.Count == 1 ? "{0} issue" : "{0} issues", issues.Count); if (numberOfCommits > 0) { - var commitsLink = _vcsProvider.GetCommitsUrl(_user, _repository, _targetMilestone?.Title, previousMilestone?.Title); - 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 + "?closed=1"); } else @@ -83,8 +83,6 @@ public async Task BuildReleaseNotes() } else if (numberOfCommits > 0) { - var commitsLink = _vcsProvider.GetCommitsUrl(_user, _repository, _targetMilestone?.Title, previousMilestone?.Title); - var commitsText = string.Format(numberOfCommits == 1 ? "{0} commit" : "{0} commits", numberOfCommits); stringBuilder.AppendFormat(@"As part of this release we had [{0}]({1}).", commitsText, commitsLink); } From af0f4bd83be958bf63240a84b43dbe90a3806bd8 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 6 Aug 2020 20:33:55 +0200 Subject: [PATCH 059/181] (GH-181) Refactor ReleaseNotesExporter --- .../GitReleaseManager.Tests/VcsServiceMock.cs | 10 ---- .../Exceptions/NotFoundException.cs | 28 +++++++++++ Source/GitReleaseManager/IVcsService.cs | 4 -- .../Provider/GitHubProvider.cs | 38 ++++++++++++++- .../Provider/IVcsProvider.cs | 4 ++ .../GitReleaseManager/ReleaseNotesExporter.cs | 47 ++++++------------- Source/GitReleaseManager/VcsService.cs | 46 ++++++++++-------- 7 files changed, 111 insertions(+), 66 deletions(-) create mode 100644 Source/GitReleaseManager/Exceptions/NotFoundException.cs diff --git a/Source/GitReleaseManager.Tests/VcsServiceMock.cs b/Source/GitReleaseManager.Tests/VcsServiceMock.cs index a71a02ba..c771422c 100644 --- a/Source/GitReleaseManager.Tests/VcsServiceMock.cs +++ b/Source/GitReleaseManager.Tests/VcsServiceMock.cs @@ -31,16 +31,6 @@ public VcsServiceMock() public int NumberOfCommits { get; set; } - public Task> GetReleasesAsync(string user, string repository) - { - return Task.FromResult(Releases); - } - - public Task GetSpecificRelease(string tagName, string user, string repository) - { - return Task.FromResult(Release); - } - public Task CreateReleaseFromMilestone(string owner, string repository, string milestone, string releaseName, string targetCommitish, IList assets, bool prerelease) { throw new System.NotImplementedException(); diff --git a/Source/GitReleaseManager/Exceptions/NotFoundException.cs b/Source/GitReleaseManager/Exceptions/NotFoundException.cs new file mode 100644 index 00000000..cafd93eb --- /dev/null +++ b/Source/GitReleaseManager/Exceptions/NotFoundException.cs @@ -0,0 +1,28 @@ +using System; +using System.Runtime.Serialization; + +namespace GitReleaseManager.Core.Exceptions +{ + [Serializable] + public class NotFoundException : Exception + { + public NotFoundException() + { + } + + public NotFoundException(string message) + : base(message) + { + } + + public NotFoundException(string message, Exception inner) + : base(message, inner) + { + } + + protected NotFoundException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/Source/GitReleaseManager/IVcsService.cs b/Source/GitReleaseManager/IVcsService.cs index 16986cc2..152bfc92 100644 --- a/Source/GitReleaseManager/IVcsService.cs +++ b/Source/GitReleaseManager/IVcsService.cs @@ -12,10 +12,6 @@ namespace GitReleaseManager.Core public interface IVcsService { - Task> GetReleasesAsync(string user, string repository); - - Task GetSpecificRelease(string tagName, string user, string repository); - Task CreateReleaseFromMilestone(string owner, string repository, string milestone, string releaseName, string targetCommitish, IList assets, bool prerelease); Task CreateReleaseFromInputFile(string owner, string repository, string name, string inputFilePath, string targetCommitish, IList assets, bool prerelease); diff --git a/Source/GitReleaseManager/Provider/GitHubProvider.cs b/Source/GitReleaseManager/Provider/GitHubProvider.cs index 9f023e51..cdab7f71 100644 --- a/Source/GitReleaseManager/Provider/GitHubProvider.cs +++ b/Source/GitReleaseManager/Provider/GitHubProvider.cs @@ -1,12 +1,15 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Threading.Tasks; using AutoMapper; using Octokit; using Issue = GitReleaseManager.Core.Model.Issue; using ItemStateFilter = GitReleaseManager.Core.Model.ItemStateFilter; using Milestone = GitReleaseManager.Core.Model.Milestone; +using NotFoundException = GitReleaseManager.Core.Exceptions.NotFoundException; +using Release = GitReleaseManager.Core.Model.Release; namespace GitReleaseManager.Core.Provider { @@ -28,7 +31,7 @@ public async Task GetCommitsCount(string owner, string repository, string @ var result = await _gitHubClient.Repository.Commit.Compare(owner, repository, @base, head).ConfigureAwait(false); return result.AheadBy; } - catch (NotFoundException) + catch (Octokit.NotFoundException) { // If there is no tag yet the Compare will return a NotFoundException // we can safely ignore @@ -94,5 +97,38 @@ public async Task> GetMilestonesAsync(string owner, strin throw new ApiException(ex.Message, ex); } } + + public async Task GetReleaseAsync(string owner, string repository, string tagName) + { + try + { + var release = await _gitHubClient.Repository.Release.Get(owner, repository, tagName).ConfigureAwait(false); + + return _mapper.Map(release); + } + catch (Octokit.NotFoundException ex) + { + throw new NotFoundException(ex.Message, ex); + } + catch (Exception ex) + { + throw new ApiException(ex.Message, ex); + } + } + + public async Task> GetReleasesAsync(string owner, string repository) + { + try + { + var releases = await _gitHubClient.Repository.Release.GetAll(owner, repository).ConfigureAwait(false); + releases = releases.OrderByDescending(r => r.CreatedAt).ToList(); + + return _mapper.Map>(releases); + } + catch (Exception ex) + { + throw new ApiException(ex.Message, ex); + } + } } } \ No newline at end of file diff --git a/Source/GitReleaseManager/Provider/IVcsProvider.cs b/Source/GitReleaseManager/Provider/IVcsProvider.cs index 19bb30ed..211733f4 100644 --- a/Source/GitReleaseManager/Provider/IVcsProvider.cs +++ b/Source/GitReleaseManager/Provider/IVcsProvider.cs @@ -13,5 +13,9 @@ public interface IVcsProvider Task> GetIssuesAsync(string owner, string repository, int milestoneNumber, ItemStateFilter itemStateFilter = ItemStateFilter.All); Task> GetMilestonesAsync(string owner, string repository, ItemStateFilter itemStateFilter = ItemStateFilter.All); + + Task GetReleaseAsync(string owner, string repository, string tagName); + + Task> GetReleasesAsync(string owner, string repository); } } \ No newline at end of file diff --git a/Source/GitReleaseManager/ReleaseNotesExporter.cs b/Source/GitReleaseManager/ReleaseNotesExporter.cs index 7bbb4f36..e3002224 100644 --- a/Source/GitReleaseManager/ReleaseNotesExporter.cs +++ b/Source/GitReleaseManager/ReleaseNotesExporter.cs @@ -7,70 +7,53 @@ namespace GitReleaseManager.Core { using System; + using System.Collections.Generic; using System.Globalization; + using System.Linq; using System.Text; using System.Text.RegularExpressions; - using System.Threading.Tasks; using GitReleaseManager.Core.Configuration; using GitReleaseManager.Core.Model; using Serilog; public class ReleaseNotesExporter { - private readonly IVcsService _vcsService; private readonly ILogger _logger; - private readonly Config _configuration; - private readonly string _user; - private readonly string _repository; + private readonly ExportConfig _configuration; - public ReleaseNotesExporter(IVcsService vcsService, ILogger logger, Config configuration, string user, string repository) + public ReleaseNotesExporter(ILogger logger, ExportConfig configuration) { - _vcsService = vcsService; _logger = logger; _configuration = configuration; - _user = user; - _repository = repository; } - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Not appropriate.")] - public async Task ExportReleaseNotes(string tagName) + public string ExportReleaseNotes(IEnumerable releases) { _logger.Verbose("Exporting release notes"); var stringBuilder = new StringBuilder(); - if (string.IsNullOrEmpty(tagName)) + if (releases.Any()) { - var releases = await _vcsService.GetReleasesAsync(_user, _repository).ConfigureAwait(false); - - if (releases.Count > 0) - { - foreach (var release in releases) - { - AppendVersionReleaseNotes(stringBuilder, release); - } - } - else + foreach (var release in releases) { - stringBuilder.Append("Unable to find any releases for specified repository."); + AppendVersionReleaseNotes(stringBuilder, release); } + + _logger.Verbose("Finished exporting release notes"); } else { - var release = await _vcsService.GetSpecificRelease(tagName, _user, _repository).ConfigureAwait(false); - - AppendVersionReleaseNotes(stringBuilder, release); + stringBuilder.Append("Unable to find any releases for specified repository."); } - _logger.Verbose("Finished exporting release notes"); - return stringBuilder.ToString(); } private void AppendVersionReleaseNotes(StringBuilder stringBuilder, Release release) { - if (_configuration.Export.IncludeCreatedDateInTitle) + if (_configuration.IncludeCreatedDateInTitle) { - stringBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "## {0} ({1})", release.TagName, release.CreatedAt.ToString(_configuration.Export.CreatedDateStringFormat, CultureInfo.InvariantCulture))); + stringBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "## {0} ({1})", release.TagName, release.CreatedAt.ToString(_configuration.CreatedDateStringFormat, CultureInfo.InvariantCulture))); } else { @@ -79,9 +62,9 @@ private void AppendVersionReleaseNotes(StringBuilder stringBuilder, Release rele stringBuilder.AppendLine(Environment.NewLine); - if (_configuration.Export.PerformRegexRemoval) + if (_configuration.PerformRegexRemoval) { - var regexPattern = new Regex(_configuration.Export.RegexText, _configuration.Export.IsMultilineRegex ? RegexOptions.Multiline : RegexOptions.Singleline); + var regexPattern = new Regex(_configuration.RegexText, _configuration.IsMultilineRegex ? RegexOptions.Multiline : RegexOptions.Singleline); var replacement = string.Empty; var replacedBody = regexPattern.Replace(release.Body, replacement); stringBuilder.AppendLine(replacedBody); diff --git a/Source/GitReleaseManager/VcsService.cs b/Source/GitReleaseManager/VcsService.cs index 97fe1bb0..bef0eb6a 100644 --- a/Source/GitReleaseManager/VcsService.cs +++ b/Source/GitReleaseManager/VcsService.cs @@ -21,6 +21,7 @@ namespace GitReleaseManager.Core using GitReleaseManager.Core.Provider; using Octokit; using Serilog; + using NotFoundException = GitReleaseManager.Core.Exceptions.NotFoundException; using Release = GitReleaseManager.Core.Model.Release; public class VcsService : IVcsService @@ -40,18 +41,6 @@ public VcsService(IVcsProvider vcsProvider, IGitHubClient gitHubClient, ILogger _configuration = configuration; } - public async Task> GetReleasesAsync(string user, string repository) - { - _logger.Verbose("Finding all releases on '{User}/{Repository}'", user, repository); - var allReleases = await _gitHubClient.Repository.Release.GetAll(user, repository).ConfigureAwait(false); - return _mapper.Map>(allReleases.OrderByDescending(r => r.CreatedAt).ToList()); - } - - public async Task GetSpecificRelease(string tagName, string user, string repository) - { - return _mapper.Map(await GetReleaseFromTagNameAsync(user, repository, tagName).ConfigureAwait(false)); - } - public async Task CreateReleaseFromMilestone(string owner, string repository, string milestone, string releaseName, string targetCommitish, IList assets, bool prerelease) { var release = await GetReleaseFromTagNameAsync(owner, repository, milestone).ConfigureAwait(false); @@ -193,11 +182,32 @@ public async Task AddAssets(string owner, string repository, string tagName, ILi } } - public Task ExportReleases(string owner, string repository, string tagName) + public async Task ExportReleases(string owner, string repository, string tagName) { - var releaseNotesExporter = new ReleaseNotesExporter(this, _logger, _configuration, owner, repository); + var releaseNotesExporter = new ReleaseNotesExporter(_logger, _configuration.Export); + var releases = Enumerable.Empty(); + + if (string.IsNullOrWhiteSpace(tagName)) + { + _logger.Verbose("Finding all releases on '{Owner}/{Repository}'", owner, repository); + releases = await _vcsProvider.GetReleasesAsync(owner, repository).ConfigureAwait(false); + } + else + { + try + { + _logger.Verbose("Finding release with tag '{TagName}' on '{Owner}/{Repository}'", owner, repository, tagName); + var release = await _vcsProvider.GetReleaseAsync(owner, repository, tagName).ConfigureAwait(false); + releases = new List { release }; + + } + catch (NotFoundException) + { + _logger.Error("Unable to find any release with the tag '{TagName}' for specified repository.", tagName); + } + } - return releaseNotesExporter.ExportReleaseNotes(tagName); + return releaseNotesExporter.ExportReleaseNotes(releases); } public async Task CloseMilestone(string owner, string repository, string milestoneTitle) @@ -402,13 +412,11 @@ private async Task CreateReleaseFromInputFileInternal(string owner, str }); } - private async Task GetReleaseFromTagNameAsync(string owner, string repository, string tagName) + private Task GetReleaseFromTagNameAsync(string owner, string repository, string tagName) { _logger.Verbose("Finding release with tag name: '{TagName}'", tagName); - var releases = await _gitHubClient.Repository.Release.GetAll(owner, repository).ConfigureAwait(false); - var release = releases.FirstOrDefault(r => r.TagName == tagName); - return release; + return _gitHubClient.Repository.Release.Get(owner, repository, tagName); } private void SleepWhenRateIsLimited() From 5357d25c96a62afc7ad169d16049d66dfff46f49 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 6 Aug 2020 20:55:21 +0200 Subject: [PATCH 060/181] (GH-181) Update and add unit tests --- .../Provider/GitHubProviderTests.cs | 73 +++++++++++++++++++ .../ReleaseNotesExporterTests.cs | 11 +-- 2 files changed, 75 insertions(+), 9 deletions(-) diff --git a/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs b/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs index a4d984a1..977cc4f3 100644 --- a/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs +++ b/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs @@ -12,6 +12,8 @@ using Issue = GitReleaseManager.Core.Model.Issue; using ItemStateFilter = GitReleaseManager.Core.Model.ItemStateFilter; using Milestone = GitReleaseManager.Core.Model.Milestone; +using NotFoundException = GitReleaseManager.Core.Exceptions.NotFoundException; +using Release = GitReleaseManager.Core.Model.Release; namespace GitReleaseManager.Core.Tests.Provider { @@ -24,6 +26,7 @@ public class GitHubProviderTests private readonly string _head = "0.5.0"; private readonly int _milestoneNumber = 1; private readonly string _milestoneNumberString = "1"; + private readonly string _tagName = "0.1.0"; private readonly Exception _exception = new Exception("API Error"); private readonly Octokit.NotFoundException _notFoundException = new Octokit.NotFoundException("NotFound", HttpStatusCode.NotFound); @@ -178,5 +181,75 @@ public async Task Should_Throw_An_Exception_On_Getting_Milestone() ex.Message.ShouldBe(_exception.Message); ex.InnerException.ShouldBe(_exception); } + + // Releases + [Test] + public async Task Should_Get_A_Release() + { + var release = new Release(); + + _gitHubClient.Repository.Release.Get(_owner, _repository, _tagName) + .Returns(Task.FromResult(new Octokit.Release())); + + _mapper.Map(Arg.Any()) + .Returns(release); + + var result = await _gitHubProvider.GetReleaseAsync(_owner, _repository, _tagName).ConfigureAwait(false); + result.ShouldBeSameAs(release); + + await _gitHubClient.Repository.Release.Received(1).Get(_owner, _repository, _tagName).ConfigureAwait(false); + _mapper.Received(1).Map(Arg.Any()); + } + + [Test] + public async Task Should_Throw_An_Exception_On_Getting_Release_For_Non_Existing_Tag() + { + _gitHubClient.Repository.Release.Get(_owner, _repository, _tagName) + .Returns(Task.FromException(_notFoundException)); + + var ex = await Should.ThrowAsync(() => _gitHubProvider.GetReleaseAsync(_owner, _repository, _tagName)).ConfigureAwait(false); + ex.Message.ShouldBe(_notFoundException.Message); + ex.InnerException.ShouldBe(_notFoundException); + } + + [Test] + public async Task Should_Throw_An_Exception_On_Getting_Release() + { + _gitHubClient.Repository.Release.Get(_owner, _repository, _tagName) + .Returns(Task.FromException(_exception)); + + var ex = await Should.ThrowAsync(() => _gitHubProvider.GetReleaseAsync(_owner, _repository, _tagName)).ConfigureAwait(false); + ex.Message.ShouldBe(_exception.Message); + ex.InnerException.ShouldBe(_exception); + } + + [Test] + public async Task Should_Get_Releases() + { + var releases = new List(); + + _gitHubClient.Repository.Release.GetAll(_owner, _repository) + .Returns(Task.FromResult((IReadOnlyList)new List())); + + _mapper.Map>(Arg.Any()) + .Returns(releases); + + var result = await _gitHubProvider.GetReleasesAsync(_owner, _repository).ConfigureAwait(false); + result.ShouldBeSameAs(releases); + + await _gitHubClient.Repository.Release.Received(1).GetAll(_owner, _repository).ConfigureAwait(false); + _mapper.Received(1).Map>(Arg.Any()); + } + + [Test] + public async Task Should_Throw_An_Exception_On_Getting_Releases() + { + _gitHubClient.Repository.Release.GetAll(_owner, _repository) + .Returns(Task.FromException>(_exception)); + + var ex = await Should.ThrowAsync(() => _gitHubProvider.GetReleasesAsync(_owner, _repository)).ConfigureAwait(false); + ex.Message.ShouldBe(_exception.Message); + ex.InnerException.ShouldBe(_exception); + } } } \ No newline at end of file diff --git a/Source/GitReleaseManager.Tests/ReleaseNotesExporterTests.cs b/Source/GitReleaseManager.Tests/ReleaseNotesExporterTests.cs index 017366ff..9dc8d0c3 100644 --- a/Source/GitReleaseManager.Tests/ReleaseNotesExporterTests.cs +++ b/Source/GitReleaseManager.Tests/ReleaseNotesExporterTests.cs @@ -61,16 +61,9 @@ public void SingleReleaseExcludeRegexRemoval() private static void AcceptTest(Config configuration, params Release[] releases) { - var vcsService = new VcsServiceMock(); var logger = Substitute.For(); - - foreach (var release in releases) - { - vcsService.Releases.Add(release); - } - - var builder = new ReleaseNotesExporter(vcsService, logger, configuration, "bob", "repo"); - var notes = builder.ExportReleaseNotes(null).Result; + var builder = new ReleaseNotesExporter(logger, configuration.Export); + var notes = builder.ExportReleaseNotes(releases); Approvals.Verify(notes); } From c62d5704f8fada8fba64deaaf2ba7d42a9623556 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 6 Aug 2020 21:39:17 +0200 Subject: [PATCH 061/181] (GH-181) Decouple ReleaseNotesBuilder and ReleaseNotesExporter from VcsService --- Source/GitReleaseManager.Cli/Program.cs | 4 ++++ .../ReleaseNotesBuilderIntegrationTests.cs | 9 ++++---- .../ReleaseNotesBuilderTests.cs | 5 +++-- .../ReleaseNotesExporterTests.cs | 2 +- .../ReleaseNotes/IReleaseNotesBuilder.cs | 9 ++++++++ .../ReleaseNotes/IReleaseNotesExporter.cs | 10 +++++++++ .../{ => ReleaseNotes}/ReleaseNotesBuilder.cs | 21 ++++++++++--------- .../ReleaseNotesExporter.cs | 4 ++-- Source/GitReleaseManager/VcsService.cs | 13 +++++++----- 9 files changed, 53 insertions(+), 24 deletions(-) create mode 100644 Source/GitReleaseManager/ReleaseNotes/IReleaseNotesBuilder.cs create mode 100644 Source/GitReleaseManager/ReleaseNotes/IReleaseNotesExporter.cs rename Source/GitReleaseManager/{ => ReleaseNotes}/ReleaseNotesBuilder.cs (96%) rename Source/GitReleaseManager/{ => ReleaseNotes}/ReleaseNotesExporter.cs (96%) diff --git a/Source/GitReleaseManager.Cli/Program.cs b/Source/GitReleaseManager.Cli/Program.cs index debe6c0c..b3f3633d 100644 --- a/Source/GitReleaseManager.Cli/Program.cs +++ b/Source/GitReleaseManager.Cli/Program.cs @@ -18,6 +18,7 @@ namespace GitReleaseManager.Cli using GitReleaseManager.Core.Configuration; using GitReleaseManager.Core.Helpers; using GitReleaseManager.Core.Provider; + using GitReleaseManager.Core.ReleaseNotes; using Microsoft.Extensions.DependencyInjection; using Octokit; using Serilog; @@ -95,6 +96,9 @@ private static void RegisterServices(BaseVcsOptions options) .AddSingleton(logger) .AddSingleton(mapper) .AddSingleton(configuration) + .AddSingleton(configuration.Export) + .AddSingleton() + .AddSingleton() .AddSingleton(gitHubClient) .AddSingleton() .AddSingleton(); diff --git a/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs b/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs index 880d4ab6..1dee9df4 100644 --- a/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs +++ b/Source/GitReleaseManager.IntegrationTests/ReleaseNotesBuilderIntegrationTests.cs @@ -14,6 +14,7 @@ namespace GitReleaseManager.IntegrationTests using GitReleaseManager.Core.Configuration; using GitReleaseManager.Core.Helpers; using GitReleaseManager.Core.Provider; + using GitReleaseManager.Core.ReleaseNotes; using NUnit.Framework; using Octokit; using Serilog; @@ -70,8 +71,8 @@ public async Task SingleMilestone() var configuration = ConfigurationProvider.Provide(currentDirectory, fileSystem); var vcsProvider = new GitHubProvider(_gitHubClient, _mapper); - var releaseNotesBuilder = new ReleaseNotesBuilder(vcsProvider, _logger, "Chocolatey", "ChocolateyGUI", "0.12.4", configuration); - var result = await releaseNotesBuilder.BuildReleaseNotes().ConfigureAwait(false); + var releaseNotesBuilder = new ReleaseNotesBuilder(vcsProvider, _logger, configuration); + var result = await releaseNotesBuilder.BuildReleaseNotes("Chocolatey", "ChocolateyGUI", "0.12.4").ConfigureAwait(false); Debug.WriteLine(result); ClipBoardHelper.SetClipboard(result); } @@ -92,8 +93,8 @@ public async Task SingleMilestone3() var configuration = ConfigurationProvider.Provide(currentDirectory, fileSystem); var vcsProvider = new GitHubProvider(_gitHubClient, _mapper); - var releaseNotesBuilder = new ReleaseNotesBuilder(vcsProvider, _logger, "Chocolatey", "ChocolateyGUI", "0.13.0", configuration); - var result = await releaseNotesBuilder.BuildReleaseNotes().ConfigureAwait(false); + var releaseNotesBuilder = new ReleaseNotesBuilder(vcsProvider, _logger, configuration); + var result = await releaseNotesBuilder.BuildReleaseNotes("Chocolatey", "ChocolateyGUI", "0.13.0").ConfigureAwait(false); Debug.WriteLine(result); ClipBoardHelper.SetClipboard(result); } diff --git a/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs b/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs index 10977d33..5b4d331e 100644 --- a/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs +++ b/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Threading.Tasks; +using GitReleaseManager.Core.ReleaseNotes; namespace GitReleaseManager.Tests { @@ -184,8 +185,8 @@ private static void AcceptTest(int commits, Config config, params Issue[] issues vcsProvider.GetMilestonesAsync(owner, repository, Arg.Any()) .Returns(Task.FromResult((IEnumerable)vcsService.Milestones)); - var builder = new ReleaseNotesBuilder(vcsProvider, logger, owner, repository, milestoneTitle, configuration); - var notes = builder.BuildReleaseNotes().Result; + var builder = new ReleaseNotesBuilder(vcsProvider, logger, configuration); + var notes = builder.BuildReleaseNotes(owner, repository, milestoneTitle).Result; Approvals.Verify(notes); } diff --git a/Source/GitReleaseManager.Tests/ReleaseNotesExporterTests.cs b/Source/GitReleaseManager.Tests/ReleaseNotesExporterTests.cs index 9dc8d0c3..3d3ffa9a 100644 --- a/Source/GitReleaseManager.Tests/ReleaseNotesExporterTests.cs +++ b/Source/GitReleaseManager.Tests/ReleaseNotesExporterTests.cs @@ -9,10 +9,10 @@ namespace GitReleaseManager.Tests using System; using System.Text; using ApprovalTests; - using GitReleaseManager.Core; using GitReleaseManager.Core.Configuration; using GitReleaseManager.Core.Helpers; using GitReleaseManager.Core.Model; + using GitReleaseManager.Core.ReleaseNotes; using NSubstitute; using NUnit.Framework; using Serilog; diff --git a/Source/GitReleaseManager/ReleaseNotes/IReleaseNotesBuilder.cs b/Source/GitReleaseManager/ReleaseNotes/IReleaseNotesBuilder.cs new file mode 100644 index 00000000..2556621e --- /dev/null +++ b/Source/GitReleaseManager/ReleaseNotes/IReleaseNotesBuilder.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace GitReleaseManager.Core.ReleaseNotes +{ + public interface IReleaseNotesBuilder + { + Task BuildReleaseNotes(string user, string repository, string milestoneTitle); + } +} \ No newline at end of file diff --git a/Source/GitReleaseManager/ReleaseNotes/IReleaseNotesExporter.cs b/Source/GitReleaseManager/ReleaseNotes/IReleaseNotesExporter.cs new file mode 100644 index 00000000..0a09785c --- /dev/null +++ b/Source/GitReleaseManager/ReleaseNotes/IReleaseNotesExporter.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using GitReleaseManager.Core.Model; + +namespace GitReleaseManager.Core.ReleaseNotes +{ + public interface IReleaseNotesExporter + { + string ExportReleaseNotes(IEnumerable releases); + } +} \ No newline at end of file diff --git a/Source/GitReleaseManager/ReleaseNotesBuilder.cs b/Source/GitReleaseManager/ReleaseNotes/ReleaseNotesBuilder.cs similarity index 96% rename from Source/GitReleaseManager/ReleaseNotesBuilder.cs rename to Source/GitReleaseManager/ReleaseNotes/ReleaseNotesBuilder.cs index 28596493..d2ce1c35 100644 --- a/Source/GitReleaseManager/ReleaseNotesBuilder.cs +++ b/Source/GitReleaseManager/ReleaseNotes/ReleaseNotesBuilder.cs @@ -4,7 +4,7 @@ // //----------------------------------------------------------------------- -namespace GitReleaseManager.Core +namespace GitReleaseManager.Core.ReleaseNotes { using System; using System.Collections.Generic; @@ -18,29 +18,30 @@ namespace GitReleaseManager.Core using GitReleaseManager.Core.Provider; using Serilog; - public class ReleaseNotesBuilder + public class ReleaseNotesBuilder : IReleaseNotesBuilder { private readonly IVcsProvider _vcsProvider; private readonly ILogger _logger; - private readonly string _user; - private readonly string _repository; - private readonly string _milestoneTitle; private readonly Config _configuration; + private string _user; + private string _repository; + private string _milestoneTitle; private IEnumerable _milestones; private Milestone _targetMilestone; - public ReleaseNotesBuilder(IVcsProvider vcsProvider, ILogger logger, string user, string repository, string milestoneTitle, Config configuration) + public ReleaseNotesBuilder(IVcsProvider vcsProvider, ILogger logger, Config configuration) { _vcsProvider = vcsProvider; _logger = logger; - _user = user; - _repository = repository; - _milestoneTitle = milestoneTitle; _configuration = configuration; } - public async Task BuildReleaseNotes() + public async Task BuildReleaseNotes(string user, string repository, string milestoneTitle) { + _user = user; + _repository = repository; + _milestoneTitle = milestoneTitle; + _logger.Verbose("Building release notes..."); await LoadMilestones().ConfigureAwait(false); GetTargetMilestone(); diff --git a/Source/GitReleaseManager/ReleaseNotesExporter.cs b/Source/GitReleaseManager/ReleaseNotes/ReleaseNotesExporter.cs similarity index 96% rename from Source/GitReleaseManager/ReleaseNotesExporter.cs rename to Source/GitReleaseManager/ReleaseNotes/ReleaseNotesExporter.cs index e3002224..72c55c95 100644 --- a/Source/GitReleaseManager/ReleaseNotesExporter.cs +++ b/Source/GitReleaseManager/ReleaseNotes/ReleaseNotesExporter.cs @@ -4,7 +4,7 @@ // //----------------------------------------------------------------------- -namespace GitReleaseManager.Core +namespace GitReleaseManager.Core.ReleaseNotes { using System; using System.Collections.Generic; @@ -16,7 +16,7 @@ namespace GitReleaseManager.Core using GitReleaseManager.Core.Model; using Serilog; - public class ReleaseNotesExporter + public class ReleaseNotesExporter : IReleaseNotesExporter { private readonly ILogger _logger; private readonly ExportConfig _configuration; diff --git a/Source/GitReleaseManager/VcsService.cs b/Source/GitReleaseManager/VcsService.cs index bef0eb6a..7b18e11a 100644 --- a/Source/GitReleaseManager/VcsService.cs +++ b/Source/GitReleaseManager/VcsService.cs @@ -19,6 +19,7 @@ namespace GitReleaseManager.Core using GitReleaseManager.Core.Exceptions; using GitReleaseManager.Core.Extensions; using GitReleaseManager.Core.Provider; + using GitReleaseManager.Core.ReleaseNotes; using Octokit; using Serilog; using NotFoundException = GitReleaseManager.Core.Exceptions.NotFoundException; @@ -30,22 +31,25 @@ public class VcsService : IVcsService private readonly IGitHubClient _gitHubClient; private readonly ILogger _logger; private readonly IMapper _mapper; + private readonly IReleaseNotesBuilder _releaseNotesBuilder; + private readonly IReleaseNotesExporter _releaseNotesExporter; private readonly Config _configuration; - public VcsService(IVcsProvider vcsProvider, IGitHubClient gitHubClient, ILogger logger, IMapper mapper, Config configuration) + public VcsService(IVcsProvider vcsProvider, IGitHubClient gitHubClient, ILogger logger, IMapper mapper, IReleaseNotesBuilder releaseNotesBuilder, IReleaseNotesExporter releaseNotesExporter, Config configuration) { _vcsProvider = vcsProvider; _gitHubClient = gitHubClient; _logger = logger; _mapper = mapper; + _releaseNotesBuilder = releaseNotesBuilder; + _releaseNotesExporter = releaseNotesExporter; _configuration = configuration; } public async Task CreateReleaseFromMilestone(string owner, string repository, string milestone, string releaseName, string targetCommitish, IList assets, bool prerelease) { var release = await GetReleaseFromTagNameAsync(owner, repository, milestone).ConfigureAwait(false); - var releaseNotesBuilder = new ReleaseNotesBuilder(_vcsProvider, _logger, owner, repository, milestone, _configuration); - var result = await releaseNotesBuilder.BuildReleaseNotes().ConfigureAwait(false); + var result = await _releaseNotesBuilder.BuildReleaseNotes(owner, repository, milestone).ConfigureAwait(false); if (release == null) { @@ -184,7 +188,6 @@ public async Task AddAssets(string owner, string repository, string tagName, ILi public async Task ExportReleases(string owner, string repository, string tagName) { - var releaseNotesExporter = new ReleaseNotesExporter(_logger, _configuration.Export); var releases = Enumerable.Empty(); if (string.IsNullOrWhiteSpace(tagName)) @@ -207,7 +210,7 @@ public async Task ExportReleases(string owner, string repository, string } } - return releaseNotesExporter.ExportReleaseNotes(releases); + return _releaseNotesExporter.ExportReleaseNotes(releases); } public async Task CloseMilestone(string owner, string repository, string milestoneTitle) From 104bffad3fff8ef7c95ae3f5000f13261770960b Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 6 Aug 2020 22:20:03 +0200 Subject: [PATCH 062/181] (GH-181) Update and add unit tests --- .../Provider/GitHubProviderTests.cs | 19 ++--- .../VcsServiceTests.cs | 80 +++++++++++++++++++ 2 files changed, 90 insertions(+), 9 deletions(-) create mode 100644 Source/GitReleaseManager.Core.Tests/VcsServiceTests.cs diff --git a/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs b/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs index 977cc4f3..166f0230 100644 --- a/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs +++ b/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs @@ -20,13 +20,14 @@ namespace GitReleaseManager.Core.Tests.Provider [TestFixture] public class GitHubProviderTests { - private readonly string _owner = "owner"; - private readonly string _repository = "repository"; - private readonly string _base = "0.1.0"; - private readonly string _head = "0.5.0"; - private readonly int _milestoneNumber = 1; - private readonly string _milestoneNumberString = "1"; - private readonly string _tagName = "0.1.0"; + private const string _owner = "owner"; + private const string _repository = "repository"; + private const string _base = "0.1.0"; + private const string _head = "0.5.0"; + private const int _milestoneNumber = 1; + private const string _milestoneNumberString = "1"; + private const string _tagName = "0.1.0"; + private readonly Exception _exception = new Exception("API Error"); private readonly Octokit.NotFoundException _notFoundException = new Octokit.NotFoundException("NotFound", HttpStatusCode.NotFound); @@ -138,7 +139,7 @@ await _gitHubClient.Issue.Received(1).GetAllForRepository(_owner, _repository, A } [Test] - public async Task Should_Throw_An_Exception_On_Getting_Issues_For_Non_Existing_Milestone() + public async Task Should_Throw_An_Exception_On_Getting_Issues_For_Non_Existent_Milestone() { _gitHubClient.Issue.GetAllForRepository(_owner, _repository, Arg.Any()) .Returns(Task.FromException>(_exception)); @@ -202,7 +203,7 @@ public async Task Should_Get_A_Release() } [Test] - public async Task Should_Throw_An_Exception_On_Getting_Release_For_Non_Existing_Tag() + public async Task Should_Throw_An_Exception_On_Getting_Release_For_Non_Existent_Tag() { _gitHubClient.Repository.Release.Get(_owner, _repository, _tagName) .Returns(Task.FromException(_notFoundException)); diff --git a/Source/GitReleaseManager.Core.Tests/VcsServiceTests.cs b/Source/GitReleaseManager.Core.Tests/VcsServiceTests.cs new file mode 100644 index 00000000..921ee1a2 --- /dev/null +++ b/Source/GitReleaseManager.Core.Tests/VcsServiceTests.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using AutoMapper; +using GitReleaseManager.Core.Configuration; +using GitReleaseManager.Core.Provider; +using GitReleaseManager.Core.ReleaseNotes; +using NSubstitute; +using NUnit.Framework; +using Octokit; +using Serilog; +using Shouldly; +using NotFoundException = GitReleaseManager.Core.Exceptions.NotFoundException; +using Release = GitReleaseManager.Core.Model.Release; + +namespace GitReleaseManager.Core.Tests +{ + public class VcsServiceTests + { + private const string _owner = "owner"; + private const string _repository = "repository"; + private const string _tagName = "0.1.0"; + + private readonly NotFoundException _notFoundException = new NotFoundException("NotFound"); + + private IReleaseNotesExporter _releaseNotesExporter; + private IReleaseNotesBuilder _releaseNotesBuilder; + private IMapper _mapper; + private ILogger _logger; + private IGitHubClient _gitHubClient; + private IVcsProvider _vcsProvider; + private Config _configuration; + private VcsService _vcsService; + + [SetUp] + public void Setup() + { + _releaseNotesExporter = Substitute.For(); + _releaseNotesBuilder = Substitute.For(); + _mapper = Substitute.For(); + _logger = Substitute.For(); + _gitHubClient = Substitute.For(); + _vcsProvider = Substitute.For(); + _configuration = new Config(); + _vcsService = new VcsService(_vcsProvider, _gitHubClient, _logger, _mapper, _releaseNotesBuilder, _releaseNotesExporter, _configuration); + } + + [TestCase(null)] + [TestCase(_tagName)] + public async Task Should_Get_Release_Notes(string tagName) + { + var releaseNotes = "Release Notes"; + + _releaseNotesExporter.ExportReleaseNotes(Arg.Any>()) + .Returns(releaseNotes); + + var result = await _vcsService.ExportReleases(_owner, _repository, tagName).ConfigureAwait(false); + result.ShouldBeSameAs(releaseNotes); + + _releaseNotesExporter.Received(1).ExportReleaseNotes(Arg.Any>()); + } + + [Test] + public async Task Should_Get_Default_Release_Notes_For_Non_Existent_Tag() + { + var releaseNotes = "Release Notes"; + + _vcsProvider.GetReleaseAsync(_owner, _repository, _tagName) + .Returns(Task.FromException(_notFoundException)); + + _releaseNotesExporter.ExportReleaseNotes(Arg.Any>()) + .Returns(releaseNotes); + + var result = await _vcsService.ExportReleases(_owner, _repository, _tagName).ConfigureAwait(false); + result.ShouldBeSameAs(releaseNotes); + + await _vcsProvider.Received(1).GetReleaseAsync(_owner, _repository, _tagName).ConfigureAwait(false); + _releaseNotesExporter.Received(1).ExportReleaseNotes(Arg.Any>()); + } + } +} \ No newline at end of file From ef1618d624b42fe908c8350efb1bb48d53c93642 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Thu, 6 Aug 2020 22:50:12 +0200 Subject: [PATCH 063/181] (GH-181) Fix LGTM warning --- Source/GitReleaseManager/VcsService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GitReleaseManager/VcsService.cs b/Source/GitReleaseManager/VcsService.cs index 7b18e11a..6792e850 100644 --- a/Source/GitReleaseManager/VcsService.cs +++ b/Source/GitReleaseManager/VcsService.cs @@ -425,7 +425,7 @@ private async Task CreateReleaseFromInputFileInternal(string owner, str private void SleepWhenRateIsLimited() { var lastApi = _gitHubClient.GetLastApiInfo(); - if (lastApi?.RateLimit.Remaining == 0) + if (lastApi?.RateLimit?.Remaining == 0) { var sleepTime = lastApi.RateLimit.Reset - DateTimeOffset.Now; _logger.Warning("Rate limit exceeded, sleeping for {$SleepTime}", sleepTime); From 48acb2a9c7ddbc8f0ffa9cf366e3db94360f7d9c Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Fri, 7 Aug 2020 19:22:51 +0200 Subject: [PATCH 064/181] (GH-181) Refactor VcsService --- Source/GitReleaseManager/Ensure.cs | 19 ++- .../Exceptions/MissingReleaseException.cs | 35 ----- Source/GitReleaseManager/IVcsService.cs | 2 +- Source/GitReleaseManager/Model/Issue.cs | 2 +- .../GitReleaseManager/Model/IssueComment.cs | 16 +++ Source/GitReleaseManager/Model/ItemState.cs | 15 ++ Source/GitReleaseManager/Model/Release.cs | 4 + .../Provider/GitHubProvider.cs | 91 ++++++++++++ .../Provider/IVcsProvider.cs | 10 ++ Source/GitReleaseManager/VcsService.cs | 135 ++++++++---------- 10 files changed, 214 insertions(+), 115 deletions(-) delete mode 100644 Source/GitReleaseManager/Exceptions/MissingReleaseException.cs create mode 100644 Source/GitReleaseManager/Model/IssueComment.cs create mode 100644 Source/GitReleaseManager/Model/ItemState.cs diff --git a/Source/GitReleaseManager/Ensure.cs b/Source/GitReleaseManager/Ensure.cs index 4e2e22a2..ce24a922 100644 --- a/Source/GitReleaseManager/Ensure.cs +++ b/Source/GitReleaseManager/Ensure.cs @@ -1,4 +1,5 @@ using System; +using System.IO; namespace GitReleaseManager.Core { @@ -24,10 +25,26 @@ public static void IsNotNullOrWhiteSpace(string str, string paramName) { throw new ArgumentNullException(paramName); } - else if (string.IsNullOrWhiteSpace(str)) + + if (string.IsNullOrWhiteSpace(str)) { throw new ArgumentException("Value cannot be empty or white-space.", paramName); } } + + /// + /// Checks if a file exists. + /// + /// The path to test. + /// A message that describes the error. + /// File does not exist. + public static void FileExists(string path, string message) + { + if (!File.Exists(path)) + { + var fileName = Path.GetFileName(path); + throw new FileNotFoundException(message, fileName); + } + } } } \ No newline at end of file diff --git a/Source/GitReleaseManager/Exceptions/MissingReleaseException.cs b/Source/GitReleaseManager/Exceptions/MissingReleaseException.cs deleted file mode 100644 index 61747415..00000000 --- a/Source/GitReleaseManager/Exceptions/MissingReleaseException.cs +++ /dev/null @@ -1,35 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) 2015 - Present - GitTools Contributors -// -// ----------------------------------------------------------------------- - -namespace GitReleaseManager.Core.Exceptions -{ - using System; - - [Serializable] - public class MissingReleaseException : Exception - { - public MissingReleaseException() - { - } - - public MissingReleaseException(string message) - : base(message) - { - } - - public MissingReleaseException(string message, Exception inner) - : base(message, inner) - { - } - - protected MissingReleaseException( - System.Runtime.Serialization.SerializationInfo info, - System.Runtime.Serialization.StreamingContext context) - : base(info, context) - { - } - } -} \ No newline at end of file diff --git a/Source/GitReleaseManager/IVcsService.cs b/Source/GitReleaseManager/IVcsService.cs index 152bfc92..378bb4ef 100644 --- a/Source/GitReleaseManager/IVcsService.cs +++ b/Source/GitReleaseManager/IVcsService.cs @@ -16,7 +16,7 @@ public interface IVcsService Task CreateReleaseFromInputFile(string owner, string repository, string name, string inputFilePath, string targetCommitish, IList assets, bool prerelease); - Task DiscardRelease(string owner, string repository, string name); + Task DiscardRelease(string owner, string repository, string tagName); Task AddAssets(string owner, string repository, string tagName, IList assets); diff --git a/Source/GitReleaseManager/Model/Issue.cs b/Source/GitReleaseManager/Model/Issue.cs index a602d9e4..677e8bac 100644 --- a/Source/GitReleaseManager/Model/Issue.cs +++ b/Source/GitReleaseManager/Model/Issue.cs @@ -12,7 +12,7 @@ public sealed class Issue { public string Title { get; set; } - public string Number { get; set; } + public int Number { get; set; } public string HtmlUrl { get; set; } diff --git a/Source/GitReleaseManager/Model/IssueComment.cs b/Source/GitReleaseManager/Model/IssueComment.cs new file mode 100644 index 00000000..d5ba502d --- /dev/null +++ b/Source/GitReleaseManager/Model/IssueComment.cs @@ -0,0 +1,16 @@ +namespace GitReleaseManager.Core.Model +{ + public class IssueComment + { + /// + /// The issue comment Id. + /// + public int Id { get; set; } + + /// + /// Details about the issue comment. + /// + public string Body { get; set; } + + } +} \ No newline at end of file diff --git a/Source/GitReleaseManager/Model/ItemState.cs b/Source/GitReleaseManager/Model/ItemState.cs new file mode 100644 index 00000000..c7f15ffa --- /dev/null +++ b/Source/GitReleaseManager/Model/ItemState.cs @@ -0,0 +1,15 @@ +namespace GitReleaseManager.Core.Model +{ + public enum ItemState + { + /// + /// Items that are open + /// + Open = 0, + + /// + /// Items that are closed + /// + Closed = 1 + } +} \ No newline at end of file diff --git a/Source/GitReleaseManager/Model/Release.cs b/Source/GitReleaseManager/Model/Release.cs index 985b8ea3..4ca80e45 100644 --- a/Source/GitReleaseManager/Model/Release.cs +++ b/Source/GitReleaseManager/Model/Release.cs @@ -10,6 +10,8 @@ namespace GitReleaseManager.Core.Model public sealed class Release { + public int Id { get; set; } + public string Body { get; set; } public string TagName { get; set; } @@ -17,5 +19,7 @@ public sealed class Release public DateTimeOffset CreatedAt { get; set; } public string HtmlUrl { get; set; } + + public bool Draft { get; set; } } } \ No newline at end of file diff --git a/Source/GitReleaseManager/Provider/GitHubProvider.cs b/Source/GitReleaseManager/Provider/GitHubProvider.cs index cdab7f71..e8fa5107 100644 --- a/Source/GitReleaseManager/Provider/GitHubProvider.cs +++ b/Source/GitReleaseManager/Provider/GitHubProvider.cs @@ -6,6 +6,8 @@ using AutoMapper; using Octokit; using Issue = GitReleaseManager.Core.Model.Issue; +using IssueComment = GitReleaseManager.Core.Model.IssueComment; +using ItemState = GitReleaseManager.Core.Model.ItemState; using ItemStateFilter = GitReleaseManager.Core.Model.ItemStateFilter; using Milestone = GitReleaseManager.Core.Model.Milestone; using NotFoundException = GitReleaseManager.Core.Exceptions.NotFoundException; @@ -15,6 +17,8 @@ namespace GitReleaseManager.Core.Provider { public class GitHubProvider : IVcsProvider { + private const string _notFoundMessgae = "NotFound"; + private readonly IGitHubClient _gitHubClient; private readonly IMapper _mapper; @@ -63,6 +67,22 @@ public string GetCommitsUrl(string owner, string repository, string head, string return url; } + public async Task CreateIssueCommentAsync(string owner, string repository, int issueNumber, string comment) + { + try + { + await _gitHubClient.Issue.Comment.Create(owner, repository, issueNumber, comment).ConfigureAwait(false); + } + catch (Octokit.NotFoundException ex) + { + throw new NotFoundException(ex.Message, ex); + } + catch (Exception ex) + { + throw new ApiException(ex.Message, ex); + } + } + public async Task> GetIssuesAsync(string owner, string repository, int milestoneNumber, ItemStateFilter itemStateFilter = ItemStateFilter.All) { try @@ -83,6 +103,44 @@ public async Task> GetIssuesAsync(string owner, string reposi } } + public async Task> GetIssueCommentsAsync(string owner, string repository, int issueNumber) + { + try + { + var comments = await _gitHubClient.Issue.Comment.GetAllForIssue(owner, repository, issueNumber).ConfigureAwait(false); + + return _mapper.Map>(comments); + } + catch (Octokit.NotFoundException ex) + { + throw new NotFoundException(ex.Message, ex); + } + catch (Exception ex) + { + throw new ApiException(ex.Message, ex); + } + } + + public async Task GetMilestoneAsync(string owner, string repository, string milestoneTitle, ItemStateFilter itemStateFilter = ItemStateFilter.All) + { + try + { + var milestones = await GetMilestonesAsync(owner, repository, itemStateFilter).ConfigureAwait(false); + var milestone = milestones.FirstOrDefault(m => m.Title == milestoneTitle); + + if (milestone is null) + { + throw new NotFoundException(_notFoundMessgae); + } + + return milestone; + } + catch (Exception ex) when (!(ex is NotFoundException)) + { + throw new ApiException(ex.Message, ex); + } + } + public async Task> GetMilestonesAsync(string owner, string repository, ItemStateFilter itemStateFilter = ItemStateFilter.All) { try @@ -98,6 +156,39 @@ public async Task> GetMilestonesAsync(string owner, strin } } + public async Task SetMilestoneStateAsync(string owner, string repository, int milestoneNumber, ItemState itemState) + { + try + { + var update = new MilestoneUpdate { State = (Octokit.ItemState)itemState }; + await _gitHubClient.Issue.Milestone.Update(owner, repository, milestoneNumber, update).ConfigureAwait(false); + } + catch (Octokit.NotFoundException ex) + { + throw new NotFoundException(ex.Message, ex); + } + catch (Exception ex) + { + throw new ApiException(ex.Message, ex); + } + } + + public async Task DeleteReleaseAsync(string owner, string repository, int id) + { + try + { + await _gitHubClient.Repository.Release.Delete(owner, repository, id).ConfigureAwait(false); + } + catch (Octokit.NotFoundException ex) + { + throw new NotFoundException(ex.Message, ex); + } + catch (Exception ex) + { + throw new ApiException(ex.Message, ex); + } + } + public async Task GetReleaseAsync(string owner, string repository, string tagName) { try diff --git a/Source/GitReleaseManager/Provider/IVcsProvider.cs b/Source/GitReleaseManager/Provider/IVcsProvider.cs index 211733f4..be2f1a32 100644 --- a/Source/GitReleaseManager/Provider/IVcsProvider.cs +++ b/Source/GitReleaseManager/Provider/IVcsProvider.cs @@ -10,10 +10,20 @@ public interface IVcsProvider string GetCommitsUrl(string owner, string repository, string head, string @base = null); + Task CreateIssueCommentAsync(string owner, string repository, int issueNumber, string comment); + Task> GetIssuesAsync(string owner, string repository, int milestoneNumber, ItemStateFilter itemStateFilter = ItemStateFilter.All); + Task> GetIssueCommentsAsync(string owner, string repository, int issueNumber); + + Task GetMilestoneAsync(string owner, string repository, string milestoneTitle, ItemStateFilter itemStateFilter = ItemStateFilter.All); + Task> GetMilestonesAsync(string owner, string repository, ItemStateFilter itemStateFilter = ItemStateFilter.All); + Task SetMilestoneStateAsync(string owner, string repository, int milestoneNumber, ItemState itemState); + + Task DeleteReleaseAsync(string owner, string repository, int id); + Task GetReleaseAsync(string owner, string repository, string tagName); Task> GetReleasesAsync(string owner, string repository); diff --git a/Source/GitReleaseManager/VcsService.cs b/Source/GitReleaseManager/VcsService.cs index 6792e850..47aa8538 100644 --- a/Source/GitReleaseManager/VcsService.cs +++ b/Source/GitReleaseManager/VcsService.cs @@ -16,12 +16,12 @@ namespace GitReleaseManager.Core using System.Threading.Tasks; using AutoMapper; using GitReleaseManager.Core.Configuration; - using GitReleaseManager.Core.Exceptions; using GitReleaseManager.Core.Extensions; using GitReleaseManager.Core.Provider; using GitReleaseManager.Core.ReleaseNotes; using Octokit; using Serilog; + using Milestone = GitReleaseManager.Core.Model.Milestone; using NotFoundException = GitReleaseManager.Core.Exceptions.NotFoundException; using Release = GitReleaseManager.Core.Model.Release; @@ -78,31 +78,46 @@ public async Task CreateReleaseFromMilestone(string owner, string repos return _mapper.Map(release); } - public Task CreateReleaseFromInputFile(string owner, string repository, string name, string inputFilePath, string targetCommitish, IList assets, bool prerelease) + public async Task CreateReleaseFromInputFile(string owner, string repository, string name, string inputFilePath, string targetCommitish, IList assets, bool prerelease) { - if (!File.Exists(inputFilePath)) - { - throw new ArgumentException("Unable to locate input file."); - } + Ensure.FileExists(inputFilePath, "Unable to locate input file."); + + _logger.Verbose("Reading release notes from: '{FilePath}'", inputFilePath); + + var inputFileContents = File.ReadAllText(inputFilePath); + + var releaseUpdate = CreateNewRelease(name, name, inputFileContents, prerelease, targetCommitish); + + _logger.Verbose("Creating new release on '{Owner}/{Repository}'", owner, repository); + _logger.Debug("{@ReleaseUpdate}", releaseUpdate); + + var release = await _gitHubClient.Repository.Release.Create(owner, repository, releaseUpdate).ConfigureAwait(false); + + await AddAssets(owner, repository, name, assets).ConfigureAwait(false); - return CreateReleaseFromInputFileInternal(owner, repository, name, inputFilePath, targetCommitish, assets, prerelease); + return _mapper.Map(release); } - public async Task DiscardRelease(string owner, string repository, string name) + public async Task DiscardRelease(string owner, string repository, string tagName) { - var release = await GetReleaseFromTagNameAsync(owner, repository, name).ConfigureAwait(false); - - if (release is null) + try { - throw new MissingReleaseException(string.Format("Unable to find a release with name {0}", name)); - } + var release = await _vcsProvider.GetReleaseAsync(owner, repository, tagName).ConfigureAwait(false); - if (!release.Draft) + if (release.Draft) + { + await _vcsProvider.DeleteReleaseAsync(owner, repository, release.Id).ConfigureAwait(false); + } + else + { + _logger.Warning("Release with tag '{TagName}' is not in draft state, so not discarding.", tagName); + } + } + catch (NotFoundException) { - throw new InvalidStateException("Release is not in draft state, so not discarding."); + _logger.Error("Unable to find a release with tag '{TagName}'", tagName); } - await _gitHubClient.Repository.Release.Delete(owner, repository, release.Id).ConfigureAwait(false); } public async Task AddAssets(string owner, string repository, string tagName, IList assets) @@ -215,42 +230,39 @@ public async Task ExportReleases(string owner, string repository, string public async Task CloseMilestone(string owner, string repository, string milestoneTitle) { - _logger.Verbose("Finding open milestone with title '{Title}' on '{Owner}/{Repository}'", milestoneTitle, owner, repository); - var milestoneClient = _gitHubClient.Issue.Milestone; - var openMilestones = await milestoneClient.GetAllForRepository(owner, repository, new MilestoneRequest { State = ItemStateFilter.Open }).ConfigureAwait(false); - var milestone = openMilestones.FirstOrDefault(m => m.Title == milestoneTitle); - - if (milestone is null) + try { - _logger.Debug("No existing open milestone with title '{Title}' was found", milestoneTitle); - return; - } + _logger.Verbose("Finding open milestone with title '{Title}' on '{Owner}/{Repository}'", milestoneTitle, owner, repository); + var milestone = await _vcsProvider.GetMilestoneAsync(owner, repository, milestoneTitle, Model.ItemStateFilter.Open).ConfigureAwait(false); - _logger.Verbose("Closing milestone '{Title}' on '{Owner}/{Repository}'", milestoneTitle, owner, repository); + _logger.Verbose("Closing milestone '{Title}' on '{Owner}/{Repository}'", milestoneTitle, owner, repository); + await _vcsProvider.SetMilestoneStateAsync(owner, repository, milestone.Number, Model.ItemState.Closed).ConfigureAwait(false); - await milestoneClient.Update(owner, repository, milestone.Number, new MilestoneUpdate { State = ItemState.Closed }).ConfigureAwait(false); - - if (_configuration.Close.IssueComments) + if (_configuration.Close.IssueComments) + { + await AddIssueCommentsAsync(owner, repository, milestone).ConfigureAwait(false); + } + } + catch (NotFoundException) { - await AddIssueCommentsAsync(owner, repository, milestone).ConfigureAwait(false); + _logger.Error("No existing open milestone with title '{Title}' was found", milestoneTitle); } } public async Task OpenMilestone(string owner, string repository, string milestoneTitle) { - _logger.Verbose("Finding closed milestone with title '{Title}' on '{Owner}/{Repository}'", milestoneTitle, owner, repository); - var milestoneClient = _gitHubClient.Issue.Milestone; - var closedMilestones = await milestoneClient.GetAllForRepository(owner, repository, new MilestoneRequest { State = ItemStateFilter.Closed }).ConfigureAwait(false); - var milestone = closedMilestones.FirstOrDefault(m => m.Title == milestoneTitle); + try + { + _logger.Verbose("Finding closed milestone with title '{Title}' on '{Owner}/{Repository}'", milestoneTitle, owner, repository); + var milestone = await _vcsProvider.GetMilestoneAsync(owner, repository, milestoneTitle, Model.ItemStateFilter.Closed).ConfigureAwait(false); - if (milestone is null) + _logger.Verbose("Opening milestone '{Title}' on '{Owner}/{Repository}'", milestoneTitle, owner, repository); + await _vcsProvider.SetMilestoneStateAsync(owner, repository, milestone.Number, Model.ItemState.Open).ConfigureAwait(false); + } + catch (NotFoundException) { - _logger.Debug("No existing closed milestone with title '{Title}' was found", milestoneTitle); - return; + _logger.Error("No existing closed milestone with title '{Title}' was found", milestoneTitle); } - - _logger.Verbose("Opening milestone '{Title}' on '{Owner}/{Repository}'", milestoneTitle, owner, repository); - await milestoneClient.Update(owner, repository, milestone.Number, new MilestoneUpdate { State = ItemState.Open }).ConfigureAwait(false); } public async Task PublishRelease(string owner, string repository, string tagName) @@ -344,19 +356,16 @@ private static string ComputeSha256Hash(string asset) } } - private async Task AddIssueCommentsAsync(string owner, string repository, Octokit.Milestone milestone) + private async Task AddIssueCommentsAsync(string owner, string repository, Milestone milestone) { const string detectionComment = ""; var issueComment = detectionComment + "\n" + _configuration.Close.IssueCommentFormat.ReplaceTemplate(new { owner, repository, Milestone = milestone.Title }); - var issues = await GetIssuesFromMilestoneAsync(owner, repository, milestone.Number).ConfigureAwait(false); + + _logger.Verbose("Finding issues with milestone: '{Milestone}", milestone.Number); + var issues = await _vcsProvider.GetIssuesAsync(owner, repository, milestone.Number, Model.ItemStateFilter.Closed).ConfigureAwait(false); foreach (var issue in issues) { - if (issue.State != ItemState.Closed) - { - continue; - } - SleepWhenRateIsLimited(); try @@ -364,7 +373,7 @@ private async Task AddIssueCommentsAsync(string owner, string repository, Octoki if (!await CommentsIncludeString(owner, repository, issue.Number, detectionComment).ConfigureAwait(false)) { _logger.Information("Adding release comment for issue #{IssueNumber}", issue.Number); - await _gitHubClient.Issue.Comment.Create(owner, repository, issue.Number, issueComment).ConfigureAwait(false); + await _vcsProvider.CreateIssueCommentAsync(owner, repository, issue.Number, issueComment).ConfigureAwait(false); } else { @@ -382,39 +391,11 @@ private async Task AddIssueCommentsAsync(string owner, string repository, Octoki private async Task CommentsIncludeString(string owner, string repository, int issueNumber, string comment) { _logger.Verbose("Finding issue comment created by GitReleaseManager for issue #{IssueNumber}", issueNumber); - var issueComments = await _gitHubClient.Issue.Comment.GetAllForIssue(owner, repository, issueNumber).ConfigureAwait(false); + var issueComments = await _vcsProvider.GetIssueCommentsAsync(owner, repository, issueNumber).ConfigureAwait(false); return issueComments.Any(c => c.Body.Contains(comment)); } - private async Task CreateReleaseFromInputFileInternal(string owner, string repository, string name, string inputFilePath, string targetCommitish, IList assets, bool prerelease) - { - _logger.Verbose("Reading release notes from: '{FilePath}'", inputFilePath); - - var inputFileContents = File.ReadAllText(inputFilePath); - - var releaseUpdate = CreateNewRelease(name, name, inputFileContents, prerelease, targetCommitish); - - _logger.Verbose("Creating new release on '{Owner}/{Repository}'", owner, repository); - _logger.Debug("{@ReleaseUpdate}", releaseUpdate); - - var release = await _gitHubClient.Repository.Release.Create(owner, repository, releaseUpdate).ConfigureAwait(false); - - await AddAssets(owner, repository, name, assets).ConfigureAwait(false); - - return _mapper.Map(release); - } - - private Task> GetIssuesFromMilestoneAsync(string owner, string repository, int milestoneNumber, ItemStateFilter state = ItemStateFilter.Closed) - { - _logger.Verbose("Finding issues with milestone: '{Milestone}", milestoneNumber); - return _gitHubClient.Issue.GetAllForRepository(owner, repository, new RepositoryIssueRequest - { - Milestone = milestoneNumber.ToString(), - State = state, - }); - } - private Task GetReleaseFromTagNameAsync(string owner, string repository, string tagName) { _logger.Verbose("Finding release with tag name: '{TagName}'", tagName); From 565c7124ee26b7779b0c91e6f622c147b86b6a1c Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Fri, 7 Aug 2020 19:23:45 +0200 Subject: [PATCH 065/181] (GH-181) Update and add unit tests --- .../EnsureTests.cs | 20 +- .../Provider/GitHubProviderTests.cs | 193 +++++++++++++++++- .../VcsServiceTests.cs | 154 +++++++++++++- .../ReleaseNotesBuilderTests.cs | 3 +- .../GitReleaseManager.Tests/VcsServiceMock.cs | 2 +- 5 files changed, 361 insertions(+), 11 deletions(-) diff --git a/Source/GitReleaseManager.Core.Tests/EnsureTests.cs b/Source/GitReleaseManager.Core.Tests/EnsureTests.cs index 83ddeeb3..91281ff4 100644 --- a/Source/GitReleaseManager.Core.Tests/EnsureTests.cs +++ b/Source/GitReleaseManager.Core.Tests/EnsureTests.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using NUnit.Framework; using Shouldly; @@ -16,8 +17,9 @@ public void Should_Throw_Exception_When_String_Is_Null() ex.ParamName.ShouldBe(paramName); } - [Test] - public void Should_Throw_Exception_When_String_Is_Whitespace([Values("", " ")] string str) + [TestCase("")] + [TestCase(" ")] + public void Should_Throw_Exception_When_String_Is_Whitespace(string str) { var paramName = nameof(str); @@ -25,5 +27,19 @@ public void Should_Throw_Exception_When_String_Is_Whitespace([Values("", " ")] s ex.Message.ShouldContain("Value cannot be empty or white-space."); ex.ParamName.ShouldBe(paramName); } + + [Test] + public void Should_Throw_Exception_When_File_Not_Exists() + { + var tempPath = Path.GetTempPath(); + var tempFile = "TempFile.txt"; + + var path = Path.Combine(tempPath, tempFile); + var message = "File does not exist"; + + var ex = Should.Throw(() => Ensure.FileExists(path, message)); + ex.Message.ShouldBe(message); + ex.FileName.ShouldBe(tempFile); + } } } \ No newline at end of file diff --git a/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs b/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs index 166f0230..6f28f663 100644 --- a/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs +++ b/Source/GitReleaseManager.Core.Tests/Provider/GitHubProviderTests.cs @@ -10,6 +10,8 @@ using Octokit; using Shouldly; using Issue = GitReleaseManager.Core.Model.Issue; +using IssueComment = GitReleaseManager.Core.Model.IssueComment; +using ItemState = GitReleaseManager.Core.Model.ItemState; using ItemStateFilter = GitReleaseManager.Core.Model.ItemStateFilter; using Milestone = GitReleaseManager.Core.Model.Milestone; using NotFoundException = GitReleaseManager.Core.Exceptions.NotFoundException; @@ -26,10 +28,14 @@ public class GitHubProviderTests private const string _head = "0.5.0"; private const int _milestoneNumber = 1; private const string _milestoneNumberString = "1"; + private const string _milestoneTitle = "0.1.0"; + private const int _issueNumber = 1; + private const string _issueComment = "Issue Comment"; private const string _tagName = "0.1.0"; + private const string _notFoundMessage = "NotFound"; private readonly Exception _exception = new Exception("API Error"); - private readonly Octokit.NotFoundException _notFoundException = new Octokit.NotFoundException("NotFound", HttpStatusCode.NotFound); + private readonly Octokit.NotFoundException _notFoundException = new Octokit.NotFoundException(_notFoundMessage, HttpStatusCode.NotFound); private IMapper _mapper; private IGitHubClient _gitHubClient; @@ -115,6 +121,39 @@ public static IEnumerable GetCommitsUrl_TestCases() } // Issues + [Test] + public async Task Should_Create_A_Issue_Comment() + { + _gitHubClient.Issue.Comment.Create(_owner, _repository, _issueNumber, _issueComment) + .Returns(Task.FromResult(new Octokit.IssueComment())); + + await _gitHubProvider.CreateIssueCommentAsync(_owner, _repository, _issueNumber, _issueComment).ConfigureAwait(false); + + await _gitHubClient.Issue.Comment.Received(1).Create(_owner, _repository, _issueNumber, _issueComment).ConfigureAwait(false); + } + + [Test] + public async Task Should_Throw_An_Exception_On_Creating_A_Issue_Comment_For_Non_Existing_Issue_Number() + { + _gitHubClient.Issue.Comment.Create(_owner, _repository, _issueNumber, _issueComment) + .Returns(Task.FromException(_notFoundException)); + + var ex = await Should.ThrowAsync(() => _gitHubProvider.CreateIssueCommentAsync(_owner, _repository, _issueNumber, _issueComment)).ConfigureAwait(false); + ex.Message.ShouldBe(_notFoundException.Message); + ex.InnerException.ShouldBe(_notFoundException); + } + + [Test] + public async Task Should_Throw_An_Exception_On_Creating_A_Issue_Comment() + { + _gitHubClient.Issue.Comment.Create(_owner, _repository, _issueNumber, _issueComment) + .Returns(Task.FromException(_exception)); + + var ex = await Should.ThrowAsync(() => _gitHubProvider.CreateIssueCommentAsync(_owner, _repository, _issueNumber, _issueComment)).ConfigureAwait(false); + ex.Message.ShouldBe(_exception.Message); + ex.InnerException.ShouldBe(_exception); + } + [TestCase(ItemStateFilter.Open)] [TestCase(ItemStateFilter.Closed)] [TestCase(ItemStateFilter.All)] @@ -149,11 +188,88 @@ public async Task Should_Throw_An_Exception_On_Getting_Issues_For_Non_Existent_M ex.InnerException.ShouldBe(_exception); } + [Test] + public async Task Should_Get_Issue_Comments() + { + var comments = new List(); + + _gitHubClient.Issue.Comment.GetAllForIssue(_owner, _repository, _issueNumber) + .Returns(Task.FromResult((IReadOnlyList)new List())); + + _mapper.Map>(Arg.Any()) + .Returns(comments); + + var result = await _gitHubProvider.GetIssueCommentsAsync(_owner, _repository, _issueNumber).ConfigureAwait(false); + result.ShouldBeSameAs(comments); + + await _gitHubClient.Issue.Comment.Received(1).GetAllForIssue(_owner, _repository, _issueNumber).ConfigureAwait(false); + _mapper.Received(1).Map>(Arg.Any()); + } + + [Test] + public async Task Should_Throw_An_Exception_On_Getting_Issue_Comments_For_Non_Existing_Issue_Number() + { + _gitHubClient.Issue.Comment.GetAllForIssue(_owner, _repository, _issueNumber) + .Returns(Task.FromException>(_notFoundException)); + + var ex = await Should.ThrowAsync(() => _gitHubProvider.GetIssueCommentsAsync(_owner, _repository, _issueNumber)).ConfigureAwait(false); + ex.Message.ShouldBe(_notFoundException.Message); + ex.InnerException.ShouldBe(_notFoundException); + } + + [Test] + public async Task Should_Throw_An_Exception_On_Getting_Issue_Comments() + { + _gitHubClient.Issue.Comment.GetAllForIssue(_owner, _repository, _issueNumber) + .Returns(Task.FromException>(_exception)); + + var ex = await Should.ThrowAsync(() => _gitHubProvider.GetIssueCommentsAsync(_owner, _repository, _issueNumber)).ConfigureAwait(false); + ex.Message.ShouldBe(_exception.Message); + ex.InnerException.ShouldBe(_exception); + } + // Milestones [TestCase(ItemStateFilter.Open)] [TestCase(ItemStateFilter.Closed)] [TestCase(ItemStateFilter.All)] public async Task Should_Get_Milestone(ItemStateFilter itemStateFilter) + { + var milestone = new Milestone { Title = _milestoneTitle }; + var milestones = new List { milestone }; + + _gitHubClient.Issue.Milestone.GetAllForRepository(_owner, _repository, Arg.Any()) + .Returns(Task.FromResult((IReadOnlyList)new List())); + + _mapper.Map>(Arg.Any()) + .Returns(milestones); + + var result = await _gitHubProvider.GetMilestoneAsync(_owner, _repository, _milestoneTitle, itemStateFilter).ConfigureAwait(false); + result.ShouldBeSameAs(milestone); + + await _gitHubClient.Issue.Milestone.Received(1).GetAllForRepository(_owner, _repository, Arg.Is(o => + o.State == (Octokit.ItemStateFilter)itemStateFilter)).ConfigureAwait(false); + + _mapper.ReceivedWithAnyArgs(1).Map>(default); + } + + [Test] + public async Task Should_Throw_An_Exception_On_Getting_Milestone_For_Non_Existing_Title() + { + _gitHubClient.Issue.Milestone.GetAllForRepository(_owner, _repository, Arg.Any()) + .Returns(Task.FromResult((IReadOnlyList)new List())); + + _mapper.Map>(Arg.Any()) + .Returns(new List()); + + var ex = await Should.ThrowAsync(() => _gitHubProvider.GetMilestoneAsync(_owner, _repository, _milestoneTitle)).ConfigureAwait(false); + ex.Message.ShouldBe(_notFoundMessage); + ex.InnerException.ShouldBeNull(); + } + + [TestCase(ItemStateFilter.Open)] + [TestCase(ItemStateFilter.Closed)] + [TestCase(ItemStateFilter.All)] + public async Task Should_Get_Milestones(ItemStateFilter itemStateFilter) { var milestones = new List(); @@ -173,7 +289,7 @@ await _gitHubClient.Issue.Milestone.Received(1).GetAllForRepository(_owner, _rep } [Test] - public async Task Should_Throw_An_Exception_On_Getting_Milestone() + public async Task Should_Throw_An_Exception_On_Getting_Milestones() { _gitHubClient.Issue.Milestone.GetAllForRepository(_owner, _repository, Arg.Any()) .Returns(Task.FromException>(_exception)); @@ -183,7 +299,80 @@ public async Task Should_Throw_An_Exception_On_Getting_Milestone() ex.InnerException.ShouldBe(_exception); } + [TestCase(ItemState.Closed)] + [TestCase(ItemState.Open)] + public async Task Should_Set_A_Milestone_State(ItemState itemState) + { + _gitHubClient.Issue.Milestone.Update(_owner, _repository, _milestoneNumber, Arg.Any()) + .Returns(Task.FromResult(new Octokit.Milestone())); + + await _gitHubProvider.SetMilestoneStateAsync(_owner, _repository, _milestoneNumber, itemState).ConfigureAwait(false); + + await _gitHubClient.Issue.Milestone.Received(1).Update(_owner, _repository, _milestoneNumber, Arg.Is(o => o.State == (Octokit.ItemState)itemState)).ConfigureAwait(false); + } + + [Test] + public async Task Should_Throw_An_Exception_On_Setting_Milestone_State_For_Non_Existent_Number() + { + _gitHubClient.Issue.Milestone.Update(_owner, _repository, _milestoneNumber, Arg.Any()) + .Returns(Task.FromException(_notFoundException)); + + var ex = await Should.ThrowAsync(() => _gitHubProvider.SetMilestoneStateAsync(_owner, _repository, _milestoneNumber, ItemState.Closed)).ConfigureAwait(false); + ex.Message.ShouldBe(_notFoundException.Message); + ex.InnerException.ShouldBeSameAs(_notFoundException); + } + + [Test] + public async Task Should_Throw_An_Exception_On_Setting_Milestone_State() + { + _gitHubClient.Issue.Milestone.Update(_owner, _repository, _milestoneNumber, Arg.Any()) + .Returns(Task.FromException(_exception)); + + var ex = await Should.ThrowAsync(() => _gitHubProvider.SetMilestoneStateAsync(_owner, _repository, _milestoneNumber, ItemState.Closed)).ConfigureAwait(false); + ex.Message.ShouldBe(_exception.Message); + ex.InnerException.ShouldBeSameAs(_exception); + } + // Releases + [Test] + public async Task Should_Delete_A_Release() + { + var id = 1; + + _gitHubClient.Repository.Release.Delete(_owner, _repository, id) + .Returns(Task.CompletedTask); + + await _gitHubProvider.DeleteReleaseAsync(_owner, _repository, id).ConfigureAwait(false); + + await _gitHubClient.Repository.Release.Received(1).Delete(_owner, _repository, id).ConfigureAwait(false); + } + + [Test] + public async Task Should_Throw_An_Exception_On_Deleting_Release_For_Non_Existent_Id() + { + var id = 1; + + _gitHubClient.Repository.Release.Delete(_owner, _repository, id) + .Returns(Task.FromException(_notFoundException)); + + var ex = await Should.ThrowAsync(() => _gitHubProvider.DeleteReleaseAsync(_owner, _repository, id)).ConfigureAwait(false); + ex.Message.ShouldBe(_notFoundException.Message); + ex.InnerException.ShouldBeSameAs(_notFoundException); + } + + [Test] + public async Task Should_Throw_An_Exception_On_Deleting_Release() + { + var id = 1; + + _gitHubClient.Repository.Release.Delete(_owner, _repository, id) + .Returns(Task.FromException(_exception)); + + var ex = await Should.ThrowAsync(() => _gitHubProvider.DeleteReleaseAsync(_owner, _repository, id)).ConfigureAwait(false); + ex.Message.ShouldBe(_exception.Message); + ex.InnerException.ShouldBeSameAs(_exception); + } + [Test] public async Task Should_Get_A_Release() { diff --git a/Source/GitReleaseManager.Core.Tests/VcsServiceTests.cs b/Source/GitReleaseManager.Core.Tests/VcsServiceTests.cs index 921ee1a2..f18c21eb 100644 --- a/Source/GitReleaseManager.Core.Tests/VcsServiceTests.cs +++ b/Source/GitReleaseManager.Core.Tests/VcsServiceTests.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using AutoMapper; using GitReleaseManager.Core.Configuration; @@ -9,6 +10,9 @@ using Octokit; using Serilog; using Shouldly; +using ItemState = GitReleaseManager.Core.Model.ItemState; +using ItemStateFilter = GitReleaseManager.Core.Model.ItemStateFilter; +using Milestone = GitReleaseManager.Core.Model.Milestone; using NotFoundException = GitReleaseManager.Core.Exceptions.NotFoundException; using Release = GitReleaseManager.Core.Model.Release; @@ -18,6 +22,8 @@ public class VcsServiceTests { private const string _owner = "owner"; private const string _repository = "repository"; + private const int _milestoneNumber = 1; + private const string _milestoneTitle = "0.1.0"; private const string _tagName = "0.1.0"; private readonly NotFoundException _notFoundException = new NotFoundException("NotFound"); @@ -44,18 +50,157 @@ public void Setup() _vcsService = new VcsService(_vcsProvider, _gitHubClient, _logger, _mapper, _releaseNotesBuilder, _releaseNotesExporter, _configuration); } - [TestCase(null)] - [TestCase(_tagName)] - public async Task Should_Get_Release_Notes(string tagName) + [Test] + public async Task Should_Close_A_Milestone() + { + var milestone = new Milestone { Number = _milestoneNumber }; + + _vcsProvider.GetMilestoneAsync(_owner, _repository, _milestoneTitle, ItemStateFilter.Open) + .Returns(Task.FromResult(milestone)); + + _vcsProvider.SetMilestoneStateAsync(_owner, _repository, milestone.Number, ItemState.Closed) + .Returns(Task.CompletedTask); + + await _vcsService.CloseMilestone(_owner, _repository, _milestoneTitle).ConfigureAwait(false); + + await _vcsProvider.Received(1).GetMilestoneAsync(_owner, _repository, _milestoneTitle, ItemStateFilter.Open).ConfigureAwait(false); + await _vcsProvider.Received(1).SetMilestoneStateAsync(_owner, _repository, milestone.Number, ItemState.Closed).ConfigureAwait(false); + } + + [Test] + public async Task Should_Log_An_Error_On_Closing_When_A_Milestone_Cannot_Be_Found() + { + _vcsProvider.GetMilestoneAsync(_owner, _repository, _milestoneTitle, ItemStateFilter.Open) + .Returns(Task.FromException(_notFoundException)); + + await _vcsService.CloseMilestone(_owner, _repository, _milestoneTitle).ConfigureAwait(false); + + await _vcsProvider.Received(1).GetMilestoneAsync(_owner, _repository, _milestoneTitle, ItemStateFilter.Open).ConfigureAwait(false); + await _vcsProvider.DidNotReceive().SetMilestoneStateAsync(_owner, _repository, _milestoneNumber, ItemState.Closed).ConfigureAwait(false); + _logger.Received(1).Error(Arg.Any(), _milestoneTitle); + } + + [Test] + public async Task Should_Open_A_Milestone() + { + var milestone = new Milestone { Number = _milestoneNumber }; + + _vcsProvider.GetMilestoneAsync(_owner, _repository, _milestoneTitle, ItemStateFilter.Closed) + .Returns(Task.FromResult(milestone)); + + _vcsProvider.SetMilestoneStateAsync(_owner, _repository, milestone.Number, ItemState.Open) + .Returns(Task.CompletedTask); + + await _vcsService.OpenMilestone(_owner, _repository, _milestoneTitle).ConfigureAwait(false); + + await _vcsProvider.Received(1).GetMilestoneAsync(_owner, _repository, _milestoneTitle, ItemStateFilter.Closed).ConfigureAwait(false); + await _vcsProvider.Received(1).SetMilestoneStateAsync(_owner, _repository, milestone.Number, ItemState.Open).ConfigureAwait(false); + _logger.Received(2).Verbose(Arg.Any(), _milestoneTitle, _owner, _repository); + } + + [Test] + public async Task Should_Log_An_Error_On_Opening_When_A_Milestone_Cannot_Be_Found() + { + _vcsProvider.GetMilestoneAsync(_owner, _repository, _milestoneTitle, ItemStateFilter.Closed) + .Returns(Task.FromException(_notFoundException)); + + await _vcsService.OpenMilestone(_owner, _repository, _milestoneTitle).ConfigureAwait(false); + + await _vcsProvider.Received(1).GetMilestoneAsync(_owner, _repository, _milestoneTitle, ItemStateFilter.Closed).ConfigureAwait(false); + await _vcsProvider.DidNotReceive().SetMilestoneStateAsync(_owner, _repository, _milestoneNumber, ItemState.Open).ConfigureAwait(false); + _logger.Received(1).Error(Arg.Any(), _milestoneTitle); + } + + // ---------------------------------------------------------------------------------------------------- + + [Test] + public async Task Should_Delete_A_Draft_Release() + { + var release = new Release + { + Id = 1, + Draft = true, + }; + + _vcsProvider.GetReleaseAsync(_owner, _repository, _tagName) + .Returns(Task.FromResult(release)); + + _vcsProvider.DeleteReleaseAsync(_owner, _repository, release.Id) + .Returns(Task.CompletedTask); + + await _vcsService.DiscardRelease(_owner, _repository, _tagName).ConfigureAwait(false); + + await _vcsProvider.Received(1).GetReleaseAsync(_owner, _repository, _tagName).ConfigureAwait(false); + await _vcsProvider.Received(1).DeleteReleaseAsync(_owner, _repository, release.Id).ConfigureAwait(false); + } + + [Test] + public async Task Should_Not_Delete_A_Published_Release() { + var release = new Release { Id = 1 }; + + _vcsProvider.GetReleaseAsync(_owner, _repository, _tagName) + .Returns(Task.FromResult(release)); + + await _vcsService.DiscardRelease(_owner, _repository, _tagName).ConfigureAwait(false); + + await _vcsProvider.Received(1).GetReleaseAsync(_owner, _repository, _tagName).ConfigureAwait(false); + await _vcsProvider.DidNotReceive().DeleteReleaseAsync(_owner, _repository, release.Id).ConfigureAwait(false); + _logger.Received(1).Warning(Arg.Any(), _tagName); + } + + [Test] + public async Task Should_Log_An_Error_On_Deleting_A_Release_For_Non_Existing_Tag() + { + _vcsProvider.GetReleaseAsync(_owner, _repository, _tagName) + .Returns(Task.FromException(_notFoundException)); + + await _vcsService.DiscardRelease(_owner, _repository, _tagName).ConfigureAwait(false); + + await _vcsProvider.Received().GetReleaseAsync(_owner, _repository, _tagName).ConfigureAwait(false); + await _vcsProvider.DidNotReceiveWithAnyArgs().DeleteReleaseAsync(_owner, _repository, default).ConfigureAwait(false); + _logger.Received(1).Error(Arg.Any(), _tagName); + } + + [Test] + public async Task Should_Get_Release_Notes() + { + var releases = Enumerable.Empty(); + var releaseNotes = "Release Notes"; + + _vcsProvider.GetReleasesAsync(_owner, _repository) + .Returns(Task.FromResult(releases)); + + _releaseNotesExporter.ExportReleaseNotes(Arg.Any>()) + .Returns(releaseNotes); + + var result = await _vcsService.ExportReleases(_owner, _repository, null).ConfigureAwait(false); + result.ShouldBeSameAs(releaseNotes); + + await _vcsProvider.DidNotReceive().GetReleaseAsync(Arg.Any(), Arg.Any(), Arg.Any()).ConfigureAwait(false); + await _vcsProvider.Received(1).GetReleasesAsync(_owner, _repository).ConfigureAwait(false); + _logger.Received(1).Verbose(Arg.Any(), _owner, _repository); + _releaseNotesExporter.Received(1).ExportReleaseNotes(Arg.Any>()); + } + + [Test] + public async Task Should_Get_Release_Notes_For_A_Tag() + { + var release = new Release(); var releaseNotes = "Release Notes"; + _vcsProvider.GetReleaseAsync(_owner, _repository, _tagName) + .Returns(Task.FromResult(release)); + _releaseNotesExporter.ExportReleaseNotes(Arg.Any>()) .Returns(releaseNotes); - var result = await _vcsService.ExportReleases(_owner, _repository, tagName).ConfigureAwait(false); + var result = await _vcsService.ExportReleases(_owner, _repository, _tagName).ConfigureAwait(false); result.ShouldBeSameAs(releaseNotes); + await _vcsProvider.Received(1).GetReleaseAsync(_owner, _repository, _tagName).ConfigureAwait(false); + await _vcsProvider.DidNotReceive().GetReleasesAsync(Arg.Any(), Arg.Any()).ConfigureAwait(false); + _logger.Received(1).Verbose(Arg.Any(), _owner, _repository, _tagName); _releaseNotesExporter.Received(1).ExportReleaseNotes(Arg.Any>()); } @@ -74,6 +219,7 @@ public async Task Should_Get_Default_Release_Notes_For_Non_Existent_Tag() result.ShouldBeSameAs(releaseNotes); await _vcsProvider.Received(1).GetReleaseAsync(_owner, _repository, _tagName).ConfigureAwait(false); + _logger.Received(1).Error(Arg.Any(), _tagName); _releaseNotesExporter.Received(1).ExportReleaseNotes(Arg.Any>()); } } diff --git a/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs b/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs index 5b4d331e..883ccd18 100644 --- a/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs +++ b/Source/GitReleaseManager.Tests/ReleaseNotesBuilderTests.cs @@ -13,7 +13,6 @@ namespace GitReleaseManager.Tests using System; using System.Linq; using ApprovalTests; - using GitReleaseManager.Core; using GitReleaseManager.Core.Configuration; using GitReleaseManager.Core.Helpers; using GitReleaseManager.Core.Model; @@ -206,7 +205,7 @@ private static Issue CreateIssue(int number, params string[] labels) { return new Issue { - Number = number.ToString(), + Number = number, Labels = labels.Select(l => new Label { Name = l }).ToList(), HtmlUrl = "http://example.com/" + number, Title = "Issue " + number, diff --git a/Source/GitReleaseManager.Tests/VcsServiceMock.cs b/Source/GitReleaseManager.Tests/VcsServiceMock.cs index c771422c..a1cb6694 100644 --- a/Source/GitReleaseManager.Tests/VcsServiceMock.cs +++ b/Source/GitReleaseManager.Tests/VcsServiceMock.cs @@ -41,7 +41,7 @@ public Task CreateReleaseFromInputFile(string owner, string repository, throw new System.NotImplementedException(); } - public Task DiscardRelease(string owner, string repository, string name) + public Task DiscardRelease(string owner, string repository, string tagName) { throw new System.NotImplementedException(); } From e6dca145a6039563121bd4094a7a98fd2b584918 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Sat, 8 Aug 2020 12:12:22 +0200 Subject: [PATCH 066/181] (GH-181) Update build script --- recipe.cake | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/recipe.cake b/recipe.cake index 1984cdf4..8d86d0f0 100644 --- a/recipe.cake +++ b/recipe.cake @@ -24,11 +24,12 @@ BuildParameters.PrintParameters(Context); ToolSettings.SetToolSettings(context: Context, dupFinderExcludePattern: new string[] { - BuildParameters.RootDirectoryPath + "/Source/GitReleaseManager.Tests/*.cs", - BuildParameters.RootDirectoryPath + "/Source/GitReleaseManager.IntegrationTests/*.cs", + BuildParameters.RootDirectoryPath + "/Source/GitReleaseManager.Core.Tests/**/*.cs", + BuildParameters.RootDirectoryPath + "/Source/GitReleaseManager.Tests/**/*.cs", + BuildParameters.RootDirectoryPath + "/Source/GitReleaseManager.IntegrationTests/**/*.cs", BuildParameters.RootDirectoryPath + "/Source/GitReleaseManager/AutoMapperConfiguration.cs", "**/*.AssemblyInfo.cs" }, - testCoverageFilter: "+[GitReleaseManager*]* -[GitReleaseManager.Tests*]*", + testCoverageFilter: "+[GitReleaseManager*]* -[GitReleaseManager.Core.Tests*]* -[GitReleaseManager.Tests*]*", testCoverageExcludeByAttribute: "*.ExcludeFromCodeCoverage*", testCoverageExcludeByFile: "*/*Designer.cs;*/*.g.cs;*/*.g.i.cs"); From 43ec9dbcc1d3532957baf49c6325fa524f504208 Mon Sep 17 00:00:00 2001 From: Artur Kordowski Date: Sun, 9 Aug 2020 21:00:34 +0200 Subject: [PATCH 067/181] (GH-181) Refactor VcsService to remove unnecessary dependencies --- Source/GitReleaseManager.Cli/Program.cs | 18 +- .../Exceptions/ForbiddenException.cs | 28 ++ .../Exceptions/InvalidStateException.cs | 35 --- Source/GitReleaseManager/IVcsService.cs | 18 +- Source/GitReleaseManager/Model/Label.cs | 13 + Source/GitReleaseManager/Model/RateLimit.cs | 22 ++ Source/GitReleaseManager/Model/Release.cs | 10 +- .../GitReleaseManager/Model/ReleaseAsset.cs | 9 + .../Model/ReleaseAssetUpload.cs | 25 ++ .../Provider/GitHubProvider.cs | 168 ++++++++++- .../Provider/IVcsProvider.cs | 18 ++ Source/GitReleaseManager/VcsService.cs | 277 +++++++++--------- 12 files changed, 438 insertions(+), 203 deletions(-) create mode 100644 Source/GitReleaseManager/Exceptions/ForbiddenException.cs delete mode 100644 Source/GitReleaseManager/Exceptions/InvalidStateException.cs create mode 100644 Source/GitReleaseManager/Model/RateLimit.cs create mode 100644 Source/GitReleaseManager/Model/ReleaseAsset.cs create mode 100644 Source/GitReleaseManager/Model/ReleaseAssetUpload.cs diff --git a/Source/GitReleaseManager.Cli/Program.cs b/Source/GitReleaseManager.Cli/Program.cs index b3f3633d..d68a1128 100644 --- a/Source/GitReleaseManager.Cli/Program.cs +++ b/Source/GitReleaseManager.Cli/Program.cs @@ -198,12 +198,12 @@ private static async Task CreateReleaseAsync(CreateSubOptions subOptions) releaseName = subOptions.Milestone; } - release = await _vcsService.CreateReleaseFromMilestone(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone, releaseName, subOptions.TargetCommitish, subOptions.AssetPaths, subOptions.Prerelease).ConfigureAwait(false); + release = await _vcsService.CreateReleaseFromMilestoneAsync(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone, releaseName, subOptions.TargetCommitish, subOptions.AssetPaths, subOptions.Prerelease).ConfigureAwait(false); } else { Log.Verbose("No milestone was specified, switching to release creating from input file"); - release = await _vcsService.CreateReleaseFromInputFile(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Name, subOptions.InputFilePath, subOptions.TargetCommitish, subOptions.AssetPaths, subOptions.Prerelease).ConfigureAwait(false); + release = await _vcsService.CreateReleaseFromInputFileAsync(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Name, subOptions.InputFilePath, subOptions.TargetCommitish, subOptions.AssetPaths, subOptions.Prerelease).ConfigureAwait(false); } Log.Information("Drafted release is available at:\n{HtmlUrl}", release.HtmlUrl); @@ -216,7 +216,7 @@ private static async Task DiscardReleaseAsync(DiscardSubOptions subOptions) Log.Information("Discarding release {Milestone}", subOptions.Milestone); _vcsService = GetVcsService(); - await _vcsService.DiscardRelease(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false); + await _vcsService.DiscardReleaseAsync(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false); return 0; } @@ -226,7 +226,7 @@ private static async Task AddAssetsAsync(AddAssetSubOptions subOptions) Log.Information("Uploading assets"); _vcsService = GetVcsService(); - await _vcsService.AddAssets(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName, subOptions.AssetPaths).ConfigureAwait(false); + await _vcsService.AddAssetsAsync(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName, subOptions.AssetPaths).ConfigureAwait(false); return 0; } @@ -236,7 +236,7 @@ private static async Task CloseMilestoneAsync(CloseSubOptions subOptions) Log.Information("Closing milestone {Milestone}", subOptions.Milestone); _vcsService = GetVcsService(); - await _vcsService.CloseMilestone(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false); + await _vcsService.CloseMilestoneAsync(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false); return 0; } @@ -246,7 +246,7 @@ private static async Task OpenMilestoneAsync(OpenSubOptions subOptions) Log.Information("Opening milestone {Milestone}", subOptions.Milestone); _vcsService = GetVcsService(); - await _vcsService.OpenMilestone(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false); + await _vcsService.OpenMilestoneAsync(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false); return 0; } @@ -255,7 +255,7 @@ private static async Task PublishReleaseAsync(PublishSubOptions subOptions) { _vcsService = GetVcsService(); - await _vcsService.PublishRelease(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName).ConfigureAwait(false); + await _vcsService.PublishReleaseAsync(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName).ConfigureAwait(false); return 0; } @@ -264,7 +264,7 @@ private static async Task ExportReleasesAsync(ExportSubOptions subOptions) Log.Information("Exporting release {TagName}", subOptions.TagName); _vcsService = GetVcsService(); - var releasesMarkdown = await _vcsService.ExportReleases(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName).ConfigureAwait(false); + var releasesMarkdown = await _vcsService.ExportReleasesAsync(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName).ConfigureAwait(false); using (var sw = new StreamWriter(File.Open(subOptions.FileOutputPath, System.IO.FileMode.OpenOrCreate))) { @@ -295,7 +295,7 @@ private static async Task CreateLabelsAsync(LabelSubOptions subOptions) Log.Information("Creating standard labels"); _vcsService = GetVcsService(); - await _vcsService.CreateLabels(subOptions.RepositoryOwner, subOptions.RepositoryName).ConfigureAwait(false); + await _vcsService.CreateLabelsAsync(subOptions.RepositoryOwner, subOptions.RepositoryName).ConfigureAwait(false); return 0; } diff --git a/Source/GitReleaseManager/Exceptions/ForbiddenException.cs b/Source/GitReleaseManager/Exceptions/ForbiddenException.cs new file mode 100644 index 00000000..f2c55512 --- /dev/null +++ b/Source/GitReleaseManager/Exceptions/ForbiddenException.cs @@ -0,0 +1,28 @@ +using System; +using System.Runtime.Serialization; + +namespace GitReleaseManager.Core.Exceptions +{ + [Serializable] + public class ForbiddenException : Exception + { + public ForbiddenException() + { + } + + public ForbiddenException(string message) + : base(message) + { + } + + public ForbiddenException(string message, Exception inner) + : base(message, inner) + { + } + + protected ForbiddenException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/Source/GitReleaseManager/Exceptions/InvalidStateException.cs b/Source/GitReleaseManager/Exceptions/InvalidStateException.cs deleted file mode 100644 index 901fc24e..00000000 --- a/Source/GitReleaseManager/Exceptions/InvalidStateException.cs +++ /dev/null @@ -1,35 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright (c) 2015 - Present - GitTools Contributors -// -// ----------------------------------------------------------------------- - -namespace GitReleaseManager.Core.Exceptions -{ - using System; - - [Serializable] - public class InvalidStateException : Exception - { - public InvalidStateException() - { - } - - public InvalidStateException(string message) - : base(message) - { - } - - public InvalidStateException(string message, Exception inner) - : base(message, inner) - { - } - - protected InvalidStateException( - System.Runtime.Serialization.SerializationInfo info, - System.Runtime.Serialization.StreamingContext context) - : base(info, context) - { - } - } -} \ No newline at end of file diff --git a/Source/GitReleaseManager/IVcsService.cs b/Source/GitReleaseManager/IVcsService.cs index 378bb4ef..415378e2 100644 --- a/Source/GitReleaseManager/IVcsService.cs +++ b/Source/GitReleaseManager/IVcsService.cs @@ -12,22 +12,22 @@ namespace GitReleaseManager.Core public interface IVcsService { - Task CreateReleaseFromMilestone(string owner, string repository, string milestone, string releaseName, string targetCommitish, IList assets, bool prerelease); + Task CreateReleaseFromMilestoneAsync(string owner, string repository, string milestone, string releaseName, string targetCommitish, IList assets, bool prerelease); - Task CreateReleaseFromInputFile(string owner, string repository, string name, string inputFilePath, string targetCommitish, IList assets, bool prerelease); + Task CreateReleaseFromInputFileAsync(string owner, string repository, string name, string inputFilePath, string targetCommitish, IList assets, bool prerelease); - Task DiscardRelease(string owner, string repository, string tagName); + Task DiscardReleaseAsync(string owner, string repository, string tagName); - Task AddAssets(string owner, string repository, string tagName, IList assets); + Task AddAssetsAsync(string owner, string repository, string tagName, IList assets); - Task ExportReleases(string owner, string repository, string tagName); + Task ExportReleasesAsync(string owner, string repository, string tagName); - Task CloseMilestone(string owner, string repository, string milestoneTitle); + Task CloseMilestoneAsync(string owner, string repository, string milestoneTitle); - Task OpenMilestone(string owner, string repository, string milestoneTitle); + Task OpenMilestoneAsync(string owner, string repository, string milestoneTitle); - Task PublishRelease(string owner, string repository, string tagName); + Task PublishReleaseAsync(string owner, string repository, string tagName); - Task CreateLabels(string owner, string repository); + Task CreateLabelsAsync(string owner, string repository); } } \ No newline at end of file diff --git a/Source/GitReleaseManager/Model/Label.cs b/Source/GitReleaseManager/Model/Label.cs index 286d31e9..01988836 100644 --- a/Source/GitReleaseManager/Model/Label.cs +++ b/Source/GitReleaseManager/Model/Label.cs @@ -8,6 +8,19 @@ namespace GitReleaseManager.Core.Model { public sealed class Label { + /// + /// Name of the label (required). + /// public string Name { get; set; } + + /// + /// Color of the label (required). + /// + public string Color { get; set; } + + /// + /// A short description of the label (optional). + /// + public string Description { get; set; } } } \ No newline at end of file diff --git a/Source/GitReleaseManager/Model/RateLimit.cs b/Source/GitReleaseManager/Model/RateLimit.cs new file mode 100644 index 00000000..c990be0b --- /dev/null +++ b/Source/GitReleaseManager/Model/RateLimit.cs @@ -0,0 +1,22 @@ +using System; + +namespace GitReleaseManager.Core.Model +{ + public class RateLimit + { + /// + /// The maximum number of requests that the consumer is permitted to make per hour. + /// + public int Limit { get; set; } + + /// + /// The number of requests remaining in the current rate limit window. + /// + public int Remaining { get; set; } + + /// + /// The date and time at which the current rate limit window resets. + /// + public DateTimeOffset Reset { get; set; } + } +} \ No newline at end of file diff --git a/Source/GitReleaseManager/Model/Release.cs b/Source/GitReleaseManager/Model/Release.cs index 4ca80e45..2f835225 100644 --- a/Source/GitReleaseManager/Model/Release.cs +++ b/Source/GitReleaseManager/Model/Release.cs @@ -7,13 +7,15 @@ namespace GitReleaseManager.Core.Model { using System; - + using System.Collections.Generic; public sealed class Release { public int Id { get; set; } public string Body { get; set; } + public string Name { get; set; } + public string TagName { get; set; } public DateTimeOffset CreatedAt { get; set; } @@ -21,5 +23,11 @@ public sealed class Release public string HtmlUrl { get; set; } public bool Draft { get; set; } + + public bool Prerelease { get; set; } + + public string TargetCommitish { get; set; } + + public IReadOnlyList Assets { get; set; } } } \ No newline at end of file diff --git a/Source/GitReleaseManager/Model/ReleaseAsset.cs b/Source/GitReleaseManager/Model/ReleaseAsset.cs new file mode 100644 index 00000000..c138cc3e --- /dev/null +++ b/Source/GitReleaseManager/Model/ReleaseAsset.cs @@ -0,0 +1,9 @@ +namespace GitReleaseManager.Core.Model +{ + public class ReleaseAsset + { + public int Id { get; set; } + + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/Source/GitReleaseManager/Model/ReleaseAssetUpload.cs b/Source/GitReleaseManager/Model/ReleaseAssetUpload.cs new file mode 100644 index 00000000..53ccec63 --- /dev/null +++ b/Source/GitReleaseManager/Model/ReleaseAssetUpload.cs @@ -0,0 +1,25 @@ +using System.IO; + +namespace GitReleaseManager.Core.Model +{ + public class ReleaseAssetUpload + { + /// + /// Gets or sets the type of the content. + /// + /// The type of the content. + public string ContentType { get; set; } + + /// + /// Gets or sets the name of the file. + /// + /// The name of the file. + public string FileName { get; set; } + + /// + /// Gets or sets the raw data. + /// + /// The raw data. + public Stream RawData { get; set; } + } +} \ No newline at end of file diff --git a/Source/GitReleaseManager/Provider/GitHubProvider.cs b/Source/GitReleaseManager/Provider/GitHubProvider.cs index e8fa5107..106da519 100644 --- a/Source/GitReleaseManager/Provider/GitHubProvider.cs +++ b/Source/GitReleaseManager/Provider/GitHubProvider.cs @@ -9,9 +9,12 @@ using IssueComment = GitReleaseManager.Core.Model.IssueComment; using ItemState = GitReleaseManager.Core.Model.ItemState; using ItemStateFilter = GitReleaseManager.Core.Model.ItemStateFilter; +using Label = GitReleaseManager.Core.Model.Label; using Milestone = GitReleaseManager.Core.Model.Milestone; using NotFoundException = GitReleaseManager.Core.Exceptions.NotFoundException; +using RateLimit = GitReleaseManager.Core.Model.RateLimit; using Release = GitReleaseManager.Core.Model.Release; +using ReleaseAssetUpload = GitReleaseManager.Core.Model.ReleaseAssetUpload; namespace GitReleaseManager.Core.Provider { @@ -28,6 +31,41 @@ public GitHubProvider(IGitHubClient gitHubClient, IMapper mapper) _mapper = mapper; } + public async Task DeleteAssetAsync(string owner, string repository, int id) + { + try + { + await _gitHubClient.Repository.Release.DeleteAsset(owner, repository, id).ConfigureAwait(false); + } + catch (Octokit.NotFoundException ex) + { + throw new NotFoundException(ex.Message, ex); + } + catch (Exception ex) + { + throw new ApiException(ex.Message, ex); + } + } + + public async Task UploadAssetAsync(Release release, ReleaseAssetUpload releaseAssetUpload) + { + try + { + var octokitRelease = _mapper.Map(release); + var octokitReleaseAssetUpload = _mapper.Map(releaseAssetUpload); + + await _gitHubClient.Repository.Release.UploadAsset(octokitRelease, octokitReleaseAssetUpload).ConfigureAwait(false); + } + catch (Octokit.NotFoundException ex) + { + throw new NotFoundException(ex.Message, ex); + } + catch (Exception ex) + { + throw new ApiException(ex.Message, ex); + } + } + public async Task GetCommitsCount(string owner, string repository, string @base, string head) { try @@ -53,16 +91,9 @@ public string GetCommitsUrl(string owner, string repository, string head, string Ensure.IsNotNullOrWhiteSpace(repository, nameof(repository)); Ensure.IsNotNullOrWhiteSpace(head, nameof(head)); - string url; - - if (string.IsNullOrWhiteSpace(@base)) - { - url = string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/commits/{2}", owner, repository, head); - } - else - { - url = string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/compare/{2}...{3}", owner, repository, @base, head); - } + string url = string.IsNullOrWhiteSpace(@base) + ? string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/commits/{2}", owner, repository, head) + : string.Format(CultureInfo.InvariantCulture, "https://github.com/{0}/{1}/compare/{2}...{3}", owner, repository, @base, head); return url; } @@ -121,6 +152,50 @@ public async Task> GetIssueCommentsAsync(string owner, } } + public async Task CreateLabelAsync(string owner, string repository, Label label) + { + try + { + var newLabel = _mapper.Map(label); + + await _gitHubClient.Issue.Labels.Create(owner, repository, newLabel).ConfigureAwait(false); + } + catch (Exception ex) + { + throw new ApiException(ex.Message, ex); + } + } + + public async Task DeleteLabelAsync(string owner, string repository, string labelName) + { + try + { + await _gitHubClient.Issue.Labels.Delete(owner, repository, labelName).ConfigureAwait(false); + } + catch (Octokit.NotFoundException ex) + { + throw new NotFoundException(ex.Message, ex); + } + catch (Exception ex) + { + throw new ApiException(ex.Message, ex); + } + } + + public async Task> GetLabelsAsync(string owner, string repository) + { + try + { + var labels = await _gitHubClient.Issue.Labels.GetAllForRepository(owner, repository).ConfigureAwait(false); + + return _mapper.Map>(labels); + } + catch (Exception ex) + { + throw new ApiException(ex.Message, ex); + } + } + public async Task GetMilestoneAsync(string owner, string repository, string milestoneTitle, ItemStateFilter itemStateFilter = ItemStateFilter.All) { try @@ -173,6 +248,22 @@ public async Task SetMilestoneStateAsync(string owner, string repository, int mi } } + public async Task CreateReleaseAsync(string owner, string repository, Release release) + { + try + { + var newRelease = _mapper.Map(release); + + var octokitRelease = await _gitHubClient.Repository.Release.Create(owner, repository, newRelease).ConfigureAwait(false); + + return _mapper.Map(octokitRelease); + } + catch (Exception ex) + { + throw new ApiException(ex.Message, ex); + } + } + public async Task DeleteReleaseAsync(string owner, string repository, int id) { try @@ -221,5 +312,62 @@ public async Task> GetReleasesAsync(string owner, string re throw new ApiException(ex.Message, ex); } } + + public async Task PublishReleaseAsync(string owner, string repository, string tagName, int releaseId) + { + try + { + var update = new ReleaseUpdate { Draft = false, TagName = tagName }; + await _gitHubClient.Repository.Release.Edit(owner, repository, releaseId, update).ConfigureAwait(false); + } + catch (Octokit.NotFoundException ex) + { + throw new NotFoundException(ex.Message, ex); + } + catch (Exception ex) + { + throw new ApiException(ex.Message, ex); + } + } + + public async Task UpdateReleaseAsync(string owner, string repository, Release release) + { + try + { + var update = new ReleaseUpdate + { + Body = release.Body, + Draft = release.Draft, + Name = release.Name, + Prerelease = release.Prerelease, + TagName = release.TagName, + TargetCommitish = release.TargetCommitish, + }; + + await _gitHubClient.Repository.Release.Edit(owner, repository, release.Id, update).ConfigureAwait(false); + } + catch (Octokit.NotFoundException ex) + { + throw new NotFoundException(ex.Message, ex); + } + catch (Exception ex) + { + throw new ApiException(ex.Message, ex); + } + } + + public RateLimit GetRateLimit() + { + try + { + var rateLimit = _gitHubClient.GetLastApiInfo().RateLimit; + + return _mapper.Map(rateLimit); + } + catch (Exception ex) + { + throw new ApiException(ex.Message, ex); + } + } } } \ No newline at end of file diff --git a/Source/GitReleaseManager/Provider/IVcsProvider.cs b/Source/GitReleaseManager/Provider/IVcsProvider.cs index be2f1a32..f8b4de76 100644 --- a/Source/GitReleaseManager/Provider/IVcsProvider.cs +++ b/Source/GitReleaseManager/Provider/IVcsProvider.cs @@ -6,6 +6,10 @@ namespace GitReleaseManager.Core.Provider { public interface IVcsProvider { + Task DeleteAssetAsync(string owner, string repository, int id); + + Task UploadAssetAsync(Release release, ReleaseAssetUpload releaseAssetUpload); + Task GetCommitsCount(string owner, string repository, string @base, string head); string GetCommitsUrl(string owner, string repository, string head, string @base = null); @@ -16,16 +20,30 @@ public interface IVcsProvider Task> GetIssueCommentsAsync(string owner, string repository, int issueNumber); + Task CreateLabelAsync(string owner, string repository, Label label); + + Task DeleteLabelAsync(string owner, string repository, string labelName); + + Task> GetLabelsAsync(string owner, string repository); + Task GetMilestoneAsync(string owner, string repository, string milestoneTitle, ItemStateFilter itemStateFilter = ItemStateFilter.All); Task> GetMilestonesAsync(string owner, string repository, ItemStateFilter itemStateFilter = ItemStateFilter.All); Task SetMilestoneStateAsync(string owner, string repository, int milestoneNumber, ItemState itemState); + Task CreateReleaseAsync(string owner, string repository, Release release); + Task DeleteReleaseAsync(string owner, string repository, int id); Task GetReleaseAsync(string owner, string repository, string tagName); Task> GetReleasesAsync(string owner, string repository); + + Task PublishReleaseAsync(string owner, string repository, string tagName, int releaseId); + + Task UpdateReleaseAsync(string owner, string repository, Release release); + + RateLimit GetRateLimit(); } } \ No newline at end of file diff --git a/Source/GitReleaseManager/VcsService.cs b/Source/GitReleaseManager/VcsService.cs index 47aa8538..4db0b1f0 100644 --- a/Source/GitReleaseManager/VcsService.cs +++ b/Source/GitReleaseManager/VcsService.cs @@ -14,91 +14,91 @@ namespace GitReleaseManager.Core using System.Text; using System.Threading; using System.Threading.Tasks; - using AutoMapper; using GitReleaseManager.Core.Configuration; + using GitReleaseManager.Core.Exceptions; using GitReleaseManager.Core.Extensions; + using GitReleaseManager.Core.Model; using GitReleaseManager.Core.Provider; using GitReleaseManager.Core.ReleaseNotes; - using Octokit; using Serilog; - using Milestone = GitReleaseManager.Core.Model.Milestone; - using NotFoundException = GitReleaseManager.Core.Exceptions.NotFoundException; - using Release = GitReleaseManager.Core.Model.Release; public class VcsService : IVcsService { + private const string _unableToFoundMilestoneMessage = "Unable to find a {State} milestone with title '{Title}' on '{Owner}/{Repository}'"; + private const string _unableToFoundReleaseMessage = "Unable to find a release with tag '{TagName}' on '{Owner}/{Repository}'"; + private readonly IVcsProvider _vcsProvider; - private readonly IGitHubClient _gitHubClient; private readonly ILogger _logger; - private readonly IMapper _mapper; private readonly IReleaseNotesBuilder _releaseNotesBuilder; private readonly IReleaseNotesExporter _releaseNotesExporter; private readonly Config _configuration; - public VcsService(IVcsProvider vcsProvider, IGitHubClient gitHubClient, ILogger logger, IMapper mapper, IReleaseNotesBuilder releaseNotesBuilder, IReleaseNotesExporter releaseNotesExporter, Config configuration) + public VcsService(IVcsProvider vcsProvider, ILogger logger, IReleaseNotesBuilder releaseNotesBuilder, IReleaseNotesExporter releaseNotesExporter, Config configuration) { _vcsProvider = vcsProvider; - _gitHubClient = gitHubClient; _logger = logger; - _mapper = mapper; _releaseNotesBuilder = releaseNotesBuilder; _releaseNotesExporter = releaseNotesExporter; _configuration = configuration; } - public async Task CreateReleaseFromMilestone(string owner, string repository, string milestone, string releaseName, string targetCommitish, IList assets, bool prerelease) + public async Task CreateReleaseFromMilestoneAsync(string owner, string repository, string milestone, string releaseName, string targetCommitish, IList assets, bool prerelease) { - var release = await GetReleaseFromTagNameAsync(owner, repository, milestone).ConfigureAwait(false); - var result = await _releaseNotesBuilder.BuildReleaseNotes(owner, repository, milestone).ConfigureAwait(false); + var releaseNotes = await _releaseNotesBuilder.BuildReleaseNotes(owner, repository, milestone).ConfigureAwait(false); + var release = await CreateRelease(owner, repository, releaseName, milestone, releaseNotes, prerelease, targetCommitish, assets).ConfigureAwait(false); - if (release == null) - { - var releaseUpdate = CreateNewRelease(releaseName, milestone, result, prerelease, targetCommitish); - _logger.Verbose("Creating new release on '{Owner}/{Repository}'", owner, repository); - _logger.Debug("{@ReleaseUpdate}", releaseUpdate); - release = await _gitHubClient.Repository.Release.Create(owner, repository, releaseUpdate).ConfigureAwait(false); - } - else - { - _logger.Warning("A release for milestone {Milestone} already exists, and will be updated", milestone); + return release; + } - if (!release.Draft && !_configuration.Create.AllowUpdateToPublishedRelease) - { - throw new InvalidOperationException("Release is not in draft state, so not updating."); - } + public async Task CreateReleaseFromInputFileAsync(string owner, string repository, string name, string inputFilePath, string targetCommitish, IList assets, bool prerelease) + { + Ensure.FileExists(inputFilePath, "Unable to locate input file."); - var releaseUpdate = release.ToUpdate(); - releaseUpdate.Body = result; - _logger.Verbose("Updating release {Milestone} on '{Owner}/{Repository}'", milestone, owner, repository); - _logger.Debug("{@ReleaseUpdate}", releaseUpdate); - await _gitHubClient.Repository.Release.Edit(owner, repository, release.Id, releaseUpdate).ConfigureAwait(false); - } + _logger.Verbose("Reading release notes from: '{FilePath}'", inputFilePath); + + var releaseNotes = File.ReadAllText(inputFilePath); + var release = await CreateRelease(owner, repository, name, name, releaseNotes, prerelease, targetCommitish, assets).ConfigureAwait(false); - await AddAssets(owner, repository, milestone, assets).ConfigureAwait(false); - return _mapper.Map(release); + return release; } - public async Task CreateReleaseFromInputFile(string owner, string repository, string name, string inputFilePath, string targetCommitish, IList assets, bool prerelease) + private async Task CreateRelease(string owner, string repository, string name, string tagName, string body, bool prerelease, string targetCommitish, IList assets) { - Ensure.FileExists(inputFilePath, "Unable to locate input file."); + Release release; - _logger.Verbose("Reading release notes from: '{FilePath}'", inputFilePath); + try + { + release = await _vcsProvider.GetReleaseAsync(owner, repository, tagName).ConfigureAwait(false); - var inputFileContents = File.ReadAllText(inputFilePath); + if (!release.Draft && !_configuration.Create.AllowUpdateToPublishedRelease) + { + throw new InvalidOperationException($"Release with tag '{tagName}' not in draft state, so not updating"); + } - var releaseUpdate = CreateNewRelease(name, name, inputFileContents, prerelease, targetCommitish); + release.Body = body; - _logger.Verbose("Creating new release on '{Owner}/{Repository}'", owner, repository); - _logger.Debug("{@ReleaseUpdate}", releaseUpdate); + _logger.Warning("A release for milestone '{Milestone}' already exists, and will be updated", tagName); + _logger.Verbose("Updating release with tag '{TagName}' on '{Owner}/{Repository}'", tagName, owner, repository); + _logger.Debug("{@Release}", release); - var release = await _gitHubClient.Repository.Release.Create(owner, repository, releaseUpdate).ConfigureAwait(false); + await _vcsProvider.UpdateReleaseAsync(owner, repository, release).ConfigureAwait(false); + } + catch (NotFoundException) + { + release = CreateReleaseModel(name, tagName, body, prerelease, targetCommitish); + + _logger.Verbose("Creating new release with tag '{TagName}' on '{Owner}/{Repository}'", tagName, owner, repository); + _logger.Debug("{@Release}", release); + + release = await _vcsProvider.CreateReleaseAsync(owner, repository, release).ConfigureAwait(false); + } - await AddAssets(owner, repository, name, assets).ConfigureAwait(false); + await AddAssetsAsync(owner, repository, tagName, assets).ConfigureAwait(false); - return _mapper.Map(release); + return release; } - public async Task DiscardRelease(string owner, string repository, string tagName) + public async Task DiscardReleaseAsync(string owner, string repository, string tagName) { try { @@ -115,93 +115,95 @@ public async Task DiscardRelease(string owner, string repository, string tagName } catch (NotFoundException) { - _logger.Error("Unable to find a release with tag '{TagName}'", tagName); + _logger.Warning(_unableToFoundReleaseMessage, tagName, owner, repository); } } - public async Task AddAssets(string owner, string repository, string tagName, IList assets) + public async Task AddAssetsAsync(string owner, string repository, string tagName, IList assets) { - var release = await GetReleaseFromTagNameAsync(owner, repository, tagName).ConfigureAwait(false); - - if (release is null) + if (assets?.Any() == true) { - _logger.Error("Unable to find Release with specified tagName"); - return; - } - - if (!(assets is null)) - { - foreach (var asset in assets) + try { - if (!File.Exists(asset)) - { - var logMessage = string.Format("Requested asset to be uploaded doesn't exist: {0}", asset); - throw new FileNotFoundException(logMessage); - } - - var assetFileName = Path.GetFileName(asset); + var release = await _vcsProvider.GetReleaseAsync(owner, repository, tagName).ConfigureAwait(false); - var existingAsset = release.Assets.FirstOrDefault(a => a.Name == assetFileName); - if (existingAsset != null) + foreach (var asset in assets) { - _logger.Warning("Requested asset to be uploaded already exists on draft release, replacing with new file: {AssetPath}", asset); - await _gitHubClient.Repository.Release.DeleteAsset(owner, repository, existingAsset.Id).ConfigureAwait(false); - } + if (!File.Exists(asset)) + { + var message = string.Format("Requested asset to be uploaded doesn't exist: {0}", asset); + throw new FileNotFoundException(message); + } - var upload = new ReleaseAssetUpload - { - FileName = assetFileName, - ContentType = "application/octet-stream", - RawData = File.Open(asset, System.IO.FileMode.Open, FileAccess.Read, FileShare.ReadWrite), - }; + var assetFileName = Path.GetFileName(asset); + var existingAsset = release.Assets.FirstOrDefault(a => a.Name == assetFileName); - _logger.Verbose("Uploading asset '{FileName}' to release '{TagName}' on '{Owner}/{Repository}'", assetFileName, tagName, owner, repository); - _logger.Debug("{@Upload}", upload); + if (existingAsset != null) + { + _logger.Warning("Requested asset to be uploaded already exists on draft release, replacing with new file: {AssetPath}", asset); + await _vcsProvider.DeleteAssetAsync(owner, repository, existingAsset.Id).ConfigureAwait(false); + } - await _gitHubClient.Repository.Release.UploadAsset(release, upload).ConfigureAwait(false); + var upload = new ReleaseAssetUpload + { + FileName = assetFileName, + ContentType = "application/octet-stream", + RawData = File.Open(asset, System.IO.FileMode.Open, FileAccess.Read, FileShare.ReadWrite), + }; - // Make sure to tidy up the stream that was created above - upload.RawData.Dispose(); - } + _logger.Verbose("Uploading asset '{FileName}' to release '{TagName}' on '{Owner}/{Repository}'", assetFileName, tagName, owner, repository); + _logger.Debug("{@Upload}", upload); - if (assets.Any() && _configuration.Create.IncludeShaSection) - { - var stringBuilder = new StringBuilder(release.Body); + await _vcsProvider.UploadAssetAsync(release, upload).ConfigureAwait(false); - if (!release.Body.Contains(_configuration.Create.ShaSectionHeading)) - { - _logger.Debug("Creating SHA section header"); - stringBuilder.AppendLine(string.Format("### {0}", _configuration.Create.ShaSectionHeading)); + // Make sure to tidy up the stream that was created above + upload.RawData.Dispose(); } - foreach (var asset in assets) + if (_configuration.Create.IncludeShaSection) { - var file = new FileInfo(asset); + var stringBuilder = new StringBuilder(release.Body); - if (!file.Exists) + if (!release.Body.Contains(_configuration.Create.ShaSectionHeading)) { - continue; + _logger.Debug("Creating SHA section header"); + stringBuilder.AppendLine(string.Format("### {0}", _configuration.Create.ShaSectionHeading)); } - _logger.Debug("Creating SHA checksum for {Name}.", file.Name); + foreach (var asset in assets) + { + var file = new FileInfo(asset); + + if (!file.Exists) + { + continue; + } + + _logger.Debug("Creating SHA checksum for {Name}.", file.Name); + + stringBuilder.AppendFormat(_configuration.Create.ShaSectionLineFormat, file.Name, ComputeSha256Hash(asset)); + stringBuilder.AppendLine(); + } - stringBuilder.AppendFormat(_configuration.Create.ShaSectionLineFormat, file.Name, ComputeSha256Hash(asset)); stringBuilder.AppendLine(); - } - stringBuilder.AppendLine(); + release.Body = stringBuilder.ToString(); - var releaseUpdate = release.ToUpdate(); - releaseUpdate.Body = stringBuilder.ToString(); - _logger.Verbose("Updating release notes with sha checksum"); - _logger.Debug("{@ReleaseUpdate}", releaseUpdate); - await _gitHubClient.Repository.Release.Edit(owner, repository, release.Id, releaseUpdate).ConfigureAwait(false); + _logger.Verbose("Updating release notes with SHA checksum"); + _logger.Debug("{@Release}", release); + + await _vcsProvider.UpdateReleaseAsync(owner, repository, release).ConfigureAwait(false); + } + } + catch (NotFoundException) + { + _logger.Warning(_unableToFoundReleaseMessage, tagName, owner, repository); } } } - public async Task ExportReleases(string owner, string repository, string tagName) + public async Task ExportReleasesAsync(string owner, string repository, string tagName) { var releases = Enumerable.Empty(); @@ -221,14 +223,14 @@ public async Task ExportReleases(string owner, string repository, string } catch (NotFoundException) { - _logger.Error("Unable to find any release with the tag '{TagName}' for specified repository.", tagName); + _logger.Warning(_unableToFoundReleaseMessage, tagName, owner, repository); } } return _releaseNotesExporter.ExportReleaseNotes(releases); } - public async Task CloseMilestone(string owner, string repository, string milestoneTitle) + public async Task CloseMilestoneAsync(string owner, string repository, string milestoneTitle) { try { @@ -245,11 +247,11 @@ public async Task CloseMilestone(string owner, string repository, string milesto } catch (NotFoundException) { - _logger.Error("No existing open milestone with title '{Title}' was found", milestoneTitle); + _logger.Warning(_unableToFoundMilestoneMessage, "open", milestoneTitle, owner, repository); } } - public async Task OpenMilestone(string owner, string repository, string milestoneTitle) + public async Task OpenMilestoneAsync(string owner, string repository, string milestoneTitle) { try { @@ -261,52 +263,54 @@ public async Task OpenMilestone(string owner, string repository, string mileston } catch (NotFoundException) { - _logger.Error("No existing closed milestone with title '{Title}' was found", milestoneTitle); + _logger.Warning(_unableToFoundMilestoneMessage, "closed", milestoneTitle, owner, repository); } } - public async Task PublishRelease(string owner, string repository, string tagName) + public async Task PublishReleaseAsync(string owner, string repository, string tagName) { - var release = await GetReleaseFromTagNameAsync(owner, repository, tagName).ConfigureAwait(false); - - if (release is null) + try { - _logger.Verbose("No release with tag '{TagName}' was found on '{Owner}/{Repository}'", tagName, owner, repository); - return; - } + var release = await _vcsProvider.GetReleaseAsync(owner, repository, tagName).ConfigureAwait(false); - var releaseUpdate = new ReleaseUpdate { TagName = tagName, Draft = false }; + _logger.Verbose("Publishing release '{TagName}' on '{Owner}/{Repository}'", tagName, owner, repository); + _logger.Debug("{@Release}", release); - _logger.Verbose("Publishing release '{TagName}' on '{Owner}/{Repository}'", tagName, owner, repository); - _logger.Debug("{@ReleaseUpdate}", releaseUpdate); - await _gitHubClient.Repository.Release.Edit(owner, repository, release.Id, releaseUpdate).ConfigureAwait(false); + await _vcsProvider.PublishReleaseAsync(owner, repository, tagName, release.Id).ConfigureAwait(false); + } + catch (NotFoundException) + { + _logger.Warning(_unableToFoundReleaseMessage, tagName, owner, repository); + } } - public async Task CreateLabels(string owner, string repository) + public async Task CreateLabelsAsync(string owner, string repository) { if (_configuration.Labels.Any()) { - var newLabels = new List(); + var newLabels = new List