thegarage-gitx 1.0.1 → 1.1.0.alpha
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.
- 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
|