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