示例#1
0
    def test_build(self):
        '''Test full build'''
        project = get(Project,
                      slug='project-1',
                      documentation_type='sphinx',
                      conf_py_file='test_conf.py',
                      versions=[fixture()])
        version = project.versions.all()[0]
        self.mocks.configure_mock('api_versions', {'return_value': [version]})
        self.mocks.configure_mock(
            'api', {'get.return_value': {
                'downloads': "no_url_here"
            }})
        self.mocks.patches['html_build'].stop()

        build_env = LocalEnvironment(project=project,
                                     version=version,
                                     build={})
        python_env = Virtualenv(version=version, build_env=build_env)
        yaml_config = get_build_config({})
        config = ConfigWrapper(version=version, yaml_config=yaml_config)
        task = UpdateDocsTask(build_env=build_env,
                              project=project,
                              python_env=python_env,
                              version=version,
                              search=False,
                              localmedia=False,
                              config=config)
        task.build_docs()

        # Get command and check first part of command list is a call to sphinx
        self.assertEqual(self.mocks.popen.call_count, 1)
        cmd = self.mocks.popen.call_args_list[0][0]
        self.assertRegexpMatches(cmd[0][0], r'python')
        self.assertRegexpMatches(cmd[0][1], r'sphinx-build')
示例#2
0
    def test_build_respects_epub_flag(self):
        '''Test build with epub enabled'''
        project = get(Project,
                      slug='project-1',
                      documentation_type='sphinx',
                      conf_py_file='test_conf.py',
                      enable_pdf_build=False,
                      enable_epub_build=True,
                      versions=[fixture()])
        version = project.versions.all()[0]

        build_env = LocalEnvironment(project=project,
                                     version=version,
                                     build={})
        python_env = Virtualenv(version=version, build_env=build_env)
        yaml_config = get_build_config({})
        config = ConfigWrapper(version=version, yaml_config=yaml_config)
        task = UpdateDocsTask(build_env=build_env,
                              project=project,
                              python_env=python_env,
                              version=version,
                              search=False,
                              localmedia=False,
                              config=config)
        task.build_docs()

        # The HTML and the Epub format were built.
        self.mocks.html_build.assert_called_once_with()
        self.mocks.epub_build.assert_called_once_with()
        # PDF however was disabled and therefore not built.
        self.assertFalse(self.mocks.pdf_build.called)
示例#3
0
    def test_build(self):
        '''Test full build'''
        project = get(Project,
                      slug='project-1',
                      documentation_type='sphinx',
                      conf_py_file='test_conf.py',
                      versions=[fixture()])
        version = project.versions.all()[0]
        self.mocks.configure_mock('api_versions', {'return_value': [version]})
        self.mocks.configure_mock('api', {
            'get.return_value': {'downloads': "no_url_here"}
        })
        self.mocks.patches['html_build'].stop()

        build_env = LocalEnvironment(project=project, version=version, build={})
        python_env = Virtualenv(version=version, build_env=build_env)
        config = ConfigWrapper(version=version, yaml_config=create_load()()[0])
        task = UpdateDocsTask(build_env=build_env, project=project, python_env=python_env,
                              version=version, search=False, localmedia=False, config=config)
        task.build_docs()

        # Get command and check first part of command list is a call to sphinx
        self.assertEqual(self.mocks.popen.call_count, 3)
        cmd = self.mocks.popen.call_args_list[2][0]
        self.assertRegexpMatches(cmd[0][0], r'python')
        self.assertRegexpMatches(cmd[0][1], r'sphinx-build')
示例#4
0
    def test_build_respects_pdf_flag(self):
        '''Build output format control'''
        project = get(Project,
                      slug='project-1',
                      documentation_type='sphinx',
                      conf_py_file='test_conf.py',
                      enable_pdf_build=True,
                      enable_epub_build=False,
                      versions=[fixture()])
        version = project.versions.all()[0]

        build_env = LocalEnvironment(project=project,
                                     version=version,
                                     build={})
        task = UpdateDocsTask(build_env=build_env,
                              version=version,
                              project=project,
                              search=False,
                              localmedia=False)
        built_docs = task.build_docs()

        # The HTML and the Epub format were built.
        self.mocks.html_build.assert_called_once_with()
        self.mocks.pdf_build.assert_called_once_with()
        # PDF however was disabled and therefore not built.
        self.assertFalse(self.mocks.epub_build.called)
