Skip to content

Instantly share code, notes, and snippets.

@konstruktoid
Last active June 4, 2025 10:42
Show Gist options
  • Save konstruktoid/29facb031454ffd7257cd9534fe5831a to your computer and use it in GitHub Desktop.
Save konstruktoid/29facb031454ffd7257cd9534fe5831a to your computer and use it in GitHub Desktop.
Skeleton Ansible argument spec generator
#!/usr/bin/env python3
# ruff: noqa: T201
"""Print a skeleton Ansible argument_specs.yml file."""
import os
from pathlib import Path
import yaml
def find_yaml_files(directory: str) -> list[str]:
"""Find all yaml files in the given directory and its subdirectories."""
yaml_files = []
for root, _dirs, files in os.walk(directory):
for file in files:
if file.endswith((".yaml", ".yml")):
yaml_files.append(os.path.join(root, file)) # noqa: PTH118, PERF401
return yaml_files
def parse_yaml_file(file_path: str) -> dict:
"""Parse a yaml file and return the data."""
with Path.open(file_path) as file:
return yaml.safe_load(file)
def extract_arguments(data: dict, prefix: str = "") -> dict:
"""Extract arguments from the yaml data."""
arguments = {}
if isinstance(data, dict):
for key, value in data.items():
new_prefix = f"{prefix}.{key}" if prefix else key
if isinstance(value, dict):
arguments.update(extract_arguments(value, new_prefix))
else:
arguments[new_prefix] = value
return arguments
def read_author_from_meta() -> str:
"""Read the author from the meta/main.yml file."""
meta_file = "meta/main.yml"
with Path.open(meta_file) as file:
data = yaml.safe_load(file)
return data.get("galaxy_info", {}).get("author", "unknown")
def read_role_name_from_meta() -> str:
"""Read the role name from the meta/main.yml file."""
meta_file = "meta/main.yml"
with Path.open(meta_file) as file:
data = yaml.safe_load(file)
return data.get("galaxy_info", {}).get("role_name", "unknown")
def read_description_from_meta() -> str:
"""Read the description from the meta/main.yml file."""
meta_file = "meta/main.yml"
with Path.open(meta_file) as file:
data = yaml.safe_load(file)
unknown_desc = (
f"This is the main entrypoint for the C({read_role_name_from_meta()}) role."
)
return data.get("galaxy_info", {}).get("description", unknown_desc)
def generate_argspec(yaml_files: list[str]) -> dict:
"""Generate a list of arguments and their default values from the yaml files."""
all_arguments = {}
for yaml_file in yaml_files:
data = parse_yaml_file(yaml_file)
arguments = extract_arguments(data)
all_arguments.update(arguments)
return all_arguments
def main() -> None:
"""Print generated output."""
directory = "defaults"
yaml_files = find_yaml_files(directory)
all_arguments = generate_argspec(yaml_files)
author = read_author_from_meta()
description = read_description_from_meta()
header = f"""argument_specs:
main:
short_description: {description}
description:
- {description}
author:
- {author}
options:"""
print(header)
for arg, value in all_arguments.items():
if type(value).__name__ == "list":
entry = f""" {arg}:
description: \"{arg} description\"
type: \"{type(value).__name__}\"
elements: \"str\"
default: \"{value}\""""
else:
entry = f""" {arg}:
description: \"{arg} description\"
type: \"{type(value).__name__}\"
default: \"{value}\""""
print(entry)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment