show separate counts for each type of patch

Show all of the types of patches proposed by the goal champions and
track the progress of completion separately.

Change-Id: I84eeb09813b37337a7655dc119dfae6f737d3c3a
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
This commit is contained in:
Doug Hellmann 2018-09-17 16:20:01 -04:00
parent 9e75cfe9e3
commit f7f1d148cf
1 changed files with 88 additions and 34 deletions

View File

@ -322,6 +322,14 @@ class PatchesCount(lister.Lister):
_import_subject = 'import zuul job settings from project-config'
_url_base = 'https://review.openstack.org/#/c/'
_subjects = [
('Imports', ['import zuul job settings from project-config']),
('tox defaults', ['fix tox python3 overrides']),
('Docs', ['switch documentation job to new PTI']),
('3.6 unit', ['add python 3.5 unit test job',
'add python 3.6 unit test job']),
]
def take_action(self, parsed_args):
gov_dat = governance.Governance(url=parsed_args.project_list)
sb_config = storyboard.get_config(parsed_args.config_file)
@ -339,16 +347,7 @@ class PatchesCount(lister.Lister):
cleanup_changes = get_cleanup_changes_by_team()
# We pass the message subject to gerrit in the query, but that
# does a full text search so we also want to do the exact
# match here in this filter.
changes = (
c for c in all_changes(
False,
extra_query='message:"{}"'.format(self._import_subject),
)
if c.get('subject') == self._import_subject
)
changes = all_changes(False)
# We aren't going to migrate the settings for the infra team.
interesting_teams = gov_dat.get_teams()
@ -360,25 +359,51 @@ class PatchesCount(lister.Lister):
team: 0
for team in interesting_teams
}
team_counts = collections.Counter(count_init)
open_counts = collections.Counter(count_init)
team_counts = {
title: collections.Counter(count_init)
for title, subject in self._subjects
}
open_counts = {
title: collections.Counter(count_init)
for title, subject in self._subjects
}
fail_counts = collections.Counter(count_init)
subject_lookup = {
subject: title
for title, subject_list in self._subjects
for subject in subject_list
}
all_titles = tuple(t for t, s in self._subjects)
LOG.debug('counting in-tree changes')
for c in changes:
status = c.get('status')
if status == 'ABANDONED':
continue
item = {gov_dat.get_repo_owner(c.get('project')) or 'other': 1}
team_counts.update(item)
title = subject_lookup.get(c.get('subject'))
if not title:
continue
team_counts[title].update(item)
if c.get('status') != 'MERGED':
open_counts.update(item)
open_counts[title].update(item)
verified_votes = count_votes(c, 'Verified')
if verified_votes.get(-1) or verified_votes.get(-2):
fail_counts.update(item)
def get_done_value(team):
if not team_counts[team]:
columns = (
('Team',) +
all_titles +
('Failing',
'Total',
'Champion')
)
def get_done_value(title, team, done_msg='+'):
if title != 'Imports':
return done_msg
if not team_counts['Imports'][team]:
n_repos = len(list(gov_dat.get_repos_for_team(team)))
return 'not started, {} repos'.format(n_repos)
cleanup = cleanup_changes.get(team.lower())
@ -386,8 +411,8 @@ class PatchesCount(lister.Lister):
return 'cleanup patch not found'
workflow_votes = count_votes(cleanup, 'Workflow')
if cleanup.get('status') == 'MERGED':
return 'MIGRATED'
if open_counts[team]:
return done_msg
if open_counts['Imports'][team]:
return 'in progress'
if workflow_votes.get(-1):
if parsed_args.minimal:
@ -399,30 +424,59 @@ class PatchesCount(lister.Lister):
return 'waiting for cleanup {}{}'.format(
self._url_base, cleanup.get('_number'))
columns = ('Team', 'Open', 'Failed', 'Total', 'Status', 'Champion')
def format_count(title, team, done_msg='+'):
oc = open_counts[title].get(team, 0)
tc = team_counts[title].get(team, 0)
if tc:
if oc:
return '{:3}/{:3}'.format(oc, tc)
return get_done_value(title, team, done_msg)
return '-'
data = [
(team, open_counts[team], fail_counts[team],
team_counts[team], get_done_value(team),
assignments.get(team, ''))
(team,) +
tuple(format_count(t, team) for t in all_titles) + (
fail_counts.get(team, 0),
sum(v.get(team, 0) for v in team_counts.values()),
assignments.get(team, '')
)
for team in sorted(interesting_teams,
key=lambda x: x.lower())
]
total_open = sum(open_counts.values())
# How many projects needed changes of this type?
needed_counts = {
title: 0
for title in all_titles
}
# How many projects have completed the changes of this type?
done_counts = {
title: 0
for title in all_titles
}
for row in data:
for i, t in enumerate(all_titles, 1):
if row[i] == '-':
# ignore this row for this column
continue
needed_counts[t] += 1
if row[i] == '+':
done_counts[t] += 1
summary_lines = {}
for title, count in done_counts.items():
summary_lines[title] = '{:3}/{:3}'.format(
count, needed_counts[title])
total_fail = sum(fail_counts.values())
total_all = sum(team_counts.values())
status_counts = collections.Counter()
for r in data:
status_counts.update({r[4]: 1})
total_all = sum(sum(v.values()) for v in team_counts.values())
data.append(
('TOTAL',
total_open,
total_fail,
total_all,
'{:2}/{:2} MIGRATED'.format(status_counts.get('MIGRATED'),
len(data)),
'')
('',) +
tuple(summary_lines.get(t, '') for t in all_titles) + (
total_fail,
total_all,
'')
)
return (columns, data)