示例#5
0
    def test_build_respects_yaml(self):
        '''Test YAML build options'''
        project = get(Project,
                      slug='project-1',
                      documentation_type='sphinx',
                      conf_py_file='test_conf.py',
                      enable_pdf_build=False,
                      enable_epub_build=False,
                      versions=[fixture()])
        version = project.versions.all()[0]

        build_env = LocalEnvironment(project=project, version=version, build={})
        python_env = Virtualenv(version=version, build_env=build_env)
        config = ConfigWrapper(version=version, yaml_config=create_load({
            'formats': ['epub']
        })()[0])
        task = UpdateDocsTask(build_env=build_env, project=project, python_env=python_env,
                              version=version, search=False, localmedia=False, config=config)
        task.build_docs()

        # The HTML and the Epub format were built.
        self.mocks.html_build.assert_called_once_with()
        self.mocks.epub_build.assert_called_once_with()
        # PDF however was disabled and therefore not built.
        self.assertFalse(self.mocks.pdf_build.called)
示例#6
0
def trigger_build(project,
                  version=None,
                  record=True,
                  force=False,
                  basic=False):
    """Trigger build for project and version

    If project has a ``build_queue``, execute task on this build queue. Queue
    will be prefixed with ``build-`` to unify build queue names.
    """
    # Avoid circular import
    from readthedocs.projects.tasks import UpdateDocsTask
    from readthedocs.builds.models import Build

    if project.skip:
        return None

    if not version:
        version = project.versions.get(slug=LATEST)

    kwargs = dict(
        pk=project.pk,
        version_pk=version.pk,
        record=record,
        force=force,
        basic=basic,
    )

    build = None
    if record:
        build = Build.objects.create(
            project=project,
            version=version,
            type='html',
            state='triggered',
            success=True,
        )
        kwargs['build_pk'] = build.pk

    options = {}
    if project.build_queue:
        options['queue'] = project.build_queue

    # Set per-task time limit
    time_limit = DOCKER_LIMITS['time']
    try:
        if project.container_time_limit:
            time_limit = int(project.container_time_limit)
    except ValueError:
        pass
    # Add 20% overhead to task, to ensure the build can timeout and the task
    # will cleanly finish.
    options['soft_time_limit'] = time_limit
    options['time_limit'] = int(time_limit * 1.2)

    update_docs = UpdateDocsTask()
    update_docs.apply_async(kwargs=kwargs, **options)

    return build
示例#7
0
def trigger_build(project, version=None, record=True, force=False, basic=False):
    """
    Trigger build for project and version.

    If project has a ``build_queue``, execute task on this build queue. Queue
    will be prefixed with ``build-`` to unify build queue names.
    """
    # Avoid circular import
    from readthedocs.projects.tasks import UpdateDocsTask
    from readthedocs.builds.models import Build

    if project.skip:
        return None

    if not version:
        version = project.versions.get(slug=LATEST)

    kwargs = dict(
        pk=project.pk,
        version_pk=version.pk,
        record=record,
        force=force,
        basic=basic,
    )

    build = None
    if record:
        build = Build.objects.create(
            project=project,
            version=version,
            type='html',
            state='triggered',
            success=True,
        )
        kwargs['build_pk'] = build.pk

    options = {}
    if project.build_queue:
        options['queue'] = project.build_queue

    # Set per-task time limit
    time_limit = DOCKER_LIMITS['time']
    try:
        if project.container_time_limit:
            time_limit = int(project.container_time_limit)
    except ValueError:
        pass
    # Add 20% overhead to task, to ensure the build can timeout and the task
    # will cleanly finish.
    options['soft_time_limit'] = time_limit
    options['time_limit'] = int(time_limit * 1.2)

    update_docs = UpdateDocsTask()
    update_docs.apply_async(kwargs=kwargs, **options)

    return build
示例#8
0
    def test_build_pdf_latex_not_failure(self):
        '''Test pass during PDF builds and bad latex failure status code'''
        self.mocks.patches['html_build'].stop()
        self.mocks.patches['pdf_build'].stop()

        project = get(Project,
                      slug='project-2',
                      documentation_type='sphinx',
                      conf_py_file='test_conf.py',
                      enable_pdf_build=True,
                      enable_epub_build=False,
                      versions=[fixture()])
        version = project.versions.all()[0]
        assert project.conf_dir() == '/tmp/rtd'

        build_env = LocalEnvironment(project=project,
                                     version=version,
                                     build={})
        python_env = Virtualenv(version=version, build_env=build_env)
        yaml_config = get_build_config({})
        config = ConfigWrapper(version=version, yaml_config=yaml_config)
        task = UpdateDocsTask(build_env=build_env,
                              project=project,
                              python_env=python_env,
                              version=version,
                              search=False,
                              localmedia=False,
                              config=config)

        # Mock out the separate calls to Popen using an iterable side_effect
        returns = [
            (('', ''), 0),  # sphinx-build html
            (('', ''), 0),  # sphinx-build pdf
            (('Output written on foo.pdf', ''), 1),  # latex
            (('', ''), 0),  # makeindex
            (('', ''), 0),  # latex
        ]
        mock_obj = mock.Mock()
        mock_obj.communicate.side_effect = [
            output for (output, status) in returns
        ]
        type(mock_obj).returncode = mock.PropertyMock(
            side_effect=[status for (output, status) in returns])
        self.mocks.popen.return_value = mock_obj

        with build_env:
            task.build_docs()
        self.assertEqual(self.mocks.popen.call_count, 5)
        self.assertTrue(build_env.successful)
    def test_build_pdf_latex_not_failure(self):
        '''Test pass during PDF builds and bad latex failure status code'''
        if six.PY3:
            import pytest
            pytest.xfail(
                "test_build_pdf_latex_not_failure is known to fail on 3.6")

        self.mocks.patches['html_build'].stop()
        self.mocks.patches['pdf_build'].stop()

        project = get(Project,
                      slug='project-2',
                      documentation_type='sphinx',
                      conf_py_file='test_conf.py',
                      enable_pdf_build=True,
                      enable_epub_build=False,
                      versions=[fixture()])
        version = project.versions.all()[0]
        assert project.conf_dir() == '/tmp/rtd'

        build_env = LocalEnvironment(project=project, version=version, build={})
        python_env = Virtualenv(version=version, build_env=build_env)
        config = ConfigWrapper(version=version, yaml_config=create_load()()[0])
        task = UpdateDocsTask(build_env=build_env, project=project, python_env=python_env,
                              version=version, search=False, localmedia=False, config=config)

        # Mock out the separate calls to Popen using an iterable side_effect
        returns = [
            (('', ''), 0),  # sphinx-build html
            (('', ''), 0),  # sphinx-build pdf
            (('Output written on foo.pdf', ''), 1),  # latex
            (('', ''), 0),  # makeindex
            (('', ''), 0),  # latex
        ]
        mock_obj = mock.Mock()
        mock_obj.communicate.side_effect = [output for (output, status)
                                            in returns]
        type(mock_obj).returncode = mock.PropertyMock(
            side_effect=[status for (output, status) in returns])
        self.mocks.popen.return_value = mock_obj

        with build_env:
            task.build_docs()
        self.assertEqual(self.mocks.popen.call_count, 7)
        self.assertTrue(build_env.successful)
