• 
      

    Go Tool for Review Bot

    Review Request #11240 — Created Oct. 22, 2020 and submitted

    Information

    ReviewBot
    master
    61c94b0...

    Reviewers

    This tool's ability to format was removed and placed into another tool,
    that tool is tentatively known as the GofmtTool. This was done because,
    go fmt is rather lightweight and does not rely on other files in order
    to carry out its function. However, go test and go vet require more
    information in order to work consistently. In particular they need
    access to the entire repository so that patched code can be fully
    analyzed against the package code. Therefore GofmtTool inherits from
    Tool, whereas GoTool inherits from RepositoryTool and is generally
    a much more computationally heavy tool.

    Manual testing was done to confirm that go test is working correctly.
    As of now it just creates general comments based on which tests have
    failed.
    Manual testing was done to confirm that go vet is working and known
    issues about failures when used against test files have been resolved.


    Description From Last Updated

    Go/Go Tools?

    daviddavid

    gofmt still exists, but I believe the modern recommendation is to use go fmt. Can we do that here to …

    daviddavid

    Perhaps "This file contains formatting errors and should be run through go fmt" ? Also, shouldn't this be checking the …

    daviddavid

    Since we have the output already in a variable, it's kind of silly to write it out to a file …

    daviddavid

    The imports should be in alphabetical order. So import json should be placed before import logging.

    ceciliaweiceciliawei

    Using the string's "split" method isn't portable (for example, windows doesn't use "/" as a path splitter). That said, there's …

    daviddavid

    It looks like we're running this for every single file, which means that if you have multiple changed files in …

    daviddavid

    Let's pull the result of dest_file.lower() out into a variable so we don't have to call it twice in these …

    chipx86chipx86

    Blank line between statements and the start of new blocks.

    chipx86chipx86

    Same here.

    chipx86chipx86

    This will scan the entirety of packages every iteration of files. If packages is a set, this will be faster, …

    chipx86chipx86

    This can fail, so we'll want to check for exceptions, just as we do further down.

    chipx86chipx86

    It's generally better to use %-formatted strings to join in variables, as this is faster in Python.

    chipx86chipx86

    We prefer %-formatted strings, rather than .format(), as it's technically faster and more consistent with the rest of our codebase. …

    chipx86chipx86

    When spanning lines, we prefer the % on the line with the variables, as it gives more room for the …

    chipx86chipx86

    No blank line here.

    chipx86chipx86

    Can you incorporate the package name in here, or something to help debug this if this comes up in production?

    chipx86chipx86

    Same as above regarding %-formatted strings.

    chipx86chipx86

    Let's use single quotes here, since the inner string doesn't use them. We prefer single quotes in Python strings wherever …

    chipx86chipx86

    If we compile this regex before we do the outer loop, it'll speed this part up.

    chipx86chipx86

    While common in Python, we shouldn't ever override _. That's because _ is commonly used as an alias to ugettext …

    chipx86chipx86

    Rather than putting this into a variable and pulling the indexes out, let's just unpack with: filename, line_num = \ …

    chipx86chipx86

    You can put the format argument on the same line, since it fits. No need for parens there either, since …

    chipx86chipx86

    No blank line here.

    chipx86chipx86

    Same comment as above regarding having identifying information in the message.

    chipx86chipx86

    Things within here are getting pretty deeply nested. Maybe break out the test and vet implementations into their own methods?

    daviddavid

    This should be wrapped in a try/except.

    daviddavid

    Would it be possible to add a comment showing an example of what the JSON output from go vet looks …

    daviddavid

    This is potentially running a lot of times, since it's deeply nested inside several loops. At the top level, can …

    daviddavid
    jblazusi
    david
    1. 
        
    2. bot/reviewbot/tools/gotool.py (Diff revision 2)
       
       
      Show all issues

      Go/Go Tools?

      1. My mistake, I was not exactly sure whether they were separate or not at the time. It is fixed now.

    3. bot/reviewbot/tools/gotool.py (Diff revision 2)
       
       

      It looks like you're leaning towards making the different uses of go optional, which is good. We should probably default to true for everything except go test, which should default to false (test suites can often be cumbersome and long-running).

      1. That is a good idea, I will make sure to implement it that way.

    4. 
        
    jblazusi
    jblazusi
    david
    1. 
        
    2. bot/reviewbot/tools/gotool.py (Diff revision 3)
       
       
      Show all issues

      gofmt still exists, but I believe the modern recommendation is to use go fmt. Can we do that here to be more future-proof?

      1. I believe that this is generally true, however, it is important to note that go fmt runs gofmt -l -w. The -w flag is responsible for overwriting the file, although I do not think that this is an issue, especially since patched files are temporary. But I do think that it is worth noting in case, whomever takes over the project is experiencing issues relating to overwriting a file.

        In short, I have updated the command to use go fmt and this can be found in the new GofmtTool CR.

    3. bot/reviewbot/tools/gotool.py (Diff revision 3)
       
       
      Show all issues

      Perhaps "This file contains formatting errors and should be run through go fmt" ?

      Also, shouldn't this be checking the output or return value from the format command? Seems like it just unconditionally adds the comment now (maybe that's still part of the WIP?)

      1. I addressed the message in the new GofmtTool. I originally did not setup conditionals, since I wanted to make sure I was getting the correct output, so this is an artifact from early testing.

    4. bot/reviewbot/tools/gotool.py (Diff revision 3)
       
       
       
       
       
       
       
       
       
      Show all issues

      Since we have the output already in a variable, it's kind of silly to write it out to a file and load it back in. We can just do:

      try:
          json_data = json.loads(cleaned_output)
      except Exception as e:
          ...
      
      1. This is definitely a blunder. I was a so caught up in using files from previous tools, that I completely forgot about just passing in the output string.

    5. 
        
    jblazusi
    jblazusi
    ceciliawei
    1. 
        
    2. bot/reviewbot/tools/gotool.py (Diff revision 4)
       
       
      Show all issues

      The imports should be in alphabetical order. So import json should be placed before import logging.

      1. Thank you, I will make sure I make this update in previous and future CRs.

    3. 
        
    david
    1. 
        
    2. bot/reviewbot/tools/gotool.py (Diff revision 4)
       
       
      Show all issues

      Using the string's "split" method isn't portable (for example, windows doesn't use "/" as a path splitter). That said, there's both a portable and easier way to do this:

      package = os.path.dirname(path)
      
      1. I was not aware of this being a portability issue, thank you so much for the advice. I have updated my code to use the os.path module in other areas as well.

    3. bot/reviewbot/tools/gotool.py (Diff revision 4)
       
       
      Show all issues

      It looks like we're running this for every single file, which means that if you have multiple changed files in a given package, we'll add the test failures multiple times.

      Instead of overriding handle_file, can we instead override handle_files, and use the file list to build a list of changed packages? We can then run the tests once per package.

      1. Excellent, this is exactly what I had in mind when I was optimizing my FBInfer Tool. However, the advice of building a list of changed packages was a very useful starting point.

    4. 
        
    jblazusi
    chipx86
    1. 
        
    2. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
       
       
       
       
       
       
      Show all issues

      Let's pull the result of dest_file.lower() out into a variable so we don't have to call it twice in these checks.

    3. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
       
      Show all issues

      Blank line between statements and the start of new blocks.

    4. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
       
      Show all issues

      Same here.

    5. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
       
      Show all issues

      This will scan the entirety of packages every iteration of files. If packages is a set, this will be faster, though then we lose the ordering. Perhaps that's okay, and we can sort the results when iterating it?

      If so, we can safely .add() into a set without needing to check existence first.

      1. That's clever, I am not sure why I did not think of using a set before. Further down, we loop through every package so the order is not relevant.

    6. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
       
       
       
       
       
       
       
       
       
      Show all issues

      This can fail, so we'll want to check for exceptions, just as we do further down.

      1. I totally agree with this. Although I think that it is worth mentioning that the other review bot tools do not have try/except blocks for the execute command.

    7. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
      Show all issues

      It's generally better to use %-formatted strings to join in variables, as this is faster in Python.

      1. I did not know that there was a difference in performance, that is good to know.

    8. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
      Show all issues

      We prefer %-formatted strings, rather than .format(), as it's technically faster and more consistent with the rest of our codebase.

      This can also be combiend with the previous line:

      formatted_output = '[%s]' % ','.join(gotest_output)
      
    9. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
      Show all issues

      When spanning lines, we prefer the % on the line with the variables, as it gives more room for the strings and helps more clearly indicate that we're formatting variables in.

    10. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
       
       
      Show all issues

      No blank line here.

    11. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
      Show all issues

      Can you incorporate the package name in here, or something to help debug this if this comes up in production?

    12. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
      Show all issues

      Same as above regarding %-formatted strings.

    13. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
      Show all issues

      Let's use single quotes here, since the inner string doesn't use them. We prefer single quotes in Python strings wherever possible.

    14. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
      Show all issues

      If we compile this regex before we do the outer loop, it'll speed this part up.

      1. I tried my best to fix this. However, I am not that familiar with regex, so I would appreciate it if you took another look at my change.

      2. Looks like you did it correctly.

      3. Perfect, I will go ahead and mark this issue as fixed.

    15. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
      Show all issues

      While common in Python, we shouldn't ever override _. That's because _ is commonly used as an alias to ugettext or ugettext_lazy, and this can have unintentional side-effects.

      Also for items, we need to use six.iteritems() to get consistent behavior between Python 2 and 3.

      1. I had no idea, thank you for letting me know. Is this common across most python programs, or just reviewboard in particular?
        If we are not using the variable, such as the situation I am in, what should I use instead of _?

      2. Christian answered this question in the slack:
        "naming is better than not, so that it's self-documenting. Avoiding unpacking those variables is even better. Fewer things for Python to deal with, less a maintainer has to worry about"

    16. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
       
      Show all issues

      Rather than putting this into a variable and pulling the indexes out, let's just unpack with:

      filename, line_num = \
          os.path.basename(key['posn']).split(':', 2)
      

      Could you also put a comment above this showing the general format of what we should expect here, so it's documented?

    17. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
       
       
      Show all issues

      You can put the format argument on the same line, since it fits. No need for parens there either, since we're not building a tuple (only one arg, and also (message) is equivalent to message since there's no tuple indicator, like a trailing comma or a second value).

    18. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
       
       
      Show all issues

      No blank line here.

    19. bot/reviewbot/tools/gotool.py (Diff revision 5)
       
       
      Show all issues

      Same comment as above regarding having identifying information in the message.

    20. 
        
    jblazusi
    jblazusi
    david
    1. 
        
    2. bot/reviewbot/tools/gotool.py (Diff revision 7)
       
       
      Show all issues

      Things within here are getting pretty deeply nested. Maybe break out the test and vet implementations into their own methods?

    3. bot/reviewbot/tools/gotool.py (Diff revision 7)
       
       
       
       
       
       
       
       
      Show all issues

      This should be wrapped in a try/except.

    4. bot/reviewbot/tools/gotool.py (Diff revision 7)
       
       
       
       
       
       
       
       
      Show all issues

      Would it be possible to add a comment showing an example of what the JSON output from go vet looks like? That way people looking at the code can see how it maps to what it's parsing.

    5. bot/reviewbot/tools/gotool.py (Diff revision 7)
       
       
       
      Show all issues

      This is potentially running a lot of times, since it's deeply nested inside several loops.

      At the top level, can we create a new dict that maps the patched file path back to f? That way we can just index into it instead of looping every time.

    6. 
        
    jblazusi
    jblazusi
    david
    1. Ship It!
    2. 
        
    jblazusi
    Review request changed
    Status:
    Completed
    Change Summary:
    Pushed to release-2.0.x (acb0cf2)