Skip to content

Commit df62fc7

Browse files
committed
Merge branch 'develop' of https://github.com/GitTools/GitReleaseManager into develop
2 parents 151724a + b7f9ebf commit df62fc7

28 files changed

+523
-15
lines changed

docs/input/docs/configuration/default-configuration.md

+15-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ create:
2020
sha-section-heading: "SHA256 Hashes of the release artifacts"
2121
sha-section-line-format: "- `{1}\t{0}`"
2222
allow-update-to-published: false
23+
include-contributors: false
2324
export:
2425
include-created-date-in-title: false
2526
created-date-string-format: ''
@@ -28,6 +29,7 @@ export:
2829
multiline-regex: false
2930
close:
3031
use-issue-comments: false
32+
set-due-date: false
3133
issue-comment: |-
3234
:tada: This issue has been resolved in version {milestone} :tada:
3335
@@ -135,6 +137,11 @@ control the look and feel of the generated release notes.
135137
- A boolean value which indicates whether or not updates can be applied to
136138
published releases. The default value is false. **NOTE:** This
137139
configuration option was added in version 0.11.0 of GitReleaseManager.
140+
- **include-contributors**
141+
- A boolean value which indicates whether the list of contributors is included
142+
in the release notes. A contributor is defined as someone who opened an issue
143+
or submitted a PR. **NOTE:** This configuration option was added in version
144+
0.19.0 of GitReleaseManager.
138145

139146
See the [example create configuration section](create-configuration) to see an
140147
example of how a footer can be configured.
@@ -176,10 +183,16 @@ tokenized values, such as milestone, owner, repository, with the actual values.
176183
- A boolean value which indicates whether or not comments are added to any
177184
closed issues that are included within a milestone, when it is being
178185
closed.
179-
- **issue-comment**
180-
- This is a template for what comment should be added to each issue. Within
186+
- **issue-comment**
187+
- This is a template for what comment should be added to each issue. Within
181188
this comment template, it is possible to replace information for example,
182189
the milestone name, the owner/repository information, etc.
190+
- **set-due-date**
191+
- A boolean value which indicates whether or not to set the due date of the
192+
milestone when closing it. The date which it is set to, is the same as the
193+
date at which the command was run, it is not possible to provide a
194+
different date. **NOTE:** This configuration option was added in version
195+
0.19.0 of GitReleaseManager.
183196

184197
## Default branch
185198

src/Directory.Packages.props

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
1111
<PackageVersion Include="coverlet.msbuild" Version="6.0.4" />
1212
<PackageVersion Include="Destructurama.Attributed" Version="5.1.0" />
13+
<PackageVersion Include="GraphQL.Client" Version="6.0.1" />
14+
<PackageVersion Include="GraphQL.Client.Serializer.SystemTextJson" Version="6.0.1" />
1315
<PackageVersion Include="IDisposableAnalyzers" Version="4.0.8" />
1416
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="9.0.0" />
1517
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.2" />

src/GitReleaseManager.Cli/Program.cs

+8
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
using GitReleaseManager.Core.Provider;
1414
using GitReleaseManager.Core.ReleaseNotes;
1515
using GitReleaseManager.Core.Templates;
16+
using GraphQL.Client.Http;
17+
using GraphQL.Client.Serializer.SystemTextJson;
1618
using Microsoft.Extensions.DependencyInjection;
1719
using NGitLab;
1820
using Octokit;
@@ -211,6 +213,12 @@ private static void RegisterVcsProvider(BaseVcsOptions vcsOptions, IServiceColle
211213
// default to Github
212214
serviceCollection
213215
.AddSingleton<IGitHubClient>((_) => new GitHubClient(new ProductHeaderValue("GitReleaseManager")) { Credentials = new Credentials(vcsOptions.Token) })
216+
.AddSingleton<GraphQL.Client.Abstractions.IGraphQLClient>(_ =>
217+
{
218+
var client = new GraphQLHttpClient(new GraphQLHttpClientOptions { EndPoint = new Uri("https://api.github.com/graphql") }, new SystemTextJsonSerializer());
219+
client.HttpClient.DefaultRequestHeaders.Add("Authorization", $"bearer {vcsOptions.Token}");
220+
return client;
221+
})
214222
.AddSingleton<IVcsProvider, GitHubProvider>();
215223
}
216224
}

