keithsalisbury-subtrac 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/VERSION.yml +1 -1
  2. data/bin/subtrac +2 -0
  3. data/lib/subtrac.rb +85 -50
  4. data/lib/subtrac/config/config.yml +22 -19
  5. data/lib/subtrac/templates/location.erb +2 -2
  6. data/lib/subtrac/templates/projects/blank/trac/wiki/WikiStart +1 -1
  7. data/lib/subtrac/templates/trac.erb +1 -1
  8. data/lib/subtrac/templates/vhost.erb +6 -6
  9. metadata +1 -105
  10. data/lib/subtrac/trac-plugins/advancedticketworkflowplugin/advancedworkflow/__init__.py +0 -0
  11. data/lib/subtrac/trac-plugins/advancedticketworkflowplugin/advancedworkflow/controller.py +0 -419
  12. data/lib/subtrac/trac-plugins/advancedticketworkflowplugin/setup.cfg +0 -3
  13. data/lib/subtrac/trac-plugins/advancedticketworkflowplugin/setup.py +0 -20
  14. data/lib/subtrac/trac-plugins/clientsplugin/clients/__init__.py +0 -0
  15. data/lib/subtrac/trac-plugins/clientsplugin/clients/action.py +0 -28
  16. data/lib/subtrac/trac-plugins/clientsplugin/clients/action_email.py +0 -168
  17. data/lib/subtrac/trac-plugins/clientsplugin/clients/action_zendesk_forum.py +0 -137
  18. data/lib/subtrac/trac-plugins/clientsplugin/clients/admin.py +0 -91
  19. data/lib/subtrac/trac-plugins/clientsplugin/clients/api.py +0 -199
  20. data/lib/subtrac/trac-plugins/clientsplugin/clients/client.py +0 -105
  21. data/lib/subtrac/trac-plugins/clientsplugin/clients/events.py +0 -287
  22. data/lib/subtrac/trac-plugins/clientsplugin/clients/eventsadmin.py +0 -71
  23. data/lib/subtrac/trac-plugins/clientsplugin/clients/htdocs/clients.css +0 -4
  24. data/lib/subtrac/trac-plugins/clientsplugin/clients/model.py +0 -135
  25. data/lib/subtrac/trac-plugins/clientsplugin/clients/processor.py +0 -70
  26. data/lib/subtrac/trac-plugins/clientsplugin/clients/reportmanager.py +0 -142
  27. data/lib/subtrac/trac-plugins/clientsplugin/clients/reports.py +0 -231
  28. data/lib/subtrac/trac-plugins/clientsplugin/clients/summary.py +0 -27
  29. data/lib/subtrac/trac-plugins/clientsplugin/clients/summary_milestone.py +0 -152
  30. data/lib/subtrac/trac-plugins/clientsplugin/clients/summary_ticketchanges.py +0 -160
  31. data/lib/subtrac/trac-plugins/clientsplugin/clients/templates/admin_client_events.html +0 -124
  32. data/lib/subtrac/trac-plugins/clientsplugin/clients/templates/admin_clients.html +0 -134
  33. data/lib/subtrac/trac-plugins/clientsplugin/cron/changes.xslt +0 -132
  34. data/lib/subtrac/trac-plugins/clientsplugin/cron/run-client-event +0 -97
  35. data/lib/subtrac/trac-plugins/clientsplugin/cron/summary.xslt +0 -161
  36. data/lib/subtrac/trac-plugins/clientsplugin/setup.py +0 -43
  37. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/__init__.py +0 -4
  38. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/burndownchart.py +0 -273
  39. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/hoursinplaceeditor.py +0 -44
  40. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/hoursremaining.py +0 -36
  41. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/htdocs/jquery-1.2.3.min.js +0 -32
  42. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/htdocs/jquery.jeditable.js +0 -409
  43. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/htdocs/jquery.jeditable.mini.js +0 -30
  44. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/templates/edithours.html +0 -53
  45. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/tests/burndownchart.py +0 -181
  46. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/tests/hoursremaining.py +0 -66
  47. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/tests/workloadchart.py +0 -47
  48. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/utils.py +0 -93
  49. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/workloadchart.py +0 -86
  50. data/lib/subtrac/trac-plugins/estimationtoolsplugin/setup.py +0 -20
  51. data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/SumRollups.js +0 -23
  52. data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/adw_tracdb.py +0 -128
  53. data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/git-post-receive +0 -40
  54. data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/trac-post-commit.py +0 -285
  55. data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/trac_billing.py +0 -173
  56. data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/utils/__init__.py +0 -0
  57. data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/utils/mail.py +0 -164
  58. data/lib/subtrac/trac-plugins/timingandestimationplugin/setup.py +0 -69
  59. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/__init__.py +0 -1
  60. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/api.py +0 -292
  61. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/blackmagic.py +0 -172
  62. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/dbhelper.py +0 -178
  63. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/billingplugin.css +0 -25
  64. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/field_disabler.js +0 -6
  65. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/formatDate.js +0 -356
  66. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/js/tip_centerwindow.js +0 -100
  67. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/js/tip_followscroll.js +0 -84
  68. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/js/wz_tooltip.js +0 -1149
  69. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/linkifyer.js +0 -119
  70. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/query.js +0 -73
  71. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/ticket.js +0 -165
  72. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/query_webui.py +0 -28
  73. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/reportmanager.py +0 -221
  74. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/reports.py +0 -675
  75. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/reports_filter.py +0 -150
  76. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/statuses.py +0 -25
  77. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/tande_filters.py +0 -131
  78. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/templates/billing.cs +0 -84
  79. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/templates/billing.html +0 -104
  80. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/ticket_daemon.py +0 -194
  81. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/ticket_policy.py +0 -62
  82. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/ticket_webui.py +0 -28
  83. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/usermanual.py +0 -127
  84. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/webui.py +0 -129
  85. data/lib/subtrac/trac-plugins/worklogplugin/setup.py +0 -29
  86. data/lib/subtrac/trac-plugins/worklogplugin/worklog/__init__.py +0 -1
  87. data/lib/subtrac/trac-plugins/worklogplugin/worklog/api.py +0 -187
  88. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/jqModal.css +0 -40
  89. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/jqModal.js +0 -67
  90. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/jquery.mousewheel.pack.js +0 -12
  91. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/jquery.timeentry.pack.js +0 -7
  92. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/tracWorklog.js +0 -40
  93. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/ui.datepicker.css +0 -208
  94. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/ui.datepicker.js +0 -1439
  95. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/work.png +0 -0
  96. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/work.xcf +0 -0
  97. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/worklogplugin.css +0 -80
  98. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/workstart.png +0 -0
  99. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/workstop.png +0 -0
  100. data/lib/subtrac/trac-plugins/worklogplugin/worklog/manager.py +0 -336
  101. data/lib/subtrac/trac-plugins/worklogplugin/worklog/reports.py +0 -598
  102. data/lib/subtrac/trac-plugins/worklogplugin/worklog/templates/worklog.html +0 -45
  103. data/lib/subtrac/trac-plugins/worklogplugin/worklog/templates/worklog_stop.html +0 -70
  104. data/lib/subtrac/trac-plugins/worklogplugin/worklog/templates/worklog_user.html +0 -40
  105. data/lib/subtrac/trac-plugins/worklogplugin/worklog/templates/worklog_webadminui.html +0 -59
  106. data/lib/subtrac/trac-plugins/worklogplugin/worklog/ticket_daemon.py +0 -33
  107. data/lib/subtrac/trac-plugins/worklogplugin/worklog/ticket_filter.py +0 -153
  108. data/lib/subtrac/trac-plugins/worklogplugin/worklog/timeline_hook.py +0 -96
  109. data/lib/subtrac/trac-plugins/worklogplugin/worklog/usermanual.py +0 -29
  110. data/lib/subtrac/trac-plugins/worklogplugin/worklog/util.py +0 -31
  111. data/lib/subtrac/trac-plugins/worklogplugin/worklog/webadminui.py +0 -47
  112. data/lib/subtrac/trac-plugins/worklogplugin/worklog/webui.py +0 -174
  113. data/lib/subtrac/trac-plugins/worklogplugin/worklog/xmlrpc.py +0 -73
