Lukasz Anforowicz | a80ca4b | 2024-09-06 21:55:09 | [diff] [blame] | 1 | #!/usr/bin/env vpython3 |
| 2 | # Copyright 2024 The Chromium Authors |
| 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | """ |
| 6 | This script can help with creating draft comments in a Gerrit code review. |
| 7 | |
| 8 | The script needs to be invoked from a `git` branch that 1) is associated |
| 9 | with a Gerrit review, and 2) has an explicitly defined upstream branch. |
| 10 | The script is typically invoked either on 1) an update branch created by |
| 11 | `//tools/crates/create_update_cl.py`, or 2) a manually crated branch that adds a |
| 12 | new crate to Chromium. |
| 13 | """ |
| 14 | |
| 15 | import argparse |
| 16 | import json |
| 17 | import os |
| 18 | import re |
| 19 | import shutil |
| 20 | import sys |
| 21 | from create_update_cl import Git |
| 22 | |
| 23 | DEPOT_TOOLS_PATH = os.path.dirname(shutil.which('gclient')) |
| 24 | sys.path.insert(0, DEPOT_TOOLS_PATH) |
| 25 | from gerrit_util import CreateHttpConn, ReadHttpJsonResponse |
| 26 | |
| 27 | |
| 28 | class DraftCreator: |
| 29 | |
| 30 | def __init__(self): |
| 31 | gerrit_json = json.loads(Git('cl', 'issue', '--json=-').splitlines()[1]) |
| 32 | self.gerrit_host = gerrit_json['gerrit_host'] |
| 33 | self.gerrit_issue = str(gerrit_json['issue']) |
| 34 | |
| 35 | def CreateDraft(self, path, line, message): |
| 36 | """ Calls the following REST API: |
| 37 | https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#create-draft |
| 38 | """ |
| 39 | |
| 40 | url_path = f'changes/{self.gerrit_issue}/revisions/current/drafts' |
| 41 | body: Dict[str, Any] = { |
| 42 | 'path': str(path), |
| 43 | 'line': int(line), |
| 44 | 'message': message, |
| 45 | 'unresolved': True, |
| 46 | } |
| 47 | print(f'Creating a comment for {path}:{line}') |
| 48 | conn = CreateHttpConn(self.gerrit_host, |
| 49 | url_path, |
| 50 | reqtype='PUT', |
| 51 | body=body) |
| 52 | response = ReadHttpJsonResponse(conn, accept_statuses=[200, 201]) |
| 53 | |
| 54 | |
| 55 | def main(): |
| 56 | parser = argparse.ArgumentParser( |
| 57 | description='Create draft comments in a Gerrit code review') |
| 58 | parser.add_argument('--comment', |
| 59 | default='TODO: `unsafe` review', |
| 60 | help='Text of the comment') |
| 61 | parser.add_argument( |
| 62 | '--trigger-regex', |
| 63 | default='\\bunsafe\\b', |
| 64 | help='Text/substring of lines that need new draft comments') |
| 65 | parser.add_argument( |
| 66 | '--path-regex', |
| 67 | default='third_party/rust/chromium_crates_io/vendor/.*\\.rs$', |
| 68 | help='Text/substring of lines that need new draft comments') |
| 69 | args = parser.parse_args() |
| 70 | |
| 71 | trigger_regex = re.compile(args.trigger_regex) |
| 72 | path_regex = re.compile(args.path_regex) |
| 73 | |
| 74 | curr_branch = Git('rev-parse', '--abbrev-ref', 'HEAD').strip() |
| 75 | upstream_branch = Git('rev-parse', '--abbrev-ref', '--symbolic-full-name', |
| 76 | '@{u}').strip() |
| 77 | file_list = Git('diff', '--name-only', '--diff-filter=ACMR', |
| 78 | f'{upstream_branch}..{curr_branch}') |
| 79 | |
| 80 | draft_creator = DraftCreator() |
| 81 | for file_path in file_list.splitlines(): |
| 82 | file_path = file_path.strip() |
| 83 | if not path_regex.search(file_path): continue |
| 84 | with open(file_path) as file: |
| 85 | lines = [line.rstrip() for line in file] |
| 86 | for line_number in range(len(lines)): |
| 87 | line = lines[line_number] |
| 88 | line_number = line_number + 1 # Line numbers in Gerrit start at 1 |
| 89 | if not trigger_regex.search(line): continue |
| 90 | draft_creator.CreateDraft(file_path, line_number, args.comment) |
| 91 | |
| 92 | return 0 |
| 93 | |
| 94 | |
| 95 | if __name__ == '__main__': |
| 96 | sys.exit(main()) |