11'''
22Usage:
3- $ python ss13_genchangelog.py [--dry-run] html/changelog.html html/changelogs/
3+ $ python ss13_genchangelog.py html/changelogs/
44
55ss13_genchangelog.py - Generate changelog from YAML.
66
3232
3333today = date .today ()
3434
35- dateformat = "%d %B %Y "
35+ fileDateFormat = "%Y-%m "
3636
3737opt = argparse .ArgumentParser ()
38- opt .add_argument ('-d' , '--dry-run' , dest = 'dryRun' , default = False , action = 'store_true' , help = 'Only parse changelogs and, if needed, the targetFile. (A .dry_changelog.yml will be output for debugging purposes.)' )
39- opt .add_argument ('-t' , '--time-period' , dest = 'timePeriod' , default = 13 , type = int , help = 'Define how many weeks back the changelog should display' )
40- opt .add_argument ('targetFile' , help = 'The HTML changelog we wish to update.' )
4138opt .add_argument ('ymlDir' , help = 'The directory of YAML changelogs we will use.' )
4239
4340args = opt .parse_args ()
41+ archiveDir = os .path .join (args .ymlDir , 'archive' )
4442
4543all_changelog_entries = {}
4644
45+ # Do not change the order, add to the bottom of the array if necessary
4746validPrefixes = [
4847 'bugfix' ,
4948 'wip' ,
50- 'tweak ' ,
49+ 'qol ' ,
5150 'soundadd' ,
5251 'sounddel' ,
53- 'rscdel' ,
5452 'rscadd' ,
53+ 'rscdel' ,
5554 'imageadd' ,
5655 'imagedel' ,
5756 'spellcheck' ,
5857 'experiment' ,
59- 'tgs' ,
6058 'balance' ,
6159 'code_imp' ,
6260 'refactor' ,
6866def dictToTuples (inp ):
6967 return [(k , v ) for k , v in inp .items ()]
7068
71- changelog_cache = os .path .join (args .ymlDir , '.all_changelog.yml' )
69+ old_changelog_cache = os .path .join (args .ymlDir , '.all_changelog.yml' )
7270
73- failed_cache_read = True
74- if os .path .isfile (changelog_cache ):
71+ if os .path .isfile (old_changelog_cache ):
7572 try :
76- with open (changelog_cache ,encoding = 'utf-8' ) as f :
73+ print ('Reading old changelog cache...' )
74+ data = {}
75+ with open (old_changelog_cache ,encoding = 'utf-8' ) as f :
7776 (_ , all_changelog_entries ) = yaml .load_all (f , Loader = yaml .SafeLoader )
78- failed_cache_read = False
7977
80- # Convert old timestamps to newer format.
81- new_entries = {}
78+ # Categorize changes by year and month
8279 for _date in all_changelog_entries .keys ():
8380 ty = type (_date ).__name__
84- # print(ty)
85- if ty in ['str' , 'unicode' ]:
86- temp_data = all_changelog_entries [_date ]
87- _date = datetime .strptime (_date , dateformat ).date ()
88- new_entries [_date ] = temp_data
89- else :
90- new_entries [_date ] = all_changelog_entries [_date ]
91- all_changelog_entries = new_entries
81+ formattedDate = _date .strftime (fileDateFormat )
82+ if not formattedDate in data :
83+ data [formattedDate ] = {}
84+ data [formattedDate ][_date ] = all_changelog_entries [_date ]
85+ # Write files with changes by year and month
86+ for month in data .keys ():
87+ print ("Writing " + month + ".yml..." )
88+ if not os .path .exists (archiveDir ):
89+ os .makedirs (archiveDir )
90+ currentFile = os .path .join (archiveDir , month + '.yml' )
91+ with open (currentFile , 'w' , encoding = 'utf-8' ) as f :
92+ yaml .dump (data [month ], f , default_flow_style = False )
93+ # Remove the old changelog cache, as we won't use it anymore
94+ print ("Removing old changelog cache..." )
95+ os .remove (old_changelog_cache )
96+ old_changelog_html = os .path .join (args .ymlDir , '..' , 'changelog.html' )
97+ if os .path .isfile (old_changelog_html ):
98+ print ("Removing old changelog html..." )
99+ os .remove (old_changelog_html )
92100 except Exception as e :
93- print ("Failed to read cache:" )
101+ print ("Failed to read old changelog cache:" )
94102 print (e , file = sys .stderr )
95103
96- if args .dryRun :
97- changelog_cache = os .path .join (args .ymlDir , '.dry_changelog.yml' )
98-
99- if failed_cache_read and os .path .isfile (args .targetFile ):
100- from bs4 import BeautifulSoup
101- from bs4 .element import NavigableString
102- print (' Generating cache...' )
103- with open (args .targetFile , 'r' , encoding = 'utf-8' ) as f :
104- soup = BeautifulSoup (f )
105- for e in soup .find_all ('div' , {'class' :'commit' }):
106- entry = {}
107- date = datetime .strptime (e .h2 .string .strip (), dateformat ).date () # key
108- for authorT in e .find_all ('h3' , {'class' :'author' }):
109- author = authorT .string
110- # Strip suffix
111- if author .endswith ('updated:' ):
112- author = author [:- 8 ]
113- author = author .strip ()
114-
115- # Find <ul>
116- ulT = authorT .next_sibling
117- while (ulT .name != 'ul' ):
118- ulT = ulT .next_sibling
119- changes = []
120-
121- for changeT in ulT .children :
122- if changeT .name != 'li' : continue
123- val = changeT .decode_contents (formatter = "html" )
124- newdat = {changeT ['class' ][0 ] + '' : val + '' }
125- if newdat not in changes :
126- changes += [newdat ]
127-
128- if len (changes ) > 0 :
129-
130- entry [author ] = changes
131- if date in all_changelog_entries :
132- all_changelog_entries [date ].update (entry )
133- else :
134- all_changelog_entries [date ] = entry
135-
136- del_after = []
137104print ('Reading changelogs...' )
138105for fileName in glob .glob (os .path .join (args .ymlDir , "*.yml" )):
139106 name , ext = os .path .splitext (os .path .basename (fileName ))
140107 if name .startswith ('.' ): continue
141108 if name == 'example' : continue
142109 fileName = os .path .abspath (fileName )
110+ formattedDate = today .strftime (fileDateFormat )
111+ monthFile = os .path .join (archiveDir , formattedDate + '.yml' )
143112 print (' Reading {}...' .format (fileName ))
144113 cl = {}
145114 with open (fileName , 'r' ,encoding = 'utf-8' ) as f :
146115 cl = yaml .load (f , Loader = yaml .SafeLoader )
147- f .close ()
148- if today not in all_changelog_entries :
149- all_changelog_entries [today ] = {}
150- author_entries = all_changelog_entries [today ].get (cl ['author' ], [])
151- if cl ['changes' ]:
116+ currentEntries = {}
117+ if os .path .exists (monthFile ):
118+ with open (monthFile ,'r' ,encoding = 'utf-8' ) as f :
119+ currentEntries = yaml .load (f , Loader = yaml .SafeLoader )
120+ if today not in currentEntries :
121+ currentEntries [today ] = {}
122+ author_entries = currentEntries [today ].get (cl ['author' ], [])
123+ if len (cl ['changes' ]):
152124 new = 0
153125 for change in cl ['changes' ]:
154126 if change not in author_entries :
@@ -157,65 +129,14 @@ def dictToTuples(inp):
157129 print (' {0}: Invalid prefix {1}' .format (fileName , change_type ), file = sys .stderr )
158130 author_entries += [change ]
159131 new += 1
160- all_changelog_entries [today ][cl ['author' ]] = author_entries
132+ currentEntries [today ][cl ['author' ]] = author_entries
161133 if new > 0 :
162134 print (' Added {0} new changelog entries.' .format (new ))
163135
164136 if cl .get ('delete-after' , False ):
165137 if os .path .isfile (fileName ):
166- if args .dryRun :
167- print (' Would delete {0} (delete-after set)...' .format (fileName ))
168- else :
169- del_after += [fileName ]
170-
171- if args .dryRun : continue
172-
173- cl ['changes' ] = []
174- with open (fileName , 'w' , encoding = 'utf-8' ) as f :
175- yaml .dump (cl , f , default_flow_style = False )
176-
177- targetDir = os .path .dirname (args .targetFile )
178-
179- with open (args .targetFile .replace ('.htm' , '.dry.htm' ) if args .dryRun else args .targetFile , 'w' , encoding = 'utf-8' ) as changelog :
180- with open (os .path .join (targetDir , 'templates' , 'header.html' ), 'r' , encoding = 'utf-8' ) as h :
181- for line in h :
182- changelog .write (line )
183-
184- weekstoshow = timedelta (weeks = args .timePeriod )
185- for _date in reversed (sorted (all_changelog_entries .keys ())):
186- if not (today - _date < weekstoshow ):
187- continue
188- entry_htm = '\n '
189- entry_htm += '\t \t \t <h2 class="date">{date}</h2>\n ' .format (date = _date .strftime (dateformat ))
190- write_entry = False
191- for author in sorted (all_changelog_entries [_date ].keys ()):
192- if not all_changelog_entries [_date ]: continue
193- author_htm = '\t \t \t <h3 class="author">{author} updated:</h3>\n ' .format (author = author )
194- author_htm += '\t \t \t <ul class="changes bgimages16">\n '
195- changes_added = []
196- for (css_class , change ) in (dictToTuples (e )[0 ] for e in all_changelog_entries [_date ][author ]):
197- if change in changes_added : continue
198- write_entry = True
199- changes_added += [change ]
200- author_htm += '\t \t \t \t <li class="{css_class}">{change}</li>\n ' .format (css_class = css_class , change = change .strip ())
201- author_htm += '\t \t \t </ul>\n '
202- if changes_added :
203- entry_htm += author_htm
204- if write_entry :
205- changelog .write (entry_htm )
206-
207- with open (os .path .join (targetDir , 'templates' , 'footer.html' ), 'r' , encoding = 'utf-8' ) as h :
208- for line in h :
209- changelog .write (line )
210-
211-
212- with open (changelog_cache , 'w' ) as f :
213- cache_head = 'DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.'
214- yaml .dump_all ([cache_head , all_changelog_entries ], f , default_flow_style = False )
215-
216- if del_after :
217- print ('Cleaning up...' )
218- for fileName in del_after :
219- if os .path .isfile (fileName ):
220- print (' Deleting {0} (delete-after set)...' .format (fileName ))
138+ print (' Deleting {0} (delete-after set)...' .format (fileName ))
221139 os .remove (fileName )
140+
141+ with open (monthFile , 'w' , encoding = 'utf-8' ) as f :
142+ yaml .dump (currentEntries , f , default_flow_style = False )
0 commit comments