1
1
using System ;
2
2
using System . Collections . Generic ;
3
3
using System . Collections . Immutable ;
4
+ using System . Diagnostics ;
5
+ using System . IO ;
4
6
using System . Linq ;
5
7
using System . Text ;
6
8
using System . Threading . Tasks ;
9
+ using Cake . Core . IO ;
10
+ using JetBrains . Annotations ;
7
11
using Octokit ;
8
12
9
- namespace ChangeLogBuilder
13
+ namespace Build ;
14
+
15
+ public static class OctokitExtensions
10
16
{
17
+ public static string ToStr ( this User user , string prefix ) => user != null
18
+ ? $ " ({ prefix } [@{ user . Login } ]({ user . HtmlUrl } ))"
19
+ : "" ;
20
+
21
+ private static string ToStr ( this Author user , string prefix ) => user != null
22
+ ? $ " ({ prefix } { user . ToLink ( ) } )"
23
+ : "" ;
24
+
25
+ private static string ToStr ( this Committer user , string prefix ) => user != null
26
+ ? $ " ({ prefix } { user . Name } )"
27
+ : "" ;
28
+
29
+ public static string ToLink ( this Author user ) => $ "[@{ user . Login } ]({ user . HtmlUrl } )";
30
+
31
+ public static string ToLinkWithName ( this Author user , string name ) => $ "[@{ user . Login } ({ name } )]({ user . HtmlUrl } )";
32
+
33
+ public static string ToCommitMessage ( this Commit commit )
34
+ {
35
+ var message = commit . Message . Trim ( ) . Split ( new [ ] { '\r ' , '\n ' } , StringSplitOptions . RemoveEmptyEntries )
36
+ . FirstOrDefault ( ) ?? "" ;
37
+ return message . Length > 80 ? message . Substring ( 0 , 77 ) + "..." : message ;
38
+ }
39
+
40
+ public static string ToLink ( this GitHubCommit commit ) => $ "[{ commit . Sha . Substring ( 0 , 6 ) } ]({ commit . HtmlUrl } )";
41
+
42
+ public static string ToByStr ( this GitHubCommit commit )
43
+ {
44
+ if ( commit . Author != null )
45
+ return commit . Author . ToStr ( "by" ) ;
46
+ return commit . Commit . Author != null ? commit . Commit . Author . ToStr ( "by" ) : "" ;
47
+ }
48
+ }
49
+
50
+ public class ChangeLogBuilder
51
+ {
52
+ public class Config
53
+ {
54
+ [ PublicAPI ] public string ProductHeader => Environment . GetEnvironmentVariable ( "GITHUB_PRODUCT" ) ;
55
+ [ PublicAPI ] public string Token => Environment . GetEnvironmentVariable ( "GITHUB_TOKEN" ) ;
56
+
57
+ [ PublicAPI ] public string RepoOwner => "dotnet" ;
58
+ [ PublicAPI ] public string RepoName => "BenchmarkDotNet" ;
59
+ [ PublicAPI ] public string CurrentMilestone { get ; }
60
+
61
+ [ PublicAPI ] public string PreviousMilestone { get ; }
62
+ [ PublicAPI ] public string LastCommit { get ; }
63
+
64
+ public void Deconstruct ( out string repoOwner , out string repoName , out string currentMilestone ,
65
+ out string previousMilestone , out string lastCommit )
66
+ {
67
+ repoOwner = RepoOwner ;
68
+ repoName = RepoName ;
69
+ currentMilestone = CurrentMilestone ;
70
+ previousMilestone = PreviousMilestone ;
71
+ lastCommit = LastCommit ;
72
+ }
73
+
74
+ public Config ( string [ ] args )
75
+ {
76
+ CurrentMilestone = args [ 0 ] ;
77
+ PreviousMilestone = args [ 1 ] ;
78
+ LastCommit = args . Length <= 2 ? CurrentMilestone : args [ 2 ] ;
79
+ }
80
+
81
+ public Config ( string currentMilestone , string previousMilestone , string lastCommit )
82
+ {
83
+ CurrentMilestone = currentMilestone ;
84
+ PreviousMilestone = previousMilestone ;
85
+ LastCommit = lastCommit ;
86
+ }
87
+ }
88
+
89
+ public class AuthorEqualityComparer : IEqualityComparer < Author >
90
+ {
91
+ public static readonly IEqualityComparer < Author > Default = new AuthorEqualityComparer ( ) ;
92
+
93
+ public bool Equals ( Author x , Author y ) => x . Login == y . Login ;
94
+
95
+ public int GetHashCode ( Author author ) => author . Login . GetHashCode ( ) ;
96
+ }
97
+
11
98
public class MarkdownBuilder
12
99
{
13
100
private readonly Config config ;
14
- private readonly StringBuilder builder ;
101
+ private readonly StringBuilder builder ;
15
102
16
103
public static async Task < string > Build ( Config config )
17
104
{
@@ -27,7 +114,7 @@ private MarkdownBuilder(Config config)
27
114
private async Task < string > Build ( )
28
115
{
29
116
var ( repoOwner , repoName , milestone , previousMilestone , lastCommit ) = config ;
30
-
117
+
31
118
var client = new GitHubClient ( new ProductHeaderValue ( config . ProductHeader ) ) ;
32
119
var tokenAuth = new Credentials ( config . Token ) ;
33
120
client . Credentials = tokenAuth ;
@@ -48,7 +135,7 @@ private async Task<string> Build()
48
135
49
136
return builder . ToString ( ) ;
50
137
}
51
-
138
+
52
139
var issueRequest = new RepositoryIssueRequest
53
140
{
54
141
State = ItemStateFilter . Closed
@@ -72,7 +159,7 @@ private async Task<string> Build()
72
159
73
160
var compare = await client . Repository . Commit . Compare ( repoOwner , repoName , previousMilestone , lastCommit ) ;
74
161
var commits = compare . Commits ;
75
-
162
+
76
163
var authorNames = new Dictionary < string , string > ( ) ;
77
164
foreach ( var contributor in commits . Select ( commit => commit . Author ) )
78
165
if ( contributor != null && ! authorNames . ContainsKey ( contributor . Login ) )
@@ -81,6 +168,7 @@ private async Task<string> Build()
81
168
var name = user ? . Name ;
82
169
authorNames [ contributor . Login ] = string . IsNullOrWhiteSpace ( name ) ? contributor . Login : name ;
83
170
}
171
+
84
172
var contributors = compare . Commits
85
173
. Select ( commit => commit . Author )
86
174
. Where ( author => author != null )
@@ -89,7 +177,7 @@ private async Task<string> Build()
89
177
. ToImmutableList ( ) ;
90
178
91
179
var milestoneHtmlUlr = $ "https://github.com/{ repoOwner } /{ repoName } /issues?q=milestone:{ milestone } ";
92
-
180
+
93
181
builder . AppendLine ( "## Milestone details" ) ;
94
182
builder . AppendLine ( ) ;
95
183
builder . AppendLine ( $ "In the [{ milestone } ]({ milestoneHtmlUlr } ) scope, ") ;
@@ -105,7 +193,7 @@ private async Task<string> Build()
105
193
AppendList ( "Commits" , commits , commit =>
106
194
$ "{ commit . ToLink ( ) } { commit . Commit . ToCommitMessage ( ) } { commit . ToByStr ( ) } ") ;
107
195
AppendList ( "Contributors" , contributors , contributor =>
108
- $ "{ authorNames [ contributor . Login ] } ({ contributor . ToLink ( ) } )". Trim ( ) ,
196
+ $ "{ authorNames [ contributor . Login ] } ({ contributor . ToLink ( ) } )". Trim ( ) ,
109
197
"Thank you very much!" ) ;
110
198
111
199
return builder . ToString ( ) ;
@@ -127,4 +215,18 @@ private void AppendList<T>(string title, IReadOnlyList<T> items, Func<T, string>
127
215
builder . AppendLine ( ) ;
128
216
}
129
217
}
130
- }
218
+
219
+ public static async Task Run ( DirectoryPath path , string currentMilestone , string previousMilestone , string lastCommit )
220
+ {
221
+ try
222
+ {
223
+ var config = new Config ( currentMilestone , previousMilestone , lastCommit ) ;
224
+ var releaseNotes = await MarkdownBuilder . Build ( config ) ;
225
+ await File . WriteAllTextAsync ( path . Combine ( config . CurrentMilestone + ".md" ) . FullPath , releaseNotes ) ;
226
+ }
227
+ catch ( Exception e )
228
+ {
229
+ await Console . Error . WriteLineAsync ( e . Demystify ( ) . ToString ( ) ) ;
230
+ }
231
+ }
232
+ }
0 commit comments