Statistics
| Branch: | Tag: | Revision:

root / devflow / flow.py @ 06edfd12

History | View | Annotate | Download (16.9 kB)

1 c3c33dd0 Christos Stavrakakis
import os
2 2e9bddbf Filippos Giannakos
import re
3 c3c33dd0 Christos Stavrakakis
4 c3c33dd0 Christos Stavrakakis
import logging
5 c3c33dd0 Christos Stavrakakis
logging.basicConfig()
6 2e9bddbf Filippos Giannakos
#from optparse import OptionParser
7 2e9bddbf Filippos Giannakos
from argparse import ArgumentParser
8 c3c33dd0 Christos Stavrakakis
9 c3c33dd0 Christos Stavrakakis
os.environ["GIT_PYTHON_TRACE"] = "full"
10 6dc2ab71 Filippos Giannakos
from devflow import utils, versioning, RC_RE
11 c3c33dd0 Christos Stavrakakis
from devflow.version import __version__
12 c3c33dd0 Christos Stavrakakis
from devflow.autopkg import call
13 2e9bddbf Filippos Giannakos
from devflow.ui import query_action, query_user, query_yes_no
14 38cd6772 Filippos Giannakos
from functools import wraps, partial
15 c3c33dd0 Christos Stavrakakis
from contextlib import contextmanager
16 c3c33dd0 Christos Stavrakakis
from git.exc import GitCommandError
17 2e9bddbf Filippos Giannakos
from sh import mktemp
18 2e9bddbf Filippos Giannakos
19 2e9bddbf Filippos Giannakos
20 2e9bddbf Filippos Giannakos
def create_temp_file(suffix):
21 2e9bddbf Filippos Giannakos
    create_dir_cmd = mktemp("/tmp/" + suffix + "-XXXXX")
22 2e9bddbf Filippos Giannakos
    return create_dir_cmd.stdout.strip()
23 c3c33dd0 Christos Stavrakakis
24 c3c33dd0 Christos Stavrakakis
25 c3c33dd0 Christos Stavrakakis
def cleanup(func):
26 c3c33dd0 Christos Stavrakakis
    @wraps(func)
27 c3c33dd0 Christos Stavrakakis
    def wrapper(self, *args, **kwargs):
28 c3c33dd0 Christos Stavrakakis
        try:
29 c3c33dd0 Christos Stavrakakis
            return func(self, *args, **kwargs)
30 c3c33dd0 Christos Stavrakakis
        except:
31 c3c33dd0 Christos Stavrakakis
            self.log.debug("Unexpected ERROR. Cleaning up repository...")
32 c3c33dd0 Christos Stavrakakis
            self.repo.git.reset("--hard", "HEAD")
33 c3c33dd0 Christos Stavrakakis
            self.repo.git.checkout(self.start_branch)
34 c3c33dd0 Christos Stavrakakis
            self.repo.git.reset("--hard", self.start_hex)
35 c3c33dd0 Christos Stavrakakis
            for branch in self.new_branches:
36 c3c33dd0 Christos Stavrakakis
                self.repo.git.branch("-D", branch)
37 c3c33dd0 Christos Stavrakakis
            for tag in self.new_tags:
38 c3c33dd0 Christos Stavrakakis
                self.repo.git.tag("-D", tag)
39 c3c33dd0 Christos Stavrakakis
            raise
40 c3c33dd0 Christos Stavrakakis
    return wrapper
41 c3c33dd0 Christos Stavrakakis
42 c3c33dd0 Christos Stavrakakis
43 c3c33dd0 Christos Stavrakakis
@contextmanager
44 c3c33dd0 Christos Stavrakakis
def conflicts():
45 c3c33dd0 Christos Stavrakakis
    try:
46 c3c33dd0 Christos Stavrakakis
        yield
47 c3c33dd0 Christos Stavrakakis
    except GitCommandError as e:
48 c3c33dd0 Christos Stavrakakis
        if e.status != 128:
49 2e9bddbf Filippos Giannakos
            print "An error occured. Resolve it and type 'exit 0'"
50 2e9bddbf Filippos Giannakos
            tmpbashrc=create_temp_file("bashrc")
51 2e9bddbf Filippos Giannakos
            f = open(tmpbashrc, 'w')
52 2e9bddbf Filippos Giannakos
            f.write("source $HOME/.bashrc ; export PS1=(Conflict)\"$PS1\"")
53 2e9bddbf Filippos Giannakos
            f.close()
54 2e9bddbf Filippos Giannakos
            call('bash --rcfile %s' % tmpbashrc)
55 2e9bddbf Filippos Giannakos
            os.unlink(tmpbashrc)
56 c3c33dd0 Christos Stavrakakis
        else:
57 c3c33dd0 Christos Stavrakakis
            raise
58 c3c33dd0 Christos Stavrakakis
59 2e9bddbf Filippos Giannakos
def get_release_version(develop_version):
60 2e9bddbf Filippos Giannakos
    version = develop_version.rstrip('next')
