root / devflow / flow.py @ 38cd6772
History | View | Annotate | Download (7.3 kB)
1 |
import os |
---|---|
2 |
|
3 |
import logging |
4 |
logging.basicConfig() |
5 |
from optparse import OptionParser |
6 |
|
7 |
os.environ["GIT_PYTHON_TRACE"] = "full" |
8 |
from devflow import utils, versioning |
9 |
from devflow.version import __version__ |
10 |
from devflow.autopkg import call |
11 |
from devflow.ui import query_action |
12 |
from functools import wraps, partial |
13 |
from contextlib import contextmanager |
14 |
from git.exc import GitCommandError |
15 |
|
16 |
|
17 |
def cleanup(func): |
18 |
@wraps(func)
|
19 |
def wrapper(self, *args, **kwargs): |
20 |
try:
|
21 |
return func(self, *args, **kwargs) |
22 |
except:
|
23 |
self.log.debug("Unexpected ERROR. Cleaning up repository...") |
24 |
self.repo.git.reset("--hard", "HEAD") |
25 |
self.repo.git.checkout(self.start_branch) |
26 |
self.repo.git.reset("--hard", self.start_hex) |
27 |
for branch in self.new_branches: |
28 |
self.repo.git.branch("-D", branch) |
29 |
for tag in self.new_tags: |
30 |
self.repo.git.tag("-D", tag) |
31 |
raise
|
32 |
return wrapper
|
33 |
|
34 |
|
35 |
@contextmanager
|
36 |
def conflicts(): |
37 |
try:
|
38 |
yield
|
39 |
except GitCommandError as e: |
40 |
if e.status != 128: |
41 |
print "An error occured. Resolve it and type 'exit'" |
42 |
call("bash")
|
43 |
else:
|
44 |
raise
|
45 |
|
46 |
|
47 |
class GitManager(object): |
48 |
def __init__(self): |
49 |
self.repo = utils.get_repository()
|
50 |
self.start_branch = self.repo.active_branch.name |
51 |
self.start_hex = self.repo.head.log()[-1].newhexsha |
52 |
self.log = logging.getLogger("") |
53 |
self.log.setLevel(logging.DEBUG)
|
54 |
self.log.info("Repository: %s. HEAD: %s", self.repo, self.start_hex) |
55 |
self.new_branches = []
|
56 |
self.new_tags = []
|
57 |
self.repo.git.pull("origin") |
58 |
|
59 |
def get_branch(self, mode, version): |
60 |
if mode not in ["release", "hotfix"]: |
61 |
raise ValueError("Unknown mode: %s" % mode) |
62 |
return "%s-%s" % (mode, version) |
63 |
|
64 |
def get_debian_branch(self, mode, version): |
65 |
if mode not in ["release", "hotfix"]: |
66 |
raise ValueError("Unknown mode: %s" % mode) |
67 |
return "debian-%s-%s" % (mode, version) |
68 |
|
69 |
@cleanup
|
70 |
def start_release(self, version): |
71 |
self.start_common("release", version) |
72 |
|
73 |
@cleanup
|
74 |
def start_hotfix(self, version): |
75 |
self.start_common("hotfix", version) |
76 |
|
77 |
@cleanup
|
78 |
def end_release(self, version): |
79 |
repo = self.repo
|
80 |
master = "master"
|
81 |
debian_master = "debian"
|
82 |
upstream = "develop"
|
83 |
debian = "debian-develop"
|
84 |
upstream_branch = self.get_branch("release", version) |
85 |
debian_branch = self.get_debian_branch("release", version) |
86 |
repo.git.checkout(upstream) |
87 |
with conflicts():
|
88 |
repo.git.merge("--no-ff", upstream_branch)
|
89 |
repo.git.checkout(debian) |
90 |
with conflicts():
|
91 |
repo.git.merge("--no-ff", debian_branch)
|
92 |
|
93 |
repo.git.checkout(master) |
94 |
with conflicts():
|
95 |
repo.git.merge("--no-ff", upstream_branch)
|
96 |
repo.git.checkout(debian_master) |
97 |
with conflicts():
|
98 |
repo.git.merge("--no-ff", debian_branch)
|
99 |
|
100 |
repo.git.checkout(upstream) |
101 |
print "To remove obsolete branches run:" |
102 |
print "git branch -d %s" % upstream_branch |
103 |
print "git branch -d %s" % debian_branch |
104 |
|
105 |
@cleanup
|
106 |
def end_hotfix(self, version): |
107 |
repo = self.repo
|
108 |
upstream = "master"
|
109 |
debian = "debian"
|
110 |
upstream_branch = self.get_branch("hotfix", version) |
111 |
debian_branch = self.get_debian_branch("hotfix", version) |
112 |
|
113 |
repo.git.checkout(upstream) |
114 |
with conflicts():
|
115 |
repo.git.merge("--no-ff", upstream_branch)
|
116 |
repo.git.checkout(debian) |
117 |
with conflicts():
|
118 |
repo.git.merge("--no-ff", debian_branch)
|
119 |
|
120 |
repo.git.checkout(upstream) |
121 |
print "To remove obsolete branches run:" |
122 |
print "git branch -d %s" % upstream_branch |
123 |
print "git branch -d %s" % debian_branch |
124 |
|
125 |
def start_common(self, mode, version): |
126 |
if mode not in ["release", "hotfix"]: |
127 |
raise ValueError("Unknown mode: %s" % mode) |
128 |
repo = self.repo
|
129 |
upstream = "develop" if mode == "release" else "master" |
130 |
debian = "debian-develop" if mode == "release" else "debian" |
131 |
upstream_branch = "%s-%s" % (mode, version)
|
132 |
debian_branch = "debian-%s-%s" % (mode, version)
|
133 |
repo.git.checkout(upstream) |
134 |
repo.git.branch(upstream_branch, upstream) |
135 |
self.new_branches.append(upstream_branch)
|
136 |
versioning.bump_version("%snext" % version)
|
137 |
repo.git.checkout(upstream_branch) |
138 |
versioning.bump_version("%src1" % version)
|
139 |
repo.git.checkout(debian) |
140 |
repo.git.branch(debian_branch, debian) |
141 |
self.new_branches.append(debian_branch)
|
142 |
repo.git.checkout(upstream_branch) |
143 |
repo.git.checkout(debian) |
144 |
|
145 |
@cleanup
|
146 |
def start_feature(self, feature_name): |
147 |
repo = self.repo
|
148 |
feature_upstream = "feature-%s" % feature_name
|
149 |
feature_debian = "debian-%s" % feature_upstream
|
150 |
repo.git.branch(feature_upstream, "develop")
|
151 |
self.new_branches.append(feature_upstream)
|
152 |
repo.git.branch(feature_debian, "debian-develop")
|
153 |
self.new_branches.append(feature_debian)
|
154 |
|
155 |
@cleanup
|
156 |
def end_feature(self, feature_name): |
157 |
repo = self.repo
|
158 |
feature_upstream = "feature-%s" % feature_name
|
159 |
if not feature_upstream in repo.branches: |
160 |
raise ValueError("Branch %s does not exist." % feature_upstream) |
161 |
feature_debian = "debian-%s" % feature_upstream
|
162 |
action = partial(self.edit_changelog, feature_upstream)
|
163 |
query_action("Edit changelog", action = action)
|
164 |
# self.edit_changelog(feature_upstream)
|
165 |
repo.git.checkout("develop")
|
166 |
with conflicts():
|
167 |
repo.git.merge(feature_upstream) |
168 |
repo.git.checkout("debian-develop")
|
169 |
if feature_debian in repo.branches: |
170 |
with conflicts():
|
171 |
repo.git.merge(feature_debian) |
172 |
repo.git.checkout("develop")
|
173 |
print "To remove obsolete branches run:" |
174 |
print "git branch -D %s" % feature_upstream |
175 |
if feature_debian in repo.branches: |
176 |
print "git branch -D %s" % feature_debian |
177 |
|
178 |
def edit_changelog(self, branch): |
179 |
repo = self.repo
|
180 |
if not branch in repo.branches: |
181 |
raise ValueError("Branch %s does not exist." % branch) |
182 |
|
183 |
repo.git.checkout(branch) |
184 |
topdir = repo.working_dir |
185 |
changelog = os.path.join(topdir, "Changelog")
|
186 |
editor = os.getenv('EDITOR')
|
187 |
if not editor: |
188 |
editor = 'vim'
|
189 |
call("%s %s" % (editor, changelog))
|
190 |
repo.git.add(changelog) |
191 |
repo.git.commit(m="Update changelog")
|
192 |
print "Updated changelog on branch %s" % branch |
193 |
|
194 |
def end_common(self, mode, version): |
195 |
pass
|
196 |
|
197 |
|
198 |
def refhead(repo): |
199 |
return repo.head.log[-1].newhexsha |
200 |
|
201 |
|
202 |
def main(): |
203 |
HELP_MSG = "usage: %prog mode=[release|hotfix|feature]"\
|
204 |
" [version|name]"
|
205 |
parser = OptionParser(usage=HELP_MSG, |
206 |
version="devflow-flow %s" % __version__,
|
207 |
add_help_option=True)
|
208 |
options, args = parser.parse_args() |
209 |
if len(args) != 3: |
210 |
parser.error("Invalid number of arguments.")
|
211 |
mode, action, version = args |
212 |
gm = GitManager() |
213 |
func = "%s_%s" % (action, mode)
|
214 |
try:
|
215 |
getattr(gm, func)(version)
|
216 |
except AttributeError: |
217 |
parser.error("Invalid arguments.")
|
218 |
|
219 |
if __name__ == "__main__": |
220 |
main() |