Skip to content

(WIP) Add output of draft release and split out VCS Provider #631

New issue

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

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

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<LangVersion>8.0</LangVersion>
<OutputType>Exe</OutputType>
Expand Down
53 changes: 45 additions & 8 deletions src/GitReleaseManager.Cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ private static void RegisterServices(BaseSubOptions options)
RegisterVcsProvider(vcsOptions, serviceCollection);
}

if (options is CreateSubOptions createOptions && !string.IsNullOrEmpty(createOptions.OutputPath))
{
configuration.Create.AllowUpdateToPublishedRelease = false;
}

serviceCollection = serviceCollection
.AddTransient((services) => new TemplateFactory(services.GetRequiredService<IFileSystem>(), services.GetRequiredService<Config>(), TemplateKind.Create));

Expand Down Expand Up @@ -197,21 +202,53 @@ private static Task<int> ExecuteCommand<TOptions>(TOptions options)
private static void LogOptions(BaseSubOptions options)
=> Log.Debug("{@Options}", options);

private static void RegisterKeyedVcsProvider<TVcsImplementation>(object provider, IServiceCollection serviceCollection)
where TVcsImplementation : class, IVcsProvider
{
static IVcsProvider ResolveService(IServiceProvider service, object key) => service.GetRequiredKeyedService<IVcsProvider>(key);

provider ??= "null";

Log.Debug("Registering {Type} with Service Key {Key}", typeof(IVcsProvider), provider);

if (typeof(TVcsImplementation) != typeof(NullReleasesProvider))
{
serviceCollection.AddKeyedSingleton<IVcsProvider, TVcsImplementation>(provider);
}

serviceCollection
.AddKeyedTransient<IAssetsProvider>(provider, ResolveService)
.AddKeyedTransient<ICommitsProvider>(provider, ResolveService)
.AddKeyedTransient<IIssuesProvider>(provider, ResolveService)
.AddKeyedTransient<IMilestonesProvider>(provider, ResolveService)
.AddKeyedTransient<IReleasesProvider>(provider, ResolveService);
}

private static void RegisterVcsProvider(BaseVcsOptions vcsOptions, IServiceCollection serviceCollection)
{
Log.Information("Using {Provider} as VCS Provider", vcsOptions.Provider);
if (vcsOptions.Provider == VcsProvider.GitLab)

serviceCollection.AddKeyedSingleton<IVcsProvider>("null", (service, _) => new NullReleasesProvider(vcsOptions.Provider.ToString(), service.GetRequiredService<ILogger>()));
RegisterKeyedVcsProvider<NullReleasesProvider>(null, serviceCollection);
RegisterKeyedVcsProvider<GitHubProvider>(VcsProvider.GitHub, serviceCollection);

serviceCollection
.AddSingleton<IGitLabClient>((_) => new GitLabClient("https://gitlab.com", vcsOptions.Token));

serviceCollection
.AddSingleton<IGitHubClient>((_) => new GitHubClient(new ProductHeaderValue("GitReleaseManager")) { Credentials = new Credentials(vcsOptions.Token) });

serviceCollection.AddTransient((service) => service.GetKeyedService<IVcsProvider>(vcsOptions.Provider) ?? service.GetRequiredKeyedService<IVcsProvider>("null"));

if (vcsOptions is CreateSubOptions createOptions && !string.IsNullOrEmpty(createOptions.OutputPath))
{
serviceCollection
.AddSingleton<IGitLabClient>((_) => new GitLabClient("https://gitlab.com", vcsOptions.Token))
.AddSingleton<IVcsProvider, GitLabProvider>();
serviceCollection.AddSingleton<IReleasesProvider>((service) => new LocalProvider(
service.GetRequiredService<IFileSystem>(),
createOptions.OutputPath));
}
else
{
// default to Github
serviceCollection
.AddSingleton<IGitHubClient>((_) => new GitHubClient(new ProductHeaderValue("GitReleaseManager")) { Credentials = new Credentials(vcsOptions.Token) })
.AddSingleton<IVcsProvider, GitHubProvider>();
serviceCollection.AddTransient((service) => service.GetKeyedService<IReleasesProvider>(vcsOptions.Provider) ?? service.GetRequiredKeyedService<IReleasesProvider>("null"));
}
}
}
Expand Down
128 changes: 65 additions & 63 deletions src/GitReleaseManager.Core.Tests/VcsServiceTests.cs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/GitReleaseManager.Core/GitReleaseManager.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v15.0\TextTemplating\Microsoft.TextTemplating.targets" Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v15.0\TextTemplating\Microsoft.TextTemplating.targets')" />
<PropertyGroup>
<LangVersion>8.0</LangVersion>
<!-- Uncomment the below property when langversion is updated to 9.0 or higher (optimally 11.0). -->
<!--<DefineConstants>$(DefineConstants);USE_GENERATED_REGEX</DefineConstants>-->
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<Title>GitReleaseManager.Core</Title>
<Description>Create release notes in markdown given a milestone</Description>
Expand Down
27 changes: 26 additions & 1 deletion src/GitReleaseManager.Core/Helpers/FileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,21 @@ public void Copy(string @source, string destination, bool overwrite)
File.Copy(@source, destination, overwrite);
}

