mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-07-06 00:33:11 +02:00
Implemented new run_after logic
This commit is contained in:
parent
03db141316
commit
0766bb4162
@ -105,32 +105,13 @@ def print_dependency_tree(graph):
|
|||||||
|
|
||||||
def generate_playbook_entries(roles_dir, prefix=None):
|
def generate_playbook_entries(roles_dir, prefix=None):
|
||||||
"""Generate playbook entries based on the sorted order."""
|
"""Generate playbook entries based on the sorted order."""
|
||||||
# Build dependency graph
|
|
||||||
graph, in_degree, roles = build_dependency_graph(roles_dir, prefix)
|
graph, in_degree, roles = build_dependency_graph(roles_dir, prefix)
|
||||||
|
|
||||||
# Print and collect roles in tree order
|
# Detect cycles and get correct topological order
|
||||||
tree_sorted_roles = print_dependency_tree(graph)
|
|
||||||
|
|
||||||
# Topologically sort the roles
|
|
||||||
sorted_role_names = topological_sort(graph, in_degree)
|
sorted_role_names = topological_sort(graph, in_degree)
|
||||||
|
|
||||||
# Ensure that roles that appear in the tree come first
|
|
||||||
final_sorted_roles = [role for role in tree_sorted_roles if role in sorted_role_names]
|
|
||||||
|
|
||||||
# Include the remaining unsorted roles
|
|
||||||
final_sorted_roles += [role for role in sorted_role_names if role not in final_sorted_roles]
|
|
||||||
|
|
||||||
# Remove duplicates, keeping only the first occurrence to preserve dependency order
|
|
||||||
seen = set()
|
|
||||||
deduplicated_roles = []
|
|
||||||
for role in final_sorted_roles:
|
|
||||||
if role not in seen:
|
|
||||||
deduplicated_roles.append(role)
|
|
||||||
seen.add(role)
|
|
||||||
|
|
||||||
# Generate the playbook entries
|
|
||||||
entries = []
|
entries = []
|
||||||
for role_name in deduplicated_roles:
|
for role_name in sorted_role_names:
|
||||||
role = roles[role_name]
|
role = roles[role_name]
|
||||||
entries.append(
|
entries.append(
|
||||||
f"- name: setup {role['application_id']}\n"
|
f"- name: setup {role['application_id']}\n"
|
||||||
|
@ -18,4 +18,8 @@ galaxy_info:
|
|||||||
issue_tracker_url: https://s.veen.world/cymaisissues
|
issue_tracker_url: https://s.veen.world/cymaisissues
|
||||||
documentation: https://s.veen.world/cymais
|
documentation: https://s.veen.world/cymais
|
||||||
logo:
|
logo:
|
||||||
class: "fa-solid fa-file-invoice-dollar"
|
class: "fa-solid fa-file-invoice-dollar"
|
||||||
|
run_after:
|
||||||
|
- docker-matomo
|
||||||
|
- docker-keycloak
|
||||||
|
- docker-mailu
|
@ -19,4 +19,8 @@ galaxy_info:
|
|||||||
documentation: https://s.veen.world/cymais
|
documentation: https://s.veen.world/cymais
|
||||||
logo:
|
logo:
|
||||||
class: "fa-solid fa-calendar-check"
|
class: "fa-solid fa-calendar-check"
|
||||||
|
run_after:
|
||||||
|
- docker-matomo
|
||||||
|
- docker-keycloak
|
||||||
|
- docker-mailu
|
||||||
dependencies: []
|
dependencies: []
|
||||||
|
@ -18,4 +18,7 @@ galaxy_info:
|
|||||||
documentation: https://s.veen.world/cymais
|
documentation: https://s.veen.world/cymais
|
||||||
logo:
|
logo:
|
||||||
class: "fa-solid fa-table"
|
class: "fa-solid fa-table"
|
||||||
dependencies: []
|
run_after:
|
||||||
|
- docker-matomo
|
||||||
|
- docker-keycloak
|
||||||
|
- docker-mailu
|
||||||
|
@ -18,4 +18,8 @@ galaxy_info:
|
|||||||
documentation: https://s.veen.world/cymais
|
documentation: https://s.veen.world/cymais
|
||||||
logo:
|
logo:
|
||||||
class: "fa-solid fa-sun"
|
class: "fa-solid fa-sun"
|
||||||
|
run_after:
|
||||||
|
- docker-matomo
|
||||||
|
- docker-keycloak
|
||||||
|
- docker-mailu
|
||||||
dependencies: []
|
dependencies: []
|
||||||
|
@ -18,4 +18,6 @@ galaxy_info:
|
|||||||
documentation: https://s.veen.world/cymais
|
documentation: https://s.veen.world/cymais
|
||||||
logo:
|
logo:
|
||||||
class: "fa-solid fa-users"
|
class: "fa-solid fa-users"
|
||||||
dependencies: []
|
run_after:
|
||||||
|
- docker-matomo
|
||||||
|
- docker-keycloak
|
||||||
|
@ -19,4 +19,7 @@ galaxy_info:
|
|||||||
logo:
|
logo:
|
||||||
class: "fa-solid fa-music"
|
class: "fa-solid fa-music"
|
||||||
run_after:
|
run_after:
|
||||||
|
- docker-matomo
|
||||||
|
- docker-keycloak
|
||||||
|
- docker-mailu
|
||||||
- docker-ldap
|
- docker-ldap
|
@ -19,3 +19,7 @@ galaxy_info:
|
|||||||
repository: "https://s.veen.world/cymais"
|
repository: "https://s.veen.world/cymais"
|
||||||
issue_tracker_url: "https://s.veen.world/cymaisissues"
|
issue_tracker_url: "https://s.veen.world/cymaisissues"
|
||||||
documentation: "https://s.veen.world/cymais"
|
documentation: "https://s.veen.world/cymais"
|
||||||
|
run_after:
|
||||||
|
- docker-matomo
|
||||||
|
- docker-keycloak
|
||||||
|
- docker-mailu
|
||||||
|
@ -19,4 +19,8 @@ galaxy_info:
|
|||||||
documentation: https://s.veen.world/cymais
|
documentation: https://s.veen.world/cymais
|
||||||
logo:
|
logo:
|
||||||
class: "fa-solid fa-code"
|
class: "fa-solid fa-code"
|
||||||
|
run_after:
|
||||||
|
- docker-matomo
|
||||||
|
- docker-keycloak
|
||||||
|
- docker-mailu
|
||||||
dependencies: []
|
dependencies: []
|
||||||
|
@ -19,4 +19,8 @@ galaxy_info:
|
|||||||
documentation: https://s.veen.world/cymais
|
documentation: https://s.veen.world/cymais
|
||||||
logo:
|
logo:
|
||||||
class: "fa-solid fa-code-branch"
|
class: "fa-solid fa-code-branch"
|
||||||
|
run_after:
|
||||||
|
- docker-matomo
|
||||||
|
- docker-keycloak
|
||||||
|
- docker-mailu
|
||||||
dependencies: []
|
dependencies: []
|
||||||
|
@ -19,4 +19,8 @@ galaxy_info:
|
|||||||
documentation: https://s.veen.world/cymais
|
documentation: https://s.veen.world/cymais
|
||||||
logo:
|
logo:
|
||||||
class: "fa-solid fa-sitemap"
|
class: "fa-solid fa-sitemap"
|
||||||
|
run_after:
|
||||||
|
- docker-matomo
|
||||||
|
- docker-keycloak
|
||||||
|
- docker-mailu
|
||||||
dependencies: []
|
dependencies: []
|
@ -19,5 +19,7 @@ galaxy_info:
|
|||||||
documentation: "https://s.veen.world/cymais"
|
documentation: "https://s.veen.world/cymais"
|
||||||
logo:
|
logo:
|
||||||
class: "fa-solid fa-list"
|
class: "fa-solid fa-list"
|
||||||
dependencies:
|
run_after:
|
||||||
- docker-mailu
|
- docker-matomo
|
||||||
|
- docker-keycloak
|
||||||
|
- docker-mailu
|
@ -20,4 +20,8 @@ galaxy_info:
|
|||||||
documentation: "https://s.veen.world/cymais"
|
documentation: "https://s.veen.world/cymais"
|
||||||
logo:
|
logo:
|
||||||
class: "fa-solid fa-satellite-dish"
|
class: "fa-solid fa-satellite-dish"
|
||||||
|
run_after:
|
||||||
|
- docker-matomo
|
||||||
|
- docker-keycloak
|
||||||
|
- docker-mailu
|
||||||
dependencies: []
|
dependencies: []
|
||||||
|
@ -18,4 +18,8 @@ galaxy_info:
|
|||||||
issue_tracker_url: "https://s.veen.world/cymaisissues"
|
issue_tracker_url: "https://s.veen.world/cymaisissues"
|
||||||
documentation: "https://s.veen.world/cymais"
|
documentation: "https://s.veen.world/cymais"
|
||||||
logo:
|
logo:
|
||||||
class: "fa-solid fa-book"
|
class: "fa-solid fa-book"
|
||||||
|
run_after:
|
||||||
|
- docker-matomo
|
||||||
|
- docker-keycloak
|
||||||
|
- docker-mailu
|
@ -19,4 +19,8 @@ galaxy_info:
|
|||||||
logo:
|
logo:
|
||||||
class: "fa-solid fa-calendar-days"
|
class: "fa-solid fa-calendar-days"
|
||||||
run_after:
|
run_after:
|
||||||
- "docker-postgres"
|
- docker-matomo
|
||||||
|
- docker-keycloak
|
||||||
|
- docker-mailu
|
||||||
|
- docker-ldap
|
||||||
|
- docker-postgres
|
||||||
|
@ -19,5 +19,9 @@ galaxy_info:
|
|||||||
documentation: "https://s.veen.world/cymais"
|
documentation: "https://s.veen.world/cymais"
|
||||||
logo:
|
logo:
|
||||||
class: "fa-solid fa-comments"
|
class: "fa-solid fa-comments"
|
||||||
|
run_after:
|
||||||
|
- docker-matomo
|
||||||
|
- docker-keycloak
|
||||||
|
- docker-mailu
|
||||||
dependencies:
|
dependencies:
|
||||||
- nginx-docker-reverse-proxy
|
- nginx-docker-reverse-proxy
|
@ -26,5 +26,9 @@ galaxy_info:
|
|||||||
documentation: "https://s.veen.world/cymais"
|
documentation: "https://s.veen.world/cymais"
|
||||||
logo:
|
logo:
|
||||||
class: "fa-solid fa-box"
|
class: "fa-solid fa-box"
|
||||||
|
run_after:
|
||||||
|
- docker-matomo
|
||||||
|
- docker-keycloak
|
||||||
|
- docker-mailu
|
||||||
dependencies: []
|
dependencies: []
|
||||||
|
|
||||||
|
85
tests/unit/test_generate_playbook.py
Normal file
85
tests/unit/test_generate_playbook.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
# Adjust path to include cli/ folder
|
||||||
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../..", "cli")))
|
||||||
|
|
||||||
|
from generate_playbook import build_dependency_graph, topological_sort, generate_playbook_entries
|
||||||
|
|
||||||
|
class TestGeneratePlaybook(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
# Create a temporary directory to simulate roles
|
||||||
|
self.temp_dir = tempfile.mkdtemp()
|
||||||
|
|
||||||
|
# Define mock roles and dependencies
|
||||||
|
self.roles = {
|
||||||
|
'role-a': {'run_after': [], 'application_id': 'a'},
|
||||||
|
'role-b': {'run_after': ['role-a'], 'application_id': 'b'},
|
||||||
|
'role-c': {'run_after': ['role-b'], 'application_id': 'c'},
|
||||||
|
'role-d': {'run_after': [], 'application_id': 'd'},
|
||||||
|
}
|
||||||
|
|
||||||
|
for role_name, meta in self.roles.items():
|
||||||
|
role_path = os.path.join(self.temp_dir, role_name)
|
||||||
|
os.makedirs(os.path.join(role_path, 'meta'), exist_ok=True)
|
||||||
|
os.makedirs(os.path.join(role_path, 'vars'), exist_ok=True)
|
||||||
|
|
||||||
|
meta_file = {
|
||||||
|
'galaxy_info': {
|
||||||
|
'run_after': meta['run_after']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vars_file = {
|
||||||
|
'application_id': meta['application_id']
|
||||||
|
}
|
||||||
|
|
||||||
|
with open(os.path.join(role_path, 'meta', 'main.yml'), 'w') as f:
|
||||||
|
yaml.dump(meta_file, f)
|
||||||
|
|
||||||
|
with open(os.path.join(role_path, 'vars', 'main.yml'), 'w') as f:
|
||||||
|
yaml.dump(vars_file, f)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
# Clean up the temporary directory
|
||||||
|
shutil.rmtree(self.temp_dir)
|
||||||
|
|
||||||
|
def test_dependency_graph_and_sort(self):
|
||||||
|
graph, in_degree, roles = build_dependency_graph(self.temp_dir)
|
||||||
|
|
||||||
|
self.assertIn('role-a', graph)
|
||||||
|
self.assertIn('role-b', graph)
|
||||||
|
self.assertEqual(graph['role-a'], ['role-b'])
|
||||||
|
self.assertEqual(graph['role-b'], ['role-c'])
|
||||||
|
self.assertEqual(graph['role-c'], [])
|
||||||
|
self.assertEqual(in_degree['role-c'], 1)
|
||||||
|
self.assertEqual(in_degree['role-b'], 1)
|
||||||
|
self.assertEqual(in_degree['role-a'], 0)
|
||||||
|
self.assertEqual(in_degree['role-d'], 0)
|
||||||
|
|
||||||
|
sorted_roles = topological_sort(graph, in_degree)
|
||||||
|
# The expected order must be a → b → c, d can be anywhere before or after
|
||||||
|
self.assertTrue(sorted_roles.index('role-a') < sorted_roles.index('role-b') < sorted_roles.index('role-c'))
|
||||||
|
|
||||||
|
def test_generate_playbook_entries(self):
|
||||||
|
entries = generate_playbook_entries(self.temp_dir)
|
||||||
|
|
||||||
|
text = ''.join(entries)
|
||||||
|
self.assertIn("setup a", text)
|
||||||
|
self.assertIn("setup b", text)
|
||||||
|
self.assertIn("setup c", text)
|
||||||
|
self.assertIn("setup d", text)
|
||||||
|
|
||||||
|
# Order must preserve run_after
|
||||||
|
a_index = text.index("setup a")
|
||||||
|
b_index = text.index("setup b")
|
||||||
|
c_index = text.index("setup c")
|
||||||
|
self.assertTrue(a_index < b_index < c_index)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
Loading…
x
Reference in New Issue
Block a user