Exemple #1
0
    def _run_task(self):
        self.poll_interval_s = int(self.options.get("poll_interval", 10))

        self._poll()  # will block until poll_complete

        self.logger.info("Job is complete.")

        summary = self.summarize_subjobs(self.subjobs)
        failed_batches = self.failed_batches(self.subjobs)
        job_aborted = summary["AnyAborted"]
        job_failed = summary[
            "AnyFailed"]  # note that a failed sub-job is different than a failed batch

        # per https://help.salesforce.com/articleView?id=code_apex_job.htm&type=5
        if job_aborted:
            raise SalesforceException("Job was aborted by a user.")
        elif job_failed:
            raise SalesforceException("Job experienced a system failure.")
        elif failed_batches:
            self.logger.info("There have been some batch failures.")
            raise SalesforceException(
                f"There were batch errors: {repr(failed_batches)}")
        elif not summary["CountsAddUp"]:
            self.logger.info("The final record counts do not add up.")
            self.logger.info("This is probably related to W-1132237")
            self.logger.info(repr(summary))

        if len(self.subjobs) > 1:
            subjob_summary = f" in {len(self.subjobs)} sub-jobs"
        else:
            subjob_summary = ""

        self.logger.info(
            f"{self.options['class_name']} took {summary['ElapsedTime']} seconds to process {summary['TotalJobItems']} batches{subjob_summary}."
        )
Exemple #2
0
    def _poll_action(self):
        # get batch status

        if not self.original_created_date:
            query_results = self.tooling.query(
                self._batch_query(date_limit=None))
            if not query_results["records"]:
                raise SalesforceException(
                    f"No {self.options['class_name']} job found.")
            self.original_created_date = parse_api_datetime(
                query_results["records"][0]["CreatedDate"])
        else:
            query_results = self.tooling.query(
                self._batch_query(date_limit=self.original_created_date))

        self.subjobs = query_results["records"]
        current_subjob = self.subjobs[0]

        summary = self.summarize_subjobs(self.subjobs)

        if len(self.subjobs) > 1:
            subjob_info = f" in {len(self.subjobs)} sub-jobs."
        else:
            subjob_info = ""

        self.logger.info(
            f"{self.options['class_name']}: "
            f"Job: {current_subjob['Id']} "
            f"{summary['JobItemsProcessed']} of {summary['TotalJobItems']} "
            f"({summary['NumberOfErrors']} failures)" + subjob_info)

        self.poll_complete = summary["Completed"]
    def _run_task(self):
        self.logger.info('Creating community "{}"'.format(
            self.options["name"]))

        # Before we can create a Community, we have to click through the "New Community"
        # button in the All Communities setup page. (This does some unknown behind-the-scenes setup).
        # Let's simulate that without actually using a browser.
        self.logger.info("Preparing org for Communities")
        s = requests.Session()
        s.get(self.org_config.start_url).raise_for_status()
        r = s.get("{}/sites/servlet.SitePrerequisiteServlet".format(
            self.org_config.instance_url))
        if r.status_code != 200:
            raise SalesforceException("Unable to prepare org for Communities")

        payload = {
            "name": self.options["name"],
            "description": self.options.get("description") or "",
            "templateName": self.options["template"],
            "urlPathPrefix": self.options.get("url_path_prefix") or "",
        }

        self.logger.info("Sending request to create Community")
        self.sf.restful("connect/communities",
                        method="POST",
                        data=json.dumps(payload))

        # Wait for the community to be created
        self.time_start = datetime.now()
        self._poll()
Exemple #4
0
    def _poll_action(self):
        elapsed = datetime.now() - self.time_start
        if elapsed.total_seconds() > self.options["timeout"]:
            raise SalesforceException(
                "Community creation not finished after {timeout} seconds".
                format(**self.options))

        community = self._get_community()
        if community is not None:
            self.poll_complete = True
            self.logger.info("Community {} created".format(community["id"]))
    def _process_response(self, result):
        """Handle the compositeResponse and raise an exception if failed."""
        subrequests = result["compositeResponse"]
        status_codes = {subrequest["httpStatusCode"] for subrequest in subrequests}

        all_success = all([self._http_ok(code) for code in status_codes])
        if self.is_all_or_none and not all_success:
            self._log_exception_message(subrequests)
            raise SalesforceException(json.dumps(subrequests, indent=2))
        else:
            self._log_success_message(subrequests)
