Skip to content

Commit 8798752

Browse files
authored
Merge pull request #6451 from stsewd/decouple-setup-env
Be explicit when using setup_env
2 parents 3639eb1 + 17ab950 commit 8798752

File tree

4 files changed

+87
-53
lines changed

4 files changed

+87
-53
lines changed

readthedocs/projects/signals.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import django.dispatch
44

55

6-
before_vcs = django.dispatch.Signal(providing_args=['version'])
6+
before_vcs = django.dispatch.Signal(providing_args=['version', 'environmemt'])
77
after_vcs = django.dispatch.Signal(providing_args=['version'])
88

9-
before_build = django.dispatch.Signal(providing_args=['version'])
9+
before_build = django.dispatch.Signal(providing_args=['version', 'environmemt'])
1010
after_build = django.dispatch.Signal(providing_args=['version'])
1111

1212
project_import = django.dispatch.Signal(providing_args=['project'])

readthedocs/projects/tasks.py

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -104,20 +104,21 @@ def get_version(version_pk):
104104
version_data = api_v2.version(version_pk).get()
105105
return APIVersion(**version_data)
106106

107-
def get_vcs_repo(self):
108-
"""Get the VCS object of the current project."""
107+
def get_vcs_repo(self, environment):
108+
"""
109+
Get the VCS object of the current project.
110+
111+
All VCS commands will be executed using `environment`.
112+
"""
109113
version_repo = self.project.vcs_repo(
110-
self.version.slug,
111-
# When called from ``SyncRepositoryTask.run`` we don't have
112-
# a ``setup_env`` so we use just ``None`` and commands won't
113-
# be recorded
114-
getattr(self, 'setup_env', None),
114+
version=self.version.slug,
115+
environment=environment,
115116
verbose_name=self.version.verbose_name,
116117
version_type=self.version.type
117118
)
118119
return version_repo
119120

