22
22
import shlex
23
23
import sys
24
24
import tempfile
25
+ import textwrap
25
26
from typing import Dict , Optional , TextIO
26
27
27
-
28
28
logger = logging .getLogger ()
29
29
logger .setLevel (logging .DEBUG )
30
30
handler = logging .StreamHandler (sys .stderr )
@@ -61,6 +61,7 @@ def write_commit(io: TextIO, title: str, body: str):
61
61
io .write (body .encode ())
62
62
io .flush ()
63
63
64
+
64
65
def parse_trailers (title , body ) -> Dict :
65
66
trailers = defaultdict (list )
66
67
@@ -77,6 +78,29 @@ def parse_trailers(title, body) -> Dict:
77
78
return trailers
78
79
79
80
81
+ def split_paragraphs (text : str ):
82
+ """
83
+ Split the given text into a generator of paragraph lines and a boolean "markdown" flag.
84
+
85
+ If any line of a paragraph starts with a markdown character, we will assume the whole paragraph
86
+ contains markdown.
87
+ """
88
+ lines = text .splitlines (keepends = True )
89
+ paragraph = []
90
+ markdown = False
91
+ for line in lines :
92
+ if line .strip () == "" :
93
+ if len (paragraph ) > 0 :
94
+ yield paragraph , markdown
95
+ paragraph .clear ()
96
+ markdown = False
97
+ else :
98
+ if line [0 ] in ("#" , "*" , "-" , "=" ) or line [0 ].isdigit ():
99
+ markdown = True
100
+ paragraph .append (line )
101
+ yield paragraph , markdown
102
+
103
+
80
104
if __name__ == "__main__" :
81
105
"""
82
106
This script performs some basic linting of our PR titles and body. The PR number is read from the PR_NUMBER
@@ -96,10 +120,6 @@ def parse_trailers(title, body) -> Dict:
96
120
* Has "Reviewers:" trailer if the PR is approved
97
121
"""
98
122
99
- if not get_env ("GITHUB_ACTIONS" ):
100
- print ("This script is intended to by run by GitHub Actions." )
101
- exit (1 )
102
-
103
123
pr_number = get_env ("PR_NUMBER" )
104
124
cmd = f"gh pr view { pr_number } --json 'title,body,reviews'"
105
125
p = subprocess .run (shlex .split (cmd ), capture_output = True )
@@ -132,6 +152,32 @@ def check(positive_assertion, ok_msg, err_msg):
132
152
check ("Delete this text and replace" not in body , "PR template text not present" , "PR template text should be removed" )
133
153
check ("Committer Checklist" not in body , "PR template text not present" , "Old PR template text should be removed" )
134
154
155
+ paragraph_iter = split_paragraphs (body )
156
+ new_paragraphs = []
157
+ for p , markdown in paragraph_iter :
158
+ if markdown :
159
+ # If a paragraph looks like it has markdown in it, wrap each line separately.
160
+ new_lines = []
161
+ for line in p :
162
+ new_lines .append (textwrap .fill (line , width = 72 , break_long_words = False , break_on_hyphens = False , replace_whitespace = False ))
163
+ rewrapped_p = "\n " .join (new_lines )
164
+ else :
165
+ rewrapped_p = textwrap .fill ("" .join (p ), width = 72 , break_long_words = False , break_on_hyphens = False , replace_whitespace = True )
166
+ new_paragraphs .append (rewrapped_p + "\n " )
167
+ body = "\n " .join (new_paragraphs )
168
+
169
+ if get_env ("GITHUB_ACTIONS" ):
170
+ with tempfile .NamedTemporaryFile () as fp :
171
+ fp .write (body .encode ())
172
+ fp .flush ()
173
+ cmd = f"gh pr edit { pr_number } --body-file { fp .name } "
174
+ p = subprocess .run (shlex .split (cmd ), capture_output = True )
175
+ fp .close ()
176
+ if p .returncode != 0 :
177
+ logger .error (f"Could not update PR { pr_number } . STDOUT: { p .stdout .decode ()} " )
178
+ else :
179
+ logger .info (f"Not reformatting { pr_number } since this is not running on GitHub Actions." )
180
+
135
181
# Check for Reviewers
136
182
approved = has_approval (reviews )
137
183
if approved :
@@ -143,12 +189,13 @@ def check(positive_assertion, ok_msg, err_msg):
143
189
logger .debug (reviewer_in_body )
144
190
145
191
logger .debug ("Commit will look like:\n " )
146
- logger .debug ("``` " )
192
+ logger .debug ("<pre> " )
147
193
io = BytesIO ()
194
+ title += f" (#{ pr_number } )"
148
195
write_commit (io , title , body )
149
196
io .seek (0 )
150
197
logger .debug (io .read ().decode ())
151
- logger .debug ("``` \n " )
198
+ logger .debug ("</pre> \n " )
152
199
153
200
exit_code = 0
154
201
logger .debug ("Validation results:" )
0 commit comments