Beispiel #1
0
    def run_setup(self, record=True):
        """
        Run setup in the local environment.

        Return True if successful.
        """
        self.setup_env = LocalBuildEnvironment(
            project=self.project,
            version=self.version,
            build=self.build,
            record=record,
            update_on_success=False,
        )

        # Environment used for code checkout & initial configuration reading
        with self.setup_env:
            if self.project.skip:
                raise ProjectBuildsSkippedError
            try:
                self.setup_vcs()
            except vcs_support_utils.LockTimeout as e:
                self.task.retry(exc=e, throw=False)
                raise VersionLockedError
            try:
                self.config = load_yaml_config(version=self.version)
            except ConfigError as e:
                raise YAMLParseError(
                    YAMLParseError.GENERIC_WITH_PARSE_EXCEPTION.format(
                        exception=str(e),
                    ),
                )

            self.save_build_config()
            self.additional_vcs_operations()

        if self.setup_env.failure or self.config is None:
            msg = 'Failing build because of setup failure: {}'.format(
                self.setup_env.failure,
            )
            log.info(
                LOG_TEMPLATE.format(
                    project=self.project.slug,
                    version=self.version.slug,
                    msg=msg,
                ),
            )

            # Send notification to users only if the build didn't fail because
            # of VersionLockedError: this exception occurs when a build is
            # triggered before the previous one has finished (e.g. two webhooks,
            # one after the other)
            if not isinstance(self.setup_env.failure, VersionLockedError):
                self.send_notifications()

            return False

        if self.setup_env.successful and not self.project.has_valid_clone:
            self.set_valid_clone()

        return True
Beispiel #2
0
    def on_failure(self, exc, task_id, args, kwargs, einfo):
        if not hasattr(self.data, 'build'):
            # NOTE: use `self.data.build_id` (passed to the task) instead
            # `self.data.build` (retrieved from the API) because it's not present,
            # probably due the API failed when retrieving it.
            #
            # So, we create the `self.data.build` with the minimum required data.
            self.data.build = {
                'id': self.data.build_pk,
            }

        # TODO: handle this `ConfigError` as a `BuildUserError` in the
        # following block
        if isinstance(exc, ConfigError):
            self.data.build['error'] = str(
                YAMLParseError(
                    YAMLParseError.GENERIC_WITH_PARSE_EXCEPTION.format(
                        exception=str(exc), ), ), )
        # Known errors in our application code (e.g. we couldn't connect to
        # Docker API). Report a generic message to the user.
        elif isinstance(exc, BuildAppError):
            self.data.build[
                'error'] = BuildAppError.GENERIC_WITH_BUILD_ID.format(
                    build_id=self.data.build['id'], )
        # Known errors in the user's project (e.g. invalid config file, invalid
        # repository, command failed, etc). Report the error back to the user
        # using the `message` attribute from the exception itself. Otherwise,
        # use a generic message.
        elif isinstance(exc, BuildUserError):
            if hasattr(exc, 'message') and exc.message is not None:
                self.data.build['error'] = exc.message
            else:
                self.data.build['error'] = BuildUserError.GENERIC
        else:
            # We don't know what happened in the build. Log the exception and
            # report a generic message to the user.
            log.exception('Build failed with unhandled exception.')
            self.data.build[
                'error'] = BuildAppError.GENERIC_WITH_BUILD_ID.format(
                    build_id=self.data.build['id'], )

        # Send notifications for unhandled errors
        if not isinstance(exc, self.exceptions_without_notifications):
            self.send_notifications(
                self.data.version.pk,
                self.data.build['id'],
                event=WebHookEvent.BUILD_FAILED,
            )

        # NOTE: why we wouldn't have `self.data.build_commit` here?
        # This attribute is set when we get it after clonning the repository
        #
        # Oh, I think this is to differentiate a task triggered with
        # `Build.commit` than a one triggered just with the `Version` to build
        # the _latest_ commit of it
        if self.data.build_commit:
            send_external_build_status(
                version_type=self.data.version.type,
                build_pk=self.data.build['id'],
                commit=self.data.build_commit,
                status=BUILD_STATUS_FAILURE,
            )

        # Update build object
        self.data.build['success'] = False