120-
def sync_repo(self):
121+
def sync_repo(self, environment):
121122
"""Update the project's repository and hit ``sync_versions`` API."""
122123
# Make Dirs
123124
if not os.path.exists(self.project.doc_path):
@@ -143,7 +144,7 @@ def sync_repo(self):
143144
'msg': msg,
144145
}
145146
)
146-
version_repo = self.get_vcs_repo()
147+
version_repo = self.get_vcs_repo(environment)
147148
version_repo.update()
148149
self.sync_versions(version_repo)
149150
identifier = getattr(self, 'commit', None) or self.version.identifier
@@ -238,9 +239,18 @@ def run(self, version_pk): # pylint: disable=arguments-differ
238239
try:
239240
self.version = self.get_version(version_pk)
240241
self.project = self.version.project
241-
before_vcs.send(sender=self.version)
242+
243+
environment = LocalBuildEnvironment(
244+
project=self.project,
245+
version=self.version,
246+
build=self.build,
247+
record=False,
248+
update_on_success=False,
249+
)
250+
251+
before_vcs.send(sender=self.version, environment=environment)
242252
with self.project.repo_nonblockinglock(version=self.version):
243-
self.sync_repo()
253+
self.sync_repo(environment)
244254
return True
245255
except RepositoryError:
246256
# Do not log as ERROR handled exceptions
@@ -343,6 +353,7 @@ def __init__(
343353
if config is not None:
344354
self.config = config
345355
self.task = task
356+
# TODO: remove this
346357
self.setup_env = None
347358

348359
# pylint: disable=arguments-differ
@@ -437,23 +448,28 @@ def run_setup(self, record=True):
437448
438449
Return True if successful.
439450
"""
440-
self.setup_env = LocalBuildEnvironment(
451+
environment = LocalBuildEnvironment(
441452
project=self.project,
442453
version=self.version,
443454
build=self.build,
444455
record=record,
445456
update_on_success=False,
446457
)
447458

459+
# TODO: Remove.
460+
# There is code that still depends of this attribute
461+
# outside this function. Don't use self.setup_env for new code.
462+
self.setup_env = environment
463+
448464
# Environment used for code checkout & initial configuration reading
449-
with self.setup_env:
465+
with environment:
450466
try:
451-
before_vcs.send(sender=self.version)
467+
before_vcs.send(sender=self.version, environment=environment)
452468
if self.project.skip:
453469
raise ProjectBuildsSkippedError
454470
try:
455471
with self.project.repo_nonblockinglock(version=self.version):
456-
self.setup_vcs()
472+
self.setup_vcs(environment)
457473
except vcs_support_utils.LockTimeout as e:
458474
self.task.retry(exc=e, throw=False)
459475
raise VersionLockedError
@@ -467,13 +483,13 @@ def run_setup(self, record=True):
467483
)
468484

469485
self.save_build_config()
470-
self.additional_vcs_operations()
486+
self.additional_vcs_operations(environment)
471487
finally:
472488
after_vcs.send(sender=self.version)
473489

474-
if self.setup_env.failure or self.config is None:
490+
if environment.failure or self.config is None:
475491
msg = 'Failing build because of setup failure: {}'.format(
476-
self.setup_env.failure,
492+
environment.failure,
477493
)
478494
log.info(
479495
LOG_TEMPLATE,
@@ -488,23 +504,23 @@ def run_setup(self, record=True):
488504
# of VersionLockedError: this exception occurs when a build is
489505
# triggered before the previous one has finished (e.g. two webhooks,
490506
# one after the other)
491-
if not isinstance(self.setup_env.failure, VersionLockedError):
507+
if not isinstance(environment.failure, VersionLockedError):
492508
self.send_notifications(self.version.pk, self.build['id'], email=True)
493509

494510
return False
495511

496-
if self.setup_env.successful and not self.project.has_valid_clone:
512+
if environment.successful and not self.project.has_valid_clone:
497513
self.set_valid_clone()
498514

499515
return True
500516

501-
def additional_vcs_operations(self):
517+
def additional_vcs_operations(self, environment):
502518
"""
503519
Execution of tasks that involve the project's VCS.
504520
505521
All this tasks have access to the configuration object.
506522
"""
507-
version_repo = self.get_vcs_repo()
523+
version_repo = self.get_vcs_repo(environment)
508524
if version_repo.supports_submodules:
509525
version_repo.update_submodules(self.config)
510526

@@ -553,6 +569,10 @@ def run_build(self, docker, record):
553569
)
554570

555571
try:
572+
before_build.send(
573+
sender=self.version,
574+
environment=self.build_env,
575+
)
556576
with self.project.repo_nonblockinglock(version=self.version):
557577
self.setup_python_environment()
558578

@@ -660,13 +680,13 @@ def get_build(build_pk):
660680
for key, val in build.items() if key not in private_keys
661681
}
662682

663-
def setup_vcs(self):
683+
def setup_vcs(self, environment):
664684
"""
665685
Update the checkout of the repo to make sure it's the latest.
666686
667687
This also syncs versions in the DB.
668688
"""
669-
self.setup_env.update_build(state=BUILD_STATE_CLONING)
689+
environment.update_build(state=BUILD_STATE_CLONING)
670690

671691
log.info(
672692
LOG_TEMPLATE,
@@ -677,7 +697,7 @@ def setup_vcs(self):
677697
}
678698
)
679699
try:
680-
self.sync_repo()
700+
self.sync_repo(environment)
681701
except RepositoryError:
682702
log.warning('There was an error with the repository', exc_info=True)
683703
# Re raise the exception to stop the build at this point
@@ -988,7 +1008,6 @@ def build_docs(self):
9881008
:rtype: dict
9891009
"""
9901010
self.build_env.update_build(state=BUILD_STATE_BUILDING)
991-
before_build.send(sender=self.version)
9921011

9931012
outcomes = defaultdict(lambda: False)
9941013
outcomes['html'] = self.build_docs_html()

readthedocs/rtd_tests/tests/test_celery.py

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,23 @@
33
from os.path import exists
44
from tempfile import mkdtemp
55

6+
from allauth.socialaccount.models import SocialAccount
67
from django.contrib.auth.models import User
78
from django_dynamic_fixture import get
89
from messages_extends.models import Message
910
from mock import MagicMock, patch
1011

11-
from allauth.socialaccount.models import SocialAccount
12-
13-
from readthedocs.builds.constants import LATEST, BUILD_STATUS_SUCCESS, EXTERNAL
14-
from readthedocs.builds.models import Build
12+
from readthedocs.builds.constants import (
13+
BUILD_STATE_TRIGGERED,
14+
BUILD_STATUS_SUCCESS,
15+
EXTERNAL,
16+
LATEST,
17+
)
18+
from readthedocs.builds.models import Build, Version
19+
from readthedocs.doc_builder.environments import LocalBuildEnvironment
1520
from readthedocs.doc_builder.exceptions import VersionLockedError
16-
from readthedocs.projects import tasks
17-
from readthedocs.builds.models import Version
1821
from readthedocs.oauth.models import RemoteRepository
22+
from readthedocs.projects import tasks
1923
from readthedocs.projects.exceptions import RepositoryError
2024
from readthedocs.projects.models import Project
2125
from readthedocs.rtd_tests.base import RTDTestCase
@@ -51,6 +55,22 @@ def setUp(self):
5155
)
5256
self.project.users.add(self.eric)
5357

58+
def get_update_docs_task(self, version):
59+
build_env = LocalBuildEnvironment(
60+
version.project, version, record=False,
61+
)
62+
63+
update_docs = tasks.UpdateDocsTaskStep(
64+
build_env=build_env,
65+
project=version.project,
66+
version=version,
67+
build={
68+
'id': 99,
69+
'state': BUILD_STATE_TRIGGERED,
70+
},
71+
)
72+
return update_docs
73+
5474
def tearDown(self):
5575
shutil.rmtree(self.repo)
5676
super().tearDown()
@@ -236,18 +256,16 @@ def test_check_duplicate_reserved_version_latest(self, checkout_path, api_v2):
236256
checkout_path.return_value = local_repo
237257

