Skip to content

Commit 6dc9c9f

Browse files
feat: add landscape cleanup action and prune orphaned logos
Signed-off-by: Ayush-Patel-56 <[email protected]>
1 parent c9c7282 commit 6dc9c9f

3 files changed

Lines changed: 153 additions & 0 deletions

File tree

.github/workflows/cleanup.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Landscape Cleanup
2+
3+
on:
4+
schedule:
5+
- cron: '0 0 * * 1' # Weekly on Monday
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: write
10+
pull-requests: write
11+
12+
jobs:
13+
cleanup:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Checkout repository
17+
uses: actions/checkout@v3
18+
19+
- name: Set up Python
20+
uses: actions/setup-python@v4
21+
with:
22+
python-version: '3.10'
23+
24+
- name: Install dependencies
25+
run: |
26+
pip install -r scripts/requirements.txt
27+
28+
- name: Run cleanup script
29+
run: |
30+
python scripts/cleanup.py --fix
31+
32+
- name: Create Pull Request
33+
uses: peter-evans/create-pull-request@v5
34+
with:
35+
token: ${{ secrets.GITHUB_TOKEN }}
36+
commit-message: "chore: landscape cleanup (orphaned logos, normalization)"
37+
title: "chore: landscape cleanup"
38+
body: |
39+
Automated landscape cleanup.
40+
- Removed orphaned logo files.
41+
- Normalized logo paths in landscape.yml.
42+
branch: automated-cleanup
43+
base: master
44+
delete-branch: true

scripts/cleanup.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import os
2+
import sys
3+
import argparse
4+
from ruamel.yaml import YAML
5+
6+
# Adjust paths
7+
LANDSCAPE_FILE = 'landscape.yml'
8+
LOGOS_DIR = 'hosted_logos'
9+
10+
def get_yaml_parser():
11+
yaml = YAML()
12+
yaml.preserve_quotes = True
13+
yaml.indent(mapping=2, sequence=4, offset=2)
14+
yaml.width = 4096
15+
return yaml
16+
17+
def load_landscape(yaml_parser):
18+
with open(LANDSCAPE_FILE, 'r', encoding='utf-8') as f:
19+
return yaml_parser.load(f)
20+
21+
def save_landscape(yaml_parser, data):
22+
with open(LANDSCAPE_FILE, 'w', encoding='utf-8') as f:
23+
yaml_parser.dump(data, f)
24+
25+
def normalize_logo_path(path):
26+
if path and path.startswith('./'):
27+
return path[2:]
28+
return path
29+
30+
def process_landscape(data, fix=False):
31+
referenced_logos = set()
32+
modified = False
33+
34+
if 'landscape' in data:
35+
for category in data['landscape']:
36+
for subcategory in category.get('subcategories', []):
37+
for item in subcategory.get('items', []):
38+
logo = item.get('logo')
39+
if logo:
40+
normalized = normalize_logo_path(logo)
41+
if normalized != logo:
42+
print(f"Normalizing logo: {logo} -> {normalized}")
43+
if fix:
44+
item['logo'] = normalized
45+
modified = True
46+
referenced_logos.add(normalized)
47+
else:
48+
referenced_logos.add(logo)
49+
return referenced_logos, modified
50+
51+
def get_hosted_logos():
52+
if not os.path.exists(LOGOS_DIR):
53+
print(f"Error: {LOGOS_DIR} dir not found")
54+
return set()
55+
return set(os.listdir(LOGOS_DIR))
56+
57+
def main():
58+
parser = argparse.ArgumentParser(description='Cleanup landscape logos')
59+
parser.add_argument('--fix', action='store_true', help='Apply fixes (delete orphans, update yaml)')
60+
args = parser.parse_args()
61+
62+
print("Loading landscape...")
63+
yaml_parser = get_yaml_parser()
64+
try:
65+
data = load_landscape(yaml_parser)
66+
except FileNotFoundError:
67+
print(f"Error: {LANDSCAPE_FILE} not found. Please run from the repo root.")
68+
return
69+
70+
referenced_logos, modified = process_landscape(data, fix=args.fix)
71+
hosted_logos = get_hosted_logos()
72+
73+
print(f"Referenced logos: {len(referenced_logos)}")
74+
print(f"Hosted logos: {len(hosted_logos)}")
75+
76+
missing_logos = referenced_logos - hosted_logos
77+
orphaned_logos = hosted_logos - referenced_logos
78+
79+
print(f"Missing logos (referenced but not found): {len(missing_logos)}")
80+
for logo in missing_logos:
81+
print(f" MISSING: {logo}")
82+
83+
print(f"Orphaned logos (found but not referenced): {len(orphaned_logos)}")
84+
85+
if args.fix:
86+
if orphaned_logos:
87+
print(f"Deleting {len(orphaned_logos)} orphaned logos...")
88+
for logo in orphaned_logos:
89+
path = os.path.join(LOGOS_DIR, logo)
90+
try:
91+
os.remove(path)
92+
print(f" Deleted: {logo}")
93+
except OSError as e:
94+
print(f" Error deleting {logo}: {e}")
95+
96+
if modified:
97+
print(f"Saving {LANDSCAPE_FILE}...")
98+
save_landscape(yaml_parser, data)
99+
else:
100+
print("No changes to landscape.yml needed.")
101+
else:
102+
if orphaned_logos:
103+
print("Run with --fix to delete orphaned logos.")
104+
if modified: # modified will be false if not fix, but conceptually changes are pending
105+
pass # logic above only modifies if fix is True.
106+
107+
if __name__ == "__main__":
108+
main()

scripts/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ruamel.yaml

0 commit comments

Comments
 (0)