Add a new integration for I Done This.
Review Request #8776 — Created Feb. 22, 2017 and submitted
I Done This is a service that provides daily status reports with a list of
tasks which are done, planned, or blocked. This integration allows posting
'done' entries to I Done This teams on behalf of users when they publish,
change, or close a review request, and when they publish reviews or replies.Each posted message includes a description of what the user did, along with
details such as the review request id, summary, and url. Reviewer groups are
also added as #tags for tracking on the I Done This website. The messages are
currently hard-coded, but could become configurable in another change.The I Done This API gives control over individual user accounts, so each user
has to provide their personal API token on their Review Board account page.
The token is validated via the API before getting encrypted and saved in the
user settings. The list of the user's teams is retrieved from the API the first
time the user needs to post, and is cached to avoid duplicate requests. The
cache expires in 24 hours, or can be deleted manually by re-saving the token.The administrator has to add an integration configuration for each I Done This
team that posts are allowed to, along with conditions to filter which review
request activity gets posted. Multiple configurations can specify the same team
to allow alternative sets of conditions, but only one message will be posted
to each unique team.The configuration method is not ideal, since the admin can't verify that the
team is correctly set up without using an API token of a user on that team.
Users also don't have access to the team configurations to choose or even see
which teams or review requests get posted. However, the overall goal is to keep
user settings to a minimum, and let he admin control the configuration. There
may be ways in the future to improve the user experience, for example by adding
UI notifications from the integration when posting to I Done This.Unit tests have been added to verify all the posted message types, various
reasons for not posting, posts with multiple configurations and team ids,
functionality of the user and admin forms, and team id requests with caching.
Unit tests pass, with full coverage except icon_static_urls().
Manually tested adding integration configurations, setting the user API token,
form validation errors, and posting all message types to I Done This.
Description | From | Last Updated |
---|---|---|
This doc comment should include a "Returns" section. |
david | |
This doc comment should include a "Returns" section. |
david | |
Because this is a property, the docstring should look more like it is for attributes (such as just "The icons … |
david | |
Col: 19 E127 continuation line over-indented for visual indent |
reviewbot | |
Add a trailing comma. |
david | |
Unlike all our other docstrings, test case descriptions shouldn't include a period, because the test runner adds an ellipsis when … |
david | |
Would you mind changing these to use the format strings instead of a hard-coded result? These tests are fragile to … |
david | |
Trailing comma. |
david | |
Trailing comma. |
david | |
Trailing comma. I assume the same throughout this file. |
david | |
Trailing comma. |
david | |
Because this is imported into other code as just create_request, it was initially a bit confusing when I read that … |
david | |
File-level docstring. |
brennie | |
<b> is deprecated. Use <strong> instead. |
brennie | |
The fieldset label should be marked for translation. |
brennie | |
Here too. |
brennie | |
Maybe use <p> over linebreaks? Also, IDK if we use self-closing tags (they are deprecated in the HTML spec) |
brennie | |
Missing file-level docstring. |
brennie | |
Must inherit from object. |
brennie | |
unicode.format is slow compared to using %-based interpolation (and we also don't really use the former elsewhere). You can change … |
brennie | |
You may want to replace - with _ in group.name because idt doesn't like tags with dashes (but underscores work … |
brennie | |
Why not just use, e.g.: import re #... re.sub(r'\s{2,}', ' ', entry) You can compile the regex with re.compile so … |
brennie | |
Coalesce into elif |
brennie | |
File-level docstring. |
brennie | |
File-level docstring. |
brennie | |
File-level docstring. |
brennie | |
This should be "Format". |
chipx86 | |
Text like ${num_issues} should be surrounded with double backticks so it'll appear as code/literal text in docs (not that we … |
chipx86 | |
We should use review_request_id instead of request_id in places. In our terminology, "Request" is the HTTP request. |
chipx86 | |
I couple suggestions for formatting and optimizations: group_names = review_request.target_groups.values_list('name', flat=True) group_tags = ' '.join( '#%s' % re.sub(r'\W', '_', group_name) … |
chipx86 | |
Let's precompile this one too. |
chipx86 | |
"ID" |
chipx86 | |
Let's put the URL in <code>...</code>. |
chipx86 | |
"ID" |
chipx86 | |
We should maybe expand this to say why this might be the case (the API token may be incorrect, please … |
chipx86 | |
You can reference by doing: :py:mod:`rbintegrations.idonethis.entries` |
chipx86 | |
Might want to explicitly disregard None entries in the conditional instead of doing the lookup. |
chipx86 | |
I'm generally a fan of collapsing down if statements, but given that we have these same checks within the if … |
chipx86 | |
Wonder if we should just do the build_server_url in post_entry, so each call site doesn't have to reepeat it. |
chipx86 | |
Should be "reply". |
chipx86 | |
E126 continuation line over-indented for hanging indent |
reviewbot | |
E126 continuation line over-indented for hanging indent |
reviewbot | |
"Return ..." "Get" implies that it's getting it from somewhere else, and doesn't necessarily imply that it's returning it. |
chipx86 | |
No need for the settings.get if it's known to be in there. Since it's most likely in there, you can … |
chipx86 | |
Same as above. |
chipx86 | |
"IDs" |
chipx86 | |
No blank line here. |
chipx86 | |
We probably should turn this into two different paragraphs, or just let it wrap, rather than forcing a line break. |
chipx86 | |
This should be models.review_request.ReviewRequest. You can wrap it after any period. |
david | |
Maybe wrap this as: raise forms.ValidationError( ugettext('Team ID cannot contain slashes.')) |
david |
-
-
-
-
Because this is a property, the docstring should look more like it is for attributes (such as just "The icons used for the integration") instead of the docstring for a method.
-
-
Unlike all our other docstrings, test case descriptions shouldn't include a period, because the test runner adds an ellipsis when printing. Here and throughout this file.
-
Would you mind changing these to use the format strings instead of a hard-coded result? These tests are fragile to text changes.
-
-
-
-
-
Because this is imported into other code as just
create_request
, it was initially a bit confusing when I read that code. Can we rename this ascreate_idt_request
so it's clear what's going on?
- Change Summary:
-
Addressed review comments.
Movedintegration_mgr.clear_all_configs_cache()
to base class for test cases - https://reviews.reviewboard.org/r/8915/
Updated some form test cases to passdata
in the constructor and callform.full_clean()
to verify that the appropriateclean_<field>
method is called. - Commit:
-
fd602194eca270644f6d58a1e61c594974805b2f12e3ce01ac26185b641a21046d9f69c09b00ad36
- Diff:
-
Revision 2 (+2783)
Checks run (2 succeeded, 1 failed with error)
-
-
-
-
-
-
Maybe use
<p>
over linebreaks? Also, IDK if we use self-closing tags (they are deprecated in the HTML spec) -
-
-
unicode.format
is slow compared to using %-based interpolation (and we also don't really use the former elsewhere). You can change these to use:format_strings = { REPLY_PUBLISHED: 'Replied to review request %(request_id)s: ' '%(summary)s %(url)s %(group_tags)s', #... }
and then interpolate with:
format_strings[entry] % { 'group_tags': group_tags, 'num_issues': num_issues, 'request_id': review_request.display_id, 'summary': review_request.summary, 'url': url, }
-
You may want to replace
-
with_
ingroup.name
because idt doesn't like tags with dashes (but underscores work for some reason :/) -
Why not just use, e.g.:
import re #... re.sub(r'\s{2,}', ' ', entry)
You can compile the regex with
re.compile
so we only have to parse the regex once.I'm not sure which is more expensive
-
-
-
-
- Change Summary:
-
Addressed Barret's review comments.
Moved entry types, template strings, and formatting toentries.py
.
Changed template string formatting to usestring.Template
.
Renamedevent_name
tosignal_name
for clarity, and to avoid confusion with custom event filtering (separate change).
Switched to explicit keyword arguments when callingIDoneThisIntegration.post_entry()
. - Commit:
-
12e3ce01ac26185b641a21046d9f69c09b00ad36ac51636aa0952f19162af89e9145298fe22af258
- Diff:
-
Revision 3 (+2859)
-
Sorry this took so long :( Change looks great, and I love the test coverage. Most of my stuff are small doc tweaks and other tiny suggestions.
-
-
Text like
${num_issues}
should be surrounded with double backticks so it'll appear as code/literal text in docs (not that we generate them yet, but still).Same with others in this function.
-
We should use
review_request_id
instead ofrequest_id
in places. In our terminology, "Request" is the HTTP request. -
I couple suggestions for formatting and optimizations:
group_names = review_request.target_groups.values_list('name', flat=True) group_tags = ' '.join( '#%s' % re.sub(r'\W', '_', group_name) for group_name in group_names )
We should also ideally precompile the regex in the module.
-
-
-
-
-
We should maybe expand this to say why this might be the case (the API token may be incorrect, please check the token in your account, etc.).
-
-
-
I'm generally a fan of collapsing down if statements, but given that we have these same checks within the
if review.ship_it
, maybe these ones should go in anelse
. -
Wonder if we should just do the
build_server_url
inpost_entry
, so each call site doesn't have to reepeat it. -
-
"Return ..."
"Get" implies that it's getting it from somewhere else, and doesn't necessarily imply that it's returning it.
-
No need for the
settings.get
if it's known to be in there.Since it's most likely in there, you can actually do:
try: return decrypt_password(settings['api_token']) except KeyError: return None
-
-
-
-
We probably should turn this into two different paragraphs, or just let it wrap, rather than forcing a line break.
- Change Summary:
-
Addressed Christian's comments.
Updated test cases to use set literals instead of set(). - Commit:
-
ac51636aa0952f19162af89e9145298fe22af258078c51d24dfdc3c6d72b3e7a50497aa60a175774
- Diff:
-
Revision 4 (+2875)
Checks run (2 succeeded)
- Change Summary:
-
Addressed David's comments, plus a few more places with the same issues.
Renamed deprecatedtype
argument toclose_type
for thereview_request_closed
signal. - Commit:
-
078c51d24dfdc3c6d72b3e7a50497aa60a1757744815cbaf463cd74f1d10c3c1e7e5fe488b5da6ab
- Diff:
-
Revision 5 (+2880)
Checks run (2 succeeded)
- Change Summary:
-
Replaced "hash ID" with "identifier" in the help text for Team ID.
- Commit:
-
4815cbaf463cd74f1d10c3c1e7e5fe488b5da6abebbfd8ed7a2783228cd97ad1f6c502b6818ee6e3
- Diff:
-
Revision 6 (+2880)
Checks run (2 succeeded)
-
This looks great!
Was there anything else you were planning for this change? If not, can you add the binary files (icons) as file attachments to this review request?