61 2e9bddbf Filippos Giannakos
    parts = version.split('.')
62 2e9bddbf Filippos Giannakos
    major_version = int(parts[0])
63 2e9bddbf Filippos Giannakos
    minor_version = int(parts[1])
64 2e9bddbf Filippos Giannakos
    #return str(major_version) + '.' + str(minor_version+1) + 'rc1'
65 2e9bddbf Filippos Giannakos
    return str(major_version) + '.' + str(minor_version+1)
66 2e9bddbf Filippos Giannakos
67 2e9bddbf Filippos Giannakos
def get_develop_version_from_release(release_version):
68 2e9bddbf Filippos Giannakos
    #version = re.sub('rc[0-9]+$', '', release_version)
69 2e9bddbf Filippos Giannakos
    version = release_version
70 2e9bddbf Filippos Giannakos
    parts = version.split('.')
71 2e9bddbf Filippos Giannakos
    major_version = int(parts[0])
72 2e9bddbf Filippos Giannakos
    minor_version = int(parts[1])
73 2e9bddbf Filippos Giannakos
    return str(major_version) + '.' + str(minor_version+1) + 'next'
74 2e9bddbf Filippos Giannakos
75 2e9bddbf Filippos Giannakos
def get_hotfix_version(version):
76 2e9bddbf Filippos Giannakos
    parts = version.split('.')
77 2e9bddbf Filippos Giannakos
    major_version = int(parts[0])
78 2e9bddbf Filippos Giannakos
    minor_version = int(parts[1])
79 2e9bddbf Filippos Giannakos
    if (len(parts) > 2):
80 2e9bddbf Filippos Giannakos
        hotfix_version = int(parts[2])
81 2e9bddbf Filippos Giannakos
    else:
82 2e9bddbf Filippos Giannakos
        hotfix_version = 0
83 2e9bddbf Filippos Giannakos
84 2e9bddbf Filippos Giannakos
    return str(major_version) + '.' + str(minor_version) + '.'\
85 2e9bddbf Filippos Giannakos
            + str(hotfix_version+1)
86 c3c33dd0 Christos Stavrakakis
87 c3c33dd0 Christos Stavrakakis
class GitManager(object):
88 c3c33dd0 Christos Stavrakakis
    def __init__(self):
89 c3c33dd0 Christos Stavrakakis
        self.repo = utils.get_repository()
90 c3c33dd0 Christos Stavrakakis
        self.start_branch = self.repo.active_branch.name
91 c3c33dd0 Christos Stavrakakis
        self.start_hex = self.repo.head.log()[-1].newhexsha
92 c3c33dd0 Christos Stavrakakis
        self.log = logging.getLogger("")
93 c3c33dd0 Christos Stavrakakis
        self.log.setLevel(logging.DEBUG)
94 c3c33dd0 Christos Stavrakakis
        self.log.info("Repository: %s. HEAD: %s", self.repo, self.start_hex)
95 c3c33dd0 Christos Stavrakakis
        self.new_branches = []
96 c3c33dd0 Christos Stavrakakis
        self.new_tags = []
97 2e9bddbf Filippos Giannakos
        #self.repo.git.pull("origin")
98 c3c33dd0 Christos Stavrakakis
99 b7e05a72 Filippos Giannakos
    def get_branch(self, mode, version):
100 b7e05a72 Filippos Giannakos
        if mode not in ["release", "hotfix"]:
101 b7e05a72 Filippos Giannakos
            raise ValueError("Unknown mode: %s" % mode)
102 b7e05a72 Filippos Giannakos
        return "%s-%s" % (mode, version)
103 b7e05a72 Filippos Giannakos
104 b7e05a72 Filippos Giannakos
    def get_debian_branch(self, mode, version):
105 b7e05a72 Filippos Giannakos
        if mode not in ["release", "hotfix"]:
106 b7e05a72 Filippos Giannakos
            raise ValueError("Unknown mode: %s" % mode)
107 b7e05a72 Filippos Giannakos
        return "debian-%s-%s" % (mode, version)
108 b7e05a72 Filippos Giannakos
109 2e9bddbf Filippos Giannakos
    def doit(self, action_yes=None, action_no=None, question="Do it", args=None,
110 2e9bddbf Filippos Giannakos
            default=False):
111 2e9bddbf Filippos Giannakos
        if not args.defaults:
112 2e9bddbf Filippos Giannakos
            ret = query_yes_no(question, default = "yes" if default else "no")
113 2e9bddbf Filippos Giannakos
        else:
114 2e9bddbf Filippos Giannakos
            ret = default
115 c3c33dd0 Christos Stavrakakis
116 2e9bddbf Filippos Giannakos
        if ret and action_yes:
117 2e9bddbf Filippos Giannakos
            action_yes()
118 2e9bddbf Filippos Giannakos
        elif not ret and action_no:
119 2e9bddbf Filippos Giannakos
            action_no()
120 2e9bddbf Filippos Giannakos
121 2e9bddbf Filippos Giannakos
    def __print_cleanup(self, branches):