示例#10
0
    def test_build_pdf_latex_failures(self):
        '''Build failure if latex fails'''
        if six.PY3:
            import pytest
            pytest.xfail(
                "test_build_pdf_latex_failures is known to fail on 3.6")

        self.mocks.patches['html_build'].stop()
        self.mocks.patches['pdf_build'].stop()

        project = get(Project,
                      slug='project-1',
                      documentation_type='sphinx',
                      conf_py_file='test_conf.py',
                      enable_pdf_build=True,
                      enable_epub_build=False,
                      versions=[fixture()])
        version = project.versions.all()[0]
        assert project.conf_dir() == '/tmp/rtd'

        build_env = LocalEnvironment(project=project, version=version, build={})
        python_env = Virtualenv(version=version, build_env=build_env)
        config = ConfigWrapper(version=version, yaml_config=create_load()()[0])
        task = UpdateDocsTask(build_env=build_env, project=project, python_env=python_env,
                              version=version, search=False, localmedia=False, config=config)

        # Mock out the separate calls to Popen using an iterable side_effect
        returns = [
            (('', ''), 0),  # sphinx-build html
            (('', ''), 0),  # sphinx-build pdf
            (('', ''), 1),  # latex
            (('', ''), 0),  # makeindex
            (('', ''), 0),  # latex
        ]
        mock_obj = mock.Mock()
        mock_obj.communicate.side_effect = [output for (output, status)
                                            in returns]
        type(mock_obj).returncode = mock.PropertyMock(
            side_effect=[status for (output, status) in returns])
        self.mocks.popen.return_value = mock_obj

        with build_env:
            task.build_docs()
        self.assertEqual(self.mocks.popen.call_count, 7)
        self.assertTrue(build_env.failed)
示例#11
0
    def test_build_pdf_latex_failures(self):
        '''Build failure if latex fails'''
        self.mocks.patches['html_build'].stop()
        self.mocks.patches['pdf_build'].stop()

        project = get(Project,
                      slug='project-1',
                      documentation_type='sphinx',
                      conf_py_file='test_conf.py',
                      enable_pdf_build=True,
                      enable_epub_build=False,
                      versions=[fixture()])
        version = project.versions.all()[0]
        assert project.conf_dir() == '/tmp/rtd'

        build_env = LocalEnvironment(project=project, version=version, build={})
        python_env = Virtualenv(version=version, build_env=build_env)
        yaml_config = get_build_config({})
        config = ConfigWrapper(version=version, yaml_config=yaml_config)
        task = UpdateDocsTask(build_env=build_env, project=project, python_env=python_env,
                              version=version, search=False, localmedia=False, config=config)

        # Mock out the separate calls to Popen using an iterable side_effect
        returns = [
            (('', ''), 0),  # sphinx-build html
            (('', ''), 0),  # sphinx-build pdf
            (('', ''), 1),  # latex
            (('', ''), 0),  # makeindex
            (('', ''), 0),  # latex
        ]
        mock_obj = mock.Mock()
        mock_obj.communicate.side_effect = [output for (output, status)
                                            in returns]
        type(mock_obj).returncode = mock.PropertyMock(
            side_effect=[status for (output, status) in returns])
        self.mocks.popen.return_value = mock_obj

        with build_env:
            task.build_docs()
        self.assertEqual(self.mocks.popen.call_count, 7)
        self.assertTrue(build_env.failed)
示例#12
0
    def test_build_respects_epub_flag(self):
        '''Test build with epub enabled'''
        project = get(Project,
                      slug='project-1',
                      documentation_type='sphinx',
                      conf_py_file='test_conf.py',
                      enable_pdf_build=False,
                      enable_epub_build=True,
                      versions=[fixture()])
        version = project.versions.all()[0]

        build_env = LocalEnvironment(project=project, version=version, build={})
        task = UpdateDocsTask(build_env=build_env, project=project,
                              version=version, search=False, localmedia=False)
        built_docs = task.build_docs()

        # The HTML and the Epub format were built.
        self.mocks.html_build.assert_called_once_with()
        self.mocks.epub_build.assert_called_once_with()
        # PDF however was disabled and therefore not built.
        self.assertFalse(self.mocks.pdf_build.called)
示例#13
0
 def handle(self, *args, **options):
     for version in Version.objects.filter(active=True, built=False):
         update_docs = UpdateDocsTask()
         update_docs.run(version.project_id,
                         record=False,
                         version_pk=version.pk)
示例#14
0
 def handle(self, *args, **options):
     for version in Version.objects.filter(active=True, built=False):
         update_docs = UpdateDocsTask()
         update_docs.run(version.project_id, record=False,
                         version_pk=version.pk)