public void CreateDirectory(string path)
{
// It is safe to call CreateDirectory, if the directory
// already exists these are no-op.

if (string.IsNullOrEmpty(path))
{
Directory.CreateDirectory(Environment.CurrentDirectory);
}
else
{
Directory.CreateDirectory(path);
}
}

public void Move(string @source, string destination)
{
File.Move(@source, destination);
Expand Down Expand Up @@ -59,9 +74,19 @@ public IEnumerable<string> DirectoryGetFiles(string directory, string searchPatt
return Directory.GetFiles(directory, searchPattern, searchOption);
}

public Stream OpenRead(string path)
{
return File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
}

public Stream OpenWrite(string path)
{
return File.OpenWrite(path);
return OpenWrite(path, overwrite: false);
}

public Stream OpenWrite(string path, bool overwrite)
{
return File.Open(path, overwrite ? FileMode.Create : FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
}
}
}
5 changes: 5 additions & 0 deletions src/GitReleaseManager.Core/Helpers/IFileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ public interface IFileSystem
{
void Copy(string source, string destination, bool overwrite);

void CreateDirectory(string path);

void Move(string source, string destination);

bool Exists(string file);
Expand All @@ -21,6 +23,9 @@ public interface IFileSystem

IEnumerable<string> DirectoryGetFiles(string directory, string searchPattern, SearchOption searchOption);

Stream OpenRead(string path);

Stream OpenWrite(string path);
Stream OpenWrite(string path, bool overwrite);
}
}
3 changes: 3 additions & 0 deletions src/GitReleaseManager.Core/Options/CreateSubOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,8 @@ public class CreateSubOptions : BaseVcsOptions

[Option("allowEmpty", Required = false, HelpText = "Allow the creation of an empty set of release notes. In this mode, milestone and input file path will be ignored.")]
public bool AllowEmpty { get; set; }

[Option("output", Required = false, HelpText = "The path to a local file location where the release notes will be created, instead of creating in remotely on the specified provider.")]
public string OutputPath { get; set; }
}
}
2 changes: 2 additions & 0 deletions src/GitReleaseManager.Core/Provider/GitHubProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public GitHubProvider(IGitHubClient gitHubClient, IMapper mapper)
_mapper = mapper;
}

public string Name => "GitHub";