122 2e9bddbf Filippos Giannakos
        print "To remove obsolete branches run:"
123 2e9bddbf Filippos Giannakos
        for b in branches:
124 2e9bddbf Filippos Giannakos
            print "git branch -D %s" % b
125 2e9bddbf Filippos Giannakos
126 2e9bddbf Filippos Giannakos
127 2e9bddbf Filippos Giannakos
    def __cleanup_branches(self, branches):
128 2e9bddbf Filippos Giannakos
        repo = self.repo
129 2e9bddbf Filippos Giannakos
        for b in branches:
130 2e9bddbf Filippos Giannakos
            repo.git.branch("-D", b)
131 2e9bddbf Filippos Giannakos
132 2e9bddbf Filippos Giannakos
    def cleanup_branches(self, branches, args, default=False):
133 2e9bddbf Filippos Giannakos
        if args.cleanup is not None:
134 2e9bddbf Filippos Giannakos
            if args.cleanup:
135 2e9bddbf Filippos Giannakos
                self.__cleanup_branches(branches)
136 2e9bddbf Filippos Giannakos
            else:
137 2e9bddbf Filippos Giannakos
                self.__print_cleanup(branches)
138 2e9bddbf Filippos Giannakos
            return
139 2e9bddbf Filippos Giannakos
140 2e9bddbf Filippos Giannakos
        question="Remove branches %s" % branches
141 2e9bddbf Filippos Giannakos
        action_yes = partial(self.__cleanup_branches, branches)
142 2e9bddbf Filippos Giannakos
        action_no = partial(self.__print_cleanup, branches)
143 2e9bddbf Filippos Giannakos
        self.doit(action_yes=action_yes, action_no=action_no,
144 2e9bddbf Filippos Giannakos
                  question=question, args=args, default=default)
145 2e9bddbf Filippos Giannakos
146 2e9bddbf Filippos Giannakos
147 2e9bddbf Filippos Giannakos
    def check_edit_changelog(self, edit_action, args, default=True):
148 2e9bddbf Filippos Giannakos
        if args.edit_changelog is not None:
149 2e9bddbf Filippos Giannakos
            if args.edit_changelog:
150 2e9bddbf Filippos Giannakos
                edit_action()
151 2e9bddbf Filippos Giannakos
            return
152 2e9bddbf Filippos Giannakos
        question = "Edit changelog ?"
153 2e9bddbf Filippos Giannakos
        self.doit(action_yes=edit_action, question=question, args=args,
154 2e9bddbf Filippos Giannakos
                  default=default)
155 2e9bddbf Filippos Giannakos
156 2e9bddbf Filippos Giannakos
    def _merge_branches(self, branch_to, branch_from):
157 2e9bddbf Filippos Giannakos
        repo = self.repo
158 2e9bddbf Filippos Giannakos
        cur_branch = repo.active_branch.name
159 2e9bddbf Filippos Giannakos
        repo.git.checkout(branch_to)
160 2e9bddbf Filippos Giannakos
        with conflicts():
161 2e9bddbf Filippos Giannakos
            repo.git.merge("--no-ff", branch_from)
162 2e9bddbf Filippos Giannakos
        repo.git.checkout(cur_branch)
163 2e9bddbf Filippos Giannakos
164 2e9bddbf Filippos Giannakos
    def merge_branches(self, branch_to, branch_from, args, default=True):
165 2e9bddbf Filippos Giannakos
        action = partial(self._merge_branches, branch_to, branch_from)
166 2e9bddbf Filippos Giannakos
        question = "Merge branch %s to %s ?" % (branch_from, branch_to)
167 2e9bddbf Filippos Giannakos
        self.doit(action_yes=action, question=question, args=args,
168 2e9bddbf Filippos Giannakos
                  default=default)
169 2e9bddbf Filippos Giannakos
170 2e9bddbf Filippos Giannakos
    def edit_changelog(self, branch, base_branch=None):
171 2e9bddbf Filippos Giannakos
        repo = self.repo
172 2e9bddbf Filippos Giannakos
        if not branch in repo.branches:
173 2e9bddbf Filippos Giannakos
            raise ValueError("Branch %s does not exist." % branch)
174 2e9bddbf Filippos Giannakos
        if base_branch and not base_branch in repo.branches:
175 2e9bddbf Filippos Giannakos
            raise ValueError("Branch %s does not exist." % base_branch)
176 2e9bddbf Filippos Giannakos
177 2e9bddbf Filippos Giannakos
        repo.git.checkout(branch)
178 2e9bddbf Filippos Giannakos
        topdir = repo.working_dir
179 2e9bddbf Filippos Giannakos
        changelog = os.path.join(topdir, "Changelog")
180 2e9bddbf Filippos Giannakos
181 2e9bddbf Filippos Giannakos
        lines = []
182 2e9bddbf Filippos Giannakos
        lines.append("#Changelog for %s\n" % branch)
183 2e9bddbf Filippos Giannakos
        if base_branch:
