thegarage-gitx 1.0.1 → 1.1.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/thegarage/gitx/cli.rb +11 -9
- data/lib/thegarage/gitx/git.rb +18 -56
- data/lib/thegarage/gitx/github.rb +22 -5
- data/lib/thegarage/gitx/version.rb +1 -1
- data/lib/thegarage/gitx.rb +6 -3
- data/spec/thegarage/gitx/cli_spec.rb +26 -40
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d12c2fe14f686a81cdbe194058f1ba83b6268adf
|
4
|
+
data.tar.gz: 632dc0ea0205114aa54e0fd1c52c4a24d9e73eda
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a4d3a943e8f7797cba62f5882be5dfee168abb7e0e8dfbf856b9bb7b0819e9b3963c3d81a4ec6132497b90c8c64845d70fd30d8908d4d5c37655e77543d8514
|
7
|
+
data.tar.gz: c41b0a09c82b7f9478ed904e35c87062b84a0365ad7c8645ef3c6fa497f4809649b52742e5694170331ce09a5521005debb47ca56f1bb860c5d44e269664092d
|
data/lib/thegarage/gitx/cli.rb
CHANGED
@@ -16,7 +16,6 @@ module Thegarage
|
|
16
16
|
# Brief description of the change, and how it accomplishes the task they set out to do.
|
17
17
|
EOS
|
18
18
|
|
19
|
-
method_option :quiet, :type => :boolean, :aliases => '-q'
|
20
19
|
method_option :trace, :type => :boolean, :aliases => '-v'
|
21
20
|
def initialize(*args)
|
22
21
|
super(*args)
|
@@ -33,7 +32,7 @@ module Thegarage
|
|
33
32
|
token = authorization_token
|
34
33
|
description = options[:description] || editor_input(PULL_REQUEST_DESCRIPTION)
|
35
34
|
branch = current_branch
|
36
|
-
repo =
|
35
|
+
repo = current_remote_repo
|
37
36
|
url = create_pull_request token, branch, repo, description
|
38
37
|
say "Pull request created: #{url}"
|
39
38
|
end
|
@@ -49,7 +48,7 @@ module Thegarage
|
|
49
48
|
say "to have most recent changes from "
|
50
49
|
say Thegarage::Gitx::BASE_BRANCH, :green
|
51
50
|
|
52
|
-
run_cmd "git pull origin #{branch}"
|
51
|
+
run_cmd "git pull origin #{branch}", :allow_failure => true
|
53
52
|
run_cmd "git pull origin #{Thegarage::Gitx::BASE_BRANCH}"
|
54
53
|
run_cmd 'git push origin HEAD'
|
55
54
|
end
|
@@ -111,13 +110,16 @@ module Thegarage
|
|
111
110
|
desc 'nuke', 'nuke the specified aggregate branch and reset it to a known good state'
|
112
111
|
method_option :destination, :type => :string, :aliases => '-d', :desc => 'destination branch to reset to'
|
113
112
|
def nuke(bad_branch)
|
114
|
-
|
115
|
-
good_branch =
|
116
|
-
good_branch = default_good_branch if good_branch.length == 0
|
117
|
-
good_branch = "last_known_good_#{good_branch}" unless good_branch.starts_with?('last_known_good_')
|
113
|
+
good_branch = options[:destination] || ask("What branch do you want to reset #{bad_branch} to? (default: #{bad_branch})")
|
114
|
+
good_branch = bad_branch if good_branch.length == 0
|
118
115
|
|
119
|
-
|
120
|
-
|
116
|
+
run_cmd "git fetch --tags"
|
117
|
+
good_tags = run_cmd("git tag -l 'build-#{good_branch}-*'").split
|
118
|
+
last_known_good_tag = good_tags.sort.last
|
119
|
+
raise "No known good tag found for branch: #{good_branch}. Verify tag exists via `git tag -l 'build-#{good_branch}-*'`" unless last_known_good_tag
|
120
|
+
return unless yes?("Reset #{bad_branch} to #{last_known_good_tag}? (y/n)", :green)
|
121
|
+
|
122
|
+
nuke_branch(bad_branch, last_known_good_tag)
|
121
123
|
end
|
122
124
|
|
123
125
|
desc 'release', 'release the current branch to production'
|
data/lib/thegarage/gitx/git.rb
CHANGED
@@ -14,31 +14,34 @@ module Thegarage
|
|
14
14
|
|
15
15
|
# lookup the current branch of the PWD
|
16
16
|
def current_branch
|
17
|
-
|
18
|
-
|
17
|
+
Grit::Head.current(current_repo).name
|
18
|
+
end
|
19
|
+
|
20
|
+
def current_repo
|
21
|
+
@repo ||= Grit::Repo.new(Dir.pwd)
|
19
22
|
end
|
20
23
|
|
21
24
|
# lookup the current repository of the PWD
|
22
25
|
# ex: git@github.com:socialcast/thegarage/gitx.git OR https://github.com/socialcast/thegarage/gitx.git
|
23
|
-
def
|
24
|
-
repo =
|
26
|
+
def current_remote_repo
|
27
|
+
repo = current_repo.config['remote.origin.url']
|
25
28
|
repo.gsub(/\.git$/,'').split(/[:\/]/).last(2).join('/')
|
26
29
|
end
|
27
30
|
|
28
31
|
# @returns [String] github username (ex: 'wireframe') of the current github.user
|
29
32
|
# @returns empty [String] when no github.user is set on the system
|
30
33
|
def current_user
|
31
|
-
|
34
|
+
current_repo.config['github.user']
|
32
35
|
end
|
33
36
|
|
34
37
|
# @returns [String] auth token stored in git (current repo, user config or installed global settings)
|
35
38
|
def github_auth_token
|
36
|
-
|
39
|
+
current_repo.config['thegarage.gitx.githubauthtoken']
|
37
40
|
end
|
38
41
|
|
39
42
|
# store new auth token in the local project git config
|
40
43
|
def github_auth_token=(new_token)
|
41
|
-
|
44
|
+
current_repo.config['thegarage.gitx.githubauthtoken'] = new_token
|
42
45
|
end
|
43
46
|
|
44
47
|
# retrieve a list of branches
|
@@ -56,11 +59,9 @@ module Thegarage
|
|
56
59
|
branches.uniq
|
57
60
|
end
|
58
61
|
|
59
|
-
# reset the specified branch to the same set of commits as the destination branch
|
60
|
-
# reverts commits on aggregate branches back to a known good state
|
61
|
-
# returns list of branches that were removed
|
62
|
+
# reset the specified aggregate branch to the same set of commits as the destination branch
|
62
63
|
def nuke_branch(branch, head_branch)
|
63
|
-
return
|
64
|
+
return if branch == head_branch
|
64
65
|
raise "Only aggregate branches are allowed to be reset: #{AGGREGATE_BRANCHES}" unless aggregate_branch?(branch)
|
65
66
|
say "Resetting "
|
66
67
|
say "#{branch} ", :green
|
@@ -68,15 +69,11 @@ module Thegarage
|
|
68
69
|
say head_branch, :green
|
69
70
|
|
70
71
|
run_cmd "git checkout #{Thegarage::Gitx::BASE_BRANCH}"
|
71
|
-
|
72
|
-
|
73
|
-
run_cmd "git
|
74
|
-
run_cmd "git push origin --delete #{branch}" rescue nil
|
75
|
-
run_cmd "git checkout -b #{branch}"
|
72
|
+
run_cmd "git branch -D #{branch}", :allow_failure => true
|
73
|
+
run_cmd "git push origin --delete #{branch}", :allow_failure => true
|
74
|
+
run_cmd "git checkout -b #{branch} #{head_branch}"
|
76
75
|
share_branch branch
|
77
76
|
run_cmd "git checkout #{Thegarage::Gitx::BASE_BRANCH}"
|
78
|
-
|
79
|
-
removed_branches
|
80
77
|
end
|
81
78
|
|
82
79
|
# share the local branch in the remote repo
|
@@ -86,7 +83,7 @@ module Thegarage
|
|
86
83
|
end
|
87
84
|
|
88
85
|
def track_branch(branch)
|
89
|
-
run_cmd "git branch --set-upstream
|
86
|
+
run_cmd "git branch --set-upstream-to origin/#{branch}"
|
90
87
|
end
|
91
88
|
|
92
89
|
# integrate a branch into a destination aggregate branch
|
@@ -107,30 +104,13 @@ module Thegarage
|
|
107
104
|
|
108
105
|
# nuke local branch and pull fresh version from remote repo
|
109
106
|
def refresh_branch_from_remote(destination_branch)
|
110
|
-
run_cmd "git branch -D #{destination_branch}"
|
107
|
+
run_cmd "git branch -D #{destination_branch}", :allow_failure => true
|
111
108
|
run_cmd "git fetch origin"
|
112
109
|
run_cmd "git checkout #{destination_branch}"
|
113
110
|
end
|
114
111
|
|
115
112
|
def aggregate_branch?(branch)
|
116
|
-
AGGREGATE_BRANCHES.include?(branch)
|
117
|
-
end
|
118
|
-
|
119
|
-
# build a summary of changes
|
120
|
-
def changelog_summary(branch)
|
121
|
-
changes = `git diff --stat origin/#{Thegarage::Gitx::BASE_BRANCH}...#{branch}`.split("\n")
|
122
|
-
stats = changes.pop
|
123
|
-
if changes.length > 5
|
124
|
-
dirs = changes.map do |file_change|
|
125
|
-
filename = "#{file_change.split.first}"
|
126
|
-
dir = filename.gsub(/\/[^\/]+$/, '')
|
127
|
-
dir
|
128
|
-
end
|
129
|
-
dir_counts = Hash.new(0)
|
130
|
-
dirs.each {|dir| dir_counts[dir] += 1 }
|
131
|
-
changes = dir_counts.to_a.sort_by {|k,v| v}.reverse.first(5).map {|k,v| "#{k} (#{v} file#{'s' if v > 1})"}
|
132
|
-
end
|
133
|
-
(changes + [stats]).join("\n")
|
113
|
+
AGGREGATE_BRANCHES.include?(branch)
|
134
114
|
end
|
135
115
|
|
136
116
|
# launch configured editor to retreive message/string
|
@@ -155,24 +135,6 @@ module Thegarage
|
|
155
135
|
description.gsub(/^\#.*/, '').chomp.strip
|
156
136
|
end
|
157
137
|
end
|
158
|
-
|
159
|
-
# load SC Git Extensions Config YAML
|
160
|
-
# @returns [Hash] of configuration options from YAML file (if it exists)
|
161
|
-
def config
|
162
|
-
@config ||= begin
|
163
|
-
if config_file.exist?
|
164
|
-
YAML.load_file(config_file)
|
165
|
-
else
|
166
|
-
{}
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
# @returns a [Pathname] for the scgitx.yml Config File
|
172
|
-
# from either ENV['SCGITX_CONFIG_PATH'] or default $PWD/config/scgitx.yml
|
173
|
-
def config_file
|
174
|
-
Pathname((ENV['SCGITX_CONFIG_PATH'] || ([Dir.pwd, '/config/scgitx.yml']).join))
|
175
|
-
end
|
176
138
|
end
|
177
139
|
end
|
178
140
|
end
|
@@ -6,6 +6,8 @@ module Thegarage
|
|
6
6
|
module Gitx
|
7
7
|
module Github
|
8
8
|
include Thegarage::Gitx::Git
|
9
|
+
CLIENT_NAME = 'The Garage Git eXtensions'
|
10
|
+
CLIENT_URL = 'https://github.com/thegarage/thegarage-gitx'
|
9
11
|
|
10
12
|
private
|
11
13
|
# request github authorization token
|
@@ -15,17 +17,32 @@ module Thegarage
|
|
15
17
|
# @see http://developer.github.com/v3/#user-agent-required
|
16
18
|
def authorization_token
|
17
19
|
auth_token = github_auth_token
|
18
|
-
return auth_token unless auth_token.blank?
|
20
|
+
return auth_token unless auth_token.to_s.blank?
|
19
21
|
|
20
22
|
username = current_user
|
21
23
|
raise "Github user not configured. Run: `git config --global github.user 'me@email.com'`" if username.empty?
|
22
|
-
password = ask("Github password for #{username}: "
|
24
|
+
password = ask("Github password for #{username}: ", :echo => false)
|
23
25
|
|
24
|
-
payload = {
|
25
|
-
|
26
|
+
payload = {
|
27
|
+
:scopes => ['repo'],
|
28
|
+
:note => CLIENT_NAME,
|
29
|
+
:note_url => CLIENT_URL
|
30
|
+
}.to_json
|
31
|
+
response = RestClient::Request.new({
|
32
|
+
:url => "https://api.github.com/authorizations",
|
33
|
+
:method => "POST",
|
34
|
+
:user => username,
|
35
|
+
:password => password,
|
36
|
+
:payload => payload,
|
37
|
+
:headers => {
|
38
|
+
:accept => :json,
|
39
|
+
:content_type => :json,
|
40
|
+
:user_agent => 'thegarage/gitx'
|
41
|
+
}
|
42
|
+
}).execute
|
26
43
|
data = JSON.parse response.body
|
27
44
|
token = data['token']
|
28
|
-
github_auth_token = token
|
45
|
+
self.github_auth_token = token
|
29
46
|
token
|
30
47
|
rescue RestClient::Exception => e
|
31
48
|
process_error e
|
data/lib/thegarage/gitx.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require "thegarage/gitx/version"
|
2
1
|
require 'thegarage/gitx/version'
|
3
2
|
require 'thegarage/gitx/string_extensions'
|
4
3
|
require 'thegarage/gitx/git'
|
@@ -12,10 +11,14 @@ module Thegarage
|
|
12
11
|
private
|
13
12
|
|
14
13
|
# execute a shell command and raise an error if non-zero exit code is returned
|
15
|
-
|
14
|
+
# return the string output from the command
|
15
|
+
def run_cmd(cmd, options = {})
|
16
16
|
say "\n$ "
|
17
17
|
say cmd.gsub("'", ''), :red
|
18
|
-
|
18
|
+
output = `#{cmd}`
|
19
|
+
success = !!$?.to_i
|
20
|
+
raise "#{cmd} failed" unless success || options[:allow_failure]
|
21
|
+
output
|
19
22
|
end
|
20
23
|
end
|
21
24
|
end
|
@@ -8,8 +8,9 @@ describe Thegarage::Gitx::CLI do
|
|
8
8
|
end
|
9
9
|
private
|
10
10
|
# stub out command execution and record commands for test inspection
|
11
|
-
def run_cmd(cmd)
|
11
|
+
def run_cmd(cmd, options={})
|
12
12
|
self.class.stubbed_executed_commands << cmd
|
13
|
+
''
|
13
14
|
end
|
14
15
|
# stub branch to always be a known branch
|
15
16
|
def current_branch
|
@@ -134,46 +135,32 @@ describe Thegarage::Gitx::CLI do
|
|
134
135
|
prototype_branches = %w( dev-foo dev-bar )
|
135
136
|
master_branches = %w( dev-foo )
|
136
137
|
Thegarage::Gitx::CLI.any_instance.should_receive(:branches).and_return(prototype_branches, master_branches, prototype_branches, master_branches)
|
138
|
+
Thegarage::Gitx::CLI.any_instance.should_receive(:yes?).and_return(false)
|
137
139
|
Thegarage::Gitx::CLI.start ['nuke', 'prototype', '--destination', 'master']
|
138
140
|
end
|
139
141
|
it 'should run expected commands' do
|
140
142
|
Thegarage::Gitx::CLI.stubbed_executed_commands.should == [
|
141
143
|
"git checkout master",
|
142
|
-
"git branch -D last_known_good_master",
|
143
|
-
"git fetch origin",
|
144
|
-
"git checkout last_known_good_master",
|
145
144
|
"git branch -D prototype",
|
146
145
|
"git push origin --delete prototype",
|
147
|
-
"git checkout -b prototype",
|
146
|
+
"git checkout -b prototype build-master-2013-10-01-01",
|
148
147
|
"git push origin prototype",
|
149
148
|
"git branch --set-upstream prototype origin/prototype",
|
150
|
-
"git checkout master",
|
151
|
-
"git checkout master",
|
152
|
-
"git branch -D last_known_good_master",
|
153
|
-
"git fetch origin",
|
154
|
-
"git checkout last_known_good_master",
|
155
|
-
"git branch -D last_known_good_prototype",
|
156
|
-
"git push origin --delete last_known_good_prototype",
|
157
|
-
"git checkout -b last_known_good_prototype",
|
158
|
-
"git push origin last_known_good_prototype",
|
159
|
-
"git branch --set-upstream last_known_good_prototype origin/last_known_good_prototype",
|
160
149
|
"git checkout master"
|
161
150
|
]
|
162
151
|
end
|
163
152
|
end
|
164
|
-
context 'when target branch == staging and --destination ==
|
153
|
+
context 'when target branch == staging and --destination == staging' do
|
165
154
|
before do
|
166
|
-
Thegarage::Gitx::CLI.
|
155
|
+
Thegarage::Gitx::CLI.any_instance.should_receive(:yes?).and_return(false)
|
156
|
+
Thegarage::Gitx::CLI.start ['nuke', 'staging', '--destination', 'staging']
|
167
157
|
end
|
168
158
|
it 'should run expected commands' do
|
169
159
|
Thegarage::Gitx::CLI.stubbed_executed_commands.should == [
|
170
160
|
"git checkout master",
|
171
|
-
"git branch -D last_known_good_staging",
|
172
|
-
"git fetch origin",
|
173
|
-
"git checkout last_known_good_staging",
|
174
161
|
"git branch -D staging",
|
175
162
|
"git push origin --delete staging",
|
176
|
-
"git checkout -b staging",
|
163
|
+
"git checkout -b staging build-staging-2013-10-02-02",
|
177
164
|
"git push origin staging",
|
178
165
|
"git branch --set-upstream staging origin/staging",
|
179
166
|
"git checkout master"
|
@@ -183,17 +170,15 @@ describe Thegarage::Gitx::CLI do
|
|
183
170
|
context 'when target branch == prototype and destination prompt == nil' do
|
184
171
|
before do
|
185
172
|
Thegarage::Gitx::CLI.any_instance.should_receive(:ask).and_return('')
|
173
|
+
Thegarage::Gitx::CLI.any_instance.should_receive(:yes?).and_return(false)
|
186
174
|
Thegarage::Gitx::CLI.start ['nuke', 'prototype']
|
187
175
|
end
|
188
|
-
it 'defaults to
|
176
|
+
it 'defaults to prototype and should run expected commands' do
|
189
177
|
Thegarage::Gitx::CLI.stubbed_executed_commands.should == [
|
190
178
|
"git checkout master",
|
191
|
-
"git branch -D last_known_good_prototype",
|
192
|
-
"git fetch origin",
|
193
|
-
"git checkout last_known_good_prototype",
|
194
179
|
"git branch -D prototype",
|
195
180
|
"git push origin --delete prototype",
|
196
|
-
"git checkout -b prototype",
|
181
|
+
"git checkout -b prototype build-prototype-2013-10-02-03",
|
197
182
|
"git push origin prototype",
|
198
183
|
"git branch --set-upstream prototype origin/prototype",
|
199
184
|
"git checkout master"
|
@@ -203,29 +188,17 @@ describe Thegarage::Gitx::CLI do
|
|
203
188
|
context 'when target branch == prototype and destination prompt = master' do
|
204
189
|
before do
|
205
190
|
Thegarage::Gitx::CLI.any_instance.should_receive(:ask).and_return('master')
|
191
|
+
Thegarage::Gitx::CLI.any_instance.should_receive(:yes?).and_return(false)
|
206
192
|
Thegarage::Gitx::CLI.start ['nuke', 'prototype']
|
207
193
|
end
|
208
194
|
it 'should run expected commands' do
|
209
195
|
Thegarage::Gitx::CLI.stubbed_executed_commands.should == [
|
210
196
|
"git checkout master",
|
211
|
-
"git branch -D last_known_good_master",
|
212
|
-
"git fetch origin",
|
213
|
-
"git checkout last_known_good_master",
|
214
197
|
"git branch -D prototype",
|
215
198
|
"git push origin --delete prototype",
|
216
|
-
"git checkout -b prototype",
|
199
|
+
"git checkout -b prototype build-master-2013-10-01-01",
|
217
200
|
"git push origin prototype",
|
218
201
|
"git branch --set-upstream prototype origin/prototype",
|
219
|
-
"git checkout master",
|
220
|
-
"git checkout master",
|
221
|
-
"git branch -D last_known_good_master",
|
222
|
-
"git fetch origin",
|
223
|
-
"git checkout last_known_good_master",
|
224
|
-
"git branch -D last_known_good_prototype",
|
225
|
-
"git push origin --delete last_known_good_prototype",
|
226
|
-
"git checkout -b last_known_good_prototype",
|
227
|
-
"git push origin last_known_good_prototype",
|
228
|
-
"git branch --set-upstream last_known_good_prototype origin/last_known_good_prototype",
|
229
202
|
"git checkout master"
|
230
203
|
]
|
231
204
|
end
|
@@ -234,10 +207,23 @@ describe Thegarage::Gitx::CLI do
|
|
234
207
|
it 'should raise error' do
|
235
208
|
lambda {
|
236
209
|
Thegarage::Gitx::CLI.any_instance.should_receive(:ask).and_return('master')
|
210
|
+
Thegarage::Gitx::CLI.any_instance.should_receive(:yes?).and_return(false)
|
237
211
|
Thegarage::Gitx::CLI.start ['nuke', 'asdfasdf']
|
238
212
|
}.should raise_error /Only aggregate branches are allowed to be reset/
|
239
213
|
end
|
240
214
|
end
|
215
|
+
context 'when user does not confirm nuking the target branch' do
|
216
|
+
before do
|
217
|
+
Thegarage::Gitx::CLI.any_instance.should_receive(:ask).and_return('master')
|
218
|
+
Thegarage::Gitx::CLI.any_instance.should_receive(:yes?).and_return(false)
|
219
|
+
Thegarage::Gitx::CLI.start ['nuke', 'prototype']
|
220
|
+
end
|
221
|
+
it 'should run expected commands' do
|
222
|
+
Thegarage::Gitx::CLI.stubbed_executed_commands.should == [
|
223
|
+
"git fetch --tags"
|
224
|
+
]
|
225
|
+
end
|
226
|
+
end
|
241
227
|
end
|
242
228
|
|
243
229
|
describe '#reviewrequest' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thegarage-gitx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.1.0.alpha
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Sonnek
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-10-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: grit
|
@@ -180,12 +180,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
180
180
|
version: '0'
|
181
181
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
182
182
|
requirements:
|
183
|
-
- - '
|
183
|
+
- - '>'
|
184
184
|
- !ruby/object:Gem::Version
|
185
|
-
version:
|
185
|
+
version: 1.3.1
|
186
186
|
requirements: []
|
187
187
|
rubyforge_project:
|
188
|
-
rubygems_version: 2.
|
188
|
+
rubygems_version: 2.1.5
|
189
189
|
signing_key:
|
190
190
|
specification_version: 4
|
191
191
|
summary: Utility scripts for Git to increase productivity for common operations
|