@@ -242,74 +242,7 @@ jobs:
242242 echo "$AI_RESPONSE" > .tmp/final-notes.txt
243243 else
244244 echo "⚠️ AI unavailable - generating concise user-friendly summaries from raw notes"
245-
246- python3 <<'PYTHON_EOF'
247- import os
248- import re
249-
250- raw = os.environ.get("RAW_NOTES", "")
251- lines = raw.splitlines()
252-
253- output = []
254- seen = set()
255-
256- def clean_line(text: str) -> str:
257- text = text.strip()
258- if not text:
259- return ""
260-
261- # Drop markdown headers/changelog lines.
262- if re.match(r"^#+\s", text, flags=re.I):
263- return ""
264- if re.match(r"^\*\*?\s*full\s+changelog", text, flags=re.I):
265- return ""
266- if re.match(r"^full\s+changelog", text, flags=re.I):
267- return ""
268-
269- text = re.sub(r"^[\s\-*•]+", "", text)
270- text = re.sub(r"\s+by\s+@?[a-zA-Z0-9_-]+\s+in\s+https?://\S+", "", text)
271- text = re.sub(r"\s+by\s+@?[a-zA-Z0-9_-]+\s*$", "", text)
272- text = re.sub(r"@([a-zA-Z0-9_-]+)", "", text)
273- text = re.sub(r"\s*\([^)]*#\d+\)\s*$", "", text)
274- text = re.sub(r"\s+#\d+\s*$", "", text)
275- text = re.sub(r"\s+", " ", text).strip(" .:-")
276-
277- if len(text) < 8:
278- return ""
279-
280- # Make user-friendly short title + summary when possible.
281- if ":" in text:
282- left, right = [p.strip() for p in text.split(":", 1)]
283- left = left[:40].rstrip(" .")
284- right_words = right.split()
285- right = " ".join(right_words[:14]).rstrip(" .")
286- text = f"{left}: {right}" if right else left
287- else:
288- words = text.split()
289- if len(words) > 16:
290- text = " ".join(words[:16]).rstrip(" .")
291-
292- return text
293-
294- for line in lines:
295- cleaned = clean_line(line)
296- if not cleaned:
297- continue
298-
299- # Normalize casing and deduplicate.
300- cleaned = cleaned[0].upper() + cleaned[1:] if cleaned else cleaned
301- key = cleaned.lower()
302- if key in seen:
303- continue
304- seen.add(key)
305-
306- output.append(f"* {cleaned}")
307- if len(output) >= 8:
308- break
309-
310- with open('.tmp/final-notes.txt', 'w', encoding='utf-8') as f:
311- f.write("\n".join(output))
312- PYTHON_EOF
245+ python3 .github/scripts/format-studio-release-notes.py
313246 fi
314247
315248 # Normalize bullets to "* " even if AI returns "- ".
@@ -454,137 +387,8 @@ jobs:
454387 exit 0
455388 fi
456389
457- # Use Python for smart version range handling
458- python3 <<'PYTHON_EOF'
459- import os
460- import re
461- from packaging.version import Version, InvalidVersion
462-
463- studio_ver = os.environ["STUDIO_VERSION"]
464- abp_ver = os.environ["ABP_VERSION"]
465- file_path = "docs/en/studio/version-mapping.md"
390+ python3 .github/scripts/update-studio-version-mapping.py
466391
467- try:
468- studio = Version(studio_ver)
469- except InvalidVersion:
470- print(f"❌ Invalid Studio version: {studio_ver}")
471- exit(1)
472-
473- with open(file_path, 'r') as f:
474- lines = f.readlines()
475-
476- # Find table start (skip SEO and headers)
477- table_start = 0
478- table_end = 0
479- for i, line in enumerate(lines):
480- if line.strip().startswith('|') and '**ABP Studio Version**' in line:
481- table_start = i
482- elif table_start > 0 and line.strip() and not line.strip().startswith('|'):
483- table_end = i
484- break
485-
486- if table_start == 0:
487- print("❌ Could not find version mapping table")
488- exit(1)
489-
490- # If no end found, table goes to end of file
491- if table_end == 0:
492- table_end = len(lines)
493-
494- # Extract sections
495- before_table = lines[:table_start] # Everything before table
496- table_header = lines[table_start:table_start+2] # Header + separator
497- data_rows = [l for l in lines[table_start+2:table_end] if l.strip().startswith('|')] # Data rows
498- after_table = lines[table_end:] # Everything after table
499-
500- new_rows = []
501- handled = False
502-
503- def parse_version_range(version_str):
504- """Parse '2.1.5 - 2.1.9' or '2.1.5' into (start, end)"""
505- version_str = version_str.strip()
506-
507- if '–' in version_str or '-' in version_str:
508- # Handle both em-dash and hyphen
509- parts = re.split(r'\s*[–-]\s*', version_str)
510- if len(parts) == 2:
511- try:
512- return Version(parts[0].strip()), Version(parts[1].strip())
513- except InvalidVersion:
514- return None, None
515-
516- try:
517- v = Version(version_str)
518- return v, v
519- except InvalidVersion:
520- return None, None
521-
522- def format_row(studio_range, abp_version):
523- """Format a table row with proper spacing"""
524- return f"| {studio_range:<22} | {abp_version:<27} |\n"
525-
526- # Process existing rows
527- for row in data_rows:
528- match = re.match(r'\|\s*(.+?)\s*\|\s*(.+?)\s*\|', row)
529- if not match:
530- continue
531-
532- existing_studio_range = match.group(1).strip()
533- existing_abp = match.group(2).strip()
534-
535- # Only consider rows with matching ABP version
536- if existing_abp != abp_ver:
537- new_rows.append(row)
538- continue
539-
540- start_ver, end_ver = parse_version_range(existing_studio_range)
541-
542- if start_ver is None or end_ver is None:
543- new_rows.append(row)
544- continue
545-
546- # Check if current studio version is in this range
547- if start_ver <= studio <= end_ver:
548- print(f"✅ Studio version {studio_ver} already covered in range {existing_studio_range}")
549- handled = True
550- new_rows.append(row)
551-
552- # Check if we should extend the range
553- elif end_ver < studio:
554- # Calculate if studio is the next logical version
555- # For patch versions: 2.1.9 -> 2.1.10
556- # For minor versions: 2.1.9 -> 2.2.0
557-
558- # Simple heuristic: if major.minor match and patch increments, extend range
559- if (start_ver.major == studio.major and
560- start_ver.minor == studio.minor and
561- studio.micro <= end_ver.micro + 5): # Allow small gaps
562-
563- new_range = f"{start_ver} - {studio}"
564- new_rows.append(format_row(new_range, abp_ver))
565- print(f"✅ Extended range: {new_range}")
566- handled = True
567- else:
568- new_rows.append(row)
569- else:
570- new_rows.append(row)
571-
572- # If not handled, add new row at top of data
573- if not handled:
574- new_row = format_row(str(studio), abp_ver)
575- new_rows.insert(0, new_row)
576- print(f"✅ Added new mapping: {studio_ver} -> {abp_ver}")
577-
578- # Write updated file - preserve ALL content
579- with open(file_path, 'w') as f:
580- f.writelines(before_table) # SEO, title, intro text
581- f.writelines(table_header) # Table header
582- f.writelines(new_rows) # Updated data rows
583- f.writelines(after_table) # Content after table (preview section, etc.)
584-
585- print("MAPPING_UPDATED=true")
586- PYTHON_EOF
587-
588392 echo "MAPPING_UPDATED=true" >> $GITHUB_ENV
589393
590394 echo "=== Updated version-mapping.md preview ==="
0 commit comments