184 2e9bddbf Filippos Giannakos
            commits = repo.git.rev_list("%s..%s" % (base_branch, branch)).split("\n")
185 2e9bddbf Filippos Giannakos
            for c in commits:
186 2e9bddbf Filippos Giannakos
                commit = repo.commit(c)
187 2e9bddbf Filippos Giannakos
                lines.append(commit.message)
188 2e9bddbf Filippos Giannakos
        lines.append("\n")
189 2e9bddbf Filippos Giannakos
190 2e9bddbf Filippos Giannakos
        f = open(changelog, 'rw+')
191 2e9bddbf Filippos Giannakos
        lines.extend(f.readlines())
192 2e9bddbf Filippos Giannakos
        f.seek(0)
193 2e9bddbf Filippos Giannakos
        f.truncate(0)
194 2e9bddbf Filippos Giannakos
        f.writelines(lines)
195 2e9bddbf Filippos Giannakos
        f.close()
196 2e9bddbf Filippos Giannakos
197 2e9bddbf Filippos Giannakos
        editor = os.getenv('EDITOR')
198 2e9bddbf Filippos Giannakos
        if not editor:
199 2e9bddbf Filippos Giannakos
            editor = 'vim'
200 2e9bddbf Filippos Giannakos
        call("%s %s" % (editor, changelog))
201 2e9bddbf Filippos Giannakos
        repo.git.add(changelog)
202 2e9bddbf Filippos Giannakos
        repo.git.commit(m="Update changelog")
203 2e9bddbf Filippos Giannakos
        print "Updated changelog on branch %s" % branch
204 c3c33dd0 Christos Stavrakakis
205 c3c33dd0 Christos Stavrakakis
    @cleanup
206 2e9bddbf Filippos Giannakos
    def start_release(self, args):
207 b7e05a72 Filippos Giannakos
        repo = self.repo
208 b7e05a72 Filippos Giannakos
        upstream = "develop"
209 b7e05a72 Filippos Giannakos
        debian = "debian-develop"
210 2e9bddbf Filippos Giannakos
        repo.git.checkout(upstream)
211 2e9bddbf Filippos Giannakos
212 2e9bddbf Filippos Giannakos
        vcs = utils.get_vcs_info()
213 2e9bddbf Filippos Giannakos
        develop_version = versioning.get_base_version(vcs)
214 2e9bddbf Filippos Giannakos
        if not args.version:
215 2e9bddbf Filippos Giannakos
            version = get_release_version(develop_version)
216 2e9bddbf Filippos Giannakos
            if not args.defaults:
217 2e9bddbf Filippos Giannakos
                version = query_user("Release version", default=version)
218 2e9bddbf Filippos Giannakos
        else:
219 2e9bddbf Filippos Giannakos
            #validate version?
220 2e9bddbf Filippos Giannakos
            pass
221 2e9bddbf Filippos Giannakos
        rc_version = "%src1" % version
222 2e9bddbf Filippos Giannakos
        new_develop_version = "%snext" % version
223 2e9bddbf Filippos Giannakos
224 b7e05a72 Filippos Giannakos
        upstream_branch = self.get_branch("release", version)
225 b7e05a72 Filippos Giannakos
        debian_branch = self.get_debian_branch("release", version)
226 2e9bddbf Filippos Giannakos
227 2e9bddbf Filippos Giannakos
        #create release branch
228 2e9bddbf Filippos Giannakos
        repo.git.branch(upstream_branch, upstream)
229 2e9bddbf Filippos Giannakos
        self.new_branches.append(upstream_branch)
230 2e9bddbf Filippos Giannakos
        repo.git.checkout(upstream_branch)
231 2e9bddbf Filippos Giannakos
        versioning.bump_version(rc_version)
232 2e9bddbf Filippos Giannakos
233 2e9bddbf Filippos Giannakos
        #create debian release branch
234 b7e05a72 Filippos Giannakos
        repo.git.checkout(debian)
235 2e9bddbf Filippos Giannakos
        repo.git.branch(debian_branch, debian)
236 2e9bddbf Filippos Giannakos
        self.new_branches.append(debian_branch)
237 b7e05a72 Filippos Giannakos
238 2e9bddbf Filippos Giannakos
        repo.git.checkout(upstream_branch)
239 2e9bddbf Filippos Giannakos
        repo.git.checkout(debian)
240 b7e05a72 Filippos Giannakos
241 2e9bddbf Filippos Giannakos
        #bump develop version
242 b7e05a72 Filippos Giannakos
        repo.git.checkout(upstream)
243 2e9bddbf Filippos Giannakos
        versioning.bump_version(new_develop_version)
244 2e9bddbf Filippos Giannakos
245 2e9bddbf Filippos Giannakos
        repo.git.checkout(upstream_branch)
246 2e9bddbf Filippos Giannakos
247 c3c33dd0 Christos Stavrakakis
248 c3c33dd0 Christos Stavrakakis
    @cleanup
