예제 #1
0
def test_resolve_npm_invalid_lock(mock_dd, mock_gpad, mock_exists):
    mock_exists.return_value = True
    mock_gpad.side_effect = KeyError()

    expected = "The lock file npm-shrinkwrap.json has an unexpected format"
    with pytest.raises(CachitoError, match=expected):
        npm.resolve_npm("/tmp/cachito-bundles/temp/1/app", {"id": 1})
예제 #2
0
def test_resolve_npm_no_lock(mock_dd, mock_exists):
    mock_exists.return_value = False

    expected = (
        "The npm-shrinkwrap.json or package-lock.json file must be present for the npm "
        "package manager")
    with pytest.raises(CachitoError, match=expected):
        npm.resolve_npm("/tmp/cachito-bundles/temp/1/app", {"id": 1})
예제 #3
0
def test_resolve_npm(
    get_worker_config,
    mock_dd,
    mock_gpad,
    mock_exists,
    shrink_wrap,
    package_lock,
    package_and_deps,
    tmpdir,
):
    get_worker_config.return_value = mock.Mock(cachito_bundles_dir=str(tmpdir))
    package_json = True
    mock_dd.return_value = {
        "@angular-devkit/[email protected]",
        "@angular/[email protected]",
        "[email protected]",
        "[email protected]",
        "[email protected]",
    }
    # Note that the dictionary returned by the get_package_and_deps function is modified as part of
    # the resolve_npm function. This is why a deep copy is necessary.
    expected_deps_info = copy.deepcopy(package_and_deps)
    expected_deps_info["downloaded_deps"] = {
        "@angular-devkit/[email protected]",
        "@angular/[email protected]",
        "[email protected]",
        "[email protected]",
        "[email protected]",
    }
    if shrink_wrap:
        expected_deps_info["lock_file_name"] = "npm-shrinkwrap.json"
        mock_exists.side_effect = [shrink_wrap, package_json]
    else:
        expected_deps_info["lock_file_name"] = "package-lock.json"
        mock_exists.side_effect = [shrink_wrap, package_lock, package_json]
    mock_gpad.return_value = package_and_deps
    # Remove the "bundled" key as does the resolve_npm function to get expected returned
    # dependencies
    for dep in expected_deps_info["deps"]:
        dep.pop("bundled")
        dep.pop("version_in_nexus")

    src_path = "/tmp/cachito-bundles/temp/1/app"
    deps_info = npm.resolve_npm(src_path, {"id": 1})

    assert deps_info == expected_deps_info
    package_json_path = os.path.join(src_path, "package.json")
    if shrink_wrap:
        lock_file_path = os.path.join(src_path, "npm-shrinkwrap.json")
    elif package_lock:
        lock_file_path = os.path.join(src_path, "package-lock.json")
    mock_gpad.assert_called_once_with(package_json_path, lock_file_path)
    # We can't verify the actual correct deps value was passed in since the deps that were passed
    # in were mutated and mock does not keep a deepcopy of the function arguments.
    mock_dd.assert_called_once_with(RequestBundleDir(1).npm_deps_dir, mock.ANY, mock.ANY, mock.ANY)
예제 #4
0
def fetch_npm_source(request_id, package_configs=None):
    """
    Resolve and fetch npm dependencies for a given request.

    This function uses the Python ``os.path`` library to manipulate paths, so the path to the
    configuration files may differ in format based on the system the Cachito worker is deployed on
    (i.e. Linux vs Windows).

    :param int request_id: the Cachito request ID this is for
    :param list package_configs: the list of optional package configurations submitted by the user
    :raise CachitoError: if the task fails
    """
    if package_configs is None:
        package_configs = []

    validate_npm_config()

    bundle_dir = RequestBundleDir(request_id)
    log.debug("Checking if the application source uses npm")
    subpaths = [
        os.path.normpath(c["path"]) for c in package_configs if c.get("path")
    ]

    if not subpaths:
        # Default to the root of the application source
        subpaths = [os.curdir]

    _verify_npm_files(bundle_dir, subpaths)

    log.info("Configuring Nexus for npm for the request %d", request_id)
    set_request_state(request_id, "in_progress", "Configuring Nexus for npm")
    repo_name = get_npm_proxy_repo_name(request_id)
    prepare_nexus_for_js_request(repo_name)

    npm_config_files = []
    downloaded_deps = set()
    for i, subpath in enumerate(subpaths):
        log.info("Fetching the npm dependencies for request %d in subpath %s",
                 request_id, subpath)
        set_request_state(
            request_id,
            "in_progress",
            f'Fetching the npm dependencies at the "{subpath}" directory"',
        )
        request = get_request(request_id)
        package_source_path = str(bundle_dir.app_subpath(subpath).source_dir)
        try:
            package_and_deps_info = resolve_npm(package_source_path,
                                                request,
                                                skip_deps=downloaded_deps)
        except CachitoError:
            log.exception("Failed to fetch npm dependencies for request %d",
                          request_id)
            raise

        downloaded_deps = downloaded_deps | package_and_deps_info[
            "downloaded_deps"]

        log.info(
            "Generating the npm configuration files for request %d in subpath %s",
            request_id,
            subpath,
        )
        remote_package_source_path = os.path.normpath(
            os.path.join("app", subpath))
        if package_and_deps_info["package.json"]:
            package_json_str = json.dumps(
                package_and_deps_info["package.json"], indent=2)
            package_json_path = os.path.join(remote_package_source_path,
                                             "package.json")
            npm_config_files.append(
                make_base64_config_file(package_json_str, package_json_path))

        if package_and_deps_info["lock_file"]:
            package_lock_str = json.dumps(package_and_deps_info["lock_file"],
                                          indent=2)
            lock_file_name = package_and_deps_info["lock_file_name"]
            lock_file_path = os.path.join(remote_package_source_path,
                                          lock_file_name)
            npm_config_files.append(
                make_base64_config_file(package_lock_str, lock_file_path))

        if i == 0:
            env_vars = get_worker_config(
            ).cachito_default_environment_variables.get("npm", {})
        else:
            env_vars = None
        package = package_and_deps_info["package"]
        update_request_with_package(request_id,
                                    package,
                                    env_vars,
                                    package_subpath=subpath)
        update_request_with_deps(request_id, package,
                                 package_and_deps_info["deps"])

    log.info("Finalizing the Nexus configuration for npm for the request %d",
             request_id)
    set_request_state(request_id, "in_progress",
                      "Finalizing the Nexus configuration for npm")
    username = get_npm_proxy_username(request_id)
    password = finalize_nexus_for_js_request(username, repo_name)

    log.info("Generating the .npmrc file(s)")
    proxy_repo_url = get_npm_proxy_repo_url(request_id)
    npm_config_files.extend(
        generate_npmrc_config_files(proxy_repo_url, username, password,
                                    subpaths))

    update_request_with_config_files(request_id, npm_config_files)