Parses the RST release note text to extract key information.
(rst_text)
| 42 | |
| 43 | |
| 44 | def parse_rst_release_note(rst_text): |
| 45 | """Parses the RST release note text to extract key information.""" |
| 46 | data = { |
| 47 | 'version': None, |
| 48 | 'release_date': None, |
| 49 | 'features': [], |
| 50 | 'bug_fixes': [], |
| 51 | 'housekeeping': [] |
| 52 | } |
| 53 | |
| 54 | version_match = re.search(r'Version\s+([^\n\*]+)', rst_text) |
| 55 | if version_match: |
| 56 | data['version'] = version_match.group(1).strip() |
| 57 | else: |
| 58 | print("Warning: Could not parse version.", file=sys.stderr) |
| 59 | |
| 60 | date_match = re.search(r'Release date:\s*(\d{4}-\d{2}-\d{2})', rst_text) |
| 61 | if date_match: |
| 62 | data['release_date'] = date_match.group(1).strip() |
| 63 | else: |
| 64 | print("Warning: Could not parse release date.", file=sys.stderr) |
| 65 | |
| 66 | current_section_list = None |
| 67 | lines = rst_text.splitlines() |
| 68 | |
| 69 | for i, line_raw in enumerate(lines): |
| 70 | line_stripped = line_raw.strip() |
| 71 | if i > 0: |
| 72 | prev_line_stripped = lines[i - 1].strip() |
| 73 | # Check if the previous line looks like an RST section underline |
| 74 | if len(prev_line_stripped) > 3 and \ |
| 75 | all(c == '*' for c in prev_line_stripped): |
| 76 | if i > 1: |
| 77 | # Header text is two lines above the current line |
| 78 | header_text_line = lines[i - 2].strip().lower() |
| 79 | if "new features" in header_text_line: |
| 80 | current_section_list = data['features'] |
| 81 | elif "bug fixes" in header_text_line: |
| 82 | current_section_list = data['bug_fixes'] |
| 83 | elif "housekeeping" in header_text_line: |
| 84 | current_section_list = data['housekeeping'] |
| 85 | else: |
| 86 | # Not a section we track, keep previous section active |
| 87 | pass |
| 88 | # Skip the (usually blank) line after the underline |
| 89 | continue |
| 90 | |
| 91 | # Parse items only if we are within a known section |
| 92 | if current_section_list is not None and line_stripped.startswith('|'): |
| 93 | line_to_parse = line_stripped |
| 94 | # Try matching the standard 'Issue #' format |
| 95 | item_match = re.match( |
| 96 | r'\|\s*`Issue\s+#(\d+)\s+<([^>]+)>`_\s*-\s*(.*)', |
| 97 | line_to_parse |
| 98 | ) |
| 99 | if item_match: |
| 100 | issue_num, url, description = item_match.groups() |
| 101 | item_data = { |
no test coverage detected