diff --git a/readthedocs/config/tests/test_config.py b/readthedocs/config/tests/test_config.py index 9850b9c79f2..0b341376d86 100644 --- a/readthedocs/config/tests/test_config.py +++ b/readthedocs/config/tests/test_config.py @@ -1,11 +1,11 @@ import os -from django.conf import settings import re import textwrap from collections import OrderedDict from unittest.mock import DEFAULT, patch import pytest +from django.conf import settings from pytest import raises from readthedocs.config import ( @@ -33,6 +33,7 @@ ) from readthedocs.config.models import ( Build, + BuildJobs, BuildWithTools, Conda, PythonInstall, @@ -1012,6 +1013,87 @@ def test_new_build_config_conflict_with_build_python_version(self): build.validate() assert excinfo.value.key == 'python.version' + @pytest.mark.parametrize("value", ["", None, "pre_invalid"]) + def test_jobs_build_config_invalid_jobs(self, value): + build = self.get_build_config( + { + "build": { + "os": "ubuntu-20.04", + "tools": {"python": "3.8"}, + "jobs": {value: ["echo 1234", "git fetch --unshallow"]}, + }, + }, + ) + with raises(InvalidConfig) as excinfo: + build.validate() + assert excinfo.value.key == "build.jobs" + + @pytest.mark.parametrize("value", ["", None, "echo 123", 42]) + def test_jobs_build_config_invalid_job_commands(self, value): + build = self.get_build_config( + { + "build": { + "os": "ubuntu-20.04", + "tools": {"python": "3.8"}, + "jobs": { + "pre_install": value, + }, + }, + }, + ) + with raises(InvalidConfig) as excinfo: + build.validate() + assert excinfo.value.key == "build.jobs.pre_install" + + def test_jobs_build_config(self): + build = self.get_build_config( + { + "build": { + "os": "ubuntu-20.04", + "tools": {"python": "3.8"}, + "jobs": { + "pre_checkout": ["echo pre_checkout"], + "post_checkout": ["echo post_checkout"], + "pre_system_dependencies": ["echo pre_system_dependencies"], + "post_system_dependencies": ["echo post_system_dependencies"], + "pre_create_environment": ["echo pre_create_environment"], + "post_create_environment": ["echo post_create_environment"], + "pre_install": ["echo pre_install", "echo `date`"], + "post_install": ["echo post_install"], + "pre_build": [ + "echo pre_build", + 'sed -i -e "s|{VERSION}|${READTHEDOCS_VERSION_NAME}|g"', + ], + "post_build": ["echo post_build"], + }, + }, + }, + ) + build.validate() + assert isinstance(build.build, BuildWithTools) + assert isinstance(build.build.jobs, BuildJobs) + assert build.build.jobs.pre_checkout == ["echo pre_checkout"] + assert build.build.jobs.post_checkout == ["echo post_checkout"] + assert build.build.jobs.pre_system_dependencies == [ + "echo pre_system_dependencies" + ] + assert build.build.jobs.post_system_dependencies == [ + "echo post_system_dependencies" + ] + assert build.build.jobs.pre_create_environment == [ + "echo pre_create_environment" + ] + assert build.build.jobs.post_create_environment == [ + "echo post_create_environment" + ] + assert build.build.jobs.pre_install == ["echo pre_install", "echo `date`"] + assert build.build.jobs.post_install == ["echo post_install"] + assert build.build.jobs.pre_build == [ + "echo pre_build", + 'sed -i -e "s|{VERSION}|${READTHEDOCS_VERSION_NAME}|g"', + ] + assert build.build.jobs.post_build == ["echo post_build"] + @pytest.mark.parametrize( 'value', [ @@ -2297,6 +2379,18 @@ def test_as_dict_new_build_config(self, tmpdir): 'full_version': settings.RTD_DOCKER_BUILD_SETTINGS['tools']['nodejs']['16'], }, }, + "jobs": { + "pre_checkout": [], + "post_checkout": [], + "pre_system_dependencies": [], + "post_system_dependencies": [], + "pre_create_environment": [], + "post_create_environment": [], + "pre_install": [], + "post_install": [], + "pre_build": [], + "post_build": [], + }, 'apt_packages': [], }, 'conda': None, diff --git a/readthedocs/projects/tests/test_build_tasks.py b/readthedocs/projects/tests/test_build_tasks.py index 81c9def784b..385d77c7d91 100644 --- a/readthedocs/projects/tests/test_build_tasks.py +++ b/readthedocs/projects/tests/test_build_tasks.py @@ -732,6 +732,46 @@ def test_build_tools(self, load_yaml_config): ] ) + @mock.patch("readthedocs.doc_builder.director.load_yaml_config") + def test_build_jobs(self, load_yaml_config): + config = BuildConfigV2( + {}, + { + "version": 2, + "build": { + "os": "ubuntu-20.04", + "tools": {"python": "3.7"}, + "jobs": { + "post_checkout": ["git fetch --unshallow"], + "pre_build": ["echo `date`"], + }, + }, + }, + source_file="readthedocs.yml", + ) + config.validate() + load_yaml_config.return_value = config + + self._trigger_update_docs_task() + + self.mocker.mocks["environment.run"].assert_has_calls( + [ + mock.call( + "git", "fetch", "--unshallow", escape_command=False, cwd=mock.ANY + ), + # Don't care about the intermediate commands. They are checked + # in other tests + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.ANY, + mock.call("echo", "`date`", escape_command=False, cwd=mock.ANY), + ] + ) + @mock.patch("readthedocs.doc_builder.python_environments.tarfile") @mock.patch("readthedocs.doc_builder.python_environments.build_tools_storage") @mock.patch("readthedocs.doc_builder.director.load_yaml_config")