forked from brunetton/redminetimesync
-
Notifications
You must be signed in to change notification settings - Fork 0
/
redminetimesync.py
executable file
·108 lines (100 loc) · 4.54 KB
/
redminetimesync.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
#!/usr/bin/python
import sqlite3
import datetime
import os
import sys
import ConfigParser
from xml.dom import minidom
from redmine import Redmine
def getDate():
'''If there's no CLI parameter, returns date for today formatted in isoformat,
otherwise returns today minus the parameter (integer)'''
date = datetime.date.today()
if len(sys.argv) == 2:
date = date - datetime.timedelta( int(sys.argv[1]) )
return date.isoformat()
def fetchParametersFromFile(configFileName='redminetimesync.config'):
'''Takes parameters from an INI file passed via configFileName paramenter
and returns an ordered dictionary with everything into the DEFAULT section'''
global configProperties
configPath = os.path.join(os.path.split(os.path.abspath(sys.argv[0]))[0],configFileName)
config = ConfigParser.RawConfigParser() # fetch parameters from a config file
config.read(configPath)
configProperties = config.defaults() # set those parameters as the actual programs to run
return configProperties
def fetchFromDatabase(dataFile, date):
'''Following http://docs.python.org/library/sqlite3.html
Fetch data from an SQLITE3 database
Returns an iterable object with SELECT result'''
_date = ("%"+getDate()+"%", "%"+getDate()+"%") # check that we get just today
connection = sqlite3.connect(dataFile)
dbCursor = connection.cursor()
dbCursor.execute("""SELECT
activities.name,facts.start_time,facts.end_time,facts.description,tags.name
FROM activities
JOIN facts ON activities.id = facts.activity_id
JOIN fact_tags ON facts.id = fact_tags.fact_id
JOIN tags ON fact_tags.tag_id = tags.id
WHERE facts.start_time LIKE ?
AND facts.end_time LIKE ?
AND tags.name IN ('Testing','Development','Design','Planning')""", _date)
return dbCursor
def filterNotNumericIssues(iterable):
'''Takes an iterable and scans for not numeric
data in the first column, via filteredIssues() call'''
filteredIssues = []
for issue in iterable:
try:
int(issue[0])
except:
act = configProperties['act'].find(issue[0])
if act == -1:
print "Filtering time entry named '%s'" % issue[0]
else:
issueConvert = configProperties['act'][act:]
newIssue = (issueConvert[issueConvert.find(':')+1:issueConvert.find(',')],issue[1],issue[2],issue[3],issue[4])
filteredIssues.append(newIssue)
else:
filteredIssues.append(issue)
return filteredIssues
def calDuration(t2,t1):
'''calculate delta between two timestamps
Return an INT with the hour value'''
t1 = t1.split()[1].split(":")
t2 = t2.split()[1].split(":")
duration = datetime.timedelta(0,int(t2[2]),0,0,int(t2[1]),int(t2[0])) - datetime.timedelta(0,int(t1[2]),0,0,int(t1[1]),int(t1[0]))
return round(duration.seconds/3600.0, 1)
def generateXml(refinedIssues):
'''Takes time entries and generate an xml good for Redmine APIs
Returns a string with the parsable XML
Cfr: http://www.redmine.org/projects/redmine/wiki/Rest_TimeEntries'''
myxml = []
date = getDate()
for issue in refinedIssues:
comment = ""
activity = ""
if issue[4] == "Design": activity = "8"
elif issue[4] == "Development": activity = "9"
elif issue[4] == "Testing": activity = "11"
elif issue[4] == "Planning": activity = "12"
if issue[3]: comment = issue[3]
myxml.append('<time_entry><issue_id>%s</issue_id><spent_on>%s</spent_on><hours>%s</hours><activity_id>%s</activity_id><comments>%s</comments></time_entry>' % (issue[0], date, calDuration(issue[2],issue[1]),activity,comment))
return myxml
def syncToRedmine():
'''Gathers issues in XML format and push them to Redmine instance'''
configProperties = fetchParametersFromFile()
xml = generateXml(filterNotNumericIssues(fetchFromDatabase(configProperties['db'], getDate())))
if xml:
try:
myredmine = Redmine(configProperties['url'], configProperties['key'])
except:
print("Something wrong, check out credentials or connectivity")
else:
for issue in xml:
xmlDocument = minidom.parseString(issue)
print issue
myredmine.post("time_entries.xml", xmlDocument)
print("Sync to %s [OK]" % configProperties['url'])
else: print("Today no time entries to send... have you been lazy?")
if __name__ == '__main__':
syncToRedmine()