Skip to content

Commit 48e76bd

Browse files
authored
init
init Merge pull request #2 from iamwatchdogs/init
2 parents e7dd0e2 + 3f80eb6 commit 48e76bd

20 files changed

+1703
-1
lines changed

.github/data/contributors-log.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"{init}": {
3+
"contributor-name": [
4+
"iamwatchdogs"
5+
],
6+
"core": "Repo",
7+
"specificity": "Initialize",
8+
"pull-request-number": [
9+
"2"
10+
],
11+
"demo-path": "https://github.com/Grow-with-Open-Source/DSA"
12+
}
13+
}
Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
#!/usr/bin/env python
2+
3+
import os
4+
import sys
5+
import json
6+
from collections import OrderedDict
7+
8+
'''
9+
This script requires following environment variables:
10+
11+
- REPO_NAME:
12+
> example: 'iamwatchdogs/test'
13+
> GitHub action variable: ${{ github.repository }}
14+
'''
15+
16+
class UpdateFileContent:
17+
"""Class that updates `index.md` based on contributors-log."""
18+
19+
# Setting static variables
20+
DATA = None
21+
REPO_NAME = None
22+
23+
def __init__(self, FILE_PATH, condition=None):
24+
25+
# Displaying starting Message
26+
print(f'\n--- Updating {FILE_PATH} ---\n')
27+
28+
# Setting Constant values
29+
self.FILE_PATH = FILE_PATH
30+
31+
# Retriving data as modifiable lines
32+
self.lines = self.get_lines()
33+
34+
# Updates lines based on the data
35+
self.update_table_of_contributors(condition)
36+
self.update_table_of_content(condition)
37+
38+
# Updating target file content
39+
self.write_lines_into_file()
40+
41+
42+
def get_lines(self):
43+
44+
# Reading lines from the file
45+
with open(self.FILE_PATH, 'r') as file:
46+
lines = file.readlines()
47+
48+
return lines
49+
50+
def write_lines_into_file(self):
51+
52+
# Updating the target file
53+
with open(self.FILE_PATH, 'w') as file:
54+
file.writelines(self.lines)
55+
56+
# Printing Success Message
57+
print(f"Updated '{self.FILE_PATH}' Successfully")
58+
59+
def find_table_points(self, search_type):
60+
61+
# Setting default return values
62+
table_starting_point = None
63+
table_ending_point = None
64+
65+
# Setting default markers
66+
table_start_marker = None
67+
table_end_marker = None
68+
69+
# Selecting respective markers based on `search-type`
70+
if search_type == 'contributors':
71+
table_start_marker = '<!-- TABLE OF CONTRIBUTORS BEGINS -->'
72+
table_end_marker= '<!-- TABLE OF CONTRIBUTORS ENDS -->'
73+
elif search_type == 'table-of-content':
74+
table_start_marker = '<!-- TABLE OF CONTENT BEGINS -->'
75+
table_end_marker= '<!-- TABLE OF CONTENT ENDS -->'
76+
else:
77+
print('Invalid Argument', file=sys.stderr)
78+
exit(1)
79+
80+
# Iterating over lines to find the markers
81+
for index, line in enumerate(self.lines):
82+
if table_starting_point is None and table_start_marker in line:
83+
table_starting_point = index
84+
elif table_ending_point is None and table_end_marker in line:
85+
table_ending_point = index
86+
if table_starting_point is not None and table_ending_point is not None:
87+
break
88+
89+
# Checking for possible errors
90+
if table_starting_point is None or table_ending_point is None:
91+
print('Table not found in the file.', file=sys.stderr)
92+
exit(2)
93+
elif table_starting_point >= table_ending_point:
94+
print('Invaild use of table markers.', file=sys.stderr)
95+
exit(3)
96+
97+
return (table_starting_point, table_ending_point)
98+
99+
def update_table_of_contributors(self, condition):
100+
101+
# Calculating stating and ending points of the targeted table
102+
table_of_contributors_start, table_of_contributors_end = self.find_table_points('contributors')
103+
104+
# Creating HTML table header to replace md table
105+
table_header = list()
106+
table_header.append('<table>\n')
107+
table_header.append('\t<tr align="center">\n')
108+
table_header.append('\t\t<th>Contribution Title</th>\n')
109+
if condition is None:
110+
table_header.append('\t\t<th>Core Contribution</th>\n')
111+
table_header.append('\t\t<th>Contributor Names</th>\n')
112+
table_header.append('\t\t<th>Pull Requests</th>\n')
113+
table_header.append('\t\t<th>Demo</th>\n')
114+
table_header.append('\t</tr>\n')
115+
116+
# Initializing empty list for lines
117+
updated_lines = list()
118+
119+
# checking for entries
120+
has_at_least_one_entry = False
121+
122+
123+
# Iterating over log to update target file
124+
for title, details in self.DATA.items():
125+
126+
# Modifying based on condition
127+
if condition is not None and not condition(details['core']):
128+
continue
129+
130+
# Processing contributors-names
131+
contributors_names = details['contributor-name']
132+
contributors_names_list = [f'<a href="https://github.com/{name}" title="goto {name} profile">{name}</a>' for name in contributors_names]
133+
contributors_names_output = ', '.join(contributors_names_list)
134+
135+
# Processing core contribution
136+
core_contribution = details['core']
137+
if condition is None:
138+
core_contribution_output = f'<a href="{core_contribution}" title="goto {core_contribution}">{core_contribution}</a>'
139+
140+
# Processing pull-requests
141+
pull_requests = details['pull-request-number']
142+
pull_requests_list = [f'<a href="https://github.com/{self.REPO_NAME}/pull/{pr}" title="visit pr \#{pr}">&#x23;{pr}</a>' for pr in pull_requests]
143+
pull_requests_output = ', '.join(pull_requests_list)
144+
145+
# Processing demo-path
146+
demo_path = details['demo-path']
147+
specificity = details['specificity']
148+
if ' ' in demo_path:
149+
demo_path = '%20'.join(demo_path.split())
150+
demo_path_output = f'<a href="{demo_path}" title="view the result of {specificity}">./{core_contribution}/{specificity}</a>'
151+
if title == 'root' or title == '{init}':
152+
demo_path_output = f'<a href="{demo_path}" title="view the result of {title}">/{self.REPO_NAME}/</a>'
153+
154+
# Appending all data together
155+
updated_lines.append('\t<tr align="center">\n')
156+
updated_lines.append(f'\t\t<td>{title}</td>\n')
157+
if condition is None:
158+
updated_lines.append(f'\t\t<td>{core_contribution_output}</td>\n')
159+
updated_lines.append(f'\t\t<td>{contributors_names_output}</td>\n')
160+
updated_lines.append(f'\t\t<td>{pull_requests_output}</td>\n')
161+
updated_lines.append(f'\t\t<td>{demo_path_output}</td>\n')
162+
updated_lines.append(f'\t</tr>\n')
163+
164+
has_at_least_one_entry = True
165+
166+
# Adding null values if table is completely empty
167+
if not has_at_least_one_entry:
168+
updated_lines.append('\t<tr align="center">\n')
169+
updated_lines.append(f'\t\t<td>-</td>\n')
170+
if condition is None:
171+
updated_lines.append(f'\t\t<td>-</td>\n')
172+
updated_lines.append(f'\t\t<td>-</td>\n')
173+
updated_lines.append(f'\t\t<td>-</td>\n')
174+
updated_lines.append(f'\t\t<td>-</td>\n')
175+
updated_lines.append(f'\t</tr>\n')
176+
177+
# Table footer
178+
table_footer = ['</table>\n']
179+
180+
# Updating the lines with updated data
181+
self.lines[table_of_contributors_start+1:table_of_contributors_end] = table_header + updated_lines + table_footer
182+
183+
# Printing Success Message
184+
print('Successfully updated the contributor details !!!...')
185+
186+
def update_table_of_content(self, condition):
187+
188+
# Calculating stating and ending points of the targeted table
189+
table_of_content_start, table_of_content_end = self.find_table_points('table-of-content')
190+
191+
# Initializing required variables
192+
updated_lines = list()
193+
table_of_content = { 'Theory': {}, 'Solved-Problems': {}, 'Repo': {} }
194+
195+
# Extracting data into required format
196+
for title, data in self.DATA.items():
197+
198+
# Setting values for ease of use and more readibility
199+
core = data['core']
200+
specificity = data['specificity']
201+
202+
# Sorting out required data
203+
if specificity not in table_of_content[core]:
204+
table_of_content[core][specificity] = None if specificity == title else [title]
205+
elif title != specificity and title not in table_of_content[core][specificity]:
206+
if table_of_content[core][specificity] is None:
207+
table_of_content[core][specificity] = [title]
208+
else:
209+
table_of_content[core][specificity].append(title)
210+
211+
# Sorting extracted data
212+
for key, value in table_of_content.items():
213+
for sub_value in value.values():
214+
if type(sub_value) == list:
215+
sub_value.sort()
216+
table_of_content[key] = OrderedDict(sorted(value.items()))
217+
218+
# Table of content header
219+
table_of_content_header = ['<ul>\n']
220+
table_of_content_footer = ['</ul>\n']
221+
222+
# Updating lines based on the extracted data
223+
for core, data in table_of_content.items():
224+
225+
# Modifying based on condition
226+
if condition is not None and not condition(core) or core == 'Repo':
227+
continue
228+
229+
# Setting Main Heading (Only for Root)
230+
if condition is None:
231+
updated_lines.append(f'\t<li><a href="{core}" href="goto {core}"><b>{core}</b></a></li>\n')
232+
233+
# Adding all headings
234+
for heading, sub_heading_list in data.items():
235+
if condition is None:
236+
updated_lines.append(f'\t\t<ul>\n')
237+
updated_lines.append(f'\t\t\t<li><a href="{core}/{heading}" title="goto {heading}">{heading}</a></li>\n')
238+
else:
239+
updated_lines.append(f'\t<li><a href="{heading}" title="goto {heading}">{heading}</a></li>\n')
240+
if sub_heading_list is not None:
241+
for sub_heading in sub_heading_list:
242+
if condition is None:
243+
updated_lines.append(f'\t\t\t<ul>\n')
244+
updated_lines.append(f'\t\t\t\t<li><a href="{core}/{heading}/{sub_heading}" title="goto {sub_heading}">{sub_heading}</a></li>\n')
245+
updated_lines.append(f'\t\t\t</ul>\n')
246+
else:
247+
updated_lines.append(f'\t<ul>\n')
248+
updated_lines.append(f'\t\t<li><a href="{heading}/{sub_heading}" title="goto {sub_heading}">{sub_heading}</a></li>\n')
249+
updated_lines.append(f'\t</ul>\n')
250+
if condition is None:
251+
updated_lines.append(f'\t\t</ul>\n')
252+
253+
# Updating the lines with updated data
254+
self.lines[table_of_content_start+1:table_of_content_end] = table_of_content_header + updated_lines + table_of_content_footer
255+
256+
# Printing Success Message
257+
print('Successfully updated the table of content !!!...')
258+
259+
260+
def main():
261+
262+
# Retrieving Environmental variables
263+
REPO_NAME = os.environ.get('REPO_NAME')
264+
265+
# Setting path for the log JSON file
266+
ROOT_INDEX_FILE_PATH = 'index.md'
267+
THEORY_INDEX_FILE_PATH = 'Theory/README.md'
268+
SOLVED_PROBLEM_INDEX_FILE_PATH = 'Solved-Problems/README.md'
269+
CONTRIBUTORS_LOG = '.github/data/contributors-log.json'
270+
271+
# Retrieving data from log file
272+
with open(CONTRIBUTORS_LOG, 'r') as json_file:
273+
DATA = json.load(json_file)
274+
275+
# Assigning values to static members for class `UpdateFileContent`
276+
UpdateFileContent.DATA = DATA
277+
UpdateFileContent.REPO_NAME = REPO_NAME
278+
279+
# Updating All required files
280+
UpdateFileContent(ROOT_INDEX_FILE_PATH)
281+
UpdateFileContent(THEORY_INDEX_FILE_PATH, lambda core: core == 'Theory')
282+
UpdateFileContent(SOLVED_PROBLEM_INDEX_FILE_PATH, lambda core: core == 'Solved-Problems')
283+
284+
if __name__ == '__main__':
285+
main()

0 commit comments

Comments
 (0)