mirror of
				https://github.com/kevinveenbirkenbach/computer-playbook.git
				synced 2025-11-04 04:08:15 +00:00 
			
		
		
		
	Add custom Ansible filter plugin get_category_entries
This commit introduces a new Ansible filter plugin named 'get_category_entries', which returns all role names under the roles/ directory that start with a given prefix. Additionally, unit tests (unittest framework) have been added under tests/unit/filterplugins/ to ensure correct behavior, including: - Returns empty list when roles/ directory is missing - Correctly filters and sorts by prefix - Ignores non-directory entries - Supports custom roles_path argument - Returns all roles when prefix is empty Reference: https://chatgpt.com/share/68a2f1ab-1fe8-800f-b22a-28c1c95802c2
This commit is contained in:
		
							
								
								
									
										31
									
								
								filter_plugins/get_category_entries.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								filter_plugins/get_category_entries.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
# Custom Ansible filter to get all role names under "roles/" with a given prefix.
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
def get_category_entries(prefix, roles_path="roles"):
 | 
			
		||||
    """
 | 
			
		||||
    Returns a list of role names under the given roles_path
 | 
			
		||||
    that start with the specified prefix.
 | 
			
		||||
 | 
			
		||||
    :param prefix: String prefix to match role names.
 | 
			
		||||
    :param roles_path: Path to the roles directory (default: 'roles').
 | 
			
		||||
    :return: List of matching role names.
 | 
			
		||||
    """
 | 
			
		||||
    if not os.path.isdir(roles_path):
 | 
			
		||||
        return []
 | 
			
		||||
 | 
			
		||||
    roles = []
 | 
			
		||||
    for entry in os.listdir(roles_path):
 | 
			
		||||
        full_path = os.path.join(roles_path, entry)
 | 
			
		||||
        if os.path.isdir(full_path) and entry.startswith(prefix):
 | 
			
		||||
            roles.append(entry)
 | 
			
		||||
 | 
			
		||||
    return sorted(roles)
 | 
			
		||||
 | 
			
		||||
class FilterModule(object):
 | 
			
		||||
    """ Custom filters for Ansible """
 | 
			
		||||
 | 
			
		||||
    def filters(self):
 | 
			
		||||
        return {
 | 
			
		||||
            "get_category_entries": get_category_entries
 | 
			
		||||
        }
 | 
			
		||||
							
								
								
									
										85
									
								
								tests/unit/filter_plugins/test_get_category_entries.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								tests/unit/filter_plugins/test_get_category_entries.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
			
		||||
# Unit tests for the get_category_entries Ansible filter plugin (unittest version).
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import unittest
 | 
			
		||||
import tempfile
 | 
			
		||||
import shutil
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
 | 
			
		||||
from filter_plugins.get_category_entries import get_category_entries
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestGetCategoryEntries(unittest.TestCase):
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        # Create an isolated temp directory for each test
 | 
			
		||||
        self._tmpdir = tempfile.TemporaryDirectory()
 | 
			
		||||
        self.tmp = Path(self._tmpdir.name)
 | 
			
		||||
 | 
			
		||||
    def tearDown(self):
 | 
			
		||||
        # Clean up the temp directory
 | 
			
		||||
        self._tmpdir.cleanup()
 | 
			
		||||
 | 
			
		||||
    def test_returns_empty_when_roles_dir_missing(self):
 | 
			
		||||
        """If the roles directory does not exist, the filter must return an empty list."""
 | 
			
		||||
        missing_dir = self.tmp / "no_such_roles_dir"
 | 
			
		||||
        self.assertFalse(missing_dir.exists())
 | 
			
		||||
        self.assertEqual(get_category_entries("docker-", roles_path=str(missing_dir)), [])
 | 
			
		||||
 | 
			
		||||
    def test_matches_prefix_and_sorts(self):
 | 
			
		||||
        """
 | 
			
		||||
        The filter should return only directory names starting with the prefix,
 | 
			
		||||
        and the result must be sorted.
 | 
			
		||||
        """
 | 
			
		||||
        roles_dir = self.tmp / "roles"
 | 
			
		||||
        roles_dir.mkdir()
 | 
			
		||||
 | 
			
		||||
        # Create role directories
 | 
			
		||||
        (roles_dir / "docker-nginx").mkdir()
 | 
			
		||||
        (roles_dir / "docker-postgres").mkdir()
 | 
			
		||||
        (roles_dir / "web-app-keycloak").mkdir()
 | 
			
		||||
        (roles_dir / "docker-redis").mkdir()
 | 
			
		||||
 | 
			
		||||
        # A file that should be ignored
 | 
			
		||||
        (roles_dir / "docker-file").write_text("not a directory")
 | 
			
		||||
 | 
			
		||||
        result = get_category_entries("docker-", roles_path=str(roles_dir))
 | 
			
		||||
        self.assertEqual(result, ["docker-nginx", "docker-postgres", "docker-redis"])
 | 
			
		||||
 | 
			
		||||
    def test_ignores_non_directories(self):
 | 
			
		||||
        """Non-directory entries under roles/ must be ignored."""
 | 
			
		||||
        roles_dir = self.tmp / "roles"
 | 
			
		||||
        roles_dir.mkdir()
 | 
			
		||||
 | 
			
		||||
        (roles_dir / "docker-engine").mkdir()
 | 
			
		||||
        (roles_dir / "docker-engine.txt").write_text("file, should be ignored")
 | 
			
		||||
 | 
			
		||||
        result = get_category_entries("docker-", roles_path=str(roles_dir))
 | 
			
		||||
        self.assertEqual(result, ["docker-engine"])
 | 
			
		||||
 | 
			
		||||
    def test_respects_custom_roles_path(self):
 | 
			
		||||
        """When roles_path is provided, the filter should use it instead of 'roles'."""
 | 
			
		||||
        custom_roles = self.tmp / "custom" / "rolesdir"
 | 
			
		||||
        custom_roles.mkdir(parents=True)
 | 
			
		||||
 | 
			
		||||
        (custom_roles / "docker-a").mkdir()
 | 
			
		||||
        (custom_roles / "docker-b").mkdir()
 | 
			
		||||
        (custom_roles / "other-c").mkdir()
 | 
			
		||||
 | 
			
		||||
        result = get_category_entries("docker-", roles_path=str(custom_roles))
 | 
			
		||||
        self.assertEqual(result, ["docker-a", "docker-b"])
 | 
			
		||||
 | 
			
		||||
    def test_empty_prefix_returns_all_roles_sorted(self):
 | 
			
		||||
        """If an empty prefix is passed, the filter should return all role directories (sorted)."""
 | 
			
		||||
        roles_dir = self.tmp / "roles"
 | 
			
		||||
        roles_dir.mkdir()
 | 
			
		||||
 | 
			
		||||
        (roles_dir / "a-role").mkdir()
 | 
			
		||||
        (roles_dir / "c-role").mkdir()
 | 
			
		||||
        (roles_dir / "b-role").mkdir()
 | 
			
		||||
 | 
			
		||||
        result = get_category_entries("", roles_path=str(roles_dir))
 | 
			
		||||
        self.assertEqual(result, ["a-role", "b-role", "c-role"])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    unittest.main()
 | 
			
		||||
		Reference in New Issue
	
	Block a user