Skip to content

Commit

Permalink
Merge pull request #265 from akordowski/feature/GH-181-add-dependency…
Browse files Browse the repository at this point in the history
…-injection

(GH-181) Add Dependency Injection
  • Loading branch information
gep13 authored Aug 24, 2020
2 parents b01de39 + 711d6ca commit dc94422
Show file tree
Hide file tree
Showing 81 changed files with 4,121 additions and 1,054 deletions.
3 changes: 2 additions & 1 deletion Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.8.0" />
<PackageReference Include="Destructurama.Attributed" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.6" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Octokit" Version="0.48.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.Debug" Version="1.0.1" PrivateAssets="All"/>
<PackageReference Include="Serilog.Sinks.Debug" Version="1.0.1" PrivateAssets="All" />
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
<PackageReference Include="seriloganalyzer" Version="0.15.0" />
</ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion Source/GitReleaseManager.Cli/Logging/LogConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace GitReleaseManager.Cli.Logging
using System.Diagnostics;
using System.Text;
using Destructurama;
using GitReleaseManager.Cli.Options;
using GitReleaseManager.Core.Options;
using Octokit;
using Serilog;
using Serilog.Events;
Expand Down
211 changes: 69 additions & 142 deletions Source/GitReleaseManager.Cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,53 +7,51 @@
namespace GitReleaseManager.Cli
{
using System;
using System.IO;
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.Commands;
using GitReleaseManager.Core.Configuration;
using GitReleaseManager.Core.Helpers;
using GitReleaseManager.Core.Options;
using GitReleaseManager.Core.Provider;
using GitReleaseManager.Core.ReleaseNotes;
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<int> Main(string[] args)
{
// Just add the TLS 1.2 protocol to the Service Point manager until
// we've upgraded to latest Octokit.
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;

_fileSystem = new FileSystem();

_mapper = AutoMapperConfiguration.Configure();

try
{
return await Parser.Default.ParseArguments<CreateSubOptions, DiscardSubOptions, AddAssetSubOptions, CloseSubOptions, OpenSubOptions, PublishSubOptions, ExportSubOptions, InitSubOptions, ShowConfigSubOptions, LabelSubOptions>(args)
.WithParsed<BaseSubOptions>(LogConfiguration.ConfigureLogging)
.WithParsed<BaseSubOptions>(CreateFiglet)
.WithParsed<BaseSubOptions>(LogOptions)
.WithParsed<BaseVcsOptions>(ReportUsernamePasswordDeprecation)
.WithParsed<BaseVcsOptions>(RegisterServices)
.MapResult(
(CreateSubOptions opts) => CreateReleaseAsync(opts),
(DiscardSubOptions opts) => DiscardReleaseAsync(opts),
(AddAssetSubOptions opts) => AddAssetsAsync(opts),
(CloseSubOptions opts) => CloseMilestoneAsync(opts),
(OpenSubOptions opts) => OpenMilestoneAsync(opts),
(PublishSubOptions opts) => PublishReleaseAsync(opts),
(ExportSubOptions opts) => ExportReleasesAsync(opts),
(InitSubOptions opts) => CreateSampleConfigFileAsync(opts),
(ShowConfigSubOptions opts) => ShowConfigAsync(opts),
(LabelSubOptions opts) => CreateLabelsAsync(opts),
(CreateSubOptions opts) => ExecuteCommand(opts),
(DiscardSubOptions opts) => ExecuteCommand(opts),
(AddAssetSubOptions opts) => ExecuteCommand(opts),
(CloseSubOptions opts) => ExecuteCommand(opts),
(OpenSubOptions opts) => ExecuteCommand(opts),
(PublishSubOptions opts) => ExecuteCommand(opts),
(ExportSubOptions opts) => ExecuteCommand(opts),
(InitSubOptions opts) => ExecuteCommand(opts),
(ShowConfigSubOptions opts) => ExecuteCommand(opts),
(LabelSubOptions opts) => ExecuteCommand(opts),
errs => Task.FromResult(1)).ConfigureAwait(false);
}
catch (AggregateException ex)
Expand All @@ -74,6 +72,53 @@ private static async Task<int> Main(string[] args)
finally
{
Log.CloseAndFlush();
DisposeServices();
}
}

private static void RegisterServices(BaseVcsOptions options)
{
var fileSystem = new FileSystem();
var logger = Log.ForContext<VcsService>();
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(configuration.Export)
.AddSingleton<ICommand<AddAssetSubOptions>, AddAssetsCommand>()
.AddSingleton<ICommand<CloseSubOptions>, CloseCommand>()
.AddSingleton<ICommand<CreateSubOptions>, CreateCommand>()
.AddSingleton<ICommand<DiscardSubOptions>, DiscardCommand>()
.AddSingleton<ICommand<ExportSubOptions>, ExportCommand>()
.AddSingleton<ICommand<InitSubOptions>, InitCommand>()
.AddSingleton<ICommand<LabelSubOptions>, LabelCommand>()
.AddSingleton<ICommand<OpenSubOptions>, OpenCommand>()
.AddSingleton<ICommand<PublishSubOptions>, PublishCommand>()
.AddSingleton<ICommand<ShowConfigSubOptions>, ShowConfigCommand>()
.AddSingleton<IFileSystem, FileSystem>()
.AddSingleton<IReleaseNotesExporter, ReleaseNotesExporter>()
.AddSingleton<IReleaseNotesBuilder, ReleaseNotesBuilder>()
.AddSingleton<IGitHubClient>(gitHubClient)
.AddSingleton<IVcsProvider, GitHubProvider>()
.AddSingleton<IVcsService, VcsService>();

_serviceProvider = serviceCollection.BuildServiceProvider();
}

private static void DisposeServices()
{
if (_serviceProvider is IDisposable serviceProvider)
{
serviceProvider.Dispose();
}
}

Expand Down Expand Up @@ -145,129 +190,11 @@ private static int GetConsoleWidth()
}
}

private static async Task<int> CreateReleaseAsync(CreateSubOptions subOptions)
{
Log.Information("Creating release...");
_vcsProvider = GetVcsProvider(subOptions);

Core.Model.Release release;
if (!string.IsNullOrEmpty(subOptions.Milestone))
{
Log.Verbose("Milestone {Milestone} was specified", subOptions.Milestone);
var releaseName = subOptions.Name;
if (string.IsNullOrWhiteSpace(releaseName))
{
Log.Verbose("No Release Name was specified, using {Milestone}.", subOptions.Milestone);
releaseName = subOptions.Milestone;
}

release = await _vcsProvider.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);
}

Log.Information("Drafted release is available at:\n{HtmlUrl}", release.HtmlUrl);
Log.Verbose("Body:\n{Body}", release.Body);
return 0;
}

private static async Task<int> DiscardReleaseAsync(DiscardSubOptions subOptions)
private static Task<int> ExecuteCommand<TOptions>(TOptions options)
where TOptions : BaseSubOptions
{
Log.Information("Discarding release {Milestone}", subOptions.Milestone);
_vcsProvider = GetVcsProvider(subOptions);

await _vcsProvider.DiscardRelease(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone);

return 0;
}

private static async Task<int> AddAssetsAsync(AddAssetSubOptions subOptions)
{
Log.Information("Uploading assets");
_vcsProvider = GetVcsProvider(subOptions);

await _vcsProvider.AddAssets(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName, subOptions.AssetPaths).ConfigureAwait(false);

return 0;
}

private static async Task<int> CloseMilestoneAsync(CloseSubOptions subOptions)
{
Log.Information("Closing milestone {Milestone}", subOptions.Milestone);
_vcsProvider = GetVcsProvider(subOptions);

await _vcsProvider.CloseMilestone(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false);

return 0;
}

private static async Task<int> OpenMilestoneAsync(OpenSubOptions subOptions)
{
Log.Information("Opening milestone {Milestone}", subOptions.Milestone);
_vcsProvider = GetVcsProvider(subOptions);

await _vcsProvider.OpenMilestone(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone).ConfigureAwait(false);

return 0;
}

private static async Task<int> PublishReleaseAsync(PublishSubOptions subOptions)
{
_vcsProvider = GetVcsProvider(subOptions);

await _vcsProvider.PublishRelease(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName).ConfigureAwait(false);
return 0;
}

private static async Task<int> ExportReleasesAsync(ExportSubOptions subOptions)
{
Log.Information("Exporting release {TagName}", subOptions.TagName);
_vcsProvider = GetVcsProvider(subOptions);

var releasesMarkdown = await _vcsProvider.ExportReleases(subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName).ConfigureAwait(false);

using (var sw = new StreamWriter(File.Open(subOptions.FileOutputPath, FileMode.OpenOrCreate)))
{
sw.Write(releasesMarkdown);
}

return 0;
}

