forked from vlall/gitwatch
-
Notifications
You must be signed in to change notification settings - Fork 0
/
gitwatch.py
executable file
·149 lines (134 loc) · 5.24 KB
/
gitwatch.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#!/usr/bin/python
# Gitwatch
# Apache License v2
# https://github.com/datamachines/gitwatch
from __future__ import print_function
import git
from datetime import datetime
import yaml
import re
import sys
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
configfile = sys.argv[1]
runfilename = "runfile.yaml"
###############################################################################
# Some functions
# Function for very simple logging capability
def log(message):
logtime = datetime.now().isoformat()
try:
with open(conf['logfile'], "a") as logfile:
logfile.write(logtime + ' ' + message + '\n')
logfile.close()
except IOError:
print(logtime, "ERROR - Unable to write to logfile.", conf['logfile'])
exit(1)
# writes our runfile to disk which records the last time of run for idempotency
def write_runfile(run):
try:
with open(runfilename, 'w') as runfile:
runfile.write( yaml.dump(run, default_flow_style=False) )
runfile.close()
log("Writing runfile")
except IOError:
log("ERROR - Unable to write runfile.")
exit(1)
# This works with AWS SES. straightforward
def send_smtp_email(email_to, email_subject, email_body):
logtime = datetime.now().isoformat()
num_recepients = len(email_to)
if num_recepients > conf['smtp_max_recepients_per_email']:
print(logtime, 'ERROR - Too many recepients.')
return 0
msg = MIMEText(email_body, 'html')
msg['Subject'] = email_subject
msg['From'] = conf['smtp_from']
msg['To'] = ','.join(email_to)
email_message = msg.as_string()
try:
smtp = smtplib.SMTP_SSL()
smtp.connect(conf['smtp_server'],int(conf['smtp_port']))
smtp.login(conf['smtp_username'], conf['smtp_password'])
smtp.sendmail(conf['smtp_from'], email_to, email_message)
smtp.close()
log("Emails sent to: " + msg['to'])
except smtplib.SMTPConnectError:
log("ERROR - Unable to connect to SMTP server.")
return 0
except smtplib.SMTPAuthenticationError:
log("ERROR - SMTP authentication error.")
return 0
return 1
###############################################################################
# Program start
# Set up configuraiton
conf = yaml.safe_load(open(configfile))
repo = git.Repo(conf['repo_dir'])
# grab the time of scrip initiialization
now = datetime.now()
init_time = int(now.strftime("%s"))
log("Initialized. Now: " + str(init_time))
# We try to read the runfile to get the last run time. If it doesn't exist
# we create one and exit cleanly.
try:
run = yaml.safe_load(open(runfilename))
except IOError:
run = dict(lastrun = int(now.strftime("%s")))
log("First run, just creating runfile and exiting.")
log("Tracking new commits from this moment in time: " + now.isoformat())
write_runfile(run)
exit(0)
# If this fails, the program will exit and not send annoying emails.
lastrun = run['lastrun']
run['lastrun'] = init_time
write_runfile(run)
# Here, we grab anything that looks like an email address from the alert-list
# file in the repo.
try:
ee = re.compile(("([a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`"
"{|}~-]+)*(@|\sat\s)(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(\.|"
"\sdot\s))+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)"))
with open(conf['repo_dir'] + conf['alert_file']) as afile:
alert_file_text = afile.read().lower()
emails = list(email[0] for email in re.findall(ee, alert_file_text))
except IOError:
log("ERROR: Unable to read alert file. " + conf['alert_file'])
exit(1)
# Check the time and see if it makes sense
log("Last run: " + str(lastrun))
tdelta = init_time - lastrun
log("Time Delta: " + str(tdelta))
if tdelta < 0:
log("ERROR: Time Delta less than zero. Did the system time change?")
exit(1)
# Iterate through the commits sending email alerts for commits that have
# happened after the time recorded in our runtime file.
commits = list(repo.iter_commits('master'))
alert_queue = []
for i in range(0,len(commits)):
commit = commits[i]
if commit.committed_date > lastrun \
and commit.committed_date < init_time:
isodtg = datetime.utcfromtimestamp(commit.committed_date).isoformat()
subject = "[" + conf['smtp_subject'] + "] by " + commit.author.name
body = "<html>\n" \
+ "The following files were modified:<br>\n"
body += "\n\n<pre>\n" + repo.git.show(commits[i]) + "\n</pre>\n<br><br>"
body += "<a href=\"" + conf['md_link_prefix'] + "\">" \
+ conf['md_link_prefix'] + "</a><br>\n"
body += "<br>\nCommit: " + str(commit) + "<br>\n" \
+ "Timestamp: " + str(commit.committed_date) + "<br>\n" \
+ "</html>\n"
#print("Body:",body)
#print("------------------")
#print("Commit:",commit)
#print("Subject:",subject)
#print("Commit timestamp:",commit.committed_date)
#print("Sending email to:", emails)
send_smtp_email(emails, subject, body)
#print(datetime.utcfromtimestamp(commit.committed_date).isoformat())
# Write the atomic initialization time to the runfile and then exit cleanly.
exit(0)