def create_build(*, upload_api: UploadAPI) -> bool:
    """
    https://help.veracode.com/reader/LMv_dtSHyb7iIxAQznC~9w/vhuQ5lMdxRNQWUK1br1mDg
    """
    try:
        endpoint = "createbuild.do"
        params = {"app_id": upload_api.app_id, "version": upload_api.build_id}

        # If a sandbox_id is specified, add it to the params
        if isinstance(upload_api.sandbox_id, str):
            params["sandbox_id"] = upload_api.sandbox_id

        # Create the build
        response = upload_api.http_post(endpoint=endpoint, params=params)
        if element_contains_error(parsed_xml=response):
            LOG.error("Veracode returned an error when attempting to call %s",
                      endpoint)
            return False
        return True
    except (
            HTTPError,
            ConnectionError,
            Timeout,
            TooManyRedirects,
            RequestException,
    ):
        LOG.error("Exception encountered when calling the Veracode API")
        return False
def begin_prescan(*, upload_api: UploadAPI) -> bool:
    """
    https://help.veracode.com/reader/LMv_dtSHyb7iIxAQznC~9w/PX5ReM5acqjM~IOVEg2~rA
    """
    endpoint = "beginprescan.do"
    params = {
        "app_id": upload_api.app_id,
        "scan_all_nonfatal_top_level_modules":
        upload_api.scan_all_nonfatal_top_level_modules,
        "auto_scan": upload_api.auto_scan,
    }

    # If a sandbox_id is specified, add it to the params
    if isinstance(upload_api.sandbox_id, str):
        params["sandbox_id"] = upload_api.sandbox_id

    try:
        response = upload_api.http_post(endpoint=endpoint, params=params)
        if element_contains_error(parsed_xml=response):
            LOG.error("Veracode returned an error when attempting to call %s",
                      endpoint)
            return False
        return True
    except (
            HTTPError,
            ConnectionError,
            Timeout,
            TooManyRedirects,
            RequestException,
    ):
        LOG.error("Exception encountered when calling the Veracode API")
        return False
def get_latest_completed_build(
    *, results_api: ResultsAPI, only_latest: Optional[bool] = True
) -> Union[InsecureElementTree.Element, bool]:
    """
    Get the latest completed build build_id for a given app_id
    https://help.veracode.com/reader/LMv_dtSHyb7iIxAQznC~9w/Q8E6r4JDAN1lykB08oGDSA
    """
    endpoint = "getappbuilds.do"
    params = {"only_latest": only_latest}
    try:
        appbuilds = results_api.http_get(endpoint=endpoint, params=params)
        if element_contains_error(parsed_xml=appbuilds):
            LOG.error("Veracode returned an error when attempting to call %s", endpoint)
            return False
    except (
        HTTPError,
        ConnectionError,
        Timeout,
        TooManyRedirects,
        RequestException,
    ):
        LOG.error("Exception encountered when calling the Veracode API")
        return False

    # Filter on the provided app_id
    for app in appbuilds:
        if app.get("app_id") == results_api.app_id:
            LOG.debug("Found app_id %s, returning %s", results_api.app_id, app)
            return app

    LOG.error(
        "Unable to find a completed build for app_id %s",
        results_api.app_id,
    )
    return False
def cancel_build(*, upload_api: UploadAPI) -> bool:
    """
    Cancel an application build

    https://help.veracode.com/reader/LMv_dtSHyb7iIxAQznC~9w/rERUQewXKGx2D_zaoi6wGw
    """
    try:
        endpoint = "deletebuild.do"
        params = {"app_id": upload_api.app_id}

        # If a sandbox_id is specified, add it to the params
        if isinstance(upload_api.sandbox_id, str):
            params["sandbox_id"] = upload_api.sandbox_id

        # https://help.veracode.com/reader/LMv_dtSHyb7iIxAQznC~9w/rERUQewXKGx2D_zaoi6wGw
        response = upload_api.http_get(endpoint=endpoint, params=params)

        if element_contains_error(parsed_xml=response):
            LOG.error("Veracode returned an error when attempting to call %s",
                      endpoint)
            return False

        if isinstance(upload_api.sandbox_id, str):
            LOG.info(
                "Successfully cancelled the build in sandbox id %s of application id %s",
                upload_api.sandbox_id,
                upload_api.app_id,
            )
            return True

        LOG.info("Successfully cancelled the build application id %s",
                 upload_api.app_id)
        return True
    except (
            HTTPError,
            ConnectionError,
            Timeout,
            TooManyRedirects,
            RequestException,
            RuntimeError,
    ):
        return False
