Skip to content

Commit 2ef2222

Browse files
jontsaiJonathan Tsai
authored andcommitted
RevisionStatusReport improvements
- move revision statuses to constants - refactors and DRYs up report generation with `ReportSectionConfig` - adds WIP diffs section to RevisionStatusReport - adds flag `include_in_slack` for sections to include in Slack
1 parent fa11f88 commit 2ef2222

File tree

7 files changed

+160
-170
lines changed

7 files changed

+160
-170
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.2.0
1+
3.3.0

phablytics/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '3.2.0'
1+
__version__ = '3.3.0'

phablytics/classes.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
import markdown
88

99
# Phablytics Imports
10-
from phablytics.constants import SERVICE_PREFIX
10+
from phablytics.constants import (
11+
REVISION_STATUSES_WIP,
12+
SERVICE_PREFIX,
13+
)
1114

1215
# Local Imports
1316
from .settings import (
@@ -498,7 +501,12 @@ def meets_acceptance_criteria(self):
498501
@property
499502
def is_wip(self):
500503
title = self.title
501-
is_wip = title.startswith('WIP') or title.startswith('[WIP]') or title.endswith('WIP')
504+
is_wip = (
505+
self.status_value in REVISION_STATUSES_WIP
506+
or title.startswith('WIP')
507+
or title.startswith('[WIP]')
508+
or title.endswith('WIP')
509+
)
502510
return is_wip
503511

504512

phablytics/constants/phab.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,21 @@
2121
'story',
2222
]
2323

24+
REVISION_STATUSES_WIP = [
25+
'changes-planned',
26+
'draft',
27+
]
28+
29+
REVISION_STATUSES_COMPLETED = [
30+
'abandoned',
31+
'published',
32+
]
33+
34+
REVISION_STATUSES_IN_REVIEW = [
35+
'accepted',
36+
'needs-review',
37+
'needs-revision',
38+
]
39+
40+
2441
SERVICE_PREFIX = 'service:'

phablytics/reports/revision_status.py

Lines changed: 123 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Python Standard Library Imports
22
import datetime
33
import random
4+
from dataclasses import dataclass
45

56
# Third Party (PyPI) Imports
67
import emoji
@@ -24,6 +25,25 @@
2425
# isort: off
2526

2627

