1
1
# -*- coding: utf-8 -*-
2
2
import collections
3
+ from datetime import datetime , timedelta
3
4
import enum
4
5
import time
5
6
@@ -13,6 +14,7 @@ class PhabricatorBuildState(enum.Enum):
13
14
Queued = 1
14
15
Secured = 2
15
16
Public = 3
17
+ Expired = 4
16
18
17
19
18
20
class PhabricatorBuild (object ):
@@ -59,7 +61,9 @@ class PhabricatorActions(object):
59
61
Common Phabricator actions shared across clients
60
62
"""
61
63
62
- def __init__ (self , url , api_key , retries = 5 , sleep = 10 ):
64
+ def __init__ (
65
+ self , url , api_key , retries = 5 , sleep = 10 , build_expiry = timedelta (hours = 24 )
66
+ ):
63
67
self .api = PhabricatorAPI (url = url , api_key = api_key )
64
68
65
69
# Phabricator secure revision retries configuration
@@ -68,10 +72,12 @@ def __init__(self, url, api_key, retries=5, sleep=10):
68
72
self .max_retries = retries
69
73
self .retries = collections .defaultdict (lambda : (retries , None ))
70
74
self .sleep = sleep
75
+ self .build_expiry = build_expiry
71
76
logger .info (
72
77
"Will retry Phabricator secure revision queries" ,
73
78
retries = retries ,
74
79
sleep = sleep ,
80
+ build_expiry = build_expiry ,
75
81
)
76
82
77
83
# Load secure projects
@@ -114,6 +120,11 @@ def update_state(self, build):
114
120
build .revision_url = self .build_revision_url (build )
115
121
logger .info ("Revision is public" , build = str (build ))
116
122
123
+ # Check if the build has not expired
124
+ if self .is_expired_build (build ):
125
+ build .state = PhabricatorBuildState .Expired
126
+ logger .info ("Revision has expired" , build = str (build ))
127
+
117
128
elif retries_left <= 0 :
118
129
# Mark as secured when no retries are left
119
130
build .state = PhabricatorBuildState .Secured
@@ -183,3 +194,31 @@ def build_revision_url(self, build):
183
194
Build a Phabricator frontend url for a build's revision
184
195
"""
185
196
return "https://{}/D{}" .format (self .api .hostname , build .revision_id )
197
+
198
+ def is_expired_build (self , build ):
199
+ """
200
+ Check if a build has expired, using its Phabricator diff information
201
+ Returns True when the build has expired and should not be processed
202
+ """
203
+ assert isinstance (build , PhabricatorBuild )
204
+
205
+ # We need Phabricator diff details to get the date
206
+ if build .diff is None :
207
+ try :
208
+ diffs = self .api .search_diffs (diff_id = build .diff_id )
209
+ if not diffs :
210
+ raise Exception (f"Diff { build .diff_id } not found on Phabricator" )
211
+ build .diff = diffs [0 ]
212
+ except Exception as e :
213
+ logger .warn ("Failed to load diff" , build = str (build ), err = str (e ))
214
+ return False
215
+
216
+ # Then we can check on the expiry date
217
+ date_created = build .diff .get ("dateCreated" )
218
+ if not date_created :
219
+ logger .warn ("No creation date found" , build = str (build ))
220
+ return False
221
+
222
+ logger .info ("Found diff creation date" , build = str (build ), created = date_created )
223
+
224
+ return datetime .now () - datetime .fromtimestamp (date_created ) > self .build_expiry
0 commit comments