public Task DeleteAssetAsync(string owner, string repository, ReleaseAsset asset)
{
return ExecuteAsync(async () =>
Expand Down
2 changes: 2 additions & 0 deletions src/GitReleaseManager.Core/Provider/GitLabProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public GitLabProvider(IGitLabClient gitLabClient, IMapper mapper, ILogger logger
_logger = logger;
}

public string Name => "GitLab";

public Task DeleteAssetAsync(string owner, string repository, ReleaseAsset asset)
{
// TODO: This is a discussion here:
Expand Down
14 changes: 14 additions & 0 deletions src/GitReleaseManager.Core/Provider/IAssetsProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace GitReleaseManager.Core.Provider
{
using System.Threading.Tasks;
using GitReleaseManager.Core.Model;

public interface IAssetsProvider
{
bool SupportsAssets { get; }

Task DeleteAssetAsync(string owner, string repository, ReleaseAsset asset);

Task UploadAssetAsync(Release release, ReleaseAssetUpload releaseAssetUpload);
}
}
13 changes: 13 additions & 0 deletions src/GitReleaseManager.Core/Provider/ICommitsProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace GitReleaseManager.Core.Provider
{
using System.Threading.Tasks;

public interface ICommitsProvider
{
bool SupportsCommits { get; }

Task<int> GetCommitsCountAsync(string owner, string repository, string baseCommit, string headCommit);

string GetCommitsUrl(string owner, string repository, string head, string baseCommit = null);
}
}
20 changes: 20 additions & 0 deletions src/GitReleaseManager.Core/Provider/IIssuesProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace GitReleaseManager.Core.Provider
{
using System.Collections.Generic;
using System.Threading.Tasks;
using GitReleaseManager.Core.Model;

public interface IIssuesProvider
{
bool SupportIssues { get; }
bool SupportIssueComments { get; }

Task CreateIssueCommentAsync(string owner, string repository, Issue issue, string comment);

Task<IEnumerable<IssueComment>> GetIssueCommentsAsync(string owner, string repository, Issue issue);

Task<IEnumerable<Issue>> GetIssuesAsync(string owner, string repository, Milestone milstone, ItemStateFilter itemStateFilter = ItemStateFilter.All);

string GetIssueType(Issue issue);
}
}
17 changes: 17 additions & 0 deletions src/GitReleaseManager.Core/Provider/ILabelsProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace GitReleaseManager.Core.Provider
{
using System.Collections.Generic;
using System.Threading.Tasks;
using GitReleaseManager.Core.Model;

public interface ILabelsProvider
{
bool SupportsLabels { get; }

Task CreateLabelAsync(string owner, string repository, Label label);

Task DeleteLabelAsync(string owner, string repository, Label label);

Task<IEnumerable<Label>> GetLabelsAsync(string owner, string repository);
}
}
19 changes: 19 additions & 0 deletions src/GitReleaseManager.Core/Provider/IMilestonesProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace GitReleaseManager.Core.Provider
{
using System.Collections.Generic;
using System.Threading.Tasks;
using GitReleaseManager.Core.Model;

public interface IMilestonesProvider
{
bool SupportMilestones { get; }

Task<Milestone> GetMilestoneAsync(string owner, string repository, string milestoneTitle, ItemStateFilter itemStateFilter = ItemStateFilter.All);

Task<IEnumerable<Milestone>> GetMilestonesAsync(string owner, string repository, ItemStateFilter itemStateFilter = ItemStateFilter.All);

Task SetMilestoneStateAsync(string owner, string repository, Milestone milestone, ItemState itemState);

string GetMilestoneQueryString();
}
}
9 changes: 9 additions & 0 deletions src/GitReleaseManager.Core/Provider/IRateLimitProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace GitReleaseManager.Core.Provider
{
using GitReleaseManager.Core.Model;

public interface IRateLimitProvider
{
RateLimit GetRateLimit();
}
}
23 changes: 23 additions & 0 deletions src/GitReleaseManager.Core/Provider/IReleasesProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using GitReleaseManager.Core.Model;

namespace GitReleaseManager.Core.Provider
{
public interface IReleasesProvider
{
bool SupportReleases { get; }

Task<Release> CreateReleaseAsync(string owner, string repository, Release release);

Task DeleteReleaseAsync(string owner, string repository, Release release);

Task<Release> GetReleaseAsync(string owner, string repository, string tagName);

Task<IEnumerable<Release>> GetReleasesAsync(string owner, string repository, bool skipPrereleases);

Task PublishReleaseAsync(string owner, string repository, string tagName, Release release);

Task UpdateReleaseAsync(string owner, string repository, Release release);
}
}
45 changes: 1 addition & 44 deletions src/GitReleaseManager.Core/Provider/IVcsProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,7 @@

namespace GitReleaseManager.Core.Provider
{
public interface IVcsProvider
public interface IVcsProvider : IAssetsProvider, ICommitsProvider, IIssuesProvider, IMilestonesProvider, IRateLimitProvider, IReleasesProvider
{
Task DeleteAssetAsync(string owner, string repository, ReleaseAsset asset);

Task UploadAssetAsync(Release release, ReleaseAssetUpload releaseAssetUpload);

Task<int> GetCommitsCountAsync(string owner, string repository, string @base, string head);

string GetCommitsUrl(string owner, string repository, string head, string @base = null);

Task CreateIssueCommentAsync(string owner, string repository, Issue issue, string comment);

Task<IEnumerable<Issue>> GetIssuesAsync(string owner, string repository, Milestone milstone, ItemStateFilter itemStateFilter = ItemStateFilter.All);

Task<IEnumerable<IssueComment>> GetIssueCommentsAsync(string owner, string repository, Issue issue);

Task CreateLabelAsync(string owner, string repository, Label label);

Task DeleteLabelAsync(string owner, string repository, Label label);

Task<IEnumerable<Label>> GetLabelsAsync(string owner, string repository);

Task<Milestone> GetMilestoneAsync(string owner, string repository, string milestoneTitle, ItemStateFilter itemStateFilter = ItemStateFilter.All);

Task<IEnumerable<Milestone>> GetMilestonesAsync(string owner, string repository, ItemStateFilter itemStateFilter = ItemStateFilter.All);

Task SetMilestoneStateAsync(string owner, string repository, Milestone milestone, ItemState itemState);

Task<Release> CreateReleaseAsync(string owner, string repository, Release release);

Task DeleteReleaseAsync(string owner, string repository, Release release);

Task<Release> GetReleaseAsync(string owner, string repository, string tagName);

Task<IEnumerable<Release>> GetReleasesAsync(string owner, string repository, bool skipPrereleases);

Task PublishReleaseAsync(string owner, string repository, string tagName, Release release);

Task UpdateReleaseAsync(string owner, string repository, Release release);

RateLimit GetRateLimit();

string GetMilestoneQueryString();

string GetIssueType(Issue issue);
}
}
Loading
Loading