249 2e9bddbf Filippos Giannakos
    def start_hotfix(self, args):
250 b7e05a72 Filippos Giannakos
        repo = self.repo
251 b7e05a72 Filippos Giannakos
        upstream = "master"
252 b7e05a72 Filippos Giannakos
        debian = "debian"
253 b7e05a72 Filippos Giannakos
        repo.git.checkout(upstream)
254 2e9bddbf Filippos Giannakos
        #maybe provide major.minor version, find the latest release/hotfix and
255 2e9bddbf Filippos Giannakos
        #branch from there ?
256 2e9bddbf Filippos Giannakos
257 2e9bddbf Filippos Giannakos
        vcs = utils.get_vcs_info()
258 2e9bddbf Filippos Giannakos
        version = versioning.get_base_version(vcs)
259 2e9bddbf Filippos Giannakos
        if not args.version:
260 2e9bddbf Filippos Giannakos
            version = get_hotfix_version(version)
261 2e9bddbf Filippos Giannakos
            if not args.defaults:
262 2e9bddbf Filippos Giannakos
                version = query_user("Hotfix version", default=version)
263 2e9bddbf Filippos Giannakos
        else:
264 2e9bddbf Filippos Giannakos
            #validate version?
265 2e9bddbf Filippos Giannakos
            pass
266 b7e05a72 Filippos Giannakos
267 2e9bddbf Filippos Giannakos
        rc_version = "%src1" % version
268 2e9bddbf Filippos Giannakos
        new_develop_version = "%snext" % version
269 c3c33dd0 Christos Stavrakakis
270 2e9bddbf Filippos Giannakos
        upstream_branch = self.get_branch("hotfix", version)
271 2e9bddbf Filippos Giannakos
        debian_branch = self.get_debian_branch("hotfix", version)
272 2e9bddbf Filippos Giannakos
273 2e9bddbf Filippos Giannakos
        #create hotfix branch
274 c3c33dd0 Christos Stavrakakis
        repo.git.branch(upstream_branch, upstream)
275 c3c33dd0 Christos Stavrakakis
        self.new_branches.append(upstream_branch)
276 c3c33dd0 Christos Stavrakakis
        repo.git.checkout(upstream_branch)
277 2e9bddbf Filippos Giannakos
        versioning.bump_version(rc_version)
278 2e9bddbf Filippos Giannakos
279 2e9bddbf Filippos Giannakos
        #create debian hotfix branch
280 c3c33dd0 Christos Stavrakakis
        repo.git.checkout(debian)
281 c3c33dd0 Christos Stavrakakis
        repo.git.branch(debian_branch, debian)
282 c3c33dd0 Christos Stavrakakis
        self.new_branches.append(debian_branch)
283 2e9bddbf Filippos Giannakos
284 c3c33dd0 Christos Stavrakakis
        repo.git.checkout(upstream_branch)
285 c3c33dd0 Christos Stavrakakis
        repo.git.checkout(debian)
286 c3c33dd0 Christos Stavrakakis
287 2e9bddbf Filippos Giannakos
        #bump develop version. Ask first or verify we have the same
288 2e9bddbf Filippos Giannakos
        #major.minornext?
289 2e9bddbf Filippos Giannakos
        #repo.git.checkout(upstream)
290 2e9bddbf Filippos Giannakos
        #versioning.bump_version(new_develop_version)
291 2e9bddbf Filippos Giannakos
292 2e9bddbf Filippos Giannakos
        repo.git.checkout(upstream_branch)
293 2e9bddbf Filippos Giannakos
294 2e9bddbf Filippos Giannakos
    @cleanup
295 2e9bddbf Filippos Giannakos
    def end_release(self, args):
296 2e9bddbf Filippos Giannakos
        version = args.version
297 2e9bddbf Filippos Giannakos
        repo = self.repo
298 2e9bddbf Filippos Giannakos
        master = "master"
299 2e9bddbf Filippos Giannakos
        debian_master = "debian"
300 2e9bddbf Filippos Giannakos
        upstream = "develop"
301 2e9bddbf Filippos Giannakos
        debian = "debian-develop"
302 2e9bddbf Filippos Giannakos
        upstream_branch = self.get_branch("release", version)
303 2e9bddbf Filippos Giannakos
        debian_branch = self.get_debian_branch("release", version)
304 2e9bddbf Filippos Giannakos
        tag = upstream_branch
305 06edfd12 Filippos Giannakos
        debian_tag = "debian/" + tag
306 2e9bddbf Filippos Giannakos
307 2e9bddbf Filippos Giannakos
        edit_action = partial(self.edit_changelog, upstream_branch, "develop")
308 2e9bddbf Filippos Giannakos
        self.check_edit_changelog(edit_action, args, default=True)
309 2e9bddbf Filippos Giannakos
310 6dc2ab71 Filippos Giannakos
        vcs = utils.get_vcs_info()
311 6dc2ab71 Filippos Giannakos
        release_version = versioning.get_base_version(vcs)
