blob: d03257c28a89da83bb734731469460f40592db1e [file] [log] [blame]
Lukasz Anforowicza80ca4b2024-09-06 21:55:091#!/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"""
6This script can help with creating draft comments in a Gerrit code review.
7
8The script needs to be invoked from a `git` branch that 1) is associated
9with a Gerrit review, and 2) has an explicitly defined upstream branch.
10The 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
12new crate to Chromium.
13"""
14
15import argparse
16import json
17import os
18import re
19import shutil
20import sys
21from create_update_cl import Git
22
23DEPOT_TOOLS_PATH = os.path.dirname(shutil.which('gclient'))
24sys.path.insert(0, DEPOT_TOOLS_PATH)
25from gerrit_util import CreateHttpConn, ReadHttpJsonResponse
26
27
28class 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
55def 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
95if __name__ == '__main__':
96 sys.exit(main())