1
|
|
|
# -*- coding: utf-8 -*- |
2
|
1 |
|
''' |
3
|
|
|
Git manipulation |
4
|
|
|
''' |
5
|
1 |
|
from __future__ import unicode_literals |
6
|
|
|
|
7
|
1 |
|
import re |
8
|
|
|
|
9
|
1 |
|
from git import GitCommandError, Repo |
10
|
|
|
|
11
|
1 |
|
import git_app_version.helper.date as dthelper |
12
|
|
|
|
13
|
1 |
|
RESERVED_KEYS = ( |
14
|
|
|
'abbrev_commit', 'author_date', 'author_email', 'author_name', |
15
|
|
|
'author_timestamp', 'branches', 'commit_date', 'commit_timestamp', |
16
|
|
|
'committer_email', 'committer_name', 'deploy_date', 'deploy_timestamp', |
17
|
|
|
'full_commit', 'message', 'top_branches', 'version' |
18
|
|
|
) |
19
|
|
|
|
20
|
|
|
|
21
|
1 |
|
class GitHandler(object): |
22
|
|
|
''' |
23
|
|
|
Git |
24
|
|
|
''' |
25
|
|
|
|
26
|
1 |
|
def __init__(self, path): |
27
|
1 |
|
self.repo = Repo(path) |
28
|
|
|
|
29
|
1 |
|
def get_deploy_date(self): |
|
|
|
|
30
|
|
|
''' |
31
|
|
|
get current date |
32
|
|
|
''' |
33
|
|
|
|
34
|
1 |
|
return dthelper.utcnow() |
35
|
|
|
|
36
|
1 |
|
def get_version(self, commit='HEAD', default=''): |
37
|
|
|
''' |
38
|
|
|
get human readable version |
39
|
|
|
result of `git describe --tag --always` |
40
|
|
|
''' |
41
|
|
|
|
42
|
1 |
|
try: |
43
|
1 |
|
version = self.repo.git.describe('--tag', '--always', |
44
|
|
|
commit).strip() |
45
|
1 |
|
except GitCommandError: |
46
|
1 |
|
version = '' |
47
|
|
|
|
48
|
1 |
|
if not version: |
49
|
1 |
|
version = default |
50
|
|
|
|
51
|
1 |
|
return version |
52
|
|
|
|
53
|
1 |
|
def get_branches(self, commit='HEAD'): |
54
|
|
|
''' |
55
|
|
|
get remote branches which commit belong |
56
|
|
|
result of `git branch --remote --no-color --contains=<commit>` |
57
|
|
|
''' |
58
|
|
|
|
59
|
1 |
|
raw = self.repo.git.branch( |
60
|
|
|
"--no-color", "--remote", "--contains=" + commit |
61
|
|
|
) |
62
|
1 |
|
raw_branches = raw.splitlines() |
63
|
|
|
|
64
|
1 |
|
regex_point = re.compile(r'->') # remove git reference pointing |
65
|
|
|
|
66
|
1 |
|
branches = [] |
67
|
1 |
|
for raw_branch in raw_branches: |
68
|
1 |
|
branch = raw_branch.strip() |
69
|
1 |
|
match = regex_point.search(branch) |
70
|
1 |
|
if not match: |
71
|
1 |
|
branches.append(branch) |
72
|
|
|
|
73
|
1 |
|
return branches |
74
|
|
|
|
75
|
1 |
|
def get_top_branches(self, branches, abbrev_commit=None): |
76
|
|
|
''' |
77
|
|
|
get remote branches which commit belong and is the branch HEAD |
78
|
|
|
''' |
79
|
|
|
|
80
|
1 |
|
top_branch = [] |
81
|
|
|
|
82
|
1 |
|
for branch in branches: |
83
|
1 |
|
if abbrev_commit == self.get_abbrev_commit(branch): |
84
|
1 |
|
top_branch.append(branch) |
85
|
|
|
|
86
|
1 |
|
return top_branch |
87
|
|
|
|
88
|
1 |
|
def remove_remote_prefix(self, branches): |
|
|
|
|
89
|
|
|
''' |
90
|
|
|
remove git remote prefix from branch name |
91
|
|
|
e.g.: origin/master = master |
92
|
|
|
''' |
93
|
1 |
|
regex_remote = re.compile(r'^[^/]+/') # remove git remote prefix |
94
|
|
|
|
95
|
1 |
|
clean_branches = [] |
96
|
1 |
|
for branch in branches: |
97
|
1 |
|
clean_branches.append(regex_remote.sub('', branch)) |
98
|
|
|
|
99
|
1 |
|
return clean_branches |
100
|
|
|
|
101
|
1 |
|
def get_committer_name(self, commit='HEAD'): |
102
|
|
|
''' |
103
|
|
|
get git committer name |
104
|
|
|
''' |
105
|
|
|
|
106
|
1 |
|
return self.repo.commit(commit).committer.name |
107
|
|
|
|
108
|
1 |
|
def get_committer_email(self, commit='HEAD'): |
109
|
|
|
''' |
110
|
|
|
get git committer email |
111
|
|
|
''' |
112
|
|
|
|
113
|
1 |
|
return self.repo.commit(commit).committer.email |
114
|
|
|
|
115
|
1 |
|
def get_author_name(self, commit='HEAD'): |
116
|
|
|
''' |
117
|
|
|
get git author name |
118
|
|
|
''' |
119
|
|
|
|
120
|
1 |
|
return self.repo.commit(commit).author.name |
121
|
|
|
|
122
|
1 |
|
def get_author_email(self, commit='HEAD'): |
123
|
|
|
''' |
124
|
|
|
get git author email |
125
|
|
|
''' |
126
|
|
|
|
127
|
1 |
|
return self.repo.commit(commit).author.email |
128
|
|
|
|
129
|
1 |
|
def get_commit_date(self, commit='HEAD'): |
130
|
|
|
''' |
131
|
|
|
get git commit date |
132
|
|
|
''' |
133
|
|
|
|
134
|
1 |
|
return self.repo.commit(commit).committed_datetime |
135
|
|
|
|
136
|
1 |
|
def get_author_date(self, commit='HEAD'): |
137
|
|
|
''' |
138
|
|
|
get git authoring date |
139
|
|
|
''' |
140
|
|
|
|
141
|
1 |
|
return self.repo.commit(commit).authored_datetime |
142
|
|
|
|
143
|
1 |
|
def get_full_commit(self, commit='HEAD'): |
144
|
|
|
''' |
145
|
|
|
get git commit full SHA1 hash |
146
|
|
|
''' |
147
|
|
|
|
148
|
1 |
|
return self.repo.commit(commit).hexsha |
149
|
|
|
|
150
|
1 |
|
def get_abbrev_commit(self, commit='HEAD'): |
151
|
|
|
''' |
152
|
|
|
get git commit shorten SHA1 hash |
153
|
|
|
''' |
154
|
|
|
|
155
|
1 |
|
return self.repo.commit(commit).hexsha[0:7] |
156
|
|
|
|
157
|
1 |
|
def get_message(self, commit='HEAD'): |
158
|
|
|
''' |
159
|
|
|
get git commit message |
160
|
|
|
''' |
161
|
|
|
|
162
|
1 |
|
return self.repo.commit(commit).message.strip() |
163
|
|
|
|
164
|
1 |
|
def get_infos(self, commit='HEAD'): |
165
|
|
|
''' |
166
|
|
|
get all git commit data |
167
|
|
|
''' |
168
|
|
|
|
169
|
1 |
|
deploy_date = self.get_deploy_date() |
170
|
1 |
|
abbrev_commit = self.get_abbrev_commit(commit) |
171
|
1 |
|
commit_date = self.get_commit_date(commit) |
172
|
1 |
|
author_date = self.get_author_date(commit) |
173
|
|
|
|
174
|
1 |
|
branches = self.get_branches(commit) |
175
|
1 |
|
top_branch = self.get_top_branches( |
176
|
|
|
branches=branches, abbrev_commit=abbrev_commit |
177
|
|
|
) |
178
|
|
|
|
179
|
1 |
|
return { |
180
|
|
|
'branches': self.remove_remote_prefix(branches), |
181
|
|
|
'top_branches': self.remove_remote_prefix(top_branch), |
182
|
|
|
'version': self.get_version(commit, default=abbrev_commit), |
183
|
|
|
'abbrev_commit': abbrev_commit, |
184
|
|
|
'full_commit': self.get_full_commit(commit), |
185
|
|
|
'message': self.get_message(commit), |
186
|
|
|
'author_name': self.get_author_name(commit), |
187
|
|
|
'author_email': self.get_author_email(commit), |
188
|
|
|
'committer_name': self.get_committer_name(commit), |
189
|
|
|
'committer_email': self.get_committer_email(commit), |
190
|
|
|
'commit_date': dthelper.iso8601_from_datetime(commit_date), |
191
|
|
|
'commit_timestamp': dthelper.timestamp_from_datetime(commit_date), |
192
|
|
|
'author_date': dthelper.iso8601_from_datetime(author_date), |
193
|
|
|
'author_timestamp': dthelper.timestamp_from_datetime(author_date), |
194
|
|
|
'deploy_date': dthelper.iso8601_from_datetime(deploy_date), |
195
|
|
|
'deploy_timestamp': dthelper.timestamp_from_datetime(deploy_date), |
196
|
|
|
} |
197
|
|
|
|
If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example
could be written as