312 6dc2ab71 Filippos Giannakos
        if re.match('.*'+RC_RE, release_version):
313 6dc2ab71 Filippos Giannakos
            new_version = re.sub(RC_RE, '', release_version)
314 6dc2ab71 Filippos Giannakos
            versioning._bump_version(new_version, vcs)
315 6dc2ab71 Filippos Giannakos
316 2e9bddbf Filippos Giannakos
        #merge to master
317 2e9bddbf Filippos Giannakos
        self._merge_branches(master, upstream_branch)
318 2e9bddbf Filippos Giannakos
        self._merge_branches(debian_master, debian_branch)
319 2e9bddbf Filippos Giannakos
320 2e9bddbf Filippos Giannakos
        #create tags
321 2e9bddbf Filippos Giannakos
        repo.git.checkout(master)
322 2e9bddbf Filippos Giannakos
        repo.git.tag("%s" % tag)
323 2e9bddbf Filippos Giannakos
        repo.git.checkout(debian)
324 06edfd12 Filippos Giannakos
        repo.git.tag("%s" % debian_tag)
325 2e9bddbf Filippos Giannakos
326 2e9bddbf Filippos Giannakos
        #merge release changes to upstream
327 2e9bddbf Filippos Giannakos
        self.merge_branches(upstream, upstream_branch, args, default=True)
328 2e9bddbf Filippos Giannakos
        self.merge_branches(debian, debian_branch, args, default=True)
329 2e9bddbf Filippos Giannakos
330 2e9bddbf Filippos Giannakos
        repo.git.checkout(upstream)
331 2e9bddbf Filippos Giannakos
332 2e9bddbf Filippos Giannakos
        branches = [upstream_branch, debian_branch]
333 2e9bddbf Filippos Giannakos
        self.cleanup_branches(branches, args, default=True)
334 2e9bddbf Filippos Giannakos
335 2e9bddbf Filippos Giannakos
    @cleanup
336 2e9bddbf Filippos Giannakos
    def end_hotfix(self, args):
337 2e9bddbf Filippos Giannakos
        version = args.version
338 2e9bddbf Filippos Giannakos
339 2e9bddbf Filippos Giannakos
        repo = self.repo
340 2e9bddbf Filippos Giannakos
        upstream = "master"
341 2e9bddbf Filippos Giannakos
        debian = "debian"
342 2e9bddbf Filippos Giannakos
        upstream_branch = self.get_branch("hotfix", version)
343 2e9bddbf Filippos Giannakos
        debian_branch = self.get_debian_branch("hotfix", version)
344 2e9bddbf Filippos Giannakos
345 2e9bddbf Filippos Giannakos
        #create tags?
346 2e9bddbf Filippos Giannakos
347 2e9bddbf Filippos Giannakos
        self._merge_branches(upstream, upstream_branch)
348 2e9bddbf Filippos Giannakos
        self._merge_branches(debian, debian_branch)
349 2e9bddbf Filippos Giannakos
350 2e9bddbf Filippos Giannakos
        repo.git.checkout(upstream)
351 2e9bddbf Filippos Giannakos
352 2e9bddbf Filippos Giannakos
        branches = [upstream_branch, debian_branch]
353 2e9bddbf Filippos Giannakos
        self.cleanup_branches(branches, args, default=True)
354 2e9bddbf Filippos Giannakos
355 c3c33dd0 Christos Stavrakakis
    @cleanup
356 2e9bddbf Filippos Giannakos
    def start_feature(self, args):
357 2e9bddbf Filippos Giannakos
        feature_name = args.feature_name
358 c3c33dd0 Christos Stavrakakis
        repo = self.repo
359 c3c33dd0 Christos Stavrakakis
        feature_upstream = "feature-%s" % feature_name
360 c3c33dd0 Christos Stavrakakis
        feature_debian = "debian-%s" % feature_upstream
361 c3c33dd0 Christos Stavrakakis
        repo.git.branch(feature_upstream, "develop")
362 c3c33dd0 Christos Stavrakakis
        self.new_branches.append(feature_upstream)
363 c3c33dd0 Christos Stavrakakis
        repo.git.branch(feature_debian, "debian-develop")
364 c3c33dd0 Christos Stavrakakis
        self.new_branches.append(feature_debian)
365 c3c33dd0 Christos Stavrakakis
366 c3c33dd0 Christos Stavrakakis
    @cleanup
367 2e9bddbf Filippos Giannakos
    def end_feature(self, args):
368 2e9bddbf Filippos Giannakos
        feature_name = args.feature_name
369 c3c33dd0 Christos Stavrakakis
        repo = self.repo
370 c3c33dd0 Christos Stavrakakis
        feature_upstream = "feature-%s" % feature_name
371 c3c33dd0 Christos Stavrakakis
        if not feature_upstream in repo.branches:
372 c3c33dd0 Christos Stavrakakis
            raise ValueError("Branch %s does not exist." % feature_upstream)
373 c3c33dd0 Christos Stavrakakis
        feature_debian = "debian-%s" % feature_upstream
