ansible-test - Validate collection ns and name.

Resolves https://github.com/ansible/ansible/issues/62079
pull/76871/head
Matt Clay 4 years ago
parent de5f60e374
commit 26b43f425f

@ -0,0 +1,2 @@
minor_changes:
- ansible-test - Stop early with an error if the current working directory contains an invalid collection namespace or name.

@ -9,6 +9,7 @@ from .util import (
ApplicationError, ApplicationError,
import_plugins, import_plugins,
is_subdir, is_subdir,
is_valid_identifier,
ANSIBLE_LIB_ROOT, ANSIBLE_LIB_ROOT,
ANSIBLE_TEST_ROOT, ANSIBLE_TEST_ROOT,
ANSIBLE_SOURCE_ROOT, ANSIBLE_SOURCE_ROOT,
@ -180,8 +181,7 @@ class DataContext:
if self.content.unsupported: if self.content.unsupported:
raise ApplicationError(self.explain_working_directory()) raise ApplicationError(self.explain_working_directory())
@staticmethod def explain_working_directory(self) -> str:
def explain_working_directory() -> str:
"""Return a message explaining the working directory requirements.""" """Return a message explaining the working directory requirements."""
blocks = [ blocks = [
'The current working directory must be within the source tree being tested.', 'The current working directory must be within the source tree being tested.',
@ -204,9 +204,16 @@ class DataContext:
blocks.append(f'Expected parent directory: {os.path.dirname(cwd)}/{{namespace}}/{{collection}}/') blocks.append(f'Expected parent directory: {os.path.dirname(cwd)}/{{namespace}}/{{collection}}/')
elif os.path.basename(cwd) == 'ansible_collections': elif os.path.basename(cwd) == 'ansible_collections':
blocks.append(f'Expected parent directory: {cwd}/{{namespace}}/{{collection}}/') blocks.append(f'Expected parent directory: {cwd}/{{namespace}}/{{collection}}/')
else: elif 'ansible_collections' not in cwd.split(os.path.sep):
blocks.append('No "ansible_collections" parent directory was found.') blocks.append('No "ansible_collections" parent directory was found.')
if self.content.collection:
if not is_valid_identifier(self.content.collection.namespace):
blocks.append(f'The namespace "{self.content.collection.namespace}" is an invalid identifier or a reserved keyword.')
if not is_valid_identifier(self.content.collection.name):
blocks.append(f'The name "{self.content.collection.name}" is an invalid identifier or a reserved keyword.')
message = '\n'.join(blocks) message = '\n'.join(blocks)
return message return message

@ -11,6 +11,10 @@ from . import (
LayoutMessages, LayoutMessages,
) )
from ...util import (
is_valid_identifier,
)
class CollectionLayout(LayoutProvider): class CollectionLayout(LayoutProvider):
"""Layout provider for Ansible collections.""" """Layout provider for Ansible collections."""
@ -28,6 +32,10 @@ class CollectionLayout(LayoutProvider):
collection_root = os.path.dirname(os.path.dirname(root)) collection_root = os.path.dirname(os.path.dirname(root))
collection_dir = os.path.relpath(root, collection_root) collection_dir = os.path.relpath(root, collection_root)
collection_namespace: str
collection_name: str
collection_namespace, collection_name = collection_dir.split(os.path.sep) collection_namespace, collection_name = collection_dir.split(os.path.sep)
collection_root = os.path.dirname(collection_root) collection_root = os.path.dirname(collection_root)
@ -65,6 +73,7 @@ class CollectionLayout(LayoutProvider):
unit_module_path='tests/unit/plugins/modules', unit_module_path='tests/unit/plugins/modules',
unit_module_utils_path='tests/unit/plugins/module_utils', unit_module_utils_path='tests/unit/plugins/module_utils',
unit_messages=unit_messages, unit_messages=unit_messages,
unsupported=not(is_valid_identifier(collection_namespace) and is_valid_identifier(collection_name)),
) )
@staticmethod @staticmethod

@ -6,6 +6,7 @@ import errno
import fcntl import fcntl
import importlib.util import importlib.util
import inspect import inspect
import keyword
import os import os
import pkgutil import pkgutil
import random import random
@ -98,6 +99,11 @@ MODE_DIRECTORY = MODE_READ | stat.S_IWUSR | stat.S_IXUSR | stat.S_IXGRP | stat.S
MODE_DIRECTORY_WRITE = MODE_DIRECTORY | stat.S_IWGRP | stat.S_IWOTH MODE_DIRECTORY_WRITE = MODE_DIRECTORY | stat.S_IWGRP | stat.S_IWOTH
def is_valid_identifier(value: str) -> bool:
"""Return True if the given value is a valid non-keyword Python identifier, otherwise return False."""
return value.isidentifier() and not keyword.iskeyword(value)
def cache(func): # type: (t.Callable[[], TValue]) -> t.Callable[[], TValue] def cache(func): # type: (t.Callable[[], TValue]) -> t.Callable[[], TValue]
"""Enforce exclusive access on a decorated function and cache the result.""" """Enforce exclusive access on a decorated function and cache the result."""
storage = {} # type: t.Dict[None, TValue] storage = {} # type: t.Dict[None, TValue]

Loading…
Cancel
Save