• 
      

    Discord Integration Option

    Review Request #11201 — Created Sept. 25, 2020 and submitted

    Information

    rbintegrations
    master

    Reviewers

    Added a Discord Integration option.
    This allows Review Board to have an option of notifying Discord channels on
    any Review Request changes. This commit also includes a refactoring of the
    notify() function in SlackIntegration.

    Added unit tests in discord/tests.py and they pass in RB3 virtual
    environment. RB4 has two exceptions (please see below).

    Tested it manually in reviewboard 3.0.x and 4.0.x.

    Issues that still need to be addressed:

    • Add assets (e.g. logos, trophies, etc.) at this location:
      https://static.reviewboard.org/integration-assets/discord

    • It has the same problem as the Slack and Mattermost Integration:
      two of the unit tests are complaining about this image here in RB4 -
      /var/folders/f1/r8mpbfkd321804b47_tgytgw0000gn/T/rb-tests-EQOxMU/
      static/rb/images/logo.png

    Summary ID Author
    Discord Chat Integration
    This allows Review Board to have an option of notifying Discord channels on any Review Request changes. This commit also includes a refactoring of the notify() function in SlackIntegration.
    b1cff2eb4fe7f953704b96c252b7b96564b31464 HailanXyouknow

    Description From Last Updated

    E261 at least two spaces before inline comment

    reviewbotreviewbot

    E262 inline comment should start with '# '

    reviewbotreviewbot

    E261 at least two spaces before inline comment

    reviewbotreviewbot

    E262 inline comment should start with '# '

    reviewbotreviewbot

    Please remove.

    MarcusBoayMarcusBoay

    TODO comment?

    MarcusBoayMarcusBoay

    Should this be Discord instead?

    MarcusBoayMarcusBoay

    Should this be Discord instead?

    MarcusBoayMarcusBoay

    Should this be Discord instead?

    MarcusBoayMarcusBoay

    Should this be Discord instead?

    MarcusBoayMarcusBoay

    It's more of a nitpick but 'mattemost' -> 'discord'

    MarcusBoayMarcusBoay

    Let's use double quotes for the quotation marks inside the string.

    daviddavid

    Please add a blank line between these two.

    daviddavid

    Maybe move the contents of this method back into the integration class? I don't see a good reason to have …

    daviddavid

    Please use single quotes for these.

    daviddavid

    Can we use a named logger here? At the top level of the file, add: logger = logging.getLogger(__name__) This can …

    daviddavid

    There's an extra blank line here that can be removed.

    daviddavid

    Please add a module docstring to the top of this file.

    daviddavid

    Add a blank line between these two.

    daviddavid

    Leftover debug output?

    daviddavid

    This line isn't necessary.

    daviddavid

    E302 expected 2 blank lines, found 1

    reviewbotreviewbot

    E128 continuation line under-indented for visual indent

    reviewbotreviewbot

    E128 continuation line under-indented for visual indent

    reviewbotreviewbot

    E128 continuation line under-indented for visual indent

    reviewbotreviewbot

    E128 continuation line under-indented for visual indent

    reviewbotreviewbot

    E128 continuation line under-indented for visual indent

    reviewbotreviewbot

    E128 continuation line under-indented for visual indent

    reviewbotreviewbot

    E128 continuation line under-indented for visual indent

    reviewbotreviewbot

    Instead of using the continuation character here, can we wrap this in parens?

    daviddavid

    As per the coding style guide, I believe these imports should be moved down to a new group as they …

    keanwengkeanweng

    Missing period here.

    keanwengkeanweng

    Should be in alphabetical order.

    keanwengkeanweng

    These imports should be moved down a group too.

    keanwengkeanweng

    Let's switch the use of single- and double-quotes here: help_text=_('Your unique Discord webhook URL. This can be found at ' …

    daviddavid

    These two lines should be swapped (alphabetical order).

    chipx86chipx86

    I think that lines 11 and 12 should be swapped so that they follow alphabetical order.

    jblazusijblazusi

    Two blank lines between imports and other code.

    chipx86chipx86

    I noticed that other review board files have 2 lines below the import statements. So I think that you should …

    jblazusijblazusi

    This should use ugettext_lazy, like the form does.

    chipx86chipx86

    Mind putting this in alphabetical order? Helps keep things organized as new settings are added.

    chipx86chipx86

    You can bump this to a modern date and time.

    chipx86chipx86

    This appears to be in the wrong spot. Should be further down, under event_name, and have , optional.

    chipx86chipx86

    Should have , optional

    chipx86chipx86

    Can you pass these as keyword arguments? Helps avoid issues as parameters get added, and keeps code readable.

    chipx86chipx86

    No need for the blank line here. We can convey this as one "paragraph", where we're building the initial state …

    chipx86chipx86

    Can you use '%s/slack' % config.... form?

    chipx86chipx86

    Can you set this to alphabetical order?

    chipx86chipx86

    If you use logger.exception, you won't need exc_info=True.

    chipx86chipx86

    Doesn't look like this function is doing that, at least not directly. Maybe state what it wraps, so it's clear …

    chipx86chipx86

    We don't need docstrings for setUp or tearDown. Sort of an exception to a rule.

    chipx86chipx86

    You can pass id=12321 to create_review_request() (in fact, it's important to do that — old code may not though).

    chipx86chipx86

    Same here with id=.

    chipx86chipx86

    No need to call this, since we already created it above.

    chipx86chipx86

    This will need a docstring.

    chipx86chipx86

    This can be a single statement.

    chipx86chipx86

    These all list , optional, but the arguments are all required in the method signature.

    chipx86chipx86

    Can you pass all these as keyword arguments?

    chipx86chipx86

    E201 whitespace after '{'

    reviewbotreviewbot

    E202 whitespace before '}'

    reviewbotreviewbot

    I have to add .encode('UTF-8) at the end of this line to get it to work for some reason. Running …

    ruonanjiaruonanjia

    Can you say "integration on Discord", so it's clear where they need to add this?

    chipx86chipx86

    This has two spellings of "Webhook": "Webhook" and "WebHook". Not your fault — we're inconsistent in places as well. I …

    chipx86chipx86

    "that that" -> "that"

    chipx86chipx86

    No space after the comma.

    chipx86chipx86

    lowercase: "utf-8".

    chipx86chipx86

    To check, is there a reason we use this User-Agent? If so, we should document this. If not, we shouldn't …

    chipx86chipx86

    Let's use "webhook".

    chipx86chipx86

    This is indented too far.

    chipx86chipx86

    Should be "dict".

    chipx86chipx86

    Since there's only one, how about just attachment?

    chipx86chipx86

    It's best to avoid one-line dictionaries with multiple keys, as it becomes harder to add to. Let's do: return { …

    chipx86chipx86
    Checks run (1 failed, 1 succeeded)
    flake8 failed.
    JSHint passed.

    flake8

    hailan
    Review request changed
    Change Summary:

    Using Slack's format for Discord webhook messages. It looks cleaner
    this way - we don't need to do weird things like translating hex
    color code to decimal numbers

    Description:
    ~  

    Looks like this right now.

    ~   Still trying to figure out how to pass in all the relevant fields.
    ~   Image

      ~

    Admins can add a Discord Integration to their Review Board. After

      ~ setting it up, it will alert them on the changes of Review Request
      ~ in the specified Discord Server.

    Commits:
    Summary ID Author
    Discord Chat Integration
    ef1955ee8bc031dd3a8ef98cb42ff730e860066c HailanXyouknow
    Discord Chat Integration
    b2f02558f931c87ef0644c8048373f161219fe4b HailanXyouknow

    Checks run (1 failed, 1 succeeded)

    flake8 failed.
    JSHint passed.

    flake8

    hailan
    hailan
    hailan
    1. 
        
    2. 
        
    hailan
    MarcusBoay
    1. 
        
    2. rbintegrations/discord/integration.py (Diff revision 4)
       
       
      Show all issues

      Please remove.

    3. rbintegrations/discord/integration.py (Diff revision 4)
       
       
      Show all issues

      TODO comment?

    4. rbintegrations/discord/integration.py (Diff revision 4)
       
       
      Show all issues

      Should this be Discord instead?

    5. rbintegrations/discord/integration.py (Diff revision 4)
       
       
      Show all issues

      Should this be Discord instead?

      1. I've added an explanation on why this it is using Slack's URL. :)

    6. rbintegrations/discord/integration.py (Diff revision 4)
       
       
      Show all issues

      Should this be Discord instead?

    7. rbintegrations/discord/integration.py (Diff revision 4)
       
       
      Show all issues

      Should this be Discord instead?

    8. rbintegrations/discord/tests.py (Diff revision 4)
       
       
      Show all issues

      It's more of a nitpick but 'mattemost' -> 'discord'

    9. 
        
    hailan
    hailan
    david
    1. Looking pretty solid. Just some style-related comments.

    2. rbintegrations/discord/forms.py (Diff revision 5)
       
       
       
       
      Show all issues

      Let's use double quotes for the quotation marks inside the string.

    3. rbintegrations/discord/integration.py (Diff revision 5)
       
       
       
      Show all issues

      Please add a blank line between these two.

    4. rbintegrations/discord/integration.py (Diff revision 5)
       
       
       
       
      Show all issues

      Maybe move the contents of this method back into the integration class? I don't see a good reason to have a separate top-level function here.

    5. rbintegrations/discord/integration.py (Diff revision 5)
       
       
       
      Show all issues

      Please use single quotes for these.

    6. rbintegrations/discord/integration.py (Diff revision 5)
       
       
      Show all issues

      Can we use a named logger here? At the top level of the file, add:

      logger = logging.getLogger(__name__)
      

      This can then be logger.debug(...)

    7. rbintegrations/discord/integration.py (Diff revision 5)
       
       
      Show all issues

      There's an extra blank line here that can be removed.

    8. rbintegrations/discord/tests.py (Diff revision 5)
       
       
      Show all issues

      Please add a module docstring to the top of this file.

    9. rbintegrations/discord/tests.py (Diff revision 5)
       
       
       
      Show all issues

      Add a blank line between these two.

    10. rbintegrations/discord/tests.py (Diff revision 5)
       
       
       
      Show all issues

      Leftover debug output?

    11. rbintegrations/slack/integration.py (Diff revision 5)
       
       
      Show all issues

      This line isn't necessary.

    12. 
        
    hailan
    Review request changed
    Change Summary:
    Addressed David's feedback.
    Tested DiscordIntegration manually and reran the unit tests.
    Commits:
    Summary ID Author
    Discord Chat Integration
    This allows Review Board to have an option of notifying Discord channels on any Review Request changes. This commit also includes a refactoring of the notify() function in SlackIntegration.
    cea446b49eba25b641cfb5fcfea406395105fa2d HailanXyouknow
    Discord Chat Integration
    This allows Review Board to have an option of notifying Discord channels on any Review Request changes. This commit also includes a refactoring of the notify() function in SlackIntegration.
    12104735761a778bc8d4283cd0d8ef263bd07210 HailanXyouknow

    Checks run (1 failed, 1 succeeded)

    flake8 failed.
    JSHint passed.

    flake8

    hailan
    david
    1. Looking very solid!

    2. rbintegrations/discord/integration.py (Diff revision 7)
       
       
       
      Show all issues

      Instead of using the continuation character here, can we wrap this in parens?

    3. 
        
    hailan
    hailan
    hailan
    hailan
    1. 
        
    2. 
        
    keanweng
    1. I don't know much about Discord Integration, so I just nit-picked on some styling issue.

      1. Thanks you! 
        I was able to learn why some modules are grouped together through this review.
    2. rbintegrations/discord/forms.py (Diff revision 9)
       
       
       
      Show all issues

      As per the coding style guide, I believe these imports should be moved down to a new group as they are Project imports?

      1. I went through other integrations and saw that reviewboard modules are grouped together with django and djblets modules.
        I think this is because reviewboard modules are considered "modules not belonging to the current project codebase" as per the style guide.
        Will wait for mentors to confirm this.

      2. That's correct. From the point of view of the rbintegrations package, reviewboard is a third-party module just like django.

    3. rbintegrations/discord/integration.py (Diff revision 9)
       
       
      Show all issues

      Missing period here.

    4. rbintegrations/discord/tests.py (Diff revision 9)
       
       
       
      Show all issues

      Should be in alphabetical order.

      1. These lines are already in alphabetical order contrib > utils

    5. rbintegrations/discord/tests.py (Diff revision 9)
       
       
       
       
      Show all issues

      These imports should be moved down a group too.

      1. Same as above, will wait for confirmation from mentors.

    6. 
        
    hailan
    david
    1. 
        
    2. rbintegrations/discord/forms.py (Diff revision 10)
       
       
       
       
      Show all issues

      Let's switch the use of single- and double-quotes here:

      help_text=_('Your unique Discord webhook URL. This can be found at '
                  'the "Integration" page after selecting '
                  '"Server Settings".')
      
    3. 
        
    hailan
    hailan
    1. 
        
    2. 
        
    chipx86
    1. This looks great! Most of my comments are just small style nits for code/docs.

    2. rbintegrations/discord/integration.py (Diff revision 11)
       
       
       
      Show all issues

      These two lines should be swapped (alphabetical order).

    3. rbintegrations/discord/integration.py (Diff revision 11)
       
       
       
       
      Show all issues

      Two blank lines between imports and other code.

    4. rbintegrations/discord/integration.py (Diff revision 11)
       
       
       
       
       
      Show all issues

      This should use ugettext_lazy, like the form does.

    5. rbintegrations/discord/integration.py (Diff revision 11)
       
       
       
       
      Show all issues

      Mind putting this in alphabetical order? Helps keep things organized as new settings are added.

    6. rbintegrations/discord/integration.py (Diff revision 11)
       
       
      Show all issues

      You can bump this to a modern date and time.

    7. rbintegrations/discord/integration.py (Diff revision 11)
       
       
       
      Show all issues

      This appears to be in the wrong spot. Should be further down, under event_name, and have , optional.

    8. rbintegrations/discord/integration.py (Diff revision 11)
       
       
      Show all issues

      Should have , optional

    9. rbintegrations/discord/integration.py (Diff revision 11)
       
       
       
       
      Show all issues

      Can you pass these as keyword arguments? Helps avoid issues as parameters get added, and keeps code readable.

    10. rbintegrations/discord/integration.py (Diff revision 11)
       
       
       
       
      Show all issues

      No need for the blank line here. We can convey this as one "paragraph", where we're building the initial state of the payload.

    11. rbintegrations/discord/integration.py (Diff revision 11)
       
       
      Show all issues

      Can you use '%s/slack' % config.... form?

    12. rbintegrations/discord/integration.py (Diff revision 11)
       
       
       
       
      Show all issues

      Can you set this to alphabetical order?

    13. rbintegrations/discord/integration.py (Diff revision 11)
       
       
       
      Show all issues

      If you use logger.exception, you won't need exc_info=True.

    14. rbintegrations/discord/integration.py (Diff revision 11)
       
       
       
       
      Show all issues

      Doesn't look like this function is doing that, at least not directly. Maybe state what it wraps, so it's clear where to go for docs?

    15. rbintegrations/discord/tests.py (Diff revision 11)
       
       
      Show all issues

      We don't need docstrings for setUp or tearDown. Sort of an exception to a rule.

    16. rbintegrations/discord/tests.py (Diff revision 11)
       
       
       
       
       
       
       
       
       
       
      Show all issues

      You can pass id=12321 to create_review_request() (in fact, it's important to do that — old code may not though).

    17. rbintegrations/discord/tests.py (Diff revision 11)
       
       
       
       
       
       
       
       
       
       
      Show all issues

      Same here with id=.

    18. rbintegrations/discord/tests.py (Diff revision 11)
       
       
      Show all issues

      No need to call this, since we already created it above.

    19. rbintegrations/discord/tests.py (Diff revision 11)
       
       
      Show all issues

      This will need a docstring.

    20. rbintegrations/slack/integration.py (Diff revision 11)
       
       
       
       
       
       
      Show all issues

      This can be a single statement.

    21. rbintegrations/slack/integration.py (Diff revision 11)
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
      Show all issues

      These all list , optional, but the arguments are all required in the method signature.

    22. rbintegrations/slack/integration.py (Diff revision 11)
       
       
       
       
      Show all issues

      Can you pass all these as keyword arguments?

    23. 
        
    jblazusi
    1. I just noticed that Christian beat me to the review, so hopefully these aren't duplicates.
      Otherwise, I manually tested the integration on my own discord server, and it works wonderfully.
      I also ran the tests and all of them worked on RB3 but strangely there are 2 failing test cases on RB4.
      However, these are already documented on the Notion documents.

    2. rbintegrations/discord/integration.py (Diff revision 11)
       
       
      Show all issues

      I think that lines 11 and 12 should be swapped so that they follow alphabetical order.

    3. rbintegrations/discord/integration.py (Diff revision 11)
       
       
      Show all issues

      I noticed that other review board files have 2 lines below the import statements. So I think that you should have 2 lines after the last import statement for your logger = logging.getLogger(__name__) and then 2 lines below before the class definition.

    4. 
        
    hailan
    Review request changed
    Change Summary:

    Address feedbacks from Christian and Jacob

    Commits:
    Summary ID Author
    Discord Chat Integration
    This allows Review Board to have an option of notifying Discord channels on any Review Request changes. This commit also includes a refactoring of the notify() function in SlackIntegration.
    1c92b2dda999f80ff90c8b40bfcdc57c028796de HailanXyouknow
    Discord Chat Integration
    This allows Review Board to have an option of notifying Discord channels on any Review Request changes. This commit also includes a refactoring of the notify() function in SlackIntegration.
    c939590f76e4cbd43cf403d88185b2290ef88d1c HailanXyouknow

    Checks run (1 failed, 1 succeeded)

    flake8 failed.
    JSHint passed.

    flake8

    hailan
    ruonanjia
    1. 
        
    2. rbintegrations/discord/integration.py (Diff revision 13)
       
       
      Show all issues

      I have to add .encode('UTF-8) at the end of this line to get it to work for some reason. Running into this issue when I try to get a message to show up on discord: TypeError: POST data should be bytes, an iterable of bytes, or a file object. It cannot be of type str.

      Other than that, tested it and works well!

      1. Yeah, that'll be important on Python 3, and must be done before the length is calculated (so we get a length in bytes and not characters).

    3. 
        
    hailan
    chipx86
    1. Just a few small things, and then this will land :)

    2. rbintegrations/discord/forms.py (Diff revision 14)
       
       
       
      Show all issues

      Can you say "integration on Discord", so it's clear where they need to add this?

    3. rbintegrations/discord/forms.py (Diff revision 14)
       
       
       
       
      Show all issues

      This has two spellings of "Webhook": "Webhook" and "WebHook". Not your fault — we're inconsistent in places as well. I think we should keep any non-title versions "webhook" (no capitalizations), as this is more standard these days.

    4. rbintegrations/discord/forms.py (Diff revision 14)
       
       
      Show all issues

      "that that" -> "that"

    5. rbintegrations/discord/forms.py (Diff revision 14)
       
       
      Show all issues

      No space after the comma.

    6. rbintegrations/discord/integration.py (Diff revision 14)
       
       
      Show all issues

      lowercase: "utf-8".

    7. rbintegrations/discord/integration.py (Diff revision 14)
       
       
      Show all issues

      To check, is there a reason we use this User-Agent? If so, we should document this. If not, we shouldn't include it.

      1. Yes, to avoid urllib blocking (403 error).
        I will add a comment in this section.

    8. rbintegrations/slack/integration.py (Diff revision 14)
       
       
      Show all issues

      Let's use "webhook".

    9. rbintegrations/slack/integration.py (Diff revision 14)
       
       
       
       
      Show all issues

      This is indented too far.

    10. rbintegrations/slack/integration.py (Diff revision 14)
       
       
      Show all issues

      Should be "dict".

    11. rbintegrations/slack/integration.py (Diff revision 14)
       
       
      Show all issues

      Since there's only one, how about just attachment?

    12. rbintegrations/slack/integration.py (Diff revision 14)
       
       
      Show all issues

      It's best to avoid one-line dictionaries with multiple keys, as it becomes harder to add to. Let's do:

      return {
          'attachments': [attachments],
          'icon_url': integration.LOGO_URL,
      }
      

      Also note the alphabetical order.

    13. 
        
    hailan
    chipx86
    1. Ship It!
    2. 
        
    chipx86
    Review request changed
    Status:
    Completed
    Change Summary:

    Pushed to release-2.0.x (133d51e).