Skip to content

Commit

Permalink
breaking change: Remove Project.do() as it was deprecated for a lon…
Browse files Browse the repository at this point in the history
…g time. Use `Project.task()` instead (#272)

* breaking change: Remove `Project.do()` as it was deprecated for a long time. Use `Project.task()` instead

* fix: Temporarily remove @deprecated from Task.outputs; the API is actively used and we have no replacement API for it

* fmt
  • Loading branch information
NiklasRosenstein authored Aug 2, 2024
1 parent c031804 commit 370ee7d
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 75 deletions.
12 changes: 12 additions & 0 deletions .changelog/_unreleased.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,15 @@ id = "17854ad9-56e6-41a9-9d69-a4a55a830682"
type = "feature"
description = "Add `kraken.std.git.gitignore_extend()` function"
author = "@NiklasRosenstein"

[[entries]]
id = "afea35ef-4ce0-4c2e-9b25-b72d288ce6c7"
type = "breaking change"
description = "Remove `Project.do()` as it was deprecated for a long time. Use `Project.task()` instead"
author = "@NiklasRosenstein"

[[entries]]
id = "aabad4ba-ff7c-47b7-9703-5a84366b6d2b"
type = "fix"
description = "Temporarily remove @deprecated from Task.outputs; the API is actively used and we have no replacement API for it"
author = "@NiklasRosenstein"
73 changes: 1 addition & 72 deletions kraken-build/src/kraken/core/system/project.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
from __future__ import annotations

import re
import warnings
from collections.abc import Mapping
from pathlib import Path
from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast, overload
from typing import TYPE_CHECKING, Any, Literal, TypeVar, overload

from deprecated import deprecated

from kraken.core.address import Address
from kraken.core.base import Currentable, MetadataContainer
from kraken.core.system.kraken_object import KrakenObject
from kraken.core.system.property import Property
from kraken.core.system.task import GroupTask, Task

if TYPE_CHECKING:
Expand Down Expand Up @@ -298,73 +294,6 @@ def remove_child(self, project: Project) -> None:

del self._members[project.name]

@deprecated(reason="Use Project.task() instead")
def do(
self,
name: str,
task_type: type[T_Task] = cast(Any, Task),
default: bool | None = None,
*,
group: str | GroupTask | None = None,
description: str | None = None,
**kwargs: Any,
) -> T_Task:
"""Add a task to the project under the given name, executing the specified action.
:param name: The name of the task to add.
:param task_type: The type of task to add.
:param default: Override :attr:`Task.default`.
:param group: Add the task to the given group in the project.
:param kwargs: Any number of properties to set on the task. Unknown properties will be ignored
with a warning log.
:return: The created task.
"""

# NOTE(NiklasRosenstein): In versions prior to kraken-core 0.12.0, we did not validate task names.
# Now, the #Address class performs the validation and is rather strict. In order to not fully
# break usage of this function with invalid names, we convert the name to a valid form instead
# and issue a warning. This behaviour shall be removed in kraken-core 0.14.0.

if not re.match(Address.Element.VALIDATION_REGEX, name):
new_name = re.sub(f"[^{Address.Element.VALID_CHARACTERS}]+", "-", name)
warnings.warn(
f"Task name `{name}` is invalid and will be normalized to `{new_name}`. Starting with "
"kraken-core 0.12.0, Task names must follow a stricter naming convention subject to the "
f"Address class' validation (must match /{Address.Element.VALIDATION_REGEX}/).",
DeprecationWarning,
stacklevel=2,
)
name = new_name

if name in self._members:
raise ValueError(f"{self} already has a member {name!r}")

task = task_type(name, self)
if default is not None:
task.default = default
if description is not None:
task.description = description

invalid_keys = set()
for key, value in kwargs.items():
prop = getattr(task, key, None)
if isinstance(prop, Property):
if value is not None:
prop.set(value)
else:
invalid_keys.add(key)
if invalid_keys:
task.logger.warning(
"properties %s cannot be set because they don't exist (task %s)", invalid_keys, task.address
)

self.add_task(task)
if isinstance(group, str):
group = self.group(group)
if group is not None:
group.add(task)
return task

def group(self, name: str, *, description: str | None = None, default: bool | None = None) -> GroupTask:
"""Create or get a group of the given name. If a task with the given name already exists, it must refer
to a task of type :class:`GroupTask`, otherwise a :class:`RuntimeError` is raised.
Expand Down
3 changes: 1 addition & 2 deletions kraken-build/src/kraken/core/system/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from pathlib import Path
from typing import TYPE_CHECKING, Any, ForwardRef, Generic, Literal, TypeVar, cast, overload

from deprecated import deprecated

from kraken.common import Supplier
from kraken.core.address import Address
Expand Down Expand Up @@ -236,7 +235,7 @@ def project(self) -> Project:
return self._parent

@property
@deprecated(reason="Task.outputs is deprecated.")
# @deprecated(reason="Task.outputs is deprecated.")
def outputs(self) -> list[Any]:
return self._outputs

Expand Down
24 changes: 23 additions & 1 deletion kraken-build/src/kraken/std/docker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

from kraken.common import import_class
from kraken.core import Project, Task
from kraken.core.system.property import Property
from kraken.core.system.task import GroupTask
from kraken.std.docker.tasks.base_build_task import BaseBuildTask
from kraken.std.docker.tasks.manifest_tool_push_task import ManifestToolPushTask

Expand All @@ -23,12 +25,32 @@ def build_docker_image(
name: str = "buildDocker",
backend: str = DEFAULT_BUILD_BACKEND,
project: Project | None = None,
default: bool = False,
group: str | GroupTask | None = None,
description: str | None = None,
**kwds: Any,
) -> BaseBuildTask:
"""Create a new task in the current project that builds a Docker image and eventually pushes it."""

project = project or Project.current()
task_class = import_class(BUILD_BACKENDS[backend], BaseBuildTask) # type: ignore[type-abstract]
return (project or Project.current()).do(name, task_class, **kwds)
task = project.task(name, task_class, default=default, group=group, description=description)

# Assign properties from the kwargs.
invalid_keys = set()
for key, value in kwds.items():
prop = getattr(task, key, None)
if isinstance(prop, Property):
if value is not None:
prop.set(value)
else:
invalid_keys.add(key)
if invalid_keys:
task.logger.warning(
"properties %s cannot be set because they don't exist (task %s)", invalid_keys, task.address
)

return task


def manifest_tool(
Expand Down

0 comments on commit 370ee7d

Please sign in to comment.