Skip to content

Commit 74450e4

Browse files
committed
init commit and first pass at scaffolding MLab UI components
1 parent a7425dd commit 74450e4

172 files changed

Lines changed: 21086 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import os
2+
import re
3+
import subprocess
4+
5+
PAGES_DIR = "src/content/pages"
6+
PERMALINK_REGEX = re.compile(r'^(\s*permalink\s*:\s*)(.+?)(\s*)$', re.IGNORECASE)
7+
8+
def run(cmd):
9+
try:
10+
return subprocess.check_output(cmd, stderr=subprocess.DEVNULL).decode().strip()
11+
except Exception:
12+
return ""
13+
14+
def safe_filename(text: str) -> str:
15+
return text.strip().replace(" ", "-")
16+
17+
# -------------------------------------------------
18+
# ✅ Determine correct git diff base (PR vs push)
19+
# -------------------------------------------------
20+
BASE_REF = os.environ.get("GITHUB_BASE_REF")
21+
22+
if BASE_REF:
23+
diff_base = f"origin/{BASE_REF}"
24+
else:
25+
diff_base = "HEAD~1"
26+
27+
# -------------------------------------------------
28+
# ✅ Get changed files INCLUDING renames
29+
# -------------------------------------------------
30+
diff_output = run([
31+
"git", "diff", "--name-status", diff_base
32+
]).splitlines()
33+
34+
changes = []
35+
36+
for line in diff_output:
37+
if not line:
38+
continue
39+
40+
parts = line.split("\t")
41+
status = parts[0]
42+
43+
if status.startswith("R"): # Rename detected
44+
old_path = parts[1]
45+
new_path = parts[2]
46+
changes.append(("rename", old_path, new_path))
47+
elif status == "M":
48+
changes.append(("modify", parts[1]))
49+
50+
# -------------------------------------------------
51+
# ✅ HANDLE FILE RENAMES → UPDATE PERMALINK
52+
# -------------------------------------------------
53+
for change in changes:
54+
if change[0] != "rename":
55+
continue
56+
57+
old_path, new_path = change[1], change[2]
58+
59+
if not new_path.startswith(PAGES_DIR) or not new_path.endswith(".yaml"):
60+
continue
61+
62+
filename = os.path.basename(new_path)
63+
filename_without_ext = os.path.splitext(filename)[0]
64+
inferred_permalink = safe_filename(filename_without_ext)
65+
66+
try:
67+
with open(new_path, "r", encoding="utf-8") as f:
68+
lines = f.readlines()
69+
except Exception:
70+
continue
71+
72+
updated = False
73+
74+
for i, line in enumerate(lines):
75+
match = PERMALINK_REGEX.match(line)
76+
if match:
77+
prefix, _, suffix = match.groups()
78+
lines[i] = f"{prefix}{inferred_permalink}{suffix}\n"
79+
updated = True
80+
break
81+
82+
if not updated:
83+
if lines:
84+
lines.insert(1, f"permalink: {inferred_permalink}\n")
85+
else:
86+
lines.append(f"permalink: {inferred_permalink}\n")
87+
88+
try:
89+
with open(new_path, "w", encoding="utf-8") as f:
90+
f.writelines(lines)
91+
print(f"✅ Updated permalink from filename: {new_path}{inferred_permalink}")
92+
except Exception:
93+
pass
94+
95+
# -------------------------------------------------
96+
# ✅ HANDLE PERMALINK CHANGES → RENAME FILE
97+
# -------------------------------------------------
98+
for change in changes:
99+
if change[0] != "modify":
100+
continue
101+
102+
file_path = change[1]
103+
104+
if not file_path.startswith(PAGES_DIR) or not file_path.endswith(".yaml"):
105+
continue
106+
107+
filename = os.path.basename(file_path)
108+
root = os.path.dirname(file_path)
109+
110+
try:
111+
new_content = run(["git", "show", f"HEAD:{file_path}"])
112+
old_content = run(["git", "show", f"{diff_base}:{file_path}"])
113+
except Exception:
114+
continue
115+
116+
old_permalink = None
117+
new_permalink = None
118+
119+
for line in old_content.splitlines():
120+
match = PERMALINK_REGEX.match(line)
121+
if match:
122+
old_permalink = match.group(2).strip().strip('"\'')
123+
break
124+
125+
for line in new_content.splitlines():
126+
match = PERMALINK_REGEX.match(line)
127+
if match:
128+
new_permalink = match.group(2).strip().strip('"\'')
129+
break
130+
131+
# ✅ Only act when permalink actually changed
132+
if new_permalink and new_permalink != old_permalink:
133+
expected_filename = f"{safe_filename(new_permalink)}.yaml"
134+
expected_path = os.path.join(root, expected_filename)
135+
136+
if os.path.basename(file_path) != expected_filename:
137+
if not os.path.exists(expected_path):
138+
try:
139+
os.rename(file_path, expected_path)
140+
print(f"✅ Renamed from permalink: {file_path}{expected_path}")
141+
except Exception:
142+
pass
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Auto-Fix Page Permalinks (Bidirectional)
2+
3+
on:
4+
push:
5+
paths:
6+
- "src/content/pages/**/*.yaml"
7+
pull_request:
8+
paths:
9+
- "src/content/pages/**/*.yaml"
10+
11+
jobs:
12+
auto-fix:
13+
runs-on: ubuntu-latest
14+
15+
permissions:
16+
contents: write
17+
18+
steps:
19+
- name: Checkout repository with full history
20+
uses: actions/checkout@v4
21+
with:
22+
fetch-depth: 0
23+
24+
- name: Set up Python
25+
uses: actions/setup-python@v5
26+
with:
27+
python-version: "3.x"
28+
29+
- name: Run bidirectional permalink sync
30+
run: |
31+
python .github/scripts/auto_fix_permalinks.py
32+
33+
- name: Commit and push changes (if any)
34+
run: |
35+
if [[ -n "$(git status --porcelain)" ]]; then
36+
git config user.name "github-actions[bot]"
37+
git config user.email "github-actions[bot]@users.noreply.github.com"
38+
git add src/content/pages
39+
git commit -m "Auto-sync permalink and filename"
40+
git push
41+
else
42+
echo "No permalink or filename changes to commit."
43+
fi

.gitignore

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# build output
2+
dist/
3+
# generated types
4+
.astro/
5+
6+
# dependencies
7+
node_modules/
8+
9+
# logs
10+
npm-debug.log*
11+
yarn-debug.log*
12+
yarn-error.log*
13+
pnpm-debug.log*
14+
15+
16+
# environment variables
17+
.env
18+
.env.production
19+
20+
# macOS-specific files
21+
.DS_Store
22+
23+
# jetbrains setting folder
24+
.idea/
25+
26+
# Local Netlify folder
27+
.netlify
28+
29+
# Local configuration
30+
.localconfig/

0 commit comments

Comments
 (0)