Skip to content

Commit 6783f24

Browse files
authored
Merge pull request #94 from meshcloud/feature/custom-oracle
Feature/custom oracle
2 parents 7ac2435 + aa4716a commit 6783f24

File tree

15 files changed

+7956
-315
lines changed

15 files changed

+7956
-315
lines changed
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Generate icon prompts for building blocks missing logo.png files.
4+
Parses README.md frontmatter and creates AI image generation prompts.
5+
"""
6+
7+
import os
8+
import sys
9+
import yaml
10+
import json
11+
from pathlib import Path
12+
13+
PLATFORM_COLORS = {
14+
"aws": {
15+
"primary": "#FF9900",
16+
"secondary": "#232F3E",
17+
"accent": "#7FBA00",
18+
"name": "AWS colors: orange (#FF9900), dark blue (#232F3E), and lime green (#7FBA00)"
19+
},
20+
"azure": {
21+
"primary": "#0078D4",
22+
"secondary": "#00BCF2",
23+
"accent": "#50E6FF",
24+
"name": "Azure colors: blue (#0078D4), cyan (#00BCF2), and light blue (#50E6FF)"
25+
},
26+
"aks": {
27+
"primary": "#326CE5",
28+
"secondary": "#0078D4",
29+
"accent": "#00BCF2",
30+
"name": "Kubernetes/Azure colors: blue (#326CE5), Azure blue (#0078D4), and cyan (#00BCF2)"
31+
},
32+
"azuredevops": {
33+
"primary": "#0078D4",
34+
"secondary": "#00BCF2",
35+
"accent": "#005A9E",
36+
"name": "Azure DevOps colors: blue (#0078D4), teal (#00BCF2), and dark blue (#005A9E)"
37+
},
38+
"gcp": {
39+
"primary": "#4285F4",
40+
"secondary": "#EA4335",
41+
"accent": "#FBBC04",
42+
"name": "Google colors: blue (#4285F4), red (#EA4335), yellow (#FBBC04), and green (#34A853)"
43+
},
44+
"github": {
45+
"primary": "#6e5494",
46+
"secondary": "#24292e",
47+
"accent": "#8b5cf6",
48+
"name": "GitHub colors: purple (#6e5494), dark gray (#24292e), and bright purple (#8b5cf6)"
49+
},
50+
"ionos": {
51+
"primary": "#003D7A",
52+
"secondary": "#FF6600",
53+
"accent": "#0096D6",
54+
"name": "IONOS colors: blue (#003D7A), orange (#FF6600), and light blue (#0096D6)"
55+
},
56+
"kubernetes": {
57+
"primary": "#326CE5",
58+
"secondary": "#00D3E0",
59+
"accent": "#7AB8FF",
60+
"name": "Kubernetes colors: blue (#326CE5), cyan (#00D3E0), and light blue (#7AB8FF)"
61+
},
62+
"oci": {
63+
"primary": "#F80000",
64+
"secondary": "#312D2A",
65+
"accent": "#C74634",
66+
"name": "Oracle colors: red (#F80000), charcoal (#312D2A), and burnt orange (#C74634)"
67+
},
68+
"sapbtp": {
69+
"primary": "#0070AD",
70+
"secondary": "#F0AB00",
71+
"accent": "#0078D4",
72+
"name": "SAP colors: blue (#0070AD), gold (#F0AB00), and light blue (#0078D4)"
73+
},
74+
"stackit": {
75+
"primary": "#00A859",
76+
"secondary": "#007A3D",
77+
"accent": "#7FBA00",
78+
"name": "STACKIT colors: green (#00A859), dark green (#007A3D), and lime (#7FBA00)"
79+
}
80+
}
81+
82+
83+
84+
def parse_readme_frontmatter(readme_path):
85+
"""Extract YAML frontmatter from README.md"""
86+
with open(readme_path, 'r', encoding='utf-8') as f:
87+
content = f.read()
88+
89+
if not content.startswith('---'):
90+
return None
91+
92+
# Extract frontmatter between --- delimiters
93+
parts = content.split('---', 2)
94+
if len(parts) < 3:
95+
return None
96+
97+
try:
98+
frontmatter = yaml.safe_load(parts[1])
99+
return frontmatter
100+
except yaml.YAMLError:
101+
return None
102+
103+
104+
def get_platform_from_frontmatter(frontmatter):
105+
"""Get the primary platform from supportedPlatforms list"""
106+
platforms = frontmatter.get('supportedPlatforms', [])
107+
if not platforms:
108+
return None
109+
return platforms[0] # Use first platform
110+
111+
112+
def generate_icon_prompt(name, platform, description):
113+
"""Generate an AI image generation prompt for an icon"""
114+
platform_colors = PLATFORM_COLORS.get(platform)
115+
116+
if not platform_colors:
117+
# Fallback to generic bright colors
118+
color_scheme = "bright, vibrant colors"
119+
else:
120+
color_scheme = platform_colors["name"]
121+
122+
# Clean up description
123+
clean_description = description.strip().replace('\n', ' ')
124+
125+
# Generate AI prompt
126+
ai_prompt = f"""Create a professional flat design icon for the meshcloud Building Block ecosystem.
127+
128+
Purpose: {clean_description}
129+
130+
Visual Style:
131+
- Plain white background (#FFFFFF) for easy removal in post-processing
132+
- Background will be converted to transparent (see post-processing steps)
133+
- Use {color_scheme} as accent colors
134+
- Maximum 2-3 colors total
135+
- Simple geometric shapes with clean lines
136+
- Flat design (no gradients, shadows, or 3D effects)
137+
- Minimalist, modern appearance
138+
139+
Composition:
140+
- Square centered layout (NOT horizontal)
141+
- Icon fills the entire canvas edge-to-edge (100% of area)
142+
- No padding or margins around the icon
143+
- Symmetrical arrangement
144+
- Platform-appropriate symbol for {platform.upper()} (e.g., cloud, container, database, server, etc.)
145+
146+
Style: Enterprise professional, instantly recognizable at small sizes, similar to app icons or logos.
147+
Dimensions: 800x800 pixels"""
148+
149+
# Generate post-processing instructions
150+
post_processing = """**Step 1: Remove white background with GIMP (free)**
151+
152+
a) Open image in GIMP
153+
b) Right-click layer → "Add Alpha Channel"
154+
c) Tools → "Select by Color" (Shift+O)
155+
d) Click white background
156+
e) Press Delete key
157+
f) File → Export As → logo.png
158+
g) Set Compression level to 9 → Export
159+
160+
**Step 2: Resize to 800x800 pixels if needed**
161+
162+
- GIMP: Image → Scale Image → 800x800px
163+
- Or use any image editor
164+
165+
**Step 3: Compress with pngquant (free command line tool)**
166+
167+
- Install: `brew install pngquant` (Mac) or `apt install pngquant` (Linux)
168+
- Run: `pngquant --quality=20-30 logo.png --ext .png --force`
169+
- This reduces file size by 60-80% while maintaining quality
170+
171+
**Target specs:** 800x800px PNG with transparent background, under 100KB"""
172+
173+
return {
174+
'ai_prompt': ai_prompt,
175+
'post_processing': post_processing
176+
}
177+
178+
def find_missing_logos(modules_dir):
179+
"""Find all buildingblock directories missing logo.png"""
180+
missing = []
181+
182+
for root, dirs, files in os.walk(modules_dir):
183+
if 'buildingblock' in root:
184+
buildingblock_path = Path(root)
185+
readme_path = buildingblock_path / 'README.md'
186+
logo_path = buildingblock_path / 'logo.png'
187+
188+
if readme_path.exists() and not logo_path.exists():
189+
frontmatter = parse_readme_frontmatter(readme_path)
190+
if frontmatter:
191+
platform = get_platform_from_frontmatter(frontmatter)
192+
name = frontmatter.get('name', 'Unknown')
193+
description = frontmatter.get('description', '')
194+
195+
# Get relative path from modules directory
196+
rel_path = buildingblock_path.relative_to(modules_dir)
197+
198+
missing.append({
199+
'path': str(rel_path),
200+
'name': name,
201+
'platform': platform,
202+
'description': description,
203+
'readme_path': str(readme_path),
204+
'logo_path': str(logo_path)
205+
})
206+
207+
return missing
208+
209+
def main():
210+
# Get modules directory
211+
repo_root = Path(__file__).parent.parent.parent
212+
modules_dir = repo_root / 'modules'
213+
214+
if not modules_dir.exists():
215+
print(f"ERROR: Modules directory not found: {modules_dir}", file=sys.stderr)
216+
sys.exit(1)
217+
218+
# Find missing logos
219+
missing_logos = find_missing_logos(modules_dir)
220+
221+
# Generate prompts for each missing logo
222+
results = []
223+
for item in missing_logos:
224+
prompt_data = generate_icon_prompt(
225+
item['name'],
226+
item['platform'] or 'generic',
227+
item['description']
228+
)
229+
230+
results.append({
231+
'name': item['name'],
232+
'platform': item['platform'],
233+
'path': item['path'],
234+
'logo_path': item['logo_path'],
235+
'ai_prompt': prompt_data['ai_prompt'],
236+
'post_processing': prompt_data['post_processing']
237+
})
238+
239+
# Output as JSON for GitHub Action to consume
240+
print(json.dumps(results, indent=2))
241+
242+
if __name__ == '__main__':
243+
main()

.github/workflows/icon-prompts.yml

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
name: Generate Icon Prompts for Missing Logos
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
paths:
7+
- 'modules/**/buildingblock/README.md'
8+
9+
permissions:
10+
pull-requests: write
11+
contents: read
12+
13+
jobs:
14+
check-missing-logos:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@v4
19+
20+
- name: Set up Python
21+
uses: actions/setup-python@v5
22+
with:
23+
python-version: '3.11'
24+
25+
- name: Install dependencies
26+
run: |
27+
pip install pyyaml
28+
29+
- name: Find missing logos and generate prompts
30+
id: generate
31+
run: |
32+
python .github/scripts/generate-icon-prompts.py > prompts.json
33+
COUNT=$(jq 'length' prompts.json)
34+
echo "has_missing=$([ "$COUNT" -gt 0 ] && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
35+
echo "count=$COUNT" >> $GITHUB_OUTPUT
36+
37+
- name: Read prompts
38+
if: steps.generate.outputs.has_missing == 'true'
39+
id: read_prompts
40+
run: |
41+
PROMPTS=$(cat prompts.json)
42+
echo "prompts<<EOF" >> $GITHUB_OUTPUT
43+
echo "$PROMPTS" >> $GITHUB_OUTPUT
44+
echo "EOF" >> $GITHUB_OUTPUT
45+
46+
- name: Generate PR comment
47+
if: steps.generate.outputs.has_missing == 'true'
48+
id: format_comment
49+
uses: actions/github-script@v7
50+
env:
51+
PROMPTS_JSON: ${{ steps.read_prompts.outputs.prompts }}
52+
with:
53+
result-encoding: string
54+
script: |
55+
const prompts = JSON.parse(process.env.PROMPTS_JSON);
56+
57+
if (prompts.length === 0) {
58+
return '';
59+
}
60+
61+
let comment = '## 🎨 Missing Building Block Icons\n\n';
62+
comment += `Found **${prompts.length}** building block(s) without \`logo.png\` files.\n\n`;
63+
comment += 'Copy the **AI Prompts** below and use them with your favorite AI image generator (Gemini, DALL-E, Midjourney, Stable Diffusion, etc.).\n\n';
64+
comment += 'Then follow the **Post-Processing Steps** to prepare the icons for upload.\n\n';
65+
comment += '---\n\n';
66+
67+
for (const item of prompts) {
68+
comment += `### ${item.name}\n\n`;
69+
comment += `**Platform:** \`${item.platform}\`\n\n`;
70+
comment += `**Path:** \`${item.logo_path}\`\n\n`;
71+
comment += '#### AI Prompt (copy this to image generator)\n\n';
72+
comment += '```\n';
73+
comment += item.ai_prompt;
74+
comment += '\n```\n\n';
75+
comment += '#### Post-Processing Instructions\n\n';
76+
comment += item.post_processing;
77+
comment += '\n\n';
78+
comment += '---\n\n';
79+
}
80+
81+
return comment;
82+
83+
- name: Find existing comment
84+
if: steps.generate.outputs.has_missing == 'true'
85+
uses: peter-evans/find-comment@v3
86+
id: find_comment
87+
with:
88+
issue-number: ${{ github.event.pull_request.number }}
89+
comment-author: 'github-actions[bot]'
90+
body-includes: '🎨 Missing Building Block Icons'
91+
92+
- name: Create or update comment
93+
if: steps.generate.outputs.has_missing == 'true'
94+
uses: peter-evans/create-or-update-comment@v4
95+
with:
96+
comment-id: ${{ steps.find_comment.outputs.comment-id }}
97+
issue-number: ${{ github.event.pull_request.number }}
98+
body: ${{ steps.format_comment.outputs.result }}
99+
edit-mode: replace
100+
101+
- name: Success message
102+
if: steps.generate.outputs.has_missing == 'false'
103+
run: |
104+
echo "✅ All building blocks have logo.png files!"

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,8 @@ yarn-error.log*
2020
*tfvars*
2121
.terraform.lock.hcl
2222
.env
23+
24+
# Generated assets
25+
website/public/assets/building-block-logos/
26+
website/public/assets/logos/
27+
website/public/assets/*.json

0 commit comments

Comments
 (0)