SF.net SVN: gar:[23441] csw/mgar/gar/v2/lib/python
wahwah at users.sourceforge.net
wahwah at users.sourceforge.net
Sun Apr 20 20:42:55 CEST 2014
Revision: 23441
http://sourceforge.net/p/gar/code/23441
Author: wahwah
Date: 2014-04-20 18:42:54 +0000 (Sun, 20 Apr 2014)
Log Message:
-----------
Activity report: Detect new maintainers
New maintainers don't have packages, but should not be retired.
Modified Paths:
--------------
csw/mgar/gar/v2/lib/python/activity.py
csw/mgar/gar/v2/lib/python/maintainer_activity_report.py
Modified: csw/mgar/gar/v2/lib/python/activity.py
===================================================================
--- csw/mgar/gar/v2/lib/python/activity.py 2014-04-20 16:43:24 UTC (rev 23440)
+++ csw/mgar/gar/v2/lib/python/activity.py 2014-04-20 18:42:54 UTC (rev 23441)
@@ -11,9 +11,10 @@
Maintainer = namedtuple('Maintainer',
['username', 'pkgs', 'last_activity', 'last_activity_pkg',
- 'active', 'mantis_status', 'fullname'])
+ 'active', 'csw_db_status', 'fullname', 'date_created'])
INACTIVE_MAINTAINER_CUTOFF = 2
+NEW_MAINTAINER_CUTOFF = 2
STALE_PACKAGE_CUTOFF = 4
STALE_FROM_COLOR = '#FFDDBB'
STALE_TO_COLOR = '#F995A0'
@@ -100,8 +101,9 @@
last_activity=datetime.datetime(1970, 1, 1, 0, 0),
last_activity_pkg=None,
active=True,
- mantis_status=None,
- fullname=None))
+ csw_db_status=None,
+ fullname=None,
+ date_created=None))
if entry['catalogname'] not in maintainer.pkgs:
maintainer.pkgs[entry['catalogname']] = entry
if maintainer.last_activity < date:
Modified: csw/mgar/gar/v2/lib/python/maintainer_activity_report.py
===================================================================
--- csw/mgar/gar/v2/lib/python/maintainer_activity_report.py 2014-04-20 16:43:24 UTC (rev 23440)
+++ csw/mgar/gar/v2/lib/python/maintainer_activity_report.py 2014-04-20 18:42:54 UTC (rev 23441)
@@ -11,6 +11,7 @@
import requests
import argparse
import datetime
+import dateutil.parser
import jinja2
import cPickle
@@ -29,9 +30,12 @@
font-size: 14px;
font-family: sans-serif;
}
- .active-False .maintainer {
- color: brown;
+ table.activity-report {
+ border-collapse: collapse;
}
+ tr.border-bottom td {
+ border-bottom: 1px gray;
+ }
.active-False .activity-tag {
color: brown;
font-weight: bold;
@@ -40,21 +44,36 @@
color: green;
font-weight: bold;
}
+ .retired-True .activity-tag {
+ color: #DDD;
+ }
.warning {
color: red;
font-weight: bold;
}
- .retired-True {
- background-color: #DDD;
- color: #AAA;
+ .retired-True, .retired-True a {
+ color: #DDD;
}
- .action-needed-True {
- background-color: #FA8;
+ .action-needed-True, .action-needed-True a {
+ background-color: MistyRose;
+ color: brown;
}
</style>
</head>
<body>
<h1>OpenCSW Maintainer activity report</h1>
+
+ <h2>Summary</h2>
+
+ <ul>
+ <li>{{ counts.active }} active maintainers</li>
+ <li>{{ counts.new }} new maintainers</li>
+ <li>{{ counts.retired }} retired maintainers</li>
+ <li>{{ counts.to_retire }} maintainers to retire</li>
+ <li>{{ counts.bogus }} bogus maintainer entries;
+ package contents does not match any maintainers in the CSW database</li>
+ </ul>
+
<h2>Maintainers to retire</h2>
<p>Limitations: This report doesn't know which maintainers are new and which ones are old.
@@ -76,29 +95,51 @@
{% endif %}
{% endfor %}
</p>
+ <p>Bogus maintainers:
+ {% for username in analysis_by_username|sort %}
+ {% if analysis_by_username[username].bogus %}
+ {{ username }}
+ {% endif %}
+ {% endfor %}
+ </p>
<h2>Activity</h2>
- <table>
+ <table class="activity-report">
<tr>
<th>username</th>
+ <th>created</th>
<th>last activity</th>
<th>years</th>
+ <th>new?</th>
<th>active?</th>
- <th>mantis</th>
+ <th>status in db</th>
<th>last pkg</th>
<th># pkgs</th>
+ <th>suggestions</th>
</tr>
{% for username in maintainers|sort %}
- <tr class="active-{{ maintainers[username].active }} retired-{{ maintainers[username].mantis_status != 'Active' }} action-needed-{{ analysis_by_username[username].to_retire }}">
+ <tr class="border-bottom active-{{ maintainers[username].active }} retired-{{ maintainers[username].csw_db_status != 'Active' }} action-needed-{{ analysis_by_username[username].to_retire }}">
<td>
<a id="{{ username }}" class="maintainer"
href="http://www.opencsw.org/maintainers/{{ username }}/">{{ username }}</a>
</td>
<td>
+ {% if maintainers[username].date_created %}
+ {{ maintainers[username].date_created.strftime('%Y-%m-%d') }}
+ {% endif %}
+ </td>
+ <td>
{{ maintainers[username].last_activity.strftime('%Y-%m-%d') }}
</td>
<td>
{{ maintainers[username].last_activity_pkg.years }}
</td>
+ <td>
+ {% if analysis_by_username[username].new %}
+ <span style="background-color: SlateBlue; color: white; padding: 2px;" class="activity-tag">new</span>
+ {% else %}
+ <span style="color: #AAA;" class="activity-tag">old</span>
+ {% endif %}
+ </td>
<td class="activity-tag">
{% if maintainers[username].active %}
<span class="activity-tag">active</span>
@@ -107,7 +148,7 @@
{% endif %}
</td>
<td>
- {{ maintainers[username].mantis_status }}
+ {{ maintainers[username].csw_db_status }}
</td>
<td>
<a href="http://buildfarm.opencsw.org/pkgdb/srv4/{{ maintainers[username].last_activity_pkg.md5_sum }}/">
@@ -118,6 +159,17 @@
{{ maintainers_in_unstable[username].pkgs|length }}
{% endif %}
</td>
+ <td>
+ {% if maintainers[username].active and maintainers[username].csw_db_status != 'Active' %}
+ inconsistent status
+ {% endif %}
+ {% if analysis_by_username[username].new and not maintainers[username].pkgs %}
+ maybe needs help
+ {% endif %}
+ {% if analysis_by_username[username].bogus %}
+ bogus maintainer defined in a package?
+ {% endif %}
+ </td>
</tr>
{% endfor %}
</table>
@@ -136,10 +188,10 @@
key_by_future = dict((executor.submit(Fetch, catrel), catrel)
for catrel in catrels)
- # Additional query: maintainers from Mantis
- mantis_url = 'http://www.opencsw.org/buglist/maintainers'
- mantis_future = executor.submit(lambda: requests.get(mantis_url).json())
- key_by_future[mantis_future] = 'mantis'
+ # Additional query: maintainers from CSW on the website
+ csw_db_url = 'http://www.opencsw.org/buglist/maintainers'
+ csw_db_future = executor.submit(lambda: requests.get(csw_db_url).json())
+ key_by_future[csw_db_future] = 'csw_db'
for future in concurrent.futures.as_completed(key_by_future):
key = key_by_future[future]
@@ -170,9 +222,9 @@
with open(args.save_as, 'w') as fd:
cPickle.dump(results_by_catrel, fd)
- # We need to remove the mantis part.
- mantis_maintainers = results_by_catrel['mantis']
- del results_by_catrel['mantis']
+ # We need to remove the csw_db part.
+ csw_db_maintainers = results_by_catrel['csw_db']
+ del results_by_catrel['csw_db']
# Flatten packages from all catalogs into a single list. For activity
# detection, we don't care which catalog a maintainer submitted a package to.
@@ -184,13 +236,25 @@
maintainers, bad_dates = activity.Maintainers(pkgs)
maintainers_in_unstable, _ = activity.Maintainers(results_by_catrel['unstable'])
- for d in mantis_maintainers:
- # maintainer, fullname, status
+ counts = {
+ 'active': 0,
+ 'to_retire': 0,
+ 'retired': 0,
+ 'bogus': 0,
+ 'new': 0,
+ }
+
+ for d in csw_db_maintainers:
+ # maintainer, fullname, status, date_created
username = d['maintainer']
status = d['status']
+ date_created = None
+ if d['date_created']:
+ date_created = dateutil.parser.parse(d['date_created'])
if username in maintainers:
maintainers[username] = (
- maintainers[username]._replace(mantis_status=status))
+ maintainers[username]._replace(csw_db_status=status,
+ date_created=date_created))
else:
maintainers[username] = (
activity.Maintainer(
@@ -199,22 +263,41 @@
last_activity=datetime.datetime(1970, 1, 1, 0, 0),
last_activity_pkg=None,
active=False,
- mantis_status=status,
- fullname=d['fullname']))
+ csw_db_status=status,
+ fullname=d['fullname'],
+ date_created=date_created))
- mantis_m_by_username = dict((m['maintainer'], m) for m in mantis_maintainers)
+ csw_db_m_by_username = dict((m['maintainer'], m) for m in csw_db_maintainers)
analysis_by_username = {}
- for username, maintainer in maintainers.iteritems():
- d = {'can_be_retired': False,
- 'to_retire': False,
- 'bogus': False}
- if username not in mantis_m_by_username:
+ now = datetime.datetime.now()
+ new_maint_cutoff = now - datetime.timedelta(days=activity.NEW_MAINTAINER_CUTOFF*365)
+ for username in maintainers:
+ d = {'to_retire': False,
+ 'bogus': False,
+ 'new': False}
+
+ # Detect new maintainers. This could be also done in activity.py, because
+ # similar functionality already exists there.
+ if (maintainers[username].date_created is not None
+ and maintainers[username].date_created > new_maint_cutoff
+ and maintainers[username].csw_db_status != 'Retired'):
+ maintainers[username] = maintainers[username]._replace(active=True)
+ d['new'] = True
+ counts['new'] += 1
+
+ if username not in csw_db_m_by_username:
d['bogus'] = True
- if not maintainer.active:
- if username not in maintainers_in_unstable:
- d['can_be_retired'] = True
- if maintainer.mantis_status != 'Retired' and not d['bogus']:
- d['to_retire'] = True
+ counts['bogus'] += 1
+ if maintainers[username].active:
+ counts['active'] += 1
+ else:
+ if not d['bogus']:
+ if maintainers[username].csw_db_status != 'Retired':
+ d['to_retire'] = True
+ counts['to_retire'] += 1
+ else:
+ counts['retired'] += 1
+
analysis_by_username[username] = d
with open(args.output, 'w') as outfd:
@@ -222,7 +305,8 @@
rendered = template.render(
maintainers=maintainers,
maintainers_in_unstable=maintainers_in_unstable,
- analysis_by_username=analysis_by_username)
+ analysis_by_username=analysis_by_username,
+ counts=counts)
outfd.write(rendered.encode('utf-8'))
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
More information about the devel
mailing list