src/GitReleaseManager.Core/Configuration/Config.cs

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public Config()
2727
ShaSectionHeading = "SHA256 Hashes of the release artifacts",
2828
ShaSectionLineFormat = "- `{1}\t{0}`",
2929
AllowUpdateToPublishedRelease = false,
30+
IncludeContributors = false,
3031
};
3132

3233
Export = new ExportConfig

src/GitReleaseManager.Core/Configuration/CreateConfig.cs

+3
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,8 @@ public class CreateConfig
3434

3535
[YamlMember(Alias = "allow-update-to-published")]
3636
public bool AllowUpdateToPublishedRelease { get; set; }
37+
38+
[YamlMember(Alias = "include-contributors")]
39+
public bool IncludeContributors { get; set; }
3740
}
3841
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text.Json;
5+
6+
namespace GitReleaseManager.Core.Extensions
7+
{
8+
internal static class JsonExtensions
9+
{
10+
/// <summary>
11+
/// Get a JsonElement from a path. Each level in the path is seperated by a dot.
12+
/// </summary>
13+
/// <param name="jsonElement">The parent Json element.</param>
14+
/// <param name="path">The path of the desired child element.</param>
15+
/// <returns>The child element.</returns>
16+
public static JsonElement GetJsonElement(this JsonElement jsonElement, string path)
17+
{
18+
if (jsonElement.ValueKind is JsonValueKind.Null || jsonElement.ValueKind is JsonValueKind.Undefined)
19+
{
20+
return default(JsonElement);
21+
}
22+
23+
string[] segments = path.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
24+
25+
foreach (var segment in segments)
26+
{
27+
if (int.TryParse(segment, out var index) && jsonElement.ValueKind == JsonValueKind.Array)
28+
{
29+
jsonElement = jsonElement.EnumerateArray().ElementAtOrDefault(index);
30+
if (jsonElement.ValueKind is JsonValueKind.Null || jsonElement.ValueKind is JsonValueKind.Undefined)
31+
{
32+
return default(JsonElement);
33+
}
34+
35+
continue;
36+
}
37+
38+
jsonElement = jsonElement.TryGetProperty(segment, out var value) ? value : default;
39+
40+
if (jsonElement.ValueKind is JsonValueKind.Null || jsonElement.ValueKind is JsonValueKind.Undefined)
41+
{
42+
return default(JsonElement);
43+
}
44+
}
45+
46+
return jsonElement;
47+
}
48+
49+
/// <summary>
50+
/// Get the first JsonElement matching a path from the provided list of paths.
51+
/// </summary>
52+
/// <param name="jsonElement">The parent Json element.</param>
53+
/// <param name="paths">The path of the desired child element.</param>
54+
/// <returns>The child element.</returns>
55+
public static JsonElement GetFirstJsonElement(this JsonElement jsonElement, IEnumerable<string> paths)
56+
{
57+
if (jsonElement.ValueKind is JsonValueKind.Null || jsonElement.ValueKind is JsonValueKind.Undefined)
58+
{
59+
return default(JsonElement);
60+
}
61+
62+
var element = default(JsonElement);
63+
64+
foreach (var path in paths)
65+
{
66+
element = jsonElement.GetJsonElement(path);
67+
68+
if (element.ValueKind is JsonValueKind.Null || element.ValueKind is JsonValueKind.Undefined)
69+
{
70+
continue;
71+
}
72+
73+
break;
74+
}
75+
76+
return element;
77+
}
78+
79+
public static string GetJsonElementValue(this JsonElement jsonElement) => jsonElement.ValueKind != JsonValueKind.Null &&
80+
jsonElement.ValueKind != JsonValueKind.Undefined
81+
? jsonElement.ToString()
82+
: default;
83+
}
84+
}