@@ -1,86 +0,0 @@
1
- from datetime import timedelta
2
- from estimationtools.utils import parse_options, execute_query, get_estimation_field, get_estimation_suffix, get_closed_states
3
- from trac.util.html import Markup
4
- from trac.wiki.macros import WikiMacroBase
5
- import copy
6
-
7
- DEFAULT_OPTIONS = {'width': '400', 'height': '100', 'color': 'ff9900'}
8
-
9
- class WorkloadChart(WikiMacroBase):
10
- """Creates workload chart for the selected tickets.
11
-
12
- This macro creates a pie chart that shows the remaining estimated workload per ticket owner,
13
- and the remaining work days.
14
- It has the following parameters:
15
- * a comma-separated list of query parameters for the ticket selection, in the form "key=value" as specified in TracQuery#QueryLanguage.
16
- * `width`: width of resulting diagram (defaults to 400)
17
- * `height`: height of resulting diagram (defaults to 100)
18
- * `color`: color specified as 6-letter string of hexadecimal values in the format `RRGGBB`.
19
- Defaults to `ff9900`, a nice orange.
20
-
21
- Examples:
22
- {{{
23
- [[WorkloadChart(milestone=Sprint 1)]]
24
- [[WorkloadChart(milestone=Sprint 1, width=600, height=100, color=00ff00)]]
25
- }}}
26
- """
27
-
28
- estimation_field = get_estimation_field()
29
- estimation_suffix = get_estimation_suffix()
30
- closed_states = get_closed_states()
31
-
32
- def render_macro(self, req, name, content):
33
- db = self.env.get_db_cnx()
34
- # prepare options
35
- options, query_args = parse_options(db, content, copy.copy(DEFAULT_OPTIONS))
36
-
37
- query_args[self.estimation_field + "!"] = None
38
- tickets = execute_query(self.env, req, query_args)
39
-
40
- sum = 0.0
41
- estimations = {}
42
- for ticket in tickets:
43
- if ticket['status'] in self.closed_states:
44
- continue
45
- try:
46
- estimation = float(ticket[self.estimation_field])
47
- owner = ticket['owner']
48
- sum += estimation
49
- if estimations.has_key(owner):
50
- estimations[owner] += estimation
51
- else:
52
- estimations[owner] = estimation
53
- except:
54
- pass
55
-
56
- estimations_string = []
57
- labels = []
58
- for owner, estimation in estimations.iteritems():
59
- labels.append("%s %s%s" % (owner, str(int(estimation)), self.estimation_suffix))
60
- estimations_string.append(str(int(estimation)))
61
-
62
- # Title
63
- title = 'Workload'
64
-
65
- # calculate remaining work time
66
- if options.get('today') and options.get('enddate'):
67
- currentdate = options['today']
68
- day = timedelta(days=1)
69
- days_remaining = 0
70
- while currentdate <= options['enddate']:
71
- if currentdate.weekday() < 5:
72
- days_remaining += 1
73
- currentdate += day
74
- title += ' %s%s (%s workdays left)' % (int(sum), self.estimation_suffix, days_remaining)
75
-
76
- return Markup("<img src=\"http://chart.apis.google.com/chart?"
77
- "chs=%sx%s"
78
- "&amp;chf=bg,s,00000000"
79
- "&amp;chd=t:%s"
80
- "&amp;cht=p3"
81
- "&amp;chtt=%s"
82
- "&amp;chl=%s"
83
- "&amp;chco=%s\" "
84
- "alt=\'Workload Chart\' />"
85
- % (options['width'], options['height'], ",".join(estimations_string),
86
- title, "|".join(labels), options['color']))
@@ -1,20 +0,0 @@
1
- #!/usr/bin/env python
2
- # -*- coding: iso-8859-1 -*-
3
-
4
- from setuptools import setup
5
-
6
- setup(
7
- name = 'EstimationTools',
8
- author = 'Joachim Hoessler',
9
- author_email = 'hoessler@gmail.com',
10
- description = 'Trac plugin for visualizing and quick editing of effort estimations',
11
- version = '0.4',
12
- license='BSD',
13
- packages=['estimationtools'],
14
- package_data = { 'estimationtools': ['htdocs/*.js', 'templates/*.html'] },
15
- entry_points = {
16
- 'trac.plugins': [
17
- 'estimationtools = estimationtools'
18
- ]
19
- }
20
- )
@@ -1,23 +0,0 @@
1
- //javascript:(function(){var filter = function (fn, list, thisObj) { var arr = []; for (var i = 0; i < list.length; i++) { if (fn.call(thisObj, list[i])) { arr.push(list[i]);return arr;var sum = 0; var tds = filter(function(td){return td.innerHTML =='None';document.getElementsByTagName('td'),this); for(var i = 0; i < tds.length; i++){sum += parseFloat(tds[i].parentNode.childNodes[5].innerHTML);alert('Total hours: ' + sum);})();
2
- javascript:(
3
- function(){
4
- var filter = function (fn, list, thisObj) {
5
- var arr = [];
6
- for (var i = 0; i < list.length; i++) {
7
- if (fn.call(thisObj, list[i])) {
8
- arr.push(list[i]);
9
- }
10
- }
11
- return arr;
12
- };
13
- var sum = 0;
14
- var tds = filter(function(td){
15
- return td.innerHTML =='None';
16
- },
17
- document.getElementsByTagName('td'),this);
18
- for(var i = 0; i < tds.length; i++){
19
- sum += parseFloat(tds[i].parentNode.childNodes[5].innerHTML);
20
- }
21
- alert('Total hours: ' + sum);
22
- }
23
- )();
@@ -1,128 +0,0 @@
1
- from pysqlite2 import dbapi2 as sqlite
2
- from datetime import datetime, timedelta
3
- from time import mktime
4
- import os
5
-
6
- tracDir = '/var/trac'
7
- projectDBLocationFormat = '/var/trac/%s/db/trac.db'
8
- # all directories in the trac directory
9
- projects = [f for f in os.listdir(tracDir) if os.path.isdir('/'.join ([tracDir, f]))]
10
-
11
- def makeDb(proj):
12
- return projectDBLocationFormat % proj
13
-
14
- def collectResultsFromAllTracs( sql ):
15
- lst = []
16
- for proj in projects:
17
- try:
18
- lst.extend([( proj , getResultSet( proj, sql ))])
19
- except Exception, e:
20
- print "collectResultsFromAllTracs: sql failed to execute on %s : %s " % (proj, e.args)
21
-
22
- return lst
23
-
24
- def executeAgainstAllTracs( sql ):
25
- for proj in projects:
26
- try:
27
- executeNonQuery( proj, sql )
28
- except:
29
- print "executeAgainstAllTracs: sql failed to execute on %s" % proj
30
-
31
-
32
- def executeNonQuery(proj, sql, *params):
33
- """Executes the query on the given project"""
34
- con = sqlite.connect(makeDb(proj))
35
- cur = con.cursor()
36
- try:
37
- cur.execute(sql, params)
38
- con.commit()
39
- finally:
40
- cur.close()
41
- con.close()
42
-
43
- def getColumnAsList(db, sql, col=0, *params):
44
- return [valueList[col] for valueList in get_all(db, sql, *params)[1]]
45
-
46
- def getScalar(proj , sql, col=0, *params):
47
- db = sqlite.connect(makeDb(proj))
48
- cur = db.cursor()
49
- try:
50
- cur.execute(sql, params)
51
- data = cur.fetchone()
52
- finally:
53
- cur.close()
54
- return data[col]
55
-
56
-
57
- def getVector(proj, sql, *params):
58
- db = sqlite.connect(makeDb(proj))
59
- cur = db.cursor()
60
- try:
61
- cur.execute(sql, params)
62
- data = cur.fetchone()
63
- finally:
64
- cur.close()
65
- return data
66
-
67
- def getAll(proj, sql, *params):
68
- """Executes the query and returns the (description, data)"""
69
- con = sqlite.connect(makeDb(proj))
70
- cur = con.cursor()
71
- try:
72
- cur.execute(sql, params)
73
- data = cur.fetchall()
74
- desc = cur.description
75
- finally:
76
- cur.close()
77
- con.close()
78
- return (desc, data)
79
-
80
- def getResultSet(proj, sql, *params):
81
- """Executes the query and returns a Result Set"""
82
- return ResultSet(getAll(proj, sql, *params))
83
-
84
- def _columnName( columnDescription ):
85
- """ given a the columnHeader from the result set from getAll gives you the column Headers """
86
- return columnDescription[0];
87
-
88
- class ResultSet:
89
- """ the result of calling getResultSet """
90
- def __init__ (self, (columnDescription, rows)):
91
- self.columnDescription, self.rows = columnDescription, rows
92
- self.columnNames = [_columnName(_) for _ in self.columnDescription]
93
- self.columnMap = self.getColumnMap()
94
-
95
- def getColumnMap ( self ):
96
- """This function will take the result set from getAll and will
97
- return a hash of the column names to their index """
98
- h = {}
99
- i = 0
100
- if self.columnDescription:
101
- for col in self.columnNames:
102
- h[ col ] = i
103
- i+=1
104
- return h;
105
-
106
- def value(self, col, row ):
107
- """ given a row(list or idx) and a column( name or idx ), retrieve the appropriate value"""
108
- tcol = type(col)
109
- trow = type(row)
110
- if tcol == str:
111
- if(trow == list or trow == tuple):
112
- return row[self.columnMap[col]]
113
- elif(trow == int):
114
- return self.rows[row][self.columnMap[col]]
115
- else:
116
- print ("rs.value Type Failed col:%s row:%s" % (type(col), type(row)))
117
- elif tcol == int:
118
- if(trow == list or trow == tuple):
119
- return row[col]
120
- elif(trow == int):
121
- return self.rows[row][col]
122
- else:
123
- print ("rs.value Type Failed col:%s row:%s" % (type(col), type(row)))
124
- else:
125
- print ("rs.value Type Failed col:%s row:%s" % (type(col), type(row)))
126
-
127
-
128
-
@@ -1,40 +0,0 @@
1
- #!/bin/sh
2
- #
3
- # An example hook script for the post-receive event
4
- #
5
- # This script is run after receive-pack has accepted a pack and the
6
- # repository has been updated. It is passed arguments in through stdin
7
- # in the form
8
- # <oldrev> <newrev> <refname>
9
- # For example:
10
- # aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master
11
- #
12
- # see contrib/hooks/ for an sample, or uncomment the next line (on debian)
13
- #
14
-
15
-
16
- TRAC_ENV="YOUR TRAC ENV HERE"
17
- LOG="/dev/null"
18
- echo "in git post commit: $TRAC_ENV" | cat >>$LOG
19
-
20
- while read oval nval ref ; do
21
- if expr "$oval" : '0*$' >/dev/null
22
- then
23
- git-rev-list "$nval"
24
- else
25
- git-rev-list "$nval" "^$oval"
26
- fi | while read com ; do
27
- echo "posting a comment to trac" | cat >>$LOG
28
- /usr/bin/python /usr/share/trac/contrib/trac-post-commit.py \
29
- -p "$TRAC_ENV" \
30
- -r "$com" \
31
- -u "$(git-rev-list -n 1 $com --pretty=format:%an | sed '1d')" \
32
- -m "$(git-rev-list -n 1 $com --pretty=medium | sed '1,3d;s:^ ::')"
33
- echo "DONE posting a comment to trac" | cat >>$LOG
34
- done
35
- done
36
-
37
- echo "Done with trac commit hook: $TRAC_ENV" | cat >>$LOG
38
-
39
- git reset --hard
40
- echo "resetting repo working copy" | cat >>$LOG
@@ -1,285 +0,0 @@
1
- #!/usr/bin/env python
2
-
3
- # trac-post-commit-hook
4
- # ----------------------------------------------------------------------------
5
- # Copyright (c) 2004 Stephen Hansen
6
- #
7
- # Permission is hereby granted, free of charge, to any person obtaining a copy
8
- # of this software and associated documentation files (the "Software"), to
9
- # deal in the Software without restriction, including without limitation the
10
- # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11
- # sell copies of the Software, and to permit persons to whom the Software is
12
- # furnished to do so, subject to the following conditions:
13
- #
14
- # The above copyright notice and this permission notice shall be included in
15
- # all copies or substantial portions of the Software.
16
- #
17
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20
- # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
- # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23
- # IN THE SOFTWARE.
24
- # ----------------------------------------------------------------------------
25
-
26
- ### Changes for the Timing and Estimation plugin
27
- #
28
- # This script is very similar to "trac-post-commit" included with trac
29
- # itself. This section explains functional changes relative to that
30
- # script, and comments throughout the code explain other differences.
31
- #
32
- ## Logging support for debugging this hook
33
- #
34
- ## Support for specifying time spent in commit messages.
35
- #
36
- # "Blah refs #12 (1)" will add 1h to the spent time for issue #12
37
- # "Blah refs #12 (spent 1.5)" will add 1h to the spent time for issue #12
38
- #
39
- # As above it is possible to use complicated messages:
40
- #
41
- # "Changed blah and foo to do this or that. Fixes #10 (1) and #12 (2),
42
- # and refs #13 (0.5)."
43
- #
44
- # This will close #10 and #12, and add a note to #13 and also add 1h
45
- # spent time to #10, add 2h spent time to #12 and add 30m spent time
46
- # to #13.
47
- #
48
- # Note that:
49
- # (spent 2), (sp 2) or simply (2) may be used for spent
50
- # ' ', ',', '&' or 'and' may be used references
51
-
52
- # This Subversion post-commit hook script is meant to interface to the
53
- # Trac (http://www.edgewall.com/products/trac/) issue tracking/wiki/etc
54
- # system.
55
- #
56
- # It should be called from the 'post-commit' script in Subversion, such as
57
- # via:
58
- #
59
- # REPOS="$1"
60
- # REV="$2"
61
- # TRAC_ENV="/path/to/tracenv"
62
- #
63
- # /usr/bin/python /usr/local/src/trac/contrib/trac-post-commit-hook \
64
- # -p "$TRAC_ENV" -r "$REV"
65
- #
66
- # (all the other arguments are now deprecated and not needed anymore)
67
- #
68
- # It searches commit messages for text in the form of:
69
- # command #1
70
- # command #1, #2
71
- # command #1 & #2
72
- # command #1 and #2
73
- #
74
- # Instead of the short-hand syntax "#1", "ticket:1" can be used as well, e.g.:
75
- # command ticket:1
76
- # command ticket:1, ticket:2
77
- # command ticket:1 & ticket:2
78
- # command ticket:1 and ticket:2
79
- #
80
- # In addition, the ':' character can be omitted and issue or bug can be used
81
- # instead of ticket.
82
- #
83
- # You can have more then one command in a message. The following commands
84
- # are supported. There is more then one spelling for each command, to make
85
- # this as user-friendly as possible.
86
- #
87
- # close, closed, closes, fix, fixed, fixes
88
- # The specified issue numbers are closed with the contents of this
89
- # commit message being added to it.
90
- # references, refs, addresses, re, see
91
- # The specified issue numbers are left in their current status, but
92
- # the contents of this commit message are added to their notes.
93
- #
94
- # A fairly complicated example of what you can do is with a commit message
95
- # of:
96
- #
97
- # Changed blah and foo to do this or that. Fixes #10 and #12, and refs #12.
98
- #
99
- # This will close #10 and #12, and add a note to #12.
100
-
101
- import re
102
- import os
103
- import sys
104
- from datetime import datetime
105
- from optparse import OptionParser
106
-
107
- parser = OptionParser()
108
- depr = '(not used anymore)'
109
- parser.add_option('-e', '--require-envelope', dest='envelope', default='',
110
- help="""
111
- Require commands to be enclosed in an envelope.
112
- If -e[], then commands must be in the form of [closes #4].
113
- Must be two characters.""")
114
- parser.add_option('-p', '--project', dest='project',
115
- help='Path to the Trac project.')
116
- parser.add_option('-r', '--revision', dest='rev',
117
- help='Repository revision number.')
118
- parser.add_option('-u', '--user', dest='user',
119
- help='The user who is responsible for this action '+depr)
120
- parser.add_option('-m', '--msg', dest='msg',
121
- help='The log message to search '+depr)
122
- parser.add_option('-c', '--encoding', dest='encoding',
123
- help='The encoding used by the log message '+depr)
124
- parser.add_option('-s', '--siteurl', dest='url',
125
- help=depr+' the base_url from trac.ini will always be used.')
126
-
127
- (options, args) = parser.parse_args(sys.argv[1:])
128
-
129
- if not 'PYTHON_EGG_CACHE' in os.environ:
130
- os.environ['PYTHON_EGG_CACHE'] = os.path.join(options.project, '.egg-cache')
131
-
132
- from trac.env import open_environment
133
- from trac.ticket.notification import TicketNotifyEmail
134
- from trac.ticket import Ticket
135
- from trac.ticket.web_ui import TicketModule
136
- # TODO: move grouped_changelog_entries to model.py
137
- from trac.util.text import to_unicode
138
- from trac.util.datefmt import utc
139
- from trac.versioncontrol.api import NoSuchChangeset
140
-
141
- # Change logfile to point to someplace this script can write.
142
- logfile = "/var/trac/commithook.log"
143
- LOG = False
144
-
145
- if LOG:
146
- f = open (logfile,"w")
147
- f.write("Begin Log\n")
148
- f.close()
149
- def log (s, *params):
150
- f = open (logfile,"a")
151
- f.write(s % params)
152
- f.write("\n")
153
- f.close()
154
- else:
155
- def log (s, *params):
156
- pass
157
-
158
- # Relative to trac standard, this table is hoisted out of class
159
- # CommitHook so that it can be used in constructing a regexp that only
160
- # matches on supported commands.
161
- _supported_cmds = {'close': '_cmdClose',
162
- 'closed': '_cmdClose',
163
- 'closes': '_cmdClose',
164
- 'fix': '_cmdClose',
165
- 'fixed': '_cmdClose',
166
- 'fixes': '_cmdClose',
167
- 'addresses': '_cmdRefs',
168
- 're': '_cmdRefs',
169
- 'references': '_cmdRefs',
170
- 'refs': '_cmdRefs',
171
- 'see': '_cmdRefs'}
172
-
173
- # Regexps are extended to include "(1)" and "(spent 1)".
174
- ticket_prefix = '(?:#|(?:ticket|issue|bug)[: ]?)'
175
- time_pattern = r'[ ]?(?:\((?:(?:spent|sp)[ ]?)?(-?[0-9]*(?:\.[0-9]+)?)\))?'
176
- ticket_reference = ticket_prefix + '[0-9]+' + time_pattern
177
- support_cmds_pattern = '|'.join(_supported_cmds.keys())
178
-
179
- # Relative to upstream, only match command tokens (rather than
180
- # matching all words).
181
- ticket_command = (r'(?P<action>(?:%s))[ ]*'
182
- '(?P<ticket>%s(?:(?:[, &]*|[ ]?and[ ]?)%s)*)' %
183
- (support_cmds_pattern, ticket_reference, ticket_reference))
184
-
185
- if options.envelope:
186
- ticket_command = r'\%s%s\%s' % (options.envelope[0], ticket_command,
187
- options.envelope[1])
188
-
189
- # Because we build the regexp to recognize only supported commands,
190
- # ignore case here.
191
- command_re = re.compile(ticket_command, re.IGNORECASE)
192
- ticket_re = re.compile(ticket_prefix + '([0-9]+)' + time_pattern, re.IGNORECASE)
193
-
194
- class CommitHook:
195
- def __init__(self, project=options.project, author=options.user,
196
- rev=options.rev, url=options.url):
197
- self.env = open_environment(project)
198
- repos = self.env.get_repository()
199
- repos.sync()
200
-
201
- # Instead of bothering with the encoding, we'll use unicode data
202
- # as provided by the Trac versioncontrol API (#1310).
203
- try:
204
- chgset = repos.get_changeset(rev)
205
- except NoSuchChangeset:
206
- return # out of scope changesets are not cached
207
- self.author = chgset.author
208
- self.rev = rev
209
- self.msg = "(In [%s]) %s" % (rev, chgset.message)
210
- self.now = datetime.now(utc)
211
-
212
- cmd_groups = command_re.findall(self.msg)
213
-
214
- log ("cmd_groups:%s", cmd_groups)
215
- tickets = {}
216
- # \todo Explain what xxx1 and xxx2 do; I can't see more params
217
- # in command_re.
218
- for cmd, tkts, xxx1, xxx2 in cmd_groups:
219
- log ("cmd:%s, tkts%s ", cmd, tkts)
220
- funcname = _supported_cmds.get(cmd.lower(), '')
221
- if funcname:
222
- for tkt_id, spent in ticket_re.findall(tkts):
223
- func = getattr(self, funcname)
224
- tickets.setdefault(tkt_id, []).append([func, spent])
225
-
226
- for tkt_id, vals in tickets.iteritems():
227
- log ("tkt_id:%s, vals%s ", tkt_id, vals)
228
- spent_total = 0.0
229
- try:
230
- db = self.env.get_db_cnx()
231
-
232
- ticket = Ticket(self.env, int(tkt_id), db)
233
- for (cmd, spent) in vals:
234
- cmd(ticket)
235
- if spent:
236
- spent_total += float(spent)
237
-
238
- # determine sequence number...
239
- cnum = 0
240
- tm = TicketModule(self.env)
241
- for change in tm.grouped_changelog_entries(ticket, db):
242
- if change['permanent']:
243
- cnum += 1
244
-
245
- if spent_total:
246
- self._setTimeTrackerFields(ticket, spent_total)
247
- ticket.save_changes(self.author, self.msg, self.now, db, cnum+1)
248
- db.commit()
249
-
250
- tn = TicketNotifyEmail(self.env)
251
- tn.notify(ticket, newticket=0, modtime=self.now)
252
- except Exception, e:
253
- # import traceback
254
- # traceback.print_exc(file=sys.stderr)
255
- log('Unexpected error while processing ticket ' \
256
- 'ID %s: %s' % (tkt_id, e))
257
- print>>sys.stderr, 'Unexpected error while processing ticket ' \
258
- 'ID %s: %s' % (tkt_id, e)
259
-
260
-
261
- def _cmdClose(self, ticket):
262
- ticket['status'] = 'closed'
263
- ticket['resolution'] = 'fixed'
264
-
265
- def _cmdRefs(self, ticket):
266
- pass
267
-
268
- def _setTimeTrackerFields(self, ticket, spent):
269
- log ("Setting ticket:%s spent: %s", ticket, spent)
270
- if (spent != ''):
271
- spentTime = float(spent)
272
- # \bug If the ticket has not been modified since
273
- # TimingAndEstimation was installed, then it might not
274
- # have hours. It should still get hours applied because
275
- # estimating and recording are separate.
276
- if (ticket.values.has_key('hours')):
277
- ticket['hours'] = str(spentTime)
278
-
279
- if __name__ == "__main__":
280
- if len(sys.argv) < 5:
281
- print "For usage: %s --help" % (sys.argv[0])
282
- print
283
- print "Note that the deprecated options will be removed in Trac 0.12."
284
- else:
285
- CommitHook()