28+
@dataclass
29+
class ReportSectionConfig:
30+
revisions: list
31+
emoji: str
32+
suffix: str
33+
order_asc: bool = True
34+
slack_color: str = None
35+
include_in_slack: bool = True
36+
37+
@property
38+
def num_revisions(self):
39+
return len(self.revisions)
40+
41+
@property
42+
def order_str(self):
43+
value = ('oldest' if self.order_asc else 'newest') + ' first'
44+
return value
45+
46+
2747
class RevisionStatusReport(PhablyticsReport):
2848
"""The Revision Status Report shows a list of Diffs being worked on by a team,
2949
and outputs them based on their acceptance/needs review status
@@ -65,6 +85,7 @@ def _prepare_report(self):
6585
)
6686

6787
# place revisions into buckets
88+
revisions_wip = []
6889
revisions_to_review = []
6990
revisions_with_blocks = []
7091
revisions_additional_approval = []
@@ -74,8 +95,7 @@ def _prepare_report(self):
7495
if revision.meets_acceptance_criteria:
7596
revisions_accepted.append(revision)
7697
elif revision.is_wip:
77-
# skip WIP
78-
pass
98+
revisions_wip.append(revision)
7999
elif revision.num_blockers > 0:
80100
revisions_with_blocks.append(revision)
81101
elif 0 < revision.num_acceptors < REVISION_ACCEPTANCE_THRESHOLD:
@@ -109,6 +129,7 @@ def _prepare_report(self):
109129
revisions_blocked.append(revision)
110130

111131
# finally, assign bucketed revisions
132+
self.revisions_wip = revisions_wip
112133
self.revisions_to_review = revisions_to_review
113134
self.revisions_change_required = revisions_change_required
114135
self.revisions_blocked = revisions_blocked
@@ -181,91 +202,91 @@ def _format_and_append_revision_to_report(self, report, revision, count, slack=T
181202

182203
report.append('')
183204

205+
def get_report_section_configs(self):
206+
configs = [
207+
# Revisions WIP
208+
ReportSectionConfig(
209+
revisions=self.revisions_wip,
210+
emoji=':construction:',
211+
suffix=f"{pluralize_verb('is', len(self.revisions_wip))} currently WIP",
212+
order_asc=False,
213+
slack_color='#ccccc', # light gray
214+
include_in_slack=False
215+
),
216+
# Revisions with 0 reviews
217+
ReportSectionConfig(
218+
revisions=self.revisions_to_review,
219+
emoji=':warning:',
220+
suffix=f"{pluralize_verb('need', len(self.revisions_to_review))} to be reviewed",
221+
order_asc=False,
222+
# slack_color='warning' # Slack-yellow, has an orange hue
223+
slack_color='#f2c744' # yellow
224+
),
225+
# Revisions with team blockers - change required
226+
ReportSectionConfig(
227+
revisions=self.revisions_change_required,
228+
emoji=':arrows_counterclockwise:',
229+
suffix=f"{pluralize_verb('require', len(self.revisions_change_required))} changes",
230+
order_asc=False,
231+
slack_color='#e8912d' # orange
232+
),
233+
# Revisions with only external blockers
234+
ReportSectionConfig(
235+
revisions=self.revisions_blocked,
236+
emoji=':no_entry_sign:',
237+
suffix=f"{pluralize_verb('is', len(self.revisions_blocked))} blocked",
238+
order_asc=False,
239+
slack_color='danger' # Slack red
240+
),
241+
# Revisions with 1 approval
242+
ReportSectionConfig(
243+
revisions=self.revisions_additional_approval,
244+
emoji=':pray:',
245+
suffix=f"{pluralize_verb('need', len(self.revisions_additional_approval))} additional approvals",
246+
order_asc=False,
247+
slack_color='#439f30' # blue
248+
),
249+
# Revisions Accepted
250+
ReportSectionConfig(
251+
revisions=self.revisions_accepted,
252+
emoji=':white_check_mark:',
253+
suffix=f"{pluralize_verb('is', len(self.revisions_accepted))} accepted and ready to land",
254+
order_asc=True,
255+
slack_color='good',
256+
)
257+
]
258+
259+
return configs
260+
184261
def generate_slack_report(self):
185262
"""Generates the Revision Status Report with Slack attachments
186263
"""
187264
attachments = []
188265

189-
# Revisions with 0 reviews
190-
num_revisions = len(self.revisions_to_review)
191-
if num_revisions > 0:
192-
report = []
193-
count = 0
194-
195-
for revision in sorted(self.revisions_to_review, key=lambda r: r.modified_ts, reverse=True):
196-
count += 1
197-
self._format_and_append_revision_to_report(report, revision, count)
198-
199-
attachments.append({
200-
'pretext': f":warning: *{num_revisions} {pluralize_noun('Diff', num_revisions)} {pluralize_verb('need', num_revisions)} to be reviewed*: _(newest first)_",
201-
'text': '\n'.join(report).encode('utf-8').decode('utf-8'),
202-
# 'color': 'warning', # Slack-yellow, has an orange hue
203-
'color': '#f2c744',
204-
})
205-
206-
# Revisions with team blockers - change required
207-
num_revisions = len(self.revisions_change_required)
208-
if num_revisions > 0:
209-
report = []
210-
count = 0
211-
212-
for revision in sorted(self.revisions_change_required, key=lambda r: r.modified_ts, reverse=True):
213-
count += 1
214-
self._format_and_append_revision_to_report(report, revision, count)
215-
216-
attachments.append({
217-
'pretext': f":arrows_counterclockwise: *{num_revisions} {pluralize_noun('Diff', num_revisions)} {pluralize_verb('require', num_revisions)} changes*: _(newest first)_",
218-
'text': '\n'.join(report).encode('utf-8').decode('utf-8'),
219-
'color': '#e8912d', # orange
220-
})
221-
222-
# Revisions with only external blockers
223-
num_revisions = len(self.revisions_blocked)
224-
if num_revisions > 0:
225-
report = []
226-
count = 0
227-
228-
for revision in sorted(self.revisions_blocked, key=lambda r: r.modified_ts, reverse=True):
229-
count += 1
230-
self._format_and_append_revision_to_report(report, revision, count)
231-
232-
attachments.append({
233-
'pretext': f":no_entry_sign: *{num_revisions} {pluralize_noun('Diff', num_revisions)} {pluralize_verb('is', num_revisions)} blocked*: _(newest first)_",
234-
'text': '\n'.join(report).encode('utf-8').decode('utf-8'),
235-
'color': 'danger',
236-
})
237-
238-
# Revisions with 1 approval
239-
num_revisions = len(self.revisions_additional_approval)
240-
if num_revisions > 0:
241-
report = []
242-
count = 0
243-
244-
for revision in sorted(self.revisions_additional_approval, key=lambda r: r.modified_ts, reverse=True):
245-
count += 1
246-
self._format_and_append_revision_to_report(report, revision, count)
247-
248-
attachments.append({
249-
'pretext': f":pray: *{num_revisions} {pluralize_noun('Diff', num_revisions)} {pluralize_verb('need', num_revisions)} additional approvals*: _(newest first)_",
250-
'text': '\n'.join(report).encode('utf-8').decode('utf-8'),
251-
'color': '#439fe0', # blue
252-
})
253-
254-
# Revisions Accepted
255-
num_revisions = len(self.revisions_accepted)
256-
if num_revisions > 0:
257-
report = []
258-
count = 0
259-
260-
for revision in sorted(self.revisions_accepted, key=lambda r: r.modified_ts):
261-
count += 1
262-
self._format_and_append_revision_to_report(report, revision, count)
263-
264-
attachments.append({
265-
'pretext': f":white_check_mark: *{num_revisions} {pluralize_noun('Diff', num_revisions)} {pluralize_verb('is', num_revisions)} accepted and ready to land*: _(oldest first)_",
266-
'text': '\n'.join(report).encode('utf-8').decode('utf-8'),
267-
'color': 'good',
268-
})
266+
report_section_configs = self.get_report_section_configs()
267+
268+
def _build_report_section(report_section_config):
269+
num_revisions = report_section_config.num_revisions
270+
if num_revisions > 0:
271+
report = []
272+
count = 0
273+
274+
for revision in sorted(report_section_config.revisions, key=lambda r: r.modified_ts, reverse=not report_section_config.order_asc):
275+
count += 1
276+
self._format_and_append_revision_to_report(report, revision, count)
277+
278+
attachments.append({
279+
'pretext': f"{report_section_config.emoji} *{num_revisions} {pluralize_noun('Diff', num_revisions)} {report_section_config.suffix}*: _({report_section_config.order_str})_",
280+
'text': '\n'.join(report).encode('utf-8').decode('utf-8'),
281+
'color': report_section_config.slack_color,
282+
})
283+
284+
for report_section_config in report_section_configs:
285+
if report_section_config.include_in_slack:
286+
_build_report_section(report_section_config)
287+
else:
288+
# exclude sections that might be too noisy for Slack, but include in web
289+
pass
269290

270291
DIFF_PRESENT_MESSAGES = [
271292
"Let's review some diffs!",
@@ -300,80 +321,26 @@ def generate_slack_report(self):
300321
def generate_text_report(self):
301322
lines = []
302323

303-
# Revisions with 0 reviews
304-
num_revisions = len(self.revisions_to_review)
305-
if num_revisions > 0:
306-
report = []
307-
count = 0
308-
309-
for revision in sorted(self.revisions_to_review, key=lambda r: r.modified_ts, reverse=True):
310-
count += 1
311-
self._format_and_append_revision_to_report(report, revision, count, slack=False)
312-
313-
icon = emoji.emojize(':warning:')
314-
lines.append(f"{icon}{HTML_ICON_SEPARATOR}**{num_revisions} {pluralize_noun('Diff', num_revisions)} {pluralize_verb('need', num_revisions)} to be reviewed**: *(newest first)*")
315-
lines.append('')
316-
lines.append('\n'.join(report).encode('utf-8').decode('utf-8'))
317-
318-
# Revisions with team blockers - change required
319-
num_revisions = len(self.revisions_change_required)
320-
if num_revisions > 0:
321-
report = []
322-
count = 0
323-
324-
for revision in sorted(self.revisions_change_required, key=lambda r: r.modified_ts, reverse=True):
325-
count += 1
326-
self._format_and_append_revision_to_report(report, revision, count, slack=False)
327-
328-
icon = emoji.emojize(':arrows_counterclockwise:', use_aliases=True)
329-
lines.append(f"{icon}{HTML_ICON_SEPARATOR}**{num_revisions} {pluralize_noun('Diff', num_revisions)} {pluralize_verb('require', num_revisions)} changes**: *(newest first)*")
330-
lines.append('')
331-
lines.append('\n'.join(report).encode('utf-8').decode('utf-8'))
332-
333-
# Revisions with only external blockers
334-
num_revisions = len(self.revisions_blocked)
335-
if num_revisions > 0:
336-
report = []
337-
count = 0
338-
339-
for revision in sorted(self.revisions_blocked, key=lambda r: r.modified_ts, reverse=True):
340-
count += 1
341-
self._format_and_append_revision_to_report(report, revision, count, slack=False)
342-
343-
icon = emoji.emojize(':no_entry_sign:', use_aliases=True)
344-
lines.append(f"{icon}{HTML_ICON_SEPARATOR}**{num_revisions} {pluralize_noun('Diff', num_revisions)} {pluralize_verb('is', num_revisions)} blocked**: *(newest first)*")
345-
lines.append('')
346-
lines.append('\n'.join(report).encode('utf-8').decode('utf-8'))
347-
348-
# Revisions with 1 approval
349-
num_revisions = len(self.revisions_additional_approval)
350-
if num_revisions > 0:
351-
report = []
352-
count = 0
353-
354-
for revision in sorted(self.revisions_additional_approval, key=lambda r: r.modified_ts, reverse=True):
355-
count += 1
356-
self._format_and_append_revision_to_report(report, revision, count, slack=False)
357-
358-
icon = emoji.emojize(':pray:', use_aliases=True)
359-
lines.append(f"{icon}{HTML_ICON_SEPARATOR}**{num_revisions} {pluralize_noun('Diff', num_revisions)} {pluralize_verb('need', num_revisions)} additional approvals**: *(newest first)*")
360-
lines.append('')
361-
lines.append('\n'.join(report).encode('utf-8').decode('utf-8'))
362-
363-
# Revisions Accepted
364-
num_revisions = len(self.revisions_accepted)
365-
if num_revisions > 0:
366-
report = []
367-
count = 0
368-
369-
for revision in sorted(self.revisions_accepted, key=lambda r: r.modified_ts):
370-
count += 1
371-
self._format_and_append_revision_to_report(report, revision, count, slack=False)
372-
373-
icon = emoji.emojize(':white_check_mark:', use_aliases=True)
374-
lines.append(f"{icon}{HTML_ICON_SEPARATOR}**{num_revisions} {pluralize_noun('Diff', num_revisions)} {pluralize_verb('is', num_revisions)} accepted and ready to land**: *(oldest first)*")
375-
lines.append('')
376-
lines.append('\n'.join(report).encode('utf-8').decode('utf-8'))
324+
report_section_configs = self.get_report_section_configs()
325+
326+
def _build_report_section(report_section_config):
327+
num_revisions = report_section_config.num_revisions
328+
if num_revisions > 0:
329+
report = []
330+
count = 0
331+
332+
for revision in sorted(report_section_config.revisions, key=lambda r: r.modified_ts, reverse=not report_section_config.order_asc):
333+
count += 1
334+
self._format_and_append_revision_to_report(report, revision, count, slack=False)
335+
336+
icon = emoji.emojize(report_section_config.emoji, use_aliases=True)
337+
338+
lines.append(f"{icon}{HTML_ICON_SEPARATOR}**{num_revisions} {pluralize_noun('Diff', num_revisions)} {report_section_config.suffix}**: *({report_section_config.order_str})*")
339+
lines.append('')
340+
lines.append('\n'.join(report).encode('utf-8').decode('utf-8'))
341+
342+
for report_section_config in report_section_configs:
343+
_build_report_section(report_section_config)
377344

378345
text_report = '\n'.join(lines)
379346
return text_report

0 commit comments

Comments
 (0)