~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to bin/commit_in_branch.py

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/env python3
2
 
 
3
 
import argparse
4
 
import subprocess
5
 
import sys
6
 
 
7
 
 
8
 
def print_(args: argparse.Namespace, success: bool, message: str) -> None:
9
 
    """
10
 
    Print function with extra coloring when supported and/or requested,
11
 
    and with a "quiet" switch
12
 
    """
13
 
 
14
 
    COLOR_SUCCESS = '\033[32m'
15
 
    COLOR_FAILURE = '\033[31m'
16
 
    COLOR_RESET = '\033[0m'
17
 
 
18
 
    if args.quiet:
19
 
        return
20
 
 
21
 
    if args.color == 'auto':
22
 
        use_colors = sys.stdout.isatty()
23
 
    else:
24
 
        use_colors = args.color == 'always'
25
 
 
26
 
    s = ''
27
 
    if use_colors:
28
 
        if success:
29
 
            s += COLOR_SUCCESS
30
 
        else:
31
 
            s += COLOR_FAILURE
32
 
 
33
 
    s += message
34
 
 
35
 
    if use_colors:
36
 
        s += COLOR_RESET
37
 
 
38
 
    print(s)
39
 
 
40
 
 
41
 
def is_commit_valid(commit: str) -> bool:
42
 
    ret = subprocess.call(['git', 'cat-file', '-e', commit],
43
 
                          stdout=subprocess.DEVNULL,
44
 
                          stderr=subprocess.DEVNULL)
45
 
    return ret == 0
46
 
 
47
 
 
48
 
def branch_has_commit(upstream: str, branch: str, commit: str) -> bool:
49
 
    """
50
 
    Returns True if the commit is actually present in the branch
51
 
    """
52
 
    ret = subprocess.call(['git', 'merge-base', '--is-ancestor',
53
 
                           commit, upstream + '/' + branch],
54
 
                          stdout=subprocess.DEVNULL,
55
 
                          stderr=subprocess.DEVNULL)
56
 
    return ret == 0
57
 
 
58
 
 
59
 
def branch_has_backport_of_commit(upstream: str, branch: str, commit: str) -> str:
60
 
    """
61
 
    Returns the commit hash if the commit has been backported to the branch,
62
 
    or an empty string if is hasn't
63
 
    """
64
 
    out = subprocess.check_output(['git', 'log', '--format=%H',
65
 
                                   branch + '-branchpoint..' + upstream + '/' + branch,
66
 
                                   '--grep', 'cherry picked from commit ' + commit],
67
 
                                  stderr=subprocess.DEVNULL)
68
 
    return out.decode().strip()
69
 
 
70
 
 
71
 
def canonicalize_commit(commit: str) -> str:
72
 
    """
73
 
    Takes a commit-ish and returns a commit sha1 if the commit exists
74
 
    """
75
 
 
76
 
    # Make sure input is valid first
77
 
    if not is_commit_valid(commit):
78
 
        raise argparse.ArgumentTypeError('invalid commit identifier: ' + commit)
79
 
 
80
 
    out = subprocess.check_output(['git', 'rev-parse', commit],
81
 
                                  stderr=subprocess.DEVNULL)
82
 
    return out.decode().strip()
83
 
 
84
 
 
85
 
def validate_branch(branch: str) -> str:
86
 
    if '/' not in branch:
87
 
        raise argparse.ArgumentTypeError('must be in the form `remote/branch`')
88
 
 
89
 
    out = subprocess.check_output(['git', 'remote', '--verbose'],
90
 
                                  stderr=subprocess.DEVNULL)
91
 
    remotes = out.decode().splitlines()
92
 
    (upstream, _) = branch.split('/')
93
 
    valid_remote = False
94
 
    for line in remotes:
95
 
        if line.startswith(upstream + '\t'):
96
 
            valid_remote = True
97
 
 
98
 
    if not valid_remote:
99
 
        raise argparse.ArgumentTypeError('Invalid remote: ' + upstream)
100
 
 
101
 
    if not is_commit_valid(branch):
102
 
        raise argparse.ArgumentTypeError('Invalid branch: ' + branch)
103
 
 
104
 
    return branch
105
 
 
106
 
 
107
 
if __name__ == "__main__":
108
 
    parser = argparse.ArgumentParser(description="""
109
 
    Returns 0 if the commit is present in the branch,
110
 
    1 if it's not,
111
 
    and 2 if it couldn't be determined (eg. invalid commit)
112
 
    """)
113
 
    parser.add_argument('commit',
114
 
                        type=canonicalize_commit,
115
 
                        help='commit sha1')
116
 
    parser.add_argument('branch',
117
 
                        type=validate_branch,
118
 
                        help='branch to check, in the form `remote/branch`')
119
 
    parser.add_argument('--quiet',
120
 
                        action='store_true',
121
 
                        help='suppress all output; exit code can still be used')
122
 
    parser.add_argument('--color',
123
 
                        choices=['auto', 'always', 'never'],
124
 
                        default='auto',
125
 
                        help='colorize output (default: true if stdout is a terminal)')
126
 
    args = parser.parse_args()
127
 
 
128
 
    (upstream, branch) = args.branch.split('/')
129
 
 
130
 
    if branch_has_commit(upstream, branch, args.commit):
131
 
        print_(args, True, 'Commit ' + args.commit + ' is in branch ' + branch)
132
 
        exit(0)
133
 
 
134
 
    backport = branch_has_backport_of_commit(upstream, branch, args.commit)
135
 
    if backport:
136
 
        print_(args, True,
137
 
               'Commit ' + args.commit + ' was backported to branch ' + branch + ' as commit ' + backport)
138
 
        exit(0)
139
 
 
140
 
    print_(args, False, 'Commit ' + args.commit + ' is NOT in branch ' + branch)
141
 
    exit(1)