File: validate_tag.py

package info (click to toggle)
cmd2 3.2.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 2,664 kB
  • sloc: python: 17,488; makefile: 114; sh: 39; javascript: 7
file content (88 lines) | stat: -rwxr-xr-x 3,322 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#!/usr/bin/env python
"""A simple script to validate that a git tag matches a SemVer pattern."""

import re
import subprocess

SEMVER_SIMPLE = re.compile(r'(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d+))?')
SEMVER_PATTERN = re.compile(
    r"""
        ^                                           # Start of the string
        v?                                          # Optional 'v' prefix (common in Git tags)
        (?P<major>0|[1-9]\d*)\.                     # Major version
        (?P<minor>0|[1-9]\d*)\.                     # Minor version
        (?P<patch>0|[1-9]\d*)                       # Patch version
        (?:-(?P<prerelease>                          # Optional pre-release section
            (?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*) #  Identifier
            (?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*
        ))?
        (?:\+(?P<build>                              # Optional build metadata section
            [0-9a-zA-Z-]+                           #  Identifier
            (?:\.[0-9a-zA-Z-]+)*
        ))?
        $                                           # End of the string
    """,
    re.VERBOSE,
)


def get_current_tag() -> str:
    """Get current git tag."""
    try:
        # Gets the name of the latest tag reachable from the current commit
        result = subprocess.run(
            ['git', 'describe', '--exact-match', '--tags', '--abbrev=0'], capture_output=True, text=True, check=True
        )
        return result.stdout.strip()
    except subprocess.CalledProcessError:
        print("Could not find a reachable tag.")
        return ''


def is_semantic_version(tag_name: str) -> bool:
    """Check if a given string complies with the semantic versioning 2.0.0 specification.

    Args:
        tag_name: The name of the Git tag to validate.

    Returns:
        bool: True if the tag is a valid semantic version, False otherwise.

    """
    # The regex pattern for semantic versioning 2.0.0 (source: https://semver.org/)
    semver_pattern = re.compile(
        r"""
        ^                                           # Start of the string
        v?                                          # Optional 'v' prefix (common in Git tags)
        (?P<major>0|[1-9]\d*)\.                     # Major version
        (?P<minor>0|[1-9]\d*)\.                     # Minor version
        (?P<patch>0|[1-9]\d*)                       # Patch version
        (?:-(?P<prerelease>                          # Optional pre-release section
            (?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*) #  Identifier
            (?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*
        ))?
        (?:\+(?P<build>                              # Optional build metadata section
            [0-9a-zA-Z-]+                           #  Identifier
            (?:\.[0-9a-zA-Z-]+)*
        ))?
        $                                           # End of the string
    """,
        re.VERBOSE,
    )

    return bool(semver_pattern.match(tag_name))


if __name__ == '__main__':
    import sys

    git_tag = get_current_tag()
    if not git_tag:
        print('Git tag does not exist for current commit.')
        sys.exit(-1)

    if not is_semantic_version(git_tag):
        print(rf"Git tag '{git_tag}' is invalid according to SemVer.")
        sys.exit(-1)

    print(rf"Git tag '{git_tag}' is valid.")