24
24
ARTIFACT_TYPES_WITHOUT_MULTIPLE_FILES_SUPPORT ,
25
25
BUILD_FINAL_STATES ,
26
26
BUILD_STATE_BUILDING ,
27
+ BUILD_STATE_CANCELLED ,
27
28
BUILD_STATE_CLONING ,
28
29
BUILD_STATE_FINISHED ,
29
30
BUILD_STATE_INSTALLING ,
@@ -136,7 +137,7 @@ class SyncRepositoryTask(SyncRepositoryMixin, Task):
136
137
in our database.
137
138
"""
138
139
139
- name = __name__ + ' .sync_repository_task'
140
+ name = __name__ + " .sync_repository_task"
140
141
max_retries = 5
141
142
default_retry_delay = 7 * 60
142
143
throws = (
@@ -145,7 +146,7 @@ class SyncRepositoryTask(SyncRepositoryMixin, Task):
145
146
)
146
147
147
148
def before_start (self , task_id , args , kwargs ):
148
- log .info (' Running task.' , name = self .name )
149
+ log .info (" Running task." , name = self .name )
149
150
150
151
# Create the object to store all the task-related data
151
152
self .data = TaskData ()
@@ -168,7 +169,7 @@ def before_start(self, task_id, args, kwargs):
168
169
169
170
# Also note there are builds that are triggered without a commit
170
171
# because they just build the latest commit for that version
171
- self .data .build_commit = kwargs .get (' build_commit' )
172
+ self .data .build_commit = kwargs .get (" build_commit" )
172
173
173
174
log .bind (
174
175
project_slug = self .data .project .slug ,
@@ -179,7 +180,7 @@ def on_failure(self, exc, task_id, args, kwargs, einfo):
179
180
# Do not log as error handled exceptions
180
181
if isinstance (exc , RepositoryError ):
181
182
log .warning (
182
- ' There was an error with the repository.' ,
183
+ " There was an error with the repository." ,
183
184
)
184
185
elif isinstance (exc , SyncRepositoryLocked ):
185
186
log .warning (
@@ -274,10 +275,8 @@ class UpdateDocsTask(SyncRepositoryMixin, Task):
274
275
build all the documentation formats and upload them to the storage.
275
276
"""
276
277
277
- name = __name__ + '.update_docs_task'
278
- autoretry_for = (
279
- BuildMaxConcurrencyError ,
280
- )
278
+ name = __name__ + ".update_docs_task"
279
+ autoretry_for = (BuildMaxConcurrencyError ,)
281
280
max_retries = settings .RTD_BUILDS_MAX_RETRIES
282
281
default_retry_delay = settings .RTD_BUILDS_RETRY_DELAY
283
282
retry_backoff = False
@@ -320,10 +319,12 @@ class UpdateDocsTask(SyncRepositoryMixin, Task):
320
319
321
320
def _setup_sigterm (self ):
322
321
def sigterm_received (* args , ** kwargs ):
323
- log .warning ('SIGTERM received. Waiting for build to stop gracefully after it finishes.' )
322
+ log .warning (
323
+ "SIGTERM received. Waiting for build to stop gracefully after it finishes."
324
+ )
324
325
325
326
def sigint_received (* args , ** kwargs ):
326
- log .warning (' SIGINT received. Canceling the build running.' )
327
+ log .warning (" SIGINT received. Canceling the build running." )
327
328
328
329
# Only allow to cancel the build if it's not already uploading the files.
329
330
# This is to protect our users to end up with half of the documentation uploaded.
@@ -347,12 +348,12 @@ def _check_concurrency_limit(self):
347
348
)
348
349
concurrency_limit_reached = response .get ("limit_reached" , False )
349
350
max_concurrent_builds = response .get (
350
- ' max_concurrent' ,
351
+ " max_concurrent" ,
351
352
settings .RTD_MAX_CONCURRENT_BUILDS ,
352
353
)
353
354
except Exception :
354
355
log .exception (
355
- ' Error while hitting/parsing API for concurrent limit checks from builder.' ,
356
+ " Error while hitting/parsing API for concurrent limit checks from builder." ,
356
357
project_slug = self .data .project .slug ,
357
358
version_slug = self .data .version .slug ,
358
359
)
@@ -375,7 +376,7 @@ def _check_concurrency_limit(self):
375
376
376
377
def _check_project_disabled (self ):
377
378
if self .data .project .skip :
378
- log .warning (' Project build skipped.' )
379
+ log .warning (" Project build skipped." )
379
380
raise BuildAppError (BuildAppError .BUILDS_DISABLED )
380
381
381
382
def before_start (self , task_id , args , kwargs ):
@@ -403,21 +404,21 @@ def before_start(self, task_id, args, kwargs):
403
404
self .data .project = self .data .version .project
404
405
405
406
# Save the builder instance's name into the build object
406
- self .data .build [' builder' ] = socket .gethostname ()
407
+ self .data .build [" builder" ] = socket .gethostname ()
407
408
408
409
# Reset any previous build error reported to the user
409
- self .data .build [' error' ] = ''
410
+ self .data .build [" error" ] = ""
410
411
# Also note there are builds that are triggered without a commit
411
412
# because they just build the latest commit for that version
412
- self .data .build_commit = kwargs .get (' build_commit' )
413
+ self .data .build_commit = kwargs .get (" build_commit" )
413
414
414
415
self .data .build_director = BuildDirector (
415
416
data = self .data ,
416
417
)
417
418
418
419
log .bind (
419
420
# NOTE: ``self.data.build`` is just a regular dict, not an APIBuild :'(
420
- builder = self .data .build [' builder' ],
421
+ builder = self .data .build [" builder" ],
421
422
commit = self .data .build_commit ,
422
423
project_slug = self .data .project .slug ,
423
424
version_slug = self .data .version .slug ,
@@ -470,7 +471,7 @@ def on_failure(self, exc, task_id, args, kwargs, einfo):
470
471
#
471
472
# So, we create the `self.data.build` with the minimum required data.
472
473
self .data .build = {
473
- 'id' : self .data .build_pk ,
474
+ "id" : self .data .build_pk ,
474
475
}
475
476
476
477
# Known errors in our application code (e.g. we couldn't connect to
@@ -488,6 +489,10 @@ def on_failure(self, exc, task_id, args, kwargs, einfo):
488
489
else :
489
490
message_id = BuildUserError .GENERIC
490
491
492
+ # Set build state as cancelled if the user cancelled the build
493
+ if isinstance (exc , BuildCancelled ):
494
+ self .data .build ["state" ] = BUILD_STATE_CANCELLED
495
+
491
496
else :
492
497
# We don't know what happened in the build. Log the exception and
493
498
# report a generic notification to the user.
@@ -513,7 +518,7 @@ def on_failure(self, exc, task_id, args, kwargs, einfo):
513
518
if message_id not in self .exceptions_without_notifications :
514
519
self .send_notifications (
515
520
self .data .version_pk ,
516
- self .data .build ['id' ],
521
+ self .data .build ["id" ],
517
522
event = WebHookEvent .BUILD_FAILED ,
518
523
)
519
524
@@ -541,7 +546,7 @@ def on_failure(self, exc, task_id, args, kwargs, einfo):
541
546
542
547
send_external_build_status (
543
548
version_type = version_type ,
544
- build_pk = self .data .build ['id' ],
549
+ build_pk = self .data .build ["id" ],
545
550
commit = self .data .build_commit ,
546
551
status = status ,
547
552
)
@@ -661,20 +666,20 @@ def on_success(self, retval, task_id, args, kwargs):
661
666
662
667
self .send_notifications (
663
668
self .data .version .pk ,
664
- self .data .build ['id' ],
669
+ self .data .build ["id" ],
665
670
event = WebHookEvent .BUILD_PASSED ,
666
671
)
667
672
668
673
if self .data .build_commit :
669
674
send_external_build_status (
670
675
version_type = self .data .version .type ,
671
- build_pk = self .data .build ['id' ],
676
+ build_pk = self .data .build ["id" ],
672
677
commit = self .data .build_commit ,
673
678
status = BUILD_STATUS_SUCCESS ,
674
679
)
675
680
676
681
# Update build object
677
- self .data .build [' success' ] = True
682
+ self .data .build [" success" ] = True
678
683
679
684
def on_retry (self , exc , task_id , args , kwargs , einfo ):
680
685
"""
@@ -686,11 +691,11 @@ def on_retry(self, exc, task_id, args, kwargs, einfo):
686
691
687
692
See https://docs.celeryproject.org/en/master/userguide/tasks.html#retrying
688
693
"""
689
- log .info (' Retrying this task.' )
694
+ log .info (" Retrying this task." )
690
695
691
696
if isinstance (exc , BuildMaxConcurrencyError ):
692
697
log .warning (
693
- ' Delaying tasks due to concurrency limit.' ,
698
+ " Delaying tasks due to concurrency limit." ,
694
699
project_slug = self .data .project .slug ,
695
700
version_slug = self .data .version .slug ,
696
701
)
@@ -713,7 +718,7 @@ def after_return(self, status, retval, task_id, args, kwargs, einfo):
713
718
so some attributes from the `self.data` object may not be defined.
714
719
"""
715
720
# Update build object
716
- self .data .build [' length' ] = (timezone .now () - self .data .start_time ).seconds
721
+ self .data .build [" length" ] = (timezone .now () - self .data .start_time ).seconds
717
722
718
723
build_state = None
719
724
# The state key might not be defined
@@ -742,9 +747,9 @@ def after_return(self, status, retval, task_id, args, kwargs, einfo):
742
747
)
743
748
744
749
log .info (
745
- ' Build finished.' ,
746
- length = self .data .build [' length' ],
747
- success = self .data .build [' success' ]
750
+ " Build finished." ,
751
+ length = self .data .build [" length" ],
752
+ success = self .data .build [" success" ],
748
753
)
749
754
750
755
def update_build (self , state = None ):
@@ -856,23 +861,20 @@ def get_build(self, build_pk):
856
861
if build_pk :
857
862
build = self .data .api_client .build (build_pk ).get ()
858
863
private_keys = [
859
- ' project' ,
860
- ' version' ,
861
- ' resource_uri' ,
862
- ' absolute_uri' ,
864
+ " project" ,
865
+ " version" ,
866
+ " resource_uri" ,
867
+ " absolute_uri" ,
863
868
]
864
869
# TODO: try to use the same technique than for ``APIProject``.
865
- return {
866
- key : val
867
- for key , val in build .items () if key not in private_keys
868
- }
870
+ return {key : val for key , val in build .items () if key not in private_keys }
869
871
870
872
# NOTE: this can be just updated on `self.data.build['']` and sent once the
871
873
# build has finished to reduce API calls.
872
874
def set_valid_clone (self ):
873
875
"""Mark on the project that it has been cloned properly."""
874
876
self .data .api_client .project (self .data .project .pk ).patch (
875
- {' has_valid_clone' : True }
877
+ {" has_valid_clone" : True }
876
878
)
877
879
self .data .project .has_valid_clone = True
878
880
self .data .version .project .has_valid_clone = True
@@ -887,7 +889,7 @@ def store_build_artifacts(self):
887
889
Remove build artifacts of types not included in this build (PDF, ePub, zip only).
888
890
"""
889
891
time_before_store_build_artifacts = timezone .now ()
890
- log .info (' Writing build artifacts to media storage' )
892
+ log .info (" Writing build artifacts to media storage" )
891
893
self .update_build (state = BUILD_STATE_UPLOADING )
892
894
893
895
valid_artifacts = self .get_valid_artifact_types ()
0 commit comments