From 1bf7a462e9c7ad8c2fd91e79c7ee07cabb8e56dc Mon Sep 17 00:00:00 2001 From: Igor Velikorossov Date: Wed, 12 Feb 2025 14:37:47 +1100 Subject: [PATCH 1/2] Allow opt-in/out of pulling issues data If no source of data is selected, then pull issues data. Otherwise only pull the desired data. --- ghdump/Program.cs | 44 ++++++++++++++++++++++++++++++-------------- ghdump/ghdump.csproj | 4 ++-- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/ghdump/Program.cs b/ghdump/Program.cs index 78c213d3..ae83674a 100644 --- a/ghdump/Program.cs +++ b/ghdump/Program.cs @@ -49,6 +49,7 @@ AllowMultipleArgumentsPerToken = true }; +var includeIssuesOption = new Option(["-i", "--include-issues"], () => null, "Include GitHub issues."); var includePullsOption = new Option(["-p", "--include-pull-requests"], () => null, "Include GitHub pull-requests."); var includeDiscussionsOption = new Option(["-d", "--include-discussions"], () => null, "Include GitHub discussions."); @@ -59,26 +60,34 @@ accessToken, repoOption, labelOption, + includeIssuesOption, includePullsOption, includeDiscussionsOption, outputPath }; -rootCommand.SetHandler(RunAsync, accessToken, repoOption, labelOption, includePullsOption, includeDiscussionsOption, outputPath); +rootCommand.SetHandler(RunAsync, accessToken, repoOption, labelOption, includeIssuesOption, includePullsOption, includeDiscussionsOption, outputPath); await rootCommand.InvokeAsync(args); -async Task RunAsync(string? accessToken, string? repo, string[] labels, bool? includePullRequests, bool? includeDiscussions, string? outputDirectory) +async Task RunAsync(string? accessToken, string? repo, string[] labels, bool? includeIssues, bool? includePullRequests, bool? includeDiscussions, string? outputDirectory) { accessToken ??= configAccessToken; - includeDiscussions ??= labels is []; outputDirectory ??= Environment.CurrentDirectory; - bool includePulls = includePullRequests ?? false; + bool issuesIncluded = includeIssues ?? false; + bool pullsIncluded = includePullRequests ?? false; + bool discussionsIncluded = includeDiscussions ?? false; + + if (!issuesIncluded && !pullsIncluded && !discussionsIncluded) + { + // If no options are specified, include issues by default + issuesIncluded = true; + } var (repoOwner, repoName) = repo?.Trim().Split('/', StringSplitOptions.RemoveEmptyEntries) switch { - [var owner, var name] => (owner, name), + [var owner, var name] => (owner, name), _ => throw new InvalidOperationException("Invalid repository format, expected owner/repo. Example: dotnet/aspnetcore.") }; @@ -102,8 +111,9 @@ async Task RunAsync(string? accessToken, string? repo, string[] labels, bool? in Console.WriteLine("No Labels specified."); } - Console.WriteLine($"Including pull-requests: {(includePulls ? "yes" : "no")}"); - Console.WriteLine($"Including discussions: {(includeDiscussions.Value ? "yes" : "no")}"); + Console.WriteLine($"Including issues: {(issuesIncluded ? "yes" : "no")}"); + Console.WriteLine($"Including pull-requests: {(pullsIncluded ? "yes" : "no")}"); + Console.WriteLine($"Including discussions: {(discussionsIncluded ? "yes" : "no")}"); Console.WriteLine($"Results directory: {outputDirectory}"); if (!await CheckRepositoryValid(repoOwner, repoName)) @@ -113,9 +123,9 @@ async Task RunAsync(string? accessToken, string? repo, string[] labels, bool? in var sw = Stopwatch.StartNew(); - var discussionsTask = GetDiscussionsAsync(includeDiscussions.Value); - var issuesTask = GetIssuesAsync(labels); - var pullsTask = GetPullRequestsAsync(labels, includePulls); + var discussionsTask = GetDiscussionsAsync(discussionsIncluded); + var issuesTask = GetIssuesAsync(labels, issuesIncluded); + var pullsTask = GetPullRequestsAsync(labels, pullsIncluded); await Task.WhenAll(discussionsTask, issuesTask, pullsTask); @@ -125,7 +135,7 @@ async Task RunAsync(string? accessToken, string? repo, string[] labels, bool? in var pulls = await pullsTask; var discussions = await discussionsTask; - await WriteResultsToDisk(outputDirectory, issues, includePulls, pulls, includeDiscussions.Value, discussions, sw.Elapsed); + await WriteResultsToDisk(outputDirectory, issuesIncluded, issues, pullsIncluded, pulls, discussionsIncluded, discussions, sw.Elapsed); async Task CheckRepositoryValid(string repoOwner, string repoName) { @@ -157,6 +167,7 @@ async Task CheckRepositoryValid(string repoOwner, string repoName) async Task WriteResultsToDisk( string outputDirectory, + bool includeIssues, List issues, bool includePullRequests, List pullRequests, @@ -180,7 +191,7 @@ async Task WriteResultsToDisk( Console.WriteLine($"Processed {issues.Count} issues."); Console.WriteLine($"Issues have been written to {fileName}."); } - else + else if (includeIssues) { Console.WriteLine("No issues found."); } @@ -225,8 +236,13 @@ async Task WriteResultsToDisk( } - async Task> GetIssuesAsync(string[] labels) + async Task> GetIssuesAsync(string[] labels, bool includeIssues) { + if (!includeIssues) + { + return []; + } + string? issuesCursor = null; GraphqlResponse? graphqlResult = null; @@ -596,7 +612,7 @@ async Task> GetPullRequestsAsync(string[] labels, bool in { var issue = issueEdge.Node; - Console.WriteLine($"Processing issue {issue.Title} ({issue.Url})"); + Console.WriteLine($"Processing pull-request {issue.Title} ({issue.Url})"); var issueJson = new GithubIssueModel { diff --git a/ghdump/ghdump.csproj b/ghdump/ghdump.csproj index 987cad1e..2824bb5c 100644 --- a/ghdump/ghdump.csproj +++ b/ghdump/ghdump.csproj @@ -6,8 +6,8 @@ enable enable 7daf1c07-0951-4b52-a198-e4a9c20265e7 - ghdump - true + ghdump + true From 3daffa1efe7990a11b8b7907eba7d2ca8d8d7cdb Mon Sep 17 00:00:00 2001 From: Igor Velikorossov Date: Wed, 12 Feb 2025 15:55:05 +1100 Subject: [PATCH 2/2] Pull issue/pull-request author information --- ghdump/Models.cs | 3 +++ ghdump/Program.cs | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/ghdump/Models.cs b/ghdump/Models.cs index b3424d00..635bc10b 100644 --- a/ghdump/Models.cs +++ b/ghdump/Models.cs @@ -80,6 +80,7 @@ public class IssueConnection public class Issue { public required string Id { get; set; } + public required Author Author { get; set; } public required string Title { get; set; } public required string Body { get; set; } public required string Url { get; set; } @@ -99,6 +100,7 @@ public class PullRequestConnection public class PullRequest { public required string Id { get; set; } + public required Author Author { get; set; } public required string Title { get; set; } public required string Body { get; set; } public required string Url { get; set; } @@ -136,6 +138,7 @@ public class GithubDiscussionModel public class GithubIssueModel { public required string Id { get; set; } + public required string Author { get; set; } public required string Title { get; set; } public required string URL { get; set; } public required DateTime CreatedAt { get; set; } diff --git a/ghdump/Program.cs b/ghdump/Program.cs index ae83674a..4eaa60a8 100644 --- a/ghdump/Program.cs +++ b/ghdump/Program.cs @@ -257,6 +257,9 @@ async Task> GetIssuesAsync(string[] labels, bool includeI edges { node { id + author { + login + } title body url @@ -341,6 +344,7 @@ async Task> GetIssuesAsync(string[] labels, bool includeI var issueJson = new GithubIssueModel { Id = issue.Id, + Author = issue.Author?.Login ?? "??", Title = issue.Title, URL = issue.Url, CreatedAt = DateTime.Parse(issue.CreatedAt).ToUniversalTime(), @@ -533,6 +537,9 @@ async Task> GetPullRequestsAsync(string[] labels, bool in edges { node { id + author { + login + } title body url @@ -617,6 +624,7 @@ async Task> GetPullRequestsAsync(string[] labels, bool in var issueJson = new GithubIssueModel { Id = issue.Id, + Author = issue.Author?.Login ?? "??", Title = issue.Title, URL = issue.Url, CreatedAt = DateTime.Parse(issue.CreatedAt).ToUniversalTime(),