2
2
#tool "nuget:?package=Mono.TextTransform&version=1.0.0"
3
3
#tool "nuget:?package=GitVersion.CommandLine&version=4.0.0"
4
4
#addin "nuget:?package=Cake.Incubator&version=4.0.1"
5
+ #addin "nuget:?package=Cake.SemVer&version=3.0.0"
6
+ #addin "nuget:?package=semver&version=2.0.4"
7
+ #addin "nuget:?package=ConsoleMenuLib&version=3.2.1"
8
+ #addin "nuget:?package=System.Interactive.Async&version=3.2.0"
5
9
6
10
using System . Reflection ;
7
11
using System . Text . RegularExpressions ;
8
12
using System . Xml . Linq ;
9
13
using Cake . Incubator . LoggingExtensions ;
14
+ using ConsoleUi ;
10
15
11
16
//////////////////////////////////////////////////////////////////////
12
17
// ARGUMENTS
@@ -33,7 +38,7 @@ if (!IsRunningOnWindows())
33
38
releaseConfigurations . Add ( "Debug-AOT" ) ;
34
39
}
35
40
36
- var nugetVersion = "0.0.1" ;
41
+ GitVersion version = null ;
37
42
38
43
//////////////////////////////////////////////////////////////////////
39
44
// TASKS
@@ -62,42 +67,37 @@ Task("Restore-NuGet-Packages")
62
67
NuGetRestore ( solutionPath ) ;
63
68
} ) ;
64
69
65
- Task ( "Show -Version" )
70
+ Task ( "Get -Version" )
66
71
. Does ( ( ) =>
67
72
{
68
- var version = GitVersion ( new GitVersionSettings
73
+ version = GitVersion ( new GitVersionSettings
69
74
{
70
75
UpdateAssemblyInfo = false ,
71
76
} ) ;
72
77
73
- Information ( "Version:\n {0}" , version . Dump ( ) ) ;
78
+ if ( AppVeyor . IsRunningOnAppVeyor )
79
+ {
80
+ if ( ! string . IsNullOrEmpty ( version . PreReleaseTag ) )
81
+ {
82
+ version . NuGetVersion = string . Format ( "{0}-{1}{2}" , version . MajorMinorPatch , version . PreReleaseLabel , AppVeyor . Environment . Build . Version . Replace ( "0.0." , "" ) . PadLeft ( 4 , '0' ) ) ;
83
+ }
84
+ AppVeyor . UpdateBuildVersion ( version . NuGetVersion ) ;
85
+ }
86
+
87
+ Information ( "Building release:\n {0}" , version . Dump ( ) ) ;
74
88
} ) ;
75
89
76
90
Task ( "Set-Build-Version" )
91
+ . IsDependentOn ( "Get-Version" )
77
92
. Does ( ( ) =>
78
93
{
79
- var version = GitVersion ( new GitVersionSettings
80
- {
81
- UpdateAssemblyInfo = false ,
82
- } ) ;
83
- nugetVersion = version . NuGetVersion ;
84
-
85
94
var assemblyInfo = TransformTextFile ( "YamlDotNet/Properties/AssemblyInfo.template" )
86
95
. WithToken ( "assemblyVersion" , $ "{ version . Major } .0.0.0")
87
96
. WithToken ( "assemblyFileVersion" , $ "{ version . MajorMinorPatch } .0")
88
- . WithToken ( "assemblyInformationalVersion" , nugetVersion )
97
+ . WithToken ( "assemblyInformationalVersion" , version . NuGetVersion )
89
98
. ToString ( ) ;
90
99
91
100
System . IO . File . WriteAllText ( "YamlDotNet/Properties/AssemblyInfo.cs" , assemblyInfo ) ;
92
-
93
- if ( AppVeyor . IsRunningOnAppVeyor )
94
- {
95
- if ( ! string . IsNullOrEmpty ( version . PreReleaseTag ) )
96
- {
97
- nugetVersion = string . Format ( "{0}-{1}{2}" , version . MajorMinorPatch , version . PreReleaseLabel , AppVeyor . Environment . Build . Version . Replace ( "0.0." , "" ) . PadLeft ( 4 , '0' ) ) ;
98
- }
99
- AppVeyor . UpdateBuildVersion ( nugetVersion ) ;
100
- }
101
101
} ) ;
102
102
103
103
Task ( "Build" )
@@ -168,11 +168,132 @@ Task("Package")
168
168
169
169
NuGetPack ( finalNuspecFile , new NuGetPackSettings
170
170
{
171
- Version = nugetVersion ,
171
+ Version = version . NuGetVersion ,
172
172
OutputDirectory = Directory ( "YamlDotNet/bin" ) ,
173
173
} ) ;
174
174
} ) ;
175
175
176
+ Task ( "Release" )
177
+ . IsDependentOn ( "Get-Version" )
178
+ . WithCriteria ( ( ) => version . BranchName == "master" , "Releases must be created from the master branch" )
179
+ . Does ( ( ) =>
180
+ {
181
+ // Find previous release
182
+ var releases = RunProcess ( "git" , "tag" , "--list" , "--merged" , "master" , "--format=\" %(refname:short)\" " , "v*" )
183
+ . Select ( tag => new
184
+ {
185
+ Tag = tag ,
186
+ Version = ParseSemVer ( tag . TrimStart ( 'v' ) ) ,
187
+ } )
188
+ . OrderByDescending ( v => v . Version )
189
+ . ToList ( ) ;
190
+
191
+ var previousVersion = releases . First ( ) ;
192
+
193
+ Information ( "The previous release was {0}" , previousVersion . Version ) ;
194
+
195
+ var releaseNotesPath = Directory ( "releases" ) . Path . CombineWithFilePath ( $ "{ version . NuGetVersion } .md") . FullPath ;
196
+ Action scaffoldReleaseNotes = ( ) =>
197
+ {
198
+ // Get the git log to scaffold the release notes
199
+ string currentHash = null ;
200
+ var commits = RunProcess ( "git" , "rev-list" , $ "{ previousVersion . Tag } ..HEAD", "--first-parent" , "--reverse" , "--pretty=tformat:%B" )
201
+ . Select ( l =>
202
+ {
203
+ var match = Regex . Match ( l , "^commit (?<hash>[a-f0-9]+)$" ) ;
204
+ if ( match . Success )
205
+ {
206
+ currentHash = match . Groups [ "hash" ] . Value ;
207
+ }
208
+ return new
209
+ {
210
+ message = l ,
211
+ commit = currentHash
212
+ } ;
213
+ } )
214
+ . GroupBy ( l => l . commit , ( k , list ) => new
215
+ {
216
+ commit = k ,
217
+ message = list
218
+ . Skip ( 1 )
219
+ . Select ( l => l . message . Trim ( ) )
220
+ . Where ( l => ! string . IsNullOrEmpty ( l ) )
221
+ . ToList ( )
222
+ } ) ;
223
+
224
+ var log = commits
225
+ . Select ( c => c . message . Select ( ( l , i ) => $ "{ ( i == 0 ? '-' : ' ' ) } { l } ") )
226
+ . Select ( c => string . Join ( " \n " , c ) ) ;
227
+
228
+ var releaseNotes = $ "# Release { version . NuGetVersion } \n \n { string . Join ( "\n \n " , log ) } ";
229
+ System . IO . File . WriteAllText ( releaseNotesPath , releaseNotes ) ;
230
+ } ;
231
+
232
+ if ( ! FileExists ( releaseNotesPath ) )
233
+ {
234
+ scaffoldReleaseNotes ( ) ;
235
+ }
236
+
237
+ // Show release menu
238
+ Menu menu = null ;
239
+
240
+ Action updateMenuDescription = ( ) => menu . Description = System . IO . File . ReadAllText ( releaseNotesPath ) ;
241
+
242
+ menu = new Menu (
243
+ "Release" ,
244
+ new ActionMenuItem ( "Edit release notes" , ctx =>
245
+ {
246
+ ctx . SuppressPause ( ) ;
247
+ RunProcess ( IsRunningOnWindows ( ) ? "notepad" : "nano" , releaseNotesPath ) ;
248
+ updateMenuDescription ( ) ;
249
+ } ) ,
250
+ new ActionMenuItem ( "Scaffold release notes" , async ctx =>
251
+ {
252
+ ctx . SuppressPause ( ) ;
253
+ if ( await ctx . UserInterface . Confirm ( true , "This will erase the current draft. Are you sure ?" ) )
254
+ {
255
+ scaffoldReleaseNotes ( ) ;
256
+ updateMenuDescription ( ) ;
257
+ }
258
+ } ) ,
259
+ new ActionMenuItem ( "Release" , async ctx =>
260
+ {
261
+ ctx . SuppressPause ( ) ;
262
+ if ( await ctx . UserInterface . Confirm ( true , "This will publish a new release. Are you sure ?" ) )
263
+ {
264
+ menu . ShouldExit = true ;
265
+
266
+ var previousReleases = releases
267
+ . Select ( r => new
268
+ {
269
+ r . Version ,
270
+ Path = $ "releases/{ r . Version } .md"
271
+ } )
272
+ . Where ( r => FileExists ( r . Path ) )
273
+ . Select ( r => $ "- [{ r . Version } ]({ r . Path } )") ;
274
+
275
+ var releaseNotesFile = string . Join ( "\n " ,
276
+ "# Release notes" ,
277
+ menu . Description . Replace ( "# Release" , "## Release" ) ,
278
+ "# Previous releases" ,
279
+ string . Join ( "\n " , previousReleases )
280
+ ) ;
281
+
282
+ System . IO . File . WriteAllText ( "RELEASE_NOTES.md" , releaseNotesFile ) ;
283
+
284
+ RunProcess ( "git" , "add" , $ "\" { releaseNotesPath } \" ", "RELEASE_NOTES.md" ) ;
285
+ RunProcess ( "git" , "commit" , "-m" , $ "\" Prepare release { version . NuGetVersion } \" ") ;
286
+ RunProcess ( "git" , "tag" , $ "v{ version . NuGetVersion } ") ;
287
+
288
+ ctx . UserInterface . Info ( $ "Your release is ready. Remember to push it using the following commands:\n \n git push && git push origin v{ version . NuGetVersion } ") ;
289
+ }
290
+ } )
291
+ ) ;
292
+
293
+ updateMenuDescription ( ) ;
294
+ new ConsoleUi . Console . ConsoleMenuRunner ( ) . Run ( menu ) . Wait ( ) ;
295
+ } ) ;
296
+
176
297
Task ( "Document" )
177
298
. IsDependentOn ( "Build" )
178
299
. Does ( ( ) =>
@@ -297,23 +418,34 @@ void BuildSolution(string solutionPath, string configuration, Verbosity verbosit
297
418
settings
298
419
. SetVerbosity ( verbosity )
299
420
. SetConfiguration ( configuration )
300
- . WithProperty ( "Version" , nugetVersion ) ;
421
+ . WithProperty ( "Version" , version . NuGetVersion ) ;
301
422
} ) ;
302
423
}
303
424
304
- void RunProcess ( string processName , params string [ ] arguments )
425
+ IEnumerable < string > RunProcess ( string processName , params string [ ] arguments )
305
426
{
306
- var exitCode = StartProcess ( processName , new ProcessSettings ( ) . WithArguments ( a =>
427
+ var settings = new ProcessSettings ( )
428
+ . SetRedirectStandardOutput ( true )
429
+ . WithArguments ( a =>
430
+ {
431
+ foreach ( var argument in arguments )
432
+ {
433
+ a . Append ( argument ) ;
434
+ }
435
+ } ) ;
436
+
437
+ using ( var process = StartAndReturnProcess ( processName , settings ) )
307
438
{
308
- foreach ( var argument in arguments )
439
+ var output = new List < string > ( process . GetStandardOutput ( ) ) ;
440
+ process . WaitForExit ( ) ;
441
+
442
+ var exitCode = process . GetExitCode ( ) ;
443
+ if ( exitCode != 0 )
309
444
{
310
- a . Append ( argument ) ;
445
+ throw new Exception ( string . Format ( "{0} failed with exit code {1}" , processName , exitCode ) ) ;
311
446
}
312
- } ) ) ;
313
447
314
- if ( exitCode != 0 )
315
- {
316
- throw new Exception ( string . Format ( "{0} failed with exit code {1}" , processName , exitCode ) ) ;
448
+ return output ;
317
449
}
318
450
}
319
451
0 commit comments