1
+ import os
2
+ import logging
3
+ from slack_sdk import WebClient
4
+ from datetime import timedelta , date , datetime
5
+
6
+ DEFAULT_VAL_FREQ = 6
7
+
8
+ def convert_to_date_and_delta (val_date , val_freq ):
9
+ "Converts validation date string to datetime and validation frequency string (months) to timedelta."
10
+ try :
11
+ val_date_conv = datetime .strptime (val_date .rstrip ('\n ' ), '%Y-%m-%d' ).date ()
12
+ val_freq_conv = timedelta (days = int (val_freq ) * 30.4 )
13
+ return val_date_conv , val_freq_conv
14
+ except ValueError :
15
+ # handles the case where validation format is incorrect
16
+ return None , None
17
+
18
+ def needs_review (val_date , val_freq ):
19
+ "Returns true if doc needs to be reviewed, based on val date and frequency"
20
+ val_date_conv , val_freq_conv = convert_to_date_and_delta (val_date , val_freq )
21
+ if val_date_conv is None or val_freq_conv is None :
22
+ return False
23
+ today = date .today ()
24
+ # calculate how long since doc was reviewed, in days
25
+ delta = today - val_date_conv
26
+ # return true or false depending on evaluation of data
27
+ return delta >= val_freq_conv
28
+
29
+ def extract_metadata (filepath ):
30
+ "Extracts validation date and validation frequency from a document."
31
+ with open (filepath ) as doc :
32
+ meta_limiters = 0
33
+ has_val_date = False
34
+ val_freq = DEFAULT_VAL_FREQ
35
+
36
+ for line in doc :
37
+ if "validation: " in line :
38
+ val_date = line .split (": " , 1 )[1 ].strip ()
39
+ has_val_date = True
40
+ if "validation-frequency:" in line :
41
+ val_freq = line .split (": " , 1 )[1 ].strip ()
42
+ if "---" in line :
43
+ meta_limiters += 1
44
+ # once two --- strings are found, it is the end of the meta section, stop checking file
45
+ if meta_limiters >= 2 :
46
+ break
47
+
48
+ return has_val_date , val_date if has_val_date else None , val_freq
49
+
50
+ def process_files (directory ):
51
+ "Processes files in the content directory to check for those needing review."
52
+ print ("Processing files to check for those needing review" )
53
+ docs_to_review = []
54
+ for subdir , dirs , files in os .walk (directory ):
55
+ for file in files :
56
+ filepath = os .path .join (subdir , file )
57
+ if filepath .endswith (".mdx" ):
58
+ has_val_date , val_date , val_freq = extract_metadata (filepath )
59
+ if has_val_date and needs_review (val_date , val_freq ):
60
+ docs_to_review .append (filepath )
61
+ return docs_to_review
62
+
63
+ def get_doc_cat_name (filepath ):
64
+ "Returns a document-to-review's category and tidied-up filepath, based on its raw filepath."
65
+ trimmed_filepath = filepath [2 :- 4 ]
66
+ filepath_list = trimmed_filepath .split ("/" )
67
+
68
+ if filepath_list [0 ] == "tutorials" :
69
+ category = filepath_list [0 ]
70
+ elif filepath_list [0 ] == "faq" :
71
+ category = filepath_list [1 ]
72
+ else :
73
+ category = ' ' .join (filepath_list [0 :2 ])
74
+
75
+ return category , trimmed_filepath
76
+
77
+ def organize_docs_by_category (docs_to_review ):
78
+ "Organizes docs to review by category into a dictionary."
79
+ print ("Organizing docs by category" )
80
+ dict_by_cat = {}
81
+
82
+ for filepath in docs_to_review :
83
+ category , trimmed_filepath = get_doc_cat_name (filepath )
84
+
85
+ if category not in dict_by_cat :
86
+ dict_by_cat [category ] = [trimmed_filepath ]
87
+ else :
88
+ dict_by_cat [category ].append (trimmed_filepath )
89
+
90
+ # sort the dictionary alphabetically by category
91
+ dict_by_cat_sorted = {key : value for key , value in sorted (dict_by_cat .items ())}
92
+
93
+ return dict_by_cat_sorted
94
+
95
+ def prep_message (docs_to_review_by_cat ):
96
+ "Prepares the message to sent to the Slack channel, containing the docs to review"
97
+ print ("Preparing message" )
98
+ message = ":wave: Hi doc team, here are some docs to review: \n \n "
99
+
100
+ for key in docs_to_review_by_cat :
101
+ message += "*" + key .title () + "*" + "\n "
102
+ for doc in docs_to_review_by_cat [key ]:
103
+ message += doc + "\n "
104
+ message += "\n "
105
+ print (message )
106
+ return (message )
107
+
108
+ def send_message (message ):
109
+ "Sends the message containing docs to review to the Slack channel"
110
+ print ("Sending message" )
111
+ client = WebClient (token = os .environ ['SLACK_BOT_TOKEN' ])
112
+ client .chat_postMessage (
113
+ channel = "#review-doc" ,
114
+ text = message ,
115
+ username = "DocReviewBot"
116
+ )
117
+
118
+ def main ():
119
+ docs_to_review = process_files ("." )
120
+ docs_to_review_by_cat = organize_docs_by_category (docs_to_review )
121
+ message = prep_message (docs_to_review_by_cat )
122
+ if os .environ .get ("DRY_RUN" ) != "true" :
123
+ send_message (message )
124
+
125
+ if __name__ == "__main__" :
126
+ main ()
0 commit comments