thegarage-gitx 2.9.0 → 2.10.0
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/README.md +4 -0
- data/lib/thegarage/gitx/cli/integrate_command.rb +1 -1
- data/lib/thegarage/gitx/cli/release_command.rb +1 -1
- data/lib/thegarage/gitx/cli/review_command.rb +51 -9
- data/lib/thegarage/gitx/extensions/string.rb +3 -2
- data/lib/thegarage/gitx/github.rb +121 -117
- data/lib/thegarage/gitx/version.rb +1 -1
- data/spec/thegarage/gitx/cli/review_command_spec.rb +62 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3ba4526a6cb6a7cfa24ec14119448eb93802865
|
4
|
+
data.tar.gz: 5f98b2f487eb204dab8c060218580871d1873386
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9689ecc4716c330e747e607a2d629d7f0613c52ad025c326d04aefcd33b5055bc16c450725c85af802754f5c6ef40a30b569087f72f85ccf824f057558e2ef7f
|
7
|
+
data.tar.gz: 0f5df20623851c98ead0d71f225dcb013c49ee86661fc9267d1b88154b8075ddd226b90c1484e4cb71b991e4592accb1bdd37c8a7d77ab1d88e9d4575c9cea69
|
data/README.md
CHANGED
@@ -35,7 +35,11 @@ options:
|
|
35
35
|
* `--assign` or `-a` = assign pull request to github user
|
36
36
|
* `--open` or `-o` = open pull request in default web browser.
|
37
37
|
* `--bump` or `-b` = bump an existing pull request by posting a comment to re-review new changes
|
38
|
+
* `--approve` = approve/signoff on pull request (with optional feedback)
|
39
|
+
* `--reject` = reject pull request (with details)
|
38
40
|
|
41
|
+
NOTE: the `--bump` option will also update the pull request commit status to mark the branch as 'pending peer review'.
|
42
|
+
This setting is cleared when a reviewer approves or rejects the pull request.
|
39
43
|
|
40
44
|
## git release
|
41
45
|
|
@@ -8,7 +8,7 @@ module Thegarage
|
|
8
8
|
module Gitx
|
9
9
|
module Cli
|
10
10
|
class IntegrateCommand < BaseCommand
|
11
|
-
include Github
|
11
|
+
include Thegarage::Gitx::Github
|
12
12
|
desc 'integrate', 'integrate the current branch into one of the aggregate development branches (default = staging)'
|
13
13
|
method_option :resume, :type => :string, :aliases => '-r', :desc => 'resume merging of feature-branch'
|
14
14
|
def integrate(integration_branch = 'staging')
|
@@ -10,7 +10,7 @@ module Thegarage
|
|
10
10
|
module Gitx
|
11
11
|
module Cli
|
12
12
|
class ReleaseCommand < BaseCommand
|
13
|
-
include Github
|
13
|
+
include Thegarage::Gitx::Github
|
14
14
|
|
15
15
|
desc 'release', 'release the current branch to production'
|
16
16
|
method_option :cleanup, :type => :boolean, :desc => 'cleanup merged branches after release'
|
@@ -8,20 +8,42 @@ module Thegarage
|
|
8
8
|
module Gitx
|
9
9
|
module Cli
|
10
10
|
class ReviewCommand < BaseCommand
|
11
|
-
include Github
|
11
|
+
include Thegarage::Gitx::Github
|
12
|
+
|
13
|
+
BUMP_COMMENT_TEMPLATE = <<-EOS.dedent
|
14
|
+
[gitx] review bump :tada:
|
15
|
+
|
16
|
+
### Changelog Summary
|
17
|
+
EOS
|
18
|
+
APPROVAL_COMMENT_TEMPLATE = <<-EOS.dedent
|
19
|
+
[gitx] review approved :shipit:
|
20
|
+
|
21
|
+
### Feedback
|
22
|
+
|
23
|
+
### Follow-up Items
|
24
|
+
EOS
|
25
|
+
REJECTION_COMMENT_TEMPLATE = <<-EOS.dedent
|
26
|
+
[gitx] review rejected
|
27
|
+
|
28
|
+
### Feedback
|
29
|
+
EOS
|
12
30
|
|
13
31
|
desc "review", "Create or update a pull request on github"
|
14
32
|
method_option :description, :type => :string, :aliases => '-d', :desc => 'pull request description'
|
15
33
|
method_option :assignee, :type => :string, :aliases => '-a', :desc => 'pull request assignee'
|
16
34
|
method_option :open, :type => :boolean, :aliases => '-o', :desc => 'open the pull request in a web browser'
|
17
35
|
method_option :bump, :type => :boolean, :aliases => '-b', :desc => 'bump an existing pull request by posting a comment to re-review new changes'
|
36
|
+
method_option :approve, :type => :boolean, :desc => 'approve the pull request an post comment on pull request'
|
37
|
+
method_option :reject, :type => :boolean, :desc => 'reject the pull request an post comment on pull request'
|
18
38
|
# @see http://developer.github.com/v3/pulls/
|
19
39
|
def review
|
20
40
|
fail 'Github authorization token not found' unless authorization_token
|
21
41
|
|
22
42
|
branch = current_branch.name
|
23
43
|
pull_request = find_or_create_pull_request(branch)
|
24
|
-
|
44
|
+
bump_pull_request(pull_request) if options[:bump]
|
45
|
+
approve_pull_request(pull_request) if options[:approve]
|
46
|
+
reject_pull_request(pull_request) if options[:reject]
|
25
47
|
assign_pull_request(pull_request) if options[:assignee]
|
26
48
|
|
27
49
|
run_cmd "open #{pull_request.html_url}" if options[:open]
|
@@ -42,15 +64,35 @@ module Thegarage
|
|
42
64
|
github_client.update_issue(github_slug, pull_request.number, title, body, options)
|
43
65
|
end
|
44
66
|
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
67
|
+
def bump_pull_request(pull_request)
|
68
|
+
comment = get_editor_input(BUMP_COMMENT_TEMPLATE)
|
69
|
+
github_client.add_comment(github_slug, pull_request.number, comment)
|
70
|
+
|
71
|
+
set_review_status('pending', 'Peer review in progress')
|
72
|
+
end
|
50
73
|
|
51
|
-
|
52
|
-
comment =
|
74
|
+
def reject_pull_request(pull_request)
|
75
|
+
comment = get_editor_input(REJECTION_COMMENT_TEMPLATE)
|
53
76
|
github_client.add_comment(github_slug, pull_request.number, comment)
|
77
|
+
|
78
|
+
set_review_status('failure', 'Peer review rejected')
|
79
|
+
end
|
80
|
+
|
81
|
+
def approve_pull_request(pull_request)
|
82
|
+
comment = get_editor_input(APPROVAL_COMMENT_TEMPLATE)
|
83
|
+
github_client.add_comment(github_slug, pull_request.number, comment)
|
84
|
+
|
85
|
+
set_review_status('success', 'Peer review approved')
|
86
|
+
end
|
87
|
+
|
88
|
+
def get_editor_input(template)
|
89
|
+
text = ask_editor(template, repo.config['core.editor'])
|
90
|
+
text = text.chomp.strip
|
91
|
+
end
|
92
|
+
|
93
|
+
def set_review_status(state, description)
|
94
|
+
latest_commit = repo.head.target_id
|
95
|
+
update_review_status(latest_commit, state, description)
|
54
96
|
end
|
55
97
|
end
|
56
98
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
class String
|
2
|
+
# @see http://api.rubyonrails.org/classes/String.html#method-i-strip_heredoc
|
2
3
|
def undent
|
3
|
-
|
4
|
-
gsub(
|
4
|
+
indent = scan(/^[ \t]*(?=\S)/).min.size || 0
|
5
|
+
gsub(/^[ \t]{#{indent}}/, '')
|
5
6
|
end
|
6
7
|
alias :dedent :undent
|
7
8
|
|
@@ -2,138 +2,142 @@ require 'octokit'
|
|
2
2
|
|
3
3
|
module Thegarage
|
4
4
|
module Gitx
|
5
|
-
module
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
pull_request
|
26
|
-
end
|
5
|
+
module Github
|
6
|
+
REVIEW_CONTEXT = 'peer_review'
|
7
|
+
CLIENT_URL = 'https://github.com/thegarage/thegarage-gitx'
|
8
|
+
PULL_REQUEST_FOOTER = <<-EOS.dedent
|
9
|
+
# Pull Request Protips(tm):
|
10
|
+
# * Include description of how this change accomplishes the task at hand.
|
11
|
+
# * Use GitHub flavored Markdown http://github.github.com/github-flavored-markdown/
|
12
|
+
# * Review CONTRIBUTING.md for recommendations of artifacts, links, images, screencasts, etc.
|
13
|
+
#
|
14
|
+
# This footer will automatically be stripped from the pull request description
|
15
|
+
EOS
|
16
|
+
|
17
|
+
def find_or_create_pull_request(branch)
|
18
|
+
pull_request = find_pull_request(branch)
|
19
|
+
pull_request ||= begin
|
20
|
+
execute_command(Thegarage::Gitx::Cli::UpdateCommand, :update)
|
21
|
+
pull_request = create_pull_request(branch)
|
22
|
+
say 'Created pull request: '
|
23
|
+
say pull_request.html_url, :green
|
24
|
+
|
27
25
|
pull_request
|
28
26
|
end
|
27
|
+
pull_request
|
28
|
+
end
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
30
|
+
# @return [Sawyer::Resource] data structure of pull request info if found
|
31
|
+
# @return nil if no pull request found
|
32
|
+
def find_pull_request(branch)
|
33
|
+
head_reference = "#{github_organization}:#{branch}"
|
34
|
+
params = {
|
35
|
+
head: head_reference,
|
36
|
+
state: 'open'
|
37
|
+
}
|
38
|
+
pull_requests = github_client.pull_requests(github_slug, params)
|
39
|
+
pull_requests.first
|
40
|
+
end
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
42
|
+
# Get the current commit status of a branch
|
43
|
+
# @see https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref
|
44
|
+
def branch_status(branch)
|
45
|
+
response = github_client.status(github_slug, branch)
|
46
|
+
response.state
|
47
|
+
end
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
say "against "
|
54
|
-
say "#{Thegarage::Gitx::BASE_BRANCH} ", :green
|
55
|
-
say "in "
|
56
|
-
say github_slug, :green
|
57
|
-
|
58
|
-
title = branch
|
59
|
-
body = pull_request_body(branch)
|
60
|
-
github_client.create_pull_request(github_slug, Thegarage::Gitx::BASE_BRANCH, branch, title, body)
|
61
|
-
end
|
49
|
+
# Update build status with peer review status
|
50
|
+
def update_review_status(commit_sha, state, description)
|
51
|
+
github_client.create_status(github_slug, commit_sha, state, context: REVIEW_CONTEXT, description: description)
|
52
|
+
end
|
62
53
|
|
63
|
-
|
64
|
-
|
65
|
-
|
54
|
+
# @see http://developer.github.com/v3/pulls/
|
55
|
+
def create_pull_request(branch)
|
56
|
+
say "Creating pull request for "
|
57
|
+
say "#{branch} ", :green
|
58
|
+
say "against "
|
59
|
+
say "#{Thegarage::Gitx::BASE_BRANCH} ", :green
|
60
|
+
say "in "
|
61
|
+
say github_slug, :green
|
62
|
+
|
63
|
+
title = branch
|
64
|
+
body = pull_request_body(branch)
|
65
|
+
github_client.create_pull_request(github_slug, Thegarage::Gitx::BASE_BRANCH, branch, title, body)
|
66
|
+
end
|
66
67
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
description_template << changelog
|
71
|
-
description_template << PULL_REQUEST_FOOTER
|
68
|
+
def pull_request_body(branch)
|
69
|
+
changelog = run_cmd("git log #{Thegarage::Gitx::BASE_BRANCH}...#{branch} --reverse --no-merges --pretty=format:'* %s%n%b'")
|
70
|
+
description = options[:description]
|
72
71
|
|
73
|
-
|
74
|
-
|
75
|
-
|
72
|
+
description_template = []
|
73
|
+
description_template << "#{description}\n" if description
|
74
|
+
description_template << '### Changelog'
|
75
|
+
description_template << changelog
|
76
|
+
description_template << PULL_REQUEST_FOOTER
|
76
77
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
# @see http://developer.github.com/v3/#user-agent-required
|
81
|
-
def authorization_token
|
82
|
-
auth_token = repo.config['thegarage.gitx.githubauthtoken']
|
83
|
-
return auth_token unless auth_token.to_s.blank?
|
84
|
-
|
85
|
-
auth_token = create_authorization
|
86
|
-
repo.config['thegarage.gitx.githubauthtoken'] = auth_token
|
87
|
-
auth_token
|
88
|
-
end
|
78
|
+
body = ask_editor(description_template.join("\n"), repo.config['core.editor'])
|
79
|
+
body.gsub(PULL_REQUEST_FOOTER, '').chomp.strip
|
80
|
+
end
|
89
81
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
82
|
+
# token is cached in local git config for future use
|
83
|
+
# @return [String] auth token stored in git (current repo, user config or installed global settings)
|
84
|
+
# @see http://developer.github.com/v3/oauth/#scopes
|
85
|
+
# @see http://developer.github.com/v3/#user-agent-required
|
86
|
+
def authorization_token
|
87
|
+
auth_token = repo.config['thegarage.gitx.githubauthtoken']
|
88
|
+
return auth_token unless auth_token.to_s.blank?
|
89
|
+
|
90
|
+
auth_token = create_authorization
|
91
|
+
repo.config['thegarage.gitx.githubauthtoken'] = auth_token
|
92
|
+
auth_token
|
93
|
+
end
|
97
94
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
}
|
106
|
-
two_factor_auth_token = ask("Github two factor authorization token (if enabled): ", :echo => false)
|
107
|
-
say ''
|
108
|
-
options[:headers] = {'X-GitHub-OTP' => two_factor_auth_token} if two_factor_auth_token
|
109
|
-
options
|
110
|
-
end
|
95
|
+
def create_authorization
|
96
|
+
password = ask("Github password for #{username}: ", :echo => false)
|
97
|
+
say ''
|
98
|
+
client = Octokit::Client.new(login: username, password: password)
|
99
|
+
response = client.create_authorization(authorization_request_options)
|
100
|
+
response.token
|
101
|
+
end
|
111
102
|
|
112
|
-
|
113
|
-
|
114
|
-
|
103
|
+
def authorization_request_options
|
104
|
+
timestamp = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%S%z')
|
105
|
+
client_name = "The Garage Git eXtensions - #{github_slug} #{timestamp}"
|
106
|
+
options = {
|
107
|
+
:scopes => ['repo'],
|
108
|
+
:note => client_name,
|
109
|
+
:note_url => CLIENT_URL
|
110
|
+
}
|
111
|
+
two_factor_auth_token = ask("Github two factor authorization token (if enabled): ", :echo => false)
|
112
|
+
say ''
|
113
|
+
options[:headers] = {'X-GitHub-OTP' => two_factor_auth_token} if two_factor_auth_token
|
114
|
+
options
|
115
|
+
end
|
115
116
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
username = repo.config['github.user']
|
120
|
-
fail "Github user not configured. Run: `git config --global github.user 'me@email.com'`" unless username
|
121
|
-
username
|
122
|
-
end
|
117
|
+
def github_client
|
118
|
+
@client ||= Octokit::Client.new(:access_token => authorization_token)
|
119
|
+
end
|
123
120
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
remote.to_s.gsub(/\.git$/,'').split(/[:\/]/).last(2).join('/')
|
132
|
-
end
|
121
|
+
# @return [String] github username (ex: 'wireframe') of the current github.user
|
122
|
+
# @raise error if github.user is not configured
|
123
|
+
def username
|
124
|
+
username = repo.config['github.user']
|
125
|
+
fail "Github user not configured. Run: `git config --global github.user 'me@email.com'`" unless username
|
126
|
+
username
|
127
|
+
end
|
133
128
|
|
134
|
-
|
135
|
-
|
136
|
-
|
129
|
+
# @return the github slug for the current repository's remote origin url.
|
130
|
+
# @example
|
131
|
+
# git@github.com:socialcast/thegarage/gitx.git #=> thegarage/gitx
|
132
|
+
# @example
|
133
|
+
# https://github.com/socialcast/thegarage/gitx.git #=> thegarage/gitx
|
134
|
+
def github_slug
|
135
|
+
remote = repo.config['remote.origin.url']
|
136
|
+
remote.to_s.gsub(/\.git$/,'').split(/[:\/]/).last(2).join('/')
|
137
|
+
end
|
138
|
+
|
139
|
+
def github_organization
|
140
|
+
github_slug.split('/').first
|
137
141
|
end
|
138
142
|
end
|
139
143
|
end
|
@@ -44,9 +44,10 @@ describe Thegarage::Gitx::Cli::ReviewCommand do
|
|
44
44
|
|
45
45
|
allow(cli).to receive(:authorization_token).and_return(authorization_token)
|
46
46
|
expect(cli).to receive(:run_cmd).with("git log master...feature-branch --reverse --no-merges --pretty=format:'* %s%n%b'").and_return("* old commit\n\n* new commit").ordered
|
47
|
-
expect(cli).to receive(:ask_editor).with("### Changelog\n* old commit\n\n* new commit\n#{Thegarage::Gitx::
|
47
|
+
expect(cli).to receive(:ask_editor).with("### Changelog\n* old commit\n\n* new commit\n#{Thegarage::Gitx::Github::PULL_REQUEST_FOOTER}", anything).and_return('description')
|
48
48
|
|
49
49
|
stub_request(:post, 'https://api.github.com/repos/thegarage/thegarage-gitx/pulls').to_return(:status => 201, :body => new_pull_request.to_json, :headers => {'Content-Type' => 'application/json'})
|
50
|
+
|
50
51
|
VCR.use_cassette('pull_request_does_not_exist') do
|
51
52
|
cli.review
|
52
53
|
end
|
@@ -124,9 +125,11 @@ describe Thegarage::Gitx::Cli::ReviewCommand do
|
|
124
125
|
}
|
125
126
|
end
|
126
127
|
let(:authorization_token) { '123123' }
|
128
|
+
let(:reference) { double('fake reference', target_id: 'e12da4') }
|
127
129
|
before do
|
128
130
|
allow(cli).to receive(:authorization_token).and_return(authorization_token)
|
129
131
|
expect(cli).to receive(:ask_editor).and_return('comment description')
|
132
|
+
allow(repo).to receive(:head).and_return(reference)
|
130
133
|
stub_request(:post, /.*api.github.com.*/).to_return(:status => 201)
|
131
134
|
|
132
135
|
VCR.use_cassette('pull_request_does_exist_with_success_status') do
|
@@ -137,6 +140,64 @@ describe Thegarage::Gitx::Cli::ReviewCommand do
|
|
137
140
|
expect(WebMock).to have_requested(:post, "https://api.github.com/repos/thegarage/thegarage-gitx/issues/10/comments").
|
138
141
|
with(body: {body: 'comment description'})
|
139
142
|
end
|
143
|
+
it 'creates pending build status for latest commit' do
|
144
|
+
expect(WebMock).to have_requested(:post, 'https://api.github.com/repos/thegarage/thegarage-gitx/statuses/e12da4').
|
145
|
+
with(body: {state: 'pending', context: 'peer_review', description: 'Peer review in progress'})
|
146
|
+
end
|
147
|
+
end
|
148
|
+
context 'when --reject flag is passed' do
|
149
|
+
let(:options) do
|
150
|
+
{
|
151
|
+
reject: true
|
152
|
+
}
|
153
|
+
end
|
154
|
+
let(:authorization_token) { '123123' }
|
155
|
+
let(:reference) { double('fake reference', target_id: 'e12da4') }
|
156
|
+
before do
|
157
|
+
allow(cli).to receive(:authorization_token).and_return(authorization_token)
|
158
|
+
expect(cli).to receive(:ask_editor).and_return('comment body')
|
159
|
+
allow(repo).to receive(:head).and_return(reference)
|
160
|
+
stub_request(:post, /.*api.github.com.*/).to_return(:status => 201)
|
161
|
+
|
162
|
+
VCR.use_cassette('pull_request_does_exist_with_success_status') do
|
163
|
+
cli.review
|
164
|
+
end
|
165
|
+
end
|
166
|
+
it 'posts comment to github' do
|
167
|
+
expect(WebMock).to have_requested(:post, "https://api.github.com/repos/thegarage/thegarage-gitx/issues/10/comments").
|
168
|
+
with(body: {body: 'comment body'})
|
169
|
+
end
|
170
|
+
it 'creates failure build status for latest commit' do
|
171
|
+
expect(WebMock).to have_requested(:post, 'https://api.github.com/repos/thegarage/thegarage-gitx/statuses/e12da4').
|
172
|
+
with(body: {state: 'failure', context: 'peer_review', description: 'Peer review rejected'})
|
173
|
+
end
|
174
|
+
end
|
175
|
+
context 'when --approve flag is passed' do
|
176
|
+
let(:options) do
|
177
|
+
{
|
178
|
+
approve: true
|
179
|
+
}
|
180
|
+
end
|
181
|
+
let(:authorization_token) { '123123' }
|
182
|
+
let(:reference) { double('fake reference', target_id: 'e12da4') }
|
183
|
+
before do
|
184
|
+
allow(cli).to receive(:authorization_token).and_return(authorization_token)
|
185
|
+
expect(cli).to receive(:ask_editor).and_return('comment body')
|
186
|
+
allow(repo).to receive(:head).and_return(reference)
|
187
|
+
stub_request(:post, /.*api.github.com.*/).to_return(:status => 201)
|
188
|
+
|
189
|
+
VCR.use_cassette('pull_request_does_exist_with_success_status') do
|
190
|
+
cli.review
|
191
|
+
end
|
192
|
+
end
|
193
|
+
it 'posts comment to github' do
|
194
|
+
expect(WebMock).to have_requested(:post, "https://api.github.com/repos/thegarage/thegarage-gitx/issues/10/comments").
|
195
|
+
with(body: {body: 'comment body'})
|
196
|
+
end
|
197
|
+
it 'creates success build status for latest commit' do
|
198
|
+
expect(WebMock).to have_requested(:post, 'https://api.github.com/repos/thegarage/thegarage-gitx/statuses/e12da4').
|
199
|
+
with(body: {state: 'success', context: 'peer_review', description: 'Peer review approved'})
|
200
|
+
end
|
140
201
|
end
|
141
202
|
end
|
142
203
|
|
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: 2.
|
4
|
+
version: 2.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Sonnek
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rugged
|