Skip to content

Commit

Permalink
Release 0.2.0a2 (#441)
Browse files Browse the repository at this point in the history
# Description

Please describe the change you have made.

## Checklist

- [ ] Tests added/updated.
- [ ] Run Demo Job Locally.
- [ ] Documentation updated.
- [ ] Changelogs updated in
[CHANGELOG.cdf-tk.md](https://github.com/cognitedata/cdf-project-templates/blob/main/CHANGELOG.cdf-tk.md).
- [ ] Template changelogs updated in
[CHANGELOG.templates.md](https://github.com/cognitedata/cdf-project-templates/blob/main/CHANGELOG.templates.md).
- [ ] Version bumped.

[_version.py](https://github.com/cognitedata/cdf-project-templates/blob/main/cognite/cognite_toolkit/_version.py)
and

[pyproject.toml](https://github.com/cognitedata/cdf-project-templates/blob/main/pyproject.toml)
per [semantic versioning](https://semver.org/).
  • Loading branch information
doctrino authored Apr 3, 2024
2 parents 215266f + 42bebf0 commit a140440
Show file tree
Hide file tree
Showing 35 changed files with 2,537 additions and 1,981 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ jobs:
run: |
poetry install
- name: Run pytest
env:
IS_GITHUB_ACTIONS: "true"
run: pytest tests
coverage:
needs: test
Expand All @@ -78,11 +80,14 @@ jobs:
run: |
poetry install
- name: Create test coverage report
env:
IS_GITHUB_ACTIONS: "true"
run: pytest --cov=cognite_toolkit/ --cov-config=pyproject.toml --cov-report=xml:coverage.xml tests/
- name: Push coverage report to PR
uses: orgoro/coverage@v3.1
with:
coverageFile: coverage.xml
thresholdAll: 0.6
token: ${{ secrets.GITHUB_TOKEN }}
dry-run-demo:
runs-on: ubuntu-latest
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ jobs:
- name: Install core dependencies
run: poetry install
- name: Run pytest
env:
IS_GITHUB_ACTIONS: "true"
run: pytest tests
build:
runs-on: ubuntu-latest
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ repos:
- --select=E,W,F,I,T,RUF,TID,UP
- --fixable=E,W,F,I,T,RUF,TID,UP
- --target-version=py39
rev: v0.2.2
rev: v0.3.4

- repo: https://github.com/psf/black
rev: 24.2.0
rev: 24.3.0
hooks:
- id: black
args:
Expand Down
21 changes: 21 additions & 0 deletions CHANGELOG.cdf-tk.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,27 @@ Changes are grouped as follows:
- `Fixed` for any bug fixes.
- `Security` in case of vulnerabilities.

## [0.2.0a2] - 2024-04-03

### Added

- Variables can now have extra spaces between curly braces and the variable name. For example, `{{ my_variable }}` is now
a valid variable. Before this change, you would have to write `{{my_variable}}`.
- If an environment variable is not found in a resource file, for example, `${CDF_CLUSTER}`, when
running `cdf-tk deploy` the user will now get a warning message that the variable is missing. Before this change,
this would pass silently and potentially cause an error when trying to deploy to CDF that was hard to debug.

### Fixed

- When running `cdf-tk` with a Token for initialization, the `cdf-tk` would raise an `IndexError`. This is now fixed.
- Container resources that did not have set the optional property `usedFor` would always be classified as changed,
when, for example, running `cdf-tk deploy --dry-run`. This is now fixed.

### Changed

- If two modules have the same name, the `cdf-tk build` command will now stop and raise an error. Before this change,
the `cdf-tk build` command would continue and overwrite the first module with the second module.

## [0.2.0a1] - 2024-03-20

### Added
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ Changes are grouped as follows:
- `Fixed` for any bug fixes.
- `Security` in case of vulnerabilities.

## [0.2.0a2] - 2024-04-03

No changes to templates.

## [0.2.0a1] - 2024-03-20

- Added functionality for wildcard detection of tags in P&ID
Expand Down
36 changes: 31 additions & 5 deletions cognite_toolkit/_cdf.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env python
# The Typer parameters get mixed up if we use the __future__ import annotations
import contextlib
import os
import sys
from collections.abc import Sequence
Expand Down Expand Up @@ -55,7 +56,24 @@
traces_sample_rate=1.0,
)

app = typer.Typer(pretty_exceptions_short=False, pretty_exceptions_show_locals=False, pretty_exceptions_enable=False)
try:
app = typer.Typer(
pretty_exceptions_short=False, pretty_exceptions_show_locals=False, pretty_exceptions_enable=False
)
except AttributeError as e:
# From Typer version 0.11 -> 0.12, breaks if you have an existing installation.
print(
"'cognite-toolkit' uses a dependency named 'typer'.",
"From 'typer' version 0.11 -> 0.12 there was a breaking change if you have an existing "
"installation of 'typer'.",
"Workaround is to uninstall 'typer-slim', and then, reinstall 'typer':",
"'pip uninstall typer-slim'",
"'pip install typer'",
sep="\n",
)
print("\nThis was triggered by the error:", e)
exit(1)

auth_app = typer.Typer(
pretty_exceptions_short=False, pretty_exceptions_show_locals=False, pretty_exceptions_enable=False
)
Expand Down Expand Up @@ -175,8 +193,10 @@ def common(
path_str = dotenv_file.relative_to(Path.cwd())
except ValueError:
path_str = dotenv_file.absolute()
print(f"Loading .env file: {path_str!s}")
load_dotenv(dotenv_file, override=override_env)
print(f"Loading .env file: {path_str!s}.")
has_loaded = load_dotenv(dotenv_file, override=override_env)
if not has_loaded:
print(" [bold yellow]WARNING:[/] No environment variables found in .env file.")

ctx.obj = Common(
verbose=verbose,
Expand Down Expand Up @@ -227,7 +247,9 @@ def build(
if not source_path.is_dir():
print(f" [bold red]ERROR:[/] {source_path} does not exist")
exit(1)
system_config = SystemYAML.load_from_directory(source_path / COGNITE_MODULES, build_env)
cognite_modules_path = source_path / COGNITE_MODULES

system_config = SystemYAML.load_from_directory(cognite_modules_path, build_env)
config = BuildConfigYAML.load_from_directory(source_path, build_env)
print(
Panel(
Expand Down Expand Up @@ -630,7 +652,11 @@ def auth_verify(
if create_group is not None and update_group != 0:
print("[bold red]ERROR: [/] --create-group and --update-group are mutually exclusive.")
exit(1)
ToolGlobals = CDFToolConfig.from_context(ctx)
with contextlib.redirect_stdout(None):
# Remove the Error message from failing to load the config
# This is verified in check_auth
ToolGlobals = CDFToolConfig.from_context(ctx)

if group_file is None:
template_dir = cast(Path, resources.files("cognite_toolkit"))
group_path = template_dir.joinpath(
Expand Down
9 changes: 9 additions & 0 deletions cognite_toolkit/_cdf_tk/load/_resource_loaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -1655,6 +1655,15 @@ def _iterate_over_edges(self, containers: ContainerList) -> Iterable[list[EdgeId
def _chunker(seq: Sequence, size: int) -> Iterable[Sequence]:
return (seq[pos : pos + size] for pos in range(0, len(seq), size))

def _is_equal_custom(self, local: ContainerApply, remote: Container) -> bool:
local_dumped = local.dump(camel_case=True)
if "usedFor" not in local_dumped:
# Setting used_for to "node" as it is the default value in the CDF and will be set by
# the server side if it is not set.
local_dumped["usedFor"] = "node"

return local_dumped == remote.as_write().dump(camel_case=True)


class ViewLoader(ResourceLoader[ViewId, ViewApply, View, ViewApplyList, ViewList]):
api_name = "data_modeling.views"
Expand Down
9 changes: 8 additions & 1 deletion cognite_toolkit/_cdf_tk/templates/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
from ._constants import BUILD_ENVIRONMENT_FILE, COGNITE_MODULES, COGNITE_MODULES_PATH, CUSTOM_MODULES
from ._constants import (
BUILD_ENVIRONMENT_FILE,
COGNITE_MODULES,
COGNITE_MODULES_PATH,
CUSTOM_MODULES,
ROOT_MODULES,
)
from ._templates import build_config, check_yaml_semantics, create_local_config, split_config
from ._utils import flatten_dict, iterate_modules, module_from_path, resource_folder_from_path

Expand All @@ -8,6 +14,7 @@
"resource_folder_from_path",
"COGNITE_MODULES",
"CUSTOM_MODULES",
"ROOT_MODULES",
"COGNITE_MODULES_PATH",
"build_config",
"BUILD_ENVIRONMENT_FILE",
Expand Down
2 changes: 2 additions & 0 deletions cognite_toolkit/_cdf_tk/templates/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
COGNITE_MODULES = "cognite_modules"
CUSTOM_MODULES = "custom_modules"

ROOT_MODULES = [COGNITE_MODULES, CUSTOM_MODULES]

# Add any other files below that should be included in a build
EXCL_FILES = ["README.md", DEFAULT_CONFIG_FILE]
# Which suffixes to exclude when we create indexed files (i.e., they are bundled with their main config file)
Expand Down
7 changes: 6 additions & 1 deletion cognite_toolkit/_cdf_tk/templates/_migration.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
- version: 0.2.0a1
- version: 0.2.0a2
cognite_modules: {}
resources: {}
tool: {}
cognite_modules_hash: ""
- version: 0.2.0a1
cognite_modules: {}
resources: {}
tool: {}
cognite_modules_hash: "4f782ad5c44e093d618df7844cece762954878bf1e0f576acb32975092131346"
- version: 0.1.2
cognite_modules: {}
resources: {}
Expand Down
28 changes: 21 additions & 7 deletions cognite_toolkit/_cdf_tk/templates/_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@
from cognite_toolkit._cdf_tk.load import LOADER_BY_FOLDER_NAME, FunctionLoader, Loader, ResourceLoader
from cognite_toolkit._cdf_tk.utils import validate_case_raw, validate_data_set_is_set, validate_modules_variables

from ._constants import COGNITE_MODULES, CUSTOM_MODULES, EXCL_INDEX_SUFFIX, PROC_TMPL_VARS_SUFFIX
from ._constants import (
EXCL_INDEX_SUFFIX,
PROC_TMPL_VARS_SUFFIX,
ROOT_MODULES,
)
from ._utils import iterate_functions, iterate_modules, module_from_path, resource_folder_from_path
from .data_classes import BuildConfigYAML, SystemYAML

Expand Down Expand Up @@ -50,7 +54,18 @@ def build_config(

config.validate_environment()

available_modules = {module.name for module, _ in iterate_modules(source_dir)}
module_name_by_path = defaultdict(list)
for module, _ in iterate_modules(source_dir):
module_name_by_path[module.name].append(module.relative_to(source_dir))
if duplicate_modules := {
module_name: paths for module_name, paths in module_name_by_path.items() if len(paths) > 1
}:
print(f" [bold red]ERROR:[/] Found the following duplicated module names in {source_dir.name}:")
for module_name, paths in duplicate_modules.items():
print(f" {module_name}: {paths}")
exit(1)

available_modules = set(module_name_by_path.keys())
system_config.validate_modules(available_modules, config.environment.selected_modules_and_packages)

selected_modules = config.get_selected_modules(system_config.packages, available_modules, verbose)
Expand Down Expand Up @@ -530,10 +545,9 @@ class ResourceFiles:
def create_local_config(config: dict[str, Any], module_dir: Path) -> Mapping[str, str]:
maps = []
parts = module_dir.parts
if parts[0] != COGNITE_MODULES and COGNITE_MODULES in parts:
parts = parts[parts.index(COGNITE_MODULES) :]
if parts[0] != CUSTOM_MODULES and CUSTOM_MODULES in parts:
parts = parts[parts.index(CUSTOM_MODULES) :]
for root_module in ROOT_MODULES:
if parts[0] != root_module and root_module in parts:
parts = parts[parts.index(root_module) :]
for no in range(len(parts), -1, -1):
if c := config.get(".".join(parts[:no])):
maps.append(c)
Expand Down Expand Up @@ -569,7 +583,7 @@ def create_file_name(filepath: Path, number_by_resource_type: dict[str, int]) ->

def replace_variables(content: str, local_config: Mapping[str, str]) -> str:
for name, variable in local_config.items():
content = content.replace(f"{{{{{name}}}}}", str(variable))
content = re.sub(rf"{{{{\s*{name}\s*}}}}", str(variable), content)
return content


Expand Down
2 changes: 2 additions & 0 deletions cognite_toolkit/_cdf_tk/templates/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ def iterate_modules(root_dir: Path) -> Iterator[tuple[Path, list[Path]]]:
Iterator[tuple[Path, list[Path]]]: A tuple containing the module directory and a list of all files in the module
"""
if not root_dir.exists():
return
for module_dir in root_dir.iterdir():
if not module_dir.is_dir():
continue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
from rich import print
from rich.panel import Panel

from cognite_toolkit._cdf_tk.templates._constants import COGNITE_MODULES, CUSTOM_MODULES
from cognite_toolkit._cdf_tk.templates._constants import (
COGNITE_MODULES,
ROOT_MODULES,
)
from cognite_toolkit._cdf_tk.templates._utils import _get_cognite_module_version, iterate_modules
from cognite_toolkit._cdf_tk.utils import calculate_directory_hash, read_yaml_file
from cognite_toolkit._version import __version__ as current_version
Expand All @@ -39,17 +42,15 @@ class ProjectDirectory:
_directories_to_copy: ClassVar[list[str]] = [
"common_function_code",
]
_root_modules: ClassVar[list[str]] = [
COGNITE_MODULES,
CUSTOM_MODULES,
]

def __init__(self, project_dir: Path, dry_run: bool):
self.project_dir = project_dir
self._dry_run = dry_run
self._source = Path(resources.files("cognite_toolkit")) # type: ignore[arg-type]
self.modules_by_root: dict[str, list[str]] = {}
for root_module in self._root_modules:
for root_module in ROOT_MODULES:
if not (self._source / root_module).exists():
continue
self.modules_by_root[root_module] = [
f"{module.relative_to(self._source)!s}" for module, _ in iterate_modules(self._source / root_module)
]
Expand Down Expand Up @@ -91,10 +92,10 @@ def copy(self, verbose: bool) -> None:
if not dry_run:
shutil.copytree(self._source / directory, self.project_dir / directory, dirs_exist_ok=True)

for root_module in self._root_modules:
for root_module, modules in self.modules_by_root.items():
if verbose:
print(f"{copy_prefix} the following modules from {root_module} to {self.target_dir_display}")
print(self.modules_by_root[root_module])
print(modules)
if not dry_run:
(Path(self.project_dir) / root_module).mkdir(exist_ok=True)
# Default files are not copied, as they are only used to setup the config.yaml.
Expand Down
Loading

0 comments on commit a140440

Please sign in to comment.