示例#15
0
def prepare_build(
        project, version=None, record=True, force=False, immutable=True):
    """
    Prepare a build in a Celery task for project and version.

    If project has a ``build_queue``, execute the task on this build queue. If
    project has ``skip=True``, the build is not triggered.

    :param project: project's documentation to be built
    :param version: version of the project to be built. Default: ``latest``
    :param record: whether or not record the build in a new Build object
    :param force: build the HTML documentation even if the files haven't changed
    :param immutable: whether or not create an immutable Celery signature
    :returns: Celery signature of UpdateDocsTask to be executed
    """
    # Avoid circular import
    from readthedocs.projects.tasks import UpdateDocsTask
    from readthedocs.builds.models import Build

    if project.skip:
        log.info(
            'Build not triggered because Project.skip=True: project=%s',
            project.slug,
        )
        return None

    if not version:
        version = project.versions.get(slug=LATEST)

    kwargs = {
        'version_pk': version.pk,
        'record': record,
        'force': force,
    }

    if record:
        build = Build.objects.create(
            project=project,
            version=version,
            type='html',
            state=BUILD_STATE_TRIGGERED,
            success=True,
        )
        kwargs['build_pk'] = build.pk

    options = {}
    if project.build_queue:
        options['queue'] = project.build_queue

    # Set per-task time limit
    time_limit = DOCKER_LIMITS['time']
    try:
        if project.container_time_limit:
            time_limit = int(project.container_time_limit)
    except ValueError:
        log.warning('Invalid time_limit for project: %s', project.slug)

    # Add 20% overhead to task, to ensure the build can timeout and the task
    # will cleanly finish.
    options['soft_time_limit'] = time_limit
    options['time_limit'] = int(time_limit * 1.2)

    update_docs_task = UpdateDocsTask()

    # Py 2.7 doesn't support ``**`` expand syntax twice. We create just one big
    # kwargs (including the options) for this and expand it just once.
    # return update_docs_task.si(project.pk, **kwargs, **options)
    kwargs.update(options)

    return update_docs_task.si(project.pk, **kwargs)
示例#16
0
def prepare_build(
        project, version=None, record=True, force=False, immutable=True):
    """
    Prepare a build in a Celery task for project and version.

    If project has a ``build_queue``, execute the task on this build queue. If
    project has ``skip=True``, the build is not triggered.

    :param project: project's documentation to be built
    :param version: version of the project to be built. Default: ``latest``
    :param record: whether or not record the build in a new Build object
    :param force: build the HTML documentation even if the files haven't changed
    :param immutable: whether or not create an immutable Celery signature
    :returns: Celery signature of UpdateDocsTask to be executed
    """
    # Avoid circular import
    from readthedocs.projects.tasks import UpdateDocsTask
    from readthedocs.builds.models import Build

    if project.skip:
        log.info(
            'Build not triggered because Project.skip=True: project=%s',
            project.slug,
        )
        return None

    if not version:
        version = project.versions.get(slug=LATEST)

    kwargs = {
        'version_pk': version.pk,
        'record': record,
        'force': force,
    }

    if record:
        build = Build.objects.create(
            project=project,
            version=version,
            type='html',
            state=BUILD_STATE_TRIGGERED,
            success=True,
        )
        kwargs['build_pk'] = build.pk

    options = {}
    if project.build_queue:
        options['queue'] = project.build_queue

    # Set per-task time limit
    time_limit = DOCKER_LIMITS['time']
    try:
        if project.container_time_limit:
            time_limit = int(project.container_time_limit)
    except ValueError:
        log.warning('Invalid time_limit for project: %s', project.slug)

    # Add 20% overhead to task, to ensure the build can timeout and the task
    # will cleanly finish.
    options['soft_time_limit'] = time_limit
    options['time_limit'] = int(time_limit * 1.2)

    update_docs_task = UpdateDocsTask()

    # Py 2.7 doesn't support ``**`` expand syntax twice. We create just one big
    # kwargs (including the options) for this and expand it just once.
    # return update_docs_task.si(project.pk, **kwargs, **options)
    kwargs.update(options)

    return update_docs_task.si(project.pk, **kwargs)