src/GitReleaseManager.Core/GitReleaseManager.Core.csproj

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
<ItemGroup>
2020
<PackageReference Include="CommandLineParser" />
2121
<PackageReference Include="Destructurama.Attributed" />
22+
<PackageReference Include="GraphQL.Client" />
23+
<PackageReference Include="GraphQL.Client.Serializer.SystemTextJson" />
2224
<PackageReference Include="Microsoft.SourceLink.GitHub">
2325
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2426
<PrivateAssets>all</PrivateAssets>

src/GitReleaseManager.Core/MappingProfiles/GitHubProfile.cs

+27-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Text.Json;
23
using AutoMapper;
34
using GitReleaseManager.Core.Extensions;
45

@@ -8,10 +9,11 @@ public class GitHubProfile : Profile
89
{
910
public GitHubProfile()
1011
{
12+
// These mappings convert the result of Octokit queries to model classes
1113
CreateMap<Octokit.Issue, Model.Issue>()
1214
.ForMember(dest => dest.PublicNumber, act => act.MapFrom(src => src.Number))
1315
.ForMember(dest => dest.InternalNumber, act => act.MapFrom(src => src.Id))
14-
.ForMember(dest => dest.IsPullRequest, act => act.MapFrom(src => src.HtmlUrl.IndexOf("/pull/", StringComparison.OrdinalIgnoreCase) >= 0))
16+
.ForMember(dest => dest.IsPullRequest, act => act.MapFrom(src => src.HtmlUrl.Contains("/pull/", StringComparison.OrdinalIgnoreCase)))
1517
.ReverseMap();
1618
CreateMap<Model.IssueComment, Octokit.IssueComment>().ReverseMap();
1719
CreateMap<Model.ItemState, Octokit.ItemState>().ReverseMap();
@@ -23,11 +25,35 @@ public GitHubProfile()
2325
CreateMap<Model.ReleaseAssetUpload, Octokit.ReleaseAssetUpload>().ReverseMap();
2426
CreateMap<Model.Label, Octokit.Label>().ReverseMap();
2527
CreateMap<Model.Label, Octokit.NewLabel>().ReverseMap();
28+
CreateMap<Model.User, Octokit.User>().ReverseMap();
2629
CreateMap<Model.Milestone, Octokit.Milestone>();
2730
CreateMap<Octokit.Milestone, Model.Milestone>()
2831
.ForMember(dest => dest.PublicNumber, act => act.MapFrom(src => src.Number))
2932
.ForMember(dest => dest.InternalNumber, act => act.MapFrom(src => src.Number))
3033
.AfterMap((src, dest) => dest.Version = src.Version());
34+
35+
// These mappings convert the result of GraphQL queries to model classes
36+
CreateMap<JsonElement, Model.Issue>()
37+
.ForMember(dest => dest.PublicNumber, act => act.MapFrom(src => src.GetProperty("number").GetInt32()))
38+
.ForMember(dest => dest.InternalNumber, act => act.MapFrom(src => -1)) // Not available in graphQL (there's a "id" property but it contains a string which represents the Node ID of the object).
39+
.ForMember(dest => dest.Title, act => act.MapFrom(src => src.GetProperty("title").GetString()))
40+
.ForMember(dest => dest.HtmlUrl, act => act.MapFrom(src => src.GetProperty("url").GetString()))
41+
.ForMember(dest => dest.IsPullRequest, act => act.MapFrom(src => src.GetProperty("url").GetString().Contains("/pull/", StringComparison.OrdinalIgnoreCase)))
42+
.ForMember(dest => dest.User, act => act.MapFrom(src => src.GetProperty("author")))
43+
.ForMember(dest => dest.Labels, act => act.MapFrom(src => src.GetJsonElement("labels.nodes").EnumerateArray()))
44+
.ReverseMap();
45+
46+
CreateMap<JsonElement, Model.Label>()
47+
.ForMember(dest => dest.Name, act => act.MapFrom(src => src.GetProperty("name").GetString()))
48+
.ForMember(dest => dest.Color, act => act.MapFrom(src => src.GetProperty("color").GetString()))
49+
.ForMember(dest => dest.Description, act => act.MapFrom(src => src.GetProperty("description").GetString()))
50+
.ReverseMap();
51+
52+
CreateMap<JsonElement, Model.User>()
53+
.ForMember(dest => dest.Login, act => act.MapFrom(src => src.GetProperty("login").GetString()))
54+
.ForMember(dest => dest.HtmlUrl, act => act.MapFrom(src => $"https://github.com{src.GetProperty("resourcePath").GetString()}")) // The resourcePath contains a value similar to "/jericho". That's why we must manually prepend "https://github.com
55+
.ForMember(dest => dest.AvatarUrl, act => act.MapFrom(src => src.GetProperty("avatarUrl").GetString()))
56+
.ReverseMap();
3157
}
3258
}
3359
}

