git_reflow 0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +0 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +91 -0
- data/README.rdoc +39 -0
- data/Rakefile +13 -0
- data/bin/git-reflow +125 -0
- data/bin/gitreflow-common +314 -0
- data/features/step_definitions/debug_steps.rb +4 -0
- data/features/step_definitions/gem_steps.rb +3 -0
- data/features/step_definitions/git_steps.rb +138 -0
- data/features/support/env.rb +27 -0
- data/features/support/gem.rb +85 -0
- data/features/support/github_helpers.rb +3 -0
- data/features/user_delivers_flow.feature +22 -0
- data/features/user_installs_gem.feature +18 -0
- data/features/user_starts_flow.feature +19 -0
- data/git_reflow.gemspec +32 -0
- data/lib/git_reflow/base.rb +0 -0
- data/lib/git_reflow/version.rb +3 -0
- data/lib/git_reflow.rb +233 -0
- data/spec/fixtures/git/git_config +7 -0
- data/spec/fixtures/pull_requests/pull_request.json +123 -0
- data/spec/fixtures/pull_requests/pull_request_exists_error.json +32 -0
- data/spec/fixtures/pull_requests/pull_requests.json +117 -0
- data/spec/git_reflow_spec.rb +139 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/support/fixtures.rb +8 -0
- data/spec/support/github_helpers.rb +45 -0
- data/spec/support/web_mocks.rb +39 -0
- metadata +287 -0
@@ -0,0 +1,138 @@
|
|
1
|
+
Given /^I have a git repository with a branch named "([^"]+)" checked out$/ do |branch_name|
|
2
|
+
steps %{
|
3
|
+
Given a directory named "master_repo"
|
4
|
+
And I cd to "master_repo"
|
5
|
+
And I write to "README" with:
|
6
|
+
| Initialized |
|
7
|
+
And I successfully run `git init`
|
8
|
+
And I successfully run `git add README`
|
9
|
+
And I successfully run `git commit -m "Initial commit"`
|
10
|
+
}
|
11
|
+
|
12
|
+
unless branch_name == "master"
|
13
|
+
steps %{
|
14
|
+
And I successfully run `git checkout -b #{branch_name}`
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
steps %{
|
19
|
+
And I cd to ".."
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
Given /^I have a remote git repository named "([^"]+)"$/ do |remote_name|
|
24
|
+
steps %{
|
25
|
+
Given a directory named "#{remote_name}_repo"
|
26
|
+
When I cd to "#{remote_name}_repo"
|
27
|
+
And I successfully run `git init`
|
28
|
+
And I write to "README" with:
|
29
|
+
| Initialized |
|
30
|
+
And I successfully run `git add .`
|
31
|
+
And I successfully run `git commit -am "Initial commit"`
|
32
|
+
And I cd to ".."
|
33
|
+
And I cd to "master_repo"
|
34
|
+
And I successfully run `git remote add #{remote_name} ../#{remote_name}_repo`
|
35
|
+
And I cd to ".."
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
Given /^the remote repository named "([^"]+)" has changes on the "([^"]+)" branch$/ do |remote_name, branch_name|
|
40
|
+
steps %{
|
41
|
+
Given a directory named "#{remote_name}_repo"
|
42
|
+
When I cd to "#{remote_name}_repo"
|
43
|
+
And I successfully run `git checkout #{branch_name}`
|
44
|
+
And I append to "README" with:
|
45
|
+
| changed |
|
46
|
+
And I successfully run `git add .`
|
47
|
+
And I successfully run `git commit -am "Changed readme"`
|
48
|
+
And I cd to ".."
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
Given /^the repository has been initialized$/ do
|
53
|
+
steps %{
|
54
|
+
Given I successfully run `git branch`
|
55
|
+
Then the output should contain "master"
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
Given /^I have a new branch named "([^"]+)" checked out$/ do |branch_name|
|
60
|
+
steps %{
|
61
|
+
When I cd to "master_repo"
|
62
|
+
And I successfully run `git checkout -b #{branch_name}`
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
Given /^I have a reviewed feature branch named "([^"]+)" checked out$/ do |branch_name|
|
67
|
+
pull = {
|
68
|
+
"title" => "Amazing new feature",
|
69
|
+
"body" => "Please pull this in!",
|
70
|
+
"head" => "reenhanced:#{branch_name}",
|
71
|
+
"base" => "master",
|
72
|
+
"state" => "open"
|
73
|
+
}
|
74
|
+
stub_github_with(
|
75
|
+
:user => 'reenhanced',
|
76
|
+
:repo => 'repo',
|
77
|
+
:branch => branch_name,
|
78
|
+
:pull => pull
|
79
|
+
)
|
80
|
+
|
81
|
+
review_options = {
|
82
|
+
'base' => pull['base'],
|
83
|
+
'title' => pull['title'],
|
84
|
+
'body' => pull['body']
|
85
|
+
}
|
86
|
+
|
87
|
+
GitReflow.review review_options
|
88
|
+
|
89
|
+
# ensure we do not stay inside the remote repo
|
90
|
+
steps %{
|
91
|
+
Given I cd to ".."
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
When /^I deliver my "([^"]+)" branch$/ do |branch_name|
|
96
|
+
pull = {
|
97
|
+
"title" => "Amazing new feature",
|
98
|
+
"body" => "Please pull this in!",
|
99
|
+
"head" => "reenhanced:#{branch_name}",
|
100
|
+
"base" => "master",
|
101
|
+
"state" => "open"
|
102
|
+
}
|
103
|
+
stub_github_with(
|
104
|
+
:user => 'reenhanced',
|
105
|
+
:repo => 'repo',
|
106
|
+
:branch => branch_name,
|
107
|
+
:pull => pull
|
108
|
+
)
|
109
|
+
GitReflow.deliver
|
110
|
+
GitReflow.stub(:current_branch).and_return("master")
|
111
|
+
end
|
112
|
+
|
113
|
+
Then /^a branch named "([^"]+)" should have been created from "([^"]+)"$/ do |new_branch, base_branch|
|
114
|
+
steps %{
|
115
|
+
Then the output should match /\\* \\[new branch\\]\\s* #{Regexp.escape(base_branch)}\\s* \\-\\> #{Regexp.escape(new_branch)}/
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
Then /^the base branch named "([^"]+)" should have fetched changes from the remote git repository "([^"]+)"$/ do |base_branch, remote_name|
|
120
|
+
steps %{
|
121
|
+
Then the output should match /\\* \\[new branch\\]\\s* #{Regexp.escape(base_branch)}\\s* \\-\\> #{remote_name}.#{Regexp.escape(base_branch)}/
|
122
|
+
}
|
123
|
+
end
|
124
|
+
|
125
|
+
Then /^the subcommand "([^"]+)" should run$/ do |subcommand|
|
126
|
+
has_subcommand?(subcommand).should be_true
|
127
|
+
end
|
128
|
+
|
129
|
+
Then /^the branch "([^"]+)" should be checked out$/ do |branch_name|
|
130
|
+
GitReflow.current_branch.should == branch_name
|
131
|
+
end
|
132
|
+
|
133
|
+
Then /^the branch "([^"]+)" should be up to date with the remote repository$/ do |branch_name|
|
134
|
+
steps %{
|
135
|
+
When I successfully run `git pull origin #{branch_name}`
|
136
|
+
Then the output should contain "Already up-to-date"
|
137
|
+
}
|
138
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'aruba/cucumber'
|
2
|
+
require 'ruby-debug'
|
3
|
+
require 'webmock/cucumber'
|
4
|
+
require 'cucumber/rspec/doubles'
|
5
|
+
|
6
|
+
Before('@gem') do
|
7
|
+
CukeGem.setup('./git_reflow.gemspec')
|
8
|
+
end
|
9
|
+
|
10
|
+
After('@gem') do
|
11
|
+
CukeGem.teardown
|
12
|
+
end
|
13
|
+
|
14
|
+
Before do
|
15
|
+
FileUtils.rm_rf Dir.glob("#{Dir.tmpdir}/aruba")
|
16
|
+
end
|
17
|
+
|
18
|
+
WebMock.disable_net_connect!
|
19
|
+
|
20
|
+
def has_subcommand?(command)
|
21
|
+
# In order to see if a subcommand is run
|
22
|
+
# we have to look it up in Aruba's process list
|
23
|
+
# Aruba has a get_process helper, but it errors if none is found
|
24
|
+
# See: https://github.com/cucumber/aruba/blob/master/lib/aruba/api.rb#L239
|
25
|
+
found = processes.reverse.find{ |name, _| name == command }
|
26
|
+
found[-1] if found
|
27
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# Thanks to:
|
2
|
+
# Copyright 2011 Solano Labs All Rights Reserved
|
3
|
+
# https://gist.github.com/1132465
|
4
|
+
|
5
|
+
require 'aruba'
|
6
|
+
require 'aruba/api'
|
7
|
+
|
8
|
+
class CukeGem
|
9
|
+
@setup_done = false
|
10
|
+
|
11
|
+
class << self
|
12
|
+
include Aruba::Api
|
13
|
+
|
14
|
+
attr_reader :setup_done
|
15
|
+
|
16
|
+
def setup(gemspec, once=true)
|
17
|
+
gem_home = setup_env
|
18
|
+
if !@setup_done || !once then
|
19
|
+
@setup_done = true
|
20
|
+
mkgemdir(gem_home)
|
21
|
+
gem_install(gemspec)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def teardown
|
26
|
+
restore_env
|
27
|
+
end
|
28
|
+
|
29
|
+
def setup_env
|
30
|
+
tid = ENV['TDDIUM_TID'] || ''
|
31
|
+
gem_home = File.join(ENV['HOME'], 'tmp', 'aruba-gem')
|
32
|
+
gem_home = File.expand_path(gem_home)
|
33
|
+
|
34
|
+
set_env('GEM_HOME', gem_home)
|
35
|
+
set_env('GEM_PATH', gem_home)
|
36
|
+
set_env('BUNDLE_PATH', gem_home)
|
37
|
+
unset_bundler_env_vars
|
38
|
+
|
39
|
+
paths = (ENV['PATH'] || "").split(File::PATH_SEPARATOR)
|
40
|
+
paths.unshift(File.join(gem_home, 'bin'))
|
41
|
+
set_env('PATH', paths.uniq.join(File::PATH_SEPARATOR))
|
42
|
+
|
43
|
+
return gem_home
|
44
|
+
end
|
45
|
+
|
46
|
+
def mkgemdir(gem_home)
|
47
|
+
FileUtils::rm_rf(gem_home)
|
48
|
+
FileUtils::mkdir_p(gem_home)
|
49
|
+
|
50
|
+
output = `gem install bundler`
|
51
|
+
if $?.exitstatus != 0 then
|
52
|
+
raise "unable to install bundler into #{gem_home}: #{output}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def gem_install(gemspec)
|
57
|
+
gem_file = nil
|
58
|
+
begin
|
59
|
+
pwd = Dir.pwd
|
60
|
+
gemspec_dir = File.dirname(gemspec)
|
61
|
+
Dir.chdir(gemspec_dir)
|
62
|
+
output = `gem build #{File.basename(gemspec)}`
|
63
|
+
Dir.chdir(pwd)
|
64
|
+
|
65
|
+
if $?.exitstatus != 0 then
|
66
|
+
raise "unable to build gem: #{output}"
|
67
|
+
end
|
68
|
+
|
69
|
+
if output =~ /File:\s+([A-Za-z0-9_.-]+[.]gem)/ then
|
70
|
+
gem_file = $1
|
71
|
+
output = `gem install #{File.join(gemspec_dir, gem_file)}`
|
72
|
+
if $?.exitstatus != 0 then
|
73
|
+
raise "unable to install gem: #{output}"
|
74
|
+
end
|
75
|
+
else
|
76
|
+
raise "garbled gem build output: #{output}"
|
77
|
+
end
|
78
|
+
ensure
|
79
|
+
if gem_file then
|
80
|
+
FileUtils.rm_f(File.join(gemspec_dir, gem_file))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
@gem
|
2
|
+
Feature: User delivers a flow
|
3
|
+
As a User
|
4
|
+
I can deliver a flow
|
5
|
+
So I can merge in my topic branch
|
6
|
+
|
7
|
+
Background:
|
8
|
+
Given I have a git repository with a branch named "master" checked out
|
9
|
+
And I have a remote git repository named "origin"
|
10
|
+
And the remote repository named "origin" has changes on the "master" branch
|
11
|
+
And I cd to "master_repo"
|
12
|
+
When I run `git-reflow start new-branch`
|
13
|
+
And I append to "README" with:
|
14
|
+
| changed |
|
15
|
+
And I successfully run `git add .`
|
16
|
+
And I successfully run `git commit -am "Changed readme"`
|
17
|
+
Given I have a reviewed feature branch named "new-feature" checked out
|
18
|
+
|
19
|
+
Scenario: User runs git-reflow deliver without any parameters
|
20
|
+
When I deliver my "new-feature" branch
|
21
|
+
Then the branch "master" should be checked out
|
22
|
+
And the branch "master" should be up to date with the remote repository
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Feature: User installs gem
|
2
|
+
As a user
|
3
|
+
When I install a gem
|
4
|
+
It should initialize the gem configuration
|
5
|
+
|
6
|
+
Scenario: User installs gem
|
7
|
+
When I build and install the gem
|
8
|
+
Then the output should contain "You need to setup your GitHub OAuth token\nPlease run 'git-reflow setup'"
|
9
|
+
When I successfully run `git-reflow`
|
10
|
+
Then the output should contain "usage: git-reflow [global options] command [command options]"
|
11
|
+
|
12
|
+
Scenario: User sets up GitHub
|
13
|
+
When I run `git-reflow setup` interactively
|
14
|
+
And I type "user"
|
15
|
+
And I type "password"
|
16
|
+
Then the output should contain "Please enter your GitHub username: "
|
17
|
+
And the output should contain "Please enter your GitHub password (we do NOT store this): "
|
18
|
+
And the output should contain "Your GitHub account was successfully setup!"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
@gem
|
2
|
+
Feature: User starts a new flow
|
3
|
+
As a User
|
4
|
+
When I start a new flow
|
5
|
+
I should be on a new working feature branch
|
6
|
+
|
7
|
+
Scenario: User runs git-reflow start without any parameters
|
8
|
+
When I run `git-reflow start`
|
9
|
+
Then the output should contain "usage: git-reflow start [new-branch-name]"
|
10
|
+
|
11
|
+
Scenario: User runs git-reflow start with new branch name
|
12
|
+
Given I have a git repository with a branch named "master" checked out
|
13
|
+
And I have a remote git repository named "origin"
|
14
|
+
And the remote repository named "origin" has changes on the "master" branch
|
15
|
+
And I cd to "master_repo"
|
16
|
+
When I run `git-reflow start new-branch`
|
17
|
+
Then a branch named "new-branch" should have been created from "master"
|
18
|
+
And the base branch named "master" should have fetched changes from the remote git repository "origin"
|
19
|
+
And the output should contain "Switched to a new branch 'new-branch'"
|
data/git_reflow.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Ensure we require the local version and not one we might have installed already
|
2
|
+
require File.join([File.dirname(__FILE__),'lib','git_reflow/version.rb'])
|
3
|
+
spec = Gem::Specification.new do |s|
|
4
|
+
s.name = 'git_reflow'
|
5
|
+
s.version = GitReflow::VERSION
|
6
|
+
s.authors = ["Valentino Stoll", "Robert Stern", "Nicholas Hance"]
|
7
|
+
s.email = ["dev@reenhanced.com"]
|
8
|
+
s.homepage = "http://github.com/reenhanced/gitreflow"
|
9
|
+
s.summary = "A better git process"
|
10
|
+
s.description = "Git Reflow manages your git workflow."
|
11
|
+
s.platform = Gem::Platform::RUBY
|
12
|
+
s.files = `git ls-files`.split("\n")
|
13
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
15
|
+
s.has_rdoc = true
|
16
|
+
s.extra_rdoc_files = ['README.rdoc']
|
17
|
+
s.bindir = 'bin'
|
18
|
+
s.require_paths << 'lib'
|
19
|
+
s.rdoc_options << '--title' << 'git_reflow' << '--main' << 'README.rdoc' << '-ri'
|
20
|
+
s.add_development_dependency('rake')
|
21
|
+
s.add_development_dependency('rdoc')
|
22
|
+
s.add_development_dependency('rspec')
|
23
|
+
s.add_development_dependency('aruba', '~> 0.4.6')
|
24
|
+
s.add_development_dependency('jeweler')
|
25
|
+
s.add_development_dependency('webmock')
|
26
|
+
s.add_dependency('gli', '2.0.0')
|
27
|
+
s.add_dependency('json_pure', '1.7.5')
|
28
|
+
s.add_dependency('highline')
|
29
|
+
s.add_dependency('httpclient')
|
30
|
+
s.add_dependency('github_api', '0.6.5')
|
31
|
+
s.post_install_message = "You need to setup your GitHub OAuth token\nPlease run 'git-reflow setup'"
|
32
|
+
end
|
File without changes
|
data/lib/git_reflow.rb
ADDED
@@ -0,0 +1,233 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'json/pure'
|
4
|
+
require 'open-uri'
|
5
|
+
require "highline/import"
|
6
|
+
require 'httpclient'
|
7
|
+
require 'github_api'
|
8
|
+
|
9
|
+
module GitReflow
|
10
|
+
extend self
|
11
|
+
|
12
|
+
LGTM = /lgtm|looks good to me|:\+1:|:thumbsup:/i
|
13
|
+
|
14
|
+
def setup
|
15
|
+
gh_user = ask "Please enter your GitHub username: "
|
16
|
+
gh_password = ask "Please enter your GitHub password (we do NOT store this): "
|
17
|
+
puts "\nYour GitHub account was successfully setup!"
|
18
|
+
github = Github.new :basic_auth => "#{gh_user}:#{gh_password}"
|
19
|
+
authorization = github.oauth.create 'scopes' => ['repo']
|
20
|
+
oauth_token = authorization[:token]
|
21
|
+
set_oauth_token(oauth_token)
|
22
|
+
end
|
23
|
+
|
24
|
+
def review(options = {})
|
25
|
+
options['base'] ||= 'master'
|
26
|
+
fetch_destination options['base']
|
27
|
+
|
28
|
+
begin
|
29
|
+
puts push_current_branch
|
30
|
+
pull_request = github.pull_requests.create(remote_user, remote_repo_name,
|
31
|
+
'title' => options['title'],
|
32
|
+
'body' => options['body'],
|
33
|
+
'head' => "#{remote_user}:#{current_branch}",
|
34
|
+
'base' => options['base'])
|
35
|
+
|
36
|
+
puts "Successfully created pull request ##{pull_request.number}: #{pull_request.title}\nPull Request URL: #{pull_request.html_url}\n"
|
37
|
+
ask_to_open_in_browser(pull_request.html_url)
|
38
|
+
rescue Github::Error::UnprocessableEntity => e
|
39
|
+
error_message = e.to_s
|
40
|
+
if error_message =~ /request already exists/i
|
41
|
+
existing_pull_request = find_pull_request( :from => current_branch, :to => options['base'] )
|
42
|
+
puts "Existing pull request at: #{existing_pull_request[:html_url]}"
|
43
|
+
ask_to_open_in_browser(existing_pull_request.html_url)
|
44
|
+
else
|
45
|
+
puts error_message
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def deliver(options = {})
|
51
|
+
feature_branch = current_branch
|
52
|
+
options['base'] ||= 'master'
|
53
|
+
fetch_destination options['base']
|
54
|
+
|
55
|
+
begin
|
56
|
+
existing_pull_request = find_pull_request( :from => current_branch, :to => options['base'] )
|
57
|
+
|
58
|
+
if existing_pull_request.nil?
|
59
|
+
puts "Error: No pull request exists for #{remote_user}:#{current_branch}\nPlease submit your branch for review first with \`git reflow review\`"
|
60
|
+
else
|
61
|
+
|
62
|
+
open_comment_authors = find_authors_of_open_pull_request_comments(existing_pull_request)
|
63
|
+
|
64
|
+
# if there any comment_authors left, then they haven't given a lgtm after the last commit
|
65
|
+
if open_comment_authors.empty?
|
66
|
+
lgtm_authors = comment_authors_for_pull_request(existing_pull_request, :with => LGTM)
|
67
|
+
commit_message = get_first_commit_message
|
68
|
+
puts "Merging pull request ##{existing_pull_request[:number]}: '#{existing_pull_request[:title]}', from '#{existing_pull_request[:head][:label]}' into '#{existing_pull_request[:base][:label]}'"
|
69
|
+
|
70
|
+
update_destination(options['base'])
|
71
|
+
merge_feature_branch(:feature_branch => feature_branch,
|
72
|
+
:destination_branch => options['base'],
|
73
|
+
:pull_request_number => existing_pull_request[:number],
|
74
|
+
:message => "\nCloses ##{existing_pull_request[:number]}\n\nLGTM given by: @#{lgtm_authors.join(', @')}\n")
|
75
|
+
append_to_squashed_commit_message(commit_message)
|
76
|
+
committed = system('git commit')
|
77
|
+
|
78
|
+
if committed
|
79
|
+
puts "Merge complete!"
|
80
|
+
deploy_and_cleanup = ask "Would you like to push this branch to your remote repo and cleanup your feature branch? "
|
81
|
+
if deploy_and_cleanup =~ /^y/i
|
82
|
+
puts `git push origin #{options['base']}`
|
83
|
+
puts `git push origin :#{feature_branch}`
|
84
|
+
puts `git br -D #{feature_branch}`
|
85
|
+
puts "Nice job buddy."
|
86
|
+
end
|
87
|
+
else
|
88
|
+
puts "There were problems commiting your feature... please check the errors above and try again."
|
89
|
+
end
|
90
|
+
else
|
91
|
+
puts "[deliver halted] You still need a LGTM from: #{open_comment_authors.join(', ')}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
rescue Github::Error::UnprocessableEntity => e
|
96
|
+
errors = JSON.parse(e.response_message[:body])
|
97
|
+
error_messages = errors["errors"].collect {|error| "GitHub Error: #{error["message"].gsub(/^base\s/, '')}" unless error["message"].nil?}.compact.join("\n")
|
98
|
+
puts error_messages
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def github
|
103
|
+
@github ||= Github.new :oauth_token => get_oauth_token
|
104
|
+
end
|
105
|
+
|
106
|
+
def get_oauth_token
|
107
|
+
`git config --get github.oauth-token`.strip
|
108
|
+
end
|
109
|
+
|
110
|
+
def current_branch
|
111
|
+
`git branch --no-color | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g'`.strip
|
112
|
+
end
|
113
|
+
|
114
|
+
def github_user
|
115
|
+
`git config --get github.user`.strip
|
116
|
+
end
|
117
|
+
|
118
|
+
def remote_user
|
119
|
+
gh_remote_user = `git config --get remote.origin.url`.strip
|
120
|
+
gh_remote_user.slice!(/github\.com[\/:](\w|-|\.)+/i)[11..-1]
|
121
|
+
end
|
122
|
+
|
123
|
+
def remote_repo_name
|
124
|
+
gh_repo = `git config --get remote.origin.url`.strip
|
125
|
+
gh_repo.slice(/\/(\w|-|\.)+$/i)[1..-5]
|
126
|
+
end
|
127
|
+
|
128
|
+
def get_first_commit_message
|
129
|
+
`git log --pretty=format:"%s" --no-merges -n 1`.strip
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def set_oauth_token(oauth_token)
|
135
|
+
`git config --global --replace-all github.oauth-token #{oauth_token}`
|
136
|
+
end
|
137
|
+
|
138
|
+
def push_current_branch
|
139
|
+
`git push origin #{current_branch}`
|
140
|
+
end
|
141
|
+
|
142
|
+
def fetch_destination(destination_branch)
|
143
|
+
`git fetch origin #{destination_branch}`
|
144
|
+
end
|
145
|
+
|
146
|
+
def update_destination(destination_branch)
|
147
|
+
origin_branch = current_branch
|
148
|
+
`git checkout #{destination_branch}`
|
149
|
+
puts `git pull origin #{destination_branch}`
|
150
|
+
`git checkout #{origin_branch}`
|
151
|
+
end
|
152
|
+
|
153
|
+
def merge_feature_branch(options = {})
|
154
|
+
options[:destination_branch] ||= 'master'
|
155
|
+
message = options[:message] || "\nCloses ##{options[:pull_request_number]}\n"
|
156
|
+
|
157
|
+
`git checkout #{options[:destination_branch]}`
|
158
|
+
puts `git merge --squash #{options[:feature_branch]}`
|
159
|
+
# append pull request number to commit message
|
160
|
+
append_to_squashed_commit_message(message)
|
161
|
+
end
|
162
|
+
|
163
|
+
def append_to_squashed_commit_message(message = '')
|
164
|
+
`echo "#{message}" | cat - .git/SQUASH_MSG > ./tmp_squash_msg`
|
165
|
+
`mv ./tmp_squash_msg .git/SQUASH_MSG`
|
166
|
+
end
|
167
|
+
|
168
|
+
def find_pull_request(options)
|
169
|
+
existing_pull_request = nil
|
170
|
+
github.pull_requests.all(remote_user, remote_repo_name, :state => 'open') do |pull_request|
|
171
|
+
if pull_request[:base][:label] == "#{remote_user}:#{options[:to]}" and
|
172
|
+
pull_request[:head][:label] == "#{remote_user}:#{options[:from]}"
|
173
|
+
existing_pull_request = pull_request
|
174
|
+
break
|
175
|
+
end
|
176
|
+
end
|
177
|
+
existing_pull_request
|
178
|
+
end
|
179
|
+
|
180
|
+
def find_authors_of_open_pull_request_comments(pull_request)
|
181
|
+
# first we'll gather all the authors that have commented on the pull request
|
182
|
+
comments = github.issues.comments.all remote_user, remote_repo_name, pull_request[:number]
|
183
|
+
review_comments = github.pull_requests.comments.all remote_user, remote_repo_name, pull_request[:number]
|
184
|
+
all_comments = comments + review_comments
|
185
|
+
comment_authors = comment_authors_for_pull_request(pull_request)
|
186
|
+
|
187
|
+
# now we need to check that all the commented authors have given a lgtm after the last commit
|
188
|
+
all_comments.each do |comment|
|
189
|
+
next unless comment_authors.include?(comment.user.login)
|
190
|
+
pull_last_committed_at = Time.parse pull_request.head.repo.updated_at
|
191
|
+
comment_created_at = Time.parse(comment.created_at)
|
192
|
+
if comment_created_at > pull_last_committed_at
|
193
|
+
if comment.body =~ LGTM
|
194
|
+
comment_authors -= [comment.user.login]
|
195
|
+
else
|
196
|
+
comment_authors << comment.user.login unless comment_authors.include?(comment.user.login)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
comment_authors || []
|
202
|
+
end
|
203
|
+
|
204
|
+
def comment_authors_for_pull_request(pull_request, options = {})
|
205
|
+
comments = github.issues.comments.all remote_user, remote_repo_name, pull_request[:number]
|
206
|
+
review_comments = github.pull_requests.comments.all remote_user, remote_repo_name, pull_request[:number]
|
207
|
+
all_comments = comments + review_comments
|
208
|
+
comment_authors = []
|
209
|
+
|
210
|
+
all_comments.each do |comment|
|
211
|
+
comment_authors << comment.user.login if !comment_authors.include?(comment.user.login) and (options[:with].nil? or comment.body =~ options[:with])
|
212
|
+
end
|
213
|
+
|
214
|
+
# remove the current user from the list to check
|
215
|
+
comment_authors -= [github_user]
|
216
|
+
end
|
217
|
+
|
218
|
+
# WARNING: this currently only supports OS X and UBUNTU
|
219
|
+
def ask_to_open_in_browser(url)
|
220
|
+
if RUBY_PLATFORM =~ /darwin|linux/i
|
221
|
+
open_in_browser = ask "Would you like to open it in your browser? "
|
222
|
+
if open_in_browser =~ /^y/i
|
223
|
+
if RUBY_PLATFORM =~ /darwin/i
|
224
|
+
# OS X
|
225
|
+
`open #{url}`
|
226
|
+
else
|
227
|
+
# Ubuntu
|
228
|
+
`xdg-open #{url}`
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|