def build_exists(*, upload_api: UploadAPI) -> bool:
    """
    Return whether a build already exists

    https://help.veracode.com/reader/orRWez4I0tnZNaA_i0zn9g/Yjclv0XIfU1v_yqmkt18zA
    """

    try:
        endpoint = "getbuildlist.do"
        params = {"app_id": upload_api.app_id}

        # If a sandbox_id is specified, add it to the params
        if isinstance(upload_api.sandbox_id, str):
            params["sandbox_id"] = upload_api.sandbox_id

        response = upload_api.http_get(endpoint=endpoint, params=params)

        if element_contains_error(parsed_xml=response):
            LOG.error("Veracode returned an error when attempting to call %s",
                      endpoint)
            raise RuntimeError

        try:
            # If we don't throw, at least one build already exists
            response[0].get("build_id")
            return False

        except IndexError:
            # No existing builds
            return True

    except (
            HTTPError,
            ConnectionError,
            Timeout,
            TooManyRedirects,
            RequestException,
            RuntimeError,
    ) as e:
        raise RuntimeError from e
def get_sandbox_id(*, sandbox_api: SandboxAPI) -> Union[str, None]:
    """
    Query for and return the sandbox_id

    https://help.veracode.com/reader/LMv_dtSHyb7iIxAQznC~9w/twPT73YBy_iQvrsGEZamhQ
    """
    try:
        endpoint = "getsandboxlist.do"
        params = {"app_id": sandbox_api.app_id}

        sandboxes = sandbox_api.http_get(endpoint=endpoint, params=params)

        if element_contains_error(parsed_xml=sandboxes):
            LOG.error("Veracode returned an error when attempting to call %s",
                      endpoint)
            raise RuntimeError

        for sandbox in sandboxes:
            if sandbox_api.sandbox_name == sandbox.get("sandbox_name"):
                # Returns the first sandbox_name match as duplicates are not
                # allowed by Veracode
                return sandbox.get("sandbox_id")

        # No sandbox_id exists with the provided sandbox_name
        LOG.info(
            "A sandbox named %s does not exist in application id %s",
            sandbox_api.sandbox_name,
            sandbox_api.app_id,
        )
        return None
    except (
            HTTPError,
            ConnectionError,
            Timeout,
            TooManyRedirects,
            RequestException,
            RuntimeError,
    ) as e:
        raise RuntimeError from e
def create_sandbox(*, sandbox_api: SandboxAPI) -> str:
    """
    Create a sandbox and return the sandbox_id

    https://help.veracode.com/reader/LMv_dtSHyb7iIxAQznC~9w/jp8rPey8I5WsuWz7bY2SZg
    """
    try:
        endpoint = "createsandbox.do"
        params = {
            "app_id": sandbox_api.app_id,
            "sandbox_name": sandbox_api.sandbox_name,
        }

        response = sandbox_api.http_post(endpoint=endpoint, params=params)

        if element_contains_error(parsed_xml=response):
            LOG.error("Veracode returned an error when attempting to call %s",
                      endpoint)
            raise RuntimeError

        try:
            # Because we only make one sandbox at a time, we can use index 0 to
            # extract and then return the sandbox_id
            return response[0].get("sandbox_id")
        except (KeyError, IndexError) as e:
            LOG.error(
                "Unable to extract the sandbox_id from the Veracode response")
            raise RuntimeError from e
    except (
            HTTPError,
            ConnectionError,
            Timeout,
            TooManyRedirects,
            RequestException,
            RuntimeError,
    ) as e:
        raise RuntimeError from e