git_reflow 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
File without changes
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,91 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ git_reflow (0.2)
5
+ github_api (= 0.6.5)
6
+ gli (= 2.0.0)
7
+ highline
8
+ httpclient
9
+ json_pure (= 1.7.5)
10
+
11
+ GEM
12
+ remote: http://rubygems.org/
13
+ specs:
14
+ addressable (2.3.2)
15
+ aruba (0.4.11)
16
+ childprocess (>= 0.2.3)
17
+ cucumber (>= 1.1.1)
18
+ ffi (>= 1.0.11)
19
+ rspec (>= 2.7.0)
20
+ builder (3.0.0)
21
+ childprocess (0.3.5)
22
+ ffi (~> 1.0, >= 1.0.6)
23
+ crack (0.3.1)
24
+ cucumber (1.2.1)
25
+ builder (>= 2.1.2)
26
+ diff-lcs (>= 1.1.3)
27
+ gherkin (~> 2.11.0)
28
+ json (>= 1.4.6)
29
+ diff-lcs (1.1.3)
30
+ faraday (0.8.4)
31
+ multipart-post (~> 1.1)
32
+ ffi (1.1.5)
33
+ gherkin (2.11.2)
34
+ json (>= 1.4.6)
35
+ git (1.2.5)
36
+ github_api (0.6.5)
37
+ faraday (~> 0.8.1)
38
+ hashie (~> 1.2.0)
39
+ multi_json (~> 1.3)
40
+ nokogiri (~> 1.5.2)
41
+ oauth2
42
+ gli (2.0.0)
43
+ hashie (1.2.0)
44
+ highline (1.6.14)
45
+ httpauth (0.1)
46
+ httpclient (2.2.7)
47
+ jeweler (1.8.4)
48
+ bundler (~> 1.0)
49
+ git (>= 1.2.5)
50
+ rake
51
+ rdoc
52
+ json (1.7.5)
53
+ json_pure (1.7.5)
54
+ jwt (0.1.5)
55
+ multi_json (>= 1.0)
56
+ multi_json (1.3.6)
57
+ multipart-post (1.1.5)
58
+ nokogiri (1.5.5)
59
+ oauth2 (0.8.0)
60
+ faraday (~> 0.8)
61
+ httpauth (~> 0.1)
62
+ jwt (~> 0.1.4)
63
+ multi_json (~> 1.0)
64
+ rack (~> 1.2)
65
+ rack (1.4.1)
66
+ rake (0.9.2.2)
67
+ rdoc (3.12)
68
+ json (~> 1.4)
69
+ rspec (2.11.0)
70
+ rspec-core (~> 2.11.0)
71
+ rspec-expectations (~> 2.11.0)
72
+ rspec-mocks (~> 2.11.0)
73
+ rspec-core (2.11.1)
74
+ rspec-expectations (2.11.2)
75
+ diff-lcs (~> 1.1.3)
76
+ rspec-mocks (2.11.2)
77
+ webmock (1.8.9)
78
+ addressable (>= 2.2.7)
79
+ crack (>= 0.1.7)
80
+
81
+ PLATFORMS
82
+ ruby
83
+
84
+ DEPENDENCIES
85
+ aruba (~> 0.4.6)
86
+ git_reflow!
87
+ jeweler
88
+ rake
89
+ rdoc
90
+ rspec
91
+ webmock
data/README.rdoc ADDED
@@ -0,0 +1,39 @@
1
+ git-reflow
2
+ ==========
3
+ Tools to help build software that just works.
4
+
5
+ How it works
6
+ -------------
7
+ `$ git reflow setup`
8
+ Sets up your Github credentials
9
+
10
+ `$ git reflow start branch-name`
11
+ Creates new branch
12
+ Prompts for PT ticket numbers? (Keep the PT stuff as a plugin?)
13
+
14
+ `$ git reflow review [branch]`
15
+ Assumes remote 'origin'
16
+ Performs the following against [branch] or master if branch is not specified:
17
+ `git fetch origin`
18
+ - Are we up-to-date with changes from the destination?
19
+ - Fail with "origin/[branch] has newer changes" if no
20
+ - Run the test suite
21
+ - If fails, do not continue
22
+ - If not configured, fail with "Run test suite then use flag --green"
23
+ `git push origin current-branch` # Updates remote branch
24
+ - Do we have pull request?
25
+ - if no, create it and print "Pull request created at http://pull-url/"
26
+
27
+ `$ git reflow deliver [branch]`
28
+ - Do we have lgtm after last commit?
29
+ - If no, print "Still waiting for review" (Maybe provide a way to skip this with `--lgtm`?)
30
+ - Prompt "Accepted by:" and get name/email/github username of person who does acceptance
31
+ - Checkout destination branch
32
+ - Update destination from origin (`git pull origin [branch]`)
33
+ - Merge squashed (`git merge --squash branch-name`)
34
+ - Prepare commit message (Adds Closes #pull-request-number)
35
+ - Perform the commit
36
+ - Push to branch
37
+ - Delete the remote branch
38
+ - Delete the local branch
39
+ - Deploy (Maybe with flag `--deploy`)
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'rake'
2
+ require 'bundler/gem_tasks'
3
+ require 'cucumber'
4
+ require 'cucumber/rake/task'
5
+
6
+ Dir[File.join(File.dirname(__FILE__),'lib/tasks/*.rake')].each { |f| load f }
7
+
8
+ Cucumber::Rake::Task.new(:features) do |t|
9
+ t.cucumber_opts = "features --format pretty -x"
10
+ t.fork = false
11
+ end
12
+
13
+ task :default => [:spec, :cucumber]
data/bin/git-reflow ADDED
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env ruby
2
+ # 1.9 adds realpath to resolve symlinks; 1.8 doesn't
3
+ # have this method, so we add it so we get resolved symlinks
4
+ # and compatibility
5
+ unless File.respond_to? :realpath
6
+ class File #:nodoc:
7
+ def self.realpath path
8
+ return realpath(File.readlink(path)) if symlink?(path)
9
+ path
10
+ end
11
+ end
12
+ end
13
+ $: << File.expand_path(File.dirname(File.realpath(__FILE__)) + '/../lib')
14
+ require 'rubygems'
15
+ require 'gli'
16
+ require 'git_reflow'
17
+ require 'git_reflow/version'
18
+
19
+ include GLI::App
20
+
21
+ program_desc 'Git Reflow manages your git workflow.'
22
+
23
+ version GitReflow::VERSION
24
+
25
+ desc 'Describe some switch here'
26
+ switch [:s,:switch]
27
+
28
+ desc 'Describe some flag here'
29
+ default_value 'the default'
30
+ arg_name 'The name of the argument'
31
+ flag [:f,:flagname]
32
+
33
+ desc 'Setup your GitHub account'
34
+ command :setup do |c|
35
+ c.action do |global_options,options,args|
36
+ GitReflow.setup
37
+ end
38
+ end
39
+
40
+ desc 'Start will create a new feature branch and setup remote tracking'
41
+ arg_name 'Describe arguments to start here'
42
+ command :start do |c|
43
+ c.desc 'Describe a switch to start'
44
+ c.switch :s
45
+
46
+ c.desc 'Describe a flag to start'
47
+ c.default_value 'default'
48
+ c.flag :f
49
+ c.action do |global_options,options,args|
50
+
51
+ # Your command logic here
52
+ if args.empty?
53
+ raise "usage: git-reflow start [new-branch-name]"
54
+ else
55
+ `git push origin master:refs/heads/#{args[0]}`
56
+ `git fetch origin`
57
+ `git checkout --track -b #{args[0]} origin/#{args[0]}`
58
+ end
59
+ # If you have any errors, just raise them
60
+ # raise "that command made no sense"
61
+ end
62
+ end
63
+
64
+ desc 'Describe review here'
65
+ arg_name 'Describe arguments to review here'
66
+ command :review do |c|
67
+ c.action do |global_options,options,args|
68
+ review_options = {'base' => nil, 'title' => nil, 'body' => nil}
69
+ case args.length
70
+ when 3
71
+ review_options['base'] = args[0]
72
+ review_options['title'] = args[1]
73
+ review_options['body'] = args[2]
74
+ when 2
75
+ review_options['base'] = args[0]
76
+ review_options['title'] = args[1]
77
+ review_options['body'] = review_options['title']
78
+ when 1
79
+ review_options['base'] = args[0]
80
+ review_options['title'] = review_options['body'] = GitReflow.get_first_commit_message
81
+ else
82
+ review_options['title'] = review_options['body'] = GitReflow.get_first_commit_message
83
+ end
84
+ GitReflow.review review_options
85
+ end
86
+ end
87
+
88
+ desc 'deliver will merge your feature branch down to your base branch'
89
+ arg_name 'base_branch - the branch you want to merge into'
90
+ command :deliver do |c|
91
+ c.action do |global_options,options,args|
92
+ deliver_options = {'base' => nil, 'head' => nil}
93
+ case args.length
94
+ when 2
95
+ deliver_options['base'] = args[0]
96
+ deliver_options['head'] = args[1]
97
+ when 1
98
+ deliver_options['base'] = args[0]
99
+ end
100
+ GitReflow.deliver deliver_options
101
+ end
102
+ end
103
+
104
+ pre do |global,command,options,args|
105
+ # Pre logic here
106
+ # Return true to proceed; false to abourt and not call the
107
+ # chosen command
108
+ # Use skips_pre before a command to skip this block
109
+ # on that command only
110
+ true
111
+ end
112
+
113
+ post do |global,command,options,args|
114
+ # Post logic here
115
+ # Use skips_post before a command to skip this
116
+ # block on that command only
117
+ end
118
+
119
+ on_error do |exception|
120
+ # Error logic here
121
+ # return false to skip default error handling
122
+ true
123
+ end
124
+
125
+ exit run(ARGV)
@@ -0,0 +1,314 @@
1
+ #!/bin/sh
2
+ # git-flow -- A collection of Git extensions to provide high-level
3
+ # repository operations for Vincent Driessen's branching model.
4
+ #
5
+ # Original blog post presenting this model is found at:
6
+ # http://nvie.com/git-model
7
+ #
8
+ # Feel free to contribute to this project at:
9
+ # http://github.com/nvie/gitreflow
10
+ #
11
+ # Copyright 2010 Vincent Driessen. All rights reserved.
12
+ #
13
+ # Redistribution and use in source and binary forms, with or without
14
+ # modification, are permitted provided that the following conditions are met:
15
+ #
16
+ # 1. Redistributions of source code must retain the above copyright notice,
17
+ # this list of conditions and the following disclaimer.
18
+ #
19
+ # 2. Redistributions in binary form must reproduce the above copyright
20
+ # notice, this list of conditions and the following disclaimer in the
21
+ # documentation and/or other materials provided with the distribution.
22
+ #
23
+ # THIS SOFTWARE IS PROVIDED BY VINCENT DRIESSEN ``AS IS'' AND ANY EXPRESS OR
24
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25
+ # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
26
+ # EVENT SHALL VINCENT DRIESSEN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28
+ # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
30
+ # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
32
+ # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
+ #
34
+ # The views and conclusions contained in the software and documentation are
35
+ # those of the authors and should not be interpreted as representing official
36
+ # policies, either expressed or implied, of Vincent Driessen.
37
+ #
38
+
39
+ #
40
+ # Common functionality
41
+ #
42
+
43
+ # shell output
44
+ warn() { echo "$@" >&2; }
45
+ die() { warn "$@"; exit 1; }
46
+
47
+ escape() {
48
+ echo "$1" | sed 's/\([\.\+\$\*]\)/\\\1/g'
49
+ }
50
+
51
+ # set logic
52
+ has() {
53
+ local item=$1; shift
54
+ echo " $@ " | grep -q " $(escape $item) "
55
+ }
56
+
57
+ # basic math
58
+ min() { [ "$1" -le "$2" ] && echo "$1" || echo "$2"; }
59
+ max() { [ "$1" -ge "$2" ] && echo "$1" || echo "$2"; }
60
+
61
+ # basic string matching
62
+ startswith() { [ "$1" != "${1#$2}" ]; }
63
+ endswith() { [ "$1" != "${1%$2}" ]; }
64
+
65
+ #
66
+ # Git specific common functionality
67
+ #
68
+
69
+ git_local_branches() { git branch --no-color | sed 's/^[* ] //'; }
70
+ git_remote_branches() { git branch -r --no-color | sed 's/^[* ] //'; }
71
+ git_all_branches() { ( git branch --no-color; git branch -r --no-color) | sed 's/^[* ] //'; }
72
+ git_all_tags() { git tag; }
73
+
74
+ git_current_branch() {
75
+ git branch --no-color | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g'
76
+ }
77
+
78
+ git_is_clean_working_tree() {
79
+ if ! git diff --no-ext-diff --ignore-submodules --quiet --exit-code; then
80
+ return 1
81
+ elif ! git diff-index --cached --quiet --ignore-submodules HEAD --; then
82
+ return 2
83
+ else
84
+ return 0
85
+ fi
86
+ }
87
+
88
+ git_repo_is_headless() {
89
+ ! git rev-parse --quiet --verify HEAD >/dev/null 2>&1
90
+ }
91
+
92
+ git_local_branch_exists() {
93
+ has $1 $(git_local_branches)
94
+ }
95
+
96
+ git_remote_branch_exists() {
97
+ has $1 $(git_remote_branches)
98
+ }
99
+
100
+ git_branch_exists() {
101
+ has $1 $(git_all_branches)
102
+ }
103
+
104
+ git_tag_exists() {
105
+ has $1 $(git_all_tags)
106
+ }
107
+
108
+ #
109
+ # git_compare_branches()
110
+ #
111
+ # Tests whether branches and their "origin" counterparts have diverged and need
112
+ # merging first. It returns error codes to provide more detail, like so:
113
+ #
114
+ # 0 Branch heads point to the same commit
115
+ # 1 First given branch needs fast-forwarding
116
+ # 2 Second given branch needs fast-forwarding
117
+ # 3 Branch needs a real merge
118
+ # 4 There is no merge base, i.e. the branches have no common ancestors
119
+ #
120
+ git_compare_branches() {
121
+ local commit1=$(git rev-parse "$1")
122
+ local commit2=$(git rev-parse "$2")
123
+ if [ "$commit1" != "$commit2" ]; then
124
+ local base=$(git merge-base "$commit1" "$commit2")
125
+ if [ $? -ne 0 ]; then
126
+ return 4
127
+ elif [ "$commit1" = "$base" ]; then
128
+ return 1
129
+ elif [ "$commit2" = "$base" ]; then
130
+ return 2
131
+ else
132
+ return 3
133
+ fi
134
+ else
135
+ return 0
136
+ fi
137
+ }
138
+
139
+ #
140
+ # git_is_branch_merged_into()
141
+ #
142
+ # Checks whether branch $1 is succesfully merged into $2
143
+ #
144
+ git_is_branch_merged_into() {
145
+ local subject=$1
146
+ local base=$2
147
+ local all_merges="$(git branch --no-color --contains $subject | sed 's/^[* ] //')"
148
+ has $base $all_merges
149
+ }
150
+
151
+ #
152
+ # gitreflow specific common functionality
153
+ #
154
+
155
+ # check if this repo has been inited for gitreflow
156
+ gitreflow_has_master_configured() {
157
+ local master=$(git config --get gitreflow.branch.master)
158
+ [ "$master" != "" ] && git_local_branch_exists "$master"
159
+ }
160
+
161
+ gitreflow_has_develop_configured() {
162
+ local develop=$(git config --get gitreflow.branch.develop)
163
+ [ "$develop" != "" ] && git_local_branch_exists "$develop"
164
+ }
165
+
166
+ gitreflow_has_prefixes_configured() {
167
+ git config --get gitreflow.prefix.feature >/dev/null 2>&1 && \
168
+ git config --get gitreflow.prefix.release >/dev/null 2>&1 && \
169
+ git config --get gitreflow.prefix.hotfix >/dev/null 2>&1 && \
170
+ git config --get gitreflow.prefix.support >/dev/null 2>&1 && \
171
+ git config --get gitreflow.prefix.versiontag >/dev/null 2>&1
172
+ }
173
+
174
+ gitreflow_is_initialized() {
175
+ gitreflow_has_master_configured && \
176
+ gitreflow_has_develop_configured && \
177
+ [ "$(git config --get gitreflow.branch.master)" != \
178
+ "$(git config --get gitreflow.branch.develop)" ] && \
179
+ gitreflow_has_prefixes_configured
180
+ }
181
+
182
+ # loading settings that can be overridden using git config
183
+ gitreflow_load_settings() {
184
+ export DOT_GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
185
+ export MASTER_BRANCH=$(git config --get gitreflow.branch.master)
186
+ export DEVELOP_BRANCH=$(git config --get gitreflow.branch.develop)
187
+ export ORIGIN=$(git config --get gitreflow.origin || echo origin)
188
+ }
189
+
190
+ #
191
+ # gitreflow_resolve_nameprefix
192
+ #
193
+ # Inputs:
194
+ # $1 = name prefix to resolve
195
+ # $2 = branch prefix to use
196
+ #
197
+ # Searches branch names from git_local_branches() to look for a unique
198
+ # branch name whose name starts with the given name prefix.
199
+ #
200
+ # There are multiple exit codes possible:
201
+ # 0: The unambiguous full name of the branch is written to stdout
202
+ # (success)
203
+ # 1: No match is found.
204
+ # 2: Multiple matches found. These matches are written to stderr
205
+ #
206
+ gitreflow_resolve_nameprefix() {
207
+ local name=$1
208
+ local prefix=$2
209
+ local matches
210
+ local num_matches
211
+
212
+ # first, check if there is a perfect match
213
+ if git_local_branch_exists "$prefix$name"; then
214
+ echo "$name"
215
+ return 0
216
+ fi
217
+
218
+ matches=$(echo "$(git_local_branches)" | grep "^$(escape "$prefix$name")")
219
+ num_matches=$(echo "$matches" | wc -l)
220
+ if [ -z "$matches" ]; then
221
+ # no prefix match, so take it literally
222
+ warn "No branch matches prefix '$name'"
223
+ return 1
224
+ else
225
+ if [ $num_matches -eq 1 ]; then
226
+ echo "${matches#$prefix}"
227
+ return 0
228
+ else
229
+ # multiple matches, cannot decide
230
+ warn "Multiple branches match prefix '$name':"
231
+ for match in $matches; do
232
+ warn "- $match"
233
+ done
234
+ return 2
235
+ fi
236
+ fi
237
+ }
238
+
239
+ #
240
+ # Assertions for use in git-flow subcommands
241
+ #
242
+
243
+ require_git_repo() {
244
+ if ! git rev-parse --git-dir >/dev/null 2>&1; then
245
+ die "fatal: Not a git repository"
246
+ fi
247
+ }
248
+
249
+ require_gitreflow_initialized() {
250
+ if ! gitreflow_is_initialized; then
251
+ die "fatal: Not a gitreflow-enabled repo yet. Please run \"git flow init\" first."
252
+ fi
253
+ }
254
+
255
+ require_clean_working_tree() {
256
+ git_is_clean_working_tree
257
+ local result=$?
258
+ if [ $result -eq 1 ]; then
259
+ die "fatal: Working tree contains unstaged changes. Aborting."
260
+ fi
261
+ if [ $result -eq 2 ]; then
262
+ die "fatal: Index contains uncommited changes. Aborting."
263
+ fi
264
+ }
265
+
266
+ require_local_branch() {
267
+ if ! git_local_branch_exists $1; then
268
+ die "fatal: Local branch '$1' does not exist and is required."
269
+ fi
270
+ }
271
+
272
+ require_remote_branch() {
273
+ if ! has $1 $(git_remote_branches); then
274
+ die "Remote branch '$1' does not exist and is required."
275
+ fi
276
+ }
277
+
278
+ require_branch() {
279
+ if ! has $1 $(git_all_branches); then
280
+ die "Branch '$1' does not exist and is required."
281
+ fi
282
+ }
283
+
284
+ require_branch_absent() {
285
+ if has $1 $(git_all_branches); then
286
+ die "Branch '$1' already exists. Pick another name."
287
+ fi
288
+ }
289
+
290
+ require_tag_absent() {
291
+ for tag in $(git_all_tags); do
292
+ if [ "$1" = "$tag" ]; then
293
+ die "Tag '$1' already exists. Pick another name."
294
+ fi
295
+ done
296
+ }
297
+
298
+ require_branches_equal() {
299
+ require_local_branch "$1"
300
+ require_remote_branch "$2"
301
+ git_compare_branches "$1" "$2"
302
+ local status=$?
303
+ if [ $status -gt 0 ]; then
304
+ warn "Branches '$1' and '$2' have diverged."
305
+ if [ $status -eq 1 ]; then
306
+ die "And branch '$1' may be fast-forwarded."
307
+ elif [ $status -eq 2 ]; then
308
+ # Warn here, since there is no harm in being ahead
309
+ warn "And local branch '$1' is ahead of '$2'."
310
+ else
311
+ die "Branches need merging first."
312
+ fi
313
+ fi
314
+ }
@@ -0,0 +1,4 @@
1
+ When /^I debug$/ do
2
+ debugger
3
+ end
4
+
@@ -0,0 +1,3 @@
1
+ When /^I build and install the gem$/ do
2
+ CukeGem.setup('./git_reflow.gemspec')
3
+ end