built with logos

This commit is contained in:
2025-11-26 20:50:12 -08:00
parent 20bc9f8c6a
commit 98d6399ecb
2 changed files with 45 additions and 10 deletions
+14 -7
View File
@@ -1,13 +1,13 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Portainer templates generator (Portainer CE compatible) Portainer templates generator (Portainer CE compatible, v3 format)
Usage: Usage:
python3 _build/portainer_template_build.py [--nologo] [--branch BRANCH] [--output PATH] [--no-skip-volpath] python3 _build/portainer_template_build.py [--nologo] [--branch BRANCH] [--output PATH] [--no-skip-volpath]
Defaults: Defaults:
branch = master branch = master
output = ./templates.json output = ./templates.json
skips projects containing "${VOL_PATH" by default (use --no-skip-volpath to disable) skips projects containing "${VOL_PATH" by default (use --no-skip-volpath to disable)
Note: Branch is used only for logo asset lookup; templates use default repo branch (master). Note: Generates v3 format with unique IDs to fix compatibility issues in Portainer 2.22+.
""" """
from pathlib import Path from pathlib import Path
import argparse import argparse
@@ -119,11 +119,12 @@ def parse_env_vars(dir_path: Path) -> List[Dict[str,str]]:
# ------------------------- # -------------------------
# Build Portainer template object # Build Portainer template object
# ------------------------- # -------------------------
def generate_template_object(dir_path: Path, branch: str, nologo: bool) -> Dict: def generate_template_object(dir_path: Path, branch: str, nologo: bool, template_id: int) -> Dict:
name = dir_path.name name = dir_path.name
readme_path = dir_path / "README.md" readme_path = dir_path / "README.md"
env_vars = parse_env_vars(dir_path) env_vars = parse_env_vars(dir_path)
obj = { obj = {
"id": template_id, # Unique ID for v3 format
"type": 3, "type": 3,
"title": name, "title": name,
"name": name, "name": name,
@@ -143,7 +144,11 @@ def generate_template_object(dir_path: Path, branch: str, nologo: bool) -> Dict:
for v in env_vars: for v in env_vars:
if not v.get("name"): if not v.get("name"):
continue continue
env_entries.append({"name": v["name"], "label": v["name"], "default": v.get("default","")}) env_entries.append({
"name": v["name"],
"label": v["name"],
"default": v.get("default","")
})
if env_entries: if env_entries:
obj["env"] = env_entries obj["env"] = env_entries
return obj return obj
@@ -164,6 +169,7 @@ def main():
templates = [] templates = []
skipped = [] skipped = []
errored = [] errored = []
template_counter = 1 # Start ID from 1
for item in sorted(REPO_ROOT.iterdir()): for item in sorted(REPO_ROOT.iterdir()):
if not item.is_dir(): if not item.is_dir():
continue continue
@@ -179,14 +185,15 @@ def main():
skipped.append((item.name, "uses ${VOL_PATH}")) skipped.append((item.name, "uses ${VOL_PATH}"))
continue continue
try: try:
tpl = generate_template_object(item, branch=branch, nologo=nologo) tpl = generate_template_object(item, branch=branch, nologo=nologo, template_id=template_counter)
templates.append(tpl) templates.append(tpl)
template_counter += 1
except Exception as e: except Exception as e:
errored.append((item.name, str(e))) errored.append((item.name, str(e)))
output = {"version": "2", "templates": templates} output = {"version": "3", "templates": templates}
# write atomic # write atomic
write_atomic(out_path, json.dumps(output, indent=2)) write_atomic(out_path, json.dumps(output, indent=2))
print(f"Generated {out_path} with {len(templates)} templates.") print(f"Generated {out_path} with {len(templates)} templates (v3 format with IDs).")
if skipped: if skipped:
print("Skipped projects:") print("Skipped projects:")
for n, reason in skipped: for n, reason in skipped:
+31 -3
View File
@@ -1,7 +1,8 @@
{ {
"version": "2", "version": "3",
"templates": [ "templates": [
{ {
"id": 1,
"type": 3, "type": 3,
"title": "archivebox", "title": "archivebox",
"name": "archivebox", "name": "archivebox",
@@ -25,6 +26,7 @@
] ]
}, },
{ {
"id": 2,
"type": 3, "type": 3,
"title": "authentik", "title": "authentik",
"name": "authentik", "name": "authentik",
@@ -41,6 +43,7 @@
} }
}, },
{ {
"id": 3,
"type": 3, "type": 3,
"title": "bookstack", "title": "bookstack",
"name": "bookstack", "name": "bookstack",
@@ -49,7 +52,7 @@
"Auto" "Auto"
], ],
"platform": "linux", "platform": "linux",
"logo": "https://i.4lt.ca/cookbooks/default.png", "logo": "https://i.4lt.ca/cookbooks/bookstack.png",
"description": "BookStack is a self-hosted wiki platform for organizing and storing documentation in a simple, book/chapter/page structure. This Docker Compose stack allows easy deployment with persistent storage.", "description": "BookStack is a self-hosted wiki platform for organizing and storing documentation in a simple, book/chapter/page structure. This Docker Compose stack allows easy deployment with persistent storage.",
"repository": { "repository": {
"url": "https://github.com/nickyeoman/docker-compose-cookbooks", "url": "https://github.com/nickyeoman/docker-compose-cookbooks",
@@ -129,6 +132,7 @@
] ]
}, },
{ {
"id": 4,
"type": 3, "type": 3,
"title": "dockge", "title": "dockge",
"name": "dockge", "name": "dockge",
@@ -145,6 +149,7 @@
} }
}, },
{ {
"id": 5,
"type": 3, "type": 3,
"title": "docmost", "title": "docmost",
"name": "docmost", "name": "docmost",
@@ -161,6 +166,7 @@
} }
}, },
{ {
"id": 6,
"type": 3, "type": 3,
"title": "dozzle", "title": "dozzle",
"name": "dozzle", "name": "dozzle",
@@ -177,6 +183,7 @@
} }
}, },
{ {
"id": 7,
"type": 3, "type": 3,
"title": "etherpad", "title": "etherpad",
"name": "etherpad", "name": "etherpad",
@@ -193,6 +200,7 @@
} }
}, },
{ {
"id": 8,
"type": 3, "type": 3,
"title": "hedgedoc", "title": "hedgedoc",
"name": "hedgedoc", "name": "hedgedoc",
@@ -209,6 +217,7 @@
} }
}, },
{ {
"id": 9,
"type": 3, "type": 3,
"title": "homepage", "title": "homepage",
"name": "homepage", "name": "homepage",
@@ -237,6 +246,7 @@
] ]
}, },
{ {
"id": 10,
"type": 3, "type": 3,
"title": "invoiceninja", "title": "invoiceninja",
"name": "invoiceninja", "name": "invoiceninja",
@@ -455,6 +465,7 @@
] ]
}, },
{ {
"id": 11,
"type": 3, "type": 3,
"title": "joomla", "title": "joomla",
"name": "joomla", "name": "joomla",
@@ -471,6 +482,7 @@
} }
}, },
{ {
"id": 12,
"type": 3, "type": 3,
"title": "listmonk", "title": "listmonk",
"name": "listmonk", "name": "listmonk",
@@ -509,6 +521,7 @@
] ]
}, },
{ {
"id": 13,
"type": 3, "type": 3,
"title": "mariadb", "title": "mariadb",
"name": "mariadb", "name": "mariadb",
@@ -552,6 +565,7 @@
] ]
}, },
{ {
"id": 14,
"type": 3, "type": 3,
"title": "matomo", "title": "matomo",
"name": "matomo", "name": "matomo",
@@ -600,6 +614,7 @@
] ]
}, },
{ {
"id": 15,
"type": 3, "type": 3,
"title": "memos", "title": "memos",
"name": "memos", "name": "memos",
@@ -616,6 +631,7 @@
} }
}, },
{ {
"id": 16,
"type": 3, "type": 3,
"title": "passbolt", "title": "passbolt",
"name": "passbolt", "name": "passbolt",
@@ -669,6 +685,7 @@
] ]
}, },
{ {
"id": 17,
"type": 3, "type": 3,
"title": "peertube", "title": "peertube",
"name": "peertube", "name": "peertube",
@@ -685,6 +702,7 @@
} }
}, },
{ {
"id": 18,
"type": 3, "type": 3,
"title": "penpot", "title": "penpot",
"name": "penpot", "name": "penpot",
@@ -701,6 +719,7 @@
} }
}, },
{ {
"id": 19,
"type": 3, "type": 3,
"title": "phpmyadmin", "title": "phpmyadmin",
"name": "phpmyadmin", "name": "phpmyadmin",
@@ -774,6 +793,7 @@
] ]
}, },
{ {
"id": 20,
"type": 3, "type": 3,
"title": "pihole", "title": "pihole",
"name": "pihole", "name": "pihole",
@@ -807,6 +827,7 @@
] ]
}, },
{ {
"id": 21,
"type": 3, "type": 3,
"title": "posthog", "title": "posthog",
"name": "posthog", "name": "posthog",
@@ -823,6 +844,7 @@
} }
}, },
{ {
"id": 22,
"type": 3, "type": 3,
"title": "prowlarr", "title": "prowlarr",
"name": "prowlarr", "name": "prowlarr",
@@ -856,6 +878,7 @@
] ]
}, },
{ {
"id": 23,
"type": 3, "type": 3,
"title": "redis", "title": "redis",
"name": "redis", "name": "redis",
@@ -884,6 +907,7 @@
] ]
}, },
{ {
"id": 24,
"type": 3, "type": 3,
"title": "rocketchat", "title": "rocketchat",
"name": "rocketchat", "name": "rocketchat",
@@ -917,6 +941,7 @@
] ]
}, },
{ {
"id": 25,
"type": 3, "type": 3,
"title": "shlink", "title": "shlink",
"name": "shlink", "name": "shlink",
@@ -933,6 +958,7 @@
} }
}, },
{ {
"id": 26,
"type": 3, "type": 3,
"title": "thunderbird", "title": "thunderbird",
"name": "thunderbird", "name": "thunderbird",
@@ -941,7 +967,7 @@
"Auto" "Auto"
], ],
"platform": "linux", "platform": "linux",
"logo": "https://i.4lt.ca/cookbooks/default.png", "logo": "https://i.4lt.ca/cookbooks/thunderbird.png",
"description": "Git Hub: https://github.com/jlesage/docker-thunderbird Proxy Port: 5800", "description": "Git Hub: https://github.com/jlesage/docker-thunderbird Proxy Port: 5800",
"repository": { "repository": {
"url": "https://github.com/nickyeoman/docker-compose-cookbooks", "url": "https://github.com/nickyeoman/docker-compose-cookbooks",
@@ -976,6 +1002,7 @@
] ]
}, },
{ {
"id": 27,
"type": 3, "type": 3,
"title": "unami", "title": "unami",
"name": "unami", "name": "unami",
@@ -992,6 +1019,7 @@
} }
}, },
{ {
"id": 28,
"type": 3, "type": 3,
"title": "wallabag", "title": "wallabag",
"name": "wallabag", "name": "wallabag",