Esempio n. 1
0
 def save_build_config(self):
     """Save config in the build object."""
     pk = self.build['id']
     config = self.config.as_dict()
     api_v2.build(pk).patch({
         'config': config,
     })
     self.build['config'] = config
Esempio n. 2
0
    def update_build(self, state=None):
        """Record a build by hitting the API

        This step is skipped if we aren't recording the build, or if we don't
        want to record successful builds yet (if we are running setup commands
        for the build)
        """
        if not self.record:
            return None

        self.build['project'] = self.project.pk
        self.build['version'] = self.version.pk
        self.build['builder'] = socket.gethostname()
        self.build['state'] = state
        if self.done:
            self.build['success'] = self.successful

            # TODO drop exit_code and provide a more meaningful UX for error
            # reporting
            if self.failure and isinstance(self.failure,
                                           BuildEnvironmentException):
                self.build['exit_code'] = self.failure.status_code
            elif self.commands:
                self.build['exit_code'] = max(
                    [cmd.exit_code for cmd in self.commands])

        self.build['setup'] = self.build['setup_error'] = ""
        self.build['output'] = self.build['error'] = ""

        if self.start_time:
            build_length = (datetime.utcnow() - self.start_time)
            self.build['length'] = int(build_length.total_seconds())

        if self.failure is not None:
            # Only surface the error message if it was a
            # BuildEnvironmentException or BuildEnvironmentWarning
            if isinstance(
                    self.failure,
                (BuildEnvironmentException, BuildEnvironmentWarning)):
                self.build['error'] = str(self.failure)
            else:
                self.build['error'] = ugettext_noop(
                    "An unexpected error occurred")

        # Attempt to stop unicode errors on build reporting
        for key, val in list(self.build.items()):
            if isinstance(val, six.binary_type):
                self.build[key] = val.decode('utf-8', 'ignore')

        try:
            api_v2.build(self.build['id']).put(self.build)
        except HttpClientError as e:
            log.error("Unable to post a new build: %s", e.content)
        except Exception:
            log.error("Unknown build exception", exc_info=True)
    def update_build(self, state=None):
        """Record a build by hitting the API

        This step is skipped if we aren't recording the build, or if we don't
        want to record successful builds yet (if we are running setup commands
        for the build)
        """
        if not self.record:
            return None

        self.build['project'] = self.project.pk
        self.build['version'] = self.version.pk
        self.build['builder'] = socket.gethostname()
        self.build['state'] = state
        if self.done:
            self.build['success'] = self.successful

            # TODO drop exit_code and provide a more meaningful UX for error
            # reporting
            if self.failure and isinstance(self.failure,
                                           BuildEnvironmentException):
                self.build['exit_code'] = self.failure.status_code
            elif self.commands:
                self.build['exit_code'] = max([cmd.exit_code
                                               for cmd in self.commands])

        self.build['setup'] = self.build['setup_error'] = ""
        self.build['output'] = self.build['error'] = ""

        if self.start_time:
            build_length = (datetime.utcnow() - self.start_time)
            self.build['length'] = int(build_length.total_seconds())

        if self.failure is not None:
            # Only surface the error message if it was a
            # BuildEnvironmentException or BuildEnvironmentWarning
            if isinstance(self.failure,
                          (BuildEnvironmentException, BuildEnvironmentWarning)):
                self.build['error'] = str(self.failure)
            else:
                self.build['error'] = ugettext_noop(
                    "An unexpected error occurred")

        # Attempt to stop unicode errors on build reporting
        for key, val in list(self.build.items()):
            if isinstance(val, six.binary_type):
                self.build[key] = val.decode('utf-8', 'ignore')

        try:
            api_v2.build(self.build['id']).put(self.build)
        except HttpClientError as e:
            log.error("Unable to post a new build: %s", e.content)
        except Exception:
            log.error("Unknown build exception", exc_info=True)
Esempio n. 4
0
    def get_build(build_pk):
        """
        Retrieve build object from API

        :param build_pk: Build primary key
        """
        build = {}
        if build_pk:
            build = api_v2.build(build_pk).get()
        return dict((key, val) for (key, val) in build.items() if key not in
                    ['project', 'version', 'resource_uri', 'absolute_uri'])
Esempio n. 5
0
    def get_build(build_pk):
        """
        Retrieve build object from API

        :param build_pk: Build primary key
        """
        build = {}
        if build_pk:
            build = api_v2.build(build_pk).get()
        return dict((key, val) for (key, val) in build.items()
                    if key not in ['project', 'version', 'resource_uri',
                                   'absolute_uri'])
Esempio n. 6
0
    def run(self,
            pk,
            version_pk=None,
            build_pk=None,
            record=True,
            docker=False,
            search=True,
            force=False,
            localmedia=True,
            **__):
        """
        Run a documentation build.

        This is fully wrapped in exception handling to account for a number of failure cases.
        """
        try:
            self.project = self.get_project(pk)
            self.version = self.get_version(self.project, version_pk)
            self.build = self.get_build(build_pk)
            self.build_search = search
            self.build_localmedia = localmedia
            self.build_force = force
            self.config = None

            setup_successful = self.run_setup(record=record)
            if setup_successful:
                self.run_build(record=record, docker=docker)
            failure = self.setup_env.failure or self.build_env.failure
        except Exception as e:  # noqa
            log.exception(
                'An unhandled exception was raised outside the build environment',
                extra={'tags': {
                    'build': build_pk
                }})
            failure = _(
                'Unknown error encountered. '
                'Please include the build id ({build_id}) in any bug reports.'.
                format(build_id=build_pk))

        # **Always** report build status.
        # This can still fail if the API Is totally down, but should catch more failures
        result = {}
        build_updates = {'state': BUILD_STATE_FINISHED}
        build_data = {}
        if hasattr(self, 'build'):
            build_data.update(self.build)
        if failure:
            build_updates['success'] = False
            build_updates['error'] = failure
        build_data.update(build_updates)
        result = api_v2.build(build_pk).patch(build_updates)
        return result
Esempio n. 7
0
    def update_build(self, state=None):
        """Record a build by hitting the API

        This step is skipped if we aren't recording the build, or if we don't
        want to record successful builds yet (if we are running setup commands
        for the build)
        """
        if not self.record or (state == BUILD_STATE_FINISHED
                               and not self.report_build_success):
            return None

        self.build['project'] = self.project.pk
        self.build['version'] = self.version.pk
        self.build['builder'] = socket.gethostname()
        self.build['state'] = state
        if self.done:
            self.build['success'] = self.successful

            # TODO drop exit_code and provide a more meaningful UX for error
            # reporting
            if self.failure and isinstance(self.failure,
                                           BuildEnvironmentException):
                self.build['exit_code'] = self.failure.status_code
            elif len(self.commands) > 0:
                self.build['exit_code'] = max(
                    [cmd.exit_code for cmd in self.commands])

        self.build['setup'] = self.build['setup_error'] = ""
        self.build['output'] = self.build['error'] = ""

        if self.start_time:
            build_length = (datetime.utcnow() - self.start_time)
            self.build['length'] = build_length.total_seconds()

        if self.failure is not None:
            self.build['error'] = str(self.failure)

        # Attempt to stop unicode errors on build reporting
        for key, val in self.build.items():
            if isinstance(val, basestring):
                self.build[key] = val.decode('utf-8', 'ignore')

        try:
            resp = api_v2.build(self.build['id']).put(self.build)
        except Exception:
            log.error("Unable to post a new build", exc_info=True)
Esempio n. 8
0
    def get_build(build_pk):
        """
        Retrieve build object from API.

        :param build_pk: Build primary key
        """
        build = {}
        if build_pk:
            build = api_v2.build(build_pk).get()
        private_keys = [
            'project', 'version', 'resource_uri', 'absolute_uri',
        ]
        return {
            key: val
            for key, val in build.items()
            if key not in private_keys
        }