238258
version = self.project.versions.get(slug=LATEST)
239-
sync_repository = tasks.UpdateDocsTaskStep()
240-
sync_repository.version = version
241-
sync_repository.project = self.project
259+
sync_repository = self.get_update_docs_task(version)
242260
with self.assertRaises(RepositoryError) as e:
243-
sync_repository.sync_repo()
261+
sync_repository.sync_repo(sync_repository.build_env)
244262
self.assertEqual(
245263
str(e.exception),
246264
RepositoryError.DUPLICATED_RESERVED_VERSIONS,
247265
)
248266

249267
delete_git_branch(self.repo, 'latest')
250-
sync_repository.sync_repo()
268+
sync_repository.sync_repo(sync_repository.build_env)
251269
api_v2.project().sync_versions.post.assert_called()
252270

253271
@patch('readthedocs.projects.tasks.api_v2')
@@ -262,11 +280,9 @@ def test_check_duplicate_reserved_version_stable(self, checkout_path, api_v2):
262280
checkout_path.return_value = local_repo
263281

264282
version = self.project.versions.get(slug=LATEST)
265-
sync_repository = tasks.UpdateDocsTaskStep()
266-
sync_repository.version = version
267-
sync_repository.project = self.project
283+
sync_repository = self.get_update_docs_task(version)
268284
with self.assertRaises(RepositoryError) as e:
269-
sync_repository.sync_repo()
285+
sync_repository.sync_repo(sync_repository.build_env)
270286
self.assertEqual(
271287
str(e.exception),
272288
RepositoryError.DUPLICATED_RESERVED_VERSIONS,
@@ -281,11 +297,10 @@ def test_check_duplicate_no_reserved_version(self, api_v2):
281297
create_git_tag(self.repo, 'no-reserved')
282298

283299
version = self.project.versions.get(slug=LATEST)
284-
sync_repository = tasks.UpdateDocsTaskStep()
285-
sync_repository.version = version
286-
sync_repository.project = self.project
287-
sync_repository.sync_repo()
288300

301+
sync_repository = self.get_update_docs_task(version)
302+
303+
sync_repository.sync_repo(sync_repository.build_env)
289304
api_v2.project().sync_versions.post.assert_called()
290305

291306
def test_public_task_exception(self):

readthedocs/rtd_tests/tests/test_config_integration.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from django_dynamic_fixture import get
99
from mock import MagicMock, PropertyMock, patch
1010

11-
from readthedocs.builds.constants import EXTERNAL, BUILD_STATE_TRIGGERED
11+
from readthedocs.builds.constants import BUILD_STATE_TRIGGERED, EXTERNAL
1212
from readthedocs.builds.models import Version
1313
from readthedocs.config import (
1414
ALL,
@@ -20,12 +20,12 @@
2020
from readthedocs.config.models import PythonInstallRequirements
2121
from readthedocs.config.tests.utils import apply_fs
2222
from readthedocs.doc_builder.config import load_yaml_config
23+
from readthedocs.doc_builder.constants import DOCKER_IMAGE_SETTINGS
2324
from readthedocs.doc_builder.environments import LocalBuildEnvironment
2425
from readthedocs.doc_builder.python_environments import Conda, Virtualenv
2526
from readthedocs.projects import tasks
2627
from readthedocs.projects.models import Project
2728
from readthedocs.rtd_tests.utils import create_git_submodule, make_git_repo
28-
from readthedocs.doc_builder.constants import DOCKER_IMAGE_SETTINGS
2929

3030

3131
def create_load(config=None):
@@ -1062,7 +1062,7 @@ def test_submodules_include(
10621062

10631063
update_docs = self.get_update_docs_task()
10641064
checkout_path.return_value = git_repo
1065-
update_docs.additional_vcs_operations()
1065+
update_docs.additional_vcs_operations(update_docs.build_env)
10661066

10671067
args, kwargs = checkout_submodules.call_args
10681068
assert set(args[0]) == set(expected)
@@ -1091,7 +1091,7 @@ def test_submodules_exclude(
10911091

10921092
update_docs = self.get_update_docs_task()
10931093
checkout_path.return_value = git_repo
1094-
update_docs.additional_vcs_operations()
1094+
update_docs.additional_vcs_operations(update_docs.build_env)
10951095

10961096
args, kwargs = checkout_submodules.call_args
10971097
assert set(args[0]) == {'two', 'three'}
@@ -1120,7 +1120,7 @@ def test_submodules_exclude_all(
11201120

11211121
update_docs = self.get_update_docs_task()
11221122
checkout_path.return_value = git_repo
1123-
update_docs.additional_vcs_operations()
1123+
update_docs.additional_vcs_operations(update_docs.build_env)
11241124

11251125
checkout_submodules.assert_not_called()
11261126

@@ -1143,6 +1143,6 @@ def test_submodules_default_exclude_all(
11431143

11441144
update_docs = self.get_update_docs_task()
11451145
checkout_path.return_value = git_repo
1146-
update_docs.additional_vcs_operations()
1146+
update_docs.additional_vcs_operations(update_docs.build_env)
11471147

11481148
checkout_submodules.assert_not_called()

0 commit comments

Comments
 (0)