diff --git a/GitReleaseManager.yaml b/GitReleaseManager.yaml new file mode 100644 index 00000000..7e23acdf --- /dev/null +++ b/GitReleaseManager.yaml @@ -0,0 +1,24 @@ +# create: +# include-footer: true | false +# footer-heading: Where to get it +# footer-content: You can download this release from [chocolatey](https://chocolatey.org/packages/chocolateyGUI/{milestone} +# footer-includes-milestone: true | false +# milestone-replace-text: '{milestone}' +# export: +# include-created-date-in-title: true | false +# created-date-string-format: MMMM dd, yyyy +# perform-regex-removal: true | false +# regex-text: '### Where to get it(\r\n)*You can .*\)' +# multiline-regex: true | false +# issue-labels-include: +# - Bug +# - Duplicate +# - Enhancement +# - Feature +# - Help Wanted +# - Improvement +# - Invalid +# - Question +# - WontFix +# issue-labels-exclude: +# - Internal Refactoring diff --git a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj index aa4ecac7..94f61dea 100644 --- a/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj +++ b/Source/GitReleaseManager.Cli/GitReleaseManager.Cli.csproj @@ -2,7 +2,7 @@ Exe GitReleaseManager - netcoreapp2.0;net451 + netcoreapp2.0;net462 1.0.1 false publish\ @@ -55,5 +55,6 @@ + \ No newline at end of file diff --git a/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj b/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj index 9d907613..3cde9c89 100644 --- a/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj +++ b/Source/GitReleaseManager.Cli/GitReleaseManager.Tool.csproj @@ -50,5 +50,6 @@ + diff --git a/Source/GitReleaseManager.Cli/GitReleaseManager.yaml b/Source/GitReleaseManager.Cli/GitReleaseManager.yaml new file mode 100644 index 00000000..7e23acdf --- /dev/null +++ b/Source/GitReleaseManager.Cli/GitReleaseManager.yaml @@ -0,0 +1,24 @@ +# create: +# include-footer: true | false +# footer-heading: Where to get it +# footer-content: You can download this release from [chocolatey](https://chocolatey.org/packages/chocolateyGUI/{milestone} +# footer-includes-milestone: true | false +# milestone-replace-text: '{milestone}' +# export: +# include-created-date-in-title: true | false +# created-date-string-format: MMMM dd, yyyy +# perform-regex-removal: true | false +# regex-text: '### Where to get it(\r\n)*You can .*\)' +# multiline-regex: true | false +# issue-labels-include: +# - Bug +# - Duplicate +# - Enhancement +# - Feature +# - Help Wanted +# - Improvement +# - Invalid +# - Question +# - WontFix +# issue-labels-exclude: +# - Internal Refactoring diff --git a/Source/GitReleaseManager.Cli/Program.cs b/Source/GitReleaseManager.Cli/Program.cs index de1a76dc..ec886b03 100644 --- a/Source/GitReleaseManager.Cli/Program.cs +++ b/Source/GitReleaseManager.Cli/Program.cs @@ -1,358 +1,93 @@ -//----------------------------------------------------------------------- -// -// Copyright (c) 2015 - Present - GitTools Contributors -// -//----------------------------------------------------------------------- +using GitReleaseManager.Core; +using GitReleaseManager.Core.Configuration; +using GitReleaseManager.Core.Helpers; +using Spectre.Cli; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.IO; +using System.Text; namespace GitReleaseManager.Cli { - using System; - using System.Collections.Generic; - using System.Globalization; - using System.IO; - using System.Linq; - using System.Net; - using System.Text; - using System.Threading.Tasks; - using CommandLine; - using GitReleaseManager.Cli.Options; - using GitReleaseManager.Core; - using GitReleaseManager.Core.Configuration; - using GitReleaseManager.Core.Helpers; - using Octokit; - using FileMode = System.IO.FileMode; - - public static class Program + public class Program { - private static StringBuilder log = new StringBuilder(); - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Not required")] - private static 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; - - var fileSystem = new FileSystem(); - - return Parser.Default.ParseArguments(args) - .MapResult( - (CreateSubOptions opts) => CreateReleaseAsync(opts, fileSystem).Result, - (AddAssetSubOptions opts) => AddAssetsAsync(opts).Result, - (CloseSubOptions opts) => CloseMilestoneAsync(opts).Result, - (PublishSubOptions opts) => PublishReleaseAsync(opts).Result, - (ExportSubOptions opts) => ExportReleasesAsync(opts, fileSystem).Result, - (InitSubOptions opts) => CreateSampleConfigFile(opts, fileSystem), - (ShowConfigSubOptions opts) => ShowConfig(opts, fileSystem), - (LabelSubOptions opts) => CreateLabelsAsync(opts).Result, - errs => 1); - } - - private static async Task CreateReleaseAsync(CreateSubOptions subOptions, IFileSystem fileSystem) - { - try - { - ConfigureLogging(subOptions.LogFilePath); - - var github = subOptions.CreateGitHubClient(); - var configuration = ConfigurationProvider.Provide(subOptions.TargetDirectory ?? Environment.CurrentDirectory, fileSystem); - - Release release; - if (!string.IsNullOrEmpty(subOptions.Milestone)) - { - release = await CreateReleaseFromMilestone(github, subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone, subOptions.TargetCommitish, subOptions.AssetPaths, subOptions.Prerelease, configuration); - } - else - { - release = await CreateReleaseFromInputFile(github, subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Name, subOptions.InputFilePath, subOptions.TargetCommitish, subOptions.AssetPaths, subOptions.Prerelease); - } - - Console.WriteLine(release.HtmlUrl); - return 0; - } - catch (Exception ex) - { - Console.WriteLine(ex); - - return 1; - } - } - - private static async Task AddAssetsAsync(AddAssetSubOptions subOptions) - { - try - { - ConfigureLogging(subOptions.LogFilePath); - - var github = subOptions.CreateGitHubClient(); - - await AddAssets(github, subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName, subOptions.AssetPaths); - - return 0; - } - catch (Exception ex) - { - Console.WriteLine(ex); - - return 1; - } - } - - private static async Task CloseMilestoneAsync(CloseSubOptions subOptions) + public static void Main(string[] args) { - try - { - ConfigureLogging(subOptions.LogFilePath); - - var github = subOptions.CreateGitHubClient(); + var app = new CommandApp(); - await CloseMilestone(github, subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.Milestone); - - return 0; - } - catch (Exception ex) + app.Configure(config => { - Console.WriteLine(ex); + config.AddCommand("create"); + config.AddCommand("addasset"); + config.AddCommand("init"); + }); - return 1; - } - } - - private static async Task PublishReleaseAsync(PublishSubOptions subOptions) - { - try - { - ConfigureLogging(subOptions.LogFilePath); - - var github = subOptions.CreateGitHubClient(); - - await PublishRelease(github, subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName); - - return 0; - } - catch (Exception ex) - { - Console.WriteLine(ex); - - return 1; - } - } - - private static async Task ExportReleasesAsync(ExportSubOptions subOptions, IFileSystem fileSystem) - { - try - { - ConfigureLogging(subOptions.LogFilePath); - - var github = subOptions.CreateGitHubClient(); - var configuration = ConfigurationProvider.Provide(subOptions.TargetDirectory ?? Environment.CurrentDirectory, fileSystem); - - var releasesMarkdown = await ExportReleases(github, subOptions.RepositoryOwner, subOptions.RepositoryName, subOptions.TagName, configuration); - - using (var sw = new StreamWriter(File.Open(subOptions.FileOutputPath, FileMode.OpenOrCreate))) - { - sw.Write(releasesMarkdown); - } - - return 0; - } - catch (Exception ex) - { - Console.WriteLine(ex); - - return 1; - } + app.Run(args); } + } - private static int CreateSampleConfigFile(InitSubOptions subOptions, IFileSystem fileSystem) + [Description("Creates a draft release notes from a milestone.")] + public sealed class CreateCommand : Command + { + public override int Execute(CommandContext context, CreateSettings settings) { - ConfigureLogging(subOptions.LogFilePath); - - ConfigurationProvider.WriteSample(subOptions.TargetDirectory ?? Environment.CurrentDirectory, fileSystem); return 0; } + } - private static int ShowConfig(ShowConfigSubOptions subOptions, IFileSystem fileSystem) - { - ConfigureLogging(subOptions.LogFilePath); - - Console.WriteLine(ConfigurationProvider.GetEffectiveConfigAsString(subOptions.TargetDirectory ?? Environment.CurrentDirectory, fileSystem)); - return 0; - } - - private static async Task CreateLabelsAsync(LabelSubOptions subOptions) - { - try - { - ConfigureLogging(subOptions.LogFilePath); - - var newLabels = new List(); - newLabels.Add(new NewLabel("Breaking change", "b60205")); - newLabels.Add(new NewLabel("Bug", "ee0701")); - newLabels.Add(new NewLabel("Build", "009800")); - newLabels.Add(new NewLabel("Documentation", "d4c5f9")); - newLabels.Add(new NewLabel("Feature", "84b6eb")); - newLabels.Add(new NewLabel("Improvement", "207de5")); - newLabels.Add(new NewLabel("Question", "cc317c")); - newLabels.Add(new NewLabel("good first issue", "7057ff")); - newLabels.Add(new NewLabel("help wanted", "33aa3f")); - - var github = subOptions.CreateGitHubClient(); - - var labels = await github.Issue.Labels.GetAllForRepository(subOptions.RepositoryOwner, subOptions.RepositoryName); - - foreach (var label in labels) - { - await github.Issue.Labels.Delete(subOptions.RepositoryOwner, subOptions.RepositoryName, label.Name); - } - - foreach (var label in newLabels) - { - await github.Issue.Labels.Create(subOptions.RepositoryOwner, subOptions.RepositoryName, label); - } - - return 0; - } - catch (Exception ex) - { - Console.WriteLine(ex); - - return 1; - } - } - private static async Task CreateReleaseFromMilestone(GitHubClient github, string owner, string repository, string milestone, string targetCommitish, IList assets, bool prerelease, Config configuration) - { - var releaseNotesBuilder = new ReleaseNotesBuilder(new DefaultGitHubClient(github, owner, repository), owner, repository, milestone, configuration); - - var result = await releaseNotesBuilder.BuildReleaseNotes(); - - var releaseUpdate = CreateNewRelease(milestone, result, prerelease, targetCommitish); - - var release = await github.Repository.Release.Create(owner, repository, releaseUpdate); - - await AddAssets(github, assets, release); - - return release; - } - - private static async Task CreateReleaseFromInputFile(GitHubClient github, 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."); - } - - var inputFileContents = File.ReadAllText(inputFilePath); - - var releaseUpdate = CreateNewRelease(name, inputFileContents, prerelease, targetCommitish); - - var release = await github.Repository.Release.Create(owner, repository, releaseUpdate); - - await AddAssets(github, assets, release); - - return release; - } + public sealed class CreateSettings : BaseSettings + { + } - private static async Task AddAssets(GitHubClient github, string owner, string repository, string tagName, IList assets) + [Description("Adds an asset to an existing release.")] + public sealed class AddAssetCommand : Command + { + public override int Execute(CommandContext context, AddAssetSettings settings) { - var releases = await github.Repository.Release.GetAll(owner, repository); - - var release = releases.FirstOrDefault(r => r.TagName == tagName); - - if (release == null) - { - Logger.WriteError("Unable to find Release with specified tagName"); - return; - } - - await AddAssets(github, assets, release); + return 0; } + } - private static async Task ExportReleases(GitHubClient github, string owner, string repository, string tagName, Config configuration) - { - var releaseNotesExporter = new ReleaseNotesExporter(new DefaultGitHubClient(github, owner, repository), configuration); - - var result = await releaseNotesExporter.ExportReleaseNotes(tagName); + public sealed class AddAssetSettings : BaseSettings + { - return result; - } + } - private static async Task CloseMilestone(GitHubClient github, string owner, string repository, string milestoneTitle) + [Description("Creates a sample Yaml Configuration file in root directory")] + public sealed class InitCommand : BaseCommand + { + protected override int ExecuteCommand(CommandContext context, InitSettings settings) { - var milestoneClient = github.Issue.Milestone; - var openMilestones = await milestoneClient.GetAllForRepository(owner, repository, new MilestoneRequest { State = ItemStateFilter.Open }); - var milestone = openMilestones.FirstOrDefault(m => m.Title == milestoneTitle); - - if (milestone == null) - { - return; - } - - await milestoneClient.Update(owner, repository, milestone.Number, new MilestoneUpdate { State = ItemState.Closed }); + ConfigurationProvider.WriteSample(settings.TargetDirectory ?? Environment.CurrentDirectory, FileSystem); + return 0; } + } - private static async Task PublishRelease(GitHubClient github, string owner, string repository, string tagName) - { - var releases = await github.Repository.Release.GetAll(owner, repository); - var release = releases.FirstOrDefault(r => r.TagName == tagName); - - if (release == null) - { - return; - } + public sealed class InitSettings : BaseSettings + { - var releaseUpdate = new ReleaseUpdate { TagName = tagName, Draft = false }; + } - await github.Repository.Release.Edit(owner, repository, release.Id, releaseUpdate); - } + public abstract class BaseCommand : Command + where T : BaseSettings + { + private StringBuilder log = new StringBuilder(); + protected FileSystem FileSystem { get; } = new FileSystem(); - private static async Task AddAssets(GitHubClient github, IList assets, Release release) + public sealed override int Execute(CommandContext context, T settings) { - if (assets != null) - { - foreach (var asset in assets) - { - if (!File.Exists(asset)) - { - continue; - } - - var upload = new ReleaseAssetUpload - { - FileName = Path.GetFileName(asset), - ContentType = "application/octet-stream", - RawData = File.Open(asset, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) - }; - - await github.Repository.Release.UploadAsset(release, upload); + ConfigureLogging(settings.LogFilePath); - // Make sure to tidy up the stream that was created above - upload.RawData.Dispose(); - } - } + return ExecuteCommand(context, settings); } - private static NewRelease CreateNewRelease(string name, string body, bool prerelease, string targetCommitish) - { - var newRelease = new NewRelease(name) - { - Draft = true, - Body = body, - Name = name, - Prerelease = prerelease - }; - - if (!string.IsNullOrEmpty(targetCommitish)) - { - newRelease.TargetCommitish = targetCommitish; - } - - return newRelease; - } + protected abstract int ExecuteCommand(CommandContext context, T settings); [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Not required.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is required here.")] - private static void ConfigureLogging(string logFilePath) + private void ConfigureLogging(string logFilePath) { var writeActions = new List> { @@ -395,4 +130,17 @@ private static void WriteLogEntry(string logFilePath, string s) File.AppendAllText(logFilePath, contents); } } + + public abstract class BaseSettings : CommandSettings + { + [CommandOption("-d|--targetDirectory ")] + public string TargetDirectory { get; set; } + + [CommandOption("-l|--logFilePath ")] + public string LogFilePath { get; set; } + + // TODO: Move to higher level, not on every command + [CommandOption("--version")] + public bool Version { get; set; } + } } \ No newline at end of file diff --git a/tools/packages.config b/tools/packages.config index 6c62e9be..e130e680 100644 --- a/tools/packages.config +++ b/tools/packages.config @@ -1,4 +1,4 @@ - - - - + + + +