1+ // Copyright 2024 © Sandro Figo
2+
3+ using System ;
4+ using System . Collections . Generic ;
5+ using System . Text ;
6+ using System . Text . RegularExpressions ;
7+ using Nuke . Common . IO ;
8+ using Nuke . Common . Utilities ;
9+ using Nuke . Common . Utilities . Collections ;
10+
11+ public class Changelog
12+ {
13+ public ChangelogTextSection Header ;
14+ public List < ChangelogReleaseSection > Sections = new ( ) ;
15+
16+ public static Changelog FromFile ( AbsolutePath changelogFile )
17+ {
18+ string [ ] lines = changelogFile . ReadAllLines ( ) ;
19+
20+ return new Changelog
21+ {
22+ Header = GetHeader ( lines ) ,
23+ Sections = GetSections ( lines )
24+ } ;
25+ }
26+
27+ static bool IsSectionStart ( string line )
28+ {
29+ return line . StartsWith ( "## " ) ;
30+ }
31+
32+ static bool IsSubSectionStart ( string line )
33+ {
34+ return line . StartsWith ( "### " ) ;
35+ }
36+
37+ static bool IsSubSectionEntry ( string line )
38+ {
39+ return line . StartsWith ( "-" ) ;
40+ }
41+
42+ static bool IsVersionComparison ( string line )
43+ {
44+ return line . StartsWith ( "[" ) ;
45+ }
46+
47+ static ChangelogTextSection GetHeader ( IEnumerable < string > lines )
48+ {
49+ var header = new ChangelogTextSection ( ) ;
50+
51+ foreach ( string l in lines )
52+ {
53+ if ( IsSectionStart ( l ) )
54+ {
55+ return header ;
56+ }
57+
58+ header . Lines . Add ( l ) ;
59+ }
60+
61+ return header ;
62+ }
63+
64+
65+ static List < ChangelogReleaseSection > GetSections ( IEnumerable < string > lines )
66+ {
67+ var sections = new List < ChangelogReleaseSection > ( ) ;
68+
69+ string currentSubSection = "" ;
70+
71+ foreach ( string l in lines )
72+ {
73+ if ( IsSectionStart ( l ) )
74+ {
75+ string currentSectionVersion = Regex . Match ( l , @"\[(?<version>.*)\]" ) . Groups [ "version" ] . Value . Trim ( ) ;
76+ string currentSectionReleaseDate = Regex . Match ( l , @"(?<release_date>\d+-\d+-\d+)" ) . Groups [ "release_date" ] . Value . Trim ( ) ;
77+
78+ sections . Add ( new ChangelogReleaseSection
79+ {
80+ Version = currentSectionVersion ,
81+ ReleaseDate = currentSectionReleaseDate
82+ } ) ;
83+
84+ currentSubSection = "" ;
85+ }
86+ else if ( IsSubSectionStart ( l ) && sections . Count > 0 )
87+ {
88+ string subSectionName = l . Replace ( "###" , "" ) . Trim ( ) . ToLowerInvariant ( ) ;
89+
90+ currentSubSection = subSectionName ;
91+ }
92+ else if ( IsSubSectionEntry ( l ) && ! currentSubSection . IsNullOrWhiteSpace ( ) )
93+ {
94+ string entry = l . TrimStart ( "-" ) . Trim ( ) ;
95+
96+ if ( Enum . TryParse ( currentSubSection , true , out EntryType entryType ) )
97+ {
98+ sections [ ^ 1 ] . Entries [ entryType ] . Add ( entry ) ;
99+ }
100+ }
101+ }
102+
103+ return sections ;
104+ }
105+
106+ public override string ToString ( )
107+ {
108+ var stringBuilder = new StringBuilder ( ) ;
109+
110+ if ( Header != null )
111+ stringBuilder . AppendLine ( Header . ToString ( ) ) ;
112+
113+ stringBuilder . AppendJoin ( System . Environment . NewLine , Sections ) ;
114+
115+ return stringBuilder . ToString ( ) ;
116+ }
117+ }
118+
119+ public class ChangelogReleaseSection
120+ {
121+ public string Version { get ; set ; }
122+ public string ReleaseDate { get ; set ; }
123+
124+ public Dictionary < EntryType , List < string > > Entries { get ; set ; } = new ( )
125+ {
126+ { EntryType . Added , new List < string > ( ) } ,
127+ { EntryType . Changed , new List < string > ( ) } ,
128+ { EntryType . Deprecated , new List < string > ( ) } ,
129+ { EntryType . Removed , new List < string > ( ) } ,
130+ { EntryType . Fixed , new List < string > ( ) } ,
131+ { EntryType . Security , new List < string > ( ) }
132+ } ;
133+
134+ public override string ToString ( )
135+ {
136+ var lines = new List < string > ( ) ;
137+
138+ lines . Add ( $ "## [{ Version } ]{ ( ReleaseDate . IsNullOrWhiteSpace ( ) ? "" : $ " - { ReleaseDate } ") } ") ;
139+ lines . Add ( "" ) ;
140+
141+ foreach ( var group in Entries )
142+ {
143+ if ( ! group . Value . IsEmpty ( ) )
144+ {
145+ lines . Add ( $ "### { group . Key } ") ;
146+ lines . Add ( "" ) ;
147+ foreach ( string s in group . Value )
148+ lines . Add ( $ "- { s } ") ;
149+ lines . Add ( "" ) ;
150+ }
151+ }
152+
153+ var stringBuilder = new StringBuilder ( ) ;
154+
155+ return stringBuilder . AppendJoin ( System . Environment . NewLine , lines ) . ToString ( ) ;
156+ }
157+ }
158+
159+ public class ChangelogTextSection
160+ {
161+ public List < string > Lines { get ; } = new ( ) ;
162+
163+ public override string ToString ( )
164+ {
165+ var stringBuilder = new StringBuilder ( ) ;
166+
167+ stringBuilder . AppendJoin ( System . Environment . NewLine , Lines ) ;
168+
169+ return stringBuilder . ToString ( ) ;
170+ }
171+ }
172+
173+ public enum EntryType
174+ {
175+ Added ,
176+ Changed ,
177+ Deprecated ,
178+ Removed ,
179+ Fixed ,
180+ Security ,
181+ }
0 commit comments