feat(ansible): steward:category + steward:confirm playbook metadata
Extend the playbook metadata convention with a namespaced `# steward:<key>:` comment block: - steward:category — free-text grouping label, shown as a badge in the browse list and on the run form. - steward:confirm — true/yes/1/on marks a playbook destructive; the run form then requires a confirmation tick (required checkbox in the shared vars fragment) before it can launch. sources.discover_playbook_meta() parses description + category + confirm (first match per key; `# description:` still primary, `# steward:description:` alias). discover_playbook_description() now delegates to it. The browse list reads per-playbook meta to show category badges + descriptions; the run-form and playbook-vars fragments render the badge + confirm gate. Bundled playbooks tagged: docker_prune → category maintenance + confirm true; provision/install/update → category host-agent. Docs: docs/reference/playbook-authoring.md updated (keys now implemented) and a quick reference added next to the code at steward/ansible/PLAYBOOK_CONVENTIONS.md. Tests added for category/confirm/alias parsing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -50,7 +50,16 @@ async def browse():
|
||||
all_sources = _get_sources()
|
||||
source_data = []
|
||||
for source in all_sources:
|
||||
playbooks = src_module.discover_playbooks(source["path"])
|
||||
playbooks = []
|
||||
for path in src_module.discover_playbooks(source["path"]):
|
||||
contents = src_module.read_playbook(source["path"], path)
|
||||
meta = (src_module.discover_playbook_meta(contents) if contents is not None
|
||||
else {"description": "", "category": ""})
|
||||
playbooks.append({
|
||||
"path": path,
|
||||
"category": meta["category"],
|
||||
"description": meta["description"],
|
||||
})
|
||||
inventories = src_module.discover_inventories(source["path"])
|
||||
source_data.append({
|
||||
"source": source,
|
||||
@@ -165,14 +174,15 @@ async def playbook_vars():
|
||||
playbook_path = (request.args.get("playbook_path", "") or "").strip()
|
||||
source = next((s for s in _get_sources() if s["name"] == source_name), None)
|
||||
variables: list = []
|
||||
description = ""
|
||||
meta: dict = {"description": "", "category": "", "confirm": False}
|
||||
if source and playbook_path:
|
||||
contents = src_module.read_playbook(source["path"], playbook_path)
|
||||
if contents is not None:
|
||||
variables = src_module.discover_playbook_variables(contents)
|
||||
description = src_module.discover_playbook_description(contents)
|
||||
meta = src_module.discover_playbook_meta(contents)
|
||||
return await render_template(
|
||||
"ansible/_playbook_vars.html", variables=variables, description=description)
|
||||
"ansible/_playbook_vars.html", variables=variables,
|
||||
description=meta["description"], category=meta["category"], confirm=meta["confirm"])
|
||||
|
||||
|
||||
@ansible_bp.get("/run-form/<source_name>/<path:playbook_path>")
|
||||
@@ -189,7 +199,7 @@ async def run_form(source_name: str, playbook_path: str):
|
||||
if contents is None:
|
||||
return "Playbook not found", 404
|
||||
variables = src_module.discover_playbook_variables(contents)
|
||||
description = src_module.discover_playbook_description(contents)
|
||||
meta = src_module.discover_playbook_meta(contents)
|
||||
inventories = src_module.discover_inventories(source["path"])
|
||||
|
||||
async with current_app.db_sessionmaker() as db:
|
||||
@@ -201,7 +211,8 @@ async def run_form(source_name: str, playbook_path: str):
|
||||
return await render_template(
|
||||
"ansible/_run_form.html",
|
||||
source_name=source_name, playbook_path=playbook_path,
|
||||
variables=variables, description=description, targets=targets, groups=groups,
|
||||
variables=variables, description=meta["description"], category=meta["category"],
|
||||
confirm=meta["confirm"], targets=targets, groups=groups,
|
||||
inventories=inventories,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user