Exemple #6
0
 def _run_task(self):
     object_handler = getattr(self.sf, self.object)
     rc = object_handler.create(self.values)
     if rc["success"]:
         self.logger.info(f"{self.object} record inserted: {rc['id']}")
     else:
         # this will probably never execute, due to simple_salesforce throwing
         # an exception, but just in case:
         raise SalesforceException(
             f"Could not insert {self.object} record : {rc['errors']}"
         )
    def _poll_action(self):
        elapsed = datetime.now() - self.time_start
        if elapsed.total_seconds() > self.options["timeout"]:
            raise SalesforceException(
                "Community creation not finished after {timeout} seconds".
                format(**self.options))

        community_list = self.sf.restful("connect/communities")["communities"]
        communities = {c["name"]: c for c in community_list}
        if self.options["name"] in communities:
            self.poll_complete = True
            self.logger.info("Community {} created".format(
                communities[self.options["name"]]["id"]))
    def _poll_action(self, ):
        soql_check_upload = "select Id, Status, Errors, MetadataPackageVersionId from PackageUploadRequest where Id = '{}'".format(
            self.upload_id)

        uploadresult = self.tooling.query(soql_check_upload)
        if uploadresult['totalSize'] != 1:
            message = 'Failed to get info for upload with id {}'.format(
                self.upload_id)
            self.logger.error(message)
            raise SalesforceException(message)

        self.upload = uploadresult['records'][0]
        self.logger.info('PackageUploadRequest {} is {}'.format(
            self.upload_id, self.upload['Status']))

        self.poll_complete = not self._poll_again(self.upload['Status'])
Exemple #9
0
    def _run_task(self):
        self.poll_interval_s = int(self.options.get('poll_interval', 10))

        self._poll() # will block until poll_complete

        self.logger.info('Job is complete.')

        if not self.success:
            self.logger.info('There were some batch failures.')
            raise SalesforceException(self.batch['ExtendedStatus'])

        self.logger.info('%s took %d seconds to process %d batches.',
                         self.batch['ApexClass']['Name'],
                         self.delta,
                         self.batch['TotalJobItems'])

        return self.success
Exemple #10
0
    def _check_result(self, result):
        # anon_results is an ExecuteAnonymous Result
        # https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/sforce_api_calls_executeanonymous_result.htm
        anon_results = result.json()

        # A result of `None` (body == "null") with a 200 status code
        # means that a gack occurred.
        if anon_results is None:
            raise SalesforceException(
                "Anonymous Apex returned the result `null`. "
                "This often indicates a gack occurred.")
        if not anon_results["compiled"]:
            raise ApexCompilationException(anon_results["line"],
                                           anon_results["compileProblem"])
        if not anon_results["success"]:
            raise ApexException(anon_results["exceptionMessage"],
                                anon_results["exceptionStackTrace"])
Exemple #11
0
    def _run_task(self):
        self.poll_interval_s = int(self.options.get("poll_interval", 10))

        self._poll()  # will block until poll_complete

        self.logger.info("Job is complete.")

        if not self.success:
            self.logger.info("There were some batch failures.")
            raise SalesforceException(self.batch["ExtendedStatus"])

        self.logger.info(
            "%s took %d seconds to process %d batches.",
            self.batch["ApexClass"]["Name"],
            self.delta,
            self.batch["TotalJobItems"],
        )

        return self.success
Exemple #12
0
    def _poll_action(self):
        try:
            query_results = self.sf.query(self._object_query)
        except SalesforceError as e:
            message = e.content[0]["message"]
            if "No such column 'SetupOwnerId'" in message:
                message = "Only Hierarchical Custom Settings objects are supported."
            raise TaskOptionsError(f"Query Error: {message}")

        self.record = None
        for row in query_results["records"]:
            setupOwnerId = str(row["SetupOwnerId"])
            if setupOwnerId.startswith("00D"):
                self.record = row

        if not self.record:
            raise SalesforceException(
                "Hierarchical Custom Settings Org Default record not found")

        self.poll_complete = not self._poll_again()
Exemple #13
0
    def _run_task(self):
        community_id = self.options.get("community_id", None)
        community_name = self.options.get("name", None)

        if community_id is None:
            if community_name is None:
                missing_required = ["name", "community_id"]
                raise TaskOptionsError("{} requires one of options ({}) "
                                       "and no values were provided".format(
                                           self.__class__.__name__,
                                           ", ".join(missing_required)))

            self.logger.info('Finding id for Community "{}"'.format(
                self.options["name"]))
            community_list = self.sf.restful(
                "connect/communities")["communities"]
            communities = {c["name"]: c for c in community_list}

            if self.options["name"] in communities:
                community_id = communities[self.options["name"]]["id"]
            else:
                raise SalesforceException(
                    'Unable to find a Community named "{}"'.format(
                        community_id))

            self.logger.info(
                'Sending request to publish Community "{}" ({})'.format(
                    community_name, community_id))
        else:
            self.logger.info(
                "Sending request to publish Community ({})".format(
                    community_id))

        response = self.sf.restful(
            "connect/communities/{}/publish".format(community_id),
            method="POST")

        self.logger.info(response["message"])
Exemple #14
0
    def _run_task(self):
        self.poll_interval_s = int(self.options.get("poll_interval", 10))

        self._poll()  # will block until poll_complete

        self.logger.info("Job is complete.")

        vals = {
            key: value
            for key, value in self.batch.items() if key in {
                "Id",
                "Status",
                "ExtendedStatus",
                "NumberOfErrors",
                "JobItemsProcessed",
                "TotalJobItems",
            }
        }
        if not self.success:
            self.logger.info("There have been some batch failures.")
            self.logger.info("Error values:")
            self.logger.info(repr(vals))
            raise SalesforceException("There were import errors: %s" %
                                      repr(vals))
        elif not self.done_for_sure:
            self.logger.info("The final record counts do not add up.")
            self.logger.info("This is probably related to W-1132237")
            self.logger.info(repr(vals))

        self.logger.info(
            "%s took %d seconds to process %d batches.",
            self.batch["ApexClass"]["Name"],
            self.delta,
            self.batch["TotalJobItems"],
        )

        return self.success
Exemple #15
0
 def _get_one_record(self, query, message):
     result = self.tooling.query(query)
     if result["totalSize"] != 1:
         self.logger.error(message)
         raise SalesforceException(message)
     return result["records"][0]
    def _run_task(self):
        package_res = self.tooling.query(
            "select Id from MetadataPackage where NamespacePrefix='{}'".format(
                self.options['namespace']))

        if package_res['totalSize'] != 1:
            message = 'No package found with namespace {}'.format(
                self.options['namespace'])
            self.logger.error(message)
            raise SalesforceException(message)

        package_id = package_res['records'][0]['Id']

        production = self.options.get('production',
                                      False) in [True, 'True', 'true']
        package_info = {
            'VersionName': self.options['name'],
            'IsReleaseVersion': production,
            'MetadataPackageId': package_id,
        }

        if 'description' in self.options:
            package_info['Description'] = self.options['description']
        if 'password' in self.options:
            package_info['Password'] = self.options['password']
        if 'post_install_url' in self.options:
            package_info['PostInstallUrl'] = self.options['post_install_url']
        if 'release_notes_url' in self.options:
            package_info['ReleaseNotesUrl'] = self.options['release_notes_url']

        PackageUploadRequest = self._get_tooling_object('PackageUploadRequest')
        self.upload = PackageUploadRequest.create(package_info)
        self.upload_id = self.upload['id']

        self.logger.info(
            'Created PackageUploadRequest {} for Package {}'.format(
                self.upload_id, package_id))
        self._poll()

        if self.upload['Status'] == 'ERROR':
            self.logger.error(
                'Package upload failed with the following errors')
            for error in self.upload['Errors']['errors']:
                self.logger.error('  {}'.format(error['message']))

            # use the last error in the batch, but log them all.
            if error['message'] == 'ApexTestFailure':
                e = ApexTestException
            else:
                e = SalesforceException
            raise e('Package upload failed')
        else:
            version_id = self.upload['MetadataPackageVersionId']
            version_res = self.tooling.query(
                "select MajorVersion, MinorVersion, PatchVersion, BuildNumber, ReleaseState from MetadataPackageVersion where Id = '{}'"
                .format(version_id))
            if version_res['totalSize'] != 1:
                message = 'Version {} not found'.format(version_id)
                self.logger.error(message)
                raise SalesforceException(message)

            version = version_res['records'][0]
            version_parts = [
                str(version['MajorVersion']),
                str(version['MinorVersion']),
            ]
            if version['PatchVersion']:
                version_parts.append(str(version['PatchVersion']))

            self.version_number = '.'.join(version_parts)

            if version['ReleaseState'] == 'Beta':
                self.version_number += ' (Beta {})'.format(
                    version['BuildNumber'])

            self.return_values = {
                'version_number': str(self.version_number),
                'version_id': version_id,
                'package_id': package_id
            }

            self.logger.info('Uploaded package version {} with Id {}'.format(
                self.version_number, version_id))