374 2e9bddbf Filippos Giannakos
375 2e9bddbf Filippos Giannakos
        edit_action = partial(self.edit_changelog, feature_upstream, "develop")
376 2e9bddbf Filippos Giannakos
        self.check_edit_changelog(edit_action, args, default=True)
377 2e9bddbf Filippos Giannakos
378 2e9bddbf Filippos Giannakos
        #merge to develop
379 2e9bddbf Filippos Giannakos
        self._merge_branches("develop", feature_upstream)
380 c3c33dd0 Christos Stavrakakis
        if feature_debian in repo.branches:
381 2e9bddbf Filippos Giannakos
            self._merge_branches("debian-develop", feature_debian)
382 c3c33dd0 Christos Stavrakakis
        repo.git.checkout("develop")
383 2e9bddbf Filippos Giannakos
384 2e9bddbf Filippos Giannakos
        branches = [feature_upstream]
385 c3c33dd0 Christos Stavrakakis
        if feature_debian in repo.branches:
386 2e9bddbf Filippos Giannakos
            branches.append(feature_debian)
387 2e9bddbf Filippos Giannakos
        self.cleanup_branches(branches, args, default=True)
388 c3c33dd0 Christos Stavrakakis
389 e278c46e Filippos Giannakos
390 2e9bddbf Filippos Giannakos
def refhead(repo):
391 2e9bddbf Filippos Giannakos
    return repo.head.log[-1].newhexsha
392 30d42d95 Filippos Giannakos
393 30d42d95 Filippos Giannakos
394 2e9bddbf Filippos Giannakos
def main():
395 2e9bddbf Filippos Giannakos
    parser = ArgumentParser(description="Devflow tool")
396 2e9bddbf Filippos Giannakos
    parser.add_argument('-V', '--version', action='version',
397 2e9bddbf Filippos Giannakos
            version='devflow-flow %s' % __version__)
398 2e9bddbf Filippos Giannakos
    parser.add_argument('-d', '--defaults', action='store_true', default=False,
399 2e9bddbf Filippos Giannakos
            help="Assume default on every choice, unless a value is provided")
400 30d42d95 Filippos Giannakos
401 2e9bddbf Filippos Giannakos
    subparsers = parser.add_subparsers()
402 e278c46e Filippos Giannakos
403 c3c33dd0 Christos Stavrakakis
404 2e9bddbf Filippos Giannakos
    init_parser = subparsers.add_parser('init',
405 2e9bddbf Filippos Giannakos
            help="Initialize a new devflow repo")
406 2e9bddbf Filippos Giannakos
    init_parser.add_argument('-m', '--master', type=str, nargs='?',
407 2e9bddbf Filippos Giannakos
            help="Master branch")
408 2e9bddbf Filippos Giannakos
    init_parser.add_argument('-d', '--develop', type=str, nargs='?',
409 2e9bddbf Filippos Giannakos
            help="Develop branch")
410 2e9bddbf Filippos Giannakos
    init_parser.set_defaults(func='init_repo')
411 c3c33dd0 Christos Stavrakakis
412 c3c33dd0 Christos Stavrakakis
413 2e9bddbf Filippos Giannakos
    feature_parser = subparsers.add_parser('feature', help="Feature options")
414 2e9bddbf Filippos Giannakos
    feature_subparsers = feature_parser.add_subparsers()
415 2e9bddbf Filippos Giannakos
416 2e9bddbf Filippos Giannakos
    feature_start_parser = feature_subparsers.add_parser('start',
417 2e9bddbf Filippos Giannakos
            help="Start a new feature")
418 2e9bddbf Filippos Giannakos
    feature_start_parser.set_defaults(func='start_feature')
419 2e9bddbf Filippos Giannakos
    feature_start_parser.add_argument('feature_name', type=str,
420 2e9bddbf Filippos Giannakos
            help="Name of the feature")
421 2e9bddbf Filippos Giannakos
422 2e9bddbf Filippos Giannakos
    feature_finish_parser = feature_subparsers.add_parser('finish',
423 2e9bddbf Filippos Giannakos
            help="Finish a feature")
424 2e9bddbf Filippos Giannakos
    feature_finish_parser.set_defaults(func='end_feature')
425 2e9bddbf Filippos Giannakos
    feature_finish_parser.add_argument('feature_name', type=str,
426 2e9bddbf Filippos Giannakos
            help="Name of the feature")
427 2e9bddbf Filippos Giannakos
    feature_finish_parser.add_argument('--no-edit-changelog',
428 2e9bddbf Filippos Giannakos
            action='store_const', const=False, dest='edit_changelog',
429 2e9bddbf Filippos Giannakos
            help="Do not edit the changelog")
430 2e9bddbf Filippos Giannakos
    feature_finish_parser.add_argument('--no-cleanup', action='store_const',
431 2e9bddbf Filippos Giannakos
            const=True, dest='cleanup', help="Do not cleanup branches")
