๐Ÿ“ฆ sorend / git-version-py

๐Ÿ“„ gitversion.py ยท 97 lines
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
89
90
91
92
93
94
95
96
97#!/usr/bin/env python

import subprocess
import semantic_version
import re
import argparse


BASE_VERSION_STRING = "0.0.0"
BASE_VERSION = semantic_version.Version(BASE_VERSION_STRING)


def git(*args):
    cmd_line = ["git"] + list(args)
    return subprocess.check_output(cmd_line, text=True).strip().splitlines()


def tags_by_branch(branch):
    return git("tag", "--merged", branch)


def current_branch_or_tag():
    try:
        return git("symbolic-ref", "--short", "HEAD")[0]
    except:
        return git("describe", "--tags")[0]


def current_commit_hash():
    return git("rev-parse", "--verify", "HEAD", "--short")[0].rjust(7, '0')


def commits_distance(tag=None):
    if tag is None:
        return git("rev-list", "--count", "HEAD")[0]
    else:
        return git("rev-list", "--count", "HEAD", f"^{tag}")[0]


def get_commits_since(tag=None):
    try:
        if tag is not None and len(git("tag", "-l", tag)) > 0:
            last_commit = git("show-ref", "-s", tag)[0]
            return git("log", "--pretty=%B", f"{last_commit}..HEAD")
        else:
            return git("log", "--pretty=%B", "HEAD")
    except:
        return []  # no commits


def get_previous_tag_and_version():
    cb = current_branch_or_tag()
    branch_tags = tags_by_branch(cb)
    previous_version = BASE_VERSION
    previous_tag = None
    
    for tag in branch_tags:
        try:
            tag_without_prefix = tag.lstrip('v')  # remove "v" from "v1.2.3" -> "1.2.3"
            v : Version = semantic_version.Version(tag_without_prefix)
            if len(v.prerelease) > 0:
                continue
            elif previous_version < v:
                previous_version = v
                previous_tag = tag
        except:
            pass
                
    return cb, previous_tag, previous_version


def get_new_version():
    cb, pt, pv = get_previous_tag_and_version()
    if cb == "main":
        cd = commits_distance(pt)
        prerelease = ["dev", cd] if int(cd) > 0 else []
        previous_version = semantic_version.Version(major=pv.major, minor=pv.minor, patch=pv.patch, prerelease=prerelease)
    else:
        branch_sanitized_name = re.sub(r"[^a-z0-9]", "", cb.lower())[:20]
        prerelease = [branch_sanitized_name, commits_distance(pt), current_commit_hash()]
        previous_version = semantic_version.Version(major=pv.major, minor=pv.minor, patch=pv.patch + 1, prerelease=prerelease)

    return str(previous_version)


def get_previous_version():
    cb, pt, pv = get_previous_tag_and_version()
    return str(pv)


if __name__ == "__main__":

    print(get_previous_version())
    print(get_new_version())