Exemple #17
0
    def _run_task(self):
        package_res = self.tooling.query(
            "select Id from MetadataPackage where NamespacePrefix='{}'".format(
                self.options["namespace"]))

        if package_res["totalSize"] != 1:
            message = "No package found with namespace {}".format(
                self.options["namespace"])
            self.logger.error(message)
            raise SalesforceException(message)

        package_id = package_res["records"][0]["Id"]

        production = self.options.get("production",
                                      False) in [True, "True", "true"]
        package_info = {
            "VersionName": self.options["name"],
            "IsReleaseVersion": production,
            "MetadataPackageId": package_id,
        }

        if "description" in self.options:
            package_info["Description"] = self.options["description"]
        if "password" in self.options:
            package_info["Password"] = self.options["password"]
        if "post_install_url" in self.options:
            package_info["PostInstallUrl"] = self.options["post_install_url"]
        if "release_notes_url" in self.options:
            package_info["ReleaseNotesUrl"] = self.options["release_notes_url"]

        PackageUploadRequest = self._get_tooling_object("PackageUploadRequest")
        self.upload = PackageUploadRequest.create(package_info)
        self.upload_id = self.upload["id"]

        self.logger.info(
            "Created PackageUploadRequest {} for Package {}".format(
                self.upload_id, package_id))
        self._poll()

        if self.upload["Status"] == "ERROR":
            self.logger.error(
                "Package upload failed with the following errors")
            for error in self.upload["Errors"]["errors"]:
                self.logger.error("  {}".format(error["message"]))

            # use the last error in the batch, but log them all.
            if error["message"] == "ApexTestFailure":
                e = ApexTestException
            else:
                e = SalesforceException
            raise e("Package upload failed")
        else:
            version_id = self.upload["MetadataPackageVersionId"]
            version_res = self.tooling.query(
                "select MajorVersion, MinorVersion, PatchVersion, BuildNumber, ReleaseState from MetadataPackageVersion where Id = '{}'"
                .format(version_id))
            if version_res["totalSize"] != 1:
                message = "Version {} not found".format(version_id)
                self.logger.error(message)
                raise SalesforceException(message)

            version = version_res["records"][0]
            version_parts = [
                str(version["MajorVersion"]),
                str(version["MinorVersion"])
            ]
            if version["PatchVersion"]:
                version_parts.append(str(version["PatchVersion"]))

            self.version_number = ".".join(version_parts)

            if version["ReleaseState"] == "Beta":
                self.version_number += " (Beta {})".format(
                    version["BuildNumber"])

            self.return_values = {
                "version_number": str(self.version_number),
                "version_id": version_id,
                "package_id": package_id,
            }

            self.logger.info("Uploaded package version {} with Id {}".format(
                self.version_number, version_id))