Esempio n. 9
0
    def update_build(self, state=None):
        """Record a build by hitting the API

        This step is skipped if we aren't recording the build, or if we don't
        want to record successful builds yet (if we are running setup commands
        for the build)
        """
        if not self.record or (state == BUILD_STATE_FINISHED and
                               not self.report_build_success):
            return None

        self.build['project'] = self.project.pk
        self.build['version'] = self.version.pk
        self.build['builder'] = socket.gethostname()
        self.build['state'] = state
        if self.done:
            self.build['success'] = self.successful

            # TODO drop exit_code and provide a more meaningful UX for error
            # reporting
            if self.failure and isinstance(self.failure,
                                           BuildEnvironmentException):
                self.build['exit_code'] = self.failure.status_code
            elif len(self.commands) > 0:
                self.build['exit_code'] = max([cmd.exit_code
                                               for cmd in self.commands])

        self.build['setup'] = self.build['setup_error'] = ""
        self.build['output'] = self.build['error'] = ""

        if self.start_time:
            build_length = (datetime.utcnow() - self.start_time)
            self.build['length'] = build_length.total_seconds()

        if self.failure is not None:
            self.build['error'] = str(self.failure)

        # Attempt to stop unicode errors on build reporting
        for key, val in self.build.items():
            if isinstance(val, basestring):
                self.build[key] = val.decode('utf-8', 'ignore')

        try:
            resp = api_v2.build(self.build['id']).put(self.build)
        except Exception:
            log.error("Unable to post a new build", exc_info=True)
Esempio n. 10
0
    def run(self, pk, version_pk=None, build_pk=None, record=True,
            docker=False, search=True, force=False, localmedia=True, **__):
        """
        Run a documentation build.

        This is fully wrapped in exception handling to account for a number of failure cases.
        """
        try:
            self.project = self.get_project(pk)
            self.version = self.get_version(self.project, version_pk)
            self.build = self.get_build(build_pk)
            self.build_search = search
            self.build_localmedia = localmedia
            self.build_force = force
            self.config = None

            setup_successful = self.run_setup(record=record)
            if setup_successful:
                self.run_build(record=record, docker=docker)
            failure = self.setup_env.failure or self.build_env.failure
        except Exception as e:  # noqa
            log.exception(
                'An unhandled exception was raised outside the build environment',
                extra={'tags': {'build': build_pk}}
            )
            failure = _('Unknown error encountered. '
                        'Please include the build id ({build_id}) in any bug reports.'.format(
                            build_id=build_pk
                        ))

        # **Always** report build status.
        # This can still fail if the API Is totally down, but should catch more failures
        result = {}
        build_updates = {'state': BUILD_STATE_FINISHED}
        build_data = {}
        if hasattr(self, 'build'):
            build_data.update(self.build)
        if failure:
            build_updates['success'] = False
            build_updates['error'] = failure
        build_data.update(build_updates)
        result = api_v2.build(build_pk).patch(build_updates)
        return result
