-
Notifications
You must be signed in to change notification settings - Fork 3
/
git_hashes.py
140 lines (113 loc) · 5.48 KB
/
git_hashes.py
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# Python module for getting git commits from the command line args
import datetime
import os
import subprocess
import sys
def parseISO8601Likedatetime(s):
return datetime.datetime.strptime(s, "%Y-%m-%d %H:%M:%S %z")
def get_git_hashes(args):
def shell_exec(cmd, verbose=args.verbose, check=False, stdout=None, stderr=None):
if verbose:
print('+ %s'%cmd)
return subprocess.run(cmd, shell=True, check=check, stdout=stdout, stderr=stderr)
def get_major_minor_patch(i): # "4.09.2+dev0-2020-03-13"
n = i.split('+')[0].split('.') # ['4', '09', '2']
return (int(n[0]), int(n[1]), int(n[2])) # 4, 9, 2
def check_ocaml_version_mismatch(user_input, git_hash):
proc_output = shell_exec('git show %s:VERSION | head -1' % (git_hash), stdout=subprocess.PIPE)
version = proc_output.stdout.decode('utf-8').split('\n')[0]
major1, minor1, patch1 = get_major_minor_patch(user_input)
major2, minor2, patch2 = get_major_minor_patch(version)
if (major1 == major2) and (minor1 == minor2) and (patch1 == patch2):
return True
else:
return False
old_cwd = os.getcwd()
repo_path = os.path.abspath(args.repo)
if args.verbose: print('using repo: %s'%repo_path)
os.chdir(repo_path)
shell_exec('git checkout %s'%args.branch)
if args.repo_pull:
if args.repo_reset_hard:
shell_exec('git fetch')
shell_exec('git reset --hard origin/%s'%args.branch)
shell_exec('git pull')
# git date notes:
# https://docs.microsoft.com/en-us/azure/devops/repos/git/git-dates?view=azure-devops
commit_xtra_args = ' --date=local'
if args.commit_after:
commit_xtra_args += ' --after %s'%args.commit_after
if args.commit_before:
commit_xtra_args += ' --before %s'%args.commit_before
commit_path = '%s..'%args.main_branch if args.main_branch != args.branch else ''
# first parent notes:
# http://www.davidchudzicki.com/posts/first-parent/
first_parent = '' if args.no_first_parent else '--first-parent'
if args.commit_choice_method == 'version_tags':
proc_output = shell_exec('git log %s --pretty=format:\'%%H %%s\' %s | grep VERSION | grep %s'%(first_parent, commit_xtra_args, args.branch), stdout=subprocess.PIPE)
hash_comments = proc_output.stdout.decode('utf-8').split('\n')[::-1]
hash_comments = filter(bool, hash_comments) # remove empty strings
hashes = [hc.split(' ')[0] for hc in hash_comments]
if args.verbose:
for hc in hash_comments:
print(hc)
elif args.commit_choice_method == 'status_success':
proc_output = shell_exec('git log %s %s --pretty=format:\'%%H\' %s' % (commit_path, first_parent, commit_xtra_args), stdout=subprocess.PIPE)
all_hashes = proc_output.stdout.decode('utf-8').split('\n')[::-1]
all_hashes = filter(bool, all_hashes) # remove empty strings
def get_hash_status(h):
curl_xtra_args = '-s'
if args.github_oauth_token is not None:
curl_xtra_args = curl_xtra_args + ' -H "Authorization: token %s"'%args.github_oauth_token
proc_output = shell_exec('curl %s https://api.github.com/repos/ocaml/ocaml/commits/%s/status | jq .state'%(curl_xtra_args, h), stdout=subprocess.PIPE)
return proc_output.stdout.decode('utf-8').strip().strip('"')
hashes = []
for h in all_hashes:
state = get_hash_status(h)
if args.verbose: print('%s is state of %s'%(state, h))
if state == 'success':
hashes.append(h)
elif args.commit_choice_method.startswith('from_hash='):
# get commits from this hash forwards
first_hash = args.commit_choice_method.split('=')[1]
proc_output = shell_exec('git log %s^.. %s --pretty=format:\'%%H %%s\' %s'%(first_hash, first_parent, commit_xtra_args), stdout=subprocess.PIPE)
all_hashes = proc_output.stdout.decode('utf-8').split('\n')[::-1]
all_hashes = filter(bool, all_hashes) # remove empty strings
hashes = [hc.split(' ')[0] for hc in all_hashes]
elif args.commit_choice_method.startswith('hash='):
hashes = args.commit_choice_method.split('=')[1]
hashes = hashes.split(',')
elif args.commit_choice_method.startswith('delay=') or args.commit_choice_method == 'all':
# Need to batch the commits that happen on the same timestamp:
# - often the build will not work properly if you don't do this
# - codespeed will re-order the commits based on hash that occur on same timestamp
if args.commit_choice_method == 'all':
h, m, s = 0, 0, 0
else:
time_str = args.commit_choice_method.split('=')[1]
h, m, s = map(int, time_str.split(':'))
dur = datetime.timedelta(hours=h, minutes=m, seconds=s)
proc_output = shell_exec('git log %s %s --pretty=format:\'%%H/%%ci\' %s'%(commit_path, first_parent, commit_xtra_args), stdout=subprocess.PIPE)
hash_commit_dates = proc_output.stdout.decode('utf-8').split('\n')[::-1]
hash_commit_dates = filter(bool, hash_commit_dates) # remove empty strings
hashes = []
last_h = ''
last_d = parseISO8601Likedatetime('1971-01-01 00:00:00 +0000')
for hcd in hash_commit_dates:
h, d = hcd.split('/')
d = parseISO8601Likedatetime(d)
if d - last_d > dur and last_h != '':
if args.verbose: print('Taking %s %s'%(str(last_d), last_h))
hashes.append(last_h)
last_h, last_d = h, d
if datetime.datetime.now(datetime.timezone.utc) - last_d >= dur:
hashes.append(last_h)
if args.verbose: print('Taking %s %s'%(str(last_d), last_h))
else:
print('Unknown commit choice method "%s"'%args.commit_choice_method)
sys.exit(1)
hashes = [ h for h in hashes if h ] # filter any null hashes
if args.sandmark_tag_override:
hashes = [h for h in hashes if check_ocaml_version_mismatch(args.sandmark_tag_override, h)]
os.chdir(old_cwd)
return hashes