private static Task<int> CreateSampleConfigFileAsync(InitSubOptions subOptions)
{
Log.Information("Creating sample configuration file");
var directory = subOptions.TargetDirectory ?? Environment.CurrentDirectory;
ConfigurationProvider.WriteSample(directory, _fileSystem);
return Task.FromResult(0);
}

private static Task<int> ShowConfigAsync(ShowConfigSubOptions subOptions)
{
var configuration = ConfigurationProvider.GetEffectiveConfigAsString(subOptions.TargetDirectory ?? Environment.CurrentDirectory, _fileSystem);

Log.Information("{Configuration}", configuration);
return Task.FromResult(0);
}

private static async Task<int> CreateLabelsAsync(LabelSubOptions subOptions)
{
Log.Information("Creating standard labels");
_vcsProvider = GetVcsProvider(subOptions);

await _vcsProvider.CreateLabels(subOptions.RepositoryOwner, subOptions.RepositoryName).ConfigureAwait(false);
return 0;
}

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 command = _serviceProvider.GetRequiredService<ICommand<TOptions>>();
return command.Execute(options);
}

private static void LogOptions(BaseSubOptions options)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// -----------------------------------------------------------------------
// <copyright file="AddAssetsCommandTests.cs" company="GitTools Contributors">
// Copyright (c) 2015 - Present - GitTools Contributors
// </copyright>
// -----------------------------------------------------------------------

using System.Collections.Generic;
using System.Threading.Tasks;
using GitReleaseManager.Core.Commands;
using GitReleaseManager.Core.Options;
using NSubstitute;
using NUnit.Framework;
using Serilog;
using Shouldly;

namespace GitReleaseManager.Core.Tests.Commands
{
[TestFixture]
public class AddAssetsCommandTests
{
private IVcsService _vcsService;
private ILogger _logger;
private AddAssetsCommand _command;

[SetUp]
public void Setup()
{
_vcsService = Substitute.For<IVcsService>();
_logger = Substitute.For<ILogger>();
_command = new AddAssetsCommand(_vcsService, _logger);
}

[Test]
public async Task Should_Execute_Command()
{
var options = new AddAssetSubOptions
{
RepositoryOwner = "owner",
RepositoryName = "repository",
TagName = "0.1.0",
AssetPaths = new List<string>(),
};

_vcsService.AddAssetsAsync(options.RepositoryOwner, options.RepositoryName, options.TagName, options.AssetPaths).
Returns(Task.CompletedTask);

var result = await _command.Execute(options).ConfigureAwait(false);
result.ShouldBe(0);

await _vcsService.Received(1).AddAssetsAsync(options.RepositoryOwner, options.RepositoryName, options.TagName, options.AssetPaths).ConfigureAwait(false);
_logger.Received(1).Information(Arg.Any<string>());
}
}
}
52 changes: 52 additions & 0 deletions Source/GitReleaseManager.Core.Tests/Commands/CloseCommandTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// -----------------------------------------------------------------------
// <copyright file="CloseCommandTests.cs" company="GitTools Contributors">
// Copyright (c) 2015 - Present - GitTools Contributors
// </copyright>
// -----------------------------------------------------------------------

using System.Threading.Tasks;
using GitReleaseManager.Core.Commands;
using GitReleaseManager.Core.Options;
using NSubstitute;
using NUnit.Framework;
using Serilog;
using Shouldly;

namespace GitReleaseManager.Core.Tests.Commands
{
[TestFixture]
public class CloseCommandTests
{
private IVcsService _vcsService;
private ILogger _logger;
private CloseCommand _command;

[SetUp]
public void Setup()
{
_vcsService = Substitute.For<IVcsService>();
_logger = Substitute.For<ILogger>();
_command = new CloseCommand(_vcsService, _logger);
}

[Test]
public async Task Should_Execute_Command()
{
var options = new CloseSubOptions
{
RepositoryOwner = "owner",
RepositoryName = "repository",
Milestone = "0.1.0",
};

_vcsService.CloseMilestoneAsync(options.RepositoryOwner, options.RepositoryName, options.Milestone)
.Returns(Task.CompletedTask);

var result = await _command.Execute(options).ConfigureAwait(false);
result.ShouldBe(0);

await _vcsService.Received(1).CloseMilestoneAsync(options.RepositoryOwner, options.RepositoryName, options.Milestone).ConfigureAwait(false);
_logger.Received(1).Information(Arg.Any<string>(), options.Milestone);
}
}
}
Loading

0 comments on commit dc94422

Please sign in to comment.