| """Utilities related to the Cast branching scheme.""" |
| |
| from __future__ import absolute_import |
| import re |
| |
| RELEASE_BRANCH_PATTERN = r'(?P<major>\d+)\.(?P<minor>\d+)(?P<version>.+)?' |
| # See go/nest-tv-branch-strategy. |
| ANDROID_TV_RELEASE_BRANCH_PATTERN = (r'^android(\d+)-(\d+\.\d+)-(.+)' |
| r'-(factory|ota)(|\d+)$') |
| |
| |
| def parse_release_branch(branch_name): |
| """Converts string branch_name to tuple (int major, int minor, version).""" |
| match = re.match(RELEASE_BRANCH_PATTERN, branch_name) |
| if not match: |
| raise ValueError('Invalid branch name: {}'.format(branch_name)) |
| major = int(match.group('major')) |
| minor = int(match.group('minor')) |
| version = match.group('version') |
| try: |
| version = int(version) |
| except (TypeError, ValueError): |
| pass |
| return major, minor, version |
| |
| |
| def is_release_branch(branch): |
| """Returns True if |branch| matching release branch patterns.""" |
| return (branch and |
| (re.match(RELEASE_BRANCH_PATTERN, branch) or |
| re.match(ANDROID_TV_RELEASE_BRANCH_PATTERN, branch))) |
| |
| |
| def is_master_branch(branch): |
| """Returns True if |branch| is a master branch.""" |
| return branch == 'master' |
| |
| |
| def is_branch_equal_to_or_later_than(branch, threshold): |
| """Returns True if |branch| is at least as new as |threshold|. |
| |
| Returns False if |branch| is older than |threshold|. Returns True if |
| |branch| is newer than |threshold|, matches |threshold|, or is 'master'. |
| |
| Args: |
| branch: A Cast branch, of the form X.YY{a-d} or 'master'. |
| threshold: A Cast branch, of the form X.YY{a-d} or 'master'. |
| |
| Returns: |
| True if |branch| is at least as new as |threshold|. |
| |
| Raises: |
| ValueError: if either |branch| or |threshold| is poorly-formed. |
| """ |
| if is_master_branch(branch): |
| return True |
| # This means it is a named branch. Usually a bringup branch so we should run |
| # everything. |
| if not is_release_branch(branch): |
| return True |
| # Exclude Android TV release branch from version comparison. |
| if re.match(ANDROID_TV_RELEASE_BRANCH_PATTERN, branch): |
| return True |
| if threshold == 'master': |
| return False |
| if threshold is None: |
| return True |
| |
| t_major, t_minor, t_ver = parse_release_branch(threshold) |
| major, minor, ver = parse_release_branch(branch) |
| t_ver = t_ver if t_ver is not None else -1 |
| ver = ver if ver is not None else -1 |
| # If the version is a string for one of them we need to compare both as |
| # strings. |
| if any(isinstance(v, str) for v in (t_ver, ver)): |
| t_ver = str(t_ver) |
| ver = str(ver) |
| return (major > t_major or |
| (major == t_major and minor > t_minor) or |
| (major == t_major and minor == t_minor and ver >= t_ver)) |