432 2e9bddbf Filippos Giannakos
433 2e9bddbf Filippos Giannakos
    release_parser = subparsers.add_parser('release', help="release options")
434 2e9bddbf Filippos Giannakos
    release_subparsers = release_parser.add_subparsers()
435 2e9bddbf Filippos Giannakos
436 2e9bddbf Filippos Giannakos
437 2e9bddbf Filippos Giannakos
    release_start_parser = release_subparsers.add_parser('start',
438 2e9bddbf Filippos Giannakos
            help="Start a new release")
439 2e9bddbf Filippos Giannakos
    release_start_parser.add_argument('--version', type=str,
440 2e9bddbf Filippos Giannakos
            help="Version of the release")
441 2e9bddbf Filippos Giannakos
    release_start_parser.add_argument('--develop-version', type=str,
442 2e9bddbf Filippos Giannakos
            help="New develop version")
443 2e9bddbf Filippos Giannakos
    release_start_parser.set_defaults(func='start_release')
444 2e9bddbf Filippos Giannakos
445 2e9bddbf Filippos Giannakos
446 2e9bddbf Filippos Giannakos
    release_finish_parser = release_subparsers.add_parser('finish',
447 2e9bddbf Filippos Giannakos
            help="Finish a release")
448 2e9bddbf Filippos Giannakos
    release_finish_parser.add_argument('version', type=str,
449 2e9bddbf Filippos Giannakos
            help="Version of the release")
450 2e9bddbf Filippos Giannakos
    release_finish_parser.add_argument('--no-edit-changelog',
451 2e9bddbf Filippos Giannakos
            action='store_const', const=False, dest='edit_changelog',
452 2e9bddbf Filippos Giannakos
            help="Do not edit the changelog")
453 2e9bddbf Filippos Giannakos
    release_finish_parser.add_argument('--no-cleanup', action='store_const',
454 2e9bddbf Filippos Giannakos
            const=True, dest='cleanup', help="Do not cleanup branches")
455 2e9bddbf Filippos Giannakos
456 2e9bddbf Filippos Giannakos
    release_finish_parser.set_defaults(func='end_release')
457 2e9bddbf Filippos Giannakos
458 2e9bddbf Filippos Giannakos
    hotfix_parser = subparsers.add_parser('hotfix', help="hotfix options")
459 2e9bddbf Filippos Giannakos
    hotfix_subparsers = hotfix_parser.add_subparsers()
460 2e9bddbf Filippos Giannakos
461 2e9bddbf Filippos Giannakos
462 2e9bddbf Filippos Giannakos
    hotfix_start_parser = hotfix_subparsers.add_parser('start',
463 2e9bddbf Filippos Giannakos
            help="Start a new hotfix")
464 2e9bddbf Filippos Giannakos
    hotfix_start_parser.add_argument('--version', type=str,
465 2e9bddbf Filippos Giannakos
            help="Version of the hotfix")
466 2e9bddbf Filippos Giannakos
    hotfix_start_parser.add_argument('--develop-version', type=str,
467 2e9bddbf Filippos Giannakos
            help="New develop version")
468 2e9bddbf Filippos Giannakos
    hotfix_start_parser.set_defaults(func='start_hotfix')
469 2e9bddbf Filippos Giannakos
470 2e9bddbf Filippos Giannakos
471 2e9bddbf Filippos Giannakos
    hotfix_finish_parser = hotfix_subparsers.add_parser('finish',
472 2e9bddbf Filippos Giannakos
            help="Finish a hotfix")
473 2e9bddbf Filippos Giannakos
    hotfix_finish_parser.add_argument('version', type=str,
474 2e9bddbf Filippos Giannakos
            help="Version of the hotfix")
475 2e9bddbf Filippos Giannakos
    hotfix_finish_parser.add_argument('--no-edit-changelog',
476 2e9bddbf Filippos Giannakos
            action='store_const', const=False, dest='edit_changelog',
477 2e9bddbf Filippos Giannakos
            help="Do not edit the changelog")
478 2e9bddbf Filippos Giannakos
    hotfix_finish_parser.add_argument('--no-cleanup', action='store_const',
479 2e9bddbf Filippos Giannakos
            const=True, dest='cleanup', help="Do not cleanup branches")
480 2e9bddbf Filippos Giannakos
    hotfix_finish_parser.set_defaults(func='end_hotfix')
481 2e9bddbf Filippos Giannakos
482 2e9bddbf Filippos Giannakos
483 2e9bddbf Filippos Giannakos
484 2e9bddbf Filippos Giannakos
    args = parser.parse_args()
485 c3c33dd0 Christos Stavrakakis
486 c3c33dd0 Christos Stavrakakis
    gm = GitManager()
487 2e9bddbf Filippos Giannakos
    getattr(gm, args.func)(args)
488 2e9bddbf Filippos Giannakos
489 c3c33dd0 Christos Stavrakakis
490 c3c33dd0 Christos Stavrakakis
if __name__ == "__main__":
491 c3c33dd0 Christos Stavrakakis
    main()