Statistics
| Branch: | Tag: | Revision:

root / devflow / flow.py @ 842df8ac

History | View | Annotate | Download (5.7 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
    @cleanup
59
    def start_release(self, version):
60
        self.start_common("release", version)
61

    
62
    @cleanup
63
    def start_hotfix(self, version):
64
        self.start_common("hotfix", version)
65

    
66
    @cleanup
67
    def end_release(self, version):
68
        self.end_common("release", version)
69

    
70
    @cleanup
71
    def end_hotfix(self, version):
72
        self.end_common("hotfix", version)
73

    
74
    def start_common(self, mode, version):
75
        if mode not in ["release", "hotfix"]:
76
            raise ValueError("Unknown mode: %s" % mode)
77
        repo = self.repo
78
        upstream = "develop" if mode == "release" else "master"
79
        debian = "debian-develop" if mode == "release" else "debian"
80
        upstream_branch = "%s-%s" % (mode, version)
81
        debian_branch = "debian-%s-%s" % (mode, version)
82
        repo.git.checkout(upstream)
83
        repo.git.branch(upstream_branch, upstream)
84
        self.new_branches.append(upstream_branch)
85
        versioning.bump_version("%snext" % version)
86
        repo.git.checkout(upstream_branch)
87
        versioning.bump_version("%src1" % version)
88
        repo.git.checkout(debian)
89
        repo.git.branch(debian_branch, debian)
90
        self.new_branches.append(debian_branch)
91
        repo.git.checkout(upstream_branch)
92
        repo.git.checkout(debian)
93

    
94
    @cleanup
95
    def start_feature(self, feature_name):
96
        repo = self.repo
97
        feature_upstream = "feature-%s" % feature_name
98
        feature_debian = "debian-%s" % feature_upstream
99
        repo.git.branch(feature_upstream, "develop")
100
        self.new_branches.append(feature_upstream)
101
        repo.git.branch(feature_debian, "debian-develop")
102
        self.new_branches.append(feature_debian)
103

    
104
    @cleanup
105
    def end_feature(self, feature_name):
106
        repo = self.repo
107
        feature_upstream = "feature-%s" % feature_name
108
        if not feature_upstream in repo.branches:
109
            raise ValueError("Branch %s does not exist." % feature_upstream)
110
        feature_debian = "debian-%s" % feature_upstream
111
        repo.git.checkout("develop")
112
        with conflicts():
113
            repo.git.merge(feature_upstream)
114
        repo.git.checkout("debian-develop")
115
        if feature_debian in repo.branches:
116
            with conflicts():
117
                repo.git.merge(feature_debian)
118
        repo.git.checkout("develop")
119
        print "To remove obsolete branches run:"
120
        print "git branch -D %s" % feature_upstream
121
        if feature_debian in repo.branches:
122
            print "git branch -D %s" % feature_debian
123

    
124
    def end_common(self, mode, version):
125
        if mode not in ["release", "hotfix"]:
126
            raise ValueError("Unknown mode: %s" % mode)
127
        repo = self.repo
128
        master = "master"
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
        with conflicts():
135
            repo.git.merge("--no-ff", upstream_branch)
136
        repo.git.checkout(master)
137
        with conflicts():
138
            repo.git.merge("--no-ff", upstream_branch)
139
        repo.git.checkout(debian)
140
        with conflicts():
141
            repo.git.merge("--no-ff", debian_branch)
142
        repo.git.checkout(upstream)
143
        print "To remove obsolete branches run:"
144
        print "git branch -d %s" % upstream_branch
145
        print "git branch -d %s" % debian_branch
146

    
147

    
148
def refhead(repo):
149
    return repo.head.log[-1].newhexsha
150

    
151

    
152
def main():
153
    HELP_MSG = "usage: %prog mode=[release|hotfix|feature]"\
154
               " [version|name]"
155
    parser = OptionParser(usage=HELP_MSG,
156
                          version="devflow-flow %s" % __version__,
157
                          add_help_option=True)
158
    options, args = parser.parse_args()
159
    if len(args) != 3:
160
        parser.error("Invalid number of arguments.")
161
    mode, action, version = args
162
    gm = GitManager()
163
    func = "%s_%s" % (action, mode)
164
    try:
165
        getattr(gm, func)(version)
166
    except AttributeError:
167
        parser.error("Invalid arguments.")
168

    
169
if __name__ == "__main__":
170
    main()