|
| 1 | +""" |
| 2 | +Determines if Release conditions are met. |
| 3 | +
|
| 4 | +The script will check the following conditions: |
| 5 | +1. **Is today a release day?** |
| 6 | + - The script checks if today is a specified in ReleaseConfig weekday that falls on the release cycle of the team. |
| 7 | +2. **Is the [Unreleased] section of the CHANGELOG.md not empty?** |
| 8 | + - The script checks if the [Unreleased] section in the CHANGELOG.md contains meaningful entries. |
| 9 | +3. **Does the release branch already exist?** |
| 10 | + - If the release branch for the target release already exists, the script will not run. |
| 11 | +""" |
| 12 | +#!/usr/bin/env python3 |
| 13 | +import datetime |
| 14 | +import re |
| 15 | +import sys |
| 16 | +import os |
| 17 | + |
| 18 | +PARENT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '../ReleaseAutomation')) |
| 19 | +sys.path.insert(0, PARENT_DIR) |
| 20 | + |
| 21 | +from release_config import ReleaseConfig |
| 22 | + |
| 23 | +def is_release_date(weekday, release_week_cycle, anchor_date): |
| 24 | + """ |
| 25 | + Checks if today is a weekday that falls on the release_week_cycle starting from anchor_date . |
| 26 | + Returns True if it is, False otherwise. |
| 27 | + """ |
| 28 | + today = datetime.date.today() |
| 29 | + # Check first if today is given weekday |
| 30 | + # Note as for example you could run a job that utilizes the fact that weekly trigger as per https://internaldocs.unity.com/yamato_continuous_integration/usage/jobs/recurring-jobs/#cron-syntax runs every Saturday, between 2 and 8 AM UTC depending on the load |
| 31 | + if today.weekday() != weekday: |
| 32 | + return False |
| 33 | + |
| 34 | + # Condition 2: Must be on a release_week_cycle interval from the anchor_date. |
| 35 | + days_since_anchor = (today - anchor_date).days |
| 36 | + weeks_since_anchor = days_since_anchor / 7 |
| 37 | + |
| 38 | + # We run on the first week of every release_week_cycle (e.g., week 0, 4, 8, ...) |
| 39 | + return weeks_since_anchor % release_week_cycle == 0 |
| 40 | + |
| 41 | + |
| 42 | +def is_changelog_empty(changelog_path): |
| 43 | + """ |
| 44 | + Checks if the [Unreleased] section in the CHANGELOG.md contains meaningful entries. |
| 45 | + It is considered "empty" if the section only contains headers (like ### Added) but no actual content. |
| 46 | + """ |
| 47 | + if not os.path.exists(changelog_path): |
| 48 | + raise FileNotFoundError(f"Changelog file not found at {changelog_path}") |
| 49 | + |
| 50 | + with open(changelog_path, 'r', encoding='UTF-8') as f: |
| 51 | + content = f.read() |
| 52 | + |
| 53 | + # This pattern starts where Unreleased section is placed |
| 54 | + # Then it matches in the first group all empty sections (only lines that are empty or start with ##) |
| 55 | + # The second group matches the start of the next Changelog entry (## [). |
| 56 | + # if both groups are matched it means that the Unreleased section is empty. |
| 57 | + pattern = re.compile(r"^## \[Unreleased\]\n((?:^###.*\n|^\s*\n)*)(^## \[)", re.MULTILINE) |
| 58 | + match = pattern.search(content) |
| 59 | + |
| 60 | + # If we find a match for the "empty unreleased changelog entry" pattern, it means the changelog IS empty. |
| 61 | + return match |
| 62 | + |
| 63 | + |
| 64 | +def verifyReleaseConditions(config: ReleaseConfig): |
| 65 | + """ |
| 66 | + Function to verify if the release automation job should run. |
| 67 | + This function checks the following conditions: |
| 68 | + 1. If today is a scheduled release day (based on release cycle, weekday and anchor date). |
| 69 | + 2. If the [Unreleased] section of the CHANGELOG.md is not empty. |
| 70 | + 3. If the release branch does not already exist. |
| 71 | + """ |
| 72 | + |
| 73 | + error_messages = [] |
| 74 | + |
| 75 | + try: |
| 76 | + if not is_release_date(config.weekday, config.release_week_cycle, config.anchor_date): |
| 77 | + error_messages.append(f"Condition not met: Today is not the scheduled release day. It should be weekday: {config.weekday}, every {config.release_week_cycle} weeks starting from {config.anchor_date}.") |
| 78 | + |
| 79 | + if is_changelog_empty(config.changelog_path): |
| 80 | + error_messages.append("Condition not met: The [Unreleased] section of the changelog has no meaningful entries.") |
| 81 | + |
| 82 | + if config.github_manager.is_branch_present(config.release_branch_name): |
| 83 | + error_messages.append("Condition not met: The release branch already exists.") |
| 84 | + |
| 85 | + if error_messages: |
| 86 | + print("\n--- Release conditions not met: ---") |
| 87 | + for i, msg in enumerate(error_messages, 1): |
| 88 | + print(f"{i}. {msg}") |
| 89 | + print("\nJob will not run. Exiting.") |
| 90 | + sys.exit(1) |
| 91 | + |
| 92 | + except Exception as e: |
| 93 | + print(f"\n--- ERROR: Release Verification failed ---", file=sys.stderr) |
| 94 | + print(f"Reason: {e}", file=sys.stderr) |
| 95 | + sys.exit(1) |
0 commit comments