Skip to content

Commit

Permalink
Add support for add subcommand to scaffold devfile resources (#305)
Browse files Browse the repository at this point in the history
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Bradley A. Thornton <bthornto@redhat.com>
Co-authored-by: Sorin Sbarnea <sorin.sbarnea@gmail.com>
  • Loading branch information
4 people authored Nov 7, 2024
1 parent 49fee76 commit cd506b5
Show file tree
Hide file tree
Showing 6 changed files with 467 additions and 18 deletions.
43 changes: 26 additions & 17 deletions src/ansible_creator/arg_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@

COMING_SOON = (
"add resource devcontainer",
"add resource devfile",
"add resource role",
"add plugin action",
"add plugin filter",
Expand Down Expand Up @@ -199,22 +198,7 @@ def _add_args_init_common(self, parser: ArgumentParser) -> None:
"This flag is deprecated and will be removed soon."
),
)
parser.add_argument(
"-o",
"--overwrite",
default=False,
dest="overwrite",
action="store_true",
help="Overwrite existing files or directories.",
)
parser.add_argument(
"-no",
"--no-overwrite",
default=False,
dest="no_overwrite",
action="store_true",
help="Flag that restricts overwriting operation.",
)
self._add_overwrite(parser)

def _add_args_plugin_common(self, parser: ArgumentParser) -> None:
"""Add common plugin arguments to the parser.
Expand Down Expand Up @@ -293,6 +277,8 @@ def _add_resource_devfile(self: Parser, subparser: SubParser[ArgumentParser]) ->
help="The destination directory for the devfile file. The default is the "
"current working directory.",
)

self._add_overwrite(parser)
self._add_args_common(parser)

def _add_resource_role(self: Parser, subparser: SubParser[ArgumentParser]) -> None:
Expand Down Expand Up @@ -382,6 +368,29 @@ def _add_plugin_lookup(self: Parser, subparser: SubParser[ArgumentParser]) -> No
self._add_args_common(parser)
self._add_args_plugin_common(parser)

def _add_overwrite(self, parser: ArgumentParser) -> None:
"""Add overwrite and no-overwrite arguments to the parser.
Args:
parser: The parser to add overwrite and no_overwrite options
"""
parser.add_argument(
"-o",
"--overwrite",
default=False,
dest="overwrite",
action="store_true",
help="Overwrite existing files or directories.",
)
parser.add_argument(
"-no",
"--no-overwrite",
default=False,
dest="no_overwrite",
action="store_true",
help="Flag that restricts overwriting operation.",
)

def _init(self: Parser, subparser: SubParser[ArgumentParser]) -> None:
"""Initialize an Ansible project.
Expand Down
7 changes: 6 additions & 1 deletion src/ansible_creator/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@ class Config:
project: The type of project to scaffold.
collection_name: The name of the collection.
namespace: The namespace for the collection.
resource_type: The type of resource to be scaffolded.
type: The type of the project for which the resource is being scaffolded.
path: The file path where the resource should be added.
"""

creator_version: str
output: Output
subcommand: str

collection: str = ""
force: bool = False
overwrite: bool = False
Expand All @@ -44,6 +46,9 @@ class Config:
project: str = ""
collection_name: str | None = None
namespace: str = ""
resource_type: str = ""
type: str = ""
path: str = ""

def __post_init__(self: Config) -> None:
"""Post process config values."""
Expand Down
150 changes: 150 additions & 0 deletions src/ansible_creator/subcommands/add.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
"""Definitions for ansible-creator add action."""

from __future__ import annotations

import uuid

from pathlib import Path
from typing import TYPE_CHECKING

from ansible_creator.exceptions import CreatorError
from ansible_creator.templar import Templar
from ansible_creator.types import TemplateData
from ansible_creator.utils import Copier, Walker, ask_yes_no


if TYPE_CHECKING:
from ansible_creator.config import Config
from ansible_creator.output import Output


class Add:
"""Class to handle the add subcommand."""

def __init__(
self: Add,
config: Config,
) -> None:
"""Initialize the add action.
Args:
config: App configuration object.
"""
self._resource_type: str = config.resource_type
self._resource_id: str = f"common.{self._resource_type}"
self._add_path: Path = Path(config.path)
self._force = config.force
self._overwrite = config.overwrite
self._no_overwrite = config.no_overwrite
self._creator_version = config.creator_version
self._project = config.project
self.output: Output = config.output
self.templar = Templar()

def run(self) -> None:
"""Start scaffolding the resource file."""
self._check_add_path()
self.output.debug(msg=f"final collection path set to {self._add_path}")

self._scaffold()

def _check_add_path(self) -> None:
"""Validate the provided add path.
Raises:
CreatorError: If the add path does not exist.
"""
if not self._add_path.exists():
msg = f"The path {self._add_path} does not exist. Please provide an existing directory."
raise CreatorError(msg)

def unique_name_in_devfile(self) -> str:
"""Use project specific name in devfile.
Returns:
Unique name entry.
"""
final_name = ".".join(self._add_path.parts[-2:])
final_uuid = str(uuid.uuid4())[:8]
return f"{final_name}-{final_uuid}"

def _scaffold(self) -> None:
"""Scaffold the specified resource file based on the resource type.
Raises:
CreatorError: If unsupported resource type is given.
"""
self.output.debug(f"Started copying {self._project} resource to destination")

# Call the appropriate scaffolding function based on the resource type
if self._resource_type == "devfile":
template_data = self._get_devfile_template_data()

else:

msg = f"Unsupported resource type: {self._resource_type}"
raise CreatorError(msg)

self._perform_scaffold(template_data)

def _perform_scaffold(self, template_data: TemplateData) -> None:
"""Perform the actual scaffolding process using the provided template data.
Args:
template_data: TemplateData
Raises:
CreatorError: If there are conflicts and overwriting is not allowed, or if the
destination directory contains files that will be overwritten.
"""
walker = Walker(
resources=(f"common.{self._resource_type}",),
resource_id=self._resource_id,
dest=self._add_path,
output=self.output,
template_data=template_data,
templar=self.templar,
)
paths = walker.collect_paths()
copier = Copier(output=self.output)

if self._no_overwrite:
msg = "The flag `--no-overwrite` restricts overwriting."
if paths.has_conflicts():
msg += (
"\nThe destination directory contains files that can be overwritten."
"\nPlease re-run ansible-creator with --overwrite to continue."
)
raise CreatorError(msg)

if not paths.has_conflicts() or self._force or self._overwrite:
copier.copy_containers(paths)
self.output.note(f"Resource added to {self._add_path}")
return

if not self._overwrite:
question = (
"Files in the destination directory will be overwritten. Do you want to proceed?"
)
if ask_yes_no(question):
copier.copy_containers(paths)
else:
msg = (
"The destination directory contains files that will be overwritten."
" Please re-run ansible-creator with --overwrite to continue."
)
raise CreatorError(msg)

self.output.note(f"Resource added to {self._add_path}")

def _get_devfile_template_data(self) -> TemplateData:
"""Get the template data for devfile resources.
Returns:
TemplateData: Data required for templating the devfile resource.
"""
return TemplateData(
resource_type=self._resource_type,
creator_version=self._creator_version,
dev_file_name=self.unique_name_in_devfile(),
)
2 changes: 2 additions & 0 deletions src/ansible_creator/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class TemplateData:
"""Dataclass representing the template data.
Attributes:
resource_type: The type of resource to be scaffolded.
additions: A dictionary containing additional data to add to the gitignore.
collection_name: The name of the collection.
creator_version: The version of the creator.
Expand All @@ -27,6 +28,7 @@ class TemplateData:
recommended_extensions: A list of recommended VsCode extensions.
"""

resource_type: str = ""
additions: dict[str, dict[str, dict[str, str | bool]]] = field(default_factory=dict)
collection_name: str = ""
creator_version: str = ""
Expand Down
15 changes: 15 additions & 0 deletions tests/fixtures/common/devfile/devfile.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
schemaVersion: 2.2.2
metadata:
name: testorg
components:
- name: tooling-container
container:
image: ghcr.io/ansible/ansible-workspace-env-reference:latest
memoryRequest: 256M
memoryLimit: 6Gi
cpuRequest: 250m
cpuLimit: 2000m
args: ["tail", "-f", "/dev/null"]
env:
- name: KUBEDOCK_ENABLED
value: "true"
Loading

0 comments on commit cd506b5

Please sign in to comment.