10
10
import threading
11
11
import time
12
12
from abc import ABC , abstractmethod
13
- from datetime import datetime
13
+ from datetime import datetime , timezone
14
14
from email import utils
15
15
from functools import cached_property
16
16
from pathlib import Path
@@ -1218,6 +1218,16 @@ def _munge_dict(dest, src, keys):
1218
1218
return pr_json
1219
1219
1220
1220
1221
+ def parse_pr_json_last_updated (pr_data : Union [Dict , LazyJson ]) -> Optional [datetime ]:
1222
+ """Parse the last updated time from a PR json blob. If it is not present, return None."""
1223
+ last_updated = pr_data .get ("updated_at" , None )
1224
+ if last_updated is not None :
1225
+ last_updated = datetime .fromisoformat (last_updated )
1226
+ if last_updated .tzinfo is None :
1227
+ last_updated = last_updated .replace (tzinfo = timezone .utc )
1228
+ return last_updated
1229
+
1230
+
1221
1231
def lazy_update_pr_json (
1222
1232
pr_json : Union [Dict , LazyJson ], force : bool = False
1223
1233
) -> Union [Dict , LazyJson ]:
@@ -1240,6 +1250,8 @@ def lazy_update_pr_json(
1240
1250
pr_json : dict-like
1241
1251
A dict-like object with the current PR information.
1242
1252
"""
1253
+ last_updated = parse_pr_json_last_updated (pr_json )
1254
+
1243
1255
hdrs = {
1244
1256
"Authorization" : f"token { get_bot_token ()} " ,
1245
1257
"Accept" : "application/vnd.github.v3+json" ,
@@ -1270,9 +1282,19 @@ def lazy_update_pr_json(
1270
1282
)
1271
1283
1272
1284
if r .status_code == 200 :
1273
- pr_json = trim_pr_json_keys (pr_json , src_pr_json = r .json ())
1274
- pr_json ["ETag" ] = r .headers ["ETag" ]
1275
- pr_json ["Last-Modified" ] = r .headers ["Last-Modified" ]
1285
+ # I have seen things come in out of order for reasons I do not
1286
+ # fully understand. We do not update in this case. - MRB
1287
+ new_last_updated = parse_pr_json_last_updated (r .json ())
1288
+ if (
1289
+ last_updated is None
1290
+ or new_last_updated is None
1291
+ or new_last_updated >= last_updated
1292
+ ):
1293
+ pr_json = trim_pr_json_keys (pr_json , src_pr_json = r .json ())
1294
+ pr_json ["ETag" ] = r .headers ["ETag" ]
1295
+ pr_json ["Last-Modified" ] = r .headers ["Last-Modified" ]
1296
+ else :
1297
+ pr_json = trim_pr_json_keys (pr_json )
1276
1298
else :
1277
1299
pr_json = trim_pr_json_keys (pr_json )
1278
1300
@@ -1358,8 +1380,11 @@ def close_out_labels(
1358
1380
pr_obj = get_pr_obj_from_pr_json (pr_json , gh )
1359
1381
pr_obj .create_comment (
1360
1382
"Due to the `bot-rerun` label I'm closing "
1361
- "this PR. I will make another one as"
1362
- f" appropriate.\n \n <sub>This message was generated by { get_bot_run_url ()} "
1383
+ "this PR. I will make another PR as"
1384
+ " appropriate. You should expect to "
1385
+ "wait at least a few hours, or possibly "
1386
+ "much longer, for a new PR."
1387
+ f"\n \n <sub>This message was generated by { get_bot_run_url ()} "
1363
1388
"- please use this URL for debugging.</sub>" ,
1364
1389
)
1365
1390
pr_obj .close ()
@@ -1404,7 +1429,10 @@ def close_out_dirty_prs(
1404
1429
pr_obj .create_comment (
1405
1430
"I see that this PR has conflicts, and I'm the only committer. "
1406
1431
"I'm going to close this PR and will make another one as"
1407
- f" appropriate.\n \n <sub>This was generated by { get_bot_run_url ()} - "
1432
+ " appropriate. You should expect to "
1433
+ "wait at least a few hours, or possibly "
1434
+ "much longer, for a new PR."
1435
+ f"\n \n <sub>This was generated by { get_bot_run_url ()} - "
1408
1436
"please use this URL for debugging.</sub>" ,
1409
1437
)
1410
1438
pr_obj .close ()
0 commit comments