Esempio n. 11
0
    def update_build(self, state=None):
        """
        Record a build by hitting the API.

        This step is skipped if we aren't recording the build. To avoid
        recording successful builds yet (for instance, running setup commands
        for the build), set the ``update_on_success`` argument to False on
        environment instantiation.

        If there was an error on the build, update the build regardless of
        whether ``update_on_success`` is ``True`` or not.
        """
        if not self.record:
            return None

        self.build['project'] = self.project.pk
        self.build['version'] = self.version.pk
        self.build['builder'] = socket.gethostname()
        self.build['state'] = state
        if self.done:
            self.build['success'] = self.successful

            # TODO drop exit_code and provide a more meaningful UX for error
            # reporting
            if self.failure and isinstance(self.failure,
                                           BuildEnvironmentException):
                self.build['exit_code'] = self.failure.status_code
            elif self.commands:
                self.build['exit_code'] = max(
                    [cmd.exit_code for cmd in self.commands])

        self.build['setup'] = self.build['setup_error'] = ""
        self.build['output'] = self.build['error'] = ""

        if self.start_time:
            build_length = (datetime.utcnow() - self.start_time)
            self.build['length'] = int(build_length.total_seconds())

        if self.failure is not None:
            # Surface a generic error if the class is not a
            # BuildEnvironmentError
            if not isinstance(
                    self.failure,
                (BuildEnvironmentException, BuildEnvironmentWarning)):
                log.error('Build failed with unhandled exception: %s',
                          str(self.failure),
                          extra={
                              'stack': True,
                              'tags': {
                                  'build': self.build['id']
                              },
                          })
                self.failure = BuildEnvironmentError(
                    BuildEnvironmentError.GENERIC_WITH_BUILD_ID.format(
                        build_id=self.build['id'], ))
            self.build['error'] = str(self.failure)

        # Attempt to stop unicode errors on build reporting
        for key, val in list(self.build.items()):
            if isinstance(val, six.binary_type):
                self.build[key] = val.decode('utf-8', 'ignore')

        # We are selective about when we update the build object here
        update_build = (
            # Build isn't done yet, we unconditionally update in this state
            not self.done
            # Build is done, but isn't successful, always update
            or (self.done and not self.successful)
            # Otherwise, are we explicitly to not update?
            or self.update_on_success)
        if update_build:
            try:
                api_v2.build(self.build['id']).put(self.build)
            except HttpClientError as e:
                log.exception(
                    "Unable to update build: id=%d",
                    self.build['id'],
                )
            except Exception:
                log.exception("Unknown build exception")
    def update_build(self, state=None):
        """
        Record a build by hitting the API.

        This step is skipped if we aren't recording the build. To avoid
        recording successful builds yet (for instance, running setup commands
        for the build), set the ``update_on_success`` argument to False on
        environment instantiation.

        If there was an error on the build, update the build regardless of
        whether ``update_on_success`` is ``True`` or not.
        """
        if not self.record:
            return None

        self.build['project'] = self.project.pk
        self.build['version'] = self.version.pk
        self.build['builder'] = socket.gethostname()
        self.build['state'] = state
        if self.done:
            self.build['success'] = self.successful

            # TODO drop exit_code and provide a more meaningful UX for error
            # reporting
            if self.failure and isinstance(self.failure,
                                           BuildEnvironmentException):
                self.build['exit_code'] = self.failure.status_code
            elif self.commands:
                self.build['exit_code'] = max([cmd.exit_code
                                               for cmd in self.commands])

        self.build['setup'] = self.build['setup_error'] = ""
        self.build['output'] = self.build['error'] = ""

        if self.start_time:
            build_length = (datetime.utcnow() - self.start_time)
            self.build['length'] = int(build_length.total_seconds())

        if self.failure is not None:
            # Surface a generic error if the class is not a
            # BuildEnvironmentError
            if not isinstance(self.failure,
                              (BuildEnvironmentException,
                               BuildEnvironmentWarning)):
                log.error(
                    'Build failed with unhandled exception: %s',
                    str(self.failure),
                    extra={
                        'stack': True,
                        'tags': {'build': self.build['id']},
                    }
                )
                self.failure = BuildEnvironmentError(
                    BuildEnvironmentError.GENERIC_WITH_BUILD_ID.format(
                        build_id=self.build['id'],
                    )
                )
            self.build['error'] = str(self.failure)

        # Attempt to stop unicode errors on build reporting
        for key, val in list(self.build.items()):
            if isinstance(val, six.binary_type):
                self.build[key] = val.decode('utf-8', 'ignore')

        # We are selective about when we update the build object here
        update_build = (
            # Build isn't done yet, we unconditionally update in this state
            not self.done
            # Build is done, but isn't successful, always update
            or (self.done and not self.successful)
            # Otherwise, are we explicitly to not update?
            or self.update_on_success
        )
        if update_build:
            try:
                api_v2.build(self.build['id']).put(self.build)
            except HttpClientError as e:
                log.exception(
                    "Unable to update build: id=%d",
                    self.build['id'],
                )
            except Exception:
                log.exception("Unknown build exception")