src/GitReleaseManager.Core/MappingProfiles/GitLabProfile.cs

+12
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@ public GitLabProfile()
2323
.ForMember(dest => dest.PublicNumber, act => act.MapFrom(src => src.IssueId))
2424
.ForMember(dest => dest.HtmlUrl, act => act.MapFrom(src => src.WebUrl))
2525
.ForMember(dest => dest.IsPullRequest, act => act.MapFrom(src => false))
26+
.ForMember(dest => dest.User, act => act.MapFrom(src => src.Author))
2627
.ReverseMap();
2728
CreateMap<NGitLab.Models.MergeRequest, Model.Issue>()
2829
.ForMember(dest => dest.InternalNumber, act => act.MapFrom(src => src.Id))
2930
.ForMember(dest => dest.PublicNumber, act => act.MapFrom(src => src.Iid))
3031
.ForMember(dest => dest.HtmlUrl, act => act.MapFrom(src => src.WebUrl))
3132
.ForMember(dest => dest.IsPullRequest, act => act.MapFrom(src => true))
33+
.ForMember(dest => dest.User, act => act.MapFrom(src => src.Author))
3234
.ReverseMap();
3335
CreateMap<string, Model.Label>().ForMember(dest => dest.Name, act => act.MapFrom(src => src));
3436
CreateMap<Model.Release, NGitLab.Models.ReleaseCreate>()
@@ -43,6 +45,16 @@ public GitLabProfile()
4345
.ReverseMap();
4446
CreateMap<NGitLab.Models.MergeRequestComment, Model.IssueComment>()
4547
.ReverseMap();
48+
CreateMap<Model.User, NGitLab.Models.User>()
49+
.ForMember(dest => dest.Username, act => act.MapFrom(src => src.Login))
50+
.ForMember(dest => dest.WebURL, act => act.MapFrom(src => src.HtmlUrl))
51+
.ForMember(dest => dest.AvatarURL, act => act.MapFrom(src => src.AvatarUrl))
52+
.ReverseMap();
53+
CreateMap<Model.User, NGitLab.Models.Author>()
54+
.ForMember(dest => dest.Username, act => act.MapFrom(src => src.Login))
55+
.ForMember(dest => dest.WebUrl, act => act.MapFrom(src => src.HtmlUrl))
56+
.ForMember(dest => dest.AvatarUrl, act => act.MapFrom(src => src.AvatarUrl))
57+
.ReverseMap();
4658
}
4759
}
4860
}

src/GitReleaseManager.Core/Model/Issue.cs

+4
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,9 @@ public sealed class Issue
1515
public IReadOnlyList<Label> Labels { get; set; }
1616

1717
public bool IsPullRequest { get; set; }
18+
19+
public User User { get; set; }
20+
21+
public IReadOnlyList<Issue> LinkedIssues { get; set; }
1822
}
1923
}

src/GitReleaseManager.Core/Model/IssueComment.cs

+5
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,10 @@ public class IssueComment
1111
/// Gets or sets details about the issue comment.
1212
/// </summary>
1313
public string Body { get; set; }
14+
15+
/// <summary>
16+
/// Gets or sets information about the user who made the comment.
17+
/// </summary>
18+
public User User { get; set; }
1419
}
1520
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace GitReleaseManager.Core.Model
2+
{
3+
public sealed class User
4+
{
5+
public string Login { get; set; }
6+
7+
public string HtmlUrl { get; set; }
8+
9+
public string AvatarUrl { get; set; }
10+
}
11+
}

0 commit comments

Comments
 (0)