diff --git a/jihub.Github/DependencyInjection/GithubServiceCollectionExtension.cs b/jihub.Github/DependencyInjection/GithubServiceCollectionExtension.cs index 3f83f3e..d574bca 100644 --- a/jihub.Github/DependencyInjection/GithubServiceCollectionExtension.cs +++ b/jihub.Github/DependencyInjection/GithubServiceCollectionExtension.cs @@ -12,6 +12,7 @@ public static IServiceCollection AddGithubService(this IServiceCollection servic { services.AddOptions() .Bind(section) + .ValidateDataAnnotations() .ValidateOnStart(); var sp = services.BuildServiceProvider(); diff --git a/jihub.Jira/DependencyInjection/JiraServiceCollectionExtension.cs b/jihub.Jira/DependencyInjection/JiraServiceCollectionExtension.cs index e42c6ad..20d31cb 100644 --- a/jihub.Jira/DependencyInjection/JiraServiceCollectionExtension.cs +++ b/jihub.Jira/DependencyInjection/JiraServiceCollectionExtension.cs @@ -11,6 +11,7 @@ public static IServiceCollection AddJiraService(this IServiceCollection services { services.AddOptions() .Bind(section) + .ValidateDataAnnotations() .ValidateOnStart(); var sp = services.BuildServiceProvider(); diff --git a/jihub.Parsers/DependencyInjection/ParserServiceCollectionExtension.cs b/jihub.Parsers/DependencyInjection/ParserServiceCollectionExtension.cs index a414f3a..74c9952 100644 --- a/jihub.Parsers/DependencyInjection/ParserServiceCollectionExtension.cs +++ b/jihub.Parsers/DependencyInjection/ParserServiceCollectionExtension.cs @@ -10,6 +10,7 @@ public static IServiceCollection AddParsers(this IServiceCollection services, IC { services.AddOptions() .Bind(section) + .ValidateDataAnnotations() .ValidateOnStart(); services diff --git a/jihub.Worker/Program.cs b/jihub.Worker/Program.cs index 12ab536..fce206f 100644 --- a/jihub.Worker/Program.cs +++ b/jihub.Worker/Program.cs @@ -1,24 +1,4 @@ -/******************************************************************************** - * Copyright (c) 2021, 2023 BMW Group AG - * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -using CommandLine; +using CommandLine; using jihub; using jihub.Base; using jihub.Github.DependencyInjection; @@ -29,48 +9,38 @@ try { + var options = Parser.Default.ParseArguments(args) + .MapResult(opts => + { + opts.Validate(); + return opts; + }, + err => + { + foreach (var error in err) + Console.WriteLine(error.Tag.ToString()); + + throw new ArgumentException("failed to parse options"); + }); + Console.WriteLine("Building worker"); - var host = Host + await Host .CreateDefaultBuilder(args) .ConfigureServices((hostContext, services) => { + Console.WriteLine("Building services"); services - .AddTransient() .AddJiraService(hostContext.Configuration.GetSection("Jira")) .AddGithubService(hostContext.Configuration.GetSection("Github")) .AddParsers(hostContext.Configuration.GetSection("Parsers")) .AddLogging(); - }) - .Build(); - Console.WriteLine("Building importer completed"); - - var cts = new CancellationTokenSource(); - Console.CancelKeyPress += (s, e) => - { - Console.WriteLine("Canceling..."); - cts.Cancel(); - e.Cancel = true; - }; - Console.WriteLine("Starting..."); - var workerInstance = host.Services.GetRequiredService(); - await Parser.Default.ParseArguments(args) - .MapResult(async opts => - { - opts.Validate(); + services.AddSingleton(options); + services + .AddHostedService(); + }) + .RunConsoleAsync(); - try - { - // We have the parsed arguments, so let's just pass them down - return await workerInstance.ExecuteAsync(opts, cts.Token); - } - catch - { - Console.WriteLine("Error!"); - return -3; // Unhandled error - } - }, - _ => Task.FromResult(-1)); Console.WriteLine("Execution finished shutting down"); } catch (Exception ex) diff --git a/jihub.Worker/Worker.cs b/jihub.Worker/Worker.cs index 70d27d8..ca5c9e6 100644 --- a/jihub.Worker/Worker.cs +++ b/jihub.Worker/Worker.cs @@ -5,6 +5,7 @@ using jihub.Jira.Models; using jihub.Parsers.Jira; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace jihub; @@ -12,63 +13,66 @@ namespace jihub; /// /// Worker to process the jql query. /// -public class Worker +public class Worker : IHostedService { - private readonly IServiceScopeFactory _serviceScopeFactory; + private readonly IJiraService _jiraService; + private readonly IGithubService _githubService; + private readonly IJiraParser _jiraParser; + private readonly JihubOptions _jihubOptions; private readonly ILogger _logger; /// /// Creates a new instance of /// - /// access to the services + /// + /// /// the logger + /// + /// public Worker( - IServiceScopeFactory serviceScopeFactory, + IJiraService jiraService, + IGithubService githubService, + IJiraParser jiraParser, + JihubOptions jihubOptions, ILogger logger) { - _serviceScopeFactory = serviceScopeFactory; + _jiraService = jiraService; + _githubService = githubService; + _jiraParser = jiraParser; + _jihubOptions = jihubOptions; _logger = logger; } - /// - /// Handles the conversion from jira to github issues and the import to github - /// - /// the options given by the user - /// Cancellation Token - public async Task ExecuteAsync(JihubOptions options, CancellationToken cts) + /// + public async Task StartAsync(CancellationToken cts) { try { - using var scope = _serviceScopeFactory.CreateScope(); - var jiraService = scope.ServiceProvider.GetRequiredService(); - var githubService = scope.ServiceProvider.GetRequiredService(); - var parser = scope.ServiceProvider.GetRequiredService(); - - var jiraIssues = await jiraService.GetAsync(options.SearchQuery, options.MaxResults, cts).ConfigureAwait(false); + var jiraIssues = await _jiraService.GetAsync(_jihubOptions.SearchQuery, _jihubOptions.MaxResults, cts).ConfigureAwait(false); var content = Enumerable.Empty(); - if (options.Export) + if (_jihubOptions.Export) { - content = await githubService.GetRepoContent(options.ImportOwner!, options.UploadRepo!, "contents", cts).ConfigureAwait(false); + content = await _githubService.GetRepoContent(_jihubOptions.ImportOwner!, _jihubOptions.UploadRepo!, "contents", cts).ConfigureAwait(false); } - var githubInformation = await githubService.GetRepositoryData(options.Owner, options.Repo, cts).ConfigureAwait(false); + var githubInformation = await _githubService.GetRepositoryData(_jihubOptions.Owner, _jihubOptions.Repo, cts).ConfigureAwait(false); var excludedJiraIssues = jiraIssues.Where(x => githubInformation.Issues.Any(i => i.Title.Contains($"(ext: {x.Key})"))); _logger.LogInformation("The following issues were not imported because they are already available in Github {Issues}", string.Join(",", excludedJiraIssues.Select(x => x.Key))); - var convertedIssues = await parser.ConvertIssues(jiraIssues.Except(excludedJiraIssues), options, content, githubInformation.Labels.ToList(), githubInformation.Milestones.ToList(), cts).ConfigureAwait(false); - var createdIssues = await githubService.CreateIssuesAsync(options.Owner, options.Repo, convertedIssues, cts).ConfigureAwait(false); + var convertedIssues = await _jiraParser.ConvertIssues(jiraIssues.Except(excludedJiraIssues), _jihubOptions, content, githubInformation.Labels.ToList(), githubInformation.Milestones.ToList(), cts).ConfigureAwait(false); + var createdIssues = await _githubService.CreateIssuesAsync(_jihubOptions.Owner, _jihubOptions.Repo, convertedIssues, cts).ConfigureAwait(false); - if (options.LinkChildren) + if (_jihubOptions.LinkChildren) { var childIssues = GetLinks(jiraIssues, "Parent of"); - await githubService.LinkChildren(options.Owner, options.Repo, childIssues, githubInformation.Issues, createdIssues, cts).ConfigureAwait(false); + await _githubService.LinkChildren(_jihubOptions.Owner, _jihubOptions.Repo, childIssues, githubInformation.Issues, createdIssues, cts).ConfigureAwait(false); } - if (options.LinkRelated) + if (_jihubOptions.LinkRelated) { var relatedIssues = GetLinks(jiraIssues, "relates to"); - await githubService.AddRelatesComment(options.Owner, options.Repo, relatedIssues, githubInformation.Issues, createdIssues, cts).ConfigureAwait(false); + await _githubService.AddRelatesComment(_jihubOptions.Owner, _jihubOptions.Repo, relatedIssues, githubInformation.Issues, createdIssues, cts).ConfigureAwait(false); } } catch (Exception ex) @@ -76,8 +80,6 @@ public async Task ExecuteAsync(JihubOptions options, CancellationToken cts) Environment.ExitCode = 1; _logger.LogError(ex, "processing failed with following Exception {ExceptionMessage}", ex.Message); } - - return 0; } private static Dictionary> GetLinks(IEnumerable jiraIssues, string linkType) @@ -105,4 +107,10 @@ private static Dictionary> GetLinks(IEnumerable return dict; } + + /// + public Task StopAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } }