Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make molecule collection-aware #4340

Merged
merged 9 commits into from
Dec 13, 2024
34 changes: 33 additions & 1 deletion src/molecule/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import warnings

from pathlib import Path
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, cast
from uuid import uuid4

from ansible_compat.ports import cache, cached_property
Expand All @@ -38,6 +38,7 @@
from molecule.dependency import ansible_galaxy, shell
from molecule.model import schema_v3
from molecule.provisioner import ansible
from molecule.types import CollectionData
from molecule.util import boolean


Expand Down Expand Up @@ -231,6 +232,23 @@
"""
return "molecule_parallel" if self.is_parallel else "molecule"

@property
def collection_directory(self) -> Path | None:
"""Location of collection containing the molecule files.

Returns:
Root of the collection containing the molecule files.
"""
current_dir = Path(self.project_directory)
if (current_dir / "galaxy.yml").exists():
return current_dir
show_toplevel = util.run_command("git rev-parse --show-toplevel")
if show_toplevel.returncode == 0:
git_root = Path(show_toplevel.stdout.strip())
if (git_root / "galaxy.yml").exists():
return git_root

Check warning on line 249 in src/molecule/config.py

View check run for this annotation

Codecov / codecov/patch

src/molecule/config.py#L249

Added line #L249 was not covered by tests
return None

@property
def molecule_directory(self) -> str:
"""Molecule directory for this project.
Expand All @@ -240,6 +258,20 @@
"""
return molecule_directory(self.project_directory)

@cached_property
def collection(self) -> CollectionData | None:
"""Collection metadata sourced from galaxy.yml.

Returns:
A dictionary of information about the collection molecule is running inside, if any.
"""
if not self.collection_directory:
return None

galaxy_file = self.collection_directory / "galaxy.yml"
galaxy_data = util.safe_load_file(galaxy_file)
cidrblock marked this conversation as resolved.
Show resolved Hide resolved
return cast(CollectionData, galaxy_data)

@cached_property
def dependency(self) -> Dependency | None:
"""Dependency manager in use.
Expand Down
26 changes: 26 additions & 0 deletions src/molecule/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,32 @@
Options: TypeAlias = MutableMapping[str, str | bool]


class CollectionData(TypedDict, total=False):
"""Collection metadata sourced from galaxy.yml.

Attributes:
name: The name of the collection.
namespace: The collection namespace.
version: The collection's version.
readme: Path to the README file.
authors: List of authors of the collection.
description: Description of the collection.
repository: URL of the collection's online repository.
license_file: Path to the collection's LICENSE file.
tags: List of tags applied to the collection.
"""

name: str
namespace: str
version: str
readme: str
authors: list[str]
description: str
repository: str
license_file: str
tags: list[str]


class DependencyData(TypedDict, total=False):
"""Molecule dependency configuration.

Expand Down
49 changes: 47 additions & 2 deletions tests/unit/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
# DEALINGS IN THE SOFTWARE.
from __future__ import annotations

import copy
import os

from pathlib import Path
from typing import TYPE_CHECKING, Literal

import pytest
Expand Down Expand Up @@ -84,16 +86,59 @@ def test_init_calls_validate( # noqa: D103
patched_config_validate.assert_called_once_with()


def test_collection_directory_property(
config_instance: config.Config,
resources_folder_path: Path,
) -> None:
"""Test collection_directory property.

Args:
config_instance: Instance of Config.
resources_folder_path: Path to resources directory holding a valid collection.
"""
# default path is not in a collection
assert config_instance.collection_directory is None

# Alter config_instance to start at path of a collection
config_instance = copy.copy(config_instance)
collection_path = resources_folder_path / "sample-collection"
config_instance.project_directory = str(collection_path)
assert config_instance.collection_directory == collection_path


def test_project_directory_property(config_instance: config.Config) -> None: # noqa: D103
assert os.getcwd() == config_instance.project_directory # noqa: PTH109
assert str(Path.cwd()) == config_instance.project_directory


def test_molecule_directory_property(config_instance: config.Config) -> None: # noqa: D103
x = os.path.join(os.getcwd(), "molecule") # noqa: PTH109, PTH118
x = str(Path.cwd() / "molecule")

assert x == config_instance.molecule_directory


def test_collection_property(
config_instance: config.Config,
resources_folder_path: Path,
) -> None:
"""Test collection property.

Args:
config_instance: Instance of Config.
resources_folder_path: Path to resources directory holding a valid collection.
"""
modified_instance = copy.copy(config_instance)
# default path is not in a collection
assert config_instance.collection is None

# Alter config_instance to start at path of a collection
collection_path = resources_folder_path / "sample-collection"
modified_instance.project_directory = str(collection_path)

assert modified_instance.collection is not None
assert modified_instance.collection["name"] == "goodies"
assert modified_instance.collection["namespace"] == "acme"


def test_dependency_property(config_instance: config.Config) -> None: # noqa: D103
assert isinstance(config_instance.dependency, ansible_galaxy.AnsibleGalaxy)

Expand Down
Loading