|
5 | 5 | import re |
6 | 6 | import sys |
7 | 7 | from pathlib import Path |
8 | | -from typing import (NewType, Optional, cast) |
| 8 | +from typing import (NewType, Optional, cast, Tuple) |
9 | 9 |
|
10 | 10 | import canonicaljson |
11 | 11 |
|
@@ -235,6 +235,34 @@ def is_approved(proposed_plan: str, comment: TerraformComment) -> bool: |
235 | 235 | debug('Approving plan based on plan text') |
236 | 236 | return plan_cmp(proposed_plan, comment.body) |
237 | 237 |
|
| 238 | +def format_plan_text(plan_text: str) -> Tuple[str, str]: |
| 239 | + """ |
| 240 | + Format the given plan for insertion into a PR comment |
| 241 | + """ |
| 242 | + |
| 243 | + max_body_size = 50000 # bytes |
| 244 | + |
| 245 | + def truncate(t): |
| 246 | + lines = [] |
| 247 | + total_size = 0 |
| 248 | + |
| 249 | + for line in t.splitlines(): |
| 250 | + line_size = len(line.encode()) + 1 # + newline |
| 251 | + if total_size + line_size > max_body_size: |
| 252 | + lines.append('Plan is too large to fit in a PR comment. See the full plan in the workflow log.') |
| 253 | + break |
| 254 | + |
| 255 | + lines.append(line) |
| 256 | + total_size += line_size |
| 257 | + |
| 258 | + return '\n'.join(lines) |
| 259 | + |
| 260 | + if len(plan_text.encode()) > max_body_size: |
| 261 | + # needs truncation |
| 262 | + return 'trunc', truncate(plan_text) |
| 263 | + else: |
| 264 | + return 'text', plan_text |
| 265 | + |
238 | 266 | def main() -> int: |
239 | 267 | if len(sys.argv) < 2: |
240 | 268 | sys.stderr.write(f'''Usage: |
@@ -274,14 +302,15 @@ def main() -> int: |
274 | 302 | headers = comment.headers.copy() |
275 | 303 | headers['plan_job_ref'] = job_workflow_ref() |
276 | 304 | headers['plan_hash'] = plan_hash(body, comment.issue_url) |
| 305 | + headers['plan_text_format'], plan_text = format_plan_text(body) |
277 | 306 |
|
278 | 307 | comment = update_comment( |
279 | 308 | github, |
280 | 309 | comment, |
281 | 310 | description=description, |
282 | 311 | summary=create_summary(body), |
283 | 312 | headers=headers, |
284 | | - body=body, |
| 313 | + body=plan_text, |
285 | 314 | status=status |
286 | 315 | ) |
287 | 316 |
|
@@ -316,23 +345,29 @@ def main() -> int: |
316 | 345 | sys.stdout.write("The plan on the PR must be up to date. Alternatively, set the auto_approve input to 'true' to apply outdated plans\n") |
317 | 346 | comment = update_comment(github, comment, status=f':x: Plan not applied in {job_markdown_ref()} (Plan has changed)') |
318 | 347 |
|
319 | | - sys.stdout.write("""Performing diff between the pull request plan and the plan generated at execution time ... |
320 | | -> are lines from the plan in the pull request |
321 | | -< are lines from the plan generated at execution |
322 | | -Plan changes: |
323 | | -""") |
324 | | - |
325 | 348 | approved_plan_path = os.path.join(os.environ['STEP_TMP_DIR'], 'approved-plan.txt') |
326 | 349 | with open(approved_plan_path, 'w') as f: |
327 | 350 | f.write(comment.body.strip()) |
328 | 351 | proposed_plan_path = os.path.join(os.environ['STEP_TMP_DIR'], 'proposed-plan.txt') |
329 | 352 | with open(proposed_plan_path, 'w') as f: |
330 | | - f.write(proposed_plan.strip()) |
| 353 | + _, formatted_proposed_plan = format_plan_text(proposed_plan.strip()) |
| 354 | + f.write(formatted_proposed_plan.strip()) |
| 355 | + |
331 | 356 | debug(f'diff {proposed_plan_path} {approved_plan_path}') |
332 | 357 | diff_complete = subprocess.run(['diff', proposed_plan_path, approved_plan_path], check=False, capture_output=True, encoding='utf-8') |
333 | 358 | sys.stdout.write(diff_complete.stdout) |
334 | 359 | sys.stderr.write(diff_complete.stderr) |
335 | 360 |
|
| 361 | + if diff_complete.returncode != 0: |
| 362 | + sys.stdout.write("""Performing diff between the pull request plan and the plan generated at execution time. |
| 363 | +> are lines from the plan in the pull request |
| 364 | +< are lines from the plan generated at execution |
| 365 | +Plan differences: |
| 366 | +""") |
| 367 | + |
| 368 | + if comment.headers.get('plan_text_format', 'text') == 'trunc': |
| 369 | + sys.stdout.write('\nThe plan text was too large for a PR comment, not all differences may be shown here.') |
| 370 | + |
336 | 371 | if plan_ref := comment.headers.get('plan_job_ref'): |
337 | 372 | sys.stdout.write(f'\nCompare with the plan generated by the dflook/terraform-plan action in {plan_ref}\n') |